The issue was caused by an internal error in the edge processor.
Effectively the weak attractor scheme was causing this problem.
As the weak attractors are making things worse rather than
better I dropped them.

In theory, the weak attractors render an edge undisturbed by
neighboring intersection points, but in cases or parallel edges
this lead to problems: omitting cut points violates the output
edge configuration warranties the the polygon stitcher fails.

In addition, to maintain the solution for bug #74, the cut point
capture condition was relaxed, so that edge crossing the exact
corner of the snapping rectangle of a point are not considered
captured.
This commit is contained in:
Matthias Koefferlein 2018-06-26 00:55:45 +02:00
parent b08ccb20dc
commit 94387529d6
30 changed files with 65 additions and 61 deletions

View File

@ -155,7 +155,7 @@ is_point_on_fuzzy (const db::Edge &e, const db::Point &pt)
if (a1 < 0) { a1 = -a1; }
area_type a2 = db::vprod (offset, e.d ());
if (a2 < 0) { a2 = -a2; }
return a1 <= a2;
return a1 < a2;
}
}
@ -1345,32 +1345,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
#endif
// The new cutpoint must be inserted into other edges as well.
// If the cutpoint is exactly on the edge and there is just one other edge
// the cutpoint will be a weak attractor - that is an optional cutpoint.
// In that case we can skip the cutpoint because no related edge will move.
ip_weak.clear ();
size_t n_off_edge = on_edge1 ? 0 : 1;
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
ip_weak.push_back (&*cc);
if (!is_point_on_exact (*cc, cp.second)) {
++n_off_edge;
}
}
}
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
if (n_off_edge > 1) {
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
} else {
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints);
cpp->add_attractor (cp.second, (*icc)->data - 1);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
}
}
}
@ -1435,38 +1420,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
#endif
// The new cutpoint must be inserted into other edges as well.
// If the cutpoint is exactly on the edge and there is just one other edge
// the cutpoint will be a weak attractor - that is an optional cutpoint.
// In that case we can skip the cutpoint because no related edge will move.
ip_weak.clear ();
size_t n_off_edge = 0;
if (!on_edge1) {
n_off_edge += 1;
}
if (!on_edge2) {
n_off_edge += 1;
}
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
ip_weak.push_back (&*cc);
if (!is_point_on_exact (*cc, cp.second)) {
++n_off_edge;
}
}
}
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
if (n_off_edge > 1) {
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
} else {
CutPoints *cpp = (*icc)->make_cutpoints (cutpoints);
cpp->add_attractor (cp.second, (*icc)->data - 1);
#ifdef DEBUG_EDGE_PROCESSOR
printf ("intersection point %s gives weak attractor in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
#endif
}
}
}

View File

@ -296,7 +296,7 @@ PolygonGenerator::flush ()
{
#ifdef DEBUG_POLYGON_GENERATOR
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
}
printf ("\n");
#endif
@ -325,12 +325,12 @@ PolygonGenerator::begin_scanline (db::Coord y)
#ifdef DEBUG_POLYGON_GENERATOR
printf ("m_open=");
for (open_map_type::const_iterator o = m_open.begin (); o != m_open.end (); ++o) {
printf ("%d:%s ", o->contour, o->point.to_string().c_str());
printf ("%ld:%s ", o->contour, o->point.to_string().c_str());
}
printf ("\n");
printf ("contours:\n");
for (size_t j = 0; j < mp_contours->size (); ++j) {
printf ("c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
printf ("c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
}
@ -364,7 +364,7 @@ PolygonGenerator::skip_n (size_t n)
{
join_contours (std::numeric_limits<db::Coord>::max ());
#ifdef DEBUG_POLYGON_GENERATOR
printf ("skip(%d)\n", n);
printf ("skip(%ld)\n", n);
#endif
while (n-- > 0) {
++m_open_pos;
@ -375,9 +375,9 @@ void
PolygonGenerator::put (const db::Edge &e)
{
#ifdef DEBUG_POLYGON_GENERATOR
printf ("put(%s) y=%d m_open(%d)=", e.to_string().c_str(),m_y,std::distance (m_open.begin (), m_open_pos));
printf ("put(%s) y=%d m_open(%ld)=", e.to_string().c_str(),m_y,std::distance (m_open.begin (), m_open_pos));
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
}
printf ("\n");
#endif
@ -438,7 +438,7 @@ PolygonGenerator::put (const db::Edge &e)
cnew.push_back (e.p2 ());
#ifdef DEBUG_POLYGON_GENERATOR
printf ("create %s %d\n", hole ? "hole" : "hull", poly_index);
printf ("create %s %ld\n", hole ? "hole" : "hull", inew);
#endif
m_open.insert (m_open_pos, PGPoint (hole ? e.p1 () : e.p2 (), inew, true));
m_open.insert (m_open_pos, PGPoint (hole ? e.p2 () : e.p1 (), inew, false));
@ -449,7 +449,7 @@ PolygonGenerator::put (const db::Edge &e)
#ifdef DEBUG_POLYGON_GENERATOR
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
printf ("%d:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
printf ("%ld:%s%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ');
}
printf ("\n");
#endif
@ -552,14 +552,14 @@ PolygonGenerator::join_contours (db::Coord x)
size_t i1 = m_open_pos->contour;
size_t i2 = n->contour;
#ifdef DEBUG_POLYGON_GENERATOR
printf ("join %d and %d\n", i1, i2);
printf ("join %ld and %ld\n", i1, i2);
for (open_map_iterator_type i = m_open.begin (); i != m_open.end (); ++i) {
printf ("%d:%s%c%c%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ', i == n ? '+' : ' ', i == nn ? '#' : ' ');
printf ("%ld:%s%c%c%c%c ", i->contour, i->point.to_string().c_str(), i->first ? '!' : ' ', i == m_open_pos ? '*' : ' ', i == n ? '+' : ' ', i == nn ? '#' : ' ');
}
printf ("\n");
printf ("--> input contours:\n");
for (size_t j = 0; j < mp_contours->size (); ++j) {
printf ("--> c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
printf ("--> c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
}
@ -705,7 +705,7 @@ PolygonGenerator::join_contours (db::Coord x)
if (! c1.is_hole ()) {
#ifdef DEBUG_POLYGON_GENERATOR
printf ("finish %d (hull)\n", i1);
printf ("finish %ld (hull)\n", i1);
#endif
produce_poly (c1);
@ -775,7 +775,7 @@ PolygonGenerator::join_contours (db::Coord x)
#ifdef DEBUG_POLYGON_GENERATOR
printf ("--> output contours:\n");
for (size_t j = 0; j < mp_contours->size (); ++j) {
printf ("--> c%d%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
printf ("--> c%ld%s: ", j, (*mp_contours)[j].is_hole () ? "H" : "");
for (size_t i = 0; i < (*mp_contours)[j].size (); ++i) {
printf ("%s ", ((*mp_contours)[j].begin () + i)->to_string().c_str ());
}

View File

@ -25,6 +25,7 @@
#include "dbShapeProcessor.h"
#include "dbPolygon.h"
#include "dbPolygonGenerators.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbCommonReader.h"
@ -1388,15 +1389,29 @@ TEST(24)
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
std::vector<db::Polygon> out;
{
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (2));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;3,0;3,-2;1,0;1,-9)");
EXPECT_EQ (out[1].to_string (), "(-2,1;-2,3;0,1;0,10;1,10;1,1)");
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;-2,1;-2,3;0,1;0,10;1,10;1,1;3,0;3,-2;1,0;1,-9/1,0;1,1;0,1)");
}
{
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, true);
EXPECT_EQ (out.size (), size_t (3));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;-2,1;-2,3;1,0;1,-9)");
EXPECT_EQ (out[1].to_string (), "(3,-2;1,0;1,1;3,0)");
EXPECT_EQ (out[2].to_string (), "(0,1;0,10;1,10;1,1)");
}
}
TEST(25)
@ -2346,3 +2361,28 @@ TEST(102)
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,200;100,200;100,100;200,100;200,200;500,200;500,100;600,100;600,200;0,200;0,1000;1000,1000;1000,0)");
}
// Bug 134
TEST(134)
{
const char *pd = "(30,-7957;0,0;56,-4102;30,-7921)";
db::Coord dx = 0;
db::Coord dy = -3999;
unsigned int mode = 3;
db::Polygon p;
tl::from_string (pd, p);
db::EdgeProcessor ep;
db::Polygon ps (p.sized (dx, dy, mode));
ep.insert (ps);
db::SimpleMerge op (1 /*wc>0*/);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (0));
}

BIN
testdata/bool/and6.oas vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/bool/or6.oas vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/bool/xor6.oas vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.