The Brep
The Simple Concept
The Boundary Representation
A Brep (Boundary Representation) is the data format used by professional CAD software. Unlike a Mesh, which is an approximation, a Brep is a collection of perfectly mathematical Surfaces (NURBS) joined to form a solid volume.
It represents the exact boundary between the "inside" of an object and the "outside".
The Data Structure
The Hierarchy of Topology
A Brep is a complex, nested data structure. To define a Brep, the computer navigates a hierarchy:
Faces: The individual surfaces making up the shell.Edges: Boundaries where two faces meet.Vertices: Corners where multiple edges meet.
1class BrepVertex:2 def __init__(self, location: 'Point3d'):3 self.Location = location # 3D coordinate point4 self.AdjacentEdges = [] # Edges meeting at this vertex56class BrepEdge:7 def __init__(self, curve: 'Curve3d'):8 self.EdgeCurve = curve # 3D parameter space curve9 self.StartVertex = None # BrepVertex10 self.EndVertex = None # BrepVertex11 self.AdjacentFaces = [] # Faces sharing this edge boundary1213class BrepFace:14 def __init__(self, surface: 'NurbsSurface'):15 self.UnderlyingSurface = surface # Perfect infinite mathematical surface16 self.Loops = [] # Closed loop boundary curves (trims)17 self.OuterLoop = None # The primary exterior boundary1819class Brep:20 def __init__(self):21 self.Faces = [] # List of BrepFace objects22 self.Edges = [] # List of unique BrepEdge objects23 self.Vertices = [] # List of unique BrepVertex objects
Translate(vector):
1def Translate(self, vector: 'Vector3d'):2 """Shifts the entire solid model by a vector."""3 # To avoid duplicate translation of shared elements (e.g. an edge bordering4 # two faces moving twice), we transform unique geometric pools once:56 # 1. Shift master corner coordinates once7 for vertex in self.Vertices:8 vertex.Location += vector910 # 2. Shift edge 3D curves once11 for edge in self.Edges:12 edge.Geometry.Translate(vector)1314 # 3. Shift face 3D surfaces once15 for face in self.Faces:16 face.Geometry.Translate(vector)
The Shared Topology Trap: Because B-Rep is a shared graph (multiple faces share the same edges and vertices), recursive transformation (moving a face which moves its edges and vertices) would translate shared boundaries multiple times. We prevent this by transforming unique pools of vertices, curves, and surfaces exactly once.
Scale(factor):
1def Scale(self, scale_factor: float, center: 'Point3d' = Point3d(0,0,0)):2 """Uniformly scales the Brep by a given factor around a center point."""3 # 1. Create a scaling matrix4 transform = Transform.Scale(center, scale_factor)56 # 2. Scale all topological vertices7 for vertex in self.Vertices:8 vertex.Location = transform * vertex.Location910 # 3. Scale the underlying geometries of faces and edges11 for face in self.Faces:12 face.Geometry.Transform(transform)1314 for edge in self.Edges:15 edge.Geometry.Transform(transform)
Scaling a Brep expands its entire mathematical definition. Unlike scaling a mesh, scaling a Brep preserves the perfect mathematical precision of its underlying NURBS surfaces.
Rotate(angle, axis, center):
1def Rotate(self, angle: float, axis: 'Vector3d', center: 'Point3d'):2 """Rotates the Brep around a specified axis and center point."""3 # 1. Create a rotation matrix4 transform = Transform.Rotation(angle, axis, center)56 # 2. Rotate all topological vertices7 for vertex in self.Vertices:8 vertex.Location = transform * vertex.Location910 # 3. Rotate the underlying geometries of faces and edges11 for face in self.Faces:12 face.Geometry.Transform(transform)1314 for edge in self.Edges:15 edge.Geometry.Transform(transform)
Rotating a Brep spins all internal NURBS data around an axis. This transformation is applied to every surface, trim curve, and vertex within the topological hierarchy.
Brep.IsSolid / Valence:
1# Edge valence (number of connected faces) determines B-Rep validity:2# - Naked Edge (Valence = 1): Boundary of an open surface patch.3# - Manifold Edge (Valence = 2): Watertight seam where exactly two faces join.4# - Non-Manifold Edge (Valence >= 3): T-junction where three or more faces intersect.56def ValidateSolid(brep: Brep) -> dict:7 is_manifold = True8 naked_edges = []9 non_manifold_edges = []1011 for edge in brep.Edges:12 valence = len(edge.AdjacentFaces)13 if valence == 1:14 naked_edges.append(edge)15 elif valence >= 3:16 non_manifold_edges.append(edge)17 is_manifold = False1819 is_solid = is_manifold and len(naked_edges) == 020 return {21 "IsSolid": is_solid,22 "NakedCount": len(naked_edges),23 "NonManifoldCount": len(non_manifold_edges)24 }
Compute(brep):
1def compute_brep_volume(brep: Brep) -> dict:2 """Calculates the exact volume and centroid of a closed Brep.3 Uses Gauss's Divergence Theorem: Volume = 1/3 * sum(integral(F . n dS))4 where F is the vector field [x, y, z] / 3.5 """6 if not brep.IsSolid:7 raise ValueError("Cannot compute volume of non-watertight Brep.")89 total_volume = 0.010 centroid_sum = [0.0, 0.0, 0.0]1112 # Tessellate/evaluate each face surface patch to compute integration13 for face in brep.Faces:14 # Approximate surface patch as small planar triangles or polygons15 mesh = face.Tessellate(tolerance=0.01)1617 for triangle in mesh.Triangles:18 # Vertices of the triangle in 3D19 p0, p1, p2 = triangle.V0, triangle.V1, triangle.V22021 # Signed volume of tetrahedron formed by origin (0,0,0) and the triangle22 # V = 1/6 * |p0 . (p1 x p2)|23 cross_x = p1.y * p2.z - p1.z * p2.y24 cross_y = p1.z * p2.x - p1.x * p2.z25 cross_z = p1.x * p2.y - p1.y * p2.x2627 signed_tetra_vol = (p0.x * cross_x + p0.y * cross_y + p0.z * cross_z) / 6.02829 total_volume += signed_tetra_vol3031 # Center of the tetrahedron32 cx = (p0.x + p1.x + p2.x) / 4.033 cy = (p0.y + p1.y + p2.y) / 4.034 cz = (p0.z + p1.z + p2.z) / 4.03536 centroid_sum[0] += cx * signed_tetra_vol37 centroid_sum[1] += cy * signed_tetra_vol38 centroid_sum[2] += cz * signed_tetra_vol3940 # Centroid is volume-weighted average position41 centroid = [0.0, 0.0, 0.0]42 if abs(total_volume) > 1e-9:43 centroid = [44 centroid_sum[0] / total_volume,45 centroid_sum[1] / total_volume,46 centroid_sum[2] / total_volume47 ]4849 return {50 "volume": abs(total_volume),51 "centroid": centroid,52 "is_watertight": True53 }
For a watertight Brep, you can compute the exact enclosed volume and center of mass. This is a fundamentally different operation from surface area — volume requires a closed solid boundary. Essential for BIM quantity takeoffs, structural dead-load calculations, and CNC machining stock estimation.
Deconstruct / Explode:
1def explode_brep(brep: Brep) -> dict:2 """Deconstructs a B-Rep into individual face surfaces, boundary edges, and vertices."""3 extracted_faces = []4 extracted_edges = []5 extracted_vertices = []67 # Extract faces (NURBS surfaces with trim loop boundaries)8 for i, face in enumerate(brep.Faces):9 face_geometry = face.UnderlyingSurface()10 extracted_faces.append({11 "index": i,12 "surface": face_geometry,13 "outer_loop": face.OuterLoop14 })1516 # Extract unique edges (3D curves forming face boundaries)17 for j, edge in enumerate(brep.Edges):18 edge_curve = edge.EdgeCurve19 extracted_edges.append({20 "index": j,21 "curve": edge_curve,22 "start_vertex": edge.StartVertex,23 "end_vertex": edge.EndVertex24 })2526 # Extract unique vertices (3D points at edge endpoints)27 for k, vertex in enumerate(brep.Vertices):28 extracted_vertices.append({29 "index": k,30 "position": vertex.Location31 })3233 return {34 "faces": extracted_faces,35 "edges": extracted_edges,36 "vertices": extracted_vertices37 }
Intersect(Plane):
1def create_contours(brep: Brep, plane_origin: Point3D, plane_normal: Vector3D, step: float, limit_dist: float) -> list[Curve]:2 """Generates contour curves by intersecting a Brep with parallel planes."""3 contours = []45 # Calculate spacing along the normal vector direction6 dir_normalized = plane_normal.Normalize()7 num_steps = int(limit_dist / step)89 for i in range(num_steps):10 # Shift plane origin along the normal vector11 offset_distance = i * step12 shift_vector = dir_normalized * offset_distance13 current_origin = plane_origin + shift_vector1415 # Define the mathematical intersection plane16 slice_plane = Plane(current_origin, dir_normalized)1718 # Intersect the plane with each face of the B-Rep19 plane_contours = []20 for face in brep.Faces:21 intersection_curves = face.IntersectWithPlane(slice_plane)22 for curve in intersection_curves:23 plane_contours.append(curve)2425 # Join individual intersection segments into continuous curves26 joined_curves = Curve.JoinCurves(plane_contours)27 contours.extend(joined_curves)2829 return contours
ClosestPoint(Point3d):
1def find_closest_point_on_brep(brep: Brep, test_point: Point3D) -> dict:2 """Finds the point on the B-Rep surface boundary closest to the test point.3 Projects the point onto each individual face and edge boundary.4 """5 closest_point = None6 min_distance = float('inf')7 source_element_type = None8 source_element_index = -1910 # 1. Project onto individual B-Rep Faces (surfaces)11 for i, face in enumerate(brep.Faces):12 # Projects point onto face UV space, then checks if inside face loops13 projection_result = face.ProjectPoint(test_point)14 if projection_result.IsSuccess:15 projected_pt = projection_result.Point16 dist = test_point.DistanceTo(projected_pt)17 if dist < min_distance:18 min_distance = dist19 closest_point = projected_pt20 source_element_type = "Face"21 source_element_index = i2223 # 2. Project onto B-Rep Edges (boundary curves)24 for j, edge in enumerate(brep.Edges):25 # Find closest parameter t on edge 3D curve26 success, t = edge.EdgeCurve.ClosestPoint(test_point)27 if success:28 curve_pt = edge.EdgeCurve.PointAt(t)29 dist = test_point.DistanceTo(curve_pt)30 if dist < min_distance:31 min_distance = dist32 closest_point = curve_pt33 source_element_type = "Edge"34 source_element_index = j3536 return {37 "closest_point": closest_point,38 "distance": min_distance,39 "element_type": source_element_type,40 "element_index": source_element_index41 }
Flip:
1def flip_brep_orientation(brep: Brep) -> Brep:2 """Reverses the orientation of all faces and boundary curves in a B-Rep.3 Turns solid inside-out (flipping normal vectors from outward to inward).4 """5 # 1. Flip surface normal directions on all faces6 for face in brep.Faces:7 # Toggle orientation boolean flag to invert surface normal8 face.OrientationIsReversed = not face.OrientationIsReversed910 # 2. Reverse 2D trim curves in loops to keep solid-on-left convention11 for loop in brep.Loops:12 for trim in loop.Trims:13 # Reverse start/end points and direction of parameter space curve14 trim.Reverse()1516 # 3. Reverse 3D curves of all edges to remain consistent with trims17 for edge in brep.Edges:18 # Flip edge parameter space (start parameter <-> end parameter)19 edge.EdgeCurve.Reverse()2021 return brep
In 3D modeling, a solid is defined as a closed boundary of surfaces where all the surface normals point “outward” into empty space. If the normals point inward, algorithms (like volume calculation or boolean subtractions) will treat the object as a void, or an infinite space with a hole in it.
Brep.Flip() simultaneously reverses the normals of all constituent faces. This is often necessary when creating voids for boolean differences, or fixing imported geometry that came in inverted.
IsPointInside:
1def CheckPointContainment(brep: Brep, test_point: 'Point3d', tolerance: float = 0.001) -> bool:2 """Determines if a 3D point is inside a closed Brep solid."""3 if not brep.IsSolid:4 raise ValueError("Containment check requires a closed watertight B-Rep solid.")56 # Ray casting method: shoot an arbitrary ray into infinity7 ray_direction = Vector3d(0, 0, 1) # shoot vertically up8 intersection_count = 0910 # Count how many times the ray intersects the faces11 for face in brep.Faces:12 hits = face.IntersectRay(test_point, ray_direction, tolerance)13 intersection_count += len(hits)1415 # Odd number of intersections means the point is inside the boundary16 return (intersection_count % 2) == 1
Unlike a mathematical Sphere where checking containment is just distance < radius, a Brep can be an extremely complex, concave shape with holes.
To figure out if a point is inside, the engine performs a “Raycast”. It shoots an invisible line from the point out into infinity, and counts how many times the line intersects the Brep's faces. If the count is Odd (1, 3, 5...), the point is Inside. If the count is Even (0, 2, 4...), the point is Outside. This requires the Brep to be perfectly closed (watertight).
JoinBreps(breps, tolerance):
1def join_surfaces_into_brep(surfaces: list[Surface], tolerance: float = 0.001) -> Brep:2 """Stitches multiple separate surfaces into a single topological B-Rep.34 Pairs up and merges coincident boundary edges within a distance tolerance,5 converting naked edges into shared topological edges.6 """7 brep = Brep()89 # 1. Add all surfaces as B-Rep faces10 for srf in surfaces:11 brep.AddFace(srf)1213 # 2. Iterate over all naked (unjoined) edge pairs to check for geometric coincidence14 # Topological stitching connects matching pairs of half-edges.15 naked_edges = [edge for edge in brep.Edges if edge.IsNaked]1617 for i in range(len(naked_edges)):18 edge_a = naked_edges[i]19 if not edge_a.IsNaked:20 continue # Already joined in a previous iteration2122 for j in range(i + 1, len(naked_edges)):23 edge_b = naked_edges[j]24 if not edge_b.IsNaked:25 continue2627 # Check if the 3D curves of the edges are within tolerance28 if edge_a.IsCoincidentWith(edge_b, tolerance):29 # Merge edge_b into edge_a topologically30 # This updates the B-Rep topology: the two trims now share a single Edge31 brep.StitchEdges(edge_a, edge_b)32 break3334 # 3. Rebuild B-Rep topology and validate manifold connectivity35 brep.RebuildTopology()36 return brep
Joining is the foundational operation for building Breps from individual surfaces. If the edges of adjacent surfaces match within the specified tolerance, they are stitched together.