pattern引用重解析,修复完成
This commit is contained in:
@@ -660,7 +660,23 @@ def _translated_sketch(sketch: dict[str, Any], offset: Vector3) -> dict[str, Any
|
||||
return output
|
||||
|
||||
|
||||
def _translated_node(node: FeaturePlanNode, instance_id: str, offset: Vector3) -> FeaturePlanNode:
|
||||
def _owner_plane_frame(session: ExecutionSession, selector: dict[str, Any]) -> dict[str, Any] | None:
|
||||
"""解析 selector 的 owner 特征(reference_plane)注册的显式平面 frame。
|
||||
|
||||
#6 pattern 引用重解析:pattern 重放 source(pattern_mirror)时,镜像面
|
||||
是 selector,其 owner 是 reference_plane 特征;该特征执行时把显式
|
||||
PlaneSpec 登记为拓扑上下文,这里取出该 frame 供随实例变换使用。
|
||||
"""
|
||||
owner = selector.get("owner_feature_id")
|
||||
if not owner:
|
||||
return None
|
||||
for record in session.topology.records_for_feature(str(owner)):
|
||||
if record.kind == "plane" and isinstance(record.value, PlaneSpec):
|
||||
return record.value.as_dict()
|
||||
return None
|
||||
|
||||
|
||||
def _translated_node(node: FeaturePlanNode, instance_id: str, offset: Vector3, session: ExecutionSession) -> FeaturePlanNode:
|
||||
params = deepcopy(node.params)
|
||||
components = offset
|
||||
if isinstance(params.get("plane"), dict) and params["plane"].get("origin_mm"):
|
||||
@@ -679,6 +695,45 @@ def _translated_node(node: FeaturePlanNode, instance_id: str, offset: Vector3) -
|
||||
axis = params.get("axis") or {}
|
||||
if axis.get("origin_mm"):
|
||||
axis["origin_mm"] = [float(axis["origin_mm"][index]) + components[index] for index in range(3)]
|
||||
mirror_plane = params.get("mirror_plane")
|
||||
if isinstance(mirror_plane, dict) and node.atomic_id == "pattern_mirror":
|
||||
# #6 pattern 引用重解析:镜像面是 reference_plane 引用,随实例平移
|
||||
# 到新位置后内联为显式 frame;否则重放时 resolve 到原始面,镜像
|
||||
# 副本会错误地重合在源特征附近。同时源特征也必须平移后重放:镜像
|
||||
# 副本 = reflect(源@t, 面@t),只平移面不平移源会落在 2P+t-x 处
|
||||
# 而非正确位置 2P-x+t。
|
||||
frame = _owner_plane_frame(session, mirror_plane)
|
||||
if frame is None:
|
||||
raise ValueError("mirror plane reference cannot be transformed for pattern replay")
|
||||
cloned_selector = deepcopy(mirror_plane)
|
||||
cloned_selector["frame"] = {
|
||||
"origin_mm": [frame["origin_mm"][index] + components[index] for index in range(3)],
|
||||
"x_dir": list(frame["x_dir"]),
|
||||
"normal": list(frame["normal"]),
|
||||
}
|
||||
params["mirror_plane"] = cloned_selector
|
||||
transformed_ids: list[str] = []
|
||||
for source_id in node.params.get("source_feature_ids") or []:
|
||||
source_node = session.replay_definitions.get(str(source_id))
|
||||
if source_node is None:
|
||||
raise ValueError(f"mirror pattern source feature {source_id} has no replay definition")
|
||||
temp_id = f"{instance_id}.src.{source_id}"
|
||||
shifted = _translated_node(source_node, temp_id, offset, session)
|
||||
if shifted.sketch_id:
|
||||
source_sketch = session.sketches.get(str(source_node.sketch_id))
|
||||
if source_sketch is not None:
|
||||
temp_sketch_id = f"{temp_id}.sk"
|
||||
session.sketches[temp_sketch_id] = _translated_sketch(source_sketch, offset)
|
||||
shifted = FeaturePlanNode(
|
||||
shifted.feature_id, shifted.atomic_id, shifted.name, shifted.depends_on,
|
||||
shifted.params, shifted.selectors, temp_sketch_id,
|
||||
shifted.declared_status, shifted.source_feature,
|
||||
)
|
||||
# 临时 replay 定义同样进入 nodes 表(replay_sources 以此过滤)。
|
||||
session.nodes[temp_id] = shifted
|
||||
session.replay_definitions[temp_id] = shifted
|
||||
transformed_ids.append(temp_id)
|
||||
params["source_feature_ids"] = transformed_ids
|
||||
return FeaturePlanNode(instance_id, node.atomic_id, node.name, (), params, node.selectors, node.sketch_id, node.declared_status, node.source_feature)
|
||||
|
||||
|
||||
@@ -708,7 +763,7 @@ def _execute_linear_pattern(node: FeaturePlanNode, session: ExecutionSession, ex
|
||||
dependency = pattern_transform_blocker(source)
|
||||
if dependency:
|
||||
raise ValueError(f"pattern source uses an unsupported {dependency}")
|
||||
cloned = _translated_node(source, f"{node.feature_id}.p{first}_{second}.{source.feature_id}", offset)
|
||||
cloned = _translated_node(source, f"{node.feature_id}.p{first}_{second}.{source.feature_id}", offset, session)
|
||||
sketch = session.sketches.get(str(source.sketch_id))
|
||||
execute(cloned, session, _translated_sketch(sketch, offset) if sketch else None)
|
||||
# 5. 记录本阵列的 replay 定义:后续阵列若选中本阵列,按定义递归重放,
|
||||
@@ -775,7 +830,7 @@ def _mirrored_sketch(sketch: dict[str, Any], plane: PlaneSpec) -> dict[str, Any]
|
||||
return output
|
||||
|
||||
|
||||
def _mirrored_node(node: FeaturePlanNode, instance_id: str, plane: PlaneSpec) -> FeaturePlanNode:
|
||||
def _mirrored_node(node: FeaturePlanNode, instance_id: str, plane: PlaneSpec, session: ExecutionSession) -> FeaturePlanNode:
|
||||
params = deepcopy(node.params)
|
||||
if isinstance(params.get("plane"), dict):
|
||||
for key in ("origin_mm", "x_dir", "y_dir", "normal"):
|
||||
@@ -816,6 +871,44 @@ def _mirrored_node(node: FeaturePlanNode, instance_id: str, plane: PlaneSpec) ->
|
||||
axis["origin_mm"] = _reflect_point(axis["origin_mm"], plane)
|
||||
if axis.get("direction"):
|
||||
axis["direction"] = _reflect_point(axis["direction"], plane, vector=True)
|
||||
mirror_plane = params.get("mirror_plane")
|
||||
if isinstance(mirror_plane, dict) and node.atomic_id == "pattern_mirror":
|
||||
# #6 pattern 引用重解析:镜像重放 mirror source 时,其镜像面引用
|
||||
# 随本实例的镜像面一起反射(内联为显式 frame),否则重放 resolve
|
||||
# 到原始面,嵌套镜像会退化成与源镜像重合的错误几何。源特征同样
|
||||
# 反射后重放:镜像副本 = reflect(源@P_B, reflect(面,P_B))。
|
||||
frame = _owner_plane_frame(session, mirror_plane)
|
||||
if frame is None:
|
||||
raise ValueError("mirror plane reference cannot be transformed for pattern replay")
|
||||
cloned_selector = deepcopy(mirror_plane)
|
||||
cloned_selector["frame"] = {
|
||||
"origin_mm": _reflect_point(frame["origin_mm"], plane),
|
||||
"x_dir": _reflect_point(frame["x_dir"], plane, vector=True),
|
||||
"normal": _reflect_point(frame["normal"], plane, vector=True),
|
||||
}
|
||||
params["mirror_plane"] = cloned_selector
|
||||
transformed_ids: list[str] = []
|
||||
for source_id in node.params.get("source_feature_ids") or []:
|
||||
source_node = session.replay_definitions.get(str(source_id))
|
||||
if source_node is None:
|
||||
raise ValueError(f"mirror pattern source feature {source_id} has no replay definition")
|
||||
temp_id = f"{instance_id}.src.{source_id}"
|
||||
shifted = _mirrored_node(source_node, temp_id, plane, session)
|
||||
if shifted.sketch_id:
|
||||
source_sketch = session.sketches.get(str(source_node.sketch_id))
|
||||
if source_sketch is not None:
|
||||
temp_sketch_id = f"{temp_id}.sk"
|
||||
session.sketches[temp_sketch_id] = _mirrored_sketch(source_sketch, plane)
|
||||
shifted = FeaturePlanNode(
|
||||
shifted.feature_id, shifted.atomic_id, shifted.name, shifted.depends_on,
|
||||
shifted.params, shifted.selectors, temp_sketch_id,
|
||||
shifted.declared_status, shifted.source_feature,
|
||||
)
|
||||
# 临时 replay 定义同样进入 nodes 表(replay_sources 以此过滤)。
|
||||
session.nodes[temp_id] = shifted
|
||||
session.replay_definitions[temp_id] = shifted
|
||||
transformed_ids.append(temp_id)
|
||||
params["source_feature_ids"] = transformed_ids
|
||||
return FeaturePlanNode(instance_id, node.atomic_id, node.name, (), params, node.selectors, node.sketch_id, node.declared_status, node.source_feature)
|
||||
|
||||
|
||||
@@ -831,7 +924,7 @@ def _execute_mirror_pattern(node: FeaturePlanNode, session: ExecutionSession) ->
|
||||
dependency = pattern_transform_blocker(source)
|
||||
if dependency:
|
||||
raise ValueError(f"mirror pattern source uses an unsupported {dependency}")
|
||||
cloned = _mirrored_node(source, f"{node.feature_id}.m.{source.feature_id}", resolution.record.value)
|
||||
cloned = _mirrored_node(source, f"{node.feature_id}.m.{source.feature_id}", resolution.record.value, session)
|
||||
sketch = session.sketches.get(str(source.sketch_id))
|
||||
_execute_node(cloned, session, _mirrored_sketch(sketch, resolution.record.value) if sketch else None)
|
||||
session.replay_definitions[node.feature_id] = node
|
||||
|
||||
Reference in New Issue
Block a user