mirror of https://github.com/KLayout/klayout.git
Property filter for edges too.
This commit is contained in:
parent
a219576296
commit
1fed2767e8
|
|
@ -79,6 +79,7 @@ SOURCES = \
|
|||
dbPolygonNeighborhood.cc \
|
||||
dbPolygonTools.cc \
|
||||
dbPolygonGenerators.cc \
|
||||
dbPropertiesFilter.cc \
|
||||
dbPropertiesRepository.cc \
|
||||
dbReader.cc \
|
||||
dbRecursiveInstanceIterator.cc \
|
||||
|
|
@ -315,6 +316,7 @@ HEADERS = \
|
|||
dbPolygonNeighborhood.h \
|
||||
dbPolygonTools.h \
|
||||
dbPolygonGenerators.h \
|
||||
dbPropertiesFilter.h \
|
||||
dbPropertiesRepository.h \
|
||||
dbPropertyConstraint.h \
|
||||
dbReader.h \
|
||||
|
|
|
|||
|
|
@ -1064,7 +1064,7 @@ private:
|
|||
child (0)->compute_local (cache, layout, cell, interactions, one, proc);
|
||||
|
||||
if (m_sum_of) {
|
||||
if (mp_filter->selected (one.front ())) {
|
||||
if (mp_filter->selected_set (one.front ())) {
|
||||
results.front ().insert (one.front ().begin (), one.front ().end ());
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public:
|
|||
* @brief Filters the edge set
|
||||
* If this method returns true, the edges are kept. Otherwise they are discarded.
|
||||
*/
|
||||
virtual bool selected (const std::unordered_set<db::EdgeWithProperties> &edge) const = 0;
|
||||
virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edge) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the transformation reducer for building cell variants
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ struct DB_PUBLIC EdgeLengthFilter
|
|||
/**
|
||||
* @brief Returns true if the total edge length matches the criterion
|
||||
*/
|
||||
bool selected (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
{
|
||||
length_type l = 0;
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
|
|
@ -209,7 +209,7 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
/**
|
||||
* @brief Returns true if all edge orientations match the criterion
|
||||
*/
|
||||
virtual bool selected (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
{
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
if (! selected (*e, e->properties_id ())) {
|
||||
|
|
@ -279,7 +279,7 @@ struct DB_PUBLIC SpecialEdgeOrientationFilter
|
|||
/**
|
||||
* @brief Returns true if all edge orientations match the criterion
|
||||
*/
|
||||
virtual bool selected (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
{
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
if (! selected (*e, e->properties_id ())) {
|
||||
|
|
@ -319,6 +319,29 @@ private:
|
|||
db::OrthogonalTransformationReducer m_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter implementation which implements the set filters through "all must match"
|
||||
*/
|
||||
|
||||
struct DB_PUBLIC AllEdgesMustMatchFilter
|
||||
: public EdgeFilterBase
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
AllEdgesMustMatchFilter () { }
|
||||
|
||||
virtual bool selected_set (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
{
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator p = edges.begin (); p != edges.end (); ++p) {
|
||||
if (! selected (*p, p->properties_id ())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a interacts with b
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbPropertiesFilter.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
PropertiesFilter::PropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_value_from (value), m_exact (true), m_glob (false), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PropertiesFilter::PropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_value_from (from), m_value_to (to), m_exact (false), m_glob (false), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PropertiesFilter::PropertiesFilter (const tl::Variant &name, const tl::GlobPattern &pattern, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_pattern (pattern), m_exact (true), m_glob (true), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
PropertiesFilter::prop_selected (db::properties_id_type prop_id) const
|
||||
{
|
||||
tl::MutexLocker locker (&m_lock);
|
||||
|
||||
auto c = m_cache.find (prop_id);
|
||||
if (c != m_cache.end ()) {
|
||||
return c->second;
|
||||
}
|
||||
|
||||
bool res = prop_selected_impl (prop_id);
|
||||
m_cache.insert (std::make_pair (prop_id, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
PropertiesFilter::prop_selected_impl (db::properties_id_type prop_id) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (prop_id);
|
||||
if (ps.has_value (m_name_id)) {
|
||||
|
||||
const tl::Variant &value = ps.value (m_name_id);
|
||||
|
||||
if (m_glob) {
|
||||
return m_pattern.match (value.to_string ()) != m_inverse;
|
||||
} else if (m_exact) {
|
||||
return (value == m_value_from) != m_inverse;
|
||||
} else {
|
||||
return ((m_value_from.is_nil () || ! (value < m_value_from)) && (m_value_to.is_nil () || value < m_value_to)) != m_inverse;
|
||||
}
|
||||
|
||||
} else {
|
||||
return m_inverse;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbPropertiesFilter
|
||||
#define HDR_dbPropertiesFilter
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlGlobPattern.h"
|
||||
#include "tlThreads.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A properties filter
|
||||
*
|
||||
* This is a base class for PolygonFilters, EdgeFilters etc. for selecting
|
||||
* Polygons from Regions by property.
|
||||
*/
|
||||
class DB_PUBLIC PropertiesFilter
|
||||
{
|
||||
public:
|
||||
PropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse);
|
||||
PropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse);
|
||||
PropertiesFilter (const tl::Variant &name, const tl::GlobPattern &pattern, bool inverse);
|
||||
|
||||
bool prop_selected (db::properties_id_type prop_id) const;
|
||||
|
||||
private:
|
||||
bool prop_selected_impl (db::properties_id_type prop_id) const;
|
||||
|
||||
mutable std::map<db::properties_id_type, bool> m_cache;
|
||||
db::property_names_id_type m_name_id;
|
||||
tl::Variant m_value_from, m_value_to;
|
||||
tl::GlobPattern m_pattern;
|
||||
bool m_exact;
|
||||
bool m_glob;
|
||||
bool m_inverse;
|
||||
mutable tl::Mutex m_lock;
|
||||
};
|
||||
|
||||
template <class PolygonFilter>
|
||||
class polygon_properties_filter
|
||||
: public PolygonFilter, public PropertiesFilter
|
||||
{
|
||||
public:
|
||||
polygon_properties_filter<PolygonFilter> (const tl::Variant &name, const tl::GlobPattern &pattern, bool inverse)
|
||||
: PropertiesFilter (name, pattern, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
polygon_properties_filter<PolygonFilter> (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
: PropertiesFilter (name, value, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
polygon_properties_filter<PolygonFilter> (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
: PropertiesFilter (name, from, to, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool selected (const db::Polygon &, db::properties_id_type prop_id) const
|
||||
{
|
||||
return PropertiesFilter::prop_selected (prop_id);
|
||||
}
|
||||
|
||||
bool selected (const db::PolygonRef &, db::properties_id_type prop_id) const
|
||||
{
|
||||
return PropertiesFilter::prop_selected (prop_id);
|
||||
}
|
||||
};
|
||||
|
||||
template <class BasicFilter, class ShapeType>
|
||||
class generic_properties_filter
|
||||
: public BasicFilter, public PropertiesFilter
|
||||
{
|
||||
public:
|
||||
generic_properties_filter<BasicFilter, ShapeType> (const tl::Variant &name, const tl::GlobPattern &pattern, bool inverse)
|
||||
: PropertiesFilter (name, pattern, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
generic_properties_filter<BasicFilter, ShapeType> (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
: PropertiesFilter (name, value, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
generic_properties_filter<BasicFilter, ShapeType> (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
: PropertiesFilter (name, from, to, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool selected (const ShapeType &, db::properties_id_type prop_id) const
|
||||
{
|
||||
return PropertiesFilter::prop_selected (prop_id);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include "dbRegion.h"
|
||||
#include "dbOriginalLayerRegion.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbPropertiesFilter.h"
|
||||
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
|
||||
|
|
@ -40,8 +41,10 @@ namespace gsi
|
|||
// ---------------------------------------------------------------------------------
|
||||
// EdgeFilter binding
|
||||
|
||||
typedef shape_filter_impl<db::AllEdgesMustMatchFilter> EdgeFilterBase;
|
||||
|
||||
class EdgeFilterImpl
|
||||
: public shape_filter_impl<db::EdgeFilterBase>
|
||||
: public gsi::EdgeFilterBase
|
||||
{
|
||||
public:
|
||||
EdgeFilterImpl () { }
|
||||
|
|
@ -60,25 +63,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Returns true if all edges match the criterion
|
||||
virtual bool selected (const std::unordered_set<db::EdgeWithProperties> &edges) const
|
||||
{
|
||||
if (f_selected.can_issue ()) {
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
if (! f_selected.issue<EdgeFilterImpl, bool, const db::EdgeWithProperties &> (&EdgeFilterImpl::issue_selected, *e)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (std::unordered_set<db::EdgeWithProperties>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
if (! issue_selected (*e)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gsi::Callback f_selected;
|
||||
|
||||
private:
|
||||
|
|
@ -87,8 +71,70 @@ private:
|
|||
EdgeFilterImpl (const EdgeFilterImpl &);
|
||||
};
|
||||
|
||||
Class<gsi::EdgeFilterImpl> decl_EdgeFilterImpl ("db", "EdgeFilter",
|
||||
EdgeFilterImpl::method_decls (true) +
|
||||
typedef db::generic_properties_filter<gsi::EdgeFilterBase, db::Edge> EdgePropertiesFilter;
|
||||
|
||||
static gsi::EdgeFilterBase *make_ppf1 (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
{
|
||||
return new EdgePropertiesFilter (name, value, inverse);
|
||||
}
|
||||
|
||||
static gsi::EdgeFilterBase *make_ppf2 (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
{
|
||||
return new EdgePropertiesFilter (name, from, to, inverse);
|
||||
}
|
||||
|
||||
static gsi::EdgeFilterBase *make_pg (const tl::Variant &name, const std::string &glob, bool inverse, bool case_sensitive)
|
||||
{
|
||||
tl::GlobPattern pattern (glob);
|
||||
pattern.set_case_sensitive (case_sensitive);
|
||||
return new EdgePropertiesFilter (name, pattern, inverse);
|
||||
}
|
||||
|
||||
Class<gsi::EdgeFilterBase> decl_EdgeFilterBase ("db", "EdgeFilterBase",
|
||||
gsi::EdgeFilterBase::method_decls (true) +
|
||||
gsi::constructor ("property_glob", &make_pg, gsi::arg ("name"), gsi::arg ("pattern"), gsi::arg ("inverse", false), gsi::arg ("case_sensitive", true),
|
||||
"@brief Creates a single-valued property filter\n"
|
||||
"@param name The name of the property to use.\n"
|
||||
"@param value The glob pattern to match the property value against.\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all edges without a matching property are selected.\n"
|
||||
"@param case_sensitive If true, the match is case sensitive (the default), if false, the match is not case sensitive.\n"
|
||||
"\n"
|
||||
"Apply this filter with \\Edges#filtered:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# edges is a Edges object\n"
|
||||
"# filtered_edges contains all edges where the 'net' property starts with 'C':\n"
|
||||
"filtered_edges = edges.filtered(RBA::EdgeFilterBase::property_glob('net', 'C*'))\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
) +
|
||||
gsi::constructor ("property_filter", &make_ppf1, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("inverse", false),
|
||||
"@brief Creates a single-valued property filter\n"
|
||||
"@param name The name of the property to use.\n"
|
||||
"@param value The value against which the property is checked (exact match).\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all edges without a property with the given name and value are selected.\n"
|
||||
"\n"
|
||||
"Apply this filter with \\Edges#filtered. See \\property_glob for an example.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
) +
|
||||
gsi::constructor ("property_filter_bounded", &make_ppf2, gsi::arg ("name"), gsi::arg ("from"), gsi::arg ("to"), gsi::arg ("inverse", false),
|
||||
"@brief Creates a single-valued property filter\n"
|
||||
"@param name The name of the property to use.\n"
|
||||
"@param from The lower value against which the property is checked or 'nil' if no lower bound shall be used.\n"
|
||||
"@param to The upper value against which the property is checked or 'nil' if no upper bound shall be used.\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all edges without a property with the given name and value range are selected.\n"
|
||||
"\n"
|
||||
"This version does a bounded match. The value of the propery needs to be larger or equal to 'from' and less than 'to'.\n"
|
||||
"Apply this filter with \\Edges#filtered. See \\property_glob for an example.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
),
|
||||
"@hide"
|
||||
);
|
||||
|
||||
Class<gsi::EdgeFilterImpl> decl_EdgeFilterImpl (decl_EdgeFilterBase, "db", "EdgeFilter",
|
||||
callback ("selected", &EdgeFilterImpl::issue_selected, &EdgeFilterImpl::f_selected, gsi::arg ("edge"),
|
||||
"@brief Selects an edge\n"
|
||||
"This method is the actual payload. It needs to be reimplemented in a derived class.\n"
|
||||
|
|
@ -455,12 +501,12 @@ static db::Edges moved_xy (const db::Edges *r, db::Coord x, db::Coord y)
|
|||
return r->transformed (db::Disp (db::Vector (x, y)));
|
||||
}
|
||||
|
||||
static db::Edges filtered (const db::Edges *r, const EdgeFilterImpl *f)
|
||||
static db::Edges filtered (const db::Edges *r, const gsi::EdgeFilterBase *f)
|
||||
{
|
||||
return r->filtered (*f);
|
||||
}
|
||||
|
||||
static void filter (db::Edges *r, const EdgeFilterImpl *f)
|
||||
static void filter (db::Edges *r, const gsi::EdgeFilterBase *f)
|
||||
{
|
||||
r->filter (*f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "dbCompoundOperation.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
#include "dbPropertiesFilter.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
|
|
@ -51,12 +52,7 @@ namespace gsi
|
|||
// ---------------------------------------------------------------------------------
|
||||
// PolygonFilter binding
|
||||
|
||||
class PolygonFilterBase
|
||||
: public shape_filter_impl<db::AllMustMatchFilter>
|
||||
{
|
||||
public:
|
||||
PolygonFilterBase () { }
|
||||
};
|
||||
typedef shape_filter_impl<db::AllMustMatchFilter> PolygonFilterBase;
|
||||
|
||||
class PolygonFilterImpl
|
||||
: public PolygonFilterBase
|
||||
|
|
@ -93,128 +89,41 @@ private:
|
|||
PolygonFilterImpl (const PolygonFilterImpl &);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A properties filter
|
||||
*/
|
||||
class PropertiesFilter
|
||||
{
|
||||
public:
|
||||
PropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_value_from (value), m_exact (true), m_glob (false), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
typedef db::polygon_properties_filter<gsi::PolygonFilterBase> PolygonPropertiesFilter;
|
||||
|
||||
PropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_value_from (from), m_value_to (to), m_exact (false), m_glob (false), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PropertiesFilter (const tl::Variant &name, const std::string &pattern, bool inverse)
|
||||
: m_name_id (db::property_names_id (name)), m_pattern (pattern), m_exact (true), m_glob (true), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool prop_selected (db::properties_id_type prop_id) const
|
||||
{
|
||||
auto c = m_cache.find (prop_id);
|
||||
if (c != m_cache.end ()) {
|
||||
return c->second;
|
||||
}
|
||||
|
||||
bool res = prop_selected_impl (prop_id);
|
||||
m_cache.insert (std::make_pair (prop_id, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
bool prop_selected_impl (db::properties_id_type prop_id) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (prop_id);
|
||||
if (ps.has_value (m_name_id)) {
|
||||
|
||||
const tl::Variant &value = ps.value (m_name_id);
|
||||
|
||||
if (m_glob) {
|
||||
return m_pattern.match (value.to_string ()) != m_inverse;
|
||||
} else if (m_exact) {
|
||||
return (value == m_value_from) != m_inverse;
|
||||
} else {
|
||||
return ((m_value_from.is_nil () || ! (value < m_value_from)) && (m_value_to.is_nil () || value < m_value_to)) != m_inverse;
|
||||
}
|
||||
|
||||
} else {
|
||||
return m_inverse;
|
||||
}
|
||||
}
|
||||
|
||||
mutable std::map<db::properties_id_type, bool> m_cache;
|
||||
db::property_names_id_type m_name_id;
|
||||
tl::Variant m_value_from, m_value_to;
|
||||
tl::GlobPattern m_pattern;
|
||||
bool m_exact;
|
||||
bool m_glob;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
class PolygonPropertiesFilter
|
||||
: public PolygonFilterBase, public PropertiesFilter
|
||||
{
|
||||
public:
|
||||
PolygonPropertiesFilter (const tl::Variant &name, const std::string &pattern, bool inverse)
|
||||
: PropertiesFilter (name, pattern, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PolygonPropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
: PropertiesFilter (name, value, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PolygonPropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
: PropertiesFilter (name, from, to, inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool selected (const db::Polygon &, db::properties_id_type prop_id) const
|
||||
{
|
||||
return PropertiesFilter::prop_selected (prop_id);
|
||||
}
|
||||
|
||||
bool selected (const db::PolygonRef &, db::properties_id_type prop_id) const
|
||||
{
|
||||
return PropertiesFilter::prop_selected (prop_id);
|
||||
}
|
||||
};
|
||||
|
||||
static PolygonFilterBase *make_ppf1 (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
static gsi::PolygonFilterBase *make_ppf1 (const tl::Variant &name, const tl::Variant &value, bool inverse)
|
||||
{
|
||||
return new PolygonPropertiesFilter (name, value, inverse);
|
||||
}
|
||||
|
||||
static PolygonFilterBase *make_ppf2 (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
static gsi::PolygonFilterBase *make_ppf2 (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse)
|
||||
{
|
||||
return new PolygonPropertiesFilter (name, from, to, inverse);
|
||||
}
|
||||
|
||||
static PolygonFilterBase *make_pg (const tl::Variant &name, const std::string &glob, bool inverse)
|
||||
static gsi::PolygonFilterBase *make_pg (const tl::Variant &name, const std::string &glob, bool inverse, bool case_sensitive)
|
||||
{
|
||||
return new PolygonPropertiesFilter (name, glob, inverse);
|
||||
tl::GlobPattern pattern (glob);
|
||||
pattern.set_case_sensitive (case_sensitive);
|
||||
return new PolygonPropertiesFilter (name, pattern, inverse);
|
||||
}
|
||||
|
||||
Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
||||
gsi::constructor ("property_glob", &make_pg, gsi::arg ("name"), gsi::arg ("pattern"), gsi::arg ("inverse", false),
|
||||
gsi::PolygonFilterBase::method_decls (true) +
|
||||
gsi::constructor ("property_glob", &make_pg, gsi::arg ("name"), gsi::arg ("pattern"), gsi::arg ("inverse", false), gsi::arg ("case_sensitive", true),
|
||||
"@brief Creates a single-valued property filter\n"
|
||||
"@param name The name of the property to use.\n"
|
||||
"@param value The glob pattern to match the property value against.\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all polygons without a matching property are selected.\n"
|
||||
"@param case_sensitive If true, the match is case sensitive (the default), if false, the match is not case sensitive.\n"
|
||||
"\n"
|
||||
"Apply this filter with \\Region#filtered.\n"
|
||||
"Apply this filter with \\Region#filtered:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"# region is a Region object\n"
|
||||
"# filtered_region contains all polygons where the 'net' property starts with 'C':\n"
|
||||
"filtered_region = region.filtered(RBA::PolygonFilterBase::property_glob('net', 'C*'))\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
) +
|
||||
|
|
@ -224,7 +133,7 @@ Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
|||
"@param value The value against which the property is checked (exact match).\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all polygons without a property with the given name and value are selected.\n"
|
||||
"\n"
|
||||
"Apply this filter with \\Region#filtered.\n"
|
||||
"Apply this filter with \\Region#filtered. See \\property_glob for an example.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
) +
|
||||
|
|
@ -236,7 +145,7 @@ Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
|||
"@param inverse If true, inverts the selection - i.e. all polygons without a property with the given name and value range are selected.\n"
|
||||
"\n"
|
||||
"This version does a bounded match. The value of the propery needs to be larger or equal to 'from' and less than 'to'.\n"
|
||||
"Apply this filter with \\Region#filtered.\n"
|
||||
"Apply this filter with \\Region#filtered. See \\property_glob for an example.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
),
|
||||
|
|
@ -244,7 +153,6 @@ Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
|||
);
|
||||
|
||||
Class<gsi::PolygonFilterImpl> decl_PolygonFilterImpl (decl_PolygonFilterBase, "db", "PolygonFilter",
|
||||
PolygonFilterImpl::method_decls (true) +
|
||||
callback ("selected", &PolygonFilterImpl::issue_selected, &PolygonFilterImpl::f_selected, gsi::arg ("polygon"),
|
||||
"@brief Selects a polygon\n"
|
||||
"This method is the actual payload. It needs to be reimplemented in a derived class.\n"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbPropertiesFilter.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Installs a temporary repository instance for testing
|
||||
*
|
||||
* By using a temp instance, we do not disturb other tests.
|
||||
*/
|
||||
class TempPropertiesRepository
|
||||
{
|
||||
public:
|
||||
TempPropertiesRepository ()
|
||||
{
|
||||
db::PropertiesRepository::replace_instance_temporarily (&m_temp);
|
||||
}
|
||||
|
||||
~TempPropertiesRepository ()
|
||||
{
|
||||
db::PropertiesRepository::replace_instance_temporarily (0);
|
||||
}
|
||||
|
||||
private:
|
||||
db::PropertiesRepository m_temp;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
TempPropertiesRepository temp_pr;
|
||||
|
||||
db::PropertiesSet ps;
|
||||
ps.insert ("net", 17);
|
||||
auto net17 = properties_id (ps);
|
||||
|
||||
ps.clear ();
|
||||
ps.insert ("net", 1);
|
||||
auto net1 = properties_id (ps);
|
||||
|
||||
ps.clear ();
|
||||
ps.insert ("net", 42);
|
||||
ps.insert ("not", "never");
|
||||
auto net42 = properties_id (ps);
|
||||
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), false).prop_selected (net17), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), true).prop_selected (net17), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), false).prop_selected (net42), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::Variant ("never"), true).prop_selected (net42), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("doesnotexist", tl::Variant ("never"), false).prop_selected (net42), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("doesnotexist", tl::Variant ("never"), true).prop_selected (net42), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 17, false).prop_selected (net17), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 17, true).prop_selected (net17), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 17, false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 17, true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::Variant (), 17, false).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::Variant (), 17, true).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::Variant (), 1, false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::Variant (), 1, true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 0, 2, false).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 0, 2, true).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 0, 1, false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 0, 1, true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 1, 2, false).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 1, 2, true).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", -1, tl::Variant (), false).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", -1, tl::Variant (), true).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 2, tl::Variant (), false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", 2, tl::Variant (), true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), false).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), true).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::GlobPattern ("1*"), false).prop_selected (net1), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("not", tl::GlobPattern ("1*"), true).prop_selected (net1), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), false).prop_selected (net17), true);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), true).prop_selected (net17), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), false).prop_selected (net42), false);
|
||||
EXPECT_EQ (db::PropertiesFilter ("net", tl::GlobPattern ("1*"), true).prop_selected (net42), true);
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ SOURCES = \
|
|||
dbLogTests.cc \
|
||||
dbObjectWithPropertiesTests.cc \
|
||||
dbPolygonNeighborhoodTests.cc \
|
||||
dbPropertiesFilterTests.cc \
|
||||
dbRecursiveInstanceIteratorTests.cc \
|
||||
dbRegionCheckUtilsTests.cc \
|
||||
dbTriangleTests.cc \
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ load("test_prologue.rb")
|
|||
# normalizes a specification string for region, edges etc.
|
||||
# such that the order of the objects becomes irrelevant
|
||||
def csort(s)
|
||||
# splits at ");(" without consuming the brackets
|
||||
s.split(/(?<=\));(?=\()/).sort.join(";")
|
||||
# splits at ");(" or "};(" without consuming the brackets
|
||||
s.split(/(?<=[\)\}]);(?=\()/).sort.join(";")
|
||||
end
|
||||
|
||||
class ParallelFilter < RBA::EdgeFilter
|
||||
|
|
@ -1037,6 +1037,56 @@ class DBEdges_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# properties
|
||||
def test_prop_filters
|
||||
|
||||
r = RBA::Edges::new
|
||||
r.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(0, 0, 100, 200), { "one" => -1 }))
|
||||
r.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(1, 1, 101, 201), { "one" => 17 }))
|
||||
r.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(2, 2, 102, 202), { "one" => 42 }))
|
||||
|
||||
assert_equal(r.filtered(RBA::EdgeFilter::property_filter("one", 11)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::EdgeFilter::property_filter("two", 17)).to_s, "")
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter("one", 17)).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter("one", 17, true)).to_s), csort("(0,0;100,200){one=>-1};(2,2;102,202){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, nil)).to_s), csort("(2,2;102,202){one=>42};(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, 18)).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, 18, true)).to_s), csort("(2,2;102,202){one=>42};(0,0;100,200){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", nil, 18)).to_s), csort("(1,1;101,201){one=>17};(0,0;100,200){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_glob("one", "1*")).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_glob("one", "1*", true)).to_s), csort("(2,2;102,202){one=>42};(0,0;100,200){one=>-1}"))
|
||||
|
||||
ly = RBA::Layout::new
|
||||
top = ly.create_cell("TOP")
|
||||
l1 = ly.layer(1, 0)
|
||||
|
||||
s = top.shapes(l1)
|
||||
s.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(0, 0, 100, 200), { "one" => -1 }))
|
||||
s.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(1, 1, 101, 201), { "one" => 17 }))
|
||||
s.insert(RBA::EdgeWithProperties::new(RBA::Edge::new(2, 2, 102, 202), { "one" => 42 }))
|
||||
|
||||
dss = RBA::DeepShapeStore::new
|
||||
iter = top.begin_shapes_rec(l1)
|
||||
iter.enable_properties()
|
||||
r = RBA::Edges::new(iter, dss)
|
||||
|
||||
assert_equal(r.filtered(RBA::EdgeFilter::property_filter("one", 11)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::EdgeFilter::property_filter("two", 17)).to_s, "")
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter("one", 17)).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter("one", 17, true)).to_s), csort("(0,0;100,200){one=>-1};(2,2;102,202){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, nil)).to_s), csort("(2,2;102,202){one=>42};(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, 18)).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", 17, 18, true)).to_s), csort("(2,2;102,202){one=>42};(0,0;100,200){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_filter_bounded("one", nil, 18)).to_s), csort("(1,1;101,201){one=>17};(0,0;100,200){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_glob("one", "1*")).to_s), csort("(1,1;101,201){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::EdgeFilter::property_glob("one", "1*", true)).to_s), csort("(2,2;102,202){one=>42};(0,0;100,200){one=>-1}"))
|
||||
|
||||
rr = r.dup
|
||||
rr.filter(RBA::EdgeFilter::property_filter("one", 17))
|
||||
assert_equal(csort(rr.to_s), csort("(1,1;101,201){one=>17}"))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ load("test_prologue.rb")
|
|||
# normalizes a specification string for region, edges etc.
|
||||
# such that the order of the objects becomes irrelevant
|
||||
def csort(s)
|
||||
# splits at ");(" without consuming the brackets
|
||||
s.split(/(?<=\));(?=\()/).sort.join(";")
|
||||
# splits at ");(" or "};(" without consuming the brackets
|
||||
s.split(/(?<=[\)\}]);(?=\()/).sort.join(";")
|
||||
end
|
||||
|
||||
class TriangleFilter < RBA::PolygonFilter
|
||||
|
|
@ -1593,14 +1593,14 @@ class DBRegion_TestClass < TestBase
|
|||
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 11)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("two", 17)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(0,0;0,200;100,200;100,0){one=>-1}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}")
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s), csort("(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s), csort("(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17};(0,0;0,200;100,200;100,0){one=>-1}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s), csort("(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}"))
|
||||
|
||||
ly = RBA::Layout::new
|
||||
top = ly.create_cell("TOP")
|
||||
|
|
@ -1618,14 +1618,18 @@ class DBRegion_TestClass < TestBase
|
|||
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 11)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("two", 17)).to_s, "")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s, "(1,1;1,201;101,201;101,1){one=>17}")
|
||||
assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}")
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s), csort("(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s), csort("(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s), csort("(0,0;0,200;100,200;100,0){one=>-1};(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
assert_equal(csort(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s), csort("(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}"))
|
||||
|
||||
rr = r.dup
|
||||
rr.filter(RBA::PolygonFilter::property_filter("one", 17))
|
||||
assert_equal(csort(rr.to_s), csort("(1,1;1,201;101,201;101,1){one=>17}"))
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue