diff --git a/src/doc/doc/about/25d_screenshot2.png b/src/doc/doc/about/25d_screenshot2.png
index 5c988166f4..eabf73fcff 100644
Binary files a/src/doc/doc/about/25d_screenshot2.png and b/src/doc/doc/about/25d_screenshot2.png differ
diff --git a/src/doc/doc/about/25d_view.xml b/src/doc/doc/about/25d_view.xml
index 22438889e8..1a33a8c5fe 100644
--- a/src/doc/doc/about/25d_view.xml
+++ b/src/doc/doc/about/25d_view.xml
@@ -171,19 +171,19 @@ end
-poly = input(2, 0)
-active = input(1, 0)
+gate = input(1, 0)
+active = input(2, 0)
-z(poly, zstart: 0, height: 20.nm, name: "POLY")
+z(active, zstart: 0, height: 20.nm, name: "ACTIVE")
-zz(name: "ACTIVE", like: "1/0") do
+zz(name: "GATE", like: "1/0") do
- poly_sized = poly.sized(10.nm)
- active_over_poly_sized = poly_sized & active
+ active_sized = active.sized(10.nm)
+ gate_over_active_sized = active_sized & gate
- z(active - poly, zstart: 0, height: 10.nm) # bottom sheet
- z(active_over_poly_sized - poly, height: 10.nm) # center sheet
- z(active_over_poly_sized, height: 10.nm) # top sheet
+ z(gate - active, zstart: 0, height: 10.nm)
+ z(gate_over_active_sized - active, height: 10.nm)
+ z(gate_over_active_sized, height: 10.nm)
end
diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb
index 53ac76a5a8..8aaa4341d1 100644
--- a/src/drc/drc/built-in-macros/_drc_engine.rb
+++ b/src/drc/drc/built-in-macros/_drc_engine.rb
@@ -1595,7 +1595,7 @@ def output_cell(cellname)
if ! @def_output
if @def_layout
# establish a new default output from the default layout on this occasion
- @def_output = LayoutOutputChannel::new(self, @def_layout, cellname.to_s, nil)
+ @def_output = LayoutOutputChannel::new(self, @def_layout, @def_layout.cell(cellname.to_s), nil)
end
else
@def_output.cellname = cellname.to_s
diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc
index 74db2a3fa0..3851b72ecb 100644
--- a/src/drc/unit_tests/drcSimpleTests.cc
+++ b/src/drc/unit_tests/drcSimpleTests.cc
@@ -1547,6 +1547,16 @@ TEST(60d_issue1216)
run_test (_this, "60", true);
}
+TEST(61_issue1485)
+{
+ run_test (_this, "61", false);
+}
+
+TEST(61d_issue1485)
+{
+ run_test (_this, "61", true);
+}
+
TEST(70_props)
{
run_test (_this, "70", false);
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 368ddaa394..565dbb24fa 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
@@ -1651,7 +1655,7 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
- m_current = m_start + snap (p - m_start);
+ m_current = m_start + snap_move (p - m_start);
} else {
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
@@ -1660,7 +1664,7 @@ PartialService::mouse_move_event (const db::DPoint &p, unsigned int buttons, boo
} else {
// snap movement to angle and grid without object
- m_current = m_start + snap (p - m_start);
+ m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors ();
}
@@ -2198,9 +2202,86 @@ PartialService::begin_move (MoveMode mode, const db::DPoint &p, lay::angle_const
}
}
+void
+PartialService::update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const
+{
+ db::DVector v = snap (pt) - pt;
+
+ if (! result_set || v.length () < vr.length ()) {
+ result_set = true;
+ vr = v;
+ }
+}
+
+db::DVector
+PartialService::snap_marker_to_grid (const db::DVector &v, bool &snapped) const
+{
+ if (! m_snap_objects_to_grid) {
+ return v;
+ }
+
+ snapped = false;
+ db::DVector vr;
+
+ // max. 10000 checks
+ size_t count = 10000;
+
+ db::DVector snapped_to (1.0, 1.0);
+ db::DVector vv = lay::snap_angle (v, move_ac (), &snapped_to);
+
+ TransformationVariants tv (view ());
+
+ for (auto r = m_selection.begin (); r != m_selection.end (); ++r) {
+
+ if (! r->first.is_valid (view ()) || r->first.is_cell_inst ()) {
+ continue;
+ }
+
+ const lay::CellView &cv = view ()->cellview (r->first.cv_index ());
+ const std::vector *tv_list = tv.per_cv_and_layer (r->first.cv_index (), r->first.layer ());
+ if (!tv_list || tv_list->empty ()) {
+ continue;
+ }
+
+ db::CplxTrans tr = db::DCplxTrans (vv) * tv_list->front () * db::CplxTrans (cv->layout ().dbu ()) * cv.context_trans () * r->first.trans ();
+
+ for (auto e = r->second.begin (); e != r->second.end () && count > 0; ++e) {
+ update_vector_snapped_point (tr * e->p1 (), vr, snapped);
+ --count;
+ if (count > 0) {
+ update_vector_snapped_point (tr * e->p2 (), vr, snapped);
+ --count;
+ }
+ }
+
+ }
+
+ if (snapped) {
+ vr += vv;
+ return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ());
+ } else {
+ return db::DVector ();
+ }
+}
+
+db::DVector
+PartialService::snap_move (const db::DVector &v) const
+{
+ bool snapped = false;
+ db::DVector vs = snap_marker_to_grid (v, snapped);
+ if (! snapped) {
+ vs = snap (v);
+ }
+ return vs;
+}
+
void
PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
{
+ if (! m_dragging) {
+ return;
+ }
+
m_alt_ac = ac;
set_cursor (lay::Cursor::size_all);
@@ -2214,7 +2295,7 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
// thus, we can bring the point on grid or to an object's edge or vertex
snap_details = snap2 (p);
if (snap_details.object_snap == lay::PointSnapToObjectResult::NoObject) {
- m_current = m_start + snap (p - m_start);
+ m_current = m_start + snap_move (p - m_start);
} else {
m_current = snap_details.snapped_point;
mouse_cursor_from_snap_details (snap_details);
@@ -2223,7 +2304,7 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
} else {
// snap movement to angle and grid without object
- m_current = m_start + snap (p - m_start);
+ m_current = m_start + snap_move (p - m_start);
clear_mouse_cursors ();
}
@@ -2236,6 +2317,10 @@ PartialService::move (const db::DPoint &p, lay::angle_constraint_type ac)
void
PartialService::end_move (const db::DPoint & /*p*/, lay::angle_constraint_type ac)
{
+ if (! m_dragging) {
+ return;
+ }
+
m_alt_ac = ac;
if (m_current != m_start) {
diff --git a/src/edt/edt/edtPartialService.h b/src/edt/edt/edtPartialService.h
index cdc07b61dc..113cac0f5b 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;
@@ -373,6 +374,9 @@ public slots:
db::DPoint snap (const db::DPoint &p) const;
db::DVector snap (const db::DVector &p) const;
lay::PointSnapToObjectResult snap2 (const db::DPoint &p) const;
+ void update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const;
+ db::DVector snap_marker_to_grid (const db::DVector &v, bool &snapped) const;
+ db::DVector snap_move(const db::DVector &p) const;
void enter_edge (const EdgeWithIndex &e, size_t &nmarker, partial_objects::const_iterator sel, const std::map &new_points, const std::map &new_edges, const db::ICplxTrans >, const std::vector &tv, bool transient);
void enter_vertices (size_t &nmarker, partial_objects::const_iterator sel, const std::map &new_points, const std::map &new_edges, const db::ICplxTrans >, const std::vector &tv, bool transient);
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 d2bb74075a..5d415b9b5d 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),
@@ -148,6 +150,123 @@ Service::snap (db::DPoint p) const
return p;
}
+void
+Service::update_vector_snapped_point (const db::DPoint &pt, db::DVector &vr, bool &result_set) const
+{
+ db::DVector v = snap (pt) - pt;
+
+ if (! result_set || v.length () < vr.length ()) {
+ result_set = true;
+ vr = v;
+ }
+}
+
+void
+Service::update_vector_snapped_marker (const lay::ShapeMarker *sm, const db::DTrans &trans, db::DVector &vr, bool &result_set, size_t &count) const
+{
+ const db::Shape &shape = sm->shape ();
+ db::CplxTrans tr = db::DCplxTrans (trans) * db::DCplxTrans (-sm->trans ().disp ()) * sm->trans ();
+
+ if (shape.is_text ()) {
+
+ update_vector_snapped_point (tr * shape.bbox ().center (), vr, result_set);
+ --count;
+
+ } else if (shape.is_point ()) {
+
+ update_vector_snapped_point (tr * shape.point (), vr, result_set);
+ --count;
+
+ } else if (shape.is_edge ()) {
+
+ update_vector_snapped_point (tr * shape.edge ().p1 (), vr, result_set);
+ --count;
+ if (count > 0) {
+ update_vector_snapped_point (tr * shape.edge ().p2 (), vr, result_set);
+ --count;
+ }
+
+ } else if (shape.is_path ()) {
+
+ for (auto pt = shape.begin_point (); pt != shape.end_point () && count > 0; ++pt) {
+ update_vector_snapped_point (tr * *pt, vr, result_set);
+ --count;
+ }
+
+ } else if (shape.is_box ()) {
+
+ db::Box box = shape.bbox ();
+ for (unsigned int c = 0; c < 4 && count > 0; ++c) {
+ db::Point pt = db::Point ((c & 1) != 0 ? box.left () : box.right (), (c & 2) != 0 ? box.bottom () : box.top ());
+ update_vector_snapped_point (tr * pt, vr, result_set);
+ --count;
+ }
+
+ } else if (shape.is_polygon ()) {
+
+ for (auto pt = shape.begin_hull (); pt != shape.end_hull () && count > 0; ++pt) {
+ update_vector_snapped_point (tr * *pt, vr, result_set);
+ --count;
+ }
+
+ for (unsigned int h = 0; h < shape.holes () && count > 0; ++h) {
+ for (auto pt = shape.begin_hole (h); pt != shape.end_hole (h) && count > 0; ++pt) {
+ update_vector_snapped_point (tr * *pt, vr, result_set);
+ --count;
+ }
+ }
+
+ }
+}
+
+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, bool &snapped) const
+{
+ if (! m_snap_objects_to_grid) {
+ return v;
+ }
+
+ snapped = false;
+ db::DVector vr;
+
+ // max. 10000 checks
+ size_t count = 10000;
+
+ 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, snapped, count);
+ } else if (im) {
+ update_vector_snapped_marker (im, tt, vr, snapped, count);
+ }
+
+ }
+
+ if (snapped) {
+ vr += vv;
+ return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ());
+ } else {
+ return db::DVector ();
+ }
+}
+
db::DVector
Service::snap (db::DVector v) const
{
@@ -239,6 +358,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);
@@ -434,9 +560,14 @@ void
Service::move (const db::DPoint &pu, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
- db::DPoint p = snap (m_move_start) + snap (pu - m_move_start, false /*move*/);
if (view ()->is_editable () && m_moving) {
- move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (m_move_trans.fp_trans ()) * db::DTrans (db::DPoint () - snap (m_move_start)));
+ db::DPoint ref = snap (m_move_start);
+ 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));
}
m_alt_ac = lay::AC_Global;
}
@@ -445,9 +576,14 @@ void
Service::move_transform (const db::DPoint &pu, db::DFTrans tr, lay::angle_constraint_type ac)
{
m_alt_ac = ac;
- db::DPoint p = snap (m_move_start) + snap (pu - m_move_start, false);
if (view ()->is_editable () && m_moving) {
- move_markers (db::DTrans (p - db::DPoint ()) * db::DTrans (m_move_trans.fp_trans () * tr) * db::DTrans (db::DPoint () - snap (m_move_start)));
+ db::DPoint ref = snap (m_move_start);
+ 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));
}
m_alt_ac = lay::AC_Global;
}
diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h
index 14e16c22fc..bc09bed4b2 100644
--- a/src/edt/edt/edtService.h
+++ b/src/edt/edt/edtService.h
@@ -518,6 +518,14 @@ class EDT_PUBLIC Service
*/
db::DVector snap (const db::DVector &v, bool connect) const;
+ /**
+ * @brief Proposes a grid-snapped displacement vector
+ *
+ * @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, bool &snapped) const;
+
/**
* @brief Snap a point to the edit grid with advanced snapping (including object snapping)
*
@@ -605,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;
@@ -658,6 +667,9 @@ class EDT_PUBLIC Service
private:
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/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc
index b4309db4ae..e7c54f7687 100644
--- a/src/lay/lay/layApplication.cc
+++ b/src/lay/lay/layApplication.cc
@@ -817,10 +817,8 @@ ApplicationBase::init_app ()
}
}
- std::set already_executed;
-
// run all early autorun macros
- lym::MacroCollection::root ().autorun_early (&already_executed);
+ lym::MacroCollection::root ().autorun_early ();
// redo gsi::initialize as the macros may have registered new external classes
// through the "doc to external class" mechanism.
@@ -833,7 +831,7 @@ ApplicationBase::init_app ()
// as this regenerates the macro collection, autorun_early is required again
// note: this does no re-execute macros that have been executed already
- lym::MacroCollection::root ().autorun_early (&already_executed);
+ lym::MacroCollection::root ().autorun_early ();
}
@@ -842,7 +840,7 @@ ApplicationBase::init_app ()
lym::MacroCollection::root ().rescan ();
// and yet another autorun_early pass ..
- lym::MacroCollection::root ().autorun_early (&already_executed);
+ lym::MacroCollection::root ().autorun_early ();
// creates the main window or plugin root as required
setup ();
diff --git a/src/laybasic/laybasic/layMarker.h b/src/laybasic/laybasic/layMarker.h
index d807dbf24b..3fa54b4427 100644
--- a/src/laybasic/laybasic/layMarker.h
+++ b/src/laybasic/laybasic/layMarker.h
@@ -396,6 +396,14 @@ class LAYBASIC_PUBLIC ShapeMarker
*/
void set (const db::Shape &shape, const db::ICplxTrans &t1, const std::vector &trans);
+ /**
+ * @brief Gets the shape
+ */
+ const db::Shape &shape () const
+ {
+ return m_shape;
+ }
+
private:
virtual void render (const Viewport &vp, ViewObjectCanvas &canvas);
@@ -431,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
diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc
index ac179c0ea3..e6884cce1b 100644
--- a/src/lym/lym/lymMacro.cc
+++ b/src/lym/lym/lymMacro.cc
@@ -55,7 +55,10 @@ namespace lym
// ----------------------------------------------------------------------
Macro::Macro ()
- : m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_priority (0), m_show_in_menu (false), m_is_file (false), m_interpreter (None), m_format (Macro::NoFormat)
+ : m_modified (true), m_readonly (false),
+ m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_was_autorun (false),
+ m_priority (0), m_show_in_menu (false), m_is_file (false),
+ m_interpreter (None), m_format (Macro::NoFormat)
{
mp_parent = 0;
}
@@ -70,6 +73,8 @@ void Macro::on_menu_needs_update ()
void Macro::on_changed ()
{
+ m_was_autorun = false;
+
#if defined(HAVE_QT)
emit changed ();
if (mp_parent) {
@@ -796,6 +801,11 @@ void Macro::set_autorun (bool f)
}
}
+void Macro::set_was_autorun (bool f)
+{
+ m_was_autorun = f;
+}
+
void Macro::set_priority (int p)
{
if (p != m_priority) {
diff --git a/src/lym/lym/lymMacro.h b/src/lym/lym/lymMacro.h
index 10acb6f362..88af3159dd 100644
--- a/src/lym/lym/lymMacro.h
+++ b/src/lym/lym/lymMacro.h
@@ -426,6 +426,19 @@ Q_OBJECT
return m_autorun_early;
}
+ /**
+ * @brief Sets a value indicating whether the macro was alread auto-runned
+ */
+ void set_was_autorun (bool f);
+
+ /**
+ * @brief Gets a value indicating whether the macro was alread auto-runned
+ */
+ bool was_autorun () const
+ {
+ return m_was_autorun;
+ }
+
/**
* @brief Sets a value indicating whether the macro shall be executed on startup
*/
@@ -618,6 +631,7 @@ Q_OBJECT
bool m_autorun;
bool m_autorun_default;
bool m_autorun_early;
+ bool m_was_autorun;
int m_priority;
bool m_show_in_menu;
std::string m_group_name;
diff --git a/src/lym/lym/lymMacroCollection.cc b/src/lym/lym/lymMacroCollection.cc
index 6712d6549a..4982ae1922 100644
--- a/src/lym/lym/lymMacroCollection.cc
+++ b/src/lym/lym/lymMacroCollection.cc
@@ -868,7 +868,7 @@ static bool has_autorun_for (const lym::MacroCollection &collection, bool early)
}
for (lym::MacroCollection::const_iterator c = collection.begin (); c != collection.end (); ++c) {
- if ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ())) {
+ if (((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ())) && ! c->second->was_autorun ()) {
return true;
}
}
@@ -909,35 +909,28 @@ static int collect_priority (lym::MacroCollection &collection, bool early, int f
return p;
}
-static void autorun_for_prio (lym::MacroCollection &collection, bool early, std::set *executed_already, int prio)
+static void autorun_for_prio (lym::MacroCollection &collection, bool early, int prio)
{
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
- autorun_for_prio (*c->second, early, executed_already, prio);
+ autorun_for_prio (*c->second, early, prio);
}
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
- if (c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
+ if (! c->second->was_autorun () && c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
- if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) {
-
- BEGIN_PROTECTED_SILENT
- c->second->run ();
- c->second->install_doc ();
- END_PROTECTED_SILENT
-
- if (executed_already) {
- executed_already->insert (c->second->path ());
- }
-
- }
+ BEGIN_PROTECTED_SILENT
+ c->second->run ();
+ c->second->set_was_autorun (true);
+ c->second->install_doc ();
+ END_PROTECTED_SILENT
}
}
}
-static void autorun_for (lym::MacroCollection &collection, bool early, std::set *executed_already)
+static void autorun_for (lym::MacroCollection &collection, bool early)
{
int prio = 0;
while (true) {
@@ -945,19 +938,19 @@ static void autorun_for (lym::MacroCollection &collection, bool early, std::set<
if (p < prio) {
break;
}
- autorun_for_prio (collection, early, executed_already, p);
+ autorun_for_prio (collection, early, p);
prio = p + 1;
}
}
-void MacroCollection::autorun (std::set *already_executed)
+void MacroCollection::autorun ()
{
- autorun_for (*this, false, already_executed);
+ autorun_for (*this, false);
}
-void MacroCollection::autorun_early (std::set *already_executed)
+void MacroCollection::autorun_early ()
{
- autorun_for (*this, true, already_executed);
+ autorun_for (*this, true);
}
void MacroCollection::dump (int l)
diff --git a/src/lym/lym/lymMacroCollection.h b/src/lym/lym/lymMacroCollection.h
index 60c779bc5c..427f682626 100644
--- a/src/lym/lym/lymMacroCollection.h
+++ b/src/lym/lym/lymMacroCollection.h
@@ -419,7 +419,7 @@ Q_OBJECT
/**
* @brief Runs all macros marked with auto-run
*/
- void autorun (std::set *already_executed = 0);
+ void autorun ();
/**
* @brief Returns true, if the collection has an early autorun macro
@@ -429,7 +429,7 @@ Q_OBJECT
/**
* @brief Runs all macros marked with early auto-run
*/
- void autorun_early (std::set *already_executed = 0);
+ void autorun_early ();
/**
* @brief Redo the scan (will add new files or folders)
diff --git a/testdata/drc/drcSimpleTests_61.drc b/testdata/drc/drcSimpleTests_61.drc
new file mode 100644
index 0000000000..35c3d7043c
--- /dev/null
+++ b/testdata/drc/drcSimpleTests_61.drc
@@ -0,0 +1,23 @@
+
+# Moved implementation
+
+source($drc_test_source)
+target($drc_test_target)
+
+if $drc_test_deep
+ deep
+end
+
+input(1, 0).output(1, 0)
+input(2, 0).output(2, 0)
+
+cell("TOP")
+
+l1 = input(1, 0)
+l2 = input(2, 0)
+
+l1.output(10, 0)
+l2.output(11, 0)
+l1.sized(100.nm).output(20, 0)
+(l2 - l1).output(21, 0)
+
diff --git a/testdata/drc/drcSimpleTests_61.gds b/testdata/drc/drcSimpleTests_61.gds
new file mode 100644
index 0000000000..ce30bc4750
Binary files /dev/null and b/testdata/drc/drcSimpleTests_61.gds differ
diff --git a/testdata/drc/drcSimpleTests_au61.gds b/testdata/drc/drcSimpleTests_au61.gds
new file mode 100644
index 0000000000..fc3a059a00
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au61.gds differ
diff --git a/testdata/drc/drcSimpleTests_au61d.gds b/testdata/drc/drcSimpleTests_au61d.gds
new file mode 100644
index 0000000000..06538e9c17
Binary files /dev/null and b/testdata/drc/drcSimpleTests_au61d.gds differ