9abeb6266a
- assembly forward proagation
84 lines
3.1 KiB
Python
84 lines
3.1 KiB
Python
"""Headless smoke: the manual re-pick fallback path (prompt -> frame -> pick mode)."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
|
|
|
|
import numpy as np
|
|
|
|
from OCP.gp import gp_Pnt, gp_Dir, gp_Ax2
|
|
from OCP.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
|
|
from OCP.BRepAlgoAPI import BRepAlgoAPI_Cut
|
|
|
|
from PySide6.QtWidgets import QApplication, QMessageBox
|
|
|
|
from fluency.ui.main_window import MainWindow
|
|
from fluency.models.data_model import Body
|
|
from fluency.geometry_occ.kernel import OCCGeometryObject
|
|
|
|
app = QApplication.instance() or QApplication([])
|
|
w = MainWindow()
|
|
|
|
comp = w._current_component
|
|
body = Body(name="plate")
|
|
comp.bodies[body.id] = body
|
|
box = BRepPrimAPI_MakeBox(60.0, 40.0, 5.0).Shape()
|
|
ax = gp_Ax2(gp_Pnt(10.0, 5.0, 0.0), gp_Dir(0, 0, 1))
|
|
box = BRepAlgoAPI_Cut(box, BRepPrimAPI_MakeCylinder(ax, 3.0, 6.0).Shape()).Shape()
|
|
body.geometry = OCCGeometryObject(box)
|
|
|
|
partner = w._project.add_component()
|
|
pbody = Body(name="partner")
|
|
partner.bodies[pbody.id] = pbody
|
|
pbody.geometry = OCCGeometryObject(BRepPrimAPI_MakeBox(30.0, 30.0, 10.0).Shape())
|
|
|
|
asm = w._project.get_active_assembly()
|
|
ac1 = asm.add_component_instance(comp.id, name="A")
|
|
ac2 = asm.add_component_instance(partner.id, name="B")
|
|
ac1.geom_cache[body.id] = body.geometry
|
|
c1 = ac1.add_connector(
|
|
position=(10.0, 5.0, 2.5), normal=(0, 0, 1), x_dir=(1, 0, 0),
|
|
source_obj_id=f"asm_{ac1.id}_{body.id}",
|
|
name="Conn hole", entity_type="cylindrical_face",
|
|
)
|
|
c1.partner_ac_id = ac2.id
|
|
|
|
# Activate the assembly view so the prompt path is taken.
|
|
w._assembly_view_active = True
|
|
w._selected_assembly_component_id = ac1.id
|
|
|
|
# Force a Yes from the question dialog, and record that it actually fired.
|
|
asked = {}
|
|
def fake_question(parent, title, text, buttons, default):
|
|
asked["title"] = title
|
|
return QMessageBox.StandardButton.Yes
|
|
QMessageBox.question = staticmethod(fake_question)
|
|
def fake_warning(*a, **k):
|
|
return QMessageBox.StandardButton.Ok
|
|
QMessageBox.warning = staticmethod(fake_warning)
|
|
|
|
w._prompt_relocate_unresolved([(asm, ac1, c1)])
|
|
assert asked.get("title") == "Connector Position Needed", asked
|
|
assert w._relocate_pending == [(asm, ac1, c1)], w._relocate_pending
|
|
assert w._viewer_3d._connector_pick_mode, "pick mode must be active"
|
|
|
|
# A wrong-part click must not consume the pending entry.
|
|
w._on_relocate_picked((0, 0, 0), (0, 0, 1), (1, 0, 0), "planar_face", f"asm_{ac2.id}_{pbody.id}")
|
|
assert w._relocate_pending == [(asm, ac1, c1)], "wrong part must not consume the pick"
|
|
|
|
# The right click re-homes and drains.
|
|
w._on_relocate_picked((40.0, 30.0, 2.5), (0, 0, 1), (1, 0, 0), "cylindrical_face", f"asm_{ac1.id}_{body.id}")
|
|
assert w._relocate_pending is None
|
|
assert np.allclose(c1.position, (40.0, 30.0, 2.5)), c1.position
|
|
assert not w._viewer_3d._connector_pick_mode, "pick mode must be off after completion"
|
|
|
|
# Esc cancel mid-flight clears the state.
|
|
w._relocate_pending = [(asm, ac1, c1)]
|
|
w._start_relocate_pick_next()
|
|
w._on_connector_pick_cancelled()
|
|
assert w._relocate_pending is None
|
|
assert not w._viewer_3d._connector_pick_mode
|
|
print("RELOCATE_PICK_FALLBACK_OK")
|