Issue 1145 (#1151)

* [CONSIDER MERGING] Clarification and typo fixed in DRC doc.

* Enhanced Shapes::is_valid so it's more reliable in detecting invalid shape objects.

* ObjectInstPath now has a validity attribute

* First implementation of solution for edtService (partial service to follow)

* Validating selection also for Partial Edit mode
This commit is contained in:
Matthias Köfferlein 2022-09-05 23:35:21 +02:00 committed by GitHub
parent 390cac87d3
commit 769b16ea3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 114 additions and 9 deletions

View File

@ -48,6 +48,21 @@ iterator_from_shape (const db::layer<Sh, db::unstable_layer_tag> &layer, const d
return layer.begin () + (shape.basic_ptr (typename Sh::tag ()) - &*layer.begin ());
}
template <class Sh>
inline bool
iterator_from_shape_is_valid (const db::layer<Sh, db::stable_layer_tag> &layer, const db::Shape &shape)
{
typename db::layer<Sh, db::stable_layer_tag>::iterator iter = shape.basic_iter (typename Sh::tag ());
return iter.vector () == layer.begin ().vector () && iter.is_valid ();
}
template <class Sh>
inline bool
iterator_from_shape_is_valid (const db::layer<Sh, db::unstable_layer_tag> &layer, const db::Shape &shape)
{
return layer.size () < (shape.basic_ptr (typename Sh::tag ()) - &*layer.begin ());
}
// -------------------------------------------------------------------------------
template <class Sh, class StableTag>
@ -260,10 +275,11 @@ Shapes::is_valid_shape_by_tag (Tag /*tag*/, const shape_type &shape) const
throw tl::Exception (tl::to_string (tr ("Function 'is_valid' is permitted only in editable mode")));
}
if (! shape.has_prop_id ()) {
return iterator_from_shape (get_layer<typename Tag::object_type, db::stable_layer_tag> (), shape).is_valid ();
typedef typename Tag::object_type s_type;
return iterator_from_shape_is_valid (get_layer<s_type, db::stable_layer_tag> (), shape);
} else {
typedef db::object_with_properties<typename Tag::object_type> swp_type;
return iterator_from_shape (get_layer<swp_type, db::stable_layer_tag> (), shape).is_valid ();
return iterator_from_shape_is_valid (get_layer<swp_type, db::stable_layer_tag> (), shape);
}
}

View File

