WIP: refactoring, started implementing DRC checks with property support

This commit is contained in:
Matthias Koefferlein 2023-01-18 01:36:22 +01:00
parent bd79467b4b
commit 1b7b077cea
11 changed files with 1363 additions and 1134 deletions

View File

@ -29,6 +29,7 @@ SOURCES = \
dbEdgePairs.cc \
dbEdgeProcessor.cc \
dbEdges.cc \
dbEdgesLocalOperations.cc \
dbFillTool.cc \
dbFuzzyCellMapping.cc \
dbGenericShapeIterator.cc \
@ -243,6 +244,7 @@ HEADERS = \
dbEdgePairs.h \
dbEdgeProcessor.h \
dbEdges.h \
dbEdgesLocalOperations.h \
dbEdgesToContours.h \
dbFillTool.h \
dbFuzzyCellMapping.h \

View File

@ -35,6 +35,7 @@
#include "dbLocalOperation.h"
#include "dbLocalOperationUtils.h"
#include "dbRegionLocalOperations.h" // for db::ContainedEdgesLocalOperation
#include "dbEdgesLocalOperations.h"
#include "dbHierProcessor.h"
#include "dbEmptyEdges.h"

View File

@ -1282,125 +1282,6 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
return res.release ();
}
namespace
{
template <class TS, class TI>
static
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::vector<const TI *> > >
separate_by_same_properties (const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, db::PropertyMapper &pms, db::PropertyMapper &pmi)
{
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::vector<const TI *> > > by_prop_id;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const db::object_with_properties<TS> &subject = interactions.subject_shape (i->first);
std::pair<std::vector<const TS *>, std::vector<const TI *> > &s2p = by_prop_id [pms (subject.properties_id ())];
s2p.first.push_back (&subject);
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
const std::pair<unsigned int, db::object_with_properties<TI> > &intruder = interactions.intruder_shape (*ii);
if (subject.properties_id () == pmi (intruder.second.properties_id ())) {
s2p.second.push_back (&intruder.second);
}
}
}
return by_prop_id;
}
class PolygonToEdgeLocalOperation
: public local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgeWithProperties>
{
public:
PolygonToEdgeLocalOperation (db::PropertiesRepository *target_pr, const db::PropertiesRepository *source_pr)
: local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgeWithProperties> (), m_pm (target_pr, source_pr)
{
// .. nothing yet ..
}
virtual db::Coord dist () const { return 1; }
virtual bool requests_single_subjects () const { return true; }
virtual std::string description () const { return std::string ("polygon to edges"); }
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::EdgeWithProperties> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
db::EdgeProcessor ep;
ep.set_base_verbosity (50);
auto by_prop_id = separate_by_same_properties (interactions, m_pm, m_pm);
for (auto shapes_by_prop_id = by_prop_id.begin (); shapes_by_prop_id != by_prop_id.end (); ++shapes_by_prop_id) {
db::properties_id_type prop_id = shapes_by_prop_id->first;
for (auto s = shapes_by_prop_id->second.first.begin (); s != shapes_by_prop_id->second.first.end (); ++s) {
ep.insert (**s);
}
db::property_injector<db::Edge, std::unordered_set<db::EdgeWithProperties> > results_with_properties (&results.front (), prop_id);
if (shapes_by_prop_id->second.second.empty ()) {
db::edge_to_edge_set_generator<db::property_injector<db::Edge, std::unordered_set<db::EdgeWithProperties> > > eg (results_with_properties, prop_id);
db::MergeOp op (0);
ep.process (eg, op);
} else {
// With intruders: to compute our local contribution we take the edges without and with intruders
// and deliver what is in both sets
db::MergeOp op (0);
std::vector<Edge> edges1;
db::EdgeContainer ec1 (edges1);
ep.process (ec1, op);
ep.clear ();
for (auto s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) {
ep.insert (s->second);
}
for (auto i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) {
ep.insert (i->second.second);
}
std::vector<Edge> edges2;
db::EdgeContainer ec2 (edges2);
ep.process (ec2, op);
// Runs the boolean AND between the result with and without intruders
db::box_scanner<db::Edge, size_t> scanner;
scanner.reserve (edges1.size () + edges2.size ());
for (std::vector<Edge>::const_iterator i = edges1.begin (); i != edges1.end (); ++i) {
scanner.insert (i.operator-> (), 0);
}
for (std::vector<Edge>::const_iterator i = edges2.begin (); i != edges2.end (); ++i) {
scanner.insert (i.operator-> (), 1);
}
EdgeBooleanClusterCollector<db::property_injector<Edge, std::unordered_set<db::EdgeWithProperties> > > cluster_collector (&results_with_properties, EdgeAnd);
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
}
}
}
private:
mutable db::PropertyMapper m_pm;
};
}
EdgesDelegate *
DeepRegion::edges (const EdgeFilterBase *filter) const
{

View File

@ -0,0 +1,203 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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 "dbEdgesLocalOperations.h"
#include "dbHierProcessor.h"
#include "dbLocalOperationUtils.h"
namespace db
{
// ---------------------------------------------------------------------------------------------
// EdgeBoolAndOrNotLocalOperation implementation
EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (EdgeBoolOp op)
: m_op (op)
{
// .. nothing yet ..
}
OnEmptyIntruderHint
EdgeBoolAndOrNotLocalOperation::on_empty_intruder_hint () const
{
return (m_op == EdgeAnd || m_op == EdgeIntersections) ? Drop : Copy;
}
std::string
EdgeBoolAndOrNotLocalOperation::description () const
{
if (m_op == EdgeIntersections) {
return tl::to_string (tr ("Edge INTERSECTION operation"));
} else if (m_op == EdgeAnd) {
return tl::to_string (tr ("Edge AND operation"));
} else if (m_op == EdgeNot) {
return tl::to_string (tr ("Edge NOT operation"));
} else {
return std::string ();
}
}
void
EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == size_t (m_op == EdgeAndNot ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (results.size () > 1) {
result2 = &results[1];
}
EdgeBooleanClusterCollector<std::unordered_set<db::Edge> > cluster_collector (&result, m_op, result2);
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
bool any_subject = false;
bool is_and = (m_op == EdgeAnd || m_op == EdgeAndNot || m_op == EdgeIntersections);
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
if (is_and) {
result.insert (subject);
}
} else if (i->second.empty ()) {
// shortcut (not: keep, and: drop)
if (! is_and) {
result.insert (subject);
}
} else {
scanner.insert (&subject, 0);
any_subject = true;
}
}
if (! others.empty () || any_subject) {
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
}
}
// ---------------------------------------------------------------------------------------------
// EdgeToPolygonLocalOperation implementation
EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders)
: m_op (op), m_include_borders (include_borders)
{
// .. nothing yet ..
}
OnEmptyIntruderHint
EdgeToPolygonLocalOperation::on_empty_intruder_hint () const
{
return m_op == EdgePolygonOp::Inside ? Drop : (m_op == EdgePolygonOp::Outside ? Copy : CopyToSecond);
}
std::string
EdgeToPolygonLocalOperation::description () const
{
if (m_op == EdgePolygonOp::Inside) {
return tl::to_string (tr ("Edge to polygon AND/INSIDE"));
} else if (m_op == EdgePolygonOp::Outside) {
return tl::to_string (tr ("Edge to polygon NOT/OUTSIDE"));
} else {
return tl::to_string (tr ("Edge to polygon ANDNOT/INOUTSIDE"));
}
}
void
EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == size_t (m_op == EdgePolygonOp::Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (results.size () > 1) {
result2 = &results[1];
}
db::EdgeProcessor ep;
std::set<db::PolygonRef> others;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
bool any_subject = false;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (i->second.empty ()) {
// shortcut (outside: keep, otherwise: drop)
if (m_op == db::EdgePolygonOp::Outside) {
result.insert (subject);
} else if (m_op == db::EdgePolygonOp::Both) {
result2->insert (subject);
}
} else {
ep.insert (subject, 1);
any_subject = true;
}
}
if (! others.empty () || any_subject) {
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, 0);
}
}
std::unique_ptr<db::EdgeToEdgeSetGenerator> cc_second;
if (result2) {
cc_second.reset (new db::EdgeToEdgeSetGenerator (*result2, 2 /*second tag*/));
}
db::EdgeToEdgeSetGenerator cc (result, 1 /*first tag*/, cc_second.get ());
db::EdgePolygonOp op (m_op, m_include_borders);
ep.process (cc, op);
}
}
}

View File

@ -0,0 +1,84 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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_dbEdgesLocalOperation
#define HDR_dbEdgesLocalOperation
#include "dbCommon.h"
#include "dbLayout.h"
#include "dbEdgeBoolean.h"
#include "dbEdgeProcessor.h"
#include "dbLocalOperation.h"
namespace db
{
/**
* @brief Implements a boolean AND or NOT operation between edges
*/
class DB_PUBLIC EdgeBoolAndOrNotLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
EdgeBoolAndOrNotLocalOperation (db::EdgeBoolOp op);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
// edge interaction distance is 1 to force overlap between edges and edge/boxes
virtual db::Coord dist () const { return 1; }
private:
db::EdgeBoolOp m_op;
};
/**
* @brief Implements a boolean AND or NOT operation between edges and polygons (polygons as intruders)
*
* "AND" is implemented by "outside == false", "NOT" by "outside == true" with "include_borders == true".
* With "include_borders == false" the operations are "INSIDE" and "OUTSIDE".
*/
class DB_PUBLIC EdgeToPolygonLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
{
public:
EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
// edge interaction distance is 1 to force overlap between edges and edge/boxes
virtual db::Coord dist () const { return m_include_borders ? 1 : 0; }
private:
db::EdgePolygonOp::mode_t m_op;
bool m_include_borders;
};
}
#endif

View File

@ -27,7 +27,6 @@
#include "dbBoxConvert.h"
#include "dbPolygonGenerators.h"
#include "dbPolygonTools.h"
#include "dbLocalOperationUtils.h"
#include "dbEdgeBoolean.h"
#include "dbLayoutUtils.h"
#include "tlLog.h"
@ -115,656 +114,5 @@ template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::TextRef>;
// ---------------------------------------------------------------------------------------------
// BoolAndOrNotLocalOperation implementation
template <class TS, class TI, class TR>
bool_and_or_not_local_operation<TS, TI, TR>::bool_and_or_not_local_operation (bool is_and)
: m_is_and (is_and)
{
// .. nothing yet ..
}
template <class TS, class TI, class TR>
OnEmptyIntruderHint
bool_and_or_not_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
{
return m_is_and ? Drop : Copy;
}
template <class TS, class TI, class TR>
std::string
bool_and_or_not_local_operation<TS, TI, TR>::description () const
{
return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation"));
}
template <class TS, class TI, class TR>
void
bool_and_or_not_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t max_vertex_count, double area_ratio) const
{
tl_assert (results.size () == 1);
std::unordered_set<TR> &result = results.front ();
db::EdgeProcessor ep;
size_t p1 = 0, p2 = 1;
std::set<TI> others;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TR &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
if (m_is_and) {
result.insert (subject);
}
} else if (i->second.empty ()) {
// shortcut (not: keep, and: drop)
if (! m_is_and) {
result.insert (subject);
}
} else {
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
}
if (! others.empty () && p1 > 0) {
for (auto o = others.begin (); o != others.end (); ++o) {
for (auto e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}
p2 += 2;
}
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::polygon_ref_generator<TR> pr (layout, result);
db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count);
db::PolygonGenerator pg (splitter, true, true);
ep.set_base_verbosity (50);
ep.process (pg, op);
}
}
template class DB_PUBLIC bool_and_or_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC bool_and_or_not_local_operation<db::Polygon, db::Polygon, db::Polygon>;
// ---------------------------------------------------------------------------------------------
// BoolAndOrNotLocalOperationWithProperties implementation
template <class TS, class TI, class TR>
bool_and_or_not_local_operation_with_properties<TS, TI, TR>::bool_and_or_not_local_operation_with_properties (bool is_and, db::PropertiesRepository *target_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint)
: m_is_and (is_and), m_property_constraint (property_constraint), m_pms (target_pr, subject_pr), m_pmi (target_pr, intruder_pr)
{
// .. nothing yet ..
}
template <class TS, class TI, class TR>
OnEmptyIntruderHint
bool_and_or_not_local_operation_with_properties<TS, TI, TR>::on_empty_intruder_hint () const
{
return m_is_and ? Drop : Copy;
}
template <class TS, class TI, class TR>
std::string
bool_and_or_not_local_operation_with_properties<TS, TI, TR>::description () const
{
return m_is_and ? tl::to_string (tr ("AND operation")) : tl::to_string (tr ("NOT operation"));
}
template <class TS, class TI, class TR>
void
bool_and_or_not_local_operation_with_properties<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &results, size_t max_vertex_count, double area_ratio) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::object_with_properties<TR> > &result = results.front ();
db::EdgeProcessor ep;
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> > > by_prop_id;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const db::object_with_properties<TS> &subject = interactions.subject_shape (i->first);
if (i->second.empty ()) {
if (! m_is_and) {
result.insert (db::object_with_properties<TR> (subject, m_pms (subject.properties_id ())));
}
} else {
db::properties_id_type prop_id_s = m_pms (subject.properties_id ());
auto &shapes_by_prop = by_prop_id [prop_id_s];
shapes_by_prop.first.push_front (subject);
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
const db::object_with_properties<TI> &intruder = interactions.intruder_shape (*j).second;
db::properties_id_type prop_id_i = (m_property_constraint != db::NoPropertyConstraint ? m_pmi (intruder.properties_id ()) : prop_id_s);
if ((prop_id_i != prop_id_s) == (m_property_constraint == db::DifferentPropertiesConstraint)) {
shapes_by_prop.second.insert (intruder);
}
}
}
}
for (auto p2s = by_prop_id.begin (); p2s != by_prop_id.end (); ++p2s) {
ep.clear ();
size_t p1 = 0, p2 = 1;
const std::set<TI> &others = p2s->second.second;
db::properties_id_type prop_id = p2s->first;
for (auto s = p2s->second.first.begin (); s != p2s->second.first.end (); ++s) {
const TS &subject = *s;
if (others.find (subject) != others.end ()) {
if (m_is_and) {
result.insert (db::object_with_properties<TR> (subject, prop_id));
}
} else if (others.empty ()) {
// shortcut (not: keep, and: drop)
if (! m_is_and) {
result.insert (db::object_with_properties<TR> (subject, prop_id));
}
} else {
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
}
if (! others.empty () && p1 > 0) {
for (auto o = others.begin (); o != others.end (); ++o) {
for (auto e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}
p2 += 2;
}
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::polygon_ref_generator_with_properties<db::object_with_properties<TR> > pr (layout, result, prop_id);
db::PolygonSplitter splitter (pr, area_ratio, max_vertex_count);
db::PolygonGenerator pg (splitter, true, true);
ep.set_base_verbosity (50);
ep.process (pg, op);
}
}
}
template class DB_PUBLIC bool_and_or_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC bool_and_or_not_local_operation_with_properties<db::Polygon, db::Polygon, db::Polygon>;
// ---------------------------------------------------------------------------------------------
// TwoBoolAndNotLocalOperation implementation
template <class TS, class TI, class TR>
two_bool_and_not_local_operation<TS, TI, TR>::two_bool_and_not_local_operation ()
: db::local_operation<TS, TI, TR> ()
{
// .. nothing yet ..
}
template <class TS, class TI, class TR>
void
two_bool_and_not_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t max_vertex_count, double area_ratio) const
{
tl_assert (results.size () == 2);
db::EdgeProcessor ep;
std::unordered_set<TR> &result0 = results [0];
std::unordered_set<TR> &result1 = results [1];
size_t p1 = 0, p2 = 1;
std::set<TI> others;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
result0.insert (subject);
} else if (i->second.empty ()) {
// shortcut (not: keep, and: drop)
result1.insert (subject);
} else {
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
}
if (! others.empty () && p1 > 0) {
for (auto o = others.begin (); o != others.end (); ++o) {
for (auto e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}
p2 += 2;
}
db::BooleanOp op0 (db::BooleanOp::And);
db::polygon_ref_generator<TR> pr0 (layout, result0);
db::PolygonSplitter splitter0 (pr0, area_ratio, max_vertex_count);
db::PolygonGenerator pg0 (splitter0, true, true);
db::BooleanOp op1 (db::BooleanOp::ANotB);
db::polygon_ref_generator<TR> pr1 (layout, result1);
db::PolygonSplitter splitter1 (pr1, area_ratio, max_vertex_count);
db::PolygonGenerator pg1 (splitter1, true, true);
ep.set_base_verbosity (50);
std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > procs;
procs.push_back (std::make_pair (&pg0, &op0));
procs.push_back (std::make_pair (&pg1, &op1));
ep.process (procs);
}
}
template <class TS, class TI, class TR>
std::string two_bool_and_not_local_operation<TS, TI, TR>::description () const
{
return tl::to_string (tr ("ANDNOT operation"));
}
template class DB_PUBLIC two_bool_and_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC two_bool_and_not_local_operation<db::Polygon, db::Polygon, db::Polygon>;
// ---------------------------------------------------------------------------------------------
// TwoBoolAndNotLocalOperationWithProperties implementation
template <class TS, class TI, class TR>
two_bool_and_not_local_operation_with_properties<TS, TI, TR>::two_bool_and_not_local_operation_with_properties (db::PropertiesRepository *target1_pr, db::PropertiesRepository *target2_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint)
: db::local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::object_with_properties<TR> > (),
m_property_constraint (property_constraint), m_pms (target1_pr, subject_pr), m_pmi (target1_pr, intruder_pr), m_pm12 (target2_pr, target1_pr)
{
// .. nothing yet ..
}
template <class TS, class TI, class TR>
void
two_bool_and_not_local_operation_with_properties<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &results, size_t max_vertex_count, double area_ratio) const
{
tl_assert (results.size () == 2);
std::unordered_set<db::object_with_properties<TR> > &result0 = results [0];
std::unordered_set<db::object_with_properties<TR> > &result1 = results [1];
db::EdgeProcessor ep;
std::map<db::properties_id_type, std::pair<tl::slist<TS>, std::set<TI> > > by_prop_id;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const db::object_with_properties<TS> &subject = interactions.subject_shape (i->first);
if (i->second.empty ()) {
result1.insert (db::object_with_properties<TR> (subject, m_pms (subject.properties_id ())));
} else {
db::properties_id_type prop_id_s = m_pms (subject.properties_id ());
auto &shapes_by_prop = by_prop_id [prop_id_s];
shapes_by_prop.first.push_front (subject);
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
const db::object_with_properties<TI> &intruder = interactions.intruder_shape (*j).second;
db::properties_id_type prop_id_i = (m_property_constraint != db::NoPropertyConstraint ? m_pmi (intruder.properties_id ()) : prop_id_s);
if ((prop_id_i != prop_id_s) == (m_property_constraint == db::DifferentPropertiesConstraint)) {
shapes_by_prop.second.insert (intruder);
}
}
}
}
for (auto p2s = by_prop_id.begin (); p2s != by_prop_id.end (); ++p2s) {
ep.clear ();
size_t p1 = 0, p2 = 1;
const std::set<TR> &others = p2s->second.second;
db::properties_id_type prop_id = p2s->first;
for (auto s = p2s->second.first.begin (); s != p2s->second.first.end (); ++s) {
const TR &subject = *s;
if (others.find (subject) != others.end ()) {
result0.insert (db::object_with_properties<TR> (subject, prop_id));
} else if (others.empty ()) {
// shortcut (not: keep, and: drop)
result1.insert (db::object_with_properties<TR> (subject, m_pm12 (prop_id)));
} else {
for (auto e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
}
if (! others.empty () && p1 > 0) {
for (auto o = others.begin (); o != others.end (); ++o) {
for (auto e = o->begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}
p2 += 2;
}
std::unordered_set<TR> result0_wo_props;
std::unordered_set<TR> result1_wo_props;
db::BooleanOp op0 (db::BooleanOp::And);
db::polygon_ref_generator<TR> pr0 (layout, result0_wo_props);
db::PolygonSplitter splitter0 (pr0, area_ratio, max_vertex_count);
db::PolygonGenerator pg0 (splitter0, true, true);
db::BooleanOp op1 (db::BooleanOp::ANotB);
db::polygon_ref_generator<TR> pr1 (layout, result1_wo_props);
db::PolygonSplitter splitter1 (pr1, area_ratio, max_vertex_count);
db::PolygonGenerator pg1 (splitter1, true, true);
ep.set_base_verbosity (50);
std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > procs;
procs.push_back (std::make_pair (&pg0, &op0));
procs.push_back (std::make_pair (&pg1, &op1));
ep.process (procs);
for (auto r = result0_wo_props.begin (); r != result0_wo_props.end (); ++r) {
result0.insert (db::object_with_properties<TR> (*r, prop_id));
}
for (auto r = result1_wo_props.begin (); r != result1_wo_props.end (); ++r) {
result1.insert (db::object_with_properties<TR> (*r, m_pm12 (prop_id)));
}
}
}
}
template <class TS, class TI, class TR>
std::string two_bool_and_not_local_operation_with_properties<TS, TI, TR>::description () const
{
return tl::to_string (tr ("ANDNOT operation"));
}
template class DB_PUBLIC two_bool_and_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC two_bool_and_not_local_operation_with_properties<db::Polygon, db::Polygon, db::Polygon>;
// ---------------------------------------------------------------------------------------------
SelfOverlapMergeLocalOperation::SelfOverlapMergeLocalOperation (unsigned int wrap_count)
: m_wrap_count (wrap_count)
{
// .. nothing yet ..
}
void
SelfOverlapMergeLocalOperation::do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
if (m_wrap_count == 0) {
return;
}
db::EdgeProcessor ep;
size_t p1 = 0, p2 = 1;
std::set<unsigned int> seen;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
if (seen.find (i->first) == seen.end ()) {
seen.insert (i->first);
const db::PolygonRef &subject = interactions.subject_shape (i->first);
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 o = i->second.begin (); o != i->second.end (); ++o) {
// don't take the same (really the same, not an identical one) shape twice - the interaction
// set does not take care to list just one copy of the same item on the intruder side.
if (seen.find (*o) == seen.end ()) {
seen.insert (*o);
const db::PolygonRef &intruder = interactions.intruder_shape (*o).second;
for (db::PolygonRef::polygon_edge_iterator e = intruder.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}
p2 += 2;
}
}
}
db::MergeOp op (m_wrap_count - 1);
db::PolygonRefGenerator pr (layout, result);
db::PolygonGenerator pg (pr, true, true);
ep.set_base_verbosity (50);
ep.process (pg, op);
}
OnEmptyIntruderHint SelfOverlapMergeLocalOperation::on_empty_intruder_hint () const
{
return m_wrap_count > 1 ? Drop : Copy;
}
std::string SelfOverlapMergeLocalOperation::description () const
{
return tl::sprintf (tl::to_string (tr ("Self-overlap (wrap count %d)")), int (m_wrap_count));
}
// ---------------------------------------------------------------------------------------------
// EdgeBoolAndOrNotLocalOperation implementation
EdgeBoolAndOrNotLocalOperation::EdgeBoolAndOrNotLocalOperation (EdgeBoolOp op)
: m_op (op)
{
// .. nothing yet ..
}
OnEmptyIntruderHint
EdgeBoolAndOrNotLocalOperation::on_empty_intruder_hint () const
{
return (m_op == EdgeAnd || m_op == EdgeIntersections) ? Drop : Copy;
}
std::string
EdgeBoolAndOrNotLocalOperation::description () const
{
if (m_op == EdgeIntersections) {
return tl::to_string (tr ("Edge INTERSECTION operation"));
} else if (m_op == EdgeAnd) {
return tl::to_string (tr ("Edge AND operation"));
} else if (m_op == EdgeNot) {
return tl::to_string (tr ("Edge NOT operation"));
} else {
return std::string ();
}
}
void
EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == size_t (m_op == EdgeAndNot ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (results.size () > 1) {
result2 = &results[1];
}
EdgeBooleanClusterCollector<std::unordered_set<db::Edge> > cluster_collector (&result, m_op, result2);
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
bool any_subject = false;
bool is_and = (m_op == EdgeAnd || m_op == EdgeAndNot || m_op == EdgeIntersections);
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
if (is_and) {
result.insert (subject);
}
} else if (i->second.empty ()) {
// shortcut (not: keep, and: drop)
if (! is_and) {
result.insert (subject);
}
} else {
scanner.insert (&subject, 0);
any_subject = true;
}
}
if (! others.empty () || any_subject) {
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
}
}
// ---------------------------------------------------------------------------------------------
// EdgeToPolygonLocalOperation implementation
EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders)
: m_op (op), m_include_borders (include_borders)
{
// .. nothing yet ..
}
OnEmptyIntruderHint
EdgeToPolygonLocalOperation::on_empty_intruder_hint () const
{
return m_op == EdgePolygonOp::Inside ? Drop : (m_op == EdgePolygonOp::Outside ? Copy : CopyToSecond);
}
std::string
EdgeToPolygonLocalOperation::description () const
{
if (m_op == EdgePolygonOp::Inside) {
return tl::to_string (tr ("Edge to polygon AND/INSIDE"));
} else if (m_op == EdgePolygonOp::Outside) {
return tl::to_string (tr ("Edge to polygon NOT/OUTSIDE"));
} else {
return tl::to_string (tr ("Edge to polygon ANDNOT/INOUTSIDE"));
}
}
void
EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == size_t (m_op == EdgePolygonOp::Both ? 2 : 1));
std::unordered_set<db::Edge> &result = results.front ();
std::unordered_set<db::Edge> *result2 = 0;
if (results.size () > 1) {
result2 = &results[1];
}
db::EdgeProcessor ep;
std::set<db::PolygonRef> others;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
bool any_subject = false;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
if (i->second.empty ()) {
// shortcut (outside: keep, otherwise: drop)
if (m_op == db::EdgePolygonOp::Outside) {
result.insert (subject);
} else if (m_op == db::EdgePolygonOp::Both) {
result2->insert (subject);
}
} else {
ep.insert (subject, 1);
any_subject = true;
}
}
if (! others.empty () || any_subject) {
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
for (db::PolygonRef::polygon_edge_iterator e = o->begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, 0);
}
}
std::unique_ptr<db::EdgeToEdgeSetGenerator> cc_second;
if (result2) {
cc_second.reset (new db::EdgeToEdgeSetGenerator (*result2, 2 /*second tag*/));
}
db::EdgeToEdgeSetGenerator cc (result, 1 /*first tag*/, cc_second.get ());
db::EdgePolygonOp op (m_op, m_include_borders);
ep.process (cc, op);
}
}
}

View File

@ -131,156 +131,6 @@ protected:
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &result, size_t max_vertex_count, double area_ratio) const = 0;
};
/**
* @brief Implements a boolean AND or NOT operation
*/
template <class TS, class TI, class TR>
class DB_PUBLIC bool_and_or_not_local_operation
: public local_operation<TS, TI, TR>
{
public:
bool_and_or_not_local_operation (bool is_and);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
bool m_is_and;
};
typedef bool_and_or_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> BoolAndOrNotLocalOperation;
/**
* @brief Implements a boolean AND or NOT operation with property handling
*/
template <class TS, class TI, class TR>
class DB_PUBLIC bool_and_or_not_local_operation_with_properties
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::object_with_properties<TR> >
{
public:
bool_and_or_not_local_operation_with_properties (bool is_and, db::PropertiesRepository *target_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint);
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
bool m_is_and;
db::PropertyConstraint m_property_constraint;
mutable db::PropertyMapper m_pms;
mutable db::PropertyMapper m_pmi;
};
typedef bool_and_or_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef> BoolAndOrNotLocalOperationWithProperties;
/**
* @brief Implements a boolean AND plus NOT operation
*
* This processor delivers two outputs: the first one having the AND result, the second
* one having the NOT result.
*/
template <class TS, class TI, class TR>
class DB_PUBLIC two_bool_and_not_local_operation
: public local_operation<TS, TI, TR>
{
public:
two_bool_and_not_local_operation ();
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &result, size_t max_vertex_count, double area_ratio) const;
virtual std::string description () const;
};
typedef two_bool_and_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> TwoBoolAndNotLocalOperation;
/**
* @brief Implements a boolean AND plus NOT operation
*
* This processor delivers two outputs: the first one having the AND result, the second
* one having the NOT result.
*/
template <class TS, class TI, class TR>
class DB_PUBLIC two_bool_and_not_local_operation_with_properties
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::object_with_properties<TR> >
{
public:
two_bool_and_not_local_operation_with_properties (db::PropertiesRepository *target1_pr, db::PropertiesRepository *target2_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &result, size_t max_vertex_count, double area_ratio) const;
virtual std::string description () const;
private:
db::PropertyConstraint m_property_constraint;
mutable db::PropertyMapper m_pms, m_pmi, m_pm12;
};
typedef two_bool_and_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef> TwoBoolAndNotLocalOperationWithProperties;
/**
* @brief Implements a merge operation with an overlap count
* With a given wrap_count, the result will only contains shapes where
* the original shapes overlap at least "wrap_count" times.
*/
class DB_PUBLIC SelfOverlapMergeLocalOperation
: public local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>
{
public:
SelfOverlapMergeLocalOperation (unsigned int wrap_count);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
unsigned int m_wrap_count;
};
/**
* @brief Implements a boolean AND or NOT operation between edges
*/
class DB_PUBLIC EdgeBoolAndOrNotLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
EdgeBoolAndOrNotLocalOperation (db::EdgeBoolOp op);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
// edge interaction distance is 1 to force overlap between edges and edge/boxes
virtual db::Coord dist () const { return 1; }
private:
db::EdgeBoolOp m_op;
};
/**
* @brief Implements a boolean AND or NOT operation between edges and polygons (polygons as intruders)
*
* "AND" is implemented by "outside == false", "NOT" by "outside == true" with "include_borders == true".
* With "include_borders == false" the operations are "INSIDE" and "OUTSIDE".
*/
class DB_PUBLIC EdgeToPolygonLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
{
public:
EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
// edge interaction distance is 1 to force overlap between edges and edge/boxes
virtual db::Coord dist () const { return m_include_borders ? 1 : 0; }
private:
db::EdgePolygonOp::mode_t m_op;
bool m_include_borders;
};
}
#endif

View File

@ -29,6 +29,7 @@
#include "dbLayout.h"
#include "dbPolygonGenerators.h"
#include "dbLocalOperation.h"
#include "dbHash.h"
#include "tlThreads.h"
@ -303,6 +304,45 @@ private:
db::properties_id_type m_prop_id;
};
/**
* @brief Separates the interacting shapes by property relation
*
* Returns a map of property ID, subject shapes and intruder shapes belonging to the subject shapes.
* Depending on the property constraint the intruders will either be ones with and properties (NoPropertyConstraint),
* the same properties than the subject (SamePropertiesConstraint) or different properties (DifferentPropertiesConstraint).
*/
template <class TS, class TI>
DB_PUBLIC
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<const TI *> > >
separate_interactions_by_properties (const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, db::PropertyConstraint property_constraint, db::PropertyMapper &pms, db::PropertyMapper &pmi)
{
std::map<db::properties_id_type, std::pair<std::vector<const TS *>, std::set<const TI *> > > by_prop_id;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const db::object_with_properties<TS> &subject = interactions.subject_shape (i->first);
db::properties_id_type prop_id = pms (subject.properties_id ());
std::pair<std::vector<const TS *>, std::set<const TI *> > &s2p = by_prop_id [prop_id];
s2p.first.push_back (&subject);
for (auto ii = i->second.begin (); ii != i->second.end (); ++ii) {
const std::pair<unsigned int, db::object_with_properties<TI> > &intruder = interactions.intruder_shape (*ii);
db::properties_id_type intruder_prop_id = (property_constraint == db::NoPropertyConstraint ? prop_id : pmi (intruder.second.properties_id ()));
if ((property_constraint == db::DifferentPropertiesConstraint) == (prop_id != intruder_prop_id)) {
s2p.second.insert (&intruder.second);
}
}
}
return by_prop_id;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@
#include "dbCommon.h"
#include "dbEdgePairRelations.h"
#include "dbLocalOperation.h"
#include "dbLocalOperationUtils.h"
#include "dbEdgeProcessor.h"
#include "dbRegionCheckUtils.h"
#include "dbPropertyConstraint.h"
@ -125,7 +126,8 @@ struct DB_PUBLIC RegionCheckOptions
bool _shielded = true,
OppositeFilter _opposite_filter = NoOppositeFilter,
RectFilter _rect_filter = NoRectFilter,
bool _negative = false)
bool _negative = false,
PropertyConstraint _prop_constraint = IgnoreProperties)
: whole_edges (_whole_edges),
metrics (_metrics),
ignore_angle (_ignore_angle),
@ -134,7 +136,8 @@ struct DB_PUBLIC RegionCheckOptions
shielded (_shielded),
opposite_filter (_opposite_filter),
rect_filter (_rect_filter),
negative (_negative)
negative (_negative),
prop_constraint (_prop_constraint)
{ }
/**
@ -199,6 +202,11 @@ struct DB_PUBLIC RegionCheckOptions
*/
bool negative;
/**
* @brief Specifies a property constraint - e.g. checking only shapes with the same properties
*/
PropertyConstraint prop_constraint;
/**
* @brief Gets a value indicating whether merged primary input is required
*/
@ -213,9 +221,28 @@ struct DB_PUBLIC RegionCheckOptions
}
};
template <class TS, class TI>
class check_local_operation_base
{
public:
check_local_operation_base (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
protected:
EdgeRelationFilter m_check;
bool m_different_polygons;
bool m_is_merged;
bool m_has_other;
bool m_other_is_merged;
db::RegionCheckOptions m_options;
void compute_results (db::Layout *layout, const std::vector<const TS *> &subjects, const std::set<const TI *> &intruders, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result) const;
void apply_opposite_filter (const std::vector<const TS *> &subjects, std::unordered_set<db::EdgePair> &result, std::unordered_set<db::EdgePair> &intra_polygon_result) const;
void apply_rectangle_filter (const std::vector<const TS *> &subjects, std::unordered_set<db::EdgePair> &result) const;
};
template <class TS, class TI>
class check_local_operation
: public local_operation<TS, TI, db::EdgePair>
: public local_operation<TS, TI, db::EdgePair>, public check_local_operation_base<TS, TI>
{
public:
check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
@ -226,14 +253,24 @@ public:
virtual std::string description () const;
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
};
template <class TS, class TI>
class check_local_operation_with_properties
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::EdgePair>, public check_local_operation_base<TS, TI>
{
public:
check_local_operation_with_properties (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options, db::PropertiesRepository *target_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr);
virtual db::Coord dist () const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual bool requests_single_subjects () const { return true; }
virtual std::string description () const;
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
private:
EdgeRelationFilter m_check;
bool m_different_polygons;
bool m_is_merged;
bool m_has_other;
bool m_other_is_merged;
db::RegionCheckOptions m_options;
mutable db::PropertyMapper m_pms, m_pmi;
};
typedef check_local_operation<db::PolygonRef, db::PolygonRef> CheckLocalOperation;
@ -372,6 +409,131 @@ typedef contained_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef
// the implementation is type-agnostic and can be used for edges too
typedef contained_local_operation<db::Edge, db::Edge, db::Edge> ContainedEdgesLocalOperation;
/**
* @brief Implements a boolean AND or NOT operation
*/
template <class TS, class TI, class TR>
class DB_PUBLIC bool_and_or_not_local_operation
: public local_operation<TS, TI, TR>
{
public:
bool_and_or_not_local_operation (bool is_and);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
bool m_is_and;
};
typedef bool_and_or_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> BoolAndOrNotLocalOperation;
/**
* @brief Implements a boolean AND or NOT operation with property handling
*/
template <class TS, class TI, class TR>
class DB_PUBLIC bool_and_or_not_local_operation_with_properties
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::object_with_properties<TR> >
{
public:
bool_and_or_not_local_operation_with_properties (bool is_and, db::PropertiesRepository *target_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint);
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
bool m_is_and;
db::PropertyConstraint m_property_constraint;
mutable db::PropertyMapper m_pms;
mutable db::PropertyMapper m_pmi;
};
typedef bool_and_or_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef> BoolAndOrNotLocalOperationWithProperties;
/**
* @brief Implements a boolean AND plus NOT operation
*
* This processor delivers two outputs: the first one having the AND result, the second
* one having the NOT result.
*/
template <class TS, class TI, class TR>
class DB_PUBLIC two_bool_and_not_local_operation
: public local_operation<TS, TI, TR>
{
public:
two_bool_and_not_local_operation ();
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &result, size_t max_vertex_count, double area_ratio) const;
virtual std::string description () const;
};
typedef two_bool_and_not_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> TwoBoolAndNotLocalOperation;
/**
* @brief Implements a boolean AND plus NOT operation
*
* This processor delivers two outputs: the first one having the AND result, the second
* one having the NOT result.
*/
template <class TS, class TI, class TR>
class DB_PUBLIC two_bool_and_not_local_operation_with_properties
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::object_with_properties<TR> >
{
public:
two_bool_and_not_local_operation_with_properties (db::PropertiesRepository *target1_pr, db::PropertiesRepository *target2_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr, db::PropertyConstraint property_constraint);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::object_with_properties<TR> > > &result, size_t max_vertex_count, double area_ratio) const;
virtual std::string description () const;
private:
db::PropertyConstraint m_property_constraint;
mutable db::PropertyMapper m_pms, m_pmi, m_pm12;
};
typedef two_bool_and_not_local_operation_with_properties<db::PolygonRef, db::PolygonRef, db::PolygonRef> TwoBoolAndNotLocalOperationWithProperties;
/**
* @brief Implements a merge operation with an overlap count
* With a given wrap_count, the result will only contains shapes where
* the original shapes overlap at least "wrap_count" times.
*/
class DB_PUBLIC SelfOverlapMergeLocalOperation
: public local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>
{
public:
SelfOverlapMergeLocalOperation (unsigned int wrap_count);
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &result, size_t max_vertex_count, double area_ratio) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
unsigned int m_wrap_count;
};
/**
* @brief Converts polygons to edges
*/
class DB_PUBLIC PolygonToEdgeLocalOperation
: public local_operation<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgeWithProperties>
{
public:
PolygonToEdgeLocalOperation (db::PropertiesRepository *target_pr, const db::PropertiesRepository *source_pr);
virtual db::Coord dist () const { return 1; }
virtual bool requests_single_subjects () const { return true; }
virtual std::string description () const;
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRefWithProperties, db::PolygonRefWithProperties> &interactions, std::vector<std::unordered_set<db::EdgeWithProperties> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
private:
mutable db::PropertyMapper m_pm;
};
} // namespace db
#endif

View File

@ -30,6 +30,7 @@
#include "dbEdgeProcessor.h"
#include "dbPolygonGenerators.h"
#include "dbLocalOperationUtils.h"
#include "dbRegionLocalOperations.h"
#include "dbPolygon.h"
static std::string testdata (const std::string &fn)