Skip to content

Creating a Mesh

SCADview's primary use it to help you iteratively create a mesh. When you load/reload a Python script into SCADview as you work on it, it executes the create_mesh function, and shows the returned mesh.

create_mesh Signature

The function create_mesh must:

  • Take no parameters, or all parameters must have default values.
  • Return a Trimesh, Manifold or list[Trimesh | Manifold] or... see below.

That is, the function should look like this with type hints (but type hints are not required):

from manifold3d import Manifold
from trimesh import Trimesh


def create_mesh() -> Trimesh | Manifold | list[Trimesh | Manifold]:
    ...

Interactive Parameters

Defaulted bool, int, float, and str parameters appear in the Parameters section after the script loads. Their values are passed to create_mesh by keyword when the mesh is rebuilt:

from trimesh.creation import box


def create_mesh(width: float = 2.5, include_lid: bool = True):
    mesh = box([width, width, 1])
    return mesh if include_lid else box([width, width, 0.5])

Only ordinary named and keyword-only parameters with one of those exact built-in default types are controllable. Positional-only and variadic parameters, required parameters, and defaults such as None, paths, containers, enums, NumPy scalars, and custom subclasses do not get controls. Required parameters still cause the normal load error when create_mesh is invoked.

The stack_of_balls.py example demonstrates all five supported control types in a deterministic model.

Trimesh vs Manifold

You can choose to return either Trimesh or Manifold types, or a list containing items of either type. The list does not need to have just one type.

Trimesh is simpler to use than manifold3d, which creates Manifold objects. But manifold3d is highly optimized for geometric boolean operations, and can be much faster than Trimesh. So if you are combining 100s of meshes, consider trying out manifold3d.

Toggleable Features

SCADview can expose optional geometry as UI-togglable features. Use feature on a mesh-returning function or method:

from trimesh.creation import box, cylinder

from scadview import feature


@feature
def guide():
    return box([20, 10, 8])


@feature("cutout")
def cutout():
    return cylinder(radius=3, height=20)

You can also wrap a mesh directly with feature("name", mesh):

from trimesh.creation import box

from scadview import feature


def create_mesh():
    base = box([40, 20, 10])
    guide = feature("guide", box([20, 10, 8]))
    return base.union(guide)

Feature-decorated functions and methods must return a Trimesh or Manifold. Decorating classes is not supported.

Disabled features behave like identity operands for supported boolean operations:

  • Trimesh: union(...), difference(...), intersection(...)
  • Manifold: +, -, ^

That lets you write expressions such as:

def create_mesh():
    base = box([40, 20, 10])
    return base.union(guide()).difference(cutout())

When the script is loaded, each discovered feature appears in the UI and can be toggled on or off without editing the script.

Features are enabled by default. Use feature_default to make a named feature start disabled when no UI override exists:

from trimesh.creation import box

from scadview import feature, feature_default


feature_default("supports", enabled=False)


def create_mesh():
    base = box([40, 20, 10])
    support_a = feature("supports", box([4, 4, 20]))
    support_b = feature("supports", box([4, 4, 20]))
    return base.union(support_a).union(support_b)

Defaults apply by feature name, so every mesh registered as "supports" uses the same default. If the UI has already toggled a feature, that UI state takes precedence over the script default. Repeating the same default is allowed, but declaring conflicting defaults for the same feature name raises ValueError.

Debug Features

The Features section also has a Debug features toggle. It is off by default and remains selected for the current application session. When selected, SCADview shows each enabled feature's registered source geometry as translucent debug output instead of the final mesh. This is useful for inspecting subtractive tool volumes, which may not contribute triangles to the final model.

Debug features does not change whether a feature is enabled. Clearing a feature checkbox omits that feature from the debug output; selecting Debug features again does not re-enable it. Because this is diagnostic output, Export is unavailable while it is displayed. Debug features shows only source meshes registered with feature(...); meshes not marked as features are omitted from this visualization.

Debug Mode: Return a list

Returning a list of objects results in SCADview displaying each object in the list. It is intended to be used for debugging purposes. Sometimes, if you are getting unexpected results, returning the objects in the list rather than as a single mesh before you've combined them, you can see what went wrong.

Note when returning a list, the "Export" feature is not available.

Using Color and Transparency

set_mesh_color may be applied to a Trimesh, which affects its color and transparency. This allows you to see different meshes in the list in different colors, and make them transparent so you can see other meshes hidden inside. set_mesh_color only works for Trimesh objects, and colors do not survive boolean operations.

set_mesh_color can also be useful when returning a single Trimesh, for example if you are removing hidded voids.

Output and Logging

Console output goes to the terminal where you launched scadview. You can use print(...) or Python's logging module inside your script. If you need more detail, you can set the logging level in your script.

Incremental Builds

Displaying intermediate builds of your mesh as you build it can be useful to see problems before a long build completes. It also give you a sense of how long the build might take.

SCADview supports incremental builds. To do this, create_mesh can be defined as a Generator, with the signature:

def create_mesh() ->  Generator[[Trimesh | Manifold | list[Trimesh | Manifold]]:
    yield ...
For example:
def create_mesh():
    ..create mesh1
    yield mesh1
    ...create mesh2
    yield mesh2

As this adds additional renders, building incrementatlly is generally slower than a single build. If you yield very quickly (many times per second), some renders may be skipped to keep the speed up.

As with create_mesh as a "regular" function, you can yield a singular mesh or a list of them. As above, yielding a list also puts SCADview into debug mode.

Animation

By pausing between each yield, you can animate at a consistent frame rate.

For example:

from time import sleep

from trimesh.creation import box


def create_mesh():
    b = box([10, 10, 20])
    for _ in range(100):
        yield b
        sleep(0.1)
        b.apply_translation([0.2, 0, 0])