feat: 完善 SCDM-first 参数化编辑交付版

This commit is contained in:
2026-08-20 17:12:01 +08:00
parent 4e7877e05c
commit b4feab24d2
21 changed files with 3015 additions and 1729 deletions
+75 -9
View File
@@ -479,6 +479,7 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
"same_domain_v_range",
"same_domain_height_estimate",
"same_domain_range_source",
"selected_angular_span",
):
if key in hint:
info[key] = hint[key]
@@ -656,7 +657,33 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
if angular_span is None:
angular_span = _float_or_none(info.get("angular_span")) or 0.0
is_full = bool(info.get("is_full_cylinder")) or angular_span >= math.tau * 0.92
selected_span = (
_float_or_none(info.get("selected_angular_span"))
or _float_or_none(info.get("slot_angular_span"))
or _float_or_none(info.get("angular_span"))
or angular_span
)
try:
same_domain_count = int(info.get("same_domain_face_count", 1) or 1)
except (TypeError, ValueError):
same_domain_count = 1
is_blind_split_groove = (
is_full
and same_domain_count > 1
and 1e-6 < selected_span < math.tau * 0.92
and str(info.get("cylinder_end_type") or "") == "blind"
and guess == "hole/groove candidate"
)
if guess == "hole/groove candidate":
if is_blind_split_groove:
return {
"feature_type": "圆柱孔/槽候选",
"feature_edit_actions": (
"调整圆柱孔径或槽/凹槽宽度、深度;"
"具体按孔还是按槽会在完整识别时根据周围同类特征确认。"
),
"blind_split_cylindrical_pocket": True,
}
if not is_full:
return {
"feature_type": "槽/半孔候选",
@@ -861,6 +888,7 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
"same_domain_face_count": len(side_face_ids),
"feature_highlight_face_ids": tuple(side_face_ids),
"angular_span": combined_span,
"selected_angular_span": selected_span,
"same_domain_angular_span": combined_span,
"same_domain_note": same_domain_note,
"is_full_cylinder": combined_span >= math.tau * 0.92,
@@ -2813,6 +2841,7 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
bottom_face_ids = end_faces["bottom_face_ids"]
opening_face_ids = end_faces["opening_face_ids"]
guess = str(info.get("feature_guess", "cylindrical face"))
selected_angular_span = _float_or_none(info.get("angular_span")) or combined_angular_span
has_two_axial_caps = bool(end_faces["start_end_face_ids"] and end_faces["end_end_face_ids"])
support_face_ids_for_round = sorted(set(adjacent_face_ids) - set(end_face_ids))
material_toward = str(info.get("material_toward_axis", "") or "")
@@ -2832,13 +2861,37 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
"cocylindrical region has material inside its axis and explicit planar caps at both ends"
)
domain_info["feature_guess"] = info["feature_guess"]
slot_info = self._cylindrical_slot_info(face_id, adjacent_face_ids, end_face_ids, domain_info)
is_blind_split_cylindrical_pocket = (
guess == "hole/groove candidate"
and len(side_face_ids) > 1
and combined_angular_span >= math.tau * 0.92
and 1e-6 < selected_angular_span < math.tau * 0.92
and str(info.get("cylinder_end_type") or "") == "blind"
and bool(bottom_face_ids)
and bool(opening_face_ids)
)
slot_domain_info = dict(domain_info)
if is_blind_split_cylindrical_pocket:
slot_domain_info["angular_span"] = selected_angular_span
slot_domain_info["is_full_cylinder"] = False
slot_info = self._cylindrical_slot_info(face_id, adjacent_face_ids, end_face_ids, slot_domain_info)
fillet_info = self._cylindrical_existing_fillet_info(face_id, adjacent_face_ids, end_face_ids, domain_info)
try:
slot_pair_candidate_count = int(slot_info.get("slot_pair_candidate_count", 0) or 0)
except (TypeError, ValueError):
slot_pair_candidate_count = 0
is_blind_split_cylindrical_groove = (
is_blind_split_cylindrical_pocket
and slot_pair_candidate_count >= 10
)
guess = str(info.get("feature_guess", "cylindrical face"))
angular_span = combined_angular_span
angular_span = selected_angular_span if is_blind_split_cylindrical_groove else combined_angular_span
if guess == "hole/groove candidate":
if angular_span < math.tau * 0.92:
if is_blind_split_cylindrical_groove:
feature_type = "盲槽/圆柱凹槽候选"
edit_actions = "调整槽/凹槽宽度;调整槽/凹槽深度;调整圆弧长度;调整圆弧角度"
elif angular_span < math.tau * 0.92:
feature_type = "槽/半孔候选"
edit_actions = "调整圆柱孔径;调整槽/半孔宽度;调整槽/半孔深度;调整槽/半孔圆弧长度;调整槽/半孔圆弧角度;调整槽孔总长度"
else:
@@ -2848,7 +2901,7 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
edit_actions += ";调整盲孔/盲槽深度"
else:
edit_actions += ";孔深调整需要明确盲孔底面"
if angular_span >= math.tau * 0.92:
if angular_span >= math.tau * 0.92 and not is_blind_split_cylindrical_groove:
edit_actions += ";封堵圆柱孔"
elif guess == "round/fillet candidate":
fillet_status = str(fillet_info.get("existing_fillet_status") or "")
@@ -2868,7 +2921,9 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
else:
feature_type = "未明确圆柱特征"
edit_actions = "可尝试调整圆柱孔径,但风险较高。"
if str(slot_info.get("slot_status") or "") == "blocked":
if str(slot_info.get("slot_status") or "") == "blocked" and (
is_blind_split_cylindrical_groove or angular_span < math.tau * 0.92
):
feature_type = "复杂槽/多槽组候选(暂不支持修改)"
edit_actions = "只读诊断;当前不开放槽宽、槽深、弧长、弧角或槽轴心修改。"
@@ -2900,7 +2955,8 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
"same_domain_height_estimate": axis_range["span"],
"same_domain_angular_span": combined_angular_span,
"angular_span": combined_angular_span,
"is_full_cylinder": combined_angular_span >= math.tau * 0.92,
"is_full_cylinder": combined_angular_span >= math.tau * 0.92 and not is_blind_split_cylindrical_groove,
"blind_split_cylindrical_groove": is_blind_split_cylindrical_groove,
"same_domain_range_source": axis_range["range_source"],
"same_domain_face_ids": tuple(side_face_ids),
"same_domain_face_count": len(side_face_ids),
@@ -2921,7 +2977,15 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
}
)
result.update(self._asitus_cylindrical_feature_hint_fields(face_id, result))
if angular_span >= math.tau * 0.92:
if is_blind_split_cylindrical_groove:
result["angular_span"] = selected_angular_span
result.setdefault("slot_kind", "partial-cylindrical-groove")
result.setdefault("slot_status", "candidate")
result.setdefault(
"slot_note",
"同域碎面合并后接近完整圆柱,但当前对象只有一个开口和一个底面,按盲槽/圆柱凹槽处理。",
)
elif angular_span >= math.tau * 0.92:
result.update(
{
"slot_kind": "",
@@ -2938,7 +3002,7 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
}
)
scoped_readiness_info = dict(result)
scoped_readiness_info["angular_span"] = combined_angular_span
scoped_readiness_info["angular_span"] = angular_span
scoped_readiness_info["height_estimate"] = axis_range["span"]
scoped_readiness_info["feature_guess"] = guess
if guess == "hole/groove candidate":
@@ -2966,7 +3030,9 @@ class StepModel(FeatureMixin, ExportMixin, TransformMixin, OperationMixin, Polyd
"resize_note": "当前对象已识别为圆角/倒圆;请使用已有圆角半径入口,不按孔径重切。",
}
)
if str(slot_info.get("slot_status") or "") == "blocked":
if str(slot_info.get("slot_status") or "") == "blocked" and (
is_blind_split_cylindrical_groove or angular_span < math.tau * 0.92
):
blocker = str(slot_info.get("slot_blockers") or "当前槽/半孔属于复杂槽或多槽组,暂不开放稳定修改。")
result.update(
{