WIP: predicates for Edges implementation

This commit is contained in:
Matthias Koefferlein 2022-08-28 23:35:45 +02:00
parent 0b59697189
commit 4af9b8b01c
6 changed files with 268 additions and 6 deletions

View File

@ -1629,6 +1629,7 @@ public:
void reset ()
{
mp_es->reset_stop ();
mp_op->reset ();
}
@ -1637,6 +1638,11 @@ public:
return mp_op->is_reset ();
}
bool can_stop ()
{
return mp_es->can_stop ();
}
void reserve (size_t n)
{
mp_op->reserve (n);
@ -1941,6 +1947,19 @@ public:
return true;
}
/**
* @brief Gets a value indicating whether the generator wants to stop
*/
bool can_stop ()
{
for (std::vector<EdgeProcessorState>::iterator s = m_states.begin (); s != m_states.end (); ++s) {
if (s->can_stop ()) {
return true;
}
}
return false;
}
/**
* @brief Reserve memory n edges
*/
@ -2414,7 +2433,7 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
y = edge_ymin ((*mp_work_edges) [0]);
future = mp_work_edges->begin ();
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end (); ) {
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end () && ! gs.can_stop (); ) {
if (m_report_progress) {
double p = double (std::distance (mp_work_edges->begin (), current)) / double (mp_work_edges->size ());

View File

@ -56,7 +56,7 @@ public:
/**
* @brief Constructor
*/
EdgeSink () { }
EdgeSink () : m_can_stop (false) { }
/**
* @brief Destructor
@ -123,6 +123,38 @@ public:
* @brief Signal the end of a scanline at the given y coordinate
*/
virtual void end_scanline (db::Coord /*y*/) { }
/**
* @brief Gets a value indicating that the generator wants to stop
*/
bool can_stop () const
{
return m_can_stop;
}
/**
* @brief Resets the stop request
*/
void reset_stop ()
{
m_can_stop = false;
}
protected:
/**
* @brief Sets the stop request
*
* The scanner can choose to stop once the request is set.
* This is useful for implementing receivers that can stop once a
* specific condition is found.
*/
void request_stop ()
{
m_can_stop = true;
}
private:
bool m_can_stop;
};
/**

View File

@ -274,4 +274,96 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const
}
}
// -------------------------------------------------------------------------------------------------------------
// Edge to Edge relation implementation
bool edge_interacts (const db::Edge &a, const db::Edge &b)
{
return a.intersect (b);
}
bool edge_is_inside (const db::Edge &a, const db::Edge &b)
{
return b.contains (a.p1 ()) && b.contains (a.p2 ());
}
bool edge_is_outside (const db::Edge &a, const db::Edge &b)
{
if (a.parallel (b)) {
return ! a.coincident (b);
} else {
auto pt = a.intersect_point (b);
if (! pt.first) {
// no intersection -> outside
return true;
}
return ! b.contains_excl (pt.second);
}
}
// -------------------------------------------------------------------------------------------------------------
// Edge to Polygon relation implementation
bool edge_interacts (const db::Edge &a, const db::Polygon &b)
{
return db::interact (b, a);
}
namespace {
struct DetectTagEdgeSink
: public db::EdgeSink
{
DetectTagEdgeSink (int tag)
: fail_tag (tag), result (true) { }
virtual void put (const db::Edge &, int tag)
{
if (tag == fail_tag) {
result = false;
request_stop ();
}
}
int fail_tag;
bool result;
};
}
static bool
edge_is_inside_or_outside (bool outside, const db::Edge &a, const db::Polygon &b)
{
db::EdgeProcessor ep;
ep.insert (b, 0);
ep.insert (a, 1);
DetectTagEdgeSink es (outside ? 1 : 2); // 2 is the "outside" tag in "Both" mode -> this makes inside fail
db::EdgePolygonOp op (db::EdgePolygonOp::Both, true /*include borders*/);
ep.process (es, op);
return es.result;
}
bool edge_is_inside (const db::Edge &a, const db::Polygon &b)
{
// shortcuts
if (!a.bbox ().inside (b.box ())) {
return false;
}
return edge_is_inside_or_outside (false, a, b);
}
bool edge_is_outside (const db::Edge &a, const db::Polygon &b)
{
// shortcuts
if (! a.bbox ().overlaps (b.box ())) {
return true;
}
return edge_is_inside_or_outside (true, a, b);
}
}

View File

@ -246,6 +246,21 @@ private:
EdgeAngleChecker m_checker;
};
/**
* @brief A predicate defining edge a interacts with b
*/
DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Edge &b);
/**
* @brief A predicate defining edge a is "inside" b
*/
DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Edge &b);
/**
* @brief A predicate defining edge a is "outside" b
*/
DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Edge &b);
/**
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
*/
@ -266,8 +281,9 @@ public:
if (p1 != p2) {
const db::Edge *o = p1 > p2 ? o2 : o1;
const db::Edge *oo = p1 > p2 ? o1 : o2;
// @@@
if (o->intersect (*oo)) {
if ((m_mode == EdgesInteract && db::edge_interacts (*o, *oo)) ||
(m_mode == EdgesInside && db::edge_is_inside (*o, *oo)) ||
(m_mode == EdgesOutside && db::edge_is_outside (*o, *oo))) {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
}
@ -281,6 +297,21 @@ private:
EdgeInteractionMode m_mode;
};
/**
* @brief A predicate defining edge a interacts with polygon b
*/
DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Polygon &b);
/**
* @brief A predicate defining edge a is "inside" polygon b
*/
DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Polygon &b);
/**
* @brief A predicate defining edge a is "outside" polygon b
*/
DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Polygon &b);
/**
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
*
@ -307,8 +338,9 @@ public:
tl::select (ep, e, p);
if (m_seen.find (ep) == m_seen.end ()) {
// @@@
if (db::interact (*p, *e)) {
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p)) ||
(m_mode == EdgesOutside && db::edge_is_outside (*e, *p))) {
m_seen.insert (ep);
mp_output->insert (*ep);
}

View File

@ -0,0 +1,86 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 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 "tlUnitTest.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
TEST(1)
{
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 0), db::Point (20, 00)), db::Edge (db::Point (0, 0), db::Point (10, 0))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (11, 0), db::Point (20, 00)), db::Edge (db::Point (0, 0), db::Point (10, 0))), false);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 1), db::Point (10, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 0), db::Point (1, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 1), db::Point (0, 10))), false);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 20), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 20), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (-10, -10), db::Point (10, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (5, 5), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (20, 20))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 2), db::Point (20, 22))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (0, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 1), db::Point (20, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (30, 30), db::Point (20, 20))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon ()), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (15, 15)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (10, 10), db::Point (20, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (-10, -10), db::Point (10, 20))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (5, 5), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (20, 20))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 2), db::Point (20, 22))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (0, 20))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 1), db::Point (20, 20))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (30, 30), db::Point (20, 20))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon ()), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (15, 15)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (0, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
}

View File

@ -71,6 +71,7 @@ SOURCES = \
dbEdgePairRelationsTests.cc \
dbEdgePairTests.cc \
dbEdgeTests.cc \
dbEdgesUtilsTests.cc \
dbClipTests.cc \
dbCellMappingTests.cc \
dbCellHullGeneratorTests.cc \