FEATURE: DXF accuracy and "keep layer names" feature

* "keep layer name" will not try to modify layer names into
  GDS layer/datatypes. The feature is available in the DXF
  reader options and for the buddy scripts as "--keep-layer-names"
  It applies to CIF too.
* "contour accuracy": when merging lines into contours, this
  accuracy is applied to find neighbors. By default this value
  is 0. If set to a value >0, points with distances (square
  metrics) less than this value will be connected.
  The buddy script option is --dxf-contour-accuracy=value.
This commit is contained in:
Matthias Koefferlein 2018-04-18 23:27:44 +02:00
parent 65cfb2d4e4
commit 067d52a269
6 changed files with 478 additions and 251 deletions

View File

@ -130,7 +130,8 @@ SOURCES = \
gsiDeclDbLayoutDiff.cc \
gsiDeclDbGlyphs.cc \
dbVariableWidthPath.cc \
dbNamedLayerReader.cc
dbNamedLayerReader.cc \
dbEdgesToContours.cc
HEADERS = \
dbArray.h \

View File

@ -2743,6 +2743,8 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
db::EdgesToContours e2c;
db::Coord accuracy = db::coord_traits<db::Coord>::rounded (m_contour_accuracy * m_unit / m_dbu);
for (std::map <unsigned int, std::vector <db::Edge> >::iterator ce = collected_edges.begin (); ce != collected_edges.end (); ++ce) {
std::vector <db::Edge> &edges = ce->second;
@ -2750,20 +2752,18 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
std::vector<db::Edge> cc_edges;
e2c.fill (edges.begin (), edges.end (), true /*unordered*/, &progress);
e2c.fill (edges.begin (), edges.end (), true /*unordered*/, accuracy, &progress);
for (size_t c = 0; c < e2c.contours (); ++c) {
if (e2c.contour (c).back () == e2c.contour (c).front () || m_polyline_mode == 4 /*auto-close*/) {
if (e2c.contour_closed (c) || m_polyline_mode == 4 /*auto-close*/) {
// closed contour: store for later merging
for (std::vector<db::Point>::const_iterator cc = e2c.contour (c).begin (); cc + 1 != e2c.contour (c).end (); ++cc) {
cc_edges.push_back (db::Edge (cc[0], cc[1]));
}
if (e2c.contour (c).back () != e2c.contour (c).front ()) {
cc_edges.push_back (db::Edge (e2c.contour (c).back (), e2c.contour (c).front ()));
}
cc_edges.push_back (db::Edge (e2c.contour (c).back (), e2c.contour (c).front ()));
} else {

View File

@ -0,0 +1,293 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbEdgesToContours.h"
#include "dbBoxTree.h"
#include "dbBoxConvert.h"
#include "tlProgress.h"
#include <vector>
#include <algorithm>
#include <limits>
namespace
{
template<class Iter>
class EdgeRef
{
public:
typedef typename std::iterator_traits<Iter>::value_type value_type;
typedef typename value_type::coord_type coord_type;
typedef db::point<coord_type> point_type;
EdgeRef (Iter i)
: iter (i), swapped (0), connected (false), delivered (false), seen (false), next (0)
{ }
Iter iter;
short swapped;
bool connected : 1;
bool delivered : 1;
bool seen : 1;
EdgeRef<Iter> *next;
point_type a () const
{
return swapped > 0 ? iter->p2 () : iter->p1 ();
}
point_type b () const
{
return swapped > 0 ? iter->p1 () : iter->p2 ();
}
};
template<class Iter, bool swapped>
struct EdgeRefToBox
{
public:
typedef typename std::iterator_traits<Iter>::value_type value_type;
typedef typename value_type::coord_type coord_type;
typedef db::box<coord_type> box_type;
typedef db::simple_bbox_tag complexity;
EdgeRefToBox (coord_type d)
: distance (d)
{ }
box_type operator() (EdgeRef<Iter> *er) const
{
db::point<coord_type> p = swapped ? er->iter->p2 () : er->iter->p1 ();
db::vector<coord_type> d (distance, distance);
return box_type (p - d, p + d);
}
coord_type distance;
};
}
namespace db
{
// -----------------------------------------------------------------------------
// EdgesToContours implementation
EdgesToContours::EdgesToContours ()
{
// .. nothing yet ..
}
const std::vector<db::Point> &
EdgesToContours::contour (size_t i) const
{
static std::vector<db::Point> empty;
if (i < m_contours.size ()) {
return m_contours [i];
} else {
return empty;
}
}
template <class Iter, class C> static
EdgeRef<Iter> *search_follower (const db::point<C> &p, const EdgeRef<Iter> *e, C distance, const db::box_tree<db::box<C>, EdgeRef<Iter> *, EdgeRefToBox<Iter, false> > &t1, const db::box_tree<db::box<C>, EdgeRef<Iter> *, EdgeRefToBox<Iter, true> > &t2)
{
typedef db::box<C> box_type;
double vp_min = 0.0;
EdgeRef<Iter> *cand = 0;
bool fwd = true;
// try in forward tree
typename db::box_tree<box_type, EdgeRef<Iter> *, EdgeRefToBox<Iter, false> >::touching_iterator f = t1.begin_touching (box_type (p, p), EdgeRefToBox <Iter, false> (distance));
while (! f.at_end ()) {
if (*f != e && ! (*f)->connected && (*f)->swapped != 1) {
double vp = db::vprod ((*f)->iter->d (), e->iter->d ()) * (1.0 / (*f)->iter->d ().double_length ());
if (! cand || vp < vp_min) {
vp_min = vp;
cand = *f;
}
}
++f;
}
if (! t2.empty ()) {
typename db::box_tree<box_type, EdgeRef<Iter> *, EdgeRefToBox<Iter, true> >::touching_iterator f = t2.begin_touching (box_type (p, p), EdgeRefToBox <Iter, true> (distance));
while (! f.at_end ()) {
if (*f != e && ! (*f)->connected && (*f)->swapped != -1) {
double vp = db::vprod ((*f)->iter->d (), e->iter->d ()) * (1.0 / (*f)->iter->d ().double_length ());
if (! cand || vp < vp_min) {
vp_min = vp;
cand = *f;
fwd = false;
}
}
++f;
}
}
if (cand) {
cand->swapped = fwd ? -1 : 1;
cand->connected = true;
}
return cand;
}
template <class Iter>
void
EdgesToContours::fill (Iter from, Iter to, bool no, typename std::iterator_traits<Iter>::value_type::coord_type distance, tl::RelativeProgress *progress)
{
typedef typename std::iterator_traits<Iter>::value_type value_type;
typedef typename value_type::coord_type coord_type;
typedef db::box<coord_type> box_type;
typedef db::point<coord_type> point_type;
typedef db::box_tree<box_type, EdgeRef<Iter> *, EdgeRefToBox<Iter, false> > box_tree;
typedef db::box_tree<box_type, EdgeRef<Iter> *, EdgeRefToBox<Iter, true> > box_tree_rev;
std::vector<EdgeRef<Iter> > erefs;
erefs.reserve (to - from);
for (Iter i = from; i < to; ++i) {
erefs.push_back (EdgeRef<Iter> (i));
}
// prepare two box trees: one forward (with p1 being the key)
// and a backward one with p2 being the key
box_tree bt;
box_tree_rev btr;
bt.reserve (erefs.size ());
for (typename std::vector<EdgeRef<Iter> >::iterator e = erefs.begin (); e != erefs.end (); ++e) {
bt.insert (e.operator-> ());
}
bt.sort (EdgeRefToBox <Iter, false> (distance));
if (no) {
btr.reserve (erefs.size ());
for (typename std::vector<EdgeRef<Iter> >::iterator e = erefs.begin (); e != erefs.end (); ++e) {
btr.insert (e.operator-> ());
}
btr.sort (EdgeRefToBox <Iter, true> (distance));
}
// Build the edge dependency graph (e->next being the following one)
for (typename std::vector<EdgeRef<Iter> >::iterator e = erefs.begin (); e != erefs.end (); ++e) {
EdgeRef<Iter> *ee = e.operator-> ();
while (ee && !ee->seen) {
if (progress) {
++*progress;
}
ee->seen = true;
EdgeRef<Iter> *f1 = 0, *f2 = 0;
if (ee->swapped != 1) {
f1 = search_follower (ee->iter->p2 (), ee, distance, bt, btr);
}
if (! f1 && ee->swapped != -1 && no) {
f2 = search_follower (ee->iter->p1 (), ee, distance, bt, btr);
}
if (f1) {
ee->swapped = -1;
ee->next = f1;
} else if (f2) {
ee->swapped = 1;
ee->next = f2;
}
ee = ee->next;
}
}
// Delivery
m_contours.clear ();
m_contours_closed.clear ();
// Extract the open contours
for (typename std::vector<EdgeRef<Iter> >::iterator e = erefs.begin (); e != erefs.end (); ++e) {
if (progress) {
++*progress;
}
if (! e->delivered && ! e->connected) {
m_contours.push_back (std::vector<point_type> ());
m_contours_closed.push_back (false);
m_contours.back ().push_back (e->a ());
EdgeRef<Iter> *ee = e.operator-> ();
while (ee) {
tl_assert (! ee->delivered);
m_contours.back ().push_back (ee->b ());
ee->delivered = true;
ee = ee->next;
}
}
}
// Extract the closed contours
for (typename std::vector<EdgeRef<Iter> >::iterator e = erefs.begin (); e != erefs.end (); ++e) {
if (progress) {
++*progress;
}
if (! e->delivered) {
m_contours.push_back (std::vector<point_type> ());
m_contours_closed.push_back (true);
EdgeRef<Iter> *ee = e.operator-> ();
while (ee && ! ee->delivered) {
m_contours.back ().push_back (ee->b ());
ee->delivered = true;
ee = ee->next;
}
}
}
}
// explicit instantiation
template DB_PUBLIC void EdgesToContours::fill (std::vector<db::Edge>::iterator, std::vector<db::Edge>::iterator, bool, db::Coord, tl::RelativeProgress *);
template DB_PUBLIC void EdgesToContours::fill (db::Edge *, db::Edge *, bool, db::Coord, tl::RelativeProgress *);
} // namespace db

View File

@ -27,121 +27,15 @@
#include "dbPoint.h"
#include "dbEdge.h"
#include "dbVector.h"
#include "tlProgress.h"
#include <vector>
#include <algorithm>
#include <limits>
#include <iterator>
namespace tl {
class RelativeProgress;
}
namespace db {
class DB_PUBLIC ECRef
{
public:
template <class Iter>
ECRef (Iter from, Iter e, bool swap)
{
m_index = ((long) std::distance (from, e)) + 1;
if (swap) {
m_index = -m_index;
}
}
ECRef ()
: m_index (0)
{
// .. nothing yet ..
}
ECRef (long i)
: m_index (i)
{
// .. nothing yet ..
}
bool is_null () const
{
return m_index == 0;
}
bool operator!= (ECRef b)
{
return m_index != b.m_index;
}
bool operator== (ECRef b)
{
return m_index == b.m_index;
}
template <class Iter>
const Point &a (Iter from) const
{
if (m_index > 0) {
return from [m_index - 1].p1 ();
} else {
return from [-m_index - 1].p2 ();
}
}
template <class Iter>
const Point &b (Iter from) const
{
if (m_index > 0) {
return from [m_index - 1].p2 ();
} else {
return from [-m_index - 1].p1 ();
}
}
ECRef reverse () const
{
return ECRef (-m_index);
}
size_t index () const
{
return (size_t)((m_index < 0 ? -m_index : m_index) - 1);
}
template <class Iter>
Vector d (Iter from) const
{
if (m_index > 0) {
return from [m_index - 1].d ();
} else {
return -(from [-m_index - 1].d ());
}
}
static ECRef invalid ()
{
return ECRef (std::numeric_limits <long>::min ());
}
private:
long m_index;
};
template <class Iter>
class ECLess
{
public:
ECLess (Iter from)
: m_from (from)
{
// .. nothing yet ..
}
bool operator() (ECRef p, ECRef q) const
{
return p.a (m_from) < q.a (m_from);
}
private:
Iter m_from;
};
/**
* @brief A facility to create contours from edges
*
@ -152,122 +46,29 @@ private:
* The use of this objects is to first fill it with edges and then deliver the contours
* collected in the fill step.
*/
class EdgesToContours
class DB_PUBLIC EdgesToContours
{
public:
EdgesToContours ()
{
// .. nothing yet ..
}
EdgesToContours ();
size_t contours () const
{
return m_contours.size ();
}
const std::vector <db::Point> &contour (size_t i) const
const std::vector<db::Point> &contour (size_t i) const;
bool contour_closed (size_t i) const
{
return m_contours [i];
return m_contours_closed [i];
}
template <class Iter>
void fill (Iter from, Iter to, bool no = false, tl::RelativeProgress *progress = 0)
{
m_contours.clear ();
std::vector <ECRef> ptmap;
ptmap.reserve ((size_t)(no ? 2 : 1) * std::distance (from, to));
for (Iter e = from; e != to; ++e) {
ptmap.push_back (ECRef (from, e, false));
if (no) {
ptmap.push_back (ECRef (from, e, true));
}
}
std::sort (ptmap.begin (), ptmap.end (), ECLess<Iter> (from));
std::vector <ECRef> cmap;
cmap.resize (std::distance (from, to), ECRef::invalid ());
for (std::vector <ECRef>::iterator s0 = cmap.begin (); s0 != cmap.end (); ++s0) {
if (*s0 != ECRef::invalid ()) {
continue;
}
m_contours.push_back (std::vector <db::Point> ());
std::vector <ECRef>::iterator s = s0;
ECRef fr (from, from + std::distance (cmap.begin (), s0), false);
while (! fr.is_null ()) {
std::vector <ECRef>::iterator s_old = s;
*s_old = ECRef ();
double vp_min = 0.0;
ECRef fr_old = fr;
fr = ECRef ();
std::vector <ECRef>::const_iterator f = std::lower_bound (ptmap.begin (), ptmap.end (), fr_old.reverse (), ECLess<Iter> (from));
while (f != ptmap.end () && f->a (from) == fr_old.b (from)) {
if (progress) {
++*progress;
}
std::vector <ECRef>::iterator s_new = cmap.begin () + f->index ();
if (*s_new == ECRef::invalid ()) {
double vp = db::vprod (f->d (from), fr_old.d (from)) * (1.0 / f->d (from).double_length ());
if (fr.is_null () || vp < vp_min) {
vp_min = vp;
fr = *f;
s = s_new;
*s_old = *f;
}
}
++f;
}
if (progress) {
++*progress;
}
}
// create the contour
size_t n = 2;
s = s0;
while (! s->is_null ()) {
s = cmap.begin () + s->index ();
++n;
}
m_contours.back ().reserve (n);
const db::Edge e0 (from [std::distance (cmap.begin (), s0)]);
m_contours.back ().push_back (e0.p1 ());
m_contours.back ().push_back (e0.p2 ());
s = s0;
while (! s->is_null ()) {
m_contours.back ().push_back (s->b (from));
s = cmap.begin () + s->index ();
++n;
}
}
}
void fill (Iter from, Iter to, bool no = false, typename std::iterator_traits<Iter>::value_type::coord_type distance = 0, tl::RelativeProgress *progress = 0);
private:
std::vector <std::vector <db::Point> > m_contours;
std::vector<std::vector <db::Point> > m_contours;
std::vector<bool> m_contours_closed;
};
} // namespace db

View File

@ -169,11 +169,6 @@ TEST(12)
run_test (_this, "t12.dxf.gz", "t12_au.gds.gz");
}
TEST(13)
{
run_test (_this, "t13.dxf.gz", "t13_au.gds.gz");
}
TEST(14)
{
db::DXFReaderOptions opt;
@ -446,3 +441,23 @@ TEST(30)
run_test (_this, "t30.dxf.gz", "t30d_au.gds.gz", opt);
}
// accuracy
TEST(31)
{
db::DXFReaderOptions opt;
opt.dbu = 0.001;
opt.unit = 1000;
opt.contour_accuracy = 0;
run_test (_this, "t31.dxf.gz", "t31a_au.gds.gz", opt);
opt.contour_accuracy = 0.005;
run_test (_this, "t31.dxf.gz", "t31b_au.gds.gz", opt);
opt.contour_accuracy = 0.01;
run_test (_this, "t31.dxf.gz", "t31c_au.gds.gz", opt);
opt.contour_accuracy = 0.02;
run_test (_this, "t31.dxf.gz", "t31d_au.gds.gz", opt);
}

View File

@ -49,24 +49,29 @@ TEST(1)
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;100,0;100,100;0,100;0,0");
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;100,100;0,100;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
edges [0].swap_points ();
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;0,0");
EXPECT_EQ (e2c.contour_closed (0), false);
EXPECT_EQ (c2s (e2c.contour (1)), "100,0;100,100;0,100;0,0");
EXPECT_EQ (e2c.contour_closed (1), false);
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), true);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;0,0;0,100;100,100;100,0");
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;100,100;100,0");
EXPECT_EQ (e2c.contour_closed (0), true);
edges [2].swap_points ();
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), true);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;0,0;0,100;100,100;100,0");
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;100,100;100,0");
EXPECT_EQ (e2c.contour_closed (0), true);
}
TEST(2)
@ -84,17 +89,17 @@ TEST(2)
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), true);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "-100,-100;100,-100;0,0;-100,-100");
EXPECT_EQ (c2s (e2c.contour (1)), "200,-50;0,0;-200,-50;0,100;200,-50");
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "100,-100;0,0;200,-50;0,100;-200,-50;0,0;-100,-100");
EXPECT_EQ (e2c.contour_closed (0), true);
std::swap (edges [0], edges [3]);
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), true);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "200,-50;0,100;-200,-50;0,0;200,-50");
EXPECT_EQ (c2s (e2c.contour (1)), "100,-100;0,0;-100,-100;100,-100");
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;-200,-50;0,0;100,-100;-100,-100;0,0;200,-50");
EXPECT_EQ (e2c.contour_closed (0), true);
}
@ -114,16 +119,20 @@ TEST(3)
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "-100,-100;100,-100;0,0;-100,-100");
EXPECT_EQ (c2s (e2c.contour (1)), "0,0;200,-50;0,100;-200,-50;0,0");
EXPECT_EQ (c2s (e2c.contour (0)), "100,-100;0,0;-100,-100");
EXPECT_EQ (e2c.contour_closed (0), true);
EXPECT_EQ (c2s (e2c.contour (1)), "200,-50;0,100;-200,-50;0,0");
EXPECT_EQ (e2c.contour_closed (1), true);
std::swap (edges [0], edges [3]);
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "200,-50;0,100;-200,-50;0,0;200,-50");
EXPECT_EQ (c2s (e2c.contour (1)), "100,-100;0,0;-100,-100;100,-100");
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;-200,-50;0,0;200,-50");
EXPECT_EQ (e2c.contour_closed (1), true);
EXPECT_EQ (c2s (e2c.contour (1)), "0,0;-100,-100;100,-100");
EXPECT_EQ (e2c.contour_closed (0), true);
}
@ -146,7 +155,8 @@ TEST(4)
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;-100,100;-100,200;200,200;200,100;0,100;0,200;100,200;100,0;0,0");
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;-100,100;-100,200;200,200;200,100;0,100;0,200;100,200;100,0;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
}
TEST(5)
@ -163,11 +173,27 @@ TEST(5)
db::Edge (db::Point (0, 200), db::Point (100, 200)),
};
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;-100,100;-100,200;200,200;200,100;0,100;0,200;100,200;100,0");
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;-100,100;-100,200;200,200;200,100;0,100;0,200;100,200;100,0");
EXPECT_EQ (e2c.contour_closed (0), false);
}
for (size_t i = 0 ; i < sizeof (edges) / sizeof (edges[0]); ++i) {
edges[i].set_p1 (edges[i].p1 () + db::Vector (1, 1));
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false, 10);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "1,1;0,100;-100,100;-100,200;200,200;200,100;0,100;0,200;100,200;100,0");
EXPECT_EQ (e2c.contour_closed (0), false);
}
}
TEST(6)
@ -183,12 +209,31 @@ TEST(6)
db::Edge (db::Point (1000, 100), db::Point (1000, 0))
};
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;100,0;100,100;0,100;0,0");
EXPECT_EQ (c2s (e2c.contour (1)), "1000,0;1100,0;1100,100;1000,100;1000,0");
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;100,100;0,100;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
EXPECT_EQ (c2s (e2c.contour (1)), "1100,0;1100,100;1000,100;1000,0");
EXPECT_EQ (e2c.contour_closed (1), true);
}
for (size_t i = 0 ; i < sizeof (edges) / sizeof (edges[0]); ++i) {
edges[i].set_p1 (edges[i].p1 () + db::Vector (1, 1));
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false, 10);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "100,0;100,100;0,100;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
EXPECT_EQ (c2s (e2c.contour (1)), "1100,0;1100,100;1000,100;1000,0");
EXPECT_EQ (e2c.contour_closed (1), true);
}
}
TEST(7)
@ -208,12 +253,84 @@ TEST(7)
db::Edge (db::Point (100, 0), db::Point (0, 0))
};
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,0;0,100;200,100;400,100;400,0;300,0;300,100;200,100;200,0;200,100;100,100;100,0;0,0");
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;200,100;400,100;400,0;300,0;300,100;200,100;200,0;200,100;100,100;100,0;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false, 10);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;200,100;400,100;400,0;300,0;300,100;200,100;200,0;200,100;100,100;100,0;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
}
for (size_t i = 0 ; i < sizeof (edges) / sizeof (edges[0]); ++i) {
edges[i].set_p1 (edges[i].p1 () + db::Vector (1, 1));
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false, 10);
EXPECT_EQ (e2c.contours (), size_t (1));
EXPECT_EQ (c2s (e2c.contour (0)), "0,100;200,100;400,100;400,0;300,0;300,100;200,100;200,0;200,100;100,100;100,0;0,0");
EXPECT_EQ (e2c.contour_closed (0), true);
}
for (size_t i = 0 ; i < sizeof (edges) / sizeof (edges[0]); ++i) {
edges[i].set_p1 (edges[i].p1 () + db::Vector (10, 10));
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false, 10);
EXPECT_EQ (e2c.contours (), size_t (12));
EXPECT_EQ (c2s (e2c.contour (0)), "11,11;0,100");
EXPECT_EQ (e2c.contour_closed (0), false);
}
}
TEST(8)
{
db::Edge edges[] = {
db::Edge (db::Point (100, 100), db::Point (200, 100)),
db::Edge (db::Point (100, 100), db::Point (100, 200)),
db::Edge (db::Point (0, 0), db::Point (0, 1000)),
db::Edge (db::Point (0, 1000), db::Point (1000, 1000)),
db::Edge (db::Point (1000, 1000), db::Point (1000, 0)),
db::Edge (db::Point (1000, 0), db::Point (0, 0))
};
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), false);
EXPECT_EQ (e2c.contours (), size_t (3));
EXPECT_EQ (c2s (e2c.contour (0)), "100,100;200,100");
EXPECT_EQ (e2c.contour_closed (0), false);
EXPECT_EQ (c2s (e2c.contour (1)), "100,100;100,200");
EXPECT_EQ (e2c.contour_closed (1), false);
EXPECT_EQ (c2s (e2c.contour (2)), "0,1000;1000,1000;1000,0;0,0");
EXPECT_EQ (e2c.contour_closed (2), true);
}
{
db::EdgesToContours e2c;
e2c.fill (&edges[0], &edges[0] + (sizeof (edges) / sizeof (edges [0])), true);
EXPECT_EQ (e2c.contours (), size_t (2));
EXPECT_EQ (c2s (e2c.contour (0)), "200,100;100,100;100,200");
EXPECT_EQ (e2c.contour_closed (0), false);
EXPECT_EQ (c2s (e2c.contour (1)), "0,1000;1000,1000;1000,0;0,0");
EXPECT_EQ (e2c.contour_closed (1), true);
}
}