优化engine

This commit is contained in:
2026-08-24 10:01:21 +08:00
parent 91a443d990
commit fd8c0c37ad
16 changed files with 4486 additions and 74 deletions
+54 -25
View File
@@ -51,6 +51,8 @@ SUPPORTED_ATOMIC_IDS = frozenset({
"hole_countersink",
"hole_counterbore",
"sphere_add",
"reference_plane",
"reference_axis",
})
@@ -103,6 +105,40 @@ def _ordered_profile_points(sketch: dict[str, Any]) -> list[tuple[float, float]]
return pts
def _arc_midpoint(edge: dict[str, Any], p1: Vector, p2: Vector, center: Vector, radius: float) -> Vector:
"""Return a point on the intended directed arc for ``make_three_point_arc``.
Legacy contour data has no sweep direction and retains its prior shortest
arc behavior. Evidence-v2 analytic contours carry ``clockwise`` so a
major arc or a clockwise arc cannot be silently inverted by the adapter.
"""
v1 = p1 - center
v2 = p2 - center
if v1.length < 1e-9 or v2.length < 1e-9:
return (p1 + p2) / 2
n = Vector(*(edge.get("normal") or [0, 0, 1]))
if n.length < 1e-9:
n = v1.cross(v2)
if n.length < 1e-9:
n = Vector(0, 0, 1)
n = n.normalized()
v1n = v1.normalized() * radius
if "clockwise" not in edge:
bisector = v1n + v2.normalized() * radius
if bisector.length < 1e-9:
bisector = n.cross(v1n)
return center + bisector.normalized() * radius
sweep = math.atan2(n.dot(v1.cross(v2)), v1.dot(v2))
if bool(edge["clockwise"]):
if sweep >= 0:
sweep -= math.tau
elif sweep <= 0:
sweep += math.tau
half = sweep / 2
midpoint_vector = v1n * math.cos(half) + n.cross(v1n) * math.sin(half)
return center + midpoint_vector
def _face_from_contour_edges(edges_mm: list[dict[str, Any]], *, desired_normal: list[float] | None = None) -> Face:
b123_edges: list[Edge] = []
for e in edges_mm:
@@ -116,18 +152,7 @@ def _face_from_contour_edges(edges_mm: list[dict[str, Any]], *, desired_normal:
if v1.length < 1e-9 or v2.length < 1e-9:
b123_edges.append(Edge.make_line(p1, p2))
continue
n = Vector(*(e.get("normal") or [0, 0, 1]))
if n.length < 1e-9:
n = v1.cross(v2)
if n.length < 1e-9:
n = Vector(0, 0, 1)
n = n.normalized()
v1n = v1.normalized() * r
v2n = v2.normalized() * r
bis = v1n + v2n
if bis.length < 1e-9:
bis = n.cross(v1n)
mid = center + bis.normalized() * r
mid = _arc_midpoint(e, p1, p2, center, r)
try:
b123_edges.append(Edge.make_three_point_arc(p1, mid, p2))
except Exception:
@@ -154,18 +179,7 @@ def _face_from_contour_edges(edges_mm: list[dict[str, Any]], *, desired_normal:
if v1.length < 1e-9 or v2.length < 1e-9:
rev_edges.append(Edge.make_line(p1, p2))
continue
n = Vector(*(e.get("normal") or [0, 0, 1]))
if n.length < 1e-9:
n = v1.cross(v2)
if n.length < 1e-9:
n = Vector(0, 0, 1)
n = n.normalized()
v1n = v1.normalized() * r
v2n = v2.normalized() * r
bis = v1n + v2n
if bis.length < 1e-9:
bis = n.cross(v1n)
mid = center + bis.normalized() * r
mid = _arc_midpoint(e, p1, p2, center, r)
try:
rev_edges.append(Edge.make_three_point_arc(p1, mid, p2))
except Exception:
@@ -267,7 +281,22 @@ def run_engine_plan(
sketch = step.get("sketch")
sid = step.get("step_id")
if atomic == "sphere_add":
if atomic == "reference_plane":
# Context features deliberately produce no solid. They remain
# executable plan steps so their dependencies are preserved and
# can be registered by the session-based runtime.
plane = _plane_from_workplane(params.get("plane") or {})
log.append(
f"{sid}: reference_plane origin={tuple(plane.origin)} normal={tuple(plane.z_dir)}"
)
elif atomic == "reference_axis":
axis = _axis_from_params(params.get("axis") or {})
log.append(
f"{sid}: reference_axis origin={tuple(axis.position)} direction={tuple(axis.direction)}"
)
elif atomic == "sphere_add":
radius = _f(params.get("radius_mm") or 0)
center = params.get("center_mm") or [0, 0, 0]
if radius <= 0 or len(center) != 3: