feat(cadfs): expand selector provenance coverage

This commit is contained in:
2026-09-14 11:00:14 +08:00
parent 994d06aaea
commit de21ee8a5b
45 changed files with 19837 additions and 842 deletions
+43 -3
View File
@@ -13,6 +13,11 @@ from __future__ import annotations
import math
from typing import Any
from OCP.BRep import BRep_Tool
from OCP.TopAbs import TopAbs_EDGE, TopAbs_VERTEX
from OCP.TopExp import TopExp_Explorer
from OCP.TopoDS import TopoDS
from .specs import canonical_plane_signature
from .topology import TopologyRecord
@@ -48,6 +53,40 @@ def topology_records(body: Any, feature_id: str, body_id: str) -> list[TopologyR
edges = list(body.edges())
vertices = list(body.vertices())
# build123d may wrap a vertex extracted from a solid in a distinct OCC
# handle. Builder FirstShape/LastShape vertex history is only comparable
# with the final result's native explorer handles, so retain those exact
# handles for selector records. Faces and edges keep their established
# build123d export path.
result_vertices: list[Any] = []
explorer = TopExp_Explorer(body.wrapped, TopAbs_VERTEX)
while explorer.More():
candidate = explorer.Current()
if not any(candidate.IsSame(existing) for existing in result_vertices):
result_vertices.append(candidate)
explorer.Next()
result_edges: list[Any] = []
explorer = TopExp_Explorer(body.wrapped, TopAbs_EDGE)
while explorer.More():
candidate = explorer.Current()
if not any(candidate.IsSame(existing) for existing in result_edges):
result_edges.append(candidate)
explorer.Next()
def exact_incident_edge_count(vertex: Any) -> int:
count = 0
for edge in result_edges:
edge_vertices: list[Any] = []
edge_explorer = TopExp_Explorer(edge, TopAbs_VERTEX)
while edge_explorer.More():
candidate = edge_explorer.Current()
if not any(candidate.IsSame(existing) for existing in edge_vertices):
edge_vertices.append(candidate)
edge_explorer.Next()
if any(vertex.IsSame(candidate) for candidate in edge_vertices):
count += 1
return count
def index_for(shape: Any, candidates: list[Any]) -> int | None:
"""Map a subshape returned by a face/edge back to body topology."""
# 用 is_same 把面/边的子形状映射回主体拓扑列表的下标。
@@ -302,10 +341,11 @@ def topology_records(body: Any, feature_id: str, body_id: str) -> list[TopologyR
geometry=geometry,
))
# 5. 导出顶点记录:含坐标与关联边数。
for index, vertex in enumerate(vertices):
point = [vertex.X, vertex.Y, vertex.Z]
for index, vertex in enumerate(result_vertices):
point_value = BRep_Tool.Pnt_s(TopoDS.Vertex_s(vertex))
point = [point_value.X(), point_value.Y(), point_value.Z()]
records.append(TopologyRecord(
record_id=f"{body_id}:vertex:{index}", kind="vertex", feature_id=feature_id, body_id=body_id, value=vertex,
geometry={"center_mm": point, "incident_edge_count": len(vertex_edges[index])},
geometry={"center_mm": point, "incident_edge_count": exact_incident_edge_count(vertex)},
))
return records