Spaces:
Sleeping
Sleeping
File size: 3,192 Bytes
182efca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | """B-Rep face extraction: solid shells vs free surfaces."""
from __future__ import annotations
import logging
from dataclasses import dataclass
from OCP.BRep import BRep_Tool
from OCP.TopAbs import TopAbs_FACE, TopAbs_SHELL, TopAbs_SOLID
from OCP.TopExp import TopExp_Explorer
from OCP.TopoDS import TopoDS, TopoDS_Face, TopoDS_Shape
logger = logging.getLogger(__name__)
@dataclass
class FaceExtractionResult:
"""Result of face extraction from a shape."""
faces: list[TopoDS_Face]
is_solid: bool
num_solids: int
num_shells: int
num_faces: int
def _count_topology(shape: TopoDS_Shape, topo_type) -> int:
"""Count topology entities of a given type."""
count = 0
exp = TopExp_Explorer(shape, topo_type)
while exp.More():
count += 1
exp.Next()
return count
def _has_surface_geometry(face: TopoDS_Face) -> bool:
"""Check that a face has valid underlying surface geometry."""
try:
surface = BRep_Tool.Surface_s(face)
return surface is not None
except Exception:
return False
def extract_faces(shape: TopoDS_Shape) -> FaceExtractionResult:
"""Extract faces from a B-Rep shape.
For solids (CATIA): extracts outer shell faces.
For free surfaces (Alias): collects all faces directly.
Args:
shape: The TopoDS_Shape to extract faces from.
Returns:
FaceExtractionResult with the list of faces and metadata.
"""
num_solids = _count_topology(shape, TopAbs_SOLID)
num_shells = _count_topology(shape, TopAbs_SHELL)
is_solid = num_solids > 0
faces: list[TopoDS_Face] = []
seen_hashes: set[int] = set()
if is_solid:
logger.info(
"Solid geometry detected (%d solid(s), %d shell(s)). "
"Extracting outer shell faces.",
num_solids, num_shells,
)
solid_exp = TopExp_Explorer(shape, TopAbs_SOLID)
while solid_exp.More():
shell_exp = TopExp_Explorer(solid_exp.Current(), TopAbs_FACE)
while shell_exp.More():
face = TopoDS.Face_s(shell_exp.Current())
h = hash(face)
if h not in seen_hashes and _has_surface_geometry(face):
seen_hashes.add(h)
faces.append(face)
shell_exp.Next()
solid_exp.Next()
else:
logger.info(
"Free-surface geometry detected (%d shell(s)). "
"Collecting all faces.",
num_shells,
)
face_exp = TopExp_Explorer(shape, TopAbs_FACE)
while face_exp.More():
face = TopoDS.Face_s(face_exp.Current())
h = hash(face)
if h not in seen_hashes and _has_surface_geometry(face):
seen_hashes.add(h)
faces.append(face)
face_exp.Next()
num_faces = len(faces)
logger.info("Extracted %d unique faces (duplicates removed: %s).",
num_faces, "solid" if is_solid else "surface")
return FaceExtractionResult(
faces=faces,
is_solid=is_solid,
num_solids=num_solids,
num_shells=num_shells,
num_faces=num_faces,
)
|