Docs · Godot

Godot API

The Godot wrappers over the two libraries: cadaclysm_capi reads, meshes and writes; cadaclysm_blacksmith builds exact solids. Every type and call, with the signature as the wrapper declares it — read from its source when this page is built.

Install

Install and load

The addon, addons/cadaclysm/: a GDExtension for Godot 4.4 and later, prebuilt in every SDK release as cadaclysm-<version>-godot.zip for Windows x64, macOS 11+ (universal) and Linux x64 and arm64. Copy its addons/cadaclysm/ into the project: there is no plugin to enable, and the classes are there in GDScript. To build it yourself, the SDK's godot/ folder holds its Rust source (Rust 1.94 or later) and build.py; see the Godot page. The classes are Python's, name for name, with Cadaclysm in front — CadaclysmScene, CadaclysmSolid — and Python's module functions are static functions of Cadaclysm (the reader) and CadaclysmBlacksmith (the kernel). Properties are read-only properties here too; Godot's own types stand in where Godot has one: a Transform3D, an AABB, a Color, an ArrayMesh. Files open Y up in metres, Godot's own space, unless asked otherwise.

The addon carries the libraries, in bin/<platform>/ beside the extension; an exported game gets them beside its executable, copied there by the .gdextension file. Building the addon from the SDK's godot/ folder is on the Godot page.

# addons/cadaclysm/ copied into the project; then, from any script:
func _ready() -> void:
	print(Cadaclysm.version(), " ", CadaclysmBlacksmith.version())

Where the library is found

Beside the extension: the addon's bin/<platform>/, or next to an exported game's executable. CADACLYSM_LIBRARY for the reader and CADACLYSM_BLACKSMITH_LIBRARY for the kernel, each a file or a directory, name others and win over those; past that the SDK's own search runs (beside the executable, a lib/ in any parent). Cadaclysm.library_path() says which was used, and Cadaclysm.load(path) names one outright.

The licence

Unlicensed, everything works and a notice is printed on every open and export. A licence file removes it: set CADACLYSM_LICENSE, or put cadaclysm.lic beside the executable or in the working directory, or load it from code — once per library:

Cadaclysm.license("res://cadaclysm.lic")
CadaclysmBlacksmith.license("res://cadaclysm.lic")
Quick start

Build a part, then read it back

The kernel builds a plate with a boss, bores it and rounds its corners, then writes STEP — the Examples page's first part:

# Run headless from the project's folder: godot --headless --script plate.gd
extends SceneTree

func _initialize() -> void:
	var plate := CadaclysmWorkplane.xy().extrude(CadaclysmProfile.rect(120, 80), 14).solid()
	var boss := CadaclysmWorkplane.from_solid(plate) \
		.faces(">Z").workplane() \
		.extrude(CadaclysmProfile.circle(22), 26).solid()
	var part := plate.join(boss)

	var bore := CadaclysmWorkplane.xy().extrude(CadaclysmProfile.circle(11), 60).solid().translate(0, 0, -10)
	part = part.cut(bore)

	# The plate's four vertical corners: the lines along Z between two planes
	# (the boss has vertical seams too, but those lie on its cylinder).
	var corners := []
	for edge: CadaclysmEdge in part.edges:
		if edge.is_line and absf(edge.direction.z) > 0.99 \
				and Array(edge.faces).all(func(f): return part.face_kind(f) == "plane"):
			corners.append(edge)
	part = part.fillet(corners, 12)
	part.step("plate.stp")
	quit()

The reader opens that file, walks its tree, meshes what it draws and writes glTF:

# Run headless from the project's folder: godot --headless --script read_plate.gd
extends SceneTree

func _initialize() -> void:
	var scene := CadaclysmScene.open("plate.stp")   # Y up, in metres: Godot's own space
	if scene == null:
		push_error(Cadaclysm.last_error())
		quit(1)
		return
	print(scene.schema, " ", scene.metres_per_unit, " m per unit")

	# The tree: assemblies, parts and bodies, parents before children.
	for node: CadaclysmNode in scene.walk():
		print("  ".repeat(node.depth), node.label, " [", node.kind, "]")

	# What to draw: every placement of every shape, meshed on first ask.
	for placement: CadaclysmPlacement in scene.placements:
		var mesh := placement.geometry.mesh
		print(placement.geometry.label, " ", mesh.triangle_count, " triangles")

	scene.save("plate.glb", "glb")
	scene.close()
	quit()
Reader · cadaclysm_capi

Reading, meshing, writing

Module functions

Loading the library, the licence, and opening a file — from disk or from bytes already in memory. Every other object on this page comes out of CadaclysmScene.open() or CadaclysmScene.open_bytes().

CadaclysmScene.open()

static func open(path: String) -> CadaclysmScene

Open a CAD file and read its tree. The format comes from the extension (a .zip opens its first readable member — CadaclysmScene.source_name says which). The tree is read now and the geometry is built lazily, node by node, when it is first asked for.

convention is the space to read into — a Convention, optionally with the file-units and world-UV flags — and the library converts everything it hands back into it. schema names an extra EXPRESS schema (.exp, or a directory of them); every schema the SDK ships is already built in, so it is needed only for one the library does not carry. colours asks for per-vertex colours on bodies the file painted in more than one colour.

Never returns an empty handle: on failure it returns null, false or an empty value (the reason in Cadaclysm.last_error()) carrying the library's reason.

Takes the path alone and reads Y up in metres, Godot's own space; open_with takes the rest as a Dictionary (under Scene). GDScript has no exceptions, so a failure is null: check for it.

CadaclysmScene.open_bytes()

static func open_bytes(data: PackedByteArray, format: String, options: Dictionary) -> CadaclysmScene

Open a file already in bytes — a download, a database blob, an archive member. With no file name to take the format from, it is named as an extension would name it: step, ifc, igs, 3dm, brep, scad (a leading dot is fine). The bytes are copied; the buffer can be reused as soon as this returns. Otherwise as CadaclysmScene.open().

options as open_with takes them, plus name: what the scene reports as its path.

Cadaclysm.version()

static func version() -> String

The version of the library actually loaded — the one worth reporting in a bug.

Cadaclysm.build_date()

static func build_date() -> String

When the loaded library was built, YYYY-MM-DD. A licence covers every build dated on or before its expiry.

Cadaclysm.license()

static func license(text_or_path: String) -> bool

Load a licence: the certificate text, or the path of a file holding it. Without this call the library looks in the CADACLYSM_LICENSE environment variable, then for cadaclysm.lic beside the executable and in the working directory. On a licence that does not verify it returns null, false or an empty value (the reason in Cadaclysm.last_error()) with the reason, and the previous licence (if any) stays in use.

Cadaclysm.license_info()

static func license_info() -> String

One line about the licence in use — customer=… expiry=… entitlements=… — or unlicensed (unlicensed -- <reason> when a licence was found but did not verify). Never null.

Cadaclysm.license_notice_count()

static func license_notice_count() -> int

How many unlicensed notices the library has printed to stderr in this process. An application with no console to watch (a GUI, a game) can poll this and show its own banner.

Cadaclysm.mesh_formats()

static func mesh_formats() -> Array[Dictionary]

Every mesh format CadaclysmNode.save_mesh() writes, with its file extension: stl, stl-ascii, msh (Gmsh), glb, gltf and obj in this release. Build a save menu from this list rather than hard-coding it, and a format added to the library appears without a code change.

Cadaclysm.pick_file

Ask the user for a file through the platform's own open dialog, filtered to what this build can read. null when they cancel or no dialog is available (on Linux, neither an XDG portal nor zenity). Blocks until the user acts; on macOS call it from the main thread.

Not in the Godot extension: Godot's own FileDialog picks a file.

Cadaclysm.declared_schema()

static func declared_schema(path: String) -> String

The schema a STEP or IFC file says it speaks (its FILE_SCHEMA line), read from the first few kilobytes — cheap even on a very large file. Empty when it names none.

Cadaclysm.resolve_schema

Which .exp of a schema directory matches a model: the chosen file, or — when the file's declared name resembles none of them — the whole list as fallbacks to try in turn. CadaclysmScene.open() does this itself when given a directory; this is for a caller that wants to report the choice.

Not in the Godot extension: pass the directory as open_with's schema and it chooses.

Cadaclysm.library_path()

static func library_path() -> String

Where the shared library was found: CADACLYSM_LIBRARY (a file or a directory) first, then beside the wrapper, then a lib/ directory in any parent (the SDK's layout).

Cadaclysm.NONE

The node index the C API uses for "no such node" (CADACLYSM_NONE, 0xFFFFFFFF). The wrappers turn it into null where a node may be missing (CadaclysmNode.parent, CadaclysmNode.instance_of), so it matters only when reading raw indices.

Missing nodes are null.

last_error Godot only

static func last_error() -> String

Why the last cadaclysm call that failed failed, reader or kernel; "" after a call that worked. GDScript has no exceptions: a failing call returns null (or false, -1 or an empty value) and reports the reason with push_error as well. Kept per thread.

load Godot only

static func load(path: String) -> bool

Load the reader library from a path before anything else asks for it. Optional: the extension finds it beside itself, as described under Install.

The importer Godot only

class CadaclysmImporter extends EditorSceneFormatImporter
class CadaclysmEditorPlugin extends EditorPlugin

The editor side: with the addon in a project, a STEP, IGES, IFC, 3dm, SAT, OCCT .brep or OpenSCAD file imports as a scene, the way a .glb does — a MeshInstance3D a body, Y up in metres. The Import dock's cadaclysm/ options add the edges, nest the file's tree, draw both sides of faces or add world-scale UVs. Nothing to call: the plugin registers the importer, and the imported scene is Godot's own, so an exported game draws it with no cadaclysm library.

CadaclysmScene

class CadaclysmScene extends RefCounted

An open document. Close it when done — CadaclysmScene.close(), or let the language's scope do it (with, using, defer, try-with-resources). Everything it hands back borrows from it: node handles, meshes, polylines. See Lifetimes for what survives a close.

CadaclysmScene.close()

func close() -> void

Give the document back. Idempotent. Every mesh and polyline view still held reads freed memory afterwards (the wrappers that can tell refuse to read them).

CadaclysmScene.closed

var closed: bool  # read-only

Whether CadaclysmScene.close() has run.

CadaclysmScene.path

var path: String  # read-only

The file it was read from, or the name given to CadaclysmScene.open_bytes().

CadaclysmScene.schema_path

The .exp actually used, or null — worth reporting when a directory was passed.

Not in the Godot extension.

CadaclysmScene.convention

var convention: int  # read-only

The convention it was opened with. Nothing the library hands back says what space it is in, and every array out of this scene is in this one.

An int: the number Cadaclysm.convention(name) gives for the convention's name.

CadaclysmScene.version

var version: String  # read-only

The version of the library that read it.

CadaclysmScene.schema

var schema: String  # read-only

The schema the file named, or empty for a format that names none.

CadaclysmScene.schema_read

var schema_read: String  # read-only

The schema that actually read it. A file declaring a release candidate reads under the finished schema of the same version where that is what is built in; a file whose schema is unknown reads under the one that defines its entity types.

CadaclysmScene.substituted

var substituted: bool  # read-only

Whether something other than the file's own schema read it — CadaclysmScene.schema and CadaclysmScene.schema_read differ.

CadaclysmScene.metres_per_unit

var metres_per_unit: float  # read-only

What one length unit in the file is worth in metres; 1 where the file did not say.

CadaclysmScene.bounds

var bounds: AABB  # read-only

Everything the model covers, in world coordinates — the one figure not in a node's own frame. This meshes the whole model, being the only way to know how far it reaches; to frame a view quickly, use the bounds of the nodes already built.

CadaclysmScene.diagnostics

var diagnostics: PackedStringArray  # read-only

What the file held that the reader could not build, one line each.

CadaclysmScene.source_name

var source_name: String  # read-only

The archive member this was read from, or null for a plain file.

"" for a plain file.

CadaclysmScene.nodes

var nodes: Array[CadaclysmNode]  # read-only

Every node, in index order: assemblies, shapes, layers, storeys — structure as well as geometry. To draw, iterate CadaclysmScene.placements instead.

CadaclysmScene.roots

var roots: Array[CadaclysmNode]  # read-only

The nodes nothing else contains: where a tree view starts.

CadaclysmScene.walk()

func walk() -> Array[CadaclysmNode]

Every node reachable from the roots, parents before children.

CadaclysmScene.query()

func query(filter: String) -> Array[CadaclysmNode]

The indices of the nodes a filter matches, in document order. The filter is one boolean expression in the query languageclass == ON_Brep and within(name == Walls). A filter that does not parse returns null, false or an empty value (the reason in Cadaclysm.last_error()) with the parser's message and position; one that matches nothing is an empty result, not an error.

Returns the matching nodes.

CadaclysmScene.placements

var placements: Array[CadaclysmPlacement]  # read-only

What the document draws, and where. Not the nodes: a block or an instanced part is one node of geometry drawn at several places, and a node walk draws it once at its definition's frame. Iterate this to draw, and the nodes to build a tree. See CadaclysmPlacement.

CadaclysmScene.realize_all()

func realize_all() -> int

Build every mesh now, across all cores, and return how many were built. Reading is lazy so a tree can be on screen while the shapes are still coming; asking node by node meshes on one core, this uses them all. Watch it from another thread with CadaclysmScene.realized and CadaclysmScene.realize_total; stop it with CadaclysmScene.cancel().

CadaclysmScene.realized

var realized: int  # read-only

How many nodes CadaclysmScene.realize_all() has finished. Safe to read from another thread.

CadaclysmScene.realize_total

var realize_total: int  # read-only

How many it will build in all; zero until it starts.

CadaclysmScene.cancel()

func cancel() -> void

Ask a running CadaclysmScene.realize_all() to stop. One-way for the life of the scene: later calls return at once, and meshes are still built one node at a time on request.

CadaclysmScene.save()

func save(path: String, format: String) -> bool

Write the whole scene: glb (binary glTF), gltf (text glTF, one file) or obj (every placement baked to its own named object, with a .mtl beside it when anything has a colour). Every placement of every shape, named and placed as the tree is, one material per colour; in the scene's convention (use Y-up metres for the space glTF specifies). A format outside these three, or a failed write, returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmScene.surface_matrix

var surface_matrix: Transform3D  # read-only

The 4×4 that puts CadaclysmNode.surfaces into the space everything else is already in. Meshes and polylines arrive in the scene's convention; surfaces arrive in the file's own frame, because converting a surface means converting its parameter space too. Identity for a document opened in its native convention and units.

CadaclysmScene.show

Draw every visible placement — each block instance where the file puts it — with the viewer in use. Keywords: view= (front, back, left, right, top, bottom, iso), az=, el=, zoom=, up= (default from the convention the scene was opened with), edges= (the B-rep edges over the shapes; free curves are drawn either way), width=, height=, hint=. No tolerance=: a document is drawn at the tolerance it was read with.

Comes with the viewers follow-up.

CadaclysmScene.view

Orbit the model with the viewer in use; returns (azimuth, elevation, zoom) where it was left.

Comes with the viewers follow-up.

open_with Godot only

static func open_with(path: String, options: Dictionary) -> CadaclysmScene

CadaclysmScene.open() with Python's keyword arguments as a Dictionary: convention (a name — "y-up", the default, "native", "unreal", "unity", "blender", with "+file-units" to keep the file's units — or a number), uv_world, colors, schema (an extra .exp) and source_metres_per_unit. An unknown key fails, naming the known ones. res:// and user:// paths work, in an exported game too, where a file inside the pack is read through FileAccess.

node Godot only

var node_count: int  # read-only
func node(index: int) -> CadaclysmNode

The node count, and one node by index without building the list of all of them; null past the end.

instantiate Godot only

func instantiate() -> Node3D
func instantiate_with(options: Dictionary) -> Node3D

