Merge pull request #706 from KLayout/spline-as-api

Generalized spline interpolation of DXF reader
This commit is contained in:
Matthias Köfferlein 2021-01-26 23:39:51 +01:00 committed by GitHub
commit bd41f7222d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 769 additions and 37 deletions

View File

@ -82,6 +82,7 @@ SOURCES = \
dbTilingProcessor.cc \
dbTrans.cc \
dbUserObject.cc \
dbUtils.cc \
dbVector.cc \
dbWriter.cc \
dbWriterTools.cc \
@ -122,6 +123,7 @@ SOURCES = \
gsiDeclDbText.cc \
gsiDeclDbTilingProcessor.cc \
gsiDeclDbTrans.cc \
gsiDeclDbUtils.cc \
gsiDeclDbVector.cc \
gsiDeclDbLayoutDiff.cc \
gsiDeclDbGlyphs.cc \
@ -288,6 +290,7 @@ HEADERS = \
dbTrans.h \
dbTypes.h \
dbUserObject.h \
dbUtils.h \
dbVector.h \
dbWriter.h \
dbWriterTools.h \

260
src/db/db/dbUtils.cc Normal file
View File

@ -0,0 +1,260 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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 "dbUtils.h"
#include "dbVector.h"
#include "tlException.h"
namespace db
{
/*
Rational B-Splines (NURBS) vs. non-rational B-Splines:
https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline
De Boor algorithm for NURBS
https://github.com/caadxyz/DeBoorAlgorithmNurbs
*/
static db::DPoint
b_spline_point (double x, const std::vector<std::pair<db::DPoint, double> > &control_points, int p, const std::vector<double> &t)
{
int k = (int) (std::lower_bound (t.begin (), t.end (), x + 1e-6) - t.begin ());
if (k <= p) {
return control_points.front ().first;
} else if (k > (int) control_points.size ()) {
return control_points.back ().first;
}
--k;
std::vector<db::DPoint> d;
std::vector<double> dw;
d.reserve(p + 1);
for (int j = 0; j <= p; ++j) {
double w = control_points[j + k - p].second;
d.push_back (control_points[j + k - p].first * w);
dw.push_back (w);
}
for (int r = 1; r <= p; ++r) {
for (int j = p; j >= r; --j) {
double alpha = (x - t[j + k - p]) / (t[j + 1 + k - r] - t[j + k - p]);
d[j] = d[j] * alpha + (d[j - 1] - d[j - 1] * alpha);
dw[j] = dw[j] * alpha + dw[j - 1] * (1.0 - alpha);
}
}
return d[p] * (1.0 / dw[p]);
}
/**
* @brief Inserts new points into a sequence of points to refine the curve
*
* The idea is bisection of the segments until the desired degree of accuracy has been reached.
*
* @param control_points The control points
* @param curve_points The list of curve points which is going to be extended
* @param current_curve_point The iterator pointing to the current curve point
* @param t_start The t (curve parameter) value of the current curve point
* @param dt The current t interval
* @param degree The degree of the spline
* @param knots The knots
* @param sin_da The relative accuracy value implied by the circle resolution
* @param accu The desired absolute accuracy value
*
* New points are going to be inserted after current_curve_point and current_curve_point + 1 to achieve the
* required curvature.
*/
static void
spline_interpolate (std::list<db::DPoint> &curve_points,
typename std::list<db::DPoint>::iterator current_curve_point,
double t_start,
double dt,
const std::vector<std::pair<db::DPoint, double> > &control_points,
int degree,
const std::vector<double> &knots,
double sin_da,
double accu)
{
std::list<db::DPoint>::iterator pm = current_curve_point;
++pm;
std::list<db::DPoint>::iterator pe = pm;
++pe;
db::DPoint s1 = b_spline_point (t_start + 0.5 * dt, control_points, degree, knots);
db::DPoint s2 = b_spline_point (t_start + 1.5 * dt, control_points, degree, knots);
db::DVector p1 (s1, *current_curve_point);
db::DVector p2 (*pm, s1);
double pl1 = p1.length(), pl2 = p2.length();
if (curve_points.size () < control_points.size () - degree - 1) {
curve_points.insert (pm, s1);
spline_interpolate (curve_points, current_curve_point, t_start, dt * 0.5, control_points, degree, knots, sin_da, accu);
curve_points.insert (pe, s2);
spline_interpolate (curve_points, pm, t_start + dt, dt * 0.5, control_points, degree, knots, sin_da, accu);
} else {
db::DVector q1 (s2, *pm);
db::DVector q2 (*pe, s2);
double ql1 = q1.length(), ql2 = q2.length();
db::DVector p (*pm, *current_curve_point);
db::DVector q (*pe, *pm);
double pl = p.length (), ql = q.length ();
if (fabs (db::vprod (p, q)) > pl * ql * sin_da ||
fabs (db::vprod (p1, p2)) > pl1 * pl2 * sin_da ||
fabs (db::vprod (q1, q2)) > ql1 * ql2 * sin_da) {
// angle between the segments is bigger than 2PI/n -> circle resolution is
// too small. Or: the angle between the new segments that we would introduce
// is also bigger (hence, the original segments may have a small angle but the
// curve "wiggles" when we increase the resolution)
if (fabs (db::vprod (p1, p)) > pl * accu) {
// In addition, the estimated accuracy is not good enough on the first segment: bisect this
// segment.
curve_points.insert (pm, s1);
spline_interpolate (curve_points, current_curve_point, t_start, dt * 0.5, control_points, degree, knots, sin_da, accu);
}
if (fabs (db::vprod (q1, q)) > ql * accu) {
// In addition, the estimated accuracy is not good enough on the first segment: bisect this
// segment.
curve_points.insert (pe, s2);
spline_interpolate (curve_points, pm, t_start + dt, dt * 0.5, control_points, degree, knots, sin_da, accu);
}
}
}
}
static
std::list<db::DPoint>
do_spline_interpolation (const std::vector<std::pair<db::DPoint, double> > &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
// TODO: this is quite inefficient
if (int (knots.size()) != int (control_points.size() + degree + 1)) {
throw tl::Exception (tl::to_string (tr ("Spline interpolation failed: mismatch between number of knots and points (#knots must be #points+degree+1)")));
}
if (int(knots.size ()) <= degree || control_points.empty () || degree <= 1) {
return std::list<db::DPoint> ();
}
double t0 = knots [degree];
double tn = knots [knots.size () - degree - 1];
std::list<db::DPoint> new_points;
new_points.push_back (control_points.front ().first);
double dt = 0.5 * (tn - t0);
for (double t = t0 + dt; t < tn + 1e-6; t += dt) {
db::DPoint s = b_spline_point (t, control_points, degree, knots);
new_points.push_back (s);
}
spline_interpolate (new_points, new_points.begin (), t0, dt, control_points, degree, knots, relative_accuracy, absolute_accuracy);
return new_points;
}
template <class P>
std::list<P>
spline_interpolation (const std::vector<std::pair<P, double> > &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
std::vector<std::pair<db::DPoint, double> > cp;
cp.reserve (control_points.size ());
for (size_t i = 0; i < control_points.size (); ++i) {
cp.push_back (std::make_pair (db::DPoint (control_points [i].first), control_points [i].second));
}
std::list<db::DPoint> result = do_spline_interpolation (cp, degree, knots, relative_accuracy, absolute_accuracy);
std::list<P> ret;
for (std::list<db::DPoint>::const_iterator i = result.begin (); i != result.end (); ++i) {
ret.push_back (P (*i));
}
return ret;
}
template <>
std::list<db::DPoint>
spline_interpolation (const std::vector<std::pair<db::DPoint, double> > &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
return do_spline_interpolation (control_points, degree, knots, relative_accuracy, absolute_accuracy);
}
template <class P>
std::list<P>
spline_interpolation (const std::vector<P> &control_points, const std::vector<double> &weights, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
std::vector<std::pair<P, double> > cp;
cp.reserve (control_points.size ());
for (size_t i = 0; i < control_points.size (); ++i) {
if (i >= weights.size ()) {
cp.push_back (std::make_pair (control_points [i], 1.0));
} else {
cp.push_back (std::make_pair (control_points [i], weights [i]));
}
}
return spline_interpolation (cp, degree, knots, relative_accuracy, absolute_accuracy);
}
template <class P>
std::list<P>
spline_interpolation (const std::vector<P> &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
std::vector<std::pair<P, double> > cp;
cp.reserve (control_points.size ());
for (size_t i = 0; i < control_points.size (); ++i) {
cp.push_back (std::make_pair (control_points [i], 1.0));
}
return spline_interpolation (cp, degree, knots, relative_accuracy, absolute_accuracy);
}
template std::list<db::Point> spline_interpolation (const std::vector<db::Point> &, int, const std::vector<double> &, double, double);
template std::list<db::Point> spline_interpolation (const std::vector<db::Point> &, const std::vector<double> &, int, const std::vector<double> &, double, double);
template std::list<db::Point> spline_interpolation (const std::vector<std::pair<db::Point, double> > &, int, const std::vector<double> &, double, double);
template std::list<db::DPoint> spline_interpolation (const std::vector<db::DPoint> &, int, const std::vector<double> &, double, double);
template std::list<db::DPoint> spline_interpolation (const std::vector<db::DPoint> &, const std::vector<double> &, int, const std::vector<double> &, double, double);
}

84
src/db/db/dbUtils.h Normal file
View File

@ -0,0 +1,84 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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_dbUtils
#define HDR_dbUtils
#include "dbCommon.h"
#include "dbPoint.h"
#include <list>
#include <vector>
namespace db
{
/**
* @brief Provides a Spline curve with adjustable accuracy
*
* This function computes the Spline curve for a given set of control points (point, weight), degree and knots.
*
* The knot vector needs to be padded and it's size must fulfill the condition:
*
* @code
* knots.size == control_points.size + degree + 1
* @/code
*
* The accuracy parameters allow tuing the resolution of the curve to target a specific approximation quality.
* "relative_accuracy" gives the accuracy relative to the local curvature radius, "absolute" accuracy gives the
* absolute accuracy. "accuracy" is the allowed deviation of polygon approximation from the ideal curve.
* The computed curve should meet at least one of the accurcay criteria. Setting both limits to a very small
* value will result in long run times and a large number of points returned.
*
* This function supports both rational splines (NURBS) and non-rational splines. The latter use weights of
* 1.0 for each point.
*
* The return value is a list of points forming a path which approximates the spline curve.
*/
template <class P>
DB_PUBLIC std::list<P>
spline_interpolation (const std::vector<std::pair<P, double> > &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy);
/**
* @brief A convencience version of the previous function
*
* This version takes separate vectors for point and weights for the control points.
*/
template <class P>
DB_PUBLIC std::list<P>
spline_interpolation (const std::vector<P> &control_points, const std::vector<double> &weights, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy);
/**
* @brief A convencience version of the previous function
*
* This version provides non-rational splines and does not take a weight vector.
*/
template <class P>
DB_PUBLIC std::list<P>
spline_interpolation (const std::vector<P> &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy);
}
#endif

102
src/db/db/gsiDeclDbUtils.cc Normal file
View File

@ -0,0 +1,102 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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 "gsiDecl.h"
#include "dbUtils.h"
namespace db
{
/**
* @brief A dummy class providing the namespace.
*/
struct UtilsDummy
{
static std::list<db::DPoint> spi1 (const std::vector<db::DPoint> &control_points, const std::vector<double> &weight, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
return db::spline_interpolation (control_points, weight, degree, knots, relative_accuracy, absolute_accuracy);
}
static std::list<db::Point> spi2 (const std::vector<db::Point> &control_points, const std::vector<double> &weight, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
return db::spline_interpolation (control_points, weight, degree, knots, relative_accuracy, absolute_accuracy);
}
static std::list<db::DPoint> spi3 (const std::vector<db::DPoint> &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
return db::spline_interpolation (control_points, degree, knots, relative_accuracy, absolute_accuracy);
}
static std::list<db::Point> spi4 (const std::vector<db::Point> &control_points, int degree, const std::vector<double> &knots, double relative_accuracy, double absolute_accuracy)
{
return db::spline_interpolation (control_points, degree, knots, relative_accuracy, absolute_accuracy);
}
};
}
namespace gsi
{
Class<db::UtilsDummy> decl_dbUtils ("db", "Utils",
gsi::method ("spline_interpolation", &db::UtilsDummy::spi1, gsi::arg ("control_points"), gsi::arg ("weights"), gsi::arg ("degree"), gsi::arg ("knots"), gsi::arg ("relative_accuracy"), gsi::arg ("absolute_accuracy"),
"@brief This function computes the Spline curve for a given set of control points (point, weight), degree and knots.\n"
"\n"
"The knot vector needs to be padded and it's size must fulfill the condition:\n"
"\n"
"@code\n"
" knots.size == control_points.size + degree + 1\n"
"@/code\n"
"\n"
"The accuracy parameters allow tuing the resolution of the curve to target a specific approximation quality.\n"
"\"relative_accuracy\" gives the accuracy relative to the local curvature radius, \"absolute\" accuracy gives the\n"
"absolute accuracy. \"accuracy\" is the allowed deviation of polygon approximation from the ideal curve.\n"
"The computed curve should meet at least one of the accurcay criteria. Setting both limits to a very small\n"
"value will result in long run times and a large number of points returned.\n"
"\n"
"This function supports both rational splines (NURBS) and non-rational splines. The latter use weights of\n"
"1.0 for each point.\n"
"\n"
"The return value is a list of points forming a path which approximates the spline curve.\n"
) +
gsi::method ("spline_interpolation", &db::UtilsDummy::spi2, gsi::arg ("control_points"), gsi::arg ("weights"), gsi::arg ("degree"), gsi::arg ("knots"), gsi::arg ("relative_accuracy"), gsi::arg ("absolute_accuracy"),
"@brief This function computes the Spline curve for a given set of control points (point, weight), degree and knots.\n"
"\n"
"This is the version for integer-coordinate points."
) +
gsi::method ("spline_interpolation", &db::UtilsDummy::spi3, gsi::arg ("control_points"), gsi::arg ("degree"), gsi::arg ("knots"), gsi::arg ("relative_accuracy"), gsi::arg ("absolute_accuracy"),
"@brief This function computes the Spline curve for a given set of control points (point, weight), degree and knots.\n"
"\n"
"This is the version for non-rational splines. It lacks the weight vector."
) +
gsi::method ("spline_interpolation", &db::UtilsDummy::spi4, gsi::arg ("control_points"), gsi::arg ("degree"), gsi::arg ("knots"), gsi::arg ("relative_accuracy"), gsi::arg ("absolute_accuracy"),
"@brief This function computes the Spline curve for a given set of control points (point, weight), degree and knots.\n"
"\n"
"This is the version for integer-coordinate points for non-rational splines."
),
"@brief This namespace provides a collection of utility functions\n"
"\n"
"This class has been introduced in version 0.27."
);
}

