|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TnzCore includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tmathutil.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcurves.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tbezier.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstrokedeformations.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstroke.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcurveutil.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg_wrap.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// tcg includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg/tcg_poly_ops.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#define INCLUDE_HPP
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg/tcg_polylineops.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg/tcg_cyclic.h"
|
|
Toshihiro Shimizu |
890ddd |
#undef INCLUDE_HPP
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tstrokeutil.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*********************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local namespace stuff
|
|
Toshihiro Shimizu |
890ddd |
//*********************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
3bfa54 |
typedef std::vector<tthickcubic *=""> TThickCubicArray;</tthickcubic>
|
|
Shinya Kitaoka |
3bfa54 |
typedef std::vector<tthickquadratic *=""> QuadStrokeChunkArray;</tthickquadratic>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int getControlPointIndex(const TStroke &stroke, double w) {
|
|
Shinya Kitaoka |
120a6e |
TThickPoint p = stroke.getControlPointAtParameter(w);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int i = 0;
|
|
Shinya Kitaoka |
120a6e |
int controlPointCount = stroke.getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (; i < controlPointCount; ++i)
|
|
Shinya Kitaoka |
120a6e |
if (stroke.getControlPoint(i) == p) return i;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return controlPointCount - 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double findMinimum(const TStrokeDeformation &def, const TStroke &stroke,
|
|
Shinya Kitaoka |
120a6e |
double x1, double x2, double xacc, double length = 0,
|
|
Shinya Kitaoka |
120a6e |
int max_iter = 100)
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Shinya Kitaoka |
120a6e |
int j;
|
|
Shinya Kitaoka |
120a6e |
double dx, f, fmid, xmid, rtb;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
f = def.getDelta(stroke, x1) - length;
|
|
Shinya Kitaoka |
120a6e |
fmid = def.getDelta(stroke, x2) - length;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (f == 0) return x1;
|
|
Shinya Kitaoka |
120a6e |
if (fmid == 0) return x2;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (f * fmid > 0.0) return -1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
rtb = f < 0.0 ? (dx = x2 - x1, x1) : (dx = x1 - x2, x2);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (j = 1; j <= max_iter; j++) {
|
|
Shinya Kitaoka |
120a6e |
fmid = def.getDelta(stroke, xmid = rtb + (dx *= 0.5)) - length;
|
|
Shinya Kitaoka |
120a6e |
if (fmid <= 0.0) rtb = xmid;
|
|
Shinya Kitaoka |
120a6e |
if (fabs(dx) < xacc || fmid == 0.0) return rtb;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return -2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/**
|
|
shun-iwasawa |
443318 |
* Rationale:
|
|
shun-iwasawa |
443318 |
* Suppose we want to model a segment (represented by a stroke) so that it
|
|
shun-iwasawa |
443318 |
* takes the shape of a parabola (the usual case offered by the modifier). We
|
|
shun-iwasawa |
443318 |
* assume that: (o) stroke points lie along the y=-100 axis; (o) the x's that
|
|
shun-iwasawa |
443318 |
* will correspond are x1=-10 and x2=+10 (obvious from the equation).
|
|
shun-iwasawa |
443318 |
*
|
|
shun-iwasawa |
443318 |
* The parabola may be represented on the left side by a quadratic with control
|
|
shun-iwasawa |
443318 |
* points: P0=(-10,-100), P1=(-5, 0), P2=( 0, 0). If we know the number of
|
|
shun-iwasawa |
443318 |
* linear strokes representing this parabola, we also know how many "samples"
|
|
shun-iwasawa |
443318 |
* are required for its linearization. This parameter can be used to
|
|
shun-iwasawa |
443318 |
* qualitatively determine the value with which to sample the stroke to be
|
|
shun-iwasawa |
443318 |
* tested; there will need to be as many points to move as there are samples in
|
|
shun-iwasawa |
443318 |
* the reference.
|
|
shun-iwasawa |
443318 |
*/
|
|
Shinya Kitaoka |
120a6e |
double computeIncrement(double strokeLength, double pixelSize) {
|
|
Shinya Kitaoka |
120a6e |
assert(pixelSize > 0 && "Pixel size is negative!!!");
|
|
Shinya Kitaoka |
120a6e |
assert(strokeLength > 0 && "Stroke Length size is negative!!!");
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
443318 |
// height of the parabola (goes downward)
|
|
Shinya Kitaoka |
120a6e |
double height = 100;
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
443318 |
// I suppose I'm doing at least a 100-pixel drag
|
|
Shinya Kitaoka |
120a6e |
assert(height >= 100.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double x = sqrt(height);
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
443318 |
// the point p1 will have to be at the intersection of the tangents to the two
|
|
shun-iwasawa |
443318 |
// extremes. The tangent of the point p2 and the x-axis, the other will have
|
|
shun-iwasawa |
443318 |
// versor given by the gradient at p0,
|
|
shun-iwasawa |
443318 |
// ie: grad(x,-2 x)
|
|
shun-iwasawa |
443318 |
// and if y = m x + q
|
|
Shinya Kitaoka |
120a6e |
// m =
|
|
Shinya Kitaoka |
120a6e |
double m = 2.0 * x;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double q = m * x - height;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double p1x = q / m;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double scale = strokeLength / (2.0 * x);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TScale scaleAffine(scale, scale);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TPointD p0 = scaleAffine * TPointD(-x, -height),
|
|
Shinya Kitaoka |
120a6e |
p1 = scaleAffine * TPointD(-p1x, 0.0),
|
|
Shinya Kitaoka |
120a6e |
p2 = scaleAffine * TPointD(0.0, 0.0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TQuadratic quadratic(p0, p1, p2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double step = computeStep(quadratic, pixelSize);
|
|
Toshihiro Shimizu |
890ddd |
|
|
shun-iwasawa |
443318 |
// just to add points even in the worst case.
|
|
Shinya Kitaoka |
120a6e |
if (step >= 1.0) step = 0.1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return step;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void detectEdges(const std::vector<tpointd> &pointArray,</tpointd>
|
|
Shinya Kitaoka |
120a6e |
std::vector<uint> &edgeIndexArray) {</uint>
|
|
shun-iwasawa |
443318 |
// ASSUMPTION: sharpPointArray does not contain adjacent coincident points
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int size = pointArray.size();
|
|
shun-iwasawa |
443318 |
// I check that there are more than three elements
|
|
Shinya Kitaoka |
120a6e |
if (size < 3) return;
|
|
shun-iwasawa |
443318 |
// runs pointArray and for each of its points tries to inscribe triangles
|
|
shun-iwasawa |
443318 |
// (using left and right points) considering potential corners those with
|
|
shun-iwasawa |
443318 |
// sides l such that dMin <= l <= dMax (actually at the first time that l >
|
|
shun-iwasawa |
443318 |
// dMax: breack) and with angular aperture alpha <= alphaMax.
|
|
shun-iwasawa |
443318 |
// Then it looks for local maxes among the potential corners in a window of
|
|
shun-iwasawa |
443318 |
// semiamplitude dMax(actually at the first time dMax : breack is exceeded)
|
|
shun-iwasawa |
443318 |
// default values: dMin = 7; dMax = dMin + 2; alphaMax = 2.6 (150 degrees)
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const double dMin = 4;
|
|
Shinya Kitaoka |
120a6e |
const double dMax = dMin + 3;
|
|
shun-iwasawa |
443318 |
const double alphaMax = 2.4; // ( 137.5 degrees)
|
|
Shinya Kitaoka |
120a6e |
const double dMin2 = dMin * dMin;
|
|
Shinya Kitaoka |
120a6e |
const double dMax2 = dMax * dMax;
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> sharpnessArray;</double>
|
|
shun-iwasawa |
443318 |
sharpnessArray.push_back(M_PI); // the first point is a corner
|
|
Shinya Kitaoka |
120a6e |
int nodeCount;
|
|
Shinya Kitaoka |
120a6e |
for (nodeCount = 1; nodeCount < size - 1;
|
|
shun-iwasawa |
443318 |
++nodeCount) { // scrolls the sharpPointArray excluding the extremes
|
|
Shinya Kitaoka |
120a6e |
sharpnessArray.push_back(0);
|
|
Shinya Kitaoka |
120a6e |
TPointD point(pointArray[nodeCount]);
|
|
Shinya Kitaoka |
120a6e |
int leftCount;
|
|
Shinya Kitaoka |
120a6e |
for (leftCount = nodeCount - 1; leftCount >= 0;
|
|
shun-iwasawa |
443318 |
--leftCount) { // Calculates the "left" sides of the inscribed
|
|
shun-iwasawa |
443318 |
// triangles...
|
|
Shinya Kitaoka |
120a6e |
TPointD left = pointArray[leftCount];
|
|
Shinya Kitaoka |
120a6e |
double dLeft2 = norm2(left - point);
|
|
Shinya Kitaoka |
120a6e |
if (dLeft2 < dMin2)
|
|
Shinya Kitaoka |
120a6e |
continue;
|
|
Shinya Kitaoka |
120a6e |
else if (dLeft2 > dMax2)
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
int rightCount;
|
|
Shinya Kitaoka |
120a6e |
for (rightCount = nodeCount + 1; rightCount < size;
|
|
shun-iwasawa |
443318 |
++rightCount) { // Calculates the "right" sides of the inscribed
|
|
shun-iwasawa |
443318 |
// triangles...
|
|
Shinya Kitaoka |
120a6e |
TPointD right = pointArray[rightCount];
|
|
Shinya Kitaoka |
120a6e |
double dRight2 = norm2(right - point);
|
|
Shinya Kitaoka |
120a6e |
if (dRight2 < dMin2)
|
|
Shinya Kitaoka |
120a6e |
continue;
|
|
Shinya Kitaoka |
120a6e |
else if (dMax2 < dRight2)
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
443318 |
// Calculates the "center" sides of the inscribed triangles
|
|
Shinya Kitaoka |
120a6e |
double dCenter2 = norm2(left - right);
|
|
Shinya Kitaoka |
120a6e |
assert(dLeft2 != 0.0 && dRight2 != 0.0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double cs =
|
|
Shinya Kitaoka |
120a6e |
(dLeft2 + dRight2 - dCenter2) / (2 * sqrt(dLeft2 * dRight2));
|
|
Shinya Kitaoka |
120a6e |
double alpha = acos(cs);
|
|
Shinya Kitaoka |
120a6e |
if (alpha > alphaMax) continue;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double sharpness = M_PI - alpha;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (sharpnessArray[nodeCount] < sharpness)
|
|
Shinya Kitaoka |
120a6e |
sharpnessArray[nodeCount] = sharpness;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
443318 |
edgeIndexArray.push_back(0); // the first point is a corner
|
|
Shinya Kitaoka |
120a6e |
|
|
shun-iwasawa |
443318 |
// I find local maxima by excluding extremes
|
|
Shinya Kitaoka |
120a6e |
for (nodeCount = 1; nodeCount < size - 1;
|
|
shun-iwasawa |
443318 |
++nodeCount) { // scroll through the list excluding the extremes
|
|
Shinya Kitaoka |
120a6e |
bool isCorner = true;
|
|
Shinya Kitaoka |
120a6e |
TPointD point(pointArray[nodeCount]);
|
|
Shinya Kitaoka |
120a6e |
int leftCount;
|
|
Shinya Kitaoka |
120a6e |
for (leftCount = nodeCount - 1; leftCount >= 0;
|
|
shun-iwasawa |
443318 |
--leftCount) { // scrolls down the list of sharpPoints to the left of
|
|
shun-iwasawa |
443318 |
// node...
|
|
Shinya Kitaoka |
120a6e |
TPointD left = pointArray[leftCount];
|
|
Shinya Kitaoka |
120a6e |
double dLeft2 = norm2(left - point);
|
|
Shinya Kitaoka |
120a6e |
if (dLeft2 > dMax2) break;
|
|
Shinya Kitaoka |
120a6e |
if (sharpnessArray[leftCount] > sharpnessArray[nodeCount]) {
|
|
Shinya Kitaoka |
120a6e |
isCorner = false;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (isCorner) continue;
|
|
Shinya Kitaoka |
120a6e |
int rightCount;
|
|
Shinya Kitaoka |
120a6e |
for (rightCount = nodeCount + 1; rightCount < size;
|
|
shun-iwasawa |
443318 |
++rightCount) { // scrolls the list of sharpPoints to the right of
|
|
shun-iwasawa |
443318 |
// node..
|
|
Shinya Kitaoka |
120a6e |
TPointD right = pointArray[rightCount];
|
|
Shinya Kitaoka |
120a6e |
double dRight2 = norm2(right - point);
|
|
Shinya Kitaoka |
120a6e |
if (dRight2 > dMax2) break;
|
|
Shinya Kitaoka |
120a6e |
if (sharpnessArray[rightCount] > sharpnessArray[nodeCount]) {
|
|
Shinya Kitaoka |
120a6e |
isCorner = false;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (isCorner) edgeIndexArray.push_back(nodeCount);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
shun-iwasawa |
443318 |
edgeIndexArray.push_back(size - 1); // the last point is a corner
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
120a6e |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// API functions
|
|
Toshihiro Shimizu |
890ddd |
//*******************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool increaseControlPoints(TStroke &stroke, const TStrokeDeformation &deformer,
|
|
Shinya Kitaoka |
120a6e |
double pixelSize) {
|
|
Shinya Kitaoka |
120a6e |
if (isAlmostZero(stroke.getLength())) {
|
|
Shinya Kitaoka |
120a6e |
return norm2(deformer.getDisplacement(stroke, 0.0)) > 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// step 1:
|
|
Shinya Kitaoka |
120a6e |
// It's possible to have control point at not null potential
|
|
Shinya Kitaoka |
120a6e |
// but with delta equal 0 (equipotential control point)
|
|
Shinya Kitaoka |
120a6e |
bool notVoidPotential = false;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < stroke.getControlPointCount(); ++i) {
|
|
Shinya Kitaoka |
120a6e |
double par = stroke.getParameterAtControlPoint(i);
|
|
Shinya Kitaoka |
120a6e |
if (deformer.getDisplacement(stroke, par) != TThickPoint()) {
|
|
Shinya Kitaoka |
120a6e |
notVoidPotential = true;
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// step 2:
|
|
Shinya Kitaoka |
120a6e |
// increase control point checking delta of deformer
|
|
Shinya Kitaoka |
120a6e |
double maxDifference =
|
|
shun-iwasawa |
443318 |
deformer.getMaxDiff(); // above this delta value, points are added
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int strokeControlPoint = stroke.getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// pixelSize = sq( pixelSize );
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (pixelSize < TConsts::epsilon) pixelSize = TConsts::epsilon;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double length = stroke.getLength(),
|
|
Shinya Kitaoka |
120a6e |
// set the step function of length
|
|
Shinya Kitaoka |
120a6e |
// step = length > 1.0 ? pixelSize * 15.0/ length : length,
|
|
Shinya Kitaoka |
120a6e |
// step = 0.01,
|
|
Shinya Kitaoka |
120a6e |
w = 0.0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double step = computeIncrement(length, pixelSize);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double x1, x2, d1, d2, diff, offset, minimum, incr;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
incr = step;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
while (w + incr < 1.0) {
|
|
Shinya Kitaoka |
120a6e |
d1 = deformer.getDelta(stroke, w);
|
|
Shinya Kitaoka |
120a6e |
d2 = deformer.getDelta(stroke, w + incr);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
diff = d2 - d1;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (fabs(diff) >= maxDifference) // if there is a step of potential
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
if (tsign(diff) > 0) {
|
|
Shinya Kitaoka |
120a6e |
x1 = w;
|
|
Shinya Kitaoka |
120a6e |
x2 = w + incr;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
x1 = w + incr;
|
|
Shinya Kitaoka |
120a6e |
x2 = w;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
offset = (d1 + d2) * 0.5;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// find the position of step
|
|
Shinya Kitaoka |
120a6e |
minimum = findMinimum(
|
|
Shinya Kitaoka |
120a6e |
deformer, stroke, x1, x2, TConsts::epsilon, offset,
|
|
shun-iwasawa |
443318 |
20); // A new control point should be put between x1 and x2. where?
|
|
shun-iwasawa |
443318 |
// this function finds the point at which the maxdifference value is
|
|
shun-iwasawa |
443318 |
// exceeded
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// if minimum is not found or is equal to previous value
|
|
luz paz |
6454c4 |
// use an heuristic...
|
|
Shinya Kitaoka |
120a6e |
if (minimum < 0 || w == minimum) {
|
|
Shinya Kitaoka |
120a6e |
minimum = w + incr * 0.5;
|
|
Shinya Kitaoka |
120a6e |
w += step;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
//... else insert a control point in minimum
|
|
shun-iwasawa |
443318 |
w = minimum; // scanning resumes from the new point, in this way it
|
|
shun-iwasawa |
443318 |
// thickens ...
|
|
shun-iwasawa |
443318 |
|
|
Shinya Kitaoka |
120a6e |
stroke.insertControlPoints(minimum);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// update of step
|
|
Shinya Kitaoka |
120a6e |
incr = step;
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
incr += step;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// return true if control point are increased
|
|
Shinya Kitaoka |
120a6e |
return (stroke.getControlPointCount() > strokeControlPoint) ||
|
|
Shinya Kitaoka |
120a6e |
notVoidPotential;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void modifyControlPoints(TStroke &stroke, const TStrokeDeformation &deformer) {
|
|
Shinya Kitaoka |
120a6e |
int cpCount = stroke.getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TThickPoint newP;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < cpCount; ++i) {
|
|
Shinya Kitaoka |
120a6e |
newP = stroke.getControlPoint(i) +
|
|
Shinya Kitaoka |
120a6e |
deformer.getDisplacementForControlPoint(stroke, i);
|
|
Shinya Kitaoka |
120a6e |
if (isAlmostZero(newP.thick, 0.005)) newP.thick = 0;
|
|
Shinya Kitaoka |
120a6e |
stroke.setControlPoint(i, newP);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void modifyControlPoints(TStroke &stroke, const TStrokeDeformation &deformer,
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> &controlPointLen) {</double>
|
|
Shinya Kitaoka |
120a6e |
UINT cpCount = stroke.getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TThickPoint newP;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef _DEBUG
|
|
Shinya Kitaoka |
120a6e |
UINT debugVariable = controlPointLen.size();
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Shinya Kitaoka |
120a6e |
assert(controlPointLen.size() == cpCount);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (UINT i = 0; i < cpCount; ++i) {
|
|
Shinya Kitaoka |
120a6e |
newP =
|
|
Shinya Kitaoka |
120a6e |
stroke.getControlPoint(i) +
|
|
Shinya Kitaoka |
120a6e |
deformer.getDisplacementForControlPointLen(stroke, controlPointLen[i]);
|
|
Shinya Kitaoka |
120a6e |
if (isAlmostZero(newP.thick, 0.005)) newP.thick = 0;
|
|
Shinya Kitaoka |
120a6e |
stroke.setControlPoint(i, newP);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void modifyThickness(TStroke &stroke, const TStrokeDeformation &deformer,
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> &controlPointLen, bool exponentially) {</double>
|
|
Shinya Kitaoka |
120a6e |
UINT cpCount = stroke.getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
assert(controlPointLen.size() == cpCount);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double disp;
|
|
Shinya Kitaoka |
120a6e |
double thick;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (UINT i = 0; i < cpCount; ++i) {
|
|
Shinya Kitaoka |
120a6e |
disp =
|
|
Shinya Kitaoka |
120a6e |
(deformer.getDisplacementForControlPointLen(stroke, controlPointLen[i]))
|
|
Shinya Kitaoka |
120a6e |
.thick;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
thick = stroke.getControlPoint(i).thick;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// The additive version is straightforward.
|
|
Shinya Kitaoka |
120a6e |
// The exponential version is devised to keep derivative 1 at disp == 0;
|
|
Shinya Kitaoka |
120a6e |
// it is typically used when the thickness decreases.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
thick = (exponentially && thick >= 0.005) ? thick * exp(disp / thick)
|
|
Shinya Kitaoka |
120a6e |
: thick + disp;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (thick < 0.005) thick = 0.0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stroke.setControlPoint(i, TThickPoint(stroke.getControlPoint(i), thick));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void transform_thickness(TStroke &stroke, const double poly[], int deg) {
|
|
Shinya Kitaoka |
120a6e |
int cp, cpCount = stroke.getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
for (cp = 0; cp != cpCount; ++cp) {
|
|
Shinya Kitaoka |
120a6e |
TThickPoint cpPoint = stroke.getControlPoint(cp);
|
|
Shinya Kitaoka |
120a6e |
cpPoint.thick =
|
|
Shinya Kitaoka |
120a6e |
std::max(tcg::poly_ops::evaluate(poly, deg, cpPoint.thick), 0.0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
stroke.setControlPoint(cp, cpPoint);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TStroke *Toonz::merge(const std::vector<tstroke *=""> &strokes) {</tstroke>
|
|
Shinya Kitaoka |
120a6e |
if (strokes.empty()) return 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::vector<tthickpoint> new_stroke_cp;</tthickpoint>
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int size_stroke_array = strokes.size();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int size_cp;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const TStroke *ref;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TThickPoint last = TConsts::natp;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (!strokes[0]) return 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
new_stroke_cp.push_back(strokes[0]->getControlPoint(0));
|
|
Shinya Kitaoka |
120a6e |
int i, j;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < size_stroke_array; i++) {
|
|
Shinya Kitaoka |
120a6e |
ref = strokes[i];
|
|
Shinya Kitaoka |
120a6e |
if (!ref) return 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
size_cp = ref->getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
for (j = 0; j < size_cp - 1; j++) {
|
|
Shinya Kitaoka |
120a6e |
const TThickPoint &pnt = ref->getControlPoint(j);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (last != TConsts::natp && j == 0) {
|
|
Shinya Kitaoka |
120a6e |
// new_stroke_cp.push_back( (last+pnt)*0.5 );
|
|
Shinya Kitaoka |
120a6e |
new_stroke_cp.push_back(last);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (j > 0) new_stroke_cp.push_back(pnt);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
// last point needs to be merged
|
|
Shinya Kitaoka |
120a6e |
last = ref->getControlPoint(size_cp - 1);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
new_stroke_cp.push_back(ref->getControlPoint(size_cp - 1));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TStroke *out = new TStroke(new_stroke_cp);
|
|
Shinya Kitaoka |
120a6e |
return out;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
namespace {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class CpsReader {
|
|
Shinya Kitaoka |
120a6e |
std::vector<tthickpoint> &m_cps;</tthickpoint>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
typedef TPointD value_type;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
CpsReader(std::vector<tthickpoint> &cps) : m_cps(cps) {}</tthickpoint>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void openContainer(const TPointD &point) { addElement(point); }
|
|
Shinya Kitaoka |
120a6e |
void addElement(const TPointD &point) {
|
|
Shinya Kitaoka |
120a6e |
m_cps.push_back(TThickPoint(point, 0.0));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
void closeContainer() {}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//===========================================================
|
|
Toshihiro Shimizu |
890ddd |
// Triplet to Quadratics
|
|
Toshihiro Shimizu |
890ddd |
//===========================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
template <typename iter_type=""></typename>
|
|
Shinya Kitaoka |
120a6e |
double buildLength(const iter_type &begin, const iter_type &end, double tol) {
|
|
Shinya Kitaoka |
120a6e |
// Build direction
|
|
Shinya Kitaoka |
120a6e |
iter_type it = begin, jt;
|
|
Shinya Kitaoka |
120a6e |
++it;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
const TPointD &a = *begin, &b = *it;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPointD dir(normalize(b - a)), segDir;
|
|
Shinya Kitaoka |
120a6e |
double dist;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (jt = it, ++it; it != end; jt = it, ++it) {
|
|
Shinya Kitaoka |
120a6e |
segDir = *it - *jt;
|
|
Shinya Kitaoka |
120a6e |
if (dir * segDir < 0) break;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
dist = tcg::point_ops::lineSignedDist(*it, a, dir);
|
|
Shinya Kitaoka |
120a6e |
if (fabs(dist) > tol) {
|
|
Shinya Kitaoka |
120a6e |
double s, t;
|
|
Shinya Kitaoka |
120a6e |
if (dist > 0) {
|
|
Shinya Kitaoka |
120a6e |
tcg::point_ops::intersectionCoords(
|
|
Shinya Kitaoka |
120a6e |
*jt, segDir, a + tol * tcg::point_ops::ortLeft(dir), dir, s, t);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
tcg::point_ops::intersectionCoords(
|
|
Shinya Kitaoka |
120a6e |
*jt, segDir, a + tol * tcg::point_ops::ortRight(dir), dir, s, t);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
s = tcrop(s, 0.0, 1.0);
|
|
Shinya Kitaoka |
120a6e |
return (*jt + s * segDir - a) * dir;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return (*jt - a) * dir;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Shinya Kitaoka |
120a6e |
Converts the specified points triplet into a sequence of quadratics' CPs
|
|
Shinya Kitaoka |
120a6e |
(point
|
|
Toshihiro Shimizu |
890ddd |
a is not included, whereas c is).
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Conversion takes 4 parameters:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
- Adherence: How much quadratics bend toward corners
|
|
Toshihiro Shimizu |
890ddd |
- Angle: Inner product of corner's edges - full corners threshold
|
|
Toshihiro Shimizu |
890ddd |
- Relative: Curvature radius/edge length - full corners threshold
|
|
Toshihiro Shimizu |
890ddd |
- RelativeDist: Tolerance about edge length build-ups
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
See below for extended explanation.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class TripletsConverter {
|
|
Shinya Kitaoka |
120a6e |
typedef std::vector<tpointd>::const_iterator iter_type;</tpointd>
|
|
Shinya Kitaoka |
120a6e |
typedef std::reverse_iterator<iter_type> riter_type;</iter_type>
|
|
Shinya Kitaoka |
120a6e |
typedef tcg::cyclic_iterator<iter_type> cyclic_iter_type;</iter_type>
|
|
Shinya Kitaoka |
120a6e |
typedef std::reverse_iterator<cyclic_iter_type> rcyclic_iter_type;</cyclic_iter_type>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool m_circular;
|
|
Shinya Kitaoka |
120a6e |
iter_type m_first, m_end, m_last;
|
|
Shinya Kitaoka |
120a6e |
double m_adherenceTol, m_angleTol, m_relativeTol, m_relativeDistTol;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
TripletsConverter(const iter_type &begin, const iter_type &end,
|
|
Shinya Kitaoka |
120a6e |
double adherenceTol, double angleTol, double relativeTol,
|
|
Shinya Kitaoka |
120a6e |
double relativeDistTol)
|
|
Shinya Kitaoka |
120a6e |
: m_circular(*begin == *(end - 1))
|
|
Shinya Kitaoka |
120a6e |
, m_first(m_circular ? begin + 1 : begin)
|
|
Shinya Kitaoka |
120a6e |
, m_end(end)
|
|
Shinya Kitaoka |
120a6e |
, m_adherenceTol(adherenceTol)
|
|
Shinya Kitaoka |
120a6e |
, m_angleTol(angleTol)
|
|
Shinya Kitaoka |
120a6e |
, m_relativeTol(relativeTol)
|
|
Shinya Kitaoka |
120a6e |
, m_relativeDistTol(relativeDistTol) {}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Using bisector to convert a triplet
|
|
Shinya Kitaoka |
120a6e |
void operator()(const TPointD &a, const iter_type &bt, const TPointD &c,
|
|
Shinya Kitaoka |
120a6e |
tcg::sequential_reader<std::vector<tpointd>> &output) {</std::vector<tpointd>
|
|
Shinya Kitaoka |
120a6e |
const TPointD &b = *bt;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double prod =
|
|
Shinya Kitaoka |
120a6e |
tcg::point_ops::direction(b, a) * tcg::point_ops::direction(b, c);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (prod > m_angleTol) {
|
|
Shinya Kitaoka |
120a6e |
// Full corner
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (a + b));
|
|
Shinya Kitaoka |
120a6e |
output.addElement(b);
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (b + c));
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Build the angle bisector
|
|
Shinya Kitaoka |
120a6e |
TPointD a_b(a - b);
|
|
Shinya Kitaoka |
120a6e |
TPointD c_b(c - b);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double norm_a_b = norm(a_b);
|
|
Shinya Kitaoka |
120a6e |
double norm_c_b = norm(c_b);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
a_b = a_b * (1.0 / norm_a_b);
|
|
Shinya Kitaoka |
120a6e |
c_b = c_b * (1.0 / norm_c_b);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPointD v(tcg::point_ops::normalized(a_b + c_b));
|
|
Shinya Kitaoka |
120a6e |
double cos_v_dir = fabs(a_b * v);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double t1 = tcrop(m_adherenceTol / (cos_v_dir * norm_a_b), 0.0, 0.5);
|
|
Shinya Kitaoka |
120a6e |
double t2 = tcrop(m_adherenceTol / (cos_v_dir * norm_c_b), 0.0, 0.5);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (t1 == 0.5 && t2 == 0.5) {
|
|
Shinya Kitaoka |
120a6e |
// Direct conversion
|
|
Shinya Kitaoka |
120a6e |
output.addElement(b);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Build the quadratic split
|
|
Shinya Kitaoka |
120a6e |
TPointD d(b + t1 * (a - b)), f(b + t2 * (c - b)), e(0.5 * (d + f));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build curvature radiuses at the corner
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// NOTE: Both speed and acceleration would hold 2.0 as multiplier, which
|
|
Shinya Kitaoka |
120a6e |
// is calculated implicitly.
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TPointD speed(f - d);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double num = norm(speed);
|
|
Shinya Kitaoka |
120a6e |
if (num <= TConsts::epsilon) {
|
|
Shinya Kitaoka |
120a6e |
// Curvature radius is 0 - full corner
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (a + b));
|
|
Shinya Kitaoka |
120a6e |
output.addElement(b);
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (b + c));
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
num = 2.0 * num * num *
|
|
Shinya Kitaoka |
120a6e |
num; // would be * 8 = 2^3, divided by the 4 below
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double den1 =
|
|
Shinya Kitaoka |
120a6e |
fabs(cross(speed, a - d)); // * 4, from both args of the cross
|
|
Shinya Kitaoka |
120a6e |
double den2 = fabs(cross(speed, c - f));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double radius1 = (den1 == 0.0) ? 0.0 : num / den1;
|
|
Shinya Kitaoka |
120a6e |
double radius2 = (den1 == 0.0) ? 0.0 : num / den2;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Build edges length
|
|
Shinya Kitaoka |
120a6e |
double length1, length2;
|
|
Shinya Kitaoka |
120a6e |
if (m_circular) {
|
|
Shinya Kitaoka |
120a6e |
cyclic_iter_type it(bt, m_first, m_end, 0);
|
|
Shinya Kitaoka |
120a6e |
cyclic_iter_type it1(bt, m_first, m_end, 1);
|
|
Shinya Kitaoka |
120a6e |
cyclic_iter_type it_1(bt, m_first, m_end, -1);
|
|
Shinya Kitaoka |
120a6e |
rcyclic_iter_type rit(it + 1), rit1(it_1 + 1);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
length1 = buildLength(rit, rit1, 0.25);
|
|
Shinya Kitaoka |
120a6e |
length2 = buildLength(it, it1, 0.25);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
riter_type rit(bt + 1), rend(m_first);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
length1 = buildLength(rit, rend, m_relativeDistTol);
|
|
Shinya Kitaoka |
120a6e |
length2 = buildLength(bt, m_end, m_relativeDistTol);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Test curvature radiuses against edge length
|
|
Shinya Kitaoka |
120a6e |
if (radius1 / length1 < m_relativeTol && // both must hold
|
|
Shinya Kitaoka |
120a6e |
radius2 / length2 < m_relativeTol) {
|
|
Shinya Kitaoka |
120a6e |
// Full corner
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (a + b));
|
|
Shinya Kitaoka |
120a6e |
output.addElement(b);
|
|
Shinya Kitaoka |
120a6e |
output.addElement(0.5 * (b + c));
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Quadratic split
|
|
Shinya Kitaoka |
120a6e |
output.addElement(d);
|
|
Shinya Kitaoka |
120a6e |
output.addElement(e);
|
|
Shinya Kitaoka |
120a6e |
output.addElement(f);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
output.addElement(c);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void polylineToQuadratics(const std::vector<tpointd> &polyline,</tpointd>
|
|
Shinya Kitaoka |
120a6e |
std::vector<tthickpoint> &cps, double adherenceTol,</tthickpoint>
|
|
Shinya Kitaoka |
120a6e |
double angleTol, double relativeTol,
|
|
Shinya Kitaoka |
120a6e |
double relativeDistTol, double mergeTol) {
|
|
Shinya Kitaoka |
120a6e |
CpsReader cpsReader(cps);
|
|
Shinya Kitaoka |
120a6e |
TripletsConverter op(polyline.begin(), polyline.end(), adherenceTol, angleTol,
|
|
Shinya Kitaoka |
120a6e |
relativeTol, relativeDistTol);
|
|
Shinya Kitaoka |
120a6e |
tcg::polyline_ops::toQuadratics(polyline.begin(), polyline.end(), cpsReader,
|
|
Shinya Kitaoka |
120a6e |
op, mergeTol);
|
|
Toshihiro Shimizu |
890ddd |
}
|