feat: 完善 Edge 一级编辑与 CAD 建模语义
This commit is contained in:
@@ -34,6 +34,61 @@ def _length_distribution(model: StepModel) -> dict[float, int]:
|
||||
return dict(sorted(counts.items()))
|
||||
|
||||
|
||||
def _count_near(values: list[float], target: float, tolerance: float) -> int:
|
||||
return sum(1 for value in values if abs(value - target) <= tolerance)
|
||||
|
||||
|
||||
def _assert_cube_edge_intent_geometry(
|
||||
*,
|
||||
source_length: float,
|
||||
target_length: float,
|
||||
strategy: str,
|
||||
anchor: str,
|
||||
lengths: list[float],
|
||||
tolerance: float,
|
||||
) -> None:
|
||||
target_count = _count_near(lengths, target_length, tolerance)
|
||||
source_count = _count_near(lengths, source_length, tolerance)
|
||||
delta = abs(target_length - source_length)
|
||||
effective_anchor = "keep-start" if anchor == "auto" else anchor
|
||||
if strategy == "local-edge-only-deform":
|
||||
if target_count != 1:
|
||||
raise SystemExit(
|
||||
"local Edge deformation should only make the selected Edge reach the target length; "
|
||||
f"target_count={target_count}, lengths={_length_distribution_from_values(lengths)}"
|
||||
)
|
||||
if effective_anchor == "center":
|
||||
expected_slanted = (source_length * source_length + (delta * 0.5) * (delta * 0.5)) ** 0.5
|
||||
slanted_count = _count_near(lengths, expected_slanted, tolerance)
|
||||
if source_count != 7 or slanted_count != 4:
|
||||
raise SystemExit(
|
||||
"center-anchored local Edge deformation should move both endpoints equally; "
|
||||
f"source_count={source_count}, slanted_count={slanted_count}, "
|
||||
f"expected_slanted={expected_slanted:g}, lengths={_length_distribution_from_values(lengths)}"
|
||||
)
|
||||
else:
|
||||
expected_slanted = (source_length * source_length + delta * delta) ** 0.5
|
||||
slanted_count = _count_near(lengths, expected_slanted, tolerance)
|
||||
if source_count != 9 or slanted_count != 2:
|
||||
raise SystemExit(
|
||||
"one-end anchored local Edge deformation should move only the selected Edge endpoint; "
|
||||
f"source_count={source_count}, slanted_count={slanted_count}, "
|
||||
f"expected_slanted={expected_slanted:g}, lengths={_length_distribution_from_values(lengths)}"
|
||||
)
|
||||
elif strategy in {"move-edge-end-plane-by-push-pull", "scale-owning-shape-from-edge"}:
|
||||
if target_count != 4 or source_count != 8:
|
||||
raise SystemExit(
|
||||
f"{strategy} should resize the whole cube span in the selected Edge direction; "
|
||||
f"target_count={target_count}, source_count={source_count}, "
|
||||
f"lengths={_length_distribution_from_values(lengths)}"
|
||||
)
|
||||
|
||||
|
||||
def _length_distribution_from_values(values: list[float]) -> dict[float, int]:
|
||||
counts = Counter(round(value, 6) for value in values)
|
||||
return dict(sorted(counts.items()))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Verify cube edge-length resize semantics.")
|
||||
parser.add_argument("model", nargs="?", default=str(DEFAULT_MODEL), help="STEP model path.")
|
||||
@@ -87,6 +142,24 @@ def main() -> int:
|
||||
error = abs(nearest - args.target_length)
|
||||
if error > args.tolerance:
|
||||
raise SystemExit(f"target length check failed: nearest={nearest:g}, error={error:g}")
|
||||
if (
|
||||
Path(args.model).resolve() == DEFAULT_MODEL.resolve()
|
||||
and strategy == "local-edge-only-deform"
|
||||
and (after.faces != before.faces or after.edges != before.edges)
|
||||
):
|
||||
raise SystemExit(
|
||||
"cube local Edge deformation should not split faces/edges; "
|
||||
f"before faces/edges={before.faces}/{before.edges}, after={after.faces}/{after.edges}"
|
||||
)
|
||||
if Path(args.model).resolve() == DEFAULT_MODEL.resolve():
|
||||
_assert_cube_edge_intent_geometry(
|
||||
source_length=args.source_length,
|
||||
target_length=args.target_length,
|
||||
strategy=strategy,
|
||||
anchor=args.anchor,
|
||||
lengths=lengths,
|
||||
tolerance=max(args.tolerance, 1e-5),
|
||||
)
|
||||
|
||||
print(f"model={Path(args.model)}")
|
||||
print(f"edge_id={edge_id}")
|
||||
@@ -97,6 +170,7 @@ def main() -> int:
|
||||
print(f"end_move={plan.get('local_edge_deform_end_move')}")
|
||||
print(f"before_faces={before.faces} before_edges={before.edges}")
|
||||
print(f"after_faces={after.faces} after_edges={after.edges}")
|
||||
print(f"topology_stable={after.faces == before.faces and after.edges == before.edges}")
|
||||
print(f"nearest_length={nearest:.6f} target_error={error:.6g}")
|
||||
print(f"length_distribution={_length_distribution(model)}")
|
||||
print(result.encode("ascii", "backslashreplace").decode("ascii"))
|
||||
|
||||
Reference in New Issue
Block a user