Variable path widths for DXF reader

This commit is contained in:
Matthias Koefferlein 2017-09-26 00:28:47 +02:00
parent 59dd9896e0
commit 2fd33a289a
7 changed files with 627 additions and 71 deletions

View File

@ -129,6 +129,7 @@ SOURCES = \
gsiDeclDbVector.cc \
gsiDeclDbLayoutDiff.cc \
gsiDeclDbGlyphs.cc \
dbVariableWidthPath.cc
HEADERS = \
dbArray.h \
@ -228,7 +229,8 @@ HEADERS = \
contrib/dbGDS2TextWriter.h \
dbCommonReader.h \
dbGlyphs.h \
dbCommon.h
dbCommon.h \
dbVariableWidthPath.h
RESOURCES = \
dbResources.qrc

View File

@ -30,6 +30,7 @@
#include "dbRecursiveShapeIterator.h"
#include "dbEdgeProcessor.h"
#include "dbEdgesToContours.h"
#include "dbVariableWidthPath.h"
#include "tlException.h"
#include "tlString.h"
@ -1574,17 +1575,15 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
} else if (entity_code == "LWPOLYLINE" || entity_code == "POLYLINE") {
std::vector<db::DPoint> points;
std::vector<std::pair<size_t, double> > widths;
std::string layer;
int flags = 0;
double width = 0.0;
bool width_set = false;
double width1 = 0.0, width2 = 0.0;
unsigned int got_width = 0;
double common_width = 0.0;
double common_width1 = 0.0, common_width2 = 0.0;
unsigned int common_width_set = 0;
double ex = 0.0, ey = 0.0, ez = 1.0;
size_t points_with_width = 0;
size_t points_with_one_width = 0;
size_t tot_points = 0;
double b = 0.0;
@ -1610,20 +1609,23 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
}
if (xy_flags == 3) {
size_t seg_start = std::max (size_t (1), points.size ()) - 1;
add_bulge_segment (points, db::DPoint (x, y), b);
++tot_points;
b = 0.0;
xy_flags = 0;
if (got_width == 3) {
widths.push_back (std::make_pair (seg_start, width1));
widths.push_back (std::make_pair (points.size () - 1, width2));
got_width = 0;
}
got_width = 0;
}
if (got_width == 3) {
++points_with_width;
} else if (got_width > 0) {
++points_with_one_width;
}
got_width = 0;
} else if (g == 210) {
ex = read_double ();
} else if (g == 220) {
@ -1632,7 +1634,7 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
ez = read_double ();
} else if (g == 43) {
common_width = read_double ();
common_width1 = common_width2 = read_double ();
common_width_set = 3;
} else if (g == 42) {
@ -1641,18 +1643,10 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
if (g == 41) {
got_width |= 2;
width2 = read_double ();
} else {
got_width |= 1;
}
if (!width_set) {
width = read_double ();
width_set = true;
} else {
double w = read_double ();
if (fabs (w - width) > 1e-6) {
warn ("Non-uniform width encountered on LWPOLYLINE");
}
width1 = read_double ();
}
} else {
@ -1677,18 +1671,11 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
ez = read_double ();
} else if (g == 40 || g == 41) {
if (common_width_set == 0) {
common_width = read_double ();
} else {
double w = read_double ();
if (fabs (w - common_width) > 1e-6) {
warn ("Different start and end width encountered on POLYLINE");
}
}
if (g == 40) {
common_width1 = read_double ();
common_width_set |= 1;
} else {
common_width2 = read_double ();
common_width_set |= 2;
}
@ -1703,12 +1690,6 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
const std::string &e = read_string (true);
if (e == "VERTEX") {
if (got_width == 3) {
++points_with_width;
} else if (got_width > 0) {
++points_with_one_width;
}
got_width = 0;
double x = 0.0, y = 0.0;
@ -1725,18 +1706,10 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
if (g == 41) {
got_width |= 2;
width2 = read_double ();
} else {
got_width |= 1;
}
if (!width_set) {
width = read_double ();
width_set = true;
} else {
double w = read_double ();
if (fabs (w - width) > 1e-6) {
warn ("Non-uniform width encountered on POLYLINE");
}
width1 = read_double ();
}
} else {
@ -1744,10 +1717,17 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
}
}
size_t seg_start = std::max (size_t (1), points.size ()) - 1;
add_bulge_segment (points, db::DPoint (x, y), b);
++tot_points;
b = bnew;
if (got_width == 3) {
widths.push_back (std::make_pair (seg_start, width1));
widths.push_back (std::make_pair (points.size () - 1, width2));
got_width = 0;
}
} else if (e == "SEQEND") {
while ((g = read_group_code ()) != 0) {
skip_value (g);
@ -1763,10 +1743,19 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
}
if (got_width == 3) {
++points_with_width;
} else if (got_width > 0) {
++points_with_one_width;
// Adds the common width if given
if (common_width_set > 0 && ! points.empty ()) {
if (widths.empty ()) {
widths.insert (widths.begin (), std::make_pair (size_t (0), common_width1));
widths.push_back (std::make_pair (points.size () - 1, common_width2));
} else {
if (widths.front ().first != 0) {
widths.insert (widths.begin (), std::make_pair (size_t (0), common_width1));
}
if (widths.back ().first != points.size () - 1) {
widths.push_back (std::make_pair (points.size () - 1, common_width2));
}
}
}
// Create a closing arc if a bulge was specified on the last point and the polygon is
@ -1775,24 +1764,21 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
// Hint: needs a copy, since points may be altered by add_bulge_segment
db::DPoint p0 (points [0]);
add_bulge_segment (points, p0, b);
if (! widths.empty ()) {
widths.push_back (std::make_pair (points.size () - 1, widths.front ().second));
}
}
// Let the per-vertex width override the common width
// TODO: this scheme just covers the case if all or no vertex has width
// specifications.
if (! width_set || fabs (width) < 1e-6) {
width = common_width;
}
// issue a warning if there are vertices without a width specification
if (points_with_width > 0 && points_with_width < tot_points) {
warn ("Mixed width specification encountered on LWPOLYLINE or POLYLINE - uniform width supported only");
}
if (points_with_one_width > 0) {
warn ("Single width specification encountered on LWPOLYLINE or POLYLINE vertex - full and uniform specification supported only");
}
if (common_width_set > 0 && common_width_set < 3) {
warn ("Either both start and end width must be specified on POLYLINE or none of them");
// check whether there is a common width and create a path if there is one
bool width_set = false;
double width = 0.0;
for (std::vector<std::pair<size_t, double> >::const_iterator w = widths.begin (); w != widths.end (); ++w) {
if (! width_set) {
width = w->second;
width_set = true;
} else if (width > -1e-6 && fabs (width - w->second) > 1e-6) {
width = -1.0;
}
}
std::pair <bool, unsigned int> ll = open_layer (layout, layer);
@ -1803,7 +1789,12 @@ DXFReader::read_entities (db::Layout &layout, db::Cell &cell, const db::DVector
// create the polygon or path for width = 0: in mode 2, the polygon is always created, in modes 3 and 4
// the polygon is split into edges and joined with other edges later (this will resolve holes formed by
// other polygons)
if (width < 1e-6 && (flags & 1) != 0 && m_polyline_mode == 2) {
if (width < -1e-6) {
db::DVariableWidthPath vp (points.begin (), points.end (), widths.begin (), widths.end (), tt);
cell.shapes(ll.second).insert (safe_from_double (vp.to_poly ()));
} else if (width < 1e-6 && (flags & 1) != 0 && m_polyline_mode == 2) {
db::DPolygon p;
p.assign_hull (points.begin (), points.end (), tt);

View File

@ -0,0 +1,319 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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 "dbVariableWidthPath.h"
namespace db
{
template <class C>
void
variable_width_path<C>::init ()
{
// compress the points
typename std::vector<db::point<C> >::iterator pw = m_points.begin ();
typename std::vector<db::point<C> >::const_iterator pr = m_points.begin ();
typename std::vector<std::pair<size_t, C> >::iterator ow = m_org_widths.begin ();
while (pr != m_points.end ()) {
size_t ir = pr - m_points.begin ();
*pw = *pr++;
while (pr != m_points.end () && *pw == *pr) {
++pr;
}
size_t irr = pr - m_points.begin ();
size_t iw = pw - m_points.begin ();
++pw;
while (ow != m_org_widths.end () && ow->first < irr && ow->first >= ir) {
ow->first = iw;
++ow;
}
if (ow != m_org_widths.end ()) {
tl_assert (ow->first >= irr);
}
}
m_points.erase (pw, m_points.end ());
// create a per-point width specification
width_type w = 0;
size_t i = 0;
bool last_set = false;
for (typename std::vector<std::pair<size_t, C> >::const_iterator j = m_org_widths.begin (); j != m_org_widths.end (); ++j) {
width_type w0 = w;
w = j->second;
tl_assert (j->first < m_points.size ());
if (j->first == i) {
if (last_set) {
m_widths.back ().second = j->second;
} else {
m_widths.push_back (std::make_pair (w0, j->second));
}
} else {
tl_assert (j->first > i);
tl_assert (j->first < m_points.size ());
// interpolation: first determine the whole length from last point to next
// and then interpolate each segment
double ll = 0;
for (size_t ii = i; ii < j->first; ++ii) {
ll += (m_points [ii + 1] - m_points [ii]).double_length ();
}
double l = 0;
for (size_t ii = i; ii <= j->first; ++ii) {
if (! last_set) {
width_type ww = db::coord_traits<C>::rounded (w0 + (w - w0) * (l / ll));
m_widths.push_back (std::make_pair (ww, ww));
}
last_set = false;
if (ii < j->first) {
l += (m_points [ii + 1] - m_points [ii]).double_length ();
}
}
i = j->first;
}
last_set = true;
}
// fill up the remaining widths (should not happen if the last width_spec is for
// the last point)
while (m_points.size () > m_widths.size ()) {
if (! last_set) {
m_widths.push_back (std::make_pair (w, w));
}
last_set = false;
}
}
template <class C, class Iter, class WIter, class Inserter>
static
void create_shifted_points (C /*c*/, bool forward, Iter from, Iter to, WIter wfrom, WIter wto, Inserter pts)
{
// for safety reasons
if (from == to) {
return;
}
WIter w = wfrom;
WIter ww = w;
++ww;
Iter p = from;
Iter pp = p;
++pp;
bool first = true;
while (pp != to) {
Iter ppp = pp;
++ppp;
WIter www = ww;
++www;
// Compute the unit vector of the line and it's normal (times width)
db::DVector ed (*pp - *p);
ed *= 1.0 / ed.double_length ();
if (first) {
first = false;
db::DVector nd (-ed.y (), ed.x ());
nd *= (forward ? w->second : w->first) * 0.5;
*pts++ = (*p + vector<C> (nd));
}
if (ppp == to) {
db::DVector nd (-ed.y (), ed.x ());
nd *= (forward ? ww->first : ww->second) * 0.5;
*pts++ = (*pp + vector<C> (nd));
} else if (fabs (double (ww->first) - double (ww->second)) > db::epsilon) {
// switching widths -> create a direct connection
db::DVector eed (*ppp - *pp);
eed *= 1.0 / eed.double_length ();
db::DVector nd (-ed.y (), ed.x ());
nd *= (forward ? ww->first : ww->second) * 0.5;
db::DVector nnd (-eed.y (), eed.x ());
nnd *= (forward ? ww->second : ww->first) * 0.5;
*pts++ = *pp + vector<C> (nd);
*pts++ = *pp + vector<C> (nnd);
} else {
tl_assert (www != wto);
double wi = ww->first;
db::DVector eed (*ppp - *pp);
eed *= 1.0 / eed.double_length ();
// Points in between are determined from taking two
// edges being shifted perpendicular from the orginal
// and being slightly extended. The intersection point
// of both gives the new vertex. If there is no intersection,
// the edges are simply connected.
db::DVector nd1 (-ed.y (), ed.x ());
nd1 *= (forward ? w->second : w->first) * 0.5;
db::DVector nd2 (-ed.y (), ed.x ());
nd2 *= wi * 0.5;
db::DVector nnd1 (-eed.y (), eed.x ());
nnd1 *= wi * 0.5;
db::DVector nnd2 (-eed.y (), eed.x ());
nnd2 *= (forward ? www->first : www->second) * 0.5;
bool is_folded = false;
double du = db::vprod (ed, eed);
if (fabs (du) > db::epsilon) {
double u1 = db::vprod (nnd1 - nd2, eed) / du;
double u2 = db::vprod (nd2 - nnd1, ed) / du;
is_folded = ((u1 < -db::epsilon) != (u2 < -db::epsilon));
}
if (is_folded) {
// No well-formed intersection (reflecting/back-folded segments) ->
// create a direct (inner) connection
*pts++ = *pp + vector<C> (nd2);
*pts++ = *pp + vector<C> (nnd1);
} else {
db::DVector g = (db::DPoint (*pp) + nd2) - (db::DPoint (*p) + nd1);
double gl = g.double_length ();
g *= 1.0 / gl;
db::DVector gg = (db::DPoint (*ppp) + nnd2) - (db::DPoint (*pp) + nnd1);
double ggl = gg.double_length ();
gg *= 1.0 / ggl;
double l1max = wi;
double l2max = wi;
double l1min = -gl - wi;
double l2min = -ggl - wi;
double dv = db::vprod (g, gg);
if (fabs (dv) > db::epsilon) {
double l1 = db::vprod (nnd1 - nd2, gg) / dv;
double l2 = db::vprod (nd2 - nnd1, g) / dv;
if (l1 < l1min - db::epsilon || l2 < l2min - db::epsilon) {
// Segments are too short - the won't intersect: In this case we create a loop of three
// points which define the area in self-overlapping way but confined to the path within
// the limits of it's width.
// HINT: the execution of this code is a pretty strong evidence for the existance to loops
// in the contour delivered. A proof however is missing ..
*pts++ = *pp + vector<C> (nd2);
*pts++ = *pp;
*pts++ = *pp + vector<C> (nnd1);
} else if (l1 < l1max + db::epsilon && l2 < l2max + db::epsilon) {
// well-formed corner
*pts++ = *pp + vector<C> (nd2 + g * l1);
} else {
// cut-off corner: produce two points connecting the edges
*pts++ = *pp + vector<C> (nd2 + g * std::min (l1max, l1));
*pts++ = *pp + vector<C> (nnd1 - gg * std::min (l2max, l2));
}
} else if (db::sprod (g, gg) < -db::epsilon) {
// reflecting segment
*pts++ = *pp + vector<C> (nd2 + g * wi);
*pts++ = *pp + vector<C> (nnd1 - gg * wi);
}
}
}
p = pp;
pp = ppp;
w = ww;
ww = www;
}
}
template <class C>
typename variable_width_path<C>::simple_polygon_type variable_width_path<C>::to_poly () const
{
std::vector<point<C> > pts;
pts.reserve (m_points.size () * 2); // minimum number of points required
C c = 0;
create_shifted_points (c, true, m_points.begin (), m_points.end (), m_widths.begin (), m_widths.end (), std::back_inserter (pts));
create_shifted_points (c, false, m_points.rbegin (), m_points.rend (), m_widths.rbegin (), m_widths.rend (), std::back_inserter (pts));
simple_polygon_type poly;
poly.assign_hull (pts.begin (), pts.end ());
return poly;
}
template class variable_width_path<Coord>;
template class variable_width_path<DCoord>;
}

View File

@ -0,0 +1,123 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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
*/
#ifndef HDR_dbVariableWidthPath
#define HDR_dbVariableWidthPath
#include "dbPoint.h"
#include "dbPolygon.h"
#include <vector>
#include <algorithm>
namespace db
{
/**
* @brief A class representing a variable width path
*
* A variable-width path is a path which has a non-constant width over it's
* length. A width can be assigned to certain points and will be interpolated
* for other points. Interpolation is performed along the length of the
* path's spine.
*
* The initial and final width must be specified. A point can be assigned two
* widths: an incoming and an outgoing width. If one width is specified, the
* incoming and outgoing widths are the same.
*/
template <class C>
class DB_PUBLIC variable_width_path
{
public:
typedef db::point<C> point_type;
typedef db::simple_polygon<C> simple_polygon_type;
typedef C width_type;
typedef std::pair<size_t, width_type> width_spec_type;
/**
* @brief Constructor from a set of points and width specifications
*
* I is an iterator delivering point_type objects.
*
* J is an iterator delivering width_spec_type objects.
*
* The width specification is a list of point index and width. The
* list must be sorted ascending by index. One index can be present
* twice. In this case, the first specification will be the incoming
* width, the second one will be the outgoing width.
*
* The first element of the width specification needs to be
* the initial width (0, w1) and the last element needs to be
* the final width (n-1, w2) where n is the number of points.
*/
template <class I, class J>
variable_width_path (I b, I e, J bs, J es)
: m_points (b, e), m_org_widths (bs, es)
{
init ();
}
/**
* @brief Constructor with a transformation
*/
template <class I, class J, class T>
variable_width_path (I b, I e, J bs, J es, const T &trans)
{
for (I i = b; i != e; ++i) {
m_points.push_back (trans.trans (*i));
}
for (J j = bs; j != es; ++j) {
m_org_widths.push_back (std::make_pair (j->first, trans.ctrans (j->second)));
}
init ();
}
/**
* @brief Turns the variable-width path into a polygon
*/
simple_polygon_type to_poly () const;
private:
void init ();
std::vector<point_type> m_points;
std::vector<std::pair<width_type, width_type> > m_widths;
std::vector<std::pair<size_t, C> > m_org_widths;
};
/**
* @brief The integer-type variable-width path
*/
typedef variable_width_path<db::Coord> VariableWidthPath;
/**
* @brief The float-type variable-width path
*/
typedef variable_width_path<db::DCoord> DVariableWidthPath;
}
#endif

View File

@ -290,3 +290,8 @@ TEST(29d)
run_test (_this, "t29.dxf.gz", "t29d_au.gds.gz", 0, 0.001, 1, 4, 1000, 0.001);
}
TEST(30)
{
run_test (_this, "t30.dxf.gz", "t30d_au.gds.gz", 0, 0.001, 1000, 4, 1000, 0.001);
}

View File

@ -0,0 +1,115 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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 "dbVariableWidthPath.h"
#include "tlUnitTest.h"
TEST(EmptyVP)
{
db::Point pts[] = { };
std::pair<size_t, db::Coord> widths[] = { };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "()");
}
TEST(VP1Point)
{
db::Point pts[] = { db::Point (0, 0) };
std::pair<size_t, db::Coord> widths[] = { };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "()");
}
TEST(VP2Point)
{
db::Point pts[] = { db::Point (0, 0), db::Point (200, 0) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (1), 50) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(0,-50;0,50;200,25;200,-25)");
}
TEST(VP3Point_Interpolate)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (200, 0) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (2), 50) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(0,-50;0,50;200,25;200,-25)");
}
TEST(VP3Point_Step)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (200, 0) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (1), 100), std::make_pair (size_t (1), 50), std::make_pair (size_t (2), 50) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(0,-50;0,50;100,50;100,25;200,25;200,-25;100,-25;100,-50)");
}
TEST(VP3Point_Step2)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (100, 0), db::Point (200, 0) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (1), 100), std::make_pair (size_t (2), 50), std::make_pair (size_t (3), 50) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(0,-50;0,50;100,50;100,25;200,25;200,-25;100,-25;100,-50)");
}
TEST(VP3Point90_Step)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (100, -100) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (1), 100), std::make_pair (size_t (1), 50), std::make_pair (size_t (2), 50) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(75,-100;75,0;100,-50;0,-50;0,50;100,50;125,0;125,-100)");
}
TEST(VP3Point90)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (100, -100) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (2), 0) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(100,-100;82,-29;0,-50;0,50;129,18)");
}
TEST(VP3Point90_ConstWidth)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (100, -100) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (2), 100) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(50,-100;50,-50;0,-50;0,50;150,50;150,-100)");
}
TEST(VP3Point135_ConstWidth)
{
db::Point pts[] = { db::Point (0, 0), db::Point (100, 0), db::Point (0, -100) };
std::pair<size_t, db::Coord> widths[] = { std::make_pair (size_t (0), 100), std::make_pair (size_t (2), 100) };
db::VariableWidthPath vp (&pts[0], &pts[sizeof (pts) / sizeof (pts[0])], &widths[0], &widths[sizeof (widths) / sizeof (widths[0])]);
EXPECT_EQ (vp.to_poly ().to_string (), "(35,-135;-35,-65;-21,-50;0,-50;0,50;200,50;206,35)");
}

View File

@ -58,6 +58,7 @@ SOURCES = \
dbTrans.cc \
dbVector.cc \
dbWriterTools.cc \
dbVariableWidthPath.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC