mirror of https://github.com/KLayout/klayout.git
WIP: predicates for Edges implementation
This commit is contained in:
parent
0b59697189
commit
4af9b8b01c
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +71,7 @@ SOURCES = \
|
|||
dbEdgePairRelationsTests.cc \
|
||||
dbEdgePairTests.cc \
|
||||
dbEdgeTests.cc \
|
||||
dbEdgesUtilsTests.cc \
|
||||
dbClipTests.cc \
|
||||
dbCellMappingTests.cc \
|
||||
dbCellHullGeneratorTests.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue