kumiki.csg.cutcsg¶
Flat import path
kumiki/__init__.py re-exports everything on this page via from kumiki import *, so every name below is also available directly as kumiki.AxisAlignedBoundingBox -- you do not need to import from the submodule path shown in the heading above.
kumiki.csg.cutcsg
¶
CutCSG: CSG primitives and operations for timbers and their cuts, and the features they declare.
Values are plain floats compared through the safe_* helpers (see rule.py).
- Point tests (contains_point, is_point_on_boundary, get_outward_normal) take an optional
epsfor float error. - Feature queries (find_all_features, find_first_feature, CSGFeature.test_point_unbounded) take a FeatureTestTolerances instead: slack for mesh-vs-analytic error and click imprecision.
DEFAULT_FEATURE_TEST_TOLERANCES
module-attribute
¶
DEFAULT_FEATURE_TEST_TOLERANCES = FeatureTestTolerances()
FEATURE_GROUP_PAIRS
module-attribute
¶
FEATURE_GROUP_PAIRS: dict = {FeatureGroup.SHOULDER_PLANE: frozenset({FeatureGroup.PERFECT, FeatureGroup.ROUGH, FeatureGroup.TENON}), FeatureGroup.PERFECT: frozenset({FeatureGroup.SHOULDER_PLANE, FeatureGroup.CROSSING}), FeatureGroup.ROUGH: frozenset({FeatureGroup.SHOULDER_PLANE, FeatureGroup.CROSSING}), FeatureGroup.TENON: frozenset({FeatureGroup.SHOULDER_PLANE}), FeatureGroup.CROSSING: frozenset({FeatureGroup.PERFECT, FeatureGroup.ROUGH}), FeatureGroup.NONE: frozenset()}
AxisAlignedBoundingBox
dataclass
¶
Axis-aligned bounding box of a CSG. A None bound is unbounded that way.
When is_empty, the solid has no points and the bounds are meaningless; check it first.
FeatureCategory
¶
Bases: Enum
Kind of place on a primitive's boundary a default feature names, shared by every primitive.
Paired with an index where a primitive has several (index 0 for one-offs).
PrismFace
¶
Bases: Enum
Face of a RectangularPrism; indices match TimberFace.
ExtrusionCap
¶
CylinderPart
¶
CSGFeatureType
¶
Bases: Enum
Kind of geometry a feature names: face, curved face, edge or point.
Measurements dispatch on the pair of types.
TODO consider adding DERIVED_POINT and DERIVED_FACE here
FeatureTestTolerances
dataclass
¶
How close a point must be to count as on a feature, per feature type.
Faces need only the mesh-vs-analytic gap; edges and points need more, since they are snapped to. A viewport usually scales these by world units per pixel.
for_type
¶
for_type(feature_type: CSGFeatureType) -> Numeric
Return the tolerance for feature_type.
Source code in kumiki/csg/cutcsg.py
__mul__
¶
__mul__(factor: Numeric) -> FeatureTestTolerances
Return these tolerances scaled by factor (e.g. world units per pixel).
Source code in kumiki/csg/cutcsg.py
__rmul__
¶
__rmul__(factor: Numeric) -> FeatureTestTolerances
__truediv__
¶
__truediv__(divisor: Numeric) -> FeatureTestTolerances
uniform
staticmethod
¶
uniform(eps: Numeric) -> FeatureTestTolerances
exact
staticmethod
¶
exact() -> FeatureTestTolerances
Return analytic tolerances, for geometry that was never triangulated.
FeatureGroup
¶
Bases: Enum
Which features a feature may derive an edge with:
SHOULDER_PLANE with PERFECT, ROUGH and TENON
PERFECT with SHOULDER_PLANE and CROSSING
ROUGH with SHOULDER_PLANE and CROSSING
TENON with SHOULDER_PLANE
CROSSING with PERFECT and ROUGH
NONE with nothing
- PERFECT: the perfect timber within's faces, arrises, corners and centerplanes, and rough faces lying on it (rptw.*).
- ROUGH: the rough body's faces.
- SHOULDER_PLANE: a joint's shoulder plane. TENON: a joint's tenon faces.
- CROSSING: the faces a cross lap removes.
PERFECT and ROUGH don't pair with themselves: a timber's own arrises and corners are declared. The order is the pick preference, best first.
FeatureMarkingStatus
¶
FeatureMarkingSpec
dataclass
¶
How to mark a feature on a drawing, when not the default.
mark_relative_to names the feature to dimension it from: the nearest feature of that name in the
CSG tree. Auto dimensioning prefers that measurement; naming each other makes a symmetric pair.
mark
class-attribute
instance-attribute
¶
FeaturePurpose
¶
Datum
¶
FeatureNature
¶
Bases: Enum
Where a feature lives, which sets how far it reaches:
- REAL: on the surface (a face, an arris); cropped by the cuts.
- AUXILIARY: in a void (a bore's axis); bounded by its own extent.
- PERFECT_REFERENCE: inside the material (the perfect timber within); cropped to the solid.
FeatureProperties
dataclass
¶
Metadata every feature carries.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
group
|
which features this one may derive edges with (FeatureGroup). NONE by default. |
required | |
priority
|
lower wins when several features claim a point. |
required | |
nature
|
FeatureNature. Only REAL features are tested against the triangulated result. |
required | |
marking_override
|
how to mark it on a drawing. |
required | |
purpose
|
what it is for (FeaturePurpose). |
required | |
datum
|
how much to measure from it (Datum). |
required |
marking_override
class-attribute
instance-attribute
¶
marking_override: Optional[FeatureMarkingSpec] = None
CSGFeature
dataclass
¶
Bases: ABC
A feature on a CutCSG's boundary, or a non-real one (e.g. a cylinder's axis).
Doesn't know its owner; methods take the owner node to place it in the owner's space.
properties
class-attribute
instance-attribute
¶
properties: FeatureProperties = field(default_factory=FeatureProperties)
feature_key
¶
feature_key() -> Optional[FeatureKey]
feature_type
abstractmethod
¶
feature_type() -> CSGFeatureType
locate_simple_unbounded
¶
locate_simple_unbounded(owner: CutCSG) -> Optional[LocatedFeatureGeometry]
Return the feature's unbounded Plane, Line or Point in owner's space.
None for a curved surface (a barrel, a lofted side, a curved path side).
Source code in kumiki/csg/cutcsg.py
declared_ends
¶
solve_recipe
¶
Return the carriers of owner that produce this feature, or None.
Source code in kumiki/csg/cutcsg.py
is_derived
¶
group_rank
¶
Return this feature's group's pick preference rank (derived features take their better parent's).
test_point_unbounded
abstractmethod
¶
Return whether point is on this feature's surface, ignoring its bounds.
owner places the feature. collect_feature_hits gates real features on the boundary.
Source code in kumiki/csg/cutcsg.py
FaceFeature
dataclass
¶
EdgeFeature
dataclass
¶
Bases: CSGFeature
A straight edge or axis. Locates to a Line.
feature_type
¶
feature_type() -> CSGFeatureType
PointFeature
dataclass
¶
CurvedFaceFeature
dataclass
¶
Bases: CSGFeature
A curved face. Locates to nothing: no plane, line or point describes it.
feature_type
¶
feature_type() -> CSGFeatureType
ProgrammableFaceFeature
dataclass
¶
Bases: _ProgrammableFeature, FaceFeature
ProgrammableEdgeFeature
dataclass
¶
Bases: _ProgrammableFeature, EdgeFeature
ProgrammablePointFeature
dataclass
¶
Bases: _ProgrammableFeature, PointFeature
DerivedEdgeFeature
dataclass
¶
Bases: EdgeFeature
The edge where two planar face features meet. Owned by their shared_ancestor.
test_point_unbounded
¶
Return whether point is on the edge's line (tested directly, since near-parallel faces make face tests unreliable).
Source code in kumiki/csg/cutcsg.py
locate_simple_unbounded
¶
declared_ends
¶
Return the edge's ends as bounded by its parent faces' corners, or None if they can't bound it.
Exact along a face's own axes (every arris of a box); otherwise an over-estimate.
TODO make it exact for oblique lines
Source code in kumiki/csg/cutcsg.py
solve_recipe
¶
derive
staticmethod
¶
derive(a: OwnedFeatureHit, b: OwnedFeatureHit, any_groups: bool = False) -> Optional[DerivedEdgeFeature]
Return the edge where a and b meet, or None.
None if either isn't a face, their groups can't meet (unless any_groups), either face isn't there
(e.g. an infinite prism's cap), or their planes are parallel.
Source code in kumiki/csg/cutcsg.py
is_derived
¶
group_rank
¶
DerivedPointFeature
dataclass
¶
Bases: PointFeature
The point where an edge feature crosses a face feature.
is_derived
¶
group_rank
¶
test_point_unbounded
¶
Return whether point is on the vertex itself.
Source code in kumiki/csg/cutcsg.py
locate_simple_unbounded
¶
solve_recipe
¶
derive
staticmethod
¶
derive(a: OwnedFeatureHit, b: OwnedFeatureHit) -> Optional[DerivedPointFeature]
Return the point where a and b cross, or None.
None unless they are one edge and one face whose groups can meet, both are there, and the line pierces the plane at one point (not lying in it).
Source code in kumiki/csg/cutcsg.py
HalfSpaceFeature
dataclass
¶
Bases: FaceFeature
The boundary plane of a HalfSpace.
feature_key
¶
feature_key() -> Optional[FeatureKey]
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
SimpleRectangularPrismFeature
dataclass
¶
Bases: FaceFeature
One of the six faces of a RectangularPrism, named by PrismFace.
feature_key
¶
feature_key() -> Optional[FeatureKey]
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
corners
¶
Return the face's four corners, or None if unbounded.
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
PlaneFeature
dataclass
¶
Bases: FaceFeature
An extra plane on a primitive, with its own solver carrier. Not real by default.
normal . x = offset in the owner's frame (before its transform).
normal
class-attribute
instance-attribute
¶
properties
class-attribute
instance-attribute
¶
properties: FeatureProperties = field(default_factory=lambda: FeatureProperties(nature=FeatureNature.AUXILIARY))
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
solve_recipe
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
MidplaneFeature
dataclass
¶
Bases: FaceFeature
The plane midway between two parallel planes of its owner. Not real by default.
Each of between is a feature name or a default FeatureKey. Solved from those two planes; locates
to None if they aren't parallel.
between
class-attribute
instance-attribute
¶
between: Tuple[Union[str, FeatureKey], Union[str, FeatureKey]] = ('', '')
properties
class-attribute
instance-attribute
¶
properties: FeatureProperties = field(default_factory=lambda: FeatureProperties(nature=FeatureNature.AUXILIARY))
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
solve_recipe
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
SimpleRectangularPrismEdgeFeature
dataclass
¶
Bases: EdgeFeature
An arris of a RectangularPrism, named by its two faces.
faces
class-attribute
instance-attribute
¶
__post_init__
¶
Source code in kumiki/csg/cutcsg.py
of
classmethod
¶
of(name: str, first: PrismFace, second: PrismFace, properties: Optional[FeatureProperties] = None) -> SimpleRectangularPrismEdgeFeature
Return the arris between two faces, given in either order.
Source code in kumiki/csg/cutcsg.py
feature_key
¶
feature_key() -> Optional[FeatureKey]
solve_recipe
¶
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
locate_simple_unbounded
¶
Return the line the two faces meet in, or None.
Source code in kumiki/csg/cutcsg.py
declared_ends
¶
Return the two prism corners the arris runs between, or None if the prism is unbounded there.
Source code in kumiki/csg/cutcsg.py
SimpleRectangularPrismVertexFeature
dataclass
¶
Bases: PointFeature
A corner of a RectangularPrism, named by its three faces; numbered to match TimberCorner.
faces
class-attribute
instance-attribute
¶
faces: Tuple[PrismFace, PrismFace, PrismFace] = (PrismFace.BOTTOM, PrismFace.RIGHT, PrismFace.FRONT)
__post_init__
¶
Source code in kumiki/csg/cutcsg.py
of
classmethod
¶
of(name: str, *faces: PrismFace, properties: Optional[FeatureProperties] = None) -> SimpleRectangularPrismVertexFeature
Return the corner of three faces, given in any order.
Source code in kumiki/csg/cutcsg.py
feature_key
¶
feature_key() -> Optional[FeatureKey]
solve_recipe
¶
locate_simple_unbounded
¶
test_point_unbounded
¶
CylinderAxisFeature
dataclass
¶
Bases: EdgeFeature
The centre line of a Cylinder.
solve_recipe
¶
locate_simple_unbounded
¶
declared_ends
¶
Return the axis's ends at the cylinder's caps, or None if either is infinite.
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Return whether point is on the axis line (ends not checked).
Source code in kumiki/csg/cutcsg.py
SimpleCylinderCapFeature
dataclass
¶
Bases: FaceFeature
An end cap of a Cylinder; part is TOP or BOTTOM.
feature_key
¶
feature_key() -> Optional[FeatureKey]
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
SimpleCylinderBarrelFeature
dataclass
¶
Bases: CurvedFaceFeature
The curved side of a Cylinder.
feature_key
¶
feature_key() -> Optional[FeatureKey]
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
SimpleConvexPolygonExtrusionFeature
dataclass
¶
Bases: FaceFeature
A side (points[key] to points[key+1]) or end cap of a ConvexPolygonExtrusion.
feature_key
¶
feature_key() -> Optional[FeatureKey]
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
SimpleLoftFeature
dataclass
¶
Bases: FaceFeature
A side or end cap of a ConvexPolygonSimpleLoft. Sides are planar only for a pure taper.
feature_key
¶
feature_key() -> Optional[FeatureKey]
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
ConvexProfileEdgeFeature
dataclass
¶
Bases: EdgeFeature
An edge of a ConvexPolygonExtrusion or ConvexPolygonSimpleLoft.
faces is a side and the next side (a long edge), or a side and a cap (a profile edge).
feature_key
¶
feature_key() -> Optional[FeatureKey]
solve_recipe
¶
Source code in kumiki/csg/cutcsg.py
test_point_unbounded
¶
Source code in kumiki/csg/cutcsg.py
locate_simple_unbounded
¶
Source code in kumiki/csg/cutcsg.py
declared_ends
¶
Return the edge's two ends, or None if either is at an infinite end.
FeatureSource
¶
FeatureOverride
dataclass
¶
Overrides the name and properties of a default feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
the default, e.g. prism_face_key(PrismFace.RIGHT). |
required | |
name
|
new name; None keeps the default's. |
required | |
properties
|
replaces the default's properties; None keeps them. |
required |
apply
¶
apply(default: CSGFeature) -> CSGFeature
Return the default feature at key with this override applied.
Source code in kumiki/csg/cutcsg.py
HasFeatures
dataclass
¶
Mixin for primitives that declare their own features.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feature_overrides
|
overrides of this shape's defaults, at most one per key. |
required | |
extra_features
|
keyless features with their own geometry (a bore's axis, a reference plane). |
required |
Both are validated on construction.
feature_overrides
class-attribute
instance-attribute
¶
feature_overrides: Sequence[FeatureOverride] = field(default=(), kw_only=True)
extra_features
class-attribute
instance-attribute
¶
extra_features: Sequence[CSGFeature] = field(default=(), kw_only=True)
__post_init__
¶
default_features
¶
default_features() -> Dict[FeatureKey, CSGFeature]
get_declared_features
¶
get_declared_features(source: FeatureSource = BOTH) -> List[CSGFeature]
Return the features this node declares (defaults with overrides applied, plus extras), cached per node.
Source code in kumiki/csg/cutcsg.py
OwnedFeatureHit
dataclass
¶
Bases: Generic[F_co]
A feature with the node that owns it.
feature_type
¶
feature_type() -> CSGFeatureType
locate_simple_unbounded
¶
locate_simple_unbounded() -> Optional[LocatedFeatureGeometry]
CutCSGLabel
dataclass
¶
A CSG node's optional name.
CutCSG
dataclass
¶
Bases: ABC
Base class of CSG nodes.
label
class-attribute
instance-attribute
¶
label: CutCSGLabel = field(default_factory=CutCSGLabel.NoLabel, kw_only=True)
__init_subclass__
¶
__repr__
abstractmethod
¶
display_name
classmethod
¶
get_declared_features
¶
get_declared_features(source: FeatureSource = BOTH) -> List[CSGFeature]
Return the features this node declares. Empty for compound nodes.
carriers
abstractmethod
¶
carriers() -> Dict[FeatureKey, Carrier]
Return this node's solver carriers by key.
TODO decide whether to drop NEVER_MARK features' carriers, or tag OPTIONAL ones
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
collect_feature_hits
¶
collect_feature_hits(point: V3, tolerances: FeatureTestTolerances) -> List[OwnedFeatureHit]
Return every declared feature in this subtree that point is on, each at its type's tolerance.
Real features also require point on this node's boundary; non-real ones don't.
Source code in kumiki/csg/cutcsg.py
find_all_features
¶
find_all_features(point: V3, test_tolerances: Optional[FeatureTestTolerances] = None) -> List[OwnedFeatureHit]
Return every feature at point, best first: declared ones in this subtree plus derived edges
and points.
Faces are paired into edges at the EDGE tolerance, and declared edges crossed with faces at the POINT tolerance, so edges and points can be picked from further away than their faces. Derived duplicates are dropped at the end.
Source code in kumiki/csg/cutcsg.py
find_first_feature
¶
find_first_feature(point: V3, test_tolerances: Optional[FeatureTestTolerances] = None) -> Optional[OwnedFeatureHit]
Return the best feature at point (see _sort_feature_hits), or None.
Source code in kumiki/csg/cutcsg.py
contains_point
abstractmethod
¶
is_point_on_boundary
abstractmethod
¶
get_outward_normal
abstractmethod
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
Return the outward normal at boundary point point, or None. Undefined off the boundary.
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
Return the outward normal of every face meeting at boundary point point (several on an edge or corner).
Shapes that can't tell return get_outward_normal's one.
Source code in kumiki/csg/cutcsg.py
get_aabb
abstractmethod
¶
get_aabb() -> AxisAlignedBoundingBox
get_convex_hull
¶
is_exactly_convex_hull
¶
exact_line_spans
¶
exact_line_spans(line: Line, seed: Span, tolerance: float, removing: bool) -> Optional[List[Span]]
Return where line runs inside this primitive, or None if it can't be computed exactly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
line
|
Line
|
the line, in this primitive's space. |
required |
seed
|
Span
|
the (low, high) stretch of the line to search, as parameters along its unit direction. |
required |
tolerance
|
float
|
how far outside the surface still counts as inside. |
required |
removing
|
bool
|
True when this primitive is being subtracted. A line lying on the surface counts as inside either way; this flips the comparison so that holds for a cut too. |
required |
Returns the parameter spans within seed that are inside. Default: clip seed by the convex
hull, when the primitive is exactly its hull.
Source code in kumiki/csg/cutcsg.py
angles_around_line
¶
angles_around_line(at: ndarray, direction: ndarray, basis: Tuple[ndarray, ndarray], tolerance: float) -> Optional[AngleSpans]
Return the directions around a line, at one point on it, in which this primitive has material.
Looking along the line at at, the primitive fills some angles around it; they say whether the
line runs inside it (all), off it (none), along a flat face (half a turn) or along an edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
at
|
ndarray
|
the point on the line (numpy, this primitive's space). |
required |
direction
|
ndarray
|
the line's unit direction (numpy). |
required |
basis
|
Tuple[ndarray, ndarray]
|
two unit vectors square to |
required |
tolerance
|
float
|
how far off a face still counts as on it. |
required |
Returns (low, high) angle spans in radians within [0, 2pi], or None if it can't be computed exactly. Default: from the convex hull's faces, when the primitive is exactly its hull.
Source code in kumiki/csg/cutcsg.py
line_crossings
¶
Return the parameters along the line origin + t * direction where it crosses this primitive's
surfaces: the places the material around the line can change.
origin and unit direction are numpy, in this primitive's space. Default: where the line
crosses each face plane of the convex hull.
Source code in kumiki/csg/cutcsg.py
plane_sides
¶
Return where this primitive cuts the plane of frame, as (front, back) regions within seed.
front is where it has material just on the side the plane's normal points to, back just on the other side (see cross_sections.Sides). Default: from the convex hull. Raises cross_sections.CannotCrossSection if the primitive can't be cut.
Source code in kumiki/csg/cutcsg.py
CSGParity
¶
Bases: Enum
Whether a node adds material to the result (ADDITIVE) or removes it (SUBTRACTIVE).
EmptyCSG
dataclass
¶
Bases: CutCSG
A solid with no points.
display_name
classmethod
¶
__repr__
¶
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
contains_point
¶
is_point_on_boundary
¶
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
get_convex_hull
¶
HalfSpace
dataclass
¶
Bases: HasFeatures, CutCSG
An infinite half space: all points P with P · normal >= offset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
normal
|
points into the half space. |
required | |
offset
|
the plane's signed distance from the origin along |
required |
display_name
classmethod
¶
__repr__
¶
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
contains_point
¶
Return whether P · normal >= offset.
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether P · normal == offset.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_convex_hull
¶
Source code in kumiki/csg/cutcsg.py
RectangularPrism
dataclass
¶
Bases: HasFeatures, CutCSG
A prism with rectangular cross-section, optionally infinite at either end. Parameterized like a Timber.
The cross-section (size = width along local X, height along local Y) is centred at the
transform's position; the prism runs from start_distance to end_distance along local Z.
None for either distance makes that end infinite.
transform
class-attribute
instance-attribute
¶
default_features
¶
default_features() -> Dict[FeatureKey, CSGFeature]
display_name
classmethod
¶
__post_init__
¶
Source code in kumiki/csg/cutcsg.py
get_bottom_position
¶
get_bottom_position() -> V3
Return the centre of the start end. Raises ValueError if it is infinite.
Source code in kumiki/csg/cutcsg.py
get_top_position
¶
get_top_position() -> V3
Return the centre of the far end. Raises ValueError if it is infinite.
Source code in kumiki/csg/cutcsg.py
__repr__
¶
equals_prism
¶
equals_prism(other: RectangularPrism) -> bool
Return whether every parameter equals other's.
Source code in kumiki/csg/cutcsg.py
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
Return whether key is one of this prism's carriers: a side, a finite end, or an extra plane.
Source code in kumiki/csg/cutcsg.py
contains_point
¶
Return whether point is inside or on the boundary.
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether point is on the boundary.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
get_convex_hull
¶
Source code in kumiki/csg/cutcsg.py
Cylinder
dataclass
¶
Bases: HasFeatures, CutCSG
A cylinder, optionally infinite at either end.
The axis runs through position along axis_direction, from start_distance to end_distance;
None for either makes that end infinite.
position
class-attribute
instance-attribute
¶
default_features
¶
default_features() -> Dict[FeatureKey, CSGFeature]
Return its two caps and the barrel.
Source code in kumiki/csg/cutcsg.py
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
Return the axis, the barrel around it, and a plane for each finite cap.
Source code in kumiki/csg/cutcsg.py
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
__repr__
¶
contains_point
¶
Return whether point is inside or on the boundary.
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether point is on the barrel or a finite cap.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
get_convex_hull
¶
Return a hexagonal prism circumscribing the cylinder, capped at its finite ends. It contains the cylinder.
Source code in kumiki/csg/cutcsg.py
exact_line_spans
¶
exact_line_spans(line: Line, seed: Span, tolerance: float, removing: bool) -> Optional[List[Span]]
Solved exactly: the barrel as a quadratic along the line, the caps as planes.
Source code in kumiki/csg/cutcsg.py
angles_around_line
¶
angles_around_line(at: ndarray, direction: ndarray, basis: Tuple[ndarray, ndarray], tolerance: float) -> Optional[AngleSpans]
Solved exactly: the caps, and half a turn about the barrel's tangent plane where at is on it.
Source code in kumiki/csg/cutcsg.py
line_crossings
¶
Return the parameters along the line where it crosses the barrel and the finite caps.
Source code in kumiki/csg/cutcsg.py
plane_sides
¶
Cut exactly: an ellipse (or a strip, for a plane along the axis), then the caps.
Source code in kumiki/csg/cutcsg.py
SolidsAtPoint
¶
Caches contains_point and is_point_on_boundary of one point against several solids.
Answers: any_holds, any_encloses, any_on_surface, outward_normals, average_outward_normal, close_around_it.
Source code in kumiki/csg/cutcsg.py
any_holds
¶
any_encloses
¶
any_on_surface
¶
outward_normals
¶
outward_normals() -> List[Optional[Direction3D]]
Return each on-surface solid's outward normal at the point.
every_outward_normal
¶
every_outward_normal() -> Optional[List[Direction3D]]
Return each face normal of the single solid the point is on the surface of; None if several or none.
Source code in kumiki/csg/cutcsg.py
average_outward_normal
¶
average_outward_normal(negated: bool = False) -> Optional[Direction3D]
Return the mean outward normal (negated if negated), or None if they cancel or are unknown.
Source code in kumiki/csg/cutcsg.py
close_around_it
¶
Return whether the surfaces at the point enclose it, so it is inside their union.
E.g. a point on the shared face of two touching prisms. True when no direction leaves every surface. Exact for one or two surfaces; False if any normal is unknown.
Source code in kumiki/csg/cutcsg.py
SolidUnion
dataclass
¶
Bases: CutCSG
Union of children: points in any child.
display_name
classmethod
¶
__post_init__
¶
__repr__
¶
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
contains_point
¶
is_point_on_boundary
¶
Return whether point is on some child's boundary and not enclosed by the union.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
Return the average outward normal of the children point is on the boundary of, or None.
Source code in kumiki/csg/cutcsg.py
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
Intersection
dataclass
¶
Bases: CutCSG
Intersection of left and right: points in both.
__post_init__
¶
__repr__
¶
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
contains_point
¶
is_point_on_boundary
¶
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
Return the outward normal at point, averaged where both sides' surfaces meet.
Source code in kumiki/csg/cutcsg.py
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
Source code in kumiki/csg/cutcsg.py
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
Difference
dataclass
¶
Bases: CutCSG
base minus every solid in subtract.
__post_init__
¶
__repr__
¶
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
contains_point
¶
Return whether point is in base and not strictly inside any subtracted solid (nor on a flush cut).
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether point is in the difference and on the base's surface or a cut's wall.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
Return the base's normal at point, else the average negated normal of the cuts there; None if unknown.
Source code in kumiki/csg/cutcsg.py
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
Return the base's normals at point, plus the negated normals of cuts through it not parallel to one.
Source code in kumiki/csg/cutcsg.py
ConvexPolygonExtrusion
dataclass
¶
Bases: HasFeatures, CutCSG
A convex polygon in the local XY plane extruded along local Z, optionally infinite at either end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
the polygon's (x, y) points in order; must be convex. |
required | |
transform
|
the polygon's position and orientation. |
required | |
start_distance, end_distance
|
extent along local Z; None for infinite. |
required |
transform
class-attribute
instance-attribute
¶
default_features
¶
default_features() -> Dict[FeatureKey, CSGFeature]
Return its two caps, a side per profile edge, and their edges.
Source code in kumiki/csg/cutcsg.py
display_name
classmethod
¶
get_bottom_position
¶
get_bottom_position() -> V3
Return the profile origin at start_distance. Raises ValueError if infinite.
Source code in kumiki/csg/cutcsg.py
get_top_position
¶
get_top_position() -> V3
Return the profile origin at end_distance. Raises ValueError if infinite.
Source code in kumiki/csg/cutcsg.py
__repr__
¶
is_valid
¶
Return whether it has at least 3 points, a convex polygon, and end > start when both are finite.
Source code in kumiki/csg/cutcsg.py
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
contains_point
¶
Return whether point is inside or on the boundary.
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether point is on a cap or a side.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
get_convex_hull
¶
Source code in kumiki/csg/cutcsg.py
ConvexPolygonSimpleLoft
dataclass
¶
Bases: HasFeatures, CutCSG
A solid lofted between two convex polygons in parallel planes, vertex i to vertex i.
Both profiles must be convex, with the same point count and winding, and every side planar (no
twist; see is_valid). Profiles lie in the local XY plane at bottom_points_z_pos and
top_points_z_pos along local Z; both must be finite.
transform
class-attribute
instance-attribute
¶
default_features
¶
default_features() -> Dict[FeatureKey, CSGFeature]
Return its two caps, a side per profile edge, and their edges.
Source code in kumiki/csg/cutcsg.py
display_name
classmethod
¶
__repr__
¶
is_valid
¶
Return whether both profiles are convex with 3+ matching points, top is above bottom, and every side is planar.
Source code in kumiki/csg/cutcsg.py
carriers
¶
carriers() -> Dict[FeatureKey, Carrier]
has_carrier
¶
has_carrier(key: FeatureKey) -> bool
contains_point
¶
Return whether point is inside or on the boundary.
Source code in kumiki/csg/cutcsg.py
is_point_on_boundary
¶
Return whether point is on the boundary.
Source code in kumiki/csg/cutcsg.py
get_outward_normal
¶
get_outward_normal(point: V3, eps: Optional[Numeric] = None) -> Optional[Direction3D]
get_outward_normals
¶
get_outward_normals(point: V3, eps: Optional[Numeric] = None) -> List[Direction3D]
get_aabb
¶
get_aabb() -> AxisAlignedBoundingBox
Source code in kumiki/csg/cutcsg.py
get_convex_hull
¶
is_exactly_convex_hull
¶
plane_sides
¶
Source code in kumiki/csg/cutcsg.py
arris_against_cap
¶
arris_against_cap(side: int, sides: int, end: bool) -> FeatureKey
Return the key of the arris where side side meets cap cap.
corner_on_cap
¶
corner_on_cap(vertex: int, vertices: int, end: bool) -> FeatureKey
Return the key of vertex index of the start or end profile.
default_feature_name
¶
default_feature_name(key: FeatureKey) -> str
Return the deterministic name of a default feature, e.g. "arris.5".
side_key
¶
side_key(index: int) -> FeatureKey
feature_groups_intersect
¶
feature_groups_intersect(a: FeatureGroup, b: FeatureGroup) -> bool
measured_by_default
¶
measured_by_default(purpose: FeaturePurpose) -> bool
Return whether features serving purpose are solved for by default (not rough stock or its relief).
feature_hit_sort_key
¶
feature_hit_sort_key(hit: OwnedFeatureHit) -> Tuple
Return a hit's sort key (see _sort_feature_hits).
Source code in kumiki/csg/cutcsg.py
owner_label_trails
¶
owner_label_trails(root: CutCSG) -> Dict[int, Tuple[str, ...]]
Return every node under root, keyed by id, with its label path (shoulder, shoulder#1, ...).
Source code in kumiki/csg/cutcsg.py
shared_ancestor
¶
Return the deepest node under some_common_ancestor containing both first and second, or None.
Source code in kumiki/csg/cutcsg.py
derive_edge_hits
¶
derive_edge_hits(some_common_ancestor: CutCSG, face_hits: List[OwnedFeatureHit]) -> List[OwnedFeatureHit]
Return the edges formed by pairs of face_hits, each owned by the pair's shared ancestor.
O(n^2) in the number of hits.
Source code in kumiki/csg/cutcsg.py
derive_point_hits
¶
derive_point_hits(some_common_ancestor: CutCSG, edge_hits: List[OwnedFeatureHit], face_hits: List[OwnedFeatureHit]) -> List[OwnedFeatureHit]
Return the points where an edge in edge_hits crosses a face in face_hits, each owned by the pair's shared ancestor.
An edge lying in the face's plane gives nothing.
Source code in kumiki/csg/cutcsg.py
prism_face_key
¶
prism_face_key(face: PrismFace) -> FeatureKey
Return the default key of a RectangularPrism face.
prism_arris_key
¶
prism_arris_key(first: PrismFace, second: PrismFace) -> FeatureKey
Return the default key of the arris between two faces, in either order.
Source code in kumiki/csg/cutcsg.py
prism_corner_key
¶
prism_corner_key(*faces: PrismFace) -> FeatureKey
Return the default key of the corner of three faces, in any order.
Source code in kumiki/csg/cutcsg.py
convex_profile_edge_features
¶
convex_profile_edge_features(sides: int) -> Dict[FeatureKey, CSGFeature]
Return the default edges of a convex extrusion or loft with sides sides, in key order:
side n against side n+1, then each side against the start cap, then the end cap.
Source code in kumiki/csg/cutcsg.py
measured_against
¶
measured_against(properties: FeatureProperties, partner: str, datum: Datum = NEUTRAL) -> FeatureProperties
Return properties marked relative to the feature named partner (FeatureMarkingSpec):
auto dimensioning prefers measuring between them. Two naming each other are a symmetric pair.
Source code in kumiki/csg/cutcsg.py
shoulder_override
¶
shoulder_override(key: FeatureKey, name: Optional[str] = None, group: FeatureGroup = NONE) -> FeatureOverride
Return an override marking the default at key as a shoulder plane, in group group.
Source code in kumiki/csg/cutcsg.py
has_face_plane_carrier
¶
has_face_plane_carrier(csg: HasFeatures, key: FeatureKey) -> bool
Return whether face_plane_carriers(csg) has key, locating only that one face.
Source code in kumiki/csg/cutcsg.py
face_plane_carriers
¶
face_plane_carriers(csg: HasFeatures) -> Dict[FeatureKey, Carrier]
Return a CarrierPlane per default face of csg with a plane, and per extra PlaneFeature, by key.
Not cached: a solve keeps the carriers it uses in its CarrierMap.
Source code in kumiki/csg/cutcsg.py
hit_of_kind
¶
hit_of_kind(hit: OwnedFeatureHit[CSGFeature], kind: Type[K]) -> Optional[OwnedFeatureHit[K]]
Return the hit typed as kind, or None if its feature isn't one.
point_tests_memo
¶
Context manager caching point tests (_POINT_TESTS) until the block ends.
Source code in kumiki/csg/cutcsg.py
csg_children
¶
Return the direct children of csg; empty for a primitive.
Source code in kumiki/csg/cutcsg.py
map_primitives
¶
map_primitives(csg: CutCSG, change: Callable[[HasFeatures], CutCSG]) -> CutCSG
Return csg with change applied to every feature-declaring primitive.
Source code in kumiki/csg/cutcsg.py
strip_features
¶
Return csg with every override and extra feature removed, all the way down; only defaults remain.
For copies of geometry already in another tree (e.g. a relief built from another timber).
Source code in kumiki/csg/cutcsg.py
with_purpose
¶
with_purpose(csg: CutCSG, purpose: FeaturePurpose) -> CutCSG
Return csg with every feature, all the way down, given purpose purpose.
Source code in kumiki/csg/cutcsg.py
csg_children_with_parity
¶
csg_children_with_parity(csg: CutCSG, parity: CSGParity = ADDITIVE) -> List[Tuple[CutCSG, CSGParity]]
Return the children of csg with their parity, in csg_children order. Only a Difference's subtract children invert.
Source code in kumiki/csg/cutcsg.py
walk_csg_with_parity
¶
walk_csg_with_parity(root: CutCSG, parity: CSGParity = ADDITIVE) -> Iterator[Tuple[CutCSG, CSGParity]]
Yield every node under root, including it, with its parity.
Source code in kumiki/csg/cutcsg.py
carrier_map
¶
carrier_map(root: CutCSG) -> CarrierMap
Return the CarrierMap of every primitive carrier in the tree, coincident planes merged.
Source code in kumiki/csg/cutcsg.py
make_finite_rectangular_prism_from_half_space
¶
make_finite_rectangular_prism_from_half_space(half_space: HalfSpace, size_of_space: Numeric, depth_of_space: Numeric) -> RectangularPrism
Return a finite prism standing in for half_space near its boundary.
Its start face lies on the boundary plane, it runs depth_of_space into the half space, and its
square size_of_space cross-section is centred where the normal through the origin meets the plane.
Source code in kumiki/csg/cutcsg.py
assert_distinct_children
¶
assert_distinct_children(kind: str, children: Sequence[CutCSG]) -> None
Raise if the same CSG object appears twice among children.
Source code in kumiki/csg/cutcsg.py
translate_profile
¶
translate_profiles
¶
point_in_convex_profile
¶
Return whether a 2D point is inside a convex profile, wound either way.
Source code in kumiki/csg/cutcsg.py
decompose_simple_polygon_into_convex_pieces
¶
Split a simple polygon of (u, v) points into convex quads and triangles, by horizontal bands.
Within each band between vertex v's, the active edges' crossings are paired left to right (even-odd). pathcsg.decompose_path_into_convex_pieces is the same sweep over a FancyPath.
Source code in kumiki/csg/cutcsg.py
translate_csg
¶
Return a copy of csg translated by translation.
Source code in kumiki/csg/cutcsg.py
adopt_csg
¶
adopt_csg(orig_transform: Optional[Transform], adopting_transform: Optional[Transform], csg_in_orig_space: CutCSG) -> CutCSG
Return csg_in_orig_space re-expressed from orig_transform's local space in adopting_transform's.
Either transform may be None for global space.
Example
cut_on_b = adopt_csg(timber_a.transform, timber_b.transform, cut_csg) csg_in_global = adopt_csg(timber_a.transform, None, cut_csg)
Source code in kumiki/csg/cutcsg.py
4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 | |