mirror of https://github.com/KLayout/klayout.git
Merge pull request #706 from KLayout/spline-as-api
Generalized spline interpolation of DXF reader
This commit is contained in:
commit
bd41f7222d
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -9,6 +9,7 @@ include($$PWD/../../lib_ut.pri)
|
|||
SOURCES = \
|
||||
dbCompoundOperationTests.cc \
|
||||
dbRegionUtilsTests.cc \
|
||||
dbUtilsTests.cc \
|
||||
dbWriterTools.cc \
|
||||
dbLoadLayoutOptionsTests.cc \
|
||||
dbSaveLayoutOptionsTests.cc \
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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")
|
||||
Loading…
Reference in New Issue