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
+34 -3
View File
@@ -8,6 +8,7 @@ selector resolution, never on executors.
from __future__ import annotations
import math
from typing import TYPE_CHECKING, Any
from .runtime_base import ExtentVector, FeatureExecutionError
@@ -44,12 +45,29 @@ def _targeted_extent_vector(
end_condition: dict[str, Any] | None = None,
offset_mm: float | None = None,
) -> ExtentVector:
if session.body is None:
reference = _extent_reference(node, end_condition) if condition != "through_next" else None
source_vertex_point: Vector3 | None = None
if condition == "up_to_vertex" and isinstance(reference, dict) and reference.get("kind") == "source_vertex":
raw_point = reference.get("point_mm")
if not (
isinstance(raw_point, list)
and len(raw_point) == 3
and all(isinstance(value, (int, float)) and math.isfinite(float(value)) for value in raw_point)
):
raise FeatureExecutionError(
"invalid_source_vertex_extent",
"The source-vertex extent datum must contain one finite 3D point",
extent=condition,
)
source_vertex_point = (float(raw_point[0]), float(raw_point[1]), float(raw_point[2]))
elif session.body is None:
raise FeatureExecutionError("missing_extent_body", "Selector-dependent extent requires an existing body", extent=condition)
if condition == "through_next":
target = session.body
elif source_vertex_point is not None:
target = None
else:
reference = _extent_reference(node, end_condition)
assert isinstance(reference, dict)
resolution = session.resolve(reference)
if resolution.status != "resolved" or resolution.record is None:
raise ValueError(resolution.diagnostic.message if resolution.diagnostic else "extent target was not resolved")
@@ -62,7 +80,7 @@ def _targeted_extent_vector(
)
target = resolution.record.value
if condition == "up_to_vertex":
target_point = session.adapter.vertex_coordinates(target)
target_point = source_vertex_point or session.adapter.vertex_coordinates(target)
projections = [
vector_dot(vector_subtract(target_point, point), direction)
for face in faces
@@ -89,6 +107,19 @@ def _targeted_extent_vector(
distance = session.adapter.uniform_intersection_distance(target, faces, direction)
except ValueError as error:
message = str(error)
if condition == "up_to_surface" and message == "extent target is not reached by every profile ray":
# Do not reinterpret a partially hit finite face: that path
# has explicit trimmed-solid semantics below. Only a wholly
# unreachable planar face may terminate on its supporting
# plane, and the adapter proves one positive, uniform
# profile-to-plane distance before returning it.
if not session.adapter.target_has_forward_intersection(target, faces, direction):
try:
distance = session.adapter.uniform_planar_supporting_surface_distance(target, faces, direction)
except ValueError:
pass
else:
return ExtentVector(vector_scale(direction, distance))
code = "non_uniform_extent_target" if "non-uniform" in message else "extent_target_not_reached"
if condition in {"up_to_surface", "through_next"}:
# #5 高级终止条件:profile 与目标面非均匀相交(部分采样点未