feat: 增加Face偏移保持一级关系策略

This commit is contained in:
2026-08-10 15:26:35 +08:00
parent 83c44265ba
commit 415e8a0f27
9 changed files with 357 additions and 16 deletions
+80 -6
View File
@@ -347,6 +347,12 @@ class WindowActionMixin:
self.statusBar().showMessage("未选择可修复对象")
def push_pull_face(self) -> None:
self._push_pull_face_action(keep_relations=False)
def push_pull_face_keep_relations(self) -> None:
self._push_pull_face_action(keep_relations=True)
def _push_pull_face_action(self, *, keep_relations: bool) -> None:
if self.model is None:
return
if self._edit_busy("请等待当前编辑完成后再执行新的拉伸/切除。"):
@@ -360,10 +366,11 @@ class WindowActionMixin:
QMessageBox.critical(self, "距离无效", "请输入数字形式的面移动距离。")
return
face_id = self.selected_face_id
plan = self._push_pull_plan_for_action(face_id, distance)
plan = self._push_pull_plan_for_action(face_id, distance, keep_relations=keep_relations)
operation_name = "拉伸/切除平面(保持关系)" if keep_relations else "拉伸/切除平面"
if plan["status"] == "blocked":
self._show_blocked_plan_message("拉伸/切除平面", plan, "拉伸/切除平面已阻止")
self._show_blocked_plan_message(operation_name, plan, "拉伸/切除平面已阻止")
return
if plan["risk"] != "low":
warnings = str(plan.get("warnings", ""))
@@ -383,6 +390,7 @@ class WindowActionMixin:
f"目标法向位置: {_format_value(plan.get('target_plane_position'))}\n"
f"执行策略: {_format_value(plan.get('edit_strategy_label'))}\n"
f"执行影响: {_format_value(plan.get('edit_semantics'))}\n"
f"关系约束: {_format_value(plan.get('face_push_pull_planar_constraint_summary', ''))}\n"
f"风险: {plan['risk']}\n\n"
f"{warnings_line}"
f"{plan['message']}\n\n"
@@ -395,18 +403,23 @@ class WindowActionMixin:
if result != QMessageBox.StandardButton.Yes:
self.statusBar().showMessage("已取消拉伸/切除平面")
return
isolation = self._isolation_for_plan(plan, "push_pull_face", [face_id, distance])
if keep_relations:
isolation = self._isolation_for_plan(plan, "push_pull_face_keep_relations", [face_id, distance])
else:
isolation = self._isolation_for_plan(plan, "push_pull_face", [face_id, distance])
if isolation is None:
self._show_push_pull_preview(face_id, distance, plan=plan)
else:
self.clear_edit_preview(render=False)
def action():
if keep_relations:
return self.model.push_pull_face_keep_relations(face_id, distance)
return self.model.push_pull_face(face_id, distance)
self._run_edit_action(
action,
operation_name="拉伸/切除平面",
operation_name=operation_name,
target=f"Face {face_id}",
parameters={
"part_id": plan.get("part_id"),
@@ -449,6 +462,31 @@ class WindowActionMixin:
"cylindrical_cap_extension_kind": plan.get("cylindrical_cap_extension_kind"),
"cylindrical_cap_extension_method": plan.get("cylindrical_cap_extension_method"),
"cap_extra_adjacent_face_count": plan.get("cap_extra_adjacent_face_count"),
"face_push_pull_planar_relation_constraint_requested": plan.get(
"face_push_pull_planar_relation_constraint_requested"
),
"face_push_pull_planar_relation_constraint_label": plan.get(
"face_push_pull_planar_relation_constraint_label"
),
"face_push_pull_planar_constraint_status": plan.get("face_push_pull_planar_constraint_status"),
"face_push_pull_planar_constraint_summary": plan.get("face_push_pull_planar_constraint_summary"),
"face_push_pull_planar_constraint_relation_count": plan.get(
"face_push_pull_planar_constraint_relation_count"
),
"face_push_pull_planar_constraint_parallel_count": plan.get(
"face_push_pull_planar_constraint_parallel_count"
),
"face_push_pull_planar_constraint_perpendicular_count": plan.get(
"face_push_pull_planar_constraint_perpendicular_count"
),
"face_push_pull_planar_constraint_angled_count": plan.get(
"face_push_pull_planar_constraint_angled_count"
),
"face_push_pull_planar_constraint_adjacent_face_count": plan.get(
"face_push_pull_planar_constraint_adjacent_face_count"
),
"face_push_pull_planar_constraint_blockers": plan.get("face_push_pull_planar_constraint_blockers"),
"face_push_pull_planar_constraint_warnings": plan.get("face_push_pull_planar_constraint_warnings"),
},
target_kind="face",
target_id=face_id,
@@ -700,16 +738,51 @@ class WindowActionMixin:
)
return plan
def _push_pull_plan_for_action(self, face_id: int, distance: float) -> dict[str, object]:
def _push_pull_plan_for_action(
self,
face_id: int,
distance: float,
*,
keep_relations: bool = False,
) -> dict[str, object]:
quick_plan = self._quick_push_pull_plan(face_id, distance)
if quick_plan.get("status") == "blocked":
return quick_plan
if self.model is None:
return quick_plan
if self._should_defer_push_pull_model_plan(face_id, distance, quick_plan):
if keep_relations:
blocked_plan = dict(quick_plan)
message = (
"当前 Face 属于复杂大 STEP 的多边界平面区域;“保持关系”需要在界面提交前完成一级平面关系验证。"
"为避免长时间卡住,当前版本暂不支持这种组合。请先选择简单平面 Face,"
"或改用普通“拉伸/切除”。"
)
blocked_plan.update(
{
"status": "blocked",
"risk": "blocked",
"message": message,
"blockers": message,
"resize_strategy": "push-pull-planar-face-keep-relations",
"edit_strategy_label": "保持一级平面关系的拉伸/切除",
"edit_semantics": (
"沿当前 Face 法向拉伸/切除,同时要求一级相邻平面关系可验证。"
),
"face_push_pull_planar_relation_constraint_requested": True,
"face_push_pull_planar_relation_constraint_label": "保持一级平面关系",
"face_push_pull_planar_constraint_status": "blocked",
"face_push_pull_planar_constraint_summary": "Face保持关系:当前复杂多边界平面需要完整验证,暂未开放。",
"face_push_pull_planar_constraint_blockers": message,
}
)
return blocked_plan
return self._deferred_push_pull_model_plan(quick_plan)
try:
model_plan = self.model.push_pull_plan(face_id, distance)
if keep_relations:
model_plan = self.model.push_pull_keep_relations_plan(face_id, distance)
else:
model_plan = self.model.push_pull_plan(face_id, distance)
except Exception as exc:
blocked_plan = dict(quick_plan)
blocked_plan.update(
@@ -1453,6 +1526,7 @@ class WindowActionMixin:
risk = str(plan.get("risk", ""))
isolated_geometry_operations = {
"push_pull_face",
"push_pull_face_keep_relations",
"move_face_plane_offset_local",
"resize_face_area_local",
"resize_face_area",