simvx.core.csg¶

Constructive Solid Geometry (CSG) for boolean mesh operations.

Provides CSG shape nodes that generate meshes and a combiner node that performs boolean operations (union, subtract, intersect) on child CSG shapes using a BSP-tree algorithm.

Usage::

from simvx.core.csg import CSGBox3D, CSGSphere3D, CSGCombiner3D, CSGOperation

combiner = CSGCombiner3D(operation=CSGOperation.SUBTRACT)
combiner.add_child(CSGBox3D(size=(2, 2, 2)))
combiner.add_child(CSGSphere3D(radius=1.2))
mesh = combiner.get_mesh()  # Box with sphere carved out

Module Contents¶

Classes¶

CSGOperation

Boolean operation type for CSG combining.

CSGShape3D

Base class for CSG shape nodes.

CSGBox3D

CSG box primitive. Generates an axis-aligned box mesh.

CSGSphere3D

CSG sphere primitive. Generates a UV sphere mesh.

CSGCylinder3D

CSG cylinder primitive. Generates a cylinder mesh along the Y axis.

CSGCombiner3D

Combines child CSG shapes using boolean operations.

Functions¶

csg_combine

Perform a CSG boolean operation on two meshes.

Data¶

API¶

simvx.core.csg.log[source]¶

‘getLogger(…)’

simvx.core.csg.__all__¶

[‘CSGOperation’, ‘CSGShape3D’, ‘CSGBox3D’, ‘CSGSphere3D’, ‘CSGCylinder3D’, ‘CSGCombiner3D’]

class simvx.core.csg.CSGOperation[source]¶

Bases: enum.IntEnum

Boolean operation type for CSG combining.

Initialization

Initialize self. See help(type(self)) for accurate signature.

UNION¶

0

SUBTRACT¶

1

INTERSECT¶

2

__abs__()¶
__add__()¶
__and__()¶
__bool__()¶
__ceil__()¶
__delattr__()¶
__dir__()¶
__divmod__()¶
__eq__()¶
__float__()¶
__floor__()¶
__floordiv__()¶
__format__()¶
__ge__()¶
__getattribute__()¶
__getnewargs__()¶
__getstate__()¶
__gt__()¶
__hash__()¶
__index__()¶
__int__()¶
__invert__()¶
__le__()¶
__lshift__()¶
__lt__()¶
__mod__()¶
__mul__()¶
__ne__()¶
__neg__()¶
__new__()¶
__or__()¶
__pos__()¶
__pow__()¶
__radd__()¶
__rand__()¶
__rdivmod__()¶
__reduce__()¶
__reduce_ex__()¶
__repr__()¶
__rfloordiv__()¶
__rlshift__()¶
__rmod__()¶
__rmul__()¶
__ror__()¶
__round__()¶
__rpow__()¶
__rrshift__()¶
__rshift__()¶
__rsub__()¶
__rtruediv__()¶
__rxor__()¶
__setattr__()¶
__sizeof__()¶
__str__()¶
__sub__()¶
__subclasshook__()¶
__truediv__()¶
__trunc__()¶
__xor__()¶
as_integer_ratio()¶
bit_count()¶
bit_length()¶
conjugate()¶
class denominator¶
class imag¶
is_integer()¶
class numerator¶
class real¶
to_bytes()¶
__deepcopy__(memo)¶
__copy__()¶
name()¶
value()¶
simvx.core.csg.csg_combine(mesh_a: simvx.core.graphics.mesh.Mesh, mesh_b: simvx.core.graphics.mesh.Mesh, operation: simvx.core.csg.CSGOperation) simvx.core.graphics.mesh.Mesh[source]¶

Perform a CSG boolean operation on two meshes.

Args: mesh_a: First operand mesh. mesh_b: Second operand mesh. operation: The boolean operation to apply.

Returns: A new Mesh with the result of the boolean operation.

class simvx.core.csg.CSGShape3D(operation: simvx.core.csg.CSGOperation = CSGOperation.UNION, **kwargs)[source]¶

Bases: simvx.core.nodes_3d.node3d.Node3D

Base class for CSG shape nodes.

Holds a computed mesh and an operation type used when combined by a CSGCombiner3D parent. Subclasses override _build_mesh() to generate their primitive geometry.

