mirror of https://github.com/KLayout/klayout.git
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:
parent
390cac87d3
commit
769b16ea3f
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue