Static flexible modeling
cadflow.flexible converts sparse 3D control grids into deterministic indexed triangle meshes. Use it for cloth, leather, membranes, covers, garments, and other flexible parts when the intended final form is known.
Here, static describes an authored final shape. The module does not solve equilibrium, advance time, or derive deformation from loads, gravity, contact, or material laws.
Choose the modeling object
| Object | Role |
|---|---|
FlexibleMaterial | Stores thickness and appearance metadata |
FlexiblePanel | Defines one control-grid surface and its sampling density |
FlexiblePanelMesh | Holds the built vertices, normals, and triangles for one panel |
FlexibleModel | Combines named panels into one deterministic mesh |
FlexibleMesh | Provides measurements, panel ranges, and OBJ/STL/JSON export |
RingSection / sectioned_panel | Builds a periodic panel from designed elliptical sections |
Build a panel from a control grid
Control points have shape (rows, columns, 3). The grid describes the form; sampling density controls the output tessellation.
from cadflow.flexible import FlexibleMaterial, FlexibleModel, FlexiblePanel
control_points = [
[(0, 0, 0), (0, 50, 6), (0, 100, 0)],
[(60, 0, 4), (60, 50, 18), (60, 100, 4)],
[(120, 0, 0), (120, 50, 6), (120, 100, 0)],
]
panel = FlexiblePanel(
name="formed cover",
control_points=control_points,
sample_rows=40,
sample_columns=48,
material=FlexibleMaterial(
name="coated fabric",
thickness=1.2,
color=(0.16, 0.42, 0.58),
roughness=0.7,
),
)
model = FlexibleModel("protective cover")
model.add_panel(panel)
mesh = model.build()
print(mesh.vertex_count, mesh.triangle_count)
print(mesh.bounds, mesh.surface_area, mesh.is_watertight)
The control grid must contain at least two rows and two columns, and all coordinates must be finite. sample_rows and sample_columns must be integers no smaller than their corresponding control-grid dimensions.
Control seams, thickness, and resolution
- Set
periodic_columns=Truewhen columns wrap around a closed section. Supply distinct columns around the loop; do not repeat the first column at the end. - Set material thickness to
0for a single surface. A positive thickness builds two normal-offset surfaces and triangulates the remaining boundaries into a closed thin shell. - Increase sample counts when downstream output needs finer triangles. Sampling changes mesh density, not the authored control grid.
- Keep dimensions, thickness, and downstream tolerances in one consistent unit system.
Build a periodic panel from sections
sectioned_panel is convenient for tubular or garment-like forms. Each RingSection defines an ellipse in an arbitrary 3D plane; optional wrinkle parameters apply a deterministic radial modulation.
from cadflow.flexible import (
FlexibleMaterial,
FlexibleModel,
RingSection,
sectioned_panel,
)
sections = [
RingSection(
center=(0, 0, 0),
axis_u=(1, 0, 0),
axis_v=(0, 1, 0),
radius_u=200,
radius_v=120,
wrinkle_amplitude=0.02,
wrinkle_count=7,
),
RingSection(
center=(0, 0, 500),
axis_u=(1, 0, 0),
axis_v=(0, 1, 0),
radius_u=240,
radius_v=140,
),
]
panel = sectioned_panel(
"sleeve",
sections,
control_columns=24,
sample_rows=48,
sample_columns=72,
material=FlexibleMaterial(name="woven shell", thickness=1.5),
)
model = FlexibleModel("sectioned shell")
model.add_panel(panel)
mesh = model.build()
wrinkle_amplitude is part of the designed geometry; it is not a displacement computed from physical loading. Add more uniquely named panels to the same FlexibleModel when an artifact contains separate pieces. mesh.panels preserves the vertex range, triangle range, and material of every panel.
Inspect and export
if mesh.vertex_count == 0 or mesh.triangle_count == 0:
raise RuntimeError("flexible mesh is empty")
for panel_range in mesh.panels:
print(panel_range.name, panel_range.vertex_count, panel_range.triangle_count)
mesh.write_obj("outputs/sectioned-shell.obj")
mesh.write_stl("outputs/sectioned-shell.stl")
mesh.write_json("outputs/sectioned-shell.json")
OBJ preserves panel groups and vertex normals. Binary STL contains the combined triangle mesh. JSON records panel ranges, material metadata, bounds, surface area, and watertightness.
Before delivery, inspect counts and bounds, verify that periodic seams are continuous, and confirm is_watertight when positive-thickness panels are expected to be closed. Also check that every output file exists and is non-empty.
Execution boundary
The native C++ builder performs Catmull-Rom sampling, periodic seam handling, vertex-normal construction, normal-offset thickness, and boundary-wall triangulation. Python owns control geometry, material metadata, multi-panel composition, measurements, and export. Each panel crosses this boundary through one stateless array call; no motion state or Python callback remains in the native builder.