Initialization

operation¶

‘Property(…)’

get_mesh() simvx.core.graphics.mesh.Mesh[source]¶

Return the (possibly cached) mesh for this shape.

render_layer¶

‘Property(…)’

property position¶
property rotation: simvx.core.math.types.Quat¶
property scale¶
property rotation_degrees: simvx.core.math.types.Vec3¶
property world_position: simvx.core.math.types.Vec3¶
property world_rotation: simvx.core.math.types.Quat¶
property world_scale: simvx.core.math.types.Vec3¶
property forward: simvx.core.math.types.Vec3¶
property right: simvx.core.math.types.Vec3¶
property up: simvx.core.math.types.Vec3¶
translate(offset: tuple[float, float, float] | numpy.ndarray)¶
translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
rotate_x(angle: float)¶
rotate_y(angle: float)¶
rotate_z(angle: float)¶
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
set_render_layer(index: int, enabled: bool = True) None¶
is_on_render_layer(index: int) bool¶
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
strict_errors: ClassVar[bool]¶

True

script_error_raised¶

‘Signal(…)’

classmethod __init_subclass__(**kwargs)¶
property name: str¶
property process_mode: simvx.core.descriptors.ProcessMode¶
reset_error() None¶
add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
remove_child(node: simvx.core.node.Node)¶
reparent(new_parent: simvx.core.node.Node)¶
get_node(path: str) simvx.core.node.Node¶
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
find_all(node_type: type, recursive: bool = True) list¶
property path: str¶
add_to_group(group: str)¶
remove_from_group(group: str)¶
is_in_group(group: str) bool¶
ready() None¶
enter_tree() None¶
exit_tree() None¶
process(dt: float) None¶
physics_process(dt: float) None¶
draw(renderer) None¶
input_event(event: simvx.core.events.InputEvent) None¶
input(event: simvx.core.events.TreeInputEvent) None¶
unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
stop_coroutine(gen_or_handle)¶
clear_children()¶
destroy()¶
property app¶
property tree: simvx.core.scene_tree.SceneTree¶
get_tree() simvx.core.scene_tree.SceneTree¶
__getitem__(key: str)¶
classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
__repr__()¶
class simvx.core.csg.CSGBox3D(size: simvx.core.math.types.Vec3 | collections.abc.Sequence[float] | None = None, **kwargs)[source]¶

Bases: simvx.core.csg.CSGShape3D

CSG box primitive. Generates an axis-aligned box mesh.

Attributes: size: Box dimensions as Vec3 (width, height, depth).

Initialization

size¶

‘Property(…)’

operation¶

‘Property(…)’

get_mesh() simvx.core.graphics.mesh.Mesh¶
render_layer¶

‘Property(…)’

property position¶
property rotation: simvx.core.math.types.Quat¶
property scale¶
property rotation_degrees: simvx.core.math.types.Vec3¶
property world_position: simvx.core.math.types.Vec3¶
property world_rotation: simvx.core.math.types.Quat¶
property world_scale: simvx.core.math.types.Vec3¶
property forward: simvx.core.math.types.Vec3¶
property right: simvx.core.math.types.Vec3¶
property up: simvx.core.math.types.Vec3¶
translate(offset: tuple[float, float, float] | numpy.ndarray)¶
translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
rotate_x(angle: float)¶
rotate_y(angle: float)¶
rotate_z(angle: float)¶
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
set_render_layer(index: int, enabled: bool = True) None¶
is_on_render_layer(index: int) bool¶
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
strict_errors: ClassVar[bool]¶

True

script_error_raised¶

‘Signal(…)’

classmethod __init_subclass__(**kwargs)¶
property name: str¶
property process_mode: simvx.core.descriptors.ProcessMode¶
reset_error() None¶
add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
remove_child(node: simvx.core.node.Node)¶
reparent(new_parent: simvx.core.node.Node)¶
get_node(path: str) simvx.core.node.Node¶
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
find_all(node_type: type, recursive: bool = True) list¶
property path: str¶
add_to_group(group: str)¶
remove_from_group(group: str)¶
is_in_group(group: str) bool¶
ready() None¶
enter_tree() None¶
exit_tree() None¶
process(dt: float) None¶
physics_process(dt: float) None¶
draw(renderer) None¶
input_event(event: simvx.core.events.InputEvent) None¶
input(event: simvx.core.events.TreeInputEvent) None¶
unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
stop_coroutine(gen_or_handle)¶
clear_children()¶
destroy()¶
property app¶
property tree: simvx.core.scene_tree.SceneTree¶
get_tree() simvx.core.scene_tree.SceneTree¶
__getitem__(key: str)¶
classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
__repr__()¶
class simvx.core.csg.CSGSphere3D(radius: float = 1.0, rings: int = 16, sectors: int = 16, **kwargs)[source]¶

Bases: simvx.core.csg.CSGShape3D

CSG sphere primitive. Generates a UV sphere mesh.

Attributes: radius: Sphere radius. rings: Number of horizontal rings (latitude divisions). sectors: Number of vertical sectors (longitude divisions).

Initialization

radius¶

‘Property(…)’

rings¶

‘Property(…)’

sectors¶

‘Property(…)’

operation¶

‘Property(…)’

get_mesh() simvx.core.graphics.mesh.Mesh¶
render_layer¶

‘Property(…)’

property position¶
property rotation: simvx.core.math.types.Quat¶
property scale¶
property rotation_degrees: simvx.core.math.types.Vec3¶
property world_position: simvx.core.math.types.Vec3¶
property world_rotation: simvx.core.math.types.Quat¶
property world_scale: simvx.core.math.types.Vec3¶
property forward: simvx.core.math.types.Vec3¶
property right: simvx.core.math.types.Vec3¶
property up: simvx.core.math.types.Vec3¶
translate(offset: tuple[float, float, float] | numpy.ndarray)¶
translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
rotate_x(angle: float)¶
rotate_y(angle: float)¶
rotate_z(angle: float)¶
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
set_render_layer(index: int, enabled: bool = True) None¶
is_on_render_layer(index: int) bool¶
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
strict_errors: ClassVar[bool]¶

True

script_error_raised¶

‘Signal(…)’

classmethod __init_subclass__(**kwargs)¶
property name: str¶
property process_mode: simvx.core.descriptors.ProcessMode¶
reset_error() None¶
add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
remove_child(node: simvx.core.node.Node)¶
reparent(new_parent: simvx.core.node.Node)¶
get_node(path: str) simvx.core.node.Node¶
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
find_all(node_type: type, recursive: bool = True) list¶
property path: str¶
add_to_group(group: str)¶
remove_from_group(group: str)¶
is_in_group(group: str) bool¶
ready() None¶
enter_tree() None¶
exit_tree() None¶
process(dt: float) None¶
physics_process(dt: float) None¶
draw(renderer) None¶
input_event(event: simvx.core.events.InputEvent) None¶
input(event: simvx.core.events.TreeInputEvent) None¶
unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
stop_coroutine(gen_or_handle)¶
clear_children()¶
destroy()¶
property app¶
property tree: simvx.core.scene_tree.SceneTree¶
get_tree() simvx.core.scene_tree.SceneTree¶
__getitem__(key: str)¶
classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
__repr__()¶
class simvx.core.csg.CSGCylinder3D(radius: float = 0.5, height: float = 1.0, segments: int = 16, **kwargs)[source]¶

Bases: simvx.core.csg.CSGShape3D

CSG cylinder primitive. Generates a cylinder mesh along the Y axis.

Attributes: radius: Cylinder radius. height: Total height. segments: Number of radial segments.

Initialization

radius¶

‘Property(…)’

height¶

‘Property(…)’

segments¶

‘Property(…)’

operation¶

‘Property(…)’

get_mesh() simvx.core.graphics.mesh.Mesh¶
render_layer¶

‘Property(…)’

property position¶
property rotation: simvx.core.math.types.Quat¶
property scale¶
property rotation_degrees: simvx.core.math.types.Vec3¶
property world_position: simvx.core.math.types.Vec3¶
property world_rotation: simvx.core.math.types.Quat¶
property world_scale: simvx.core.math.types.Vec3¶
property forward: simvx.core.math.types.Vec3¶
property right: simvx.core.math.types.Vec3¶
property up: simvx.core.math.types.Vec3¶
translate(offset: tuple[float, float, float] | numpy.ndarray)¶
translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
rotate_x(angle: float)¶
rotate_y(angle: float)¶
rotate_z(angle: float)¶
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
set_render_layer(index: int, enabled: bool = True) None¶
is_on_render_layer(index: int) bool¶
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
strict_errors: ClassVar[bool]¶

True

script_error_raised¶

‘Signal(…)’

classmethod __init_subclass__(**kwargs)¶
property name: str¶
property process_mode: simvx.core.descriptors.ProcessMode¶
reset_error() None¶
add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
remove_child(node: simvx.core.node.Node)¶
reparent(new_parent: simvx.core.node.Node)¶
get_node(path: str) simvx.core.node.Node¶
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
find_all(node_type: type, recursive: bool = True) list¶
property path: str¶
add_to_group(group: str)¶
remove_from_group(group: str)¶
is_in_group(group: str) bool¶
ready() None¶
enter_tree() None¶
exit_tree() None¶
process(dt: float) None¶
physics_process(dt: float) None¶
draw(renderer) None¶
input_event(event: simvx.core.events.InputEvent) None¶
input(event: simvx.core.events.TreeInputEvent) None¶
unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
stop_coroutine(gen_or_handle)¶
clear_children()¶
destroy()¶
property app¶
property tree: simvx.core.scene_tree.SceneTree¶
get_tree() simvx.core.scene_tree.SceneTree¶
__getitem__(key: str)¶
classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
__repr__()¶
class simvx.core.csg.CSGCombiner3D(**kwargs)[source]¶

Bases: simvx.core.csg.CSGShape3D

Combines child CSG shapes using boolean operations.

The first child is the base shape. Each subsequent child is combined with the accumulated result using that child’s operation property.

Usage::

combiner = CSGCombiner3D()
combiner.add_child(CSGBox3D(size=(2, 2, 2)))
combiner.add_child(CSGSphere3D(radius=1.2, operation=CSGOperation.SUBTRACT))
result = combiner.get_mesh()

Initialization

get_mesh() simvx.core.graphics.mesh.Mesh[source]¶

Combine all child CSG shapes and return the resulting mesh.

operation¶

‘Property(…)’

render_layer¶

‘Property(…)’

property position¶
property rotation: simvx.core.math.types.Quat¶
property scale¶
property rotation_degrees: simvx.core.math.types.Vec3¶
property world_position: simvx.core.math.types.Vec3¶
property world_rotation: simvx.core.math.types.Quat¶
property world_scale: simvx.core.math.types.Vec3¶
property forward: simvx.core.math.types.Vec3¶
property right: simvx.core.math.types.Vec3¶
property up: simvx.core.math.types.Vec3¶
translate(offset: tuple[float, float, float] | numpy.ndarray)¶
translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
rotate_x(angle: float)¶
rotate_y(angle: float)¶
rotate_z(angle: float)¶
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
set_render_layer(index: int, enabled: bool = True) None¶
is_on_render_layer(index: int) bool¶
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
strict_errors: ClassVar[bool]¶

True

script_error_raised¶

‘Signal(…)’

classmethod __init_subclass__(**kwargs)¶
property name: str¶
property process_mode: simvx.core.descriptors.ProcessMode¶
reset_error() None¶
add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
remove_child(node: simvx.core.node.Node)¶
reparent(new_parent: simvx.core.node.Node)¶
get_node(path: str) simvx.core.node.Node¶
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
find_all(node_type: type, recursive: bool = True) list¶
property path: str¶
add_to_group(group: str)¶
remove_from_group(group: str)¶
is_in_group(group: str) bool¶
ready() None¶
enter_tree() None¶
exit_tree() None¶
process(dt: float) None¶
physics_process(dt: float) None¶
draw(renderer) None¶
input_event(event: simvx.core.events.InputEvent) None¶
input(event: simvx.core.events.TreeInputEvent) None¶
unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
stop_coroutine(gen_or_handle)¶
clear_children()¶
destroy()¶
property app¶
property tree: simvx.core.scene_tree.SceneTree¶
get_tree() simvx.core.scene_tree.SceneTree¶
__getitem__(key: str)¶
classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
__repr__()¶