feat: 接入 SCDM 优先编辑闭环并支持阵列局部间距
接入 SCDM probe/edit/cache/校验链路,增强孔组、阵列、关系式和参数表交互。 支持阵列相邻段间距、移动意图切换、结果回滚校验,并补充对应回归脚本。
This commit is contained in:
@@ -42,6 +42,7 @@ from .relation_formulas import (
|
||||
parse_relation_formula,
|
||||
relation_value_to_text,
|
||||
rewrite_relation_formula_ids,
|
||||
validate_relation_formula_graph,
|
||||
)
|
||||
from .scdm_backend import resolve_scdm_backend
|
||||
from .scdm_edit_runner import run_scdm_edit_job
|
||||
@@ -3100,6 +3101,7 @@ class WindowStateMixin:
|
||||
text = self.relation_formula_input.text().strip() if hasattr(self, "relation_formula_input") else ""
|
||||
try:
|
||||
formula = parse_relation_formula(text)
|
||||
self._validate_relation_formula_graph(formula)
|
||||
if not replay_active:
|
||||
self._validate_relation_formula_references(formula)
|
||||
except RelationFormulaError as exc:
|
||||
@@ -3453,6 +3455,18 @@ class WindowStateMixin:
|
||||
for ref in formula.references:
|
||||
self._relation_value_for_ref(ref)
|
||||
|
||||
def _validate_relation_formula_graph(self, new_formula) -> None:
|
||||
formulas = []
|
||||
for item in getattr(self, "relation_formula_items", []) or []:
|
||||
if not bool(item.get("enabled", True)):
|
||||
continue
|
||||
try:
|
||||
formulas.append(parse_relation_formula(str(item.get("text") or "")))
|
||||
except RelationFormulaError:
|
||||
continue
|
||||
formulas.append(new_formula)
|
||||
validate_relation_formula_graph(formulas)
|
||||
|
||||
def _relation_parameter_supported(self, ref: ObjectParameterRef, *, target: bool = False) -> None:
|
||||
if target and self._relation_visible_spec_for_ref(ref) is not None:
|
||||
return
|
||||
@@ -4565,7 +4579,7 @@ class WindowStateMixin:
|
||||
return inner_wires > 0 or boundary_edges >= 16
|
||||
|
||||
def _scdm_selection_status_message(self, scdm_specs: list[dict[str, object]]) -> str:
|
||||
if self.selected_kind not in {"feature", "face", "edge"}:
|
||||
if self.selected_kind not in {"feature", "face", "edge", "solid", "part"}:
|
||||
return ""
|
||||
if self.model is None:
|
||||
return ""
|
||||
@@ -8915,8 +8929,12 @@ class WindowStateMixin:
|
||||
|
||||
def _scdm_property_target_value(self, spec: dict[str, object], text: str) -> object:
|
||||
value_type = str(spec.get("value_type") or "number")
|
||||
unit_scale = _float_or_none(spec.get("scdm_unit_scale"))
|
||||
if unit_scale is None or unit_scale <= 0:
|
||||
unit_scale = 1.0
|
||||
if value_type == "vector3":
|
||||
return list(self._parse_property_vector3(text))
|
||||
values = list(self._parse_property_vector3(text))
|
||||
return [value * unit_scale for value in values] if self._scdm_property_uses_length_units(spec) else values
|
||||
if value_type in {"number", "positive"}:
|
||||
try:
|
||||
value = float(text)
|
||||
@@ -8924,11 +8942,32 @@ class WindowStateMixin:
|
||||
raise ValueError("请输入数字形式的目标值。") from exc
|
||||
if value_type == "positive" and value <= 0:
|
||||
raise ValueError("请输入大于 0 的目标值。")
|
||||
return value
|
||||
return value * unit_scale if self._scdm_property_uses_length_units(spec) else value
|
||||
if value_type == "command":
|
||||
return True
|
||||
return text
|
||||
|
||||
@staticmethod
|
||||
def _scdm_property_uses_length_units(spec: dict[str, object]) -> bool:
|
||||
key = str(spec.get("scdm_capability_key") or spec.get("key") or "")
|
||||
value_type = str(spec.get("value_type") or "")
|
||||
if value_type == "vector3":
|
||||
return True
|
||||
suffixes = (
|
||||
".diameter",
|
||||
".radius",
|
||||
".offset",
|
||||
".width",
|
||||
".depth",
|
||||
".height",
|
||||
".distance",
|
||||
".thickness",
|
||||
".spacing",
|
||||
".segment_spacing",
|
||||
".position",
|
||||
)
|
||||
return key.endswith(suffixes)
|
||||
|
||||
@Slot(object)
|
||||
def _finish_scdm_edit_action(self, result: object) -> None:
|
||||
if hasattr(self, "_reroute_to_ui_thread") and self._reroute_to_ui_thread(lambda result=result: self._finish_scdm_edit_action(result)):
|
||||
|
||||
Reference in New Issue
Block a user