From 3fbdb065fdc42641cd4e277e40a5510604ea047b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 5 Oct 2023 22:25:30 +0200 Subject: [PATCH] Editor option for controlling snapping (snap to grid while moving), more consistent snap behavior, instance snapping --- src/edt/edt/EditorOptionsGeneric.ui | 53 ++++++++++++++----------- src/edt/edt/edtConfig.cc | 1 + src/edt/edt/edtConfig.h | 1 + src/edt/edt/edtEditorOptionsPages.cc | 6 +++ src/edt/edt/edtPartialService.cc | 4 ++ src/edt/edt/edtPartialService.h | 1 + src/edt/edt/edtPlugin.cc | 1 + src/edt/edt/edtService.cc | 59 +++++++++++++++++++++------- src/edt/edt/edtService.h | 4 +- src/laybasic/laybasic/layMarker.h | 8 ++++ src/laybasic/laybasic/laySnap.cc | 9 ++++- src/laybasic/laybasic/laySnap.h | 6 ++- 12 files changed, 112 insertions(+), 41 deletions(-) diff --git a/src/edt/edt/EditorOptionsGeneric.ui b/src/edt/edt/EditorOptionsGeneric.ui index 8de52d0097..84c102c717 100644 --- a/src/edt/edt/EditorOptionsGeneric.ui +++ b/src/edt/edt/EditorOptionsGeneric.ui @@ -95,10 +95,30 @@ 2 - - + + + + + 0 + 0 + + + + Enter the grid in micron. Can be anisotropic ("gx,gy") + + + + + - Grid + Objects + + + + + + + Snap to other objects @@ -130,17 +150,10 @@ - - - - Snap to other objects - - - - - + + - Objects + Grid @@ -157,16 +170,10 @@ - - - - - 0 - 0 - - - - Enter the grid in micron. Can be anisotropic ("gx,gy") + + + + Snap to grid while moving diff --git a/src/edt/edt/edtConfig.cc b/src/edt/edt/edtConfig.cc index 8c158130ea..50be8b6c58 100644 --- a/src/edt/edt/edtConfig.cc +++ b/src/edt/edt/edtConfig.cc @@ -32,6 +32,7 @@ namespace edt std::string cfg_edit_grid ("edit-grid"); std::string cfg_edit_snap_to_objects ("edit-snap-to-objects"); +std::string cfg_edit_snap_objects_to_grid ("edit-snap-objects-to-grid"); std::string cfg_edit_move_angle_mode ("edit-move-angle-mode"); std::string cfg_edit_connect_angle_mode ("edit-connect-angle-mode"); std::string cfg_edit_text_string ("edit-text-string"); diff --git a/src/edt/edt/edtConfig.h b/src/edt/edt/edtConfig.h index 6a8ce403a5..36862a8ea2 100644 --- a/src/edt/edt/edtConfig.h +++ b/src/edt/edt/edtConfig.h @@ -40,6 +40,7 @@ namespace edt */ extern EDT_PUBLIC std::string cfg_edit_grid; extern EDT_PUBLIC std::string cfg_edit_snap_to_objects; +extern EDT_PUBLIC std::string cfg_edit_snap_objects_to_grid; extern EDT_PUBLIC std::string cfg_edit_move_angle_mode; extern EDT_PUBLIC std::string cfg_edit_connect_angle_mode; extern EDT_PUBLIC std::string cfg_edit_text_string; diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index e7d23954d8..74a364b5b9 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -85,6 +85,7 @@ EditorOptionsGeneric::EditorOptionsGeneric (lay::LayoutViewBase *view, lay::Disp connect (mp_ui->hier_sel_cbx, SIGNAL (clicked ()), this, SLOT (edited ())); connect (mp_ui->hier_copy_mode_cbx, SIGNAL (activated (int)), this, SLOT (edited ())); connect (mp_ui->snap_objects_cbx, SIGNAL (clicked ()), this, SLOT (edited ())); + connect (mp_ui->snap_objects_to_grid_cbx, SIGNAL (clicked ()), this, SLOT (edited ())); connect (mp_ui->max_shapes_le, SIGNAL (editingFinished ()), this, SLOT (edited ())); connect (mp_ui->show_shapes_cbx, SIGNAL (clicked ()), this, SLOT (edited ())); } @@ -132,6 +133,7 @@ EditorOptionsGeneric::apply (lay::Dispatcher *root) int cpm = mp_ui->hier_copy_mode_cbx->currentIndex (); root->config_set (cfg_edit_hier_copy_mode, tl::to_string ((cpm < 0 || cpm > 1) ? -1 : cpm)); root->config_set (cfg_edit_snap_to_objects, tl::to_string (mp_ui->snap_objects_cbx->isChecked ())); + root->config_set (cfg_edit_snap_objects_to_grid, tl::to_string (mp_ui->snap_objects_to_grid_cbx->isChecked ())); configure_from_line_edit (root, mp_ui->max_shapes_le, cfg_edit_max_shapes_of_instances); root->config_set (cfg_edit_show_shapes_of_instances, tl::to_string (mp_ui->show_shapes_cbx->isChecked ())); @@ -194,6 +196,10 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root) root->config_get (cfg_edit_snap_to_objects, snap_to_objects); mp_ui->snap_objects_cbx->setChecked (snap_to_objects); + bool snap_objects_to_grid = false; + root->config_get (cfg_edit_snap_objects_to_grid, snap_objects_to_grid); + mp_ui->snap_objects_to_grid_cbx->setChecked (snap_objects_to_grid); + unsigned int max_shapes = 1000; root->config_get (cfg_edit_max_shapes_of_instances, max_shapes); mp_ui->max_shapes_le->setText (tl::to_qstring (tl::to_string (max_shapes))); diff --git a/src/edt/edt/edtPartialService.cc b/src/edt/edt/edtPartialService.cc index 85fe17e9ec..0721171539 100644 --- a/src/edt/edt/edtPartialService.cc +++ b/src/edt/edt/edtPartialService.cc @@ -1102,6 +1102,7 @@ PartialService::PartialService (db::Manager *manager, lay::LayoutViewBase *view, m_buttons (0), m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global), m_snap_to_objects (true), + m_snap_objects_to_grid (true), m_top_level_sel (false), m_hover (false), m_hover_wait (false), @@ -1341,6 +1342,9 @@ PartialService::configure (const std::string &name, const std::string &value) } else if (name == cfg_edit_snap_to_objects) { tl::from_string (value, m_snap_to_objects); return true; // taken + } else if (name == cfg_edit_snap_objects_to_grid) { + tl::from_string (value, m_snap_objects_to_grid); + return true; // taken } else if (name == cfg_edit_move_angle_mode) { acc.from_string (value, m_move_ac); return true; // taken diff --git a/src/edt/edt/edtPartialService.h b/src/edt/edt/edtPartialService.h index cdc07b61dc..cd98b953da 100644 --- a/src/edt/edt/edtPartialService.h +++ b/src/edt/edt/edtPartialService.h @@ -341,6 +341,7 @@ public slots: lay::angle_constraint_type m_connect_ac, m_move_ac, m_alt_ac; db::DVector m_edit_grid; bool m_snap_to_objects; + bool m_snap_objects_to_grid; db::DVector m_global_grid; bool m_top_level_sel; diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index d9e374902f..a23055a27b 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -331,6 +331,7 @@ class MainPluginDeclaration options.push_back (std::pair (cfg_edit_hier_copy_mode, "-1")); options.push_back (std::pair (cfg_edit_grid, "")); options.push_back (std::pair (cfg_edit_snap_to_objects, "false")); + options.push_back (std::pair (cfg_edit_snap_objects_to_grid, "true")); options.push_back (std::pair (cfg_edit_move_angle_mode, "any")); options.push_back (std::pair (cfg_edit_connect_angle_mode, "any")); options.push_back (std::pair (cfg_edit_combine_mode, "add")); diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 1b5950d61f..83a0b8744b 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -72,7 +72,8 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter m_flags (flags), m_move_sel (false), m_moving (false), m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global), - m_snap_to_objects (false), + m_snap_to_objects (true), + m_snap_objects_to_grid (true), m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000), m_hier_copy_mode (-1), m_indicate_secondary_selection (false), @@ -94,6 +95,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view) m_move_sel (false), m_moving (false), m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global), m_snap_to_objects (true), + m_snap_objects_to_grid (true), m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000), m_hier_copy_mode (-1), m_indicate_secondary_selection (false), @@ -152,7 +154,6 @@ void Service::update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const { db::DVector v = snap (pt) - pt; - v = lay::snap_angle (v, move_ac ()); if (! result_set || v.length () < vr.length ()) { result_set = true; @@ -204,32 +205,51 @@ Service::update_vector_snapped_marker (const lay::ShapeMarker *sm, const db::DTr } } +void +Service::update_vector_snapped_marker (const lay::InstanceMarker *im, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const +{ + const db::Instance &instance = im->instance (); + db::CplxTrans tr = db::DCplxTrans (trans) * db::DCplxTrans (-im->trans ().disp ()) * im->trans (); + + update_vector_snapped_point (tr * (instance.complex_trans () * db::Point ()), vr, result_set); + --count; +} + db::DVector -Service::snap_marker_to_grid (const db::DVector &v) const +Service::snap_marker_to_grid (const db::DVector &v, bool &snapped) const { + if (! m_snap_objects_to_grid) { + return v; + } + + snapped = false; db::DVector vr; - bool result_set = false; // max. 10000 checks size_t count = 10000; - db::DTrans tt = db::DTrans (v); + db::DVector snapped_to (1.0, 1.0); + db::DVector vv = lay::snap_angle (v, move_ac (), &snapped_to); + + db::DTrans tt = db::DTrans (vv); for (auto m = m_markers.begin (); m != m_markers.end () && count > 0; ++m) { const lay::ShapeMarker *sm = dynamic_cast (*m); + const lay::InstanceMarker *im = dynamic_cast (*m); if (sm) { - update_vector_snapped_marker (sm, tt, vr, result_set, count); - } else { - // @@@ instance markers + update_vector_snapped_marker (sm, tt, vr, snapped, count); + } else if (im) { + update_vector_snapped_marker (im, tt, vr, snapped, count); } } - if (result_set) { - return vr + v; + if (snapped) { + vr += vv; + return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ()); } else { - return v; + return db::DVector (); } } @@ -324,6 +344,13 @@ Service::configure (const std::string &name, const std::string &value) return true; // taken + } else if (name == cfg_edit_snap_objects_to_grid) { + + tl::from_string (value, m_snap_objects_to_grid); + service_configuration_changed (); + + return true; // taken + } else if (name == cfg_edit_move_angle_mode) { acc.from_string (value, m_move_ac); @@ -521,8 +548,9 @@ Service::move (const db::DPoint &pu, lay::angle_constraint_type ac) m_alt_ac = ac; if (view ()->is_editable () && m_moving) { db::DPoint ref = snap (m_move_start); - db::DPoint p = ref + snap_marker_to_grid (pu - ref); - if (p.equal (pu)) { + bool snapped = false; + db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped); + if (! snapped) { p = ref + snap (pu - m_move_start, false /*move*/); } move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref)); @@ -536,8 +564,9 @@ Service::move_transform (const db::DPoint &pu, db::DFTrans tr, lay::angle_constr m_alt_ac = ac; if (view ()->is_editable () && m_moving) { db::DPoint ref = snap (m_move_start); - db::DPoint p = ref + snap_marker_to_grid (pu - ref); - if (p.equal (pu)) { + bool snapped = false; + db::DPoint p = ref + snap_marker_to_grid (pu - m_move_start, snapped); + if (! snapped) { p = ref + snap (pu - m_move_start, false /*move*/); } move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (tr * m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - ref)); diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index 55f756f1bf..bc09bed4b2 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -524,7 +524,7 @@ class EDT_PUBLIC Service * @param v The input displacement * @return A displacement that pushes the (current) markers on-grid, definition depending on marker */ - db::DVector snap_marker_to_grid (const db::DVector &v) const; + db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) const; /** * @brief Snap a point to the edit grid with advanced snapping (including object snapping) @@ -613,6 +613,7 @@ class EDT_PUBLIC Service lay::angle_constraint_type m_connect_ac, m_move_ac, m_alt_ac; db::DVector m_edit_grid; bool m_snap_to_objects; + bool m_snap_objects_to_grid; db::DVector m_global_grid; bool m_top_level_sel; bool m_show_shapes_of_instances; @@ -668,6 +669,7 @@ class EDT_PUBLIC Service void copy_selected (unsigned int inst_mode); void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const; void update_vector_snapped_marker (const lay::ShapeMarker *sm, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const; + void update_vector_snapped_marker (const lay::InstanceMarker *sm, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const; }; } diff --git a/src/laybasic/laybasic/layMarker.h b/src/laybasic/laybasic/layMarker.h index 2563bd6989..3fa54b4427 100644 --- a/src/laybasic/laybasic/layMarker.h +++ b/src/laybasic/laybasic/layMarker.h @@ -439,6 +439,14 @@ class LAYBASIC_PUBLIC InstanceMarker */ ~InstanceMarker (); + /** + * @brief Gets the instance + */ + const db::Instance &instance () const + { + return m_inst; + } + /** * @brief Set the instance the marker is to display * diff --git a/src/laybasic/laybasic/laySnap.cc b/src/laybasic/laybasic/laySnap.cc index b6d268b328..d04f9395bb 100644 --- a/src/laybasic/laybasic/laySnap.cc +++ b/src/laybasic/laybasic/laySnap.cc @@ -183,7 +183,7 @@ draw_round_dbl (const db::DPoint &p1, const db::DPoint &p2, int /*h*/) } db::DVector -snap_angle (const db::DVector &in, lay::angle_constraint_type ac) +snap_angle (const db::DVector &in, lay::angle_constraint_type ac, db::DVector *snapped_to) { std::vector ref_dir; if (ac != lay::AC_Any) { @@ -206,11 +206,17 @@ snap_angle (const db::DVector &in, lay::angle_constraint_type ac) proj = db::sprod (*re, in) / (elen * re->length ()); if (proj > max_proj) { max_proj = proj; + if (snapped_to) { + *snapped_to = *re; + } out = *re * (elen * proj / re->length ()); } proj = db::sprod (-*re, in) / (elen * re->length ()); if (proj > max_proj) { max_proj = proj; + if (snapped_to) { + *snapped_to = *re; + } out = -*re * (elen * proj / re->length ()); } } @@ -218,6 +224,7 @@ snap_angle (const db::DVector &in, lay::angle_constraint_type ac) return out; } + // --------------------------------------------------------------------------------------- // obj_snap implementations diff --git a/src/laybasic/laybasic/laySnap.h b/src/laybasic/laybasic/laySnap.h index 6ac05fc685..bb22a2be95 100644 --- a/src/laybasic/laybasic/laySnap.h +++ b/src/laybasic/laybasic/laySnap.h @@ -238,8 +238,12 @@ namespace lay /** * @brief Reduce a given vector according to the angle constraint + * + * If the "snapped_to" pointer is non-null, it will receive the snap target + * vector (e.g. (1, 0) for snapping to horizontal axis. If no snapping happens, + * the value of this vector is not changed. */ - LAYBASIC_PUBLIC db::DVector snap_angle (const db::DVector &in, lay::angle_constraint_type ac); + LAYBASIC_PUBLIC db::DVector snap_angle (const db::DVector &in, lay::angle_constraint_type ac, db::DVector *snapped_to = 0); /** * @brief rounding of a double value for drawing purposes