@ -1028,13 +1028,16 @@ PartialService::PartialService (db::Manager *manager, lay::LayoutViewBase *view,
m_snap_to_objects (true),
m_top_level_sel (false),
m_hover (false),
m_hover_wait (false)
{
m_hover_wait (false),
dm_selection_to_view (this, &edt::PartialService::do_selection_to_view)
{
#if defined(HAVE_QT)
m_timer.setInterval (100 /*hover time*/);
m_timer.setSingleShot (true);
connect (&m_timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
#endif
mp_view->geom_changed_event.add (this, &edt::PartialService::selection_to_view);
}
PartialService::~PartialService ()
@ -2398,8 +2401,14 @@ PartialService::select (const db::DBox &box, SelectionMode mode)
return false;
}
void
void
PartialService::selection_to_view ()
{
dm_selection_to_view ();
}
void
PartialService::do_selection_to_view ()
{
// if dragging, establish the current displacement
db::DTrans move_trans;
@ -2424,6 +2433,17 @@ PartialService::selection_to_view ()
size_t n_marker = 0;
size_t n_inst_marker = 0;
// Reduce the selection to valid paths (issue-1145)
std::vector<partial_objects::iterator> invalid_objects;
for (partial_objects::iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
if (! r->first.is_valid (view ())) {
invalid_objects.push_back (r);
}
}
for (auto i = invalid_objects.begin (); i != invalid_objects.end (); ++i) {
m_selection.erase (*i);
}
if (! m_selection.empty ()) {
// build the transformation variants cache

View File

@ -31,6 +31,7 @@
#include "layRubberBox.h"
#include "laySnap.h"
#include "tlAssert.h"
#include "tlDeferredExecution.h"
#include "edtUtils.h"
#include "edtConfig.h"
@ -339,11 +340,15 @@ private:
bool m_hover_wait;
db::DPoint m_hover_point;
// Deferred method to update the selection
tl::DeferredMethod<edt::PartialService> dm_selection_to_view;
void hover_reset ();
void clear_partial_transient_selection ();
bool partial_select (const db::DBox &box, lay::Editable::SelectionMode mode);
void selection_to_view ();
void do_selection_to_view ();
db::DPoint snap (const db::DPoint &p) const;
db::DVector snap (const db::DVector &p) const;

View File

@ -79,7 +79,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIter
m_seq (0),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
{
// .. nothing yet ..
mp_view->geom_changed_event.add (this, &edt::Service::selection_to_view);
}
Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
@ -99,7 +99,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
m_seq (0),
dm_selection_to_view (this, &edt::Service::do_selection_to_view)
{
// .. nothing yet ..
mp_view->geom_changed_event.add (this, &edt::Service::selection_to_view);
}
Service::~Service ()
@ -1511,6 +1511,19 @@ Service::do_selection_to_view ()
// build the transformation variants cache
TransformationVariants tv (view ());
// Reduce the selection to valid paths (issue-1145)
std::vector<std::set<lay::ObjectInstPath>::iterator> invalid_objects;
for (std::set<lay::ObjectInstPath>::iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
if (! r->is_valid (view ())) {
invalid_objects.push_back (r);
}
}
for (auto i = invalid_objects.begin (); i != invalid_objects.end (); ++i) {
m_selection.erase (*i);
}
// Build markers
for (std::set<lay::ObjectInstPath>::iterator r = m_selection.begin (); r != m_selection.end (); ++r) {
const lay::CellView &cv = view ()->cellview (r->cv_index ());

View File

@ -167,7 +167,12 @@ gsi::Class<lay::ObjectInstPath> decl_ObjectInstPath ("lay", "ObjectInstPath",
"\n"
"This method has been introduced with version 0.24.\n"
) +
gsi::method ("cv_index", &lay::ObjectInstPath::cv_index,
gsi::method ("is_valid?", &lay::ObjectInstPath::is_valid, gsi::arg ("view"),
"@brief Gets a value indicating whether the instance path refers to a valid object in the context of the given view\n"
"\n"
"This predicate has been introduced in version 0.27.12.\n"
) +
gsi::method ("cv_index", &lay::ObjectInstPath::cv_index,
"@brief Gets the cellview index that describes which cell view the shape or instance is located in\n"
) +
gsi::method ("cv_index=", &lay::ObjectInstPath::set_cv_index, gsi::arg ("index"),

View File

@ -26,6 +26,7 @@
#include "layObjectInstPath.h"
#include "layCellView.h"
#include "layLayoutViewBase.h"
#include "tlException.h"
namespace lay {
@ -39,6 +40,42 @@ ObjectInstPath::ObjectInstPath ()
// .. nothing yet ..
}
bool
ObjectInstPath::is_valid (lay::LayoutViewBase *view) const
{
const lay::CellView &cv = view->cellview (cv_index ());
if (! cv.is_valid ()) {
return false;
}
const db::Layout &ly = cv->layout ();
db::cell_index_type ci = topcell ();
if (! ly.is_valid_cell_index (ci)) {
return false;
}
for (auto p = begin (); p != end (); ++p) {
if (! ly.cell (ci).is_valid (p->inst_ptr)) {
return false;
}
ci = p->inst_ptr.cell_index ();
if (! ly.is_valid_cell_index (ci)) {
return false;
}
}
if (! is_cell_inst ()) {
if (! ly.is_valid_layer (layer ())) {
return false;
}
if (! ly.cell (ci).shapes (layer ()).is_valid (shape ())) {
return false;
}
}
return true;
}
db::cell_index_type
ObjectInstPath::cell_index_tot () const
{

View File

@ -37,7 +37,7 @@
namespace lay
{
class LayoutView;
class LayoutViewBase;
}
namespace lay {
@ -299,6 +299,15 @@ public:
m_seq = s;
}
/**
* @brief Gets a value indicating whether the object path is valid
*
* After the layout has been modified, this method is able to check
* whether the object path (including shape if applicable) still points
* to a valid object.
*/
bool is_valid (lay::LayoutViewBase *view) const;
private:
unsigned int m_cv_index;
db::cell_index_type m_topcell;