mirror of https://github.com/KLayout/klayout.git
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:
parent
65cfb2d4e4
commit
067d52a269
|
|
@ -130,7 +130,8 @@ SOURCES = \
|
|||
gsiDeclDbLayoutDiff.cc \
|
||||
gsiDeclDbGlyphs.cc \
|
||||
dbVariableWidthPath.cc \
|
||||
dbNamedLayerReader.cc
|
||||
dbNamedLayerReader.cc \
|
||||
dbEdgesToContours.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue