yapCAD BREP Implementation
This document describes yapCAD’s BREP (Boundary Representation) implementation, which provides native solid modeling through integration with OpenCascade (OCC).
Overview
yapCAD supports two modes of solid geometry:
Tessellated Mode (default, no dependencies) - Solids are represented as triangle meshes. Suitable for visualization and STL export.
BREP Mode (requires pythonocc-core) - Solids carry native OCC BREP data with exact geometric definitions. Required for STEP import/export and high-fidelity boolean operations.
Implementation Status
Complete:
Full OCC BREP wrapper classes (
BrepSolid,BrepFace,BrepEdge,BrepVertex)BREP-aware primitives:
box(),sphere(),cylinder(),cone(),prism()Solid operations:
extrude(),tube(),makeRevolutionSolid(),makeLoftSolid()Adaptive sweep:
sweep_adaptive(),sweep_adaptive_hollow()Boolean operations via OCC when BREP data present
STEP import with topology preservation
STEP export (tessellated and analytic modes)
STL import/export
Transform propagation to BREP data
Curves (2D/3D):
Line, arc, circle, ellipse (full and partial arcs)
Catmull-Rom splines (open and closed)
NURBS curves
Parabola, hyperbola primitives
Surfaces:
Planar, cylindrical, conical, spherical surfaces via OCC
Tessellation on demand with quality controls
Surface evaluation and normal computation
Installation
BREP functionality requires pythonocc-core, installed via conda:
conda env create -f environment.yml
conda activate yapcad-brep
Without OCC, yapCAD operates in tessellation-only mode with reduced functionality:
No STEP import/export
Boolean operations use mesh-based algorithms (lower fidelity)
Sweep operations produce tessellated results only
Architecture
BREP Wrapper Classes
Located in yapcad/brep.py:
BrepSolid- Wraps OCC TopoDS_Solid with lazy tessellationBrepFace- Surface face with trim curvesBrepEdge- Edge with curve geometryBrepVertex- Vertex with tolerance
These classes provide bidirectional conversion:
# yapCAD solid -> OCC shape
from yapcad.brep import brep_from_solid
occ_shape = brep_from_solid(solid).shape
# OCC shape -> yapCAD solid
from yapcad.brep import solid_from_brep
solid = solid_from_brep(occ_shape)
BREP Attachment
Solids store BREP data in metadata under 'brep' key:
solid = box(10, 20, 30)
brep = solid[5].get('brep') # BrepSolid instance if OCC available
Boolean Operations
Environment variables control engine selection:
YAPCAD_BOOLEAN_ENGINE- Force engine:native,trimesh,occYAPCAD_MESH_BOOLEAN_ENGINE- Mesh fallback when OCC unavailable
Auto-selection logic:
If both operands have BREP data → use OCC
Otherwise → use mesh-based engine
STEP Import/Export
Import
from yapcad.brep import import_step
# Returns yapCAD Geometry with attached BREP
geometry = import_step("model.step")
# Access the underlying solid
solid = geometry.geom
Export
Two modes available:
Tessellated (default):
from yapcad.geom3d import write_solid_step
write_solid_step(solid, "output.step")
Analytic (preserves exact geometry):
# Via environment variable
import os
os.environ['YAPCAD_STEP_FORMAT'] = 'analytic'
write_solid_step(solid, "output.step")
# Or via write_step_analytic directly
from yapcad.brep import write_step_analytic
write_step_analytic(solid, "output.step")
Adaptive Sweep Operations
The sweep_adaptive() function creates solids by sweeping a profile along
a path with tangent-tracking orientation:
from yapcad.geom3d_util import sweep_adaptive
solid = sweep_adaptive(
profile, # region2d for cross-section
spine, # path3d with line/arc segments
angle_threshold_deg=5.0, # threshold for new section
frame_mode='minimal_twist' # or 'frenet', 'custom'
)
For hollow profiles (pipes):
solid = sweep_adaptive(
outer_profile,
spine,
inner_profiles=[inner_profile], # one or more voids
angle_threshold_deg=5.0
)
Edge Treatment: Fillets and Chamfers
Apply rounded (fillet) or beveled (chamfer) edges to BREP solids:
from yapcad.brep import (
fillet_all_edges, chamfer_all_edges,
fillet_edges, chamfer_edges,
brep_from_solid
)
from yapcad.geom3d_util import box
# Create a box solid
my_box = box(20, 20, 10)
brep_solid = brep_from_solid(my_box)
# Apply fillet (rounded edges) to all edges
filleted = fillet_all_edges(brep_solid, radius=2.0)
# Apply chamfer (beveled edges) to all edges
# Creates symmetric 45° chamfers
chamfered = chamfer_all_edges(brep_solid, distance=1.5)
# Apply fillet to specific edges only
selected_edges = [edge1, edge2] # BrepEdge objects
partial_fillet = fillet_edges(brep_solid, selected_edges, radius=1.0)
# Apply chamfer to specific edges
partial_chamfer = chamfer_edges(brep_solid, selected_edges, distance=1.0)
Notes:
Requires pythonocc-core (BREP environment)
Returns a new
BrepSolidinstance with modified edgesEdges that cannot be filleted/chamfered (too small, geometric constraints) are skipped
For selective edge operations, use edge selection helpers (see below)
See
examples/fillet_chamfer_demo.dslfor DSL usage examples
Edge Selection Functions
The yapcad.brep_edge_select module provides functions to select edges from BREP
solids based on geometric criteria. This is particularly useful for applying selective
fillets or chamfers to specific edges rather than all edges of a solid.
Basic Selection Functions
Select by Direction:
from yapcad.brep_edge_select import (
select_vertical_edges,
select_horizontal_edges,
select_edges_by_direction
)
# Select edges parallel to Z axis (vertical edges)
vertical = select_vertical_edges(brep_solid, tolerance_deg=1.0)
# Select edges perpendicular to Z axis (horizontal edges)
horizontal = select_horizontal_edges(brep_solid, tolerance_deg=1.0)
# Select edges parallel to a custom direction
edges_45deg = select_edges_by_direction(brep_solid,
direction=(1, 1, 0),
tolerance_deg=1.0)
Select by Z Position:
from yapcad.brep_edge_select import (
select_top_edges,
select_bottom_edges,
select_edges_at_z,
select_edges_in_z_range,
select_edges_crossing_z
)
# Select edges at the top of the solid (maximum Z)
top_edges = select_top_edges(brep_solid, tolerance=0.001)
# Select edges at the bottom of the solid (minimum Z)
bottom_edges = select_bottom_edges(brep_solid, tolerance=0.001)
# Select edges at a specific Z height
mid_edges = select_edges_at_z(brep_solid, z_value=5.0, tolerance=0.001)
# Select edges within a Z range
range_edges = select_edges_in_z_range(brep_solid,
z_min=2.0, z_max=8.0,
tolerance=0.001)
# Select edges that cross a specific Z height (vertical edges spanning Z)
crossing = select_edges_crossing_z(brep_solid, z_value=5.0, tolerance=0.001)
Select by Length:
from yapcad.brep_edge_select import select_edges_by_length
# Select edges within a length range
long_edges = select_edges_by_length(brep_solid, min_length=10.0)
short_edges = select_edges_by_length(brep_solid, max_length=5.0)
mid_edges = select_edges_by_length(brep_solid,
min_length=5.0,
max_length=15.0)
Select by Position:
from yapcad.brep_edge_select import (
select_edges_near_point,
select_edges_in_cylinder
)
# Select edges near a point (based on edge midpoint)
near_origin = select_edges_near_point(brep_solid,
target_point=(0, 0, 5),
max_distance=2.0)
# Select edges within a cylindrical region (useful for holes/bosses)
around_hole = select_edges_in_cylinder(brep_solid,
center=(10, 10, 0),
radius=5.0,
axis=(0, 0, 1))
Filtering Functions
from yapcad.brep_edge_select import (
filter_curved_edges,
filter_linear_edges,
get_all_edges
)
# Get all edges from a solid
all_edges = get_all_edges(brep_solid)
# Filter to only curved (non-linear) edges
curved = filter_curved_edges(all_edges)
# Filter to only linear (straight) edges
linear = filter_linear_edges(all_edges)
Set Operations on Edge Lists
Combine, intersect, or subtract edge selections:
from yapcad.brep_edge_select import (
union_edges,
intersect_edges,
subtract_edges
)
# Combine multiple selections (removes duplicates)
combined = union_edges(vertical_edges, top_edges, bottom_edges)
# Find edges common to all selections
common = intersect_edges(horizontal_edges, long_edges, top_edges)
# Remove edges from a selection
all_but_bottom = subtract_edges(all_edges, bottom_edges)
Edge Information
Get detailed information about an edge:
from yapcad.brep_edge_select import edge_info
info = edge_info(some_edge)
# Returns dict with:
# - length: Edge length
# - endpoints: ((x1, y1, z1), (x2, y2, z2))
# - midpoint: (x, y, z)
# - direction: (dx, dy, dz) for linear edges, None for curved
# - is_linear: True if edge is straight
# - is_vertical: True if parallel to Z axis
# - is_horizontal: True if perpendicular to Z axis
Complete Example: Selective Filleting
Here’s a complete example showing how to apply fillets only to specific edges:
from yapcad.brep import brep_from_solid, fillet_edges
from yapcad.brep_edge_select import (
select_vertical_edges,
select_top_edges,
intersect_edges
)
from yapcad.geom3d_util import box
# Create a box
my_box = box(20, 20, 10)
brep = brep_from_solid(my_box)
# Select only the vertical edges at the top of the box
vertical = select_vertical_edges(brep)
top = select_top_edges(brep)
top_vertical = intersect_edges(vertical, top)
# Apply fillet only to these edges
filleted_box = fillet_edges(brep, top_vertical, radius=1.0)
Notes:
All selection functions require pythonocc-core
Selection functions return lists of
BrepEdgeobjectsEdge selections can be combined using set operations
Tolerance parameters control how precisely edges must match criteria
Edge selections avoid duplicates (each unique edge appears once)
Helical Extrusion
Create smooth helical extrusions (twisted features) for gears, columns, and spiral geometry:
from yapcad.geom3d_util import helical_extrude
from yapcad.geom import line, point
# Define a square profile centered at origin
square = [
line(point(-5, -5), point(5, -5)),
line(point(5, -5), point(5, 5)),
line(point(5, 5), point(-5, 5)),
line(point(-5, 5), point(-5, -5))
]
# Create twisted column: 20mm tall, 90° total twist
twisted_column = helical_extrude(
square,
height=20,
twist_angle_deg=90,
segments=64 # Higher = smoother (recommended: 64+)
)
Parameters:
profile- region2d (closed loop of 2D curves) centered near originheight- Extrusion height along Z-axistwist_angle_deg- Total rotation angle (positive = counterclockwise from +Z)segments- Number of lofting sections (default 64, use 64+ for smooth surfaces)
Notes:
Requires pythonocc-core (uses lofting for smooth surfaces)
Zero twist produces simple extrusion
Ideal for helical gears (use with involute gear profiles)
API Reference
Key Functions
yapcad.brep:
import_step(path)- Import STEP filewrite_step_analytic(solid, path)- Export analytic STEPbrep_from_solid(solid)- Extract BREP wrappersolid_from_brep(shape)- Create solid from OCC shapefillet_all_edges(brep_solid, radius)- Round all edgeschamfer_all_edges(brep_solid, distance)- Bevel all edgesfillet_edges(brep_solid, edges, radius)- Round specific edgeschamfer_edges(brep_solid, edges, distance)- Bevel specific edges
yapcad.brep_edge_select:
get_all_edges(brep_solid)- Get all unique edges as BrepEdge objectsselect_vertical_edges(brep_solid, tolerance_deg)- Select edges parallel to Zselect_horizontal_edges(brep_solid, tolerance_deg)- Select edges perpendicular to Zselect_edges_by_direction(brep_solid, direction, tolerance_deg)- Select by directionselect_edges_by_length(brep_solid, min_length, max_length)- Select by length rangeselect_edges_at_z(brep_solid, z_value, tolerance)- Select edges at Z heightselect_edges_in_z_range(brep_solid, z_min, z_max, tolerance)- Select edges in Z rangeselect_edges_crossing_z(brep_solid, z_value, tolerance)- Select edges spanning Zselect_top_edges(brep_solid, tolerance)- Select edges at maximum Zselect_bottom_edges(brep_solid, tolerance)- Select edges at minimum Zselect_edges_near_point(brep_solid, point, max_distance)- Select by proximityselect_edges_in_cylinder(brep_solid, center, radius, axis)- Select in cylindrical regionfilter_curved_edges(edges)- Keep only curved edgesfilter_linear_edges(edges)- Keep only linear edgesedge_info(edge)- Get detailed edge propertiesunion_edges(*edge_lists)- Combine edge lists (remove duplicates)intersect_edges(*edge_lists)- Find common edgessubtract_edges(base_edges, edges_to_remove)- Remove edges from list
yapcad.geom3d:
box(l, w, h)- Rectangular prism with BREPsphere(center, radius)- Sphere with BREPcylinder(center, axis, radius, height)- Cylinder with BREPcone(center, axis, radius1, radius2, height)- Cone/frustum with BREP
yapcad.geom3d_util:
extrude(profile, direction, height)- Linear extrusionmakeRevolutionSolid(profile, axis, angle)- RevolutionmakeLoftSolid(profiles)- Loft through profilessweep_adaptive(profile, spine, ...)- Adaptive sweephelical_extrude(profile, height, twist_angle_deg, ...)- Helical/twisted extrusionradial_pattern_solid(solid, count, ...)- Circular array of solidslinear_pattern_solid(solid, count, spacing)- Linear array of solidsradial_pattern_surface(surf, count, ...)- Circular array of surfaceslinear_pattern_surface(surf, count, spacing)- Linear array of surfaces
yapcad.geom_util:
radial_pattern(geometry, count, ...)- Circular array of 2D geometrylinear_pattern(geometry, count, spacing)- Linear array of 2D geometry
yapcad.text3d:
text_solid(text, height, depth, ...)- Create 3D extruded textengrave_text(target, text, position, normal, ...)- Engrave text into solidtext_width(text, height, spacing, font)- Calculate text width for positioning
Testing
BREP tests are in tests/test_brep.py and tests/test_step_import.py.
Run with:
PYTHONPATH=./src pytest tests/test_brep.py -v
Limitations
Complex surfaces (NURBS, offset) may tessellate during operations
Boolean operations on complex geometry may fail; check results
Performance depends on OCC installation quality
Future Work
Improved NURBS surface support
Direct BREP editing operations
Better error reporting for failed operations
Integration with DSL for BREP-specific operations