From 43454962d45357003757823b63e8b477410d697c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 30 Aug 2025 23:20:23 +0200 Subject: [PATCH] Improving ruler snapping (after move_transform, snap to objects, visual snap details hint ...) --- src/ant/ant/antService.cc | 137 +++++++++++++++++++------------- src/ant/ant/antService.h | 7 +- src/lay/lay/gsiDeclLayPlugin.cc | 8 +- 3 files changed, 88 insertions(+), 64 deletions(-) diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index d4bd0acff..6f6c0e556 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -1431,7 +1431,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang const ant::Object *robj = dynamic_cast ((*ri).ptr ()); if (robj && (! robj_min || robj == robj_min)) { - if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index) && m_move_mode != MoveRuler) { + if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index)) { // found anything: make the moved ruler the selection clear_selection (); @@ -1516,28 +1516,70 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang } void -Service::move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constraint_type /*ac*/) +Service::snap_rulers (lay::angle_constraint_type ac) +{ + if (m_rulers.empty ()) { + return; + } + + lay::PointSnapToObjectResult min_snp; + double min_dist = -1.0; + db::DVector min_delta; + + for (auto r = m_rulers.begin (); r != m_rulers.end (); ++r) { + + const ant::Object *ruler = (*r)->ruler (); + + db::DPoint p1 = m_trans * ruler->p1 (); + db::DPoint p2 = m_trans * ruler->p2 (); + + auto tr = db::DTrans ((m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1); + db::DPoint org1 = tr * ruler->p1 (); + db::DPoint org2 = tr * ruler->p2 (); + + auto snp = snap2_details (org1, p1, ruler, ac); + double dist = p1.distance (snp.snapped_point); + + if (min_dist < 0 || dist < min_dist) { + min_snp = snp; + min_dist = dist; + min_delta = snp.snapped_point - p1; + } + + snp = snap2_details (org2, p2, ruler, ac); + dist = p2.distance (snp.snapped_point); + + if (min_dist < 0 || dist < min_dist) { + min_snp = snp; + min_dist = dist; + min_delta = snp.snapped_point - p2; + } + + } + + if (min_snp.object_snap != lay::PointSnapToObjectResult::NoObject) { + mouse_cursor_from_snap_details (min_snp); + } + + m_trans = db::DTrans (min_delta) * m_trans; +} + +void +Service::move_transform (const db::DPoint & /*p*/, db::DFTrans tr, lay::angle_constraint_type ac) { if (m_rulers.empty () || m_selected.empty ()) { return; } - if (m_move_mode == MoveRuler) { + auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac; + clear_mouse_cursors (); - db::DVector dp = p - db::DPoint (); - - m_original.transform (db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1)); - m_current.transform (db::DTrans (dp) * db::DTrans (tr) * db::DTrans (-dp)); - - // display current rulers' parameters - show_message (); - - m_rulers [0]->redraw (); - - } else if (m_move_mode == MoveSelected) { + if (m_move_mode == MoveSelected) { m_trans *= db::DTrans (m_p1 - db::DPoint ()) * db::DTrans (tr) * db::DTrans (db::DPoint () - m_p1); + snap_rulers (ac_eff); + for (std::vector::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) { (*r)->transform_by (db::DCplxTrans (m_trans)); } @@ -1553,90 +1595,66 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac) return; } + auto ac_eff = ac == lay::AC_Global ? m_snap_mode : ac; + clear_mouse_cursors (); + if (m_move_mode == MoveP1) { - m_current.seg_p1 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second); + m_current.seg_p1 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac)); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP2) { - m_current.seg_p2 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second); + m_current.seg_p2 (m_seg_index, snap2_visual (m_p1, p, &m_current, ac)); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP12) { - db::DPoint p12 = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint p12 = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ())); m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ())); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP21) { - db::DPoint p21 = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint p21 = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ())); m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ())); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP1X) { - db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ())); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP2X) { - db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ())); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP1Y) { - db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ())); m_rulers [0]->redraw (); } else if (m_move_mode == MoveP2Y) { - db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; + db::DPoint pc = snap2_visual (m_p1, p, &m_current, ac); m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ())); m_rulers [0]->redraw (); - } else if (m_move_mode == MoveRuler) { - - // try two ways of snapping - db::DVector dp = lay::snap_angle (p - m_p1, ac == lay::AC_Global ? m_snap_mode : ac); - - db::DPoint p1 = m_original.p1 () + dp; - db::DPoint p2 = m_original.p2 () + dp; - - std::pair r1 = snap1 (p1, m_obj_snap && m_original.snap ()); - db::DPoint q1 = r1.second; - std::pair r2 = snap1 (p2, m_obj_snap && m_original.snap ()); - db::DPoint q2 = r2.second; - - if ((!r2.first && r1.first) || ((r1.first || (!r1.first && !r2.first)) && q1.distance (p1) < q2.distance (p2))) { - q2 = q1 + (m_original.p2 () - m_original.p1 ()); - } else { - q1 = q2 + (m_original.p1 () - m_original.p2 ()); - } - - m_current.p1 (q1); - m_current.p2 (q2); - - m_rulers [0]->redraw (); - } else if (m_move_mode == MoveSelected) { db::DVector dp = p - m_p1; - // round the drag distance to grid if required: this is the least we can do in this case - if (m_grid_snap) { - dp = db::DVector (lay::snap (dp.x (), m_grid), lay::snap (dp.y (), m_grid)); - } - - dp = lay::snap_angle (dp, ac == lay::AC_Global ? m_snap_mode : ac); + dp = lay::snap_angle (dp, ac_eff); m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1); + snap_rulers (ac_eff); + for (std::vector::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) { (*r)->transform_by (db::DCplxTrans (m_trans)); } @@ -1646,7 +1664,6 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac) if (m_move_mode != MoveSelected) { show_message (); } - } void @@ -1703,6 +1720,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type) // termine the operation m_move_mode = MoveNone; + clear_mouse_cursors (); } void @@ -2040,7 +2058,7 @@ Service::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio) // otherwise we risk manipulating p1 too. ant::Object::point_list pts = m_current.points (); if (! pts.empty ()) { - pts.back () = snap2 (m_p1, p, mp_active_ruler->ruler (), ac_from_buttons (buttons)).second; + pts.back () = snap_details.snapped_point; } m_current.set_points_exact (pts); @@ -2095,11 +2113,16 @@ Service::snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::O return lay::obj_snap (m_obj_snap && obj->snap () ? mp_view : 0, p1, p2, g, snap_mode, snap_range); } -std::pair -Service::snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac) +db::DPoint +Service::snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac) { lay::PointSnapToObjectResult res = snap2_details (p1, p2, obj, ac); - return std::make_pair (res.object_snap != lay::PointSnapToObjectResult::NoObject, res.snapped_point); + + if (res.object_snap != lay::PointSnapToObjectResult::NoObject) { + mouse_cursor_from_snap_details (res); + } + + return res.snapped_point; } diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h index 509d00289..13086eeb4 100644 --- a/src/ant/ant/antService.h +++ b/src/ant/ant/antService.h @@ -208,10 +208,9 @@ public: * MoveP2X - dragging P2.x (if box-like) * MoveP1Y - dragging P1.y (if box-like) * MoveP2Y - dragging P2.y (if box-like) - * MoveRuler - dragging a whole ruler (one) * MoveSelection - dragging a whole ruler (many) */ - enum MoveMode { MoveNone, MoveP1, MoveP2, MoveP12, MoveP21, MoveP1X, MoveP2X, MoveP1Y, MoveP2Y, MoveRuler, MoveSelected }; + enum MoveMode { MoveNone, MoveP1, MoveP2, MoveP12, MoveP21, MoveP1X, MoveP2X, MoveP1Y, MoveP2Y, MoveSelected }; Service (db::Manager *manager, lay::LayoutViewBase *view); @@ -601,7 +600,7 @@ private: std::pair snap1 (const db::DPoint &p, bool obj_snap); lay::PointSnapToObjectResult snap1_details (const db::DPoint &p, bool obj_snap); - std::pair snap2 (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac); + db::DPoint snap2_visual (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac); lay::PointSnapToObjectResult snap2_details (const db::DPoint &p1, const db::DPoint &p2, const ant::Object *obj, lay::angle_constraint_type ac); lay::TwoPointSnapToObjectResult auto_measure (const db::DPoint &p, lay::angle_constraint_type ac, const ant::Template &tpl); @@ -620,6 +619,8 @@ private: virtual bool mouse_double_click_event (const db::DPoint &p, unsigned int buttons, bool prio); virtual void deactivated (); + void snap_rulers (lay::angle_constraint_type ac); + /** * @brief Select a certain ruler * diff --git a/src/lay/lay/gsiDeclLayPlugin.cc b/src/lay/lay/gsiDeclLayPlugin.cc index ca58818e8..ee4bf3441 100644 --- a/src/lay/lay/gsiDeclLayPlugin.cc +++ b/src/lay/lay/gsiDeclLayPlugin.cc @@ -1584,8 +1584,8 @@ Class decl_Plugin ("lay", "Plugin", "angle constraint. Only grid constraints and snapping to objects is supported.\n" "\n" "If \"visualize\" is true, the function will generate calls to \\add_mouse_cursor or \\add_edge_marker to " - "provide a visualization of the edges or vertexes that the point is snapping to. If you use this feature, " - "make sure you call \\clear_mouse_cursors before to remove existing cursors.\n" + "provide a visualization of the edges or vertexes that the point is snapping to. \\clear_mouse_cursors will " + "be called before.\n" "\n" "This method has been added in version 0.30.4." ) + @@ -1609,8 +1609,8 @@ Class decl_Plugin ("lay", "Plugin", "will snap to another object. The behavior is given by the respective configuration.\n" "\n" "If \"visualize\" is true, the function will generate calls to \\add_mouse_cursor or \\add_edge_marker to " - "provide a visualization of the edges or vertexes that the point is snapping to. If you use this feature, " - "make sure you call \\clear_mouse_cursors before to remove existing cursors.\n" + "provide a visualization of the edges or vertexes that the point is snapping to. \\clear_mouse_cursors will " + "be called before.\n" "\n" "This method has been added in version 0.30.4." ) +