The whole scene as Godot nodes: a Node3D holding a MeshInstance3D for every placement, the bodies drawn more than once sharing one ArrayMesh, in the file's colours. Each instance carries its file node's index as metadata: cadaclysm_node (what a click selects), cadaclysm_geometry and cadaclysm_placement. instantiate_with's options: edges (each body's edges as a lines child), edge_color, material (one Material for every body), tree (nest the placements under Node3Ds following the file's tree) and double_sided. The meshes are Godot's: they outlive CadaclysmScene.close().

drawing Godot only

func drawing(view: String) -> Dictionary

Every edge and free curve seen from view"front", "top", "left", "right", "back" or "bottom" — flattened onto the page for 2D drawing: {segments, lo, hi}, segments a PackedVector2Array of point pairs for draw_multiline, lo and hi its bounds, y down the screen.

CadaclysmNode

class CadaclysmNode extends RefCounted

One node of the document — an assembly, a part, a body, a layer, a placement. A handle, not a snapshot: each property asks the scene when read, so nothing goes stale and nothing is built that is never looked at. Names and attributes are cheap; CadaclysmNode.bounds and CadaclysmNode.mesh build the geometry.

CadaclysmNode.scene

The scene it belongs to.

Not exposed: keep the CadaclysmScene you opened.

CadaclysmNode.index

var index: int  # read-only

Its index in the scene, stable while the scene is open: a key for a map of what has been uploaded.

CadaclysmNode.name

var name: String  # read-only

The name the file gave it, or empty.

CadaclysmNode.id

var id: String  # read-only

What the file calls it: a STEP #N, an IFC GlobalId, a Rhino object id.

CadaclysmNode.kind

var kind: String  # read-only

Its type in the file: an IFC class, an openNURBS class, a STEP shape kind.

CadaclysmNode.label

var label: String  # read-only

Something to put in a tree row: the name, else the kind, else #index.

CadaclysmNode.depth

var depth: int  # read-only

How far down the tree it sits; a root is zero.

CadaclysmNode.generator

var generator: String  # read-only

What its geometry was before it was triangles — brep, mesh, csg — or empty for a node that draws nothing.

CadaclysmNode.visible

var visible: bool  # read-only

Whether the file says to show it when opened. The node's own switch, not inherited; true where the format has no such switch.

CadaclysmNode.visible_now

var visible_now: bool  # read-only

CadaclysmNode.visible with every ancestor consulted: a layer switched off hides what hangs under it.

CadaclysmNode.locked

var locked: bool  # read-only

Whether the file says it cannot be selected or edited (Rhino's lock, own or by layer). A locked node is still drawn.

CadaclysmNode.parent

var parent: CadaclysmNode  # read-only

The node containing this one, or null for a root.

CadaclysmNode.children

var children: Array[CadaclysmNode]  # read-only

The nodes directly under this one.

CadaclysmNode.instance_of

var instance_of: CadaclysmNode  # read-only

The node whose geometry this one places, or null. A part placed seventy times is one mesh and seventy transforms; this is how a caller knows to upload it once.

CadaclysmNode.select_as

var select_as: CadaclysmNode  # read-only

What a click on this node's geometry should select — usually itself. Formats that hang geometry under the object it belongs to (an IFC representation under its product) point back at the object.

CadaclysmNode.attributes

var attributes: Array[Dictionary]  # read-only

Everything the file said about the node, as Attribute values.

CadaclysmNode.can_mesh

var can_mesh: bool  # read-only

Whether the node has geometry of its own to draw. Builds nothing; most nodes are structure and answer false.

CadaclysmNode.colour

var colour: Variant  # read-only

The colour the file gave it as RGBA in 0–1, or null — most STEP files carry none, and the caller's default is the right answer.

CadaclysmNode.transform

var transform: Transform3D  # read-only

Where the node's geometry sits: a 4×4 in double precision, composed through every frame above it. Meshes stay single precision in their own frame under a double transform, so a model at survey coordinates keeps its millimetres.

A Transform3D, which a standard Godot build holds in single precision; raw_transform keeps the doubles.

CadaclysmNode.raw_transform

var raw_transform: PackedFloat64Array  # read-only

The same matrix as 16 numbers in the C API's column-major order, ready for a GPU uniform.

CadaclysmNode.bounds

var bounds: AABB  # read-only

The extent of the node's geometry in that geometry's own frame. Builds the geometry if needed; carry it through CadaclysmNode.transform for world coordinates.

CadaclysmNode.mesh

var mesh: CadaclysmMesh  # read-only

Its triangles in their own frame, built now if they have not been. A node that instances another hands back the instanced node's arrays — the same memory for every placement. The arrays are views into the scene; see Lifetimes.

Copied out of the scene, into a CadaclysmMesh of packed arrays. array_mesh() builds Godot's ArrayMesh without the copy.

CadaclysmNode.surfaces

var surfaces: Array[Dictionary]  # read-only

Its faces as exact surfaces plus the trim loops that cut them, each in the surface's own (u, v). Nothing is meshed to produce it, and reading it costs CadaclysmNode.mesh nothing. Empty where the reader has no parametric description (a tessellated body, a mesh format). In the file's frame — see CadaclysmScene.surface_matrix.

CadaclysmNode.edges

var edges: CadaclysmPolylines  # read-only

Its feature edges as polylines, for an outline overlay. Builds the geometry if needed.

CadaclysmNode.brep

var brep: CadaclysmBrep  # read-only

Its exact B-rep, as a CadaclysmBrep, for the kernel's CadaclysmSolid.from_node() to operate on — or null where it has none (a mesh, a curve, a CSG body, a JT or OpenSCAD part). Shared with the scene, not copied.

CadaclysmNode.curves

var curves: CadaclysmPolylines  # read-only

Its free curves as polylines; a 2D drawing is all of these.

CadaclysmNode.isocurves

var isocurves: CadaclysmPolylines  # read-only

Lines ruled across its surfaces, so a curved face reads as curved in a wireframe. A flat face yields its outline, so these can overlap CadaclysmNode.edges.

CadaclysmNode.save_mesh()

func save_mesh(path: String, format: String) -> bool

Write this node's own mesh — where it is defined, without its placement — in one of Cadaclysm.mesh_formats(). A node that draws nothing, or an unknown format, returns null, false or an empty value (the reason in Cadaclysm.last_error()); ask CadaclysmNode.can_mesh first to grey out a menu entry. To write the whole model, see CadaclysmScene.save().

CadaclysmNode.walk()

func walk() -> Array[CadaclysmNode]

This node and every node under it, parents before children.

CadaclysmNode.show

Draw what this node and everything under it places with the viewer in use. Keywords as CadaclysmScene.show.

Comes with the viewers follow-up.

CadaclysmNode.view

Orbit this node and everything under it; returns (azimuth, elevation, zoom) where it was left.

Comes with the viewers follow-up.

array_mesh and edge_mesh Godot only

func array_mesh() -> ArrayMesh
func edge_mesh(colour: Color = Color(0.07, 0.07, 0.08)) -> ArrayMesh

The node's triangles as an ArrayMesh, in its own frame, wound for Godot and painted its own colour (or grey); and its edges and free curves as a lines ArrayMesh, unshaded in colour. null where there is nothing to draw. Place either with CadaclysmPlacement.transform.

CadaclysmBrep

class CadaclysmBrep extends RefCounted

A body's exact B-rep — the trimmed surfaces its mesh is cut from — shared with the scene rather than copied, and held by this object until it is released. It is what CadaclysmNode.brep hands the kernel's CadaclysmSolid.from_node(), which operates on it without a copy, and it can say whether it is a Manifold. It outlives the scene it came from for as long as anything holds it. In the node's own frame and the file's own units and axes; the kernel library must come from the same release as the reader.

CadaclysmBrep.pointer()

func pointer() -> int

The brep's C pointer, which the kernel's wrapper hands across. returns null, false or an empty value (the reason in Cadaclysm.last_error()) once released.

CadaclysmBrep.layout_id()

static func layout_id() -> String

How this library lays a brep out in memory: its compiler, target and source. The kernel shares a brep only with a reader whose id equals its own.

CadaclysmBrep.manifold()

func manifold() -> Dictionary

Whether its faces make a manifold — every edge bordered by one face or two, the faces round every vertex one fan — and whether it is closed, as a Manifold. Read off the topology the file wrote, not a mesh. returns null, false or an empty value (the reason in Cadaclysm.last_error()) once released.

CadaclysmBrep.release()

func release() -> void

Give the reference back now. Leaving a with block, or the garbage collector, does it otherwise.

CadaclysmPlacement

class CadaclysmPlacement extends RefCounted

One drawing of one node's geometry at one place: what CadaclysmScene.placements lists. Two drawings of the same shape name the same geometry node, and so the same arrays — upload once, draw twice.

CadaclysmPlacement.scene

The scene it belongs to.

Not exposed: keep the CadaclysmScene you opened.

CadaclysmPlacement.index

var index: int  # read-only

Its index in CadaclysmScene.placements.

CadaclysmPlacement.geometry

var geometry: CadaclysmNode  # read-only

The node whose mesh, edges and curves this draws.

CadaclysmPlacement.select

var select: CadaclysmNode  # read-only

What a click on this drawing selects: the placement's own node rather than the shared shape, which would light up every copy.

CadaclysmPlacement.transform

var transform: Transform3D  # read-only

Where to draw it: a 4×4, already composed through every frame from the root.

CadaclysmPlacement.raw_transform

var raw_transform: PackedFloat64Array  # read-only

The same matrix as 16 numbers, column-major.

CadaclysmMesh

class CadaclysmMesh extends RefCounted

A node's triangles, in the node's own frame: what CadaclysmNode.mesh returns. The arrays are read-only views into the scene's memory, not copies — a large assembly is tens of millions of triangles, and most of them go straight to a GPU. CadaclysmMesh.copy makes arrays of your own.

CadaclysmMesh.positions

var positions: PackedVector3Array  # read-only

Three floats a vertex.

CadaclysmMesh.normals

var normals: PackedVector3Array  # read-only

Three floats a vertex, or null for a mesh that carries none.

Empty for a mesh that carries none.

CadaclysmMesh.uvs

var uvs: PackedVector2Array  # read-only

Two floats a vertex, or null: only readers asked for world-scale UVs fill them. One unit of u or v is one world unit, so faces overlap in UV space — a tiling material, not a lightmap.

Empty unless the scene was opened with uv_world.

CadaclysmMesh.colors

var colors: PackedColorArray  # read-only

Four floats (RGBA) a vertex, or null — the common case. Only a body painted in several colours, opened with colours on, carries them.

Empty unless the scene was opened with colors and the body is painted in several.

CadaclysmMesh.indices

var indices: PackedInt32Array  # read-only

Three vertex indices a triangle, unsigned 32-bit.

CadaclysmMesh.vertex_count

var vertex_count: int  # read-only

How many vertices.

CadaclysmMesh.index_count

var index_count: int  # read-only

How many indices: three a triangle.

CadaclysmMesh.triangle_count

var triangle_count: int  # read-only

How many triangles.

CadaclysmMesh.copy

The same arrays in memory of your own, safe to keep after CadaclysmScene.close(). Deliberately visible: on a large model this is where the gigabytes go.

A CadaclysmMesh is a copy already: it owns its arrays and outlives the scene.

is_empty and to_array_mesh Godot only

var is_empty: bool  # read-only
func to_array_mesh() -> ArrayMesh

Whether there are no triangles, and these triangles as an ArrayMesh wound for Godot (the library winds them counter-clockwise, Godot the other way); null when there are none.

CadaclysmPolylines

class CadaclysmPolylines extends RefCounted

Edges or curves already flattened to points, in the node's own frame: what CadaclysmNode.edges, CadaclysmNode.curves and CadaclysmNode.isocurves return. Views into the scene, like CadaclysmMesh.

CadaclysmPolylines.positions

var positions: PackedVector3Array  # read-only

Three floats a point, the runs end to end.

CadaclysmPolylines.counts

var counts: PackedInt32Array  # read-only

How many points each run has, in order.

CadaclysmPolylines.polyline_count

var polyline_count: int  # read-only

How many runs.

CadaclysmPolylines.vertex_count

var vertex_count: int  # read-only

How many points in all.

CadaclysmPolylines.segment_indices()

func segment_indices() -> PackedInt32Array

Index pairs into the positions, two per line segment — what GL_LINES and every pair-taking API want. Indices rather than points, so a caller can transform the points once and expand afterwards.

CadaclysmPolylines.segments()

func segments() -> PackedVector3Array

The segment endpoints themselves, two points per segment.

runs and to_array_mesh Godot only

var is_empty: bool  # read-only
func runs() -> Array[PackedVector3Array]
func to_array_mesh(colour: Color = Color(0.07, 0.07, 0.08)) -> ArrayMesh

Whether there are no points; each run as its own PackedVector3Array; and the lines as a lines ArrayMesh, unshaded in colour (null when empty).

Surfaces and Face

A node's faces as exact surfaces and trims: what CadaclysmNode.surfaces returns. Iterate it for Face values. In the file's own frame; CadaclysmScene.surface_matrix brings it into the scene's.

No class: surfaces is an Array of Dictionaries, one a face.

Surfaces.faces

The faces, one per trimmed face of the body.

surfaces is itself the array of faces.

Face.

One trimmed face. kind is the surface: 0 plane, 1 cylinder, 2 cone, 3 sphere, 4 torus, 5 revolution, 6 extrusion, 7 NURBS, 8 sum. origin, ax, ay, az are its frame, scalars its kind-dependent sizes (radius, angle…) and domain its (u min, v min, u max, v max). loops holds the trim loops as (u, v) points, each closing implicitly; profile, profile2 and nurbs carry what a swept or NURBS surface needs. reversed flips the normal; transposed swaps u and v. The C header's CadaclysmFace is the full description.

Each face is a Dictionary: kind, kind_name (the surface's name, "plane"...), reversed, transposed, origin, ax, ay, az (Vector3s), domain and scalars (Vector4s), loops (an Array of PackedVector2Array), profile and profile2 (PackedVector4Arrays) and nurbs (a PackedFloat32Array).

AABB

An axis-aligned box: what CadaclysmNode.bounds and CadaclysmScene.bounds return. All zeros means "nothing here".

Bounds are Godot's own AABB.

AABB.position

The low corner.

position.

AABB.end

The high corner.

end.

AABB.has_surface

Whether this is the all-zero box that stands for nothing.

has_surface() is false for it; == AABB() tells the all-zero box exactly.

AABB.size

The extent along each axis.

size.

AABB.get_center

The midpoint.

get_center().

Attribute

One thing the file said about a node: what CadaclysmNode.attributes lists.

No class: an attribute is a Dictionary, {name, kind, value, text}.

Attribute.name

What the file called it.

The name key.

Attribute.kind

Which kind of value it holds — a ValueKind. Lets a caller tell a reference from prose, or total the numbers.

The kind key, a String: "none", "text", "integer", "real", "boolean", "list" or "reference".

Attribute.value

The value, in the language's own type where it has one for the kind.

The value key: a String, an int, a float, a bool or null (lists and references arrive as Strings).

Attribute.text

The value rendered for display, identically in every wrapper: true/false, reals in their shortest exact form, lists as [a, b, c].

The text key.

Convention

The coordinate space to open a file into. The library converts on the way out, so a caller names the space it draws in and reads geometry already in it — nothing to rotate or scale afterwards.

No class: a convention is named by a String in open_with's convention option — "y-up" (the default: Godot's own space), "native", "unreal", "unity", "blender" — or given as the number Cadaclysm.convention(name) returns.

Convention.

The presets: NATIVE keeps the file's own axes and units; UNREAL is Z up, left-handed, centimetres; UNITY Y up, left-handed, metres; Y_UP Y up, right-handed, metres (glTF, three.js, most real-time engines); BLENDER Z up, right-handed, metres.

"native", "unreal", "unity", "y-up" and "blender": Strings, in open_with's convention option.

Convention.FILE_UNITS

Combine with a preset to keep its axes but the file's own units.

+file-units after the name: "unreal+file-units".

Convention.UV_WORLD

Combine with a preset to ask for world-scale texture coordinates in CadaclysmMesh.uvs. Off by default: eight bytes a vertex nobody asked for.

open_with's uv_world option: {"uv_world": true}.

Cadaclysm.convention()

static func convention(name: String) -> int

A convention from a name a user typed: unreal, or unreal+file-units. An unknown name returns null, false or an empty value (the reason in Cadaclysm.last_error()) listing the accepted ones, rather than silently reading as native.

Returns the convention's number, which open_with's convention option also takes; -1 for a name it does not know.

ValueKind

Which kind of value an Attribute holds.

No enum: an attribute's kind is its name as a String, "text", "integer"...

ValueKind.

TEXT, INTEGER, REAL, BOOLEAN; LIST (the elements rendered as [a, b, c]); REFERENCE (another entity, by the id the file gave it, so it can be followed rather than shown as prose); NONE for an attribute that had no value.

No enum: an attribute's kind is its name as a String, "text", "integer"...

Manifold

Whether a body's faces make a manifold — every edge bordered by one face or two, the faces round every vertex one fan — told from its topology rather than a mesh: what a brep's manifold and the kernel's CadaclysmSolid.manifold return. Orientation is not asked. The topology is the file's: faces that name no shared edge (IGES, each surface its own sheet; an IFC face written as one polygon) read as open however well they meet in space.

No class: a Dictionary with these keys.

Manifold.faces

How many faces.

The faces key.

Manifold.edges

How many distinct edges: one shared by two faces counts once.

The edges key.

Manifold.vertices

How many distinct vertices.

The vertices key.

Manifold.boundary_edges

Edges only one face borders: a sheet's rim, a hole in a shell.

The boundary_edges key.

Manifold.non_manifold_edges

Edges three or more faces border: a fin, or two solids meeting along a line.

The non_manifold_edges key.

Manifold.non_manifold_vertices

Vertices whose faces make more than one fan: two solids touching at a corner.

The non_manifold_vertices key.

Manifold.is_manifold

No non-manifold edge or vertex: a manifold, possibly with a boundary.

The is_manifold key.

Manifold.is_closed

A manifold with no boundary edge either: it encloses a solid.

The is_closed key.

Errors

A call into the library failed; the message is the library's own reason. One type for every reader failure.

No error type: GDScript has no exceptions. A call that fails returns null (or false, -1 or an empty value), reports the reason with push_error, and leaves it in Cadaclysm.last_error() until the next call that works.

Kernel · cadaclysm_blacksmith

Building solids

Frames and axes

A frame is twelve numbers: an origin, then the x, y and z axes, each three numbers (0,0,0, 1,0,0, 0,1,0, 0,0,1 is the world). A profile is drawn in its frame's x/y and extruded along its z. An axis is six numbers: a point and a direction, which need not be unit. CadaclysmWorkplane.xy() and friends start on the three world planes; CadaclysmSolid.face_frame() gives the frame on a face. A CadaclysmFrame builds one for you — CadaclysmFrame.xy() at any origin, CadaclysmFrame.at() from a point and a normal — and checks that its axes are square and right-handed, which a bare twelve numbers are not.

Pass a CadaclysmFrame, a Transform3D (square, unscaled axes), twelve numbers or four triples. A point is a Vector3 (Vector2 in a sketch) or an array of numbers — [1.5, 2.0, 0.0] keeps a double's precision where a Vector3 holds floats. An axis is two arguments, a point and a direction.

Module functions

The kernel's own library, licence and STEP writer. It is a separate shared library (cadaclysm_blacksmith) from the reader, with its own licence call; one licence file serves both.

CadaclysmBlacksmith.write_step()

static func write_step(path: String, solids: Array, schema: String = "", unit: String = "mm") -> bool

Write several solids as one STEP file, each its own body. unit is mm, m or in. schema is left out for AP203 (built in — no file needed), the name of another built-in schema such as AP242's AP242_MANAGED_MODEL_BASED_3D_ENGINEERING_MIM_LF (AP214's AUTOMOTIVE_DESIGN cannot carry the writer's mechanical_context), or a custom EXPRESS schema: a path to its .exp or its text.

CadaclysmBlacksmith.write_step_text()

static func write_step_text(solids: Array, schema: String = "", unit: String = "mm") -> String

The same STEP file as text, for a caller that stores or sends it rather than writing a file.

CadaclysmBlacksmith.default_schema()

static func default_schema() -> String

Where an ap203.exp file is found (CADACLYSM_SCHEMAS, else schemas/ in a parent). No longer needed to write STEP: the kernel's AP203 is built in.

CadaclysmBlacksmith.version()

static func version() -> String

The version of the kernel library actually loaded.

CadaclysmBlacksmith.build_date()

static func build_date() -> String

When the loaded kernel was built, YYYY-MM-DD.

CadaclysmBlacksmith.license()

static func license(text_or_path: String) -> bool

Load a licence into the kernel — the text, or a file's path. The reader has its own call; the same file works for both.

CadaclysmBlacksmith.license_info()

static func license_info() -> String

One line about the kernel's licence, or unlicensed. Never null.

CadaclysmBlacksmith.license_notice_count()

static func license_notice_count() -> int

How many unlicensed notices the kernel has printed to stderr in this process.

CadaclysmBlacksmith.brep_layout_id()

static func brep_layout_id() -> String

How the loaded kernel lays a brep out in memory: its compiler, target and source. CadaclysmSolid.from_node() works only where this equals the reader's CadaclysmBrep.layout_id() — the two libraries from the same release.

CadaclysmBlacksmith.library_path()

static func library_path() -> String

Where the kernel library was found: CADACLYSM_BLACKSMITH_LIBRARY first, then as the reader's.

load Godot only

static func load(path: String) -> bool

Load the kernel library from a path before anything else asks for it. Optional, as the reader's.

Tolerances Godot only

static func default_tolerance() -> float
static func fillet_tolerance() -> float

The defaults the kernel's calls take: 0.05 for booleans, meshes and bounds, 1e-6 for fillet, chamfer and shell.

rgb Godot only

static func rgb(hex: String) -> Color

"#rgb" or "#rrggbb" (the # optional) as a Color; black, with the reason in Cadaclysm.last_error(), for anything else.

CadaclysmProfile

class CadaclysmProfile extends RefCounted

A closed outline with holes, in its own x/y — what gets extruded, revolved, lofted or swept. Immutable: every method returns a new one.

Its loops must be simple: an outline that crosses or touches itself (a figure-eight, a vertex landing on another side), a hole that runs into the boundary, or two holes that overlap are refused by every call that builds a face or a closed solid, naming the loops — extrude: hole 0 crosses the boundary. The open calls (extrude_open, revolve_open, sweep_open, loft_open) build sheets, and take such a profile as it is.

CadaclysmProfile.rect()

static func rect(w: float, h: float) -> CadaclysmProfile

A w × h rectangle centred on the origin.

CadaclysmProfile.circle()

static func circle(r: float) -> CadaclysmProfile

A circle of radius r about the origin.

CadaclysmProfile.slot()

static func slot(centre: Variant, length: float, r: float) -> CadaclysmProfile

A slot (stadium) length long overall, with end radius r, centred on centre and running along x. length must exceed 2 * r.

CadaclysmProfile.polygon()

static func polygon(points: Variant) -> CadaclysmProfile

A closed polygon through the points, in order, its side back to the first point a segment of its own. At least three points.

CadaclysmProfile.regular_polygon()

static func regular_polygon(centre: Variant, radius: float, sides: int, angle: float = 0.0) -> CadaclysmProfile

A regular polygon of sides sides (at least 3) on the circle of radius about centre, its first corner at angle radians from the sketch's x axis (0 by default), the rest counter-clockwise.

CadaclysmProfile.spline()

static func spline(points: Variant, degree: int = 3, weights: PackedFloat64Array = PackedFloat64Array(), closed: bool = false) -> CadaclysmProfile

A spline of degree (3 by default) through the control polygon points, weights one per point or null. Open, it starts on the first point and ends on the last: an open chain, for CadaclysmSolid.extrude_open() or CadaclysmProfile.chain(). Closed, it is periodic — smooth through its own start, no corner there — and a closed profile. The degree is lowered to fit the points; a degree of zero, too few points (two open, three closed) or a weight not positive returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmProfile.path()

static func path(start: Variant) -> CadaclysmPath

Start drawing an outline segment by segment at start; see CadaclysmPath.

CadaclysmProfile.chain()

static func chain(pieces: Array, tolerance: float = 1e-6) -> CadaclysmProfile

Open profiles — paths ended open — joined end to end into one: the forge's merge. They may come in any order and either way round: each next piece is the first of the rest with an end within tolerance (1e-6 by default) of either end of the chain so far, reversed where that makes it meet. Every segment is kept exactly — a line a line, an arc an arc, a spline the same spline. Closed where the chain's two ends meet, otherwise an open chain. A piece that is empty, has holes, is closed on its own or meets none of the others returns null, false or an empty value (the reason in Cadaclysm.last_error()) naming it by its index.

CadaclysmProfile.from_loops()

static func from_loops(loops: Array) -> CadaclysmProfile

Closed loops, in any order, as one profile: the loop enclosing the most area is the boundary and every other a hole in it, in the order given — a sketch's rectangle and the circles drawn inside it. Each loop is a closed profile with no holes of its own, wound either way; one that closes within rounding is closed exactly. A loop that is open, empty or encloses no area, loops that cross or touch, a hole outside the boundary, or one inside another hole (an island) returns null, false or an empty value (the reason in Cadaclysm.last_error()), naming the loops by their index.

CadaclysmProfile.close_loop()

func close_loop() -> CadaclysmProfile

This profile closed — the forge's sketch "close": where its last segment stops short of its start (a path ended open), a straight segment back to it; where it already comes back within 1e-9 of its extent, its last segment made to land on the start exactly. A closed profile comes back as it is, and holes are closed the same way.

CadaclysmProfile.with_hole()

func with_hole(hole: CadaclysmProfile) -> CadaclysmProfile

This outline with hole cut out of it.

CadaclysmProfile.translate()

func translate(dx: float, dy: float) -> CadaclysmProfile

This outline moved by (dx, dy).

CadaclysmProfile.round()

func round(radius: float, corners: PackedInt32Array = PackedInt32Array(), open: bool = false) -> CadaclysmProfile

This outline with its corners rounded by radius: where two straight segments meet, both are cut back and an exact arc tangent to both goes between them; a corner next to an arc or a spline is left as it is. With no corners every such corner is rounded, the holes' too; a list picks corners of the outline — corner k is where segment k ends. open reads the profile as an open chain whose two ends stay square. A radius that does not fit returns null, false or an empty value (the reason in Cadaclysm.last_error()) naming the corner.

CadaclysmProfile.polylines

The outline, then each hole, as polylines at z = 0 within tolerance of its arcs and splines — what a viewer draws it with. A closed loop repeats its first point at the end; an open chain (a profile ended open) stays open. Views, like CadaclysmSolid.mesh().

Comes with the viewers follow-up.

CadaclysmProfile.show

Draw the outline and holes with the viewer in use, from the top by default. Keywords as CadaclysmSolid.show; edges= is ignored, the lines being the whole picture.

Comes with the viewers follow-up.

CadaclysmProfile.view

Orbit the outline with the viewer in use; returns (azimuth, elevation, zoom) where it was left.

Comes with the viewers follow-up.

CadaclysmPath

class CadaclysmPath extends RefCounted

An outline drawn a segment at a time — lines, arcs, Béziers, NURBS — then closed into a CadaclysmProfile. Ending it consumes the builder.

CadaclysmPath.line_to()

func line_to(x: float, y: float) -> CadaclysmPath

A straight segment to (x, y).

CadaclysmPath.arc_to()

func arc_to(x: float, y: float, centre: Variant, ccw: bool = true) -> CadaclysmPath

A circular arc to (x, y) about centre, counter-clockwise unless ccw is false.

CadaclysmPath.bezier_to()

func bezier_to(c1: Variant, c2: Variant, to: Variant) -> CadaclysmPath

A cubic Bézier through control points c1, c2 to to.

CadaclysmPath.nurbs_to()

func nurbs_to(control: Variant, knots: Variant, degree: int, weights: PackedFloat64Array = PackedFloat64Array()) -> CadaclysmPath

A NURBS segment: control is every control point after the current one, the endpoint last; knots the full knot vector; weights one per control point including the current one, or null for a non-rational curve.

CadaclysmPath.end()

func end() -> CadaclysmProfile

Close the outline back to its start and return the CadaclysmProfile.

CadaclysmPath.end_open()

func end_open() -> CadaclysmProfile

The path as it stands, not closed: an open chain for CadaclysmSolid.extrude_open(), CadaclysmSolid.sweep_open() or CadaclysmSolid.loft_open().

begin Godot only

static func begin(start: Variant) -> CadaclysmPath

Python's Path(start), the same as CadaclysmProfile.path(). Each step returns the path itself, so steps chain; a step that fails returns null and spends the path.

CadaclysmSweepPath

class CadaclysmSweepPath extends RefCounted

The 3D path a profile is carried along by CadaclysmSolid.sweep(): lines and circular arcs. Sweeping only borrows it, so one path can be swept many times; close it when done.

CadaclysmSweepPath.at()

static func at(point: Variant) -> CadaclysmSweepPath

Start a path at a 3D point.

CadaclysmSweepPath.along()

static func along(curve: CadaclysmProfile, frame: Variant, tolerance: float = 0.05, open: bool = true) -> CadaclysmSweepPath

The path a 2D chain (usually from CadaclysmPath.end_open()) draws on frame: a line a straight piece, an arc a circular one, a Bézier or spline fitted with biarcs — arcs tangent to each other and to the curve — within tolerance, so the path is tangent throughout and the sweep exact along it. open false closes the path back to its start.

CadaclysmSweepPath.line_to()

func line_to(point: Variant) -> CadaclysmSweepPath

A straight piece to a 3D point.

CadaclysmSweepPath.arc()

func arc(centre: Variant, axis: Variant, angle: float) -> CadaclysmSweepPath

Turn angle radians (in (0, 2π]) about the axis through centre along axis.

CadaclysmSweepPath.close()

func close() -> void

Free the path.

Slant

A plane a CadaclysmSolid.extrude_between() starts or ends on, read as a height over the sketch plane at each point: at + grad · (x, y). Flat for an ordinary cap; sloped for a mitre.

No class: a slant is a number — a flat plane at that height — or a Dictionary {at, grad}, grad two numbers.

Slant.at

The height at the sketch origin.

The at key.

Slant.grad

The slope in x and y.

The grad key.

Slant.flat

A flat plane at height at.

A bare number is a flat plane.

CadaclysmBlacksmith.slant_of_plane()

static func slant_of_plane(frame: Variant, point: Variant, normal: Variant) -> Dictionary

The plane through point square to normal, as heights over frame. A plane that contains the extrusion direction has no height and returns null, false or an empty value (the reason in Cadaclysm.last_error()).

Returns the {at, grad} Dictionary; an empty one on failure.

CadaclysmFrame

class CadaclysmFrame extends RefCounted

A frame built for you instead of twelve numbers typed out: an origin and three unit axes, square to each other and right-handed (z = x × y). It goes wherever a frame does. Immutable. The constructor takes the origin and the three axes, normalises them, and returns null, false or an empty value (the reason in Cadaclysm.last_error()) when they are not square or not right-handed.

CadaclysmFrame.xy()

static func xy(origin: Vector3 = Vector3.ZERO) -> CadaclysmFrame

The world XY plane through origin: z up, as CadaclysmWorkplane.xy().

CadaclysmFrame.xz()

static func xz(origin: Vector3 = Vector3.ZERO) -> CadaclysmFrame

The world XZ plane through origin: x along X, y along Z, so z is -Y, as CadaclysmWorkplane.xz().

CadaclysmFrame.yz()

static func yz(origin: Vector3 = Vector3.ZERO) -> CadaclysmFrame

The world YZ plane through origin: x along Y, y along Z, so z is +X, as CadaclysmWorkplane.yz().

CadaclysmFrame.at()

static func at(origin: Variant, normal: Variant, x: Vector3 = Vector3.ZERO) -> CadaclysmFrame

The plane through origin square to normal, which becomes the frame's z (it need not be unit). Its x axis is x laid onto that plane; with none, world X laid onto it, or world Y when the normal is within about 25° of X — the axes CadaclysmSolid.face_frame() gives a face facing normal. So a normal along +Z, -Y or +X gives exactly CadaclysmFrame.xy(), CadaclysmFrame.xz() or CadaclysmFrame.yz(). A zero normal, or an x along the normal, returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmFrame.of()

static func of(raw: Variant) -> CadaclysmFrame

Twelve numbers — what CadaclysmSolid.face_frame() and CadaclysmWorkplane.frame hand back — as a checked frame, to read its axes or move it.

CadaclysmFrame.midplane

The plane midway between the planes of frames a and b — Fusion's midplane: for parallel planes the one halfway between, on a's axes; for planes that meet, the plane bisecting them through the line they meet on, its x along that line.

Not in the Godot extension.

CadaclysmFrame.through

The plane through the points p, q and r: its origin p, its x towards q, its z the normal the three turn about counter-clockwise. Three points on one line returns null, false or an empty value (the reason in Cadaclysm.last_error()).

Not in the Godot extension.

CadaclysmFrame.origin

var origin: Vector3  # read-only
var x: Vector3  # read-only
var y: Vector3  # read-only
var z: Vector3  # read-only

The origin and the three axes, each three numbers.

CadaclysmFrame.translate()

func translate(dx: float, dy: float, dz: float) -> CadaclysmFrame

This frame moved by (dx, dy, dz) in world coordinates.

CadaclysmFrame.offset()

func offset(distance: float) -> CadaclysmFrame

This frame moved distance along its own z: Frame.xy().offset(5) is the XY plane at z = 5.

create Godot only

static func create(origin: Variant, x: Variant, y: Variant, z: Variant) -> CadaclysmFrame

Python's Frame(origin, x, y, z): the frame with these axes, normalised, or null where they are not square or not right-handed. (new is GDScript's own, so the constructor is create.)

Transform3D Godot only

static func from_transform(transform: Transform3D) -> CadaclysmFrame
func to_transform() -> Transform3D

A frame from a Transform3D — its basis square, unscaled and right-handed, or null — and a frame as one: basis columns x, y, z and the origin. Any call taking a frame takes a Transform3D as well.

raw Godot only

var raw: PackedFloat64Array  # read-only

The twelve doubles — origin, x, y, z — that origin, x, y and z hold as Vector3s of floats.

is_equal_approx Godot only

func is_equal_approx(other: CadaclysmFrame, tolerance: float = 1e-9) -> bool

Whether another frame's twelve numbers are each within tolerance of this one's.

CadaclysmWorkplane

class CadaclysmWorkplane extends RefCounted

The fluent chain: a frame, the solid built so far, and the face last picked. A build step replaces the solid rather than adding to it — combine solids explicitly with CadaclysmSolid.join(). Every step returns null, false or an empty value (the reason in Cadaclysm.last_error()) at once rather than holding the error for later.

CadaclysmWorkplane.xy()

static func xy() -> CadaclysmWorkplane

Start on the XY plane at the origin (Z up). CadaclysmWorkplane.xz() and CadaclysmWorkplane.yz() start on the other two.

CadaclysmWorkplane.xz()

static func xz() -> CadaclysmWorkplane

Start on the XZ plane.

CadaclysmWorkplane.yz()

static func yz() -> CadaclysmWorkplane

Start on the YZ plane.

CadaclysmWorkplane.on()

static func on(frame: Variant) -> CadaclysmWorkplane

Start on any frame (see Frames).

CadaclysmWorkplane.from_solid()

static func from_solid(solid: CadaclysmSolid) -> CadaclysmWorkplane

Start from an existing solid, on the XY plane — the usual way to pick one of its faces and build on it.

CadaclysmWorkplane.frame

var frame: CadaclysmFrame  # read-only

The current frame, 12 numbers.

A CadaclysmFrame.

CadaclysmWorkplane.cuboid()

func cuboid(x: float, y: float, z: float) -> CadaclysmWorkplane

A box on the current frame; replaces the solid.

CadaclysmWorkplane.cylinder()

func cylinder(r: float, h: float) -> CadaclysmWorkplane

A cylinder of radius r and height h standing on the current frame; replaces the solid.

CadaclysmWorkplane.face()

func face(profile: CadaclysmProfile) -> CadaclysmWorkplane

The planar sheet the profile bounds on this frame — see CadaclysmSolid.face(); replaces the solid.

CadaclysmWorkplane.extrude()

func extrude(profile: CadaclysmProfile, height: float) -> CadaclysmWorkplane

The profile extruded height along the frame's z; replaces the solid.

CadaclysmWorkplane.revolve()

func revolve(profile: CadaclysmProfile, angle: float) -> CadaclysmWorkplane

The profile revolved angle radians about the frame's y axis; replaces the solid.

CadaclysmWorkplane.translate()

func translate(dx: float, dy: float, dz: float) -> CadaclysmWorkplane

Slide the current solid. Keeps the face selection — a rigid move keeps every face's index.

CadaclysmWorkplane.faces()

func faces(selector: Variant) -> CadaclysmWorkplane

Pick a face of the current solid with a Selector.

CadaclysmWorkplane.workplane()

func workplane() -> CadaclysmWorkplane

Move the frame onto the face last picked (outward normal as z), so the next step builds on it.

CadaclysmWorkplane.solid()

func solid() -> CadaclysmSolid

The solid built so far. On an empty chain it returns null, false or an empty value (the reason in Cadaclysm.last_error()).

Selector and Axis

Which face to pick: the one furthest along an axis, furthest against it, the one facing a direction, or by index. Used by CadaclysmWorkplane.faces() and CadaclysmSolid.select_face().

No class: a selector is a String, ">Z" or "<X", a face index, or a normal as a Vector3.

Selector.max

The face furthest along axis.

">X", ">Y", ">Z".

Selector.min

The face furthest against axis.

"<X", "<Y", "<Z".

Selector.normal

The face whose outward normal is nearest direction (need not be unit).

A Vector3, or three numbers.

Selector.index

The face with this index.

An int.

Axis.

X, Y, Z: the axes Selector.max and Selector.min take.

The letter after > or <.

CadaclysmSolid

class CadaclysmSolid extends RefCounted

An exact B-rep solid (or an open sheet): planes, cylinders, cones, spheres, tori and NURBS, trimmed and joined, never approximated by triangles. Immutable — every operation returns a new one. Close it when done, or let the language's scope do it; see Lifetimes.

Primitives

CadaclysmSolid.cuboid()

static func cuboid(x: float, y: float, z: float) -> CadaclysmSolid

A box x × y × z, centred on the origin.

CadaclysmSolid.cylinder()

static func cylinder(r: float, h: float) -> CadaclysmSolid

A cylinder of radius r, from z = 0 to h.

CadaclysmSolid.cone()

static func cone(r: float, h: float) -> CadaclysmSolid

A cone of base radius r and height h, apex up.

CadaclysmSolid.sphere()

static func sphere(r: float) -> CadaclysmSolid

A sphere of radius r about the origin.

CadaclysmSolid.torus()

static func torus(major: float, minor: float) -> CadaclysmSolid

A torus about the z axis: major to the tube's centre, minor the tube's radius.

CadaclysmSolid.wedge()

static func wedge(x: float, y: float, z: float, top_x: float) -> CadaclysmSolid

A box whose top face is top_x long instead of x: a ramp.

From a profile

CadaclysmSolid.extrude()

static func extrude(profile: CadaclysmProfile, frame: Variant, height: float) -> CadaclysmSolid

The profile on frame, extruded height along the frame's z.

CadaclysmSolid.extrude_open()

static func extrude_open(profile: CadaclysmProfile, frame: Variant, height: float) -> CadaclysmSolid

The walls only, no caps: an open sheet. Takes an open CadaclysmPath.end_open() chain as well as a closed profile.

CadaclysmSolid.extrude_tapered()

static func extrude_tapered(profile: CadaclysmProfile, frame: Variant, height: float, taper: float) -> CadaclysmSolid

Extrude with a draft: the walls lean out by taper radians as they rise (in, when negative). Every wall stays exact — a plane off a line, a cone off an arc.

CadaclysmSolid.extrude_open_tapered()

static func extrude_open_tapered(profile: CadaclysmProfile, frame: Variant, height: float, taper: float) -> CadaclysmSolid

The tapered walls without caps.

CadaclysmSolid.extrude_between()

static func extrude_between(profile: CadaclysmProfile, frame: Variant, bottom: Variant, top: Variant) -> CadaclysmSolid

Extrude between two planes rather than two heights: bottom and top are each a Slant (a bare number is a flat one). With both flat this is CadaclysmSolid.extrude(); with a slope it is the mitred end of a frame member. A top that comes down to or through the bottom returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.extrude_open_between()

static func extrude_open_between(profile: CadaclysmProfile, frame: Variant, bottom: Variant, top: Variant) -> CadaclysmSolid

CadaclysmSolid.extrude_between() without the caps.

CadaclysmSolid.revolve()

static func revolve(profile: CadaclysmProfile, axis_point: Variant, axis_direction: Variant, angle: float) -> CadaclysmSolid

The profile swung angle radians about axis (a point and a direction — see Frames). The profile's x is read as the radius and its y as the height along the axis, so it must lie to one side of it.

CadaclysmSolid.revolve_open()

static func revolve_open(profile: CadaclysmProfile, axis_point: Variant, axis_direction: Variant, angle: float) -> CadaclysmSolid

The revolved surface of an open profile: a sheet.

CadaclysmSolid.revolve_in_plane()

static func revolve_in_plane(profile: CadaclysmProfile, frame: Variant, a: Variant, b: Variant, angle: float) -> CadaclysmSolid

The profile on frame swung angle radians about the axis through the sketch points a and b (each (x, y) on the frame) — the profile and its axis drawn together, as a sketch draws them, where CadaclysmSolid.revolve() reads the profile as (radius, height). The profile may lie on either side of the axis and touch it (a half-disc with its diameter on the axis turns into a ball), but not cross it. The sweep starts where the profile is drawn and turns right-handed about b - a, so a partial turn leaves one end of the solid over the profile itself.

CadaclysmSolid.revolve_open_in_plane()

static func revolve_open_in_plane(profile: CadaclysmProfile, frame: Variant, a: Variant, b: Variant, angle: float) -> CadaclysmSolid

CadaclysmSolid.revolve_in_plane() for a curve: its segments swung into a sheet, no caps.

CadaclysmSolid.coil()

static func coil(profile: CadaclysmProfile, axis_point: Variant, axis_direction: Variant, pitch: float, turns: float) -> CadaclysmSolid

The profile coiled about axis (a point and a direction): read as CadaclysmSolid.revolve() reads it — x the distance from the axis, y along it — and turned turns times while climbing pitch along the axis each turn: a spring, a thread, Fusion's Coil. The walls follow the helix to a few millionths of the radius (a helix is not a NURBS curve, so they are a close fit, exact at both ends); the two ends are the profile itself, flat. A profile reaching the axis, one with holes, or — from a full turn up — a pitch no taller than the profile returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.loft()

static func loft(a: CadaclysmProfile, frame_a: Variant, b: CadaclysmProfile, frame_b: Variant) -> CadaclysmSolid

The solid between profile a on one frame and b on another: ruled walls between matching sides (both profiles need the same number of sides, and no holes), capped by the two.

CadaclysmSolid.loft_open()

static func loft_open(a: CadaclysmProfile, frame_a: Variant, b: CadaclysmProfile, frame_b: Variant) -> CadaclysmSolid

The ruled walls without the caps.

CadaclysmSolid.loft_through()

static func loft_through(sections: Array) -> CadaclysmSolid

The solid smooth through every section — a profile on its frame, in order: each wall interpolates its side across all the profiles (cubic through four or more, quadratic through three, CadaclysmSolid.loft() through two), capped by the first and the last. Every section of the result is its profile exactly, arcs and all. The profiles must have the same number of sides and no holes; otherwise returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.loft_through_open()

static func loft_through_open(sections: Array) -> CadaclysmSolid

The walls through the curves without the caps: an open sheet.

CadaclysmSolid.sweep()

static func sweep(profile: CadaclysmProfile, frame: Variant, path: CadaclysmSweepPath) -> CadaclysmSolid

The profile on frame, carried along a CadaclysmSweepPath. A straight piece is an extrusion and an arc a revolution about the arc's axis, so nothing is approximated — a circle along an arc is an exact torus wall.

CadaclysmSolid.sweep_open()

static func sweep_open(profile: CadaclysmProfile, frame: Variant, path: CadaclysmSweepPath) -> CadaclysmSolid

The swept walls without caps: an open sheet.

CadaclysmSolid.pipe()

static func pipe(path: CadaclysmSweepPath, radius: float, thickness: float = 0.0) -> CadaclysmSolid

A circle of radius carried along a CadaclysmSweepPath, square to where it starts — Fusion's Pipe: a solid rod, or with a positive thickness a tube whose walls are that thick. The path is only borrowed, as by CadaclysmSolid.sweep(), and refused the same way.

CadaclysmSolid.extrude_faces()

func extrude_faces(height: float) -> CadaclysmSolid

Every face of a sheet pushed height along its own normal, walled and closed: the sheet as a solid of that thickness.

CadaclysmSolid.face()

static func face(profile: CadaclysmProfile, frame: Variant) -> CadaclysmSolid

The flat sheet a profile bounds on frame: one planar face, each hole a hole through it, its normal the frame's z however the profile winds, every edge the exact line, arc or spline its segment is. An open sheet — raise it with CadaclysmSolid.extrude_faces(), cut it with CadaclysmSolid.trim().

Placing

CadaclysmSolid.place()

func place(frame: Variant) -> CadaclysmSolid

A solid built about the origin moved onto frame: its origin to the frame's origin, its axes to the frame's (see Frames).

CadaclysmSolid.translate()

func translate(dx: float, dy: float, dz: float) -> CadaclysmSolid

Moved by (dx, dy, dz).

CadaclysmSolid.rotate()

func rotate(axis_point: Variant, axis_direction: Variant, radians: float) -> CadaclysmSolid

Turned radians about axis (a point and a direction).

CadaclysmSolid.mirror()

func mirror(plane: Variant) -> CadaclysmSolid

Reflected across plane: a frame whose z is the mirror plane's normal.

Booleans

CadaclysmSolid.join()

func join(other: CadaclysmSolid, tolerance: float = 0.05, merge: bool = false) -> CadaclysmSolid

The union with other, as an exact B-rep. merge (off by default, so face and edge numbers stay as they were) merges the flush faces the join leaves, as CadaclysmSolid.merge_flush() does — Go takes it as a trailing true, Java as an overload; CadaclysmSolid.cut() and CadaclysmSolid.common() take it too. tolerance (0.05 by default) is the mesh tolerance the boolean decides at: both solids are meshed at it, so a tighter one is as correct and slower. progress, where the wrapper takes one, is called with a phase name and a done/total count.

CadaclysmSolid.cut()

func cut(other: CadaclysmSolid, tolerance: float = 0.05, merge: bool = false) -> CadaclysmSolid

This solid with other removed.

CadaclysmSolid.common()

func common(other: CadaclysmSolid, tolerance: float = 0.05, merge: bool = false) -> CadaclysmSolid

What this solid and other share.

CadaclysmSolid.split_sheet()

func split_sheet(tool: CadaclysmSolid, tolerance: float = 0.05) -> CadaclysmSolid

This solid or sheet cut along tool's boundary with nothing removed: each face comes back as its pieces outside tool and then its pieces inside, in the original face order — the start of a surface trim. tool must be a closed solid. Keep the pieces you want with CadaclysmSolid.drop_faces(), or split and drop in one call with CadaclysmSolid.trim().

Faces and sheets

CadaclysmSolid.face_sheet()

func face_sheet(face: int) -> CadaclysmSolid

One face alone, as an open sheet: its surface, its loops and the exact curves on its edges, the rest of the solid left behind — raised by CadaclysmSolid.extrude_faces() it is the prism over that face. Keeps the face's colour.

CadaclysmSolid.drop_faces()

func drop_faces(faces: PackedInt32Array) -> CadaclysmSolid

This solid without the faces listed: the rest keep their surfaces, curves and colours in their order, so an index into the result is this one's with the dropped ones closed up. Dropping every face returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.trim()

func trim(tool: CadaclysmSolid, keep: String = "outside", tolerance: float = 0.05) -> CadaclysmSolid

This sheet (or solid) cut along the closed tool's boundary and the pieces on one side thrown away: keep "outside" (the default) keeps what lies outside the tool — a hole punched through — and "inside" what lies within it. Nothing on the kept side returns null, false or an empty value (the reason in Cadaclysm.last_error()). tolerance and progress as for CadaclysmSolid.join().

CadaclysmSolid.push_pull()

func push_pull(face: Variant, distance: float, tolerance: float = 0.05) -> CadaclysmSolid

Face face pushed out by distance along its outward normal — pulled in, negative — the way Fusion and Rhino extrude a face: the prism over it joined on (cut out) at tolerance, and the flush faces merged, so a box's top raised is one taller box of six faces rather than a box and a prism with every side wall split at the seam. A face on a cylinder, a cone, a sphere or a torus moves out along its normal instead, as Fusion's press-pull does: the surface a step out — a boss fatter, a bore or a countersink narrower, a dome fuller — with the flat faces beside it carried along in their own planes. Any other curved face is refused, as is a curved face with anything but a plane it can follow beside it, reaching a cone's apex, pushed to its axis or centre, off a plane beside it or run into another edge. A flat face keeps its own colour where it now lies.

Several faces push together, as Fusion's press-pull on a selection: each by its own rule, one after another in the order given, each found again after the pushes before it renumbered the faces — a box's top and a side pushed 5 is the box 5 taller and 5 wider, a boss's top and wall the boss taller and fatter. A face on the same curved surface as one before it, and joined to it, moved with that one and is not pushed twice. No faces, or a face an earlier push took away, returns null, false or an empty value (the reason in Cadaclysm.last_error()).

face is a face index, or a list of them (an Array or a PackedInt32Array).

CadaclysmSolid.refillet()

func refillet(face: int, radius: float, tolerance: float = 1e-6) -> CadaclysmSolid

The round face belongs to — a fillet's bands, balls and rim bands joined to that face — made again at radius, as Fusion's press-pull on a fillet face: taken back to the sharp edges it replaced, and those rounded again, so the round is the one CadaclysmSolid.fillet() makes at that radius. Rounds of straight edges between planes (their ends square corners, mitres, balls, or a cylinder, cone or sphere the edge runs into — a D-cut shaft's top edge, a rib's into a boss) and of circular rims between a plane and a cylinder or cone (a boss's foot, a bore's mouth, a counterbore's step); a face that is not one, or a radius that does not fit, returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.unfillet()

func unfillet(face: int) -> CadaclysmSolid

The round face belongs to taken off, the faces beside it made sharp again, meeting on the edges the round replaced — Fusion's delete of a fillet face. The same rounds as CadaclysmSolid.refillet().

CadaclysmSolid.rechamfer()

func rechamfer(face: int, distance: float, tolerance: float = 1e-6) -> CadaclysmSolid

The chamfer face belongs to — its bevels (flat between two planes, cones round rims) and the corner triangles joined to that face — cut again at distance, as Fusion's press-pull on a chamfer face: taken back to the sharp edges it cut, and those bevelled again, so the chamfer is the one CadaclysmSolid.chamfer() cuts at that distance. A flat bevel's ends may run into a cylinder, cone or sphere, as a round's may. A face that is not a chamfer's bevel, or a distance that does not fit, returns null, false or an empty value (the reason in Cadaclysm.last_error()).

CadaclysmSolid.unchamfer()

func unchamfer(face: int) -> CadaclysmSolid

The chamfer face belongs to taken off, the faces beside it made sharp again — Fusion's delete of a chamfer face. The same chamfers as CadaclysmSolid.rechamfer().

CadaclysmSolid.merge_flush()

func merge_flush() -> CadaclysmSolid

This solid with its flush faces merged: flat faces on one plane, facing one way and meeting along their edges — the seams CadaclysmSolid.join() leaves where two parts are flush — made one face, and the vertices left mid-way along a straight edge taken out.

CadaclysmSolid.split()

func split(tool: CadaclysmSolid, tolerance: float = 0.05) -> Array[CadaclysmSolid]

This solid split by tool into bodies — Fusion's Split Body — returned as a list: a closed tool gives the parts outside it, then the parts inside; a flat sheet (a CadaclysmSolid.face()) splits by the whole plane it lies on. Each connected part is a body of its own, so a U cut across both arms is three. The new faces are pieces of the tool's, the colours carried over. A tool that does not cross the solid, or a curved sheet, returns null, false or an empty value (the reason in Cadaclysm.last_error()). tolerance and progress as for CadaclysmSolid.join().

CadaclysmSolid.split_by_plane()

func split_by_plane(plane: Variant, tolerance: float = 0.05) -> Array[CadaclysmSolid]

This solid split by the plane through plane's origin, square to its z (a frame): the bodies in front of it first, then those behind.

CadaclysmSolid.lumps()

func lumps() -> Array[CadaclysmSolid]

This solid's connected bodies, each a solid of its own — faces sharing an edge are one body — in the order of their first faces. One body comes back as itself; a boolean that leaves two parts gives two.

Finishing

CadaclysmSolid.edges

var edges: Array[CadaclysmEdge]  # read-only

The solid's edges as CadaclysmEdge values — what CadaclysmSolid.fillet() and CadaclysmSolid.chamfer() take. Copied; safe to keep.

CadaclysmSolid.fillet()

func fillet(edges: Variant, radius: float, tolerance: float = 1e-6) -> CadaclysmSolid

Round the given edges (CadaclysmEdge values or their indices) with radius. Exact: the blend faces are cylinders, tori and NURBS, and the neighbours are trimmed back onto them.

CadaclysmSolid.chamfer()

func chamfer(edges: Variant, distance: float, tolerance: float = 1e-6) -> CadaclysmSolid

A flat bevel instead of a round: each edge cut back distance along both its faces.

CadaclysmSolid.shell()

func shell(thickness: float, open: PackedInt32Array = PackedInt32Array(), tolerance: float = 1e-6) -> CadaclysmSolid

Hollow the solid to walls thickness thick — inward for a positive thickness, outward (the solid becoming the cavity) for a negative one. The faces listed in open are removed so the hollow is reachable.

CadaclysmSolid.thicken()

func thicken(thickness: float, tolerance: float = 1e-6) -> CadaclysmSolid

A sheet made a solid thickness thick — Fusion's Thicken: its faces, their twins moved thickness along the faces' normals (against them for a negative thickness), and a wall round every open edge. Two faces of a folded sheet meet on their offsets' mitre; a closed sheet thickens to a hollow. Free-form (NURBS) faces offset by a fit held to tolerance. A thickness a face cannot take — a radius used up, a free-form offset folding over — returns null, false or an empty value (the reason in Cadaclysm.last_error()).

Asking

CadaclysmSolid.faces

var faces: int  # read-only

How many faces.

CadaclysmSolid.face_kind()

func face_kind(face: int) -> String

A face's surface: plane, cylinder, cone, sphere, torus, nurbs, revolution, extrusion or other.

CadaclysmSolid.select_face()

func select_face(selector: Variant) -> int

The index of the face a Selector picks.

CadaclysmSolid.face_frame()

func face_frame(face: int) -> CadaclysmFrame

The frame on a face: origin at its centre, z its outward normal, x world X laid onto the face (world Y on a face facing close to X) — CadaclysmFrame.at()'s rule, so the top of a box gets the XY plane's axes. What CadaclysmWorkplane.workplane() moves onto.

CadaclysmSolid.bounds

var bounds: AABB  # read-only

The axis-aligned bounds, over the tessellation at 0.05.

CadaclysmSolid.bounds_at()

func bounds_at(tolerance: float) -> AABB

The bounds over the tessellation at tolerance — the same cache CadaclysmSolid.mesh() fills, so asking both costs one mesh.

CadaclysmSolid.leaked_edges()

func leaked_edges(tolerance: float = 0.05) -> int

How many mesh edges at tolerance are bound by anything other than two triangles: zero for a closed solid. A seam two solids share along a line does not count; a hole or a fold does.

CadaclysmSolid.unpaired_edges()

func unpaired_edges(tolerance: float = 0.05) -> int

How many mesh edges have triangle uses that do not cancel out: zero for a closed, consistently oriented solid. Unlike CadaclysmSolid.leaked_edges() this catches a fold — two triangles running the same way.

CadaclysmSolid.is_watertight()

func is_watertight(tolerance: float = 0.05) -> bool

Whether CadaclysmSolid.leaked_edges() is zero.

CadaclysmSolid.manifold

var manifold: Dictionary  # read-only

Whether the faces make a manifold — every edge bordered by one face or two, the faces round every vertex one fan — and whether it is closed, as a Manifold. Read off the solid's topology, not a mesh, so it takes no tolerance; whether the faces all face out is CadaclysmSolid.unpaired_edges()'s question.

Colour

CadaclysmSolid.coloured()

func coloured(colour: Variant, face: int = -1) -> CadaclysmSolid

A new solid coloured (r, g, b), each 0..1 — Python and Node.js also take "#rgb" or "#rrggbb" — or, given a face (Go: ColouredFace), just that face, whose colour then wins over the solid's. What is made from a coloured solid inherits: a move keeps every colour; a boolean, fillet, chamfer or shell gives each face the colour of the input face it lies on (a cut's bore takes the tool's), and a new face — a round, a shell's inner wall — the solid's. STEP output carries no colour.

Takes a Color, "#rgb"/"#rrggbb" or three numbers; face -1, the default, colours the whole solid. colour and face_colour() hand back a Color, or null.

CadaclysmSolid.colour

var colour: Variant  # read-only

The solid's own colour as (r, g, b), or none.

CadaclysmSolid.face_colour()

func face_colour(face: int) -> Variant

A face's colour as drawn: its own, else the solid's, else none.

From files

CadaclysmSolid.open()

static func open(path: String, body: int = -1) -> CadaclysmSolid

The body a CAD file holds, as a solid: STEP (AP203/214/242), ACIS .sat, Rhino .3dm, OCCT .brep, IGES or IFC, read where it draws, in the file's own units and axes. A file drawing several bodies needs body (0-based, in drawing order) or CadaclysmSolid.open_all(). What such a solid can do is what its geometry allows: fillet and chamfer want line and circle edges; booleans take any surface, but new edges traced on a free-form face are not always writable back to STEP; and every verb meshes its operands first, so its cost grows with the body's face count. Reads through the reader library, which must be from the same release.

CadaclysmSolid.open_all()

static func open_all(path: String) -> Array[CadaclysmSolid]

Every body a CAD file draws, as solids placed where it draws them: one per placement, so a part placed twice is two solids.

CadaclysmSolid.from_node()

static func from_node(node: CadaclysmNode, placed: bool = true) -> CadaclysmSolid

The body a reader CadaclysmNode draws, as a solid — sharing the reader's brep (CadaclysmNode.brep), not copying it; the scene can be closed first. placed (the default) puts it where the node's transform does, where its mesh draws; otherwise it keeps the node's own frame. The two libraries' layouts (CadaclysmBlacksmith.brep_layout_id()) must agree, or it returns null, false or an empty value (the reason in Cadaclysm.last_error()).

Output

CadaclysmSolid.mesh()

func mesh(tolerance: float = 0.05) -> CadaclysmMesh

Triangles at tolerance: positions, normals (three floats a vertex) and indices. Views into the solid's own cache — valid until the solid is closed or meshed again at a different tolerance; copy what must outlive either.

Copied out, as a CadaclysmMesh; array_mesh() builds Godot's ArrayMesh directly.

CadaclysmSolid.face_triangles

How many triangles each face meshed to at tolerance, one count per face in face order: the triangles of CadaclysmSolid.mesh() at the same tolerance run face by face, so face f's are the counts[f] after the first counts[:f].sum(), and the counts sum to the mesh's triangle count. What a viewer colours a face by. A view, like CadaclysmSolid.mesh().

Comes with the viewers follow-up.

CadaclysmSolid.edge_polylines()

func edge_polylines(tolerance: float = 0.05) -> CadaclysmPolylines

The feature edges as polylines at tolerance, one run of points per edge. Views, like CadaclysmSolid.mesh().

Copied out, as a CadaclysmPolylines.

CadaclysmSolid.show

Draw the solid with the viewer in use — in a terminal, the picture is left in the scrollback. Each face keeps its own colour (CadaclysmSolid.face_colour(): a colour of its own, else the solid's). Keywords: view= (front, back, left, right, top, bottom, iso), az=, el=, zoom=, up=, edges=, width=, height=, hint=, tolerance=.

Comes with the viewers follow-up.

CadaclysmSolid.view

Orbit the solid with the viewer in use until it is closed; returns (azimuth, elevation, zoom) where it was left. Keywords as CadaclysmSolid.show.

Comes with the viewers follow-up.

CadaclysmSolid.step()

func step(path: String, schema: String = "", unit: String = "mm") -> bool

Write this solid as an AP203 STEP file; see CadaclysmBlacksmith.write_step() for schema and unit.

CadaclysmSolid.step_text()

func step_text(schema: String = "", unit: String = "mm") -> String

The same STEP file as text.

CadaclysmSolid.to_scene()

func to_scene(schema: String = "") -> CadaclysmScene

This solid as a reader CadaclysmScene, through STEP in memory: the door from the kernel to everything the reader does — its tree, meshes, glTF/OBJ/STL export. Needs the reader library as well.

CadaclysmSolid.close()

func close() -> void

Free the solid now. The garbage collector, or the language's scope, does it otherwise.

closed Godot only

var closed: bool  # read-only

Whether CadaclysmSolid.close() has run.

raw_bounds Godot only

func raw_bounds(tolerance: float = 0.05) -> PackedFloat64Array

CadaclysmSolid.bounds_at() as six doubles, min x, y, z then max x, y, z, where an AABB holds floats; empty on failure.

array_mesh and edge_mesh Godot only

func array_mesh(tolerance: float = 0.05) -> ArrayMesh
func edge_mesh(tolerance: float = 0.05, colour: Color = Color(0.07, 0.07, 0.08)) -> ArrayMesh

The triangles at tolerance as an ArrayMesh, wound for Godot, painted the solid's colour (or grey), both sides drawn where it is an open sheet; and its feature edges as a lines ArrayMesh, unshaded in colour. Sizes are the model's own units, millimetres as a rule: scale the node that draws them into Godot's metres.

CadaclysmEdge

class CadaclysmEdge extends RefCounted

One edge of a solid as plain data, copied out of it: what CadaclysmSolid.edges lists and CadaclysmSolid.fillet() takes.

CadaclysmEdge.index

var index: int  # read-only

Its index — what CadaclysmSolid.fillet() and CadaclysmSolid.chamfer() take.

CadaclysmEdge.kind

var kind: String  # read-only

The curve: line, circle, ellipse, nurbs or other.

CadaclysmEdge.faces

var faces: PackedInt32Array  # read-only

The faces meeting on it, as face indices.

CadaclysmEdge.segments

var segments: PackedVector3Array  # read-only

The two ends of each piece of the edge.

CadaclysmEdge.is_line

var is_line: bool  # read-only

Whether the edge is straight.

CadaclysmEdge.direction

var direction: Variant  # read-only

The unit direction of a straight edge, or null for a curved one. Picking the vertical edges of a plate is a filter on this.

raw_segments Godot only

var raw_segments: PackedFloat64Array  # read-only

CadaclysmEdge.segments as doubles, six a segment, where segments holds Vector3s of floats.

Manifold

What CadaclysmSolid.manifold returns: whether the solid's faces make a manifold, and whether it is closed, told from its topology rather than a mesh.

No class: a Dictionary with these keys.

Manifold.faces

How many faces.

The faces key.

Manifold.edges

How many distinct edges: one shared by two faces counts once.

The edges key.

Manifold.vertices

How many distinct vertices.

The vertices key.

Manifold.boundary_edges

Edges only one face borders: a sheet's rim, a hole in a shell.

The boundary_edges key.

Manifold.non_manifold_edges

Edges three or more faces border: a fin, or two solids meeting along a line.

The non_manifold_edges key.

Manifold.non_manifold_vertices

Vertices whose faces make more than one fan: two solids touching at a corner.

The non_manifold_vertices key.

Manifold.is_manifold

No non-manifold edge or vertex: a manifold, possibly with a boundary.

The is_manifold key.

Manifold.is_closed

A manifold with no boundary edge either: it encloses a solid.

The is_closed key.

Errors

What the kernel refused, in its own words: a profile that crosses itself, a fillet too large for its faces, a boolean with nothing left. Raised by the call that failed, at once.

No error type: a kernel call that fails returns null (or false, -1 or an empty value), reports the reason with push_error, and leaves it in Cadaclysm.last_error(), as the reader's do.

Lifetimes

What borrows, what to close

Every class is RefCounted: an object is freed when the last reference to it goes. close() frees a CadaclysmScene, CadaclysmSolid or CadaclysmSweepPath at once, and release() a CadaclysmBrep; a node or placement of a closed scene then fails rather than reading freed memory. GDScript has no exceptions: a call that fails returns null (or false, -1 or an empty value), reports the reason with push_error, and leaves it in Cadaclysm.last_error() — the kernel's calls too — until the next call that works.

Nothing borrows: CadaclysmNode.mesh copies the triangles out of the scene into a CadaclysmMesh of packed arrays, and CadaclysmNode.edges its lines into a CadaclysmPolylines; both outlive CadaclysmScene.close(). array_mesh() and instantiate() build Godot's own ArrayMeshes, which live on too. CadaclysmSolid.mesh() is a copy as well, so meshing the solid again changes nothing already handed back.

Strings and arrays are always copied on the way out. CadaclysmScene.realize_all() meshes on every core inside the library. A scene, its nodes and its placements share one handle that is not safe to use from two threads at once: use them from one thread at a time. Cadaclysm.last_error() is per thread, so a failure is read on the thread that failed.