View File

@ -23,46 +23,10 @@
#include "tlUnitTest.h"
#include "tlString.h"
#include "tlStringEx.h"
#include "dbRegionUtils.h"
namespace tl
{
template <class Iter>
std::string to_string (Iter b, Iter e)
{
std::string res;
for (Iter i = b; i != e; ++i) {
if (i != b) {
res += ",";
}
res += tl::to_string (*i);
}
return res;
}
template <class T>
std::string to_string (const std::vector<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::list<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::set<T> &v)
{
return to_string (v.begin (), v.end ());
}
}
TEST(1_SimpleLShape)
{
std::set<db::EdgePair> ep;

View File

@ -0,0 +1,143 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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 "dbUtils.h"
#include "tlUnitTest.h"
#include "tlStringEx.h"
#include <cmath>
TEST(1)
{
std::list<db::DPoint> pts;
std::vector<std::pair<db::DPoint, double> > cp;
cp.push_back (std::make_pair (db::DPoint (-1, 0), 1));
cp.push_back (std::make_pair (db::DPoint (-1, 1), sqrt (0.5)));
cp.push_back (std::make_pair (db::DPoint (0, 1), 1));
std::vector<double> k;
k.push_back (0.0);
k.push_back (0.0);
k.push_back (0.0);
k.push_back (1.0);
k.push_back (1.0);
k.push_back (1.0);
pts = db::spline_interpolation (cp, 2, k, 0.01, 0.01);
EXPECT_EQ (tl::to_string (pts),
"-1,0,"
"-0.983305368417,0.181963052412,"
"-0.929788301062,0.368094709562,"
"-0.836995511219,0.547209753385,"
"-0.707106781187,0.707106781187,"
"-0.547209753385,0.836995511219,"
"-0.368094709562,0.929788301062,"
"-0.181963052412,0.983305368417,"
"0,1"
);
for (std::list<db::DPoint>::iterator i = pts.begin (); i != pts.end (); ++i) {
EXPECT_EQ (fabs (i->double_distance () - 1.0) < 1e-10, true);
}
pts = db::spline_interpolation (cp, 2, k, 0.001, 0.001);
EXPECT_EQ (pts.size (), size_t (33));
for (std::list<db::DPoint>::iterator i = pts.begin (); i != pts.end (); ++i) {
EXPECT_EQ (fabs (i->double_distance () - 1.0) < 1e-10, true);
}
}
TEST(2)
{
std::list<db::DPoint> pts;
std::vector<db::DPoint> cp;
cp.push_back (db::DPoint (-1, 0));
cp.push_back (db::DPoint (-1, 1));
cp.push_back (db::DPoint (0, 1));
std::vector<double> w;
w.push_back (1);
w.push_back (sqrt (0.5));
w.push_back (1);
std::vector<double> k;
k.push_back (0.0);
k.push_back (0.0);
k.push_back (0.0);
k.push_back (1.0);
k.push_back (1.0);
k.push_back (1.0);
pts = db::spline_interpolation (cp, w, 2, k, 0.01, 0.01);
EXPECT_EQ (tl::to_string (pts),
"-1,0,"
"-0.983305368417,0.181963052412,"
"-0.929788301062,0.368094709562,"
"-0.836995511219,0.547209753385,"
"-0.707106781187,0.707106781187,"
"-0.547209753385,0.836995511219,"
"-0.368094709562,0.929788301062,"
"-0.181963052412,0.983305368417,"
"0,1"
);
}
TEST(3)
{
std::list<db::DPoint> pts;
std::vector<db::DPoint> cp;
cp.push_back (db::DPoint (-1, 0));
cp.push_back (db::DPoint (-1, 1));
cp.push_back (db::DPoint (0, 1));
std::vector<double> k;
k.push_back (0.0);
k.push_back (0.0);
k.push_back (0.0);
k.push_back (1.0);
k.push_back (1.0);
k.push_back (1.0);
// non-rational spline
pts = db::spline_interpolation (cp, 2, k, 0.01, 0.01);
EXPECT_EQ (tl::to_string (pts),
"-1,0,"
"-0.984375,0.234375,"
"-0.9375,0.4375,"
"-0.859375,0.609375,"
"-0.75,0.75,"
"-0.609375,0.859375,"
"-0.4375,0.9375,"
"-0.234375,0.984375,"
"0,1"
);
}

View File

@ -9,6 +9,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
dbCompoundOperationTests.cc \
dbRegionUtilsTests.cc \
dbUtilsTests.cc \
dbWriterTools.cc \
dbLoadLayoutOptionsTests.cc \
dbSaveLayoutOptionsTests.cc \

View File

@ -132,6 +132,7 @@ RUBYTEST (dbTextsTest, "dbTextsTest.rb")
RUBYTEST (dbTilingProcessorTest, "dbTilingProcessorTest.rb")
RUBYTEST (dbTransTest, "dbTransTest.rb")
RUBYTEST (dbVectorTest, "dbVectorTest.rb")
RUBYTEST (dbUtilsTests, "dbUtilsTests.rb")
RUBYTEST (edtTest, "edtTest.rb")
RUBYTEST (extNetTracer, "extNetTracer.rb")
RUBYTEST (imgObject, "imgObject.rb")

95
src/tl/tl/tlStringEx.h Normal file
View File

@ -0,0 +1,95 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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_tlStringEx
#define HDR_tlStringEx
#include "tlString.h"
#include <set>
#include <map>
#include <vector>
#include <list>
#include <unordered_set>
#include <unordered_map>
namespace tl
{
template <class Iter>
std::string to_string (Iter b, Iter e)
{
std::string res;
for (Iter i = b; i != e; ++i) {
if (i != b) {
res += ",";
}
res += tl::to_string (*i);
}
return res;
}
template <class T1, class T2>
std::string to_string (const std::pair<T1, T2> &p)
{
return to_string (p.first) + "," + to_string (p.second);
}
template <class T>
std::string to_string (const std::vector<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::list<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::set<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T, class V>
std::string to_string (const std::map<T, V> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::unordered_set<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T, class V>
std::string to_string (const std::unordered_map<T, V> &v)
{
return to_string (v.begin (), v.end ());
}
}
#endif

79
testdata/ruby/dbUtilsTests.rb vendored Normal file
View File

@ -0,0 +1,79 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2021 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
if !$:.member?(File::dirname($0))
$:.push(File::dirname($0))
end
load("test_prologue.rb")
class DBUtils_TestClass < TestBase
def test_1
pts = [ RBA::DPoint::new(-1, 0), RBA::DPoint::new(-1, 1), RBA::DPoint::new(0, 1) ]
weights = [ 1, Math::sqrt(0.5), 1 ]
k = [ 0, 0, 0, 1, 1, 1 ]
pts = RBA::Utils::spline_interpolation(pts, weights, 2, k, 0.01, 0.01)
assert_equal(pts.collect(&:to_s).join(","), "-1,0,-0.983305368417,0.181963052412,-0.929788301062,0.368094709562,-0.836995511219,0.547209753385,-0.707106781187,0.707106781187,-0.547209753385,0.836995511219,-0.368094709562,0.929788301062,-0.181963052412,0.983305368417,0,1")
assert_equal(pts.collect(&:abs).collect { |d| "%.12g" % d }.join(","), "1,1,1,1,1,1,1,1,1")
end
def test_2
pts = [ RBA::Point::new(-1000, 0), RBA::Point::new(-1000, 1000), RBA::Point::new(0, 1000) ]
weights = [ 1, Math::sqrt(0.5), 1]
k = [ 0, 0, 0, 1, 1, 1 ]
pts = RBA::Utils::spline_interpolation(pts, weights, 2, k, 0.01, 10)
assert_equal(pts.collect(&:to_s).join(","), "-1000,0,-983,182,-930,368,-837,547,-707,707,-547,837,-368,930,-182,983,0,1000")
assert_equal(pts.collect(&:abs).collect { |d| "%.0f" % d }.join(","), "1000,1000,1000,1000,1000,1000,1000,1000,1000")
end
def test_3
pts = [ RBA::DPoint::new(-1, 0), RBA::DPoint::new(-1, 1), RBA::DPoint::new(0, 1) ]
k = [ 0, 0, 0, 1, 1, 1 ]
pts = RBA::Utils::spline_interpolation(pts, 2, k, 0.01, 0.01)
assert_equal(pts.collect(&:to_s).join(","), "-1,0,-0.984375,0.234375,-0.9375,0.4375,-0.859375,0.609375,-0.75,0.75,-0.609375,0.859375,-0.4375,0.9375,-0.234375,0.984375,0,1")
end
def test_4
pts = [ RBA::Point::new(-1000, 0), RBA::Point::new(-1000, 1000), RBA::Point::new(0, 1000) ]
k = [ 0, 0, 0, 1, 1, 1 ]
pts = RBA::Utils::spline_interpolation(pts, 2, k, 0.01, 10)
assert_equal(pts.collect(&:to_s).join(","), "-1000,0,-984,234,-938,438,-859,609,-750,750,-609,859,-438,938,-234,984,0,1000")
assert_equal(pts.collect(&:abs).collect { |d| "%.0f" % d }.join(","), "1000,1011,1035,1053,1061,1053,1035,1011,1000")
end
end
load("test_epilogue.rb")