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
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef vector<tthickcubic *=""> TThickCubicArray;</tthickcubic>
Toshihiro Shimizu 890ddd
typedef vector<tthickquadratic *=""> QuadStrokeChunkArray;</tthickquadratic>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int getControlPointIndex(const TStroke &stroke,
Toshihiro Shimizu 890ddd
						 double w)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TThickPoint p = stroke.getControlPointAtParameter(w);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i = 0;
Toshihiro Shimizu 890ddd
	int controlPointCount = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; i < controlPointCount; ++i)
Toshihiro Shimizu 890ddd
		if (stroke.getControlPoint(i) == p)
Toshihiro Shimizu 890ddd
			return i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return controlPointCount - 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double findMinimum(const TStrokeDeformation &def,
Toshihiro Shimizu 890ddd
				   const TStroke &stroke,
Toshihiro Shimizu 890ddd
				   double x1,
Toshihiro Shimizu 890ddd
				   double x2,
Toshihiro Shimizu 890ddd
				   double xacc,
Toshihiro Shimizu 890ddd
				   double length = 0,
Toshihiro Shimizu 890ddd
				   int max_iter = 100)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int j;
Toshihiro Shimizu 890ddd
	double dx, f, fmid, xmid, rtb;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	f = def.getDelta(stroke, x1) - length;
Toshihiro Shimizu 890ddd
	fmid = def.getDelta(stroke, x2) - length;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f == 0)
Toshihiro Shimizu 890ddd
		return x1;
Toshihiro Shimizu 890ddd
	if (fmid == 0)
Toshihiro Shimizu 890ddd
		return x2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f * fmid > 0.0)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rtb = f < 0.0 ? (dx = x2 - x1, x1) : (dx = x1 - x2, x2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (j = 1; j <= max_iter; j++) {
Toshihiro Shimizu 890ddd
		fmid = def.getDelta(stroke, xmid = rtb + (dx *= 0.5)) - length;
Toshihiro Shimizu 890ddd
		if (fmid <= 0.0)
Toshihiro Shimizu 890ddd
			rtb = xmid;
Toshihiro Shimizu 890ddd
		if (fabs(dx) < xacc || fmid == 0.0)
Toshihiro Shimizu 890ddd
			return rtb;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return -2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/**
Toshihiro Shimizu 890ddd
  * Rationale:
Toshihiro Shimizu 890ddd
  *  Supponiamo di voler modellare un segmento (rappresentato da una stroke)
Toshihiro Shimizu 890ddd
  *  in modo che assuma la forma di una parabola (caso abituale offerto dal modificatore).
Toshihiro Shimizu 890ddd
  *  Poniamo il che:
Toshihiro Shimizu 890ddd
  *   (o) i punti della stroke si trovino lungo l'asse y=-100;
Toshihiro Shimizu 890ddd
  *   (o) le x che corrisponderanno siano x1=-10 e x2=+10 (ovvio dall'equazione).
Toshihiro Shimizu 890ddd
  * 
Toshihiro Shimizu 890ddd
  *  La parabola potrà essere rappresentata sul lato sx da una quadratica con 
Toshihiro Shimizu 890ddd
  *  punti di controllo:
Toshihiro Shimizu 890ddd
  *    P0=(-10,-100),
Toshihiro Shimizu 890ddd
  *    P1=(-5,    0),
Toshihiro Shimizu 890ddd
  *    P2=( 0,    0).
Toshihiro Shimizu 890ddd
  *  Se conosciamo il numero di tratti lineari che rappresentano questa parabola,
Toshihiro Shimizu 890ddd
  *  sappiamo anche quanti "campioni" sono richiesti per la sua linearizzazione.
Toshihiro Shimizu 890ddd
  *  Questo parametro può essere utilizzato per stabilire in modo qualitativo
Toshihiro Shimizu 890ddd
  *  il valore con cui campionare la stroke da testare; ci dovranno essere tanti
Toshihiro Shimizu 890ddd
  *  punti da spostare per quanti campioni sono presenti nel riferimento.
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
double
Toshihiro Shimizu 890ddd
computeIncrement(double strokeLength,
Toshihiro Shimizu 890ddd
				 double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(pixelSize > 0 && "Pixel size is negative!!!");
Toshihiro Shimizu 890ddd
	assert(strokeLength > 0 && "Stroke Length size is negative!!!");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// altezza della parabola (va verso il basso)
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		height = 100;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// suppongo di fare almeno un drag di 100 pixel
Toshihiro Shimizu 890ddd
	assert(height >= 100.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		x = sqrt(height);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// il punto p1 dovra' essere all'intersezione
Toshihiro Shimizu 890ddd
	//  tra le tangenti ai due estremi.
Toshihiro Shimizu 890ddd
	//  La tangente del punto p2 e l'asse x,
Toshihiro Shimizu 890ddd
	//  l'altra avra' versore dato dal gradiente in p0,
Toshihiro Shimizu 890ddd
	//  cioe': grad(x,-2 x)
Toshihiro Shimizu 890ddd
	//  e se y = m x + q
Toshihiro Shimizu 890ddd
	//  m =
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		m = 2.0 * x;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		q = m * x - height;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		p1x = q / m;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		scale = strokeLength / (2.0 * x);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TScale
Toshihiro Shimizu 890ddd
		scaleAffine(scale, scale);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD
Toshihiro Shimizu 890ddd
		p0 = scaleAffine * TPointD(-x, -height),
Toshihiro Shimizu 890ddd
		p1 = scaleAffine * TPointD(-p1x, 0.0),
Toshihiro Shimizu 890ddd
		p2 = scaleAffine * TPointD(0.0, 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TQuadratic
Toshihiro Shimizu 890ddd
		quadratic(p0,
Toshihiro Shimizu 890ddd
				  p1,
Toshihiro Shimizu 890ddd
				  p2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		step = computeStep(quadratic,
Toshihiro Shimizu 890ddd
						   pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//  giusto per aggiungere punti anche nel caso peggiore.
Toshihiro Shimizu 890ddd
	if (step >= 1.0)
Toshihiro Shimizu 890ddd
		step = 0.1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return step;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void detectEdges(const vector<tpointd> &pointArray, vector<uint> &edgeIndexArray)</uint></tpointd>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// ASSUNZIONE: sharpPointArray non contiene punti coincidenti adiacenti
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int size = pointArray.size();
Toshihiro Shimizu 890ddd
	// controllo che ci siano piu' di tre elementi
Toshihiro Shimizu 890ddd
	if (size < 3)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	//  scorre pointArray e per ogni suo punto cerca di inscrivere triangoli (utilizzando i
Toshihiro Shimizu 890ddd
	//  punti a sinistra e a destra) considerando potenziali corner quelli con lati l tale
Toshihiro Shimizu 890ddd
	//  che dMin <= l <= dMax (in realta' alla prima volta che l > dMax: breack) e con apertura
Toshihiro Shimizu 890ddd
	//  angolare alpha <= alphaMax. Poi cerca i max locali tra i potenziali corner in una
Toshihiro Shimizu 890ddd
	//  finestra di semiampiezza dMax (al solito alla prima volta che si supera dMax: breack)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//  valori di default: dMin = 7; dMax = dMin + 2; alphaMax = 2.6 (150°)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const double dMin = 4;
Toshihiro Shimizu 890ddd
	const double dMax = dMin + 3;
Toshihiro Shimizu 890ddd
	const double alphaMax = 2.4; // ( 137.5°)
Toshihiro Shimizu 890ddd
	const double dMin2 = dMin * dMin;
Toshihiro Shimizu 890ddd
	const double dMax2 = dMax * dMax;
Toshihiro Shimizu 890ddd
	vector<double> sharpnessArray;</double>
Toshihiro Shimizu 890ddd
	sharpnessArray.push_back(TConsts::pi); //  il primo punto e' un corner
Toshihiro Shimizu 890ddd
	int nodeCount;
Toshihiro Shimizu 890ddd
	for (nodeCount = 1; nodeCount < size - 1; ++nodeCount) { //  scorre la sharpPointArray escludendo gli estremi
Toshihiro Shimizu 890ddd
		sharpnessArray.push_back(0);
Toshihiro Shimizu 890ddd
		TPointD point(pointArray[nodeCount]);
Toshihiro Shimizu 890ddd
		int leftCount;
Toshihiro Shimizu 890ddd
		for (leftCount = nodeCount - 1; leftCount >= 0; --leftCount) { //  calcola i lati "left" dei triangoli inscritti...
Toshihiro Shimizu 890ddd
			TPointD left = pointArray[leftCount];
Toshihiro Shimizu 890ddd
			double dLeft2 = norm2(left - point);
Toshihiro Shimizu 890ddd
			if (dLeft2 < dMin2)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			else if (dLeft2 > dMax2)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			int rightCount;
Toshihiro Shimizu 890ddd
			for (rightCount = nodeCount + 1; rightCount < size; ++rightCount) { //  calcola i lati "right" dei triangoli inscritti...
Toshihiro Shimizu 890ddd
				TPointD right = pointArray[rightCount];
Toshihiro Shimizu 890ddd
				double dRight2 = norm2(right - point);
Toshihiro Shimizu 890ddd
				if (dRight2 < dMin2)
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
				else if (dMax2 < dRight2)
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//  calcola i lati "center" dei triangoli inscritti
Toshihiro Shimizu 890ddd
				double dCenter2 = norm2(left - right);
Toshihiro Shimizu 890ddd
				assert(dLeft2 != 0.0 && dRight2 != 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double cs = (dLeft2 + dRight2 - dCenter2) / (2 * sqrt(dLeft2 * dRight2));
Toshihiro Shimizu 890ddd
				double alpha = acos(cs);
Toshihiro Shimizu 890ddd
				if (alpha > alphaMax)
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double sharpness = TConsts::pi - alpha;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (sharpnessArray[nodeCount] < sharpness)
Toshihiro Shimizu 890ddd
					sharpnessArray[nodeCount] = sharpness;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	edgeIndexArray.push_back(0); //  il primo punto e' un corner
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// trovo i massimi locali escludendo gli estremi
Toshihiro Shimizu 890ddd
	for (nodeCount = 1; nodeCount < size - 1; ++nodeCount) { //  scorre la lista escludendo gli estremi
Toshihiro Shimizu 890ddd
		bool isCorner = true;
Toshihiro Shimizu 890ddd
		TPointD point(pointArray[nodeCount]);
Toshihiro Shimizu 890ddd
		int leftCount;
Toshihiro Shimizu 890ddd
		for (leftCount = nodeCount - 1; leftCount >= 0; --leftCount) { //  scorre la lista di sharpPoint a sinistra di node...
Toshihiro Shimizu 890ddd
			TPointD left = pointArray[leftCount];
Toshihiro Shimizu 890ddd
			double dLeft2 = norm2(left - point);
Toshihiro Shimizu 890ddd
			if (dLeft2 > dMax2)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			if (sharpnessArray[leftCount] > sharpnessArray[nodeCount]) {
Toshihiro Shimizu 890ddd
				isCorner = false;
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (isCorner)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		int rightCount;
Toshihiro Shimizu 890ddd
		for (rightCount = nodeCount + 1; rightCount < size; ++rightCount) { //  scorre la lista di sharpPoint a destra di node..
Toshihiro Shimizu 890ddd
			TPointD right = pointArray[rightCount];
Toshihiro Shimizu 890ddd
			double dRight2 = norm2(right - point);
Toshihiro Shimizu 890ddd
			if (dRight2 > dMax2)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			if (sharpnessArray[rightCount] > sharpnessArray[nodeCount]) {
Toshihiro Shimizu 890ddd
				isCorner = false;
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (isCorner)
Toshihiro Shimizu 890ddd
			edgeIndexArray.push_back(nodeCount);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	edgeIndexArray.push_back(size - 1); //  l'ultimo punto e' un corner
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
//    API  functions
Toshihiro Shimizu 890ddd
//*******************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool increaseControlPoints(TStroke &stroke,
Toshihiro Shimizu 890ddd
						   const TStrokeDeformation &deformer,
Toshihiro Shimizu 890ddd
						   double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isAlmostZero(stroke.getLength())) {
Toshihiro Shimizu 890ddd
		return norm2(deformer.getDisplacement(stroke, 0.0)) > 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// step 1:
Toshihiro Shimizu 890ddd
	// It's possible to have control point at not null potential
Toshihiro Shimizu 890ddd
	//  but with delta equal 0 (equipotential control point)
Toshihiro Shimizu 890ddd
	bool notVoidPotential = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < stroke.getControlPointCount(); ++i) {
Toshihiro Shimizu 890ddd
		double par = stroke.getParameterAtControlPoint(i);
Toshihiro Shimizu 890ddd
		if (deformer.getDisplacement(stroke, par) != TThickPoint()) {
Toshihiro Shimizu 890ddd
			notVoidPotential = true;
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// step 2:
Toshihiro Shimizu 890ddd
	//  increase control point checking delta of deformer
Toshihiro Shimizu 890ddd
	double maxDifference = deformer.getMaxDiff(); //sopra questo valore di delta, si aggiungono punti
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int strokeControlPoint = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// pixelSize = sq( pixelSize );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (pixelSize < TConsts::epsilon)
Toshihiro Shimizu 890ddd
		pixelSize = TConsts::epsilon;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		length = stroke.getLength(),
Toshihiro Shimizu 890ddd
		// set the step function of length
Toshihiro Shimizu 890ddd
		//    step = length > 1.0 ?  pixelSize * 15.0/ length : length,
Toshihiro Shimizu 890ddd
		//step = 0.01,
Toshihiro Shimizu 890ddd
		w = 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double
Toshihiro Shimizu 890ddd
		step = computeIncrement(length,
Toshihiro Shimizu 890ddd
								pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double x1, x2, d1, d2, diff, offset, minimum, incr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	incr = step;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (w + incr < 1.0) {
Toshihiro Shimizu 890ddd
		d1 = deformer.getDelta(stroke, w);
Toshihiro Shimizu 890ddd
		d2 = deformer.getDelta(stroke, w + incr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		diff = d2 - d1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (fabs(diff) >= maxDifference) // if there is a step of potential
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (tsign(diff) > 0) {
Toshihiro Shimizu 890ddd
				x1 = w;
Toshihiro Shimizu 890ddd
				x2 = w + incr;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				x1 = w + incr;
Toshihiro Shimizu 890ddd
				x2 = w;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			offset = (d1 + d2) * 0.5;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// find the position of step
Toshihiro Shimizu 890ddd
			minimum = findMinimum(deformer, stroke, x1, x2, TConsts::epsilon, offset, 20); //tra x1 e x2 va messo un nuovo punto di controllo. dove?
Toshihiro Shimizu 890ddd
			//questa funzione trova il punto in cui si supera il valore maxdifference
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// if minimum is not found or is equal to previous value
Toshihiro Shimizu 890ddd
			//  use an euristic...
Toshihiro Shimizu 890ddd
			if (minimum < 0 || w == minimum) {
Toshihiro Shimizu 890ddd
				minimum = w + incr * 0.5;
Toshihiro Shimizu 890ddd
				w += step;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//... else insert a control point in minimum
Toshihiro Shimizu 890ddd
			w = minimum; //la scansione riprende dal nuovo punto, in questo modo si infittisce...
Toshihiro Shimizu 890ddd
			stroke.insertControlPoints(minimum);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// update of step
Toshihiro Shimizu 890ddd
			incr = step;
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			incr += step;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// return true if control point are increased
Toshihiro Shimizu 890ddd
	return (stroke.getControlPointCount() > strokeControlPoint) || notVoidPotential;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void modifyControlPoints(TStroke &stroke,
Toshihiro Shimizu 890ddd
						 const TStrokeDeformation &deformer)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int cpCount = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint newP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < cpCount; ++i) {
Toshihiro Shimizu 890ddd
		newP = stroke.getControlPoint(i) + deformer.getDisplacementForControlPoint(stroke, i);
Toshihiro Shimizu 890ddd
		if (isAlmostZero(newP.thick, 0.005))
Toshihiro Shimizu 890ddd
			newP.thick = 0;
Toshihiro Shimizu 890ddd
		stroke.setControlPoint(i, newP);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void modifyControlPoints(TStroke &stroke,
Toshihiro Shimizu 890ddd
						 const TStrokeDeformation &deformer, vector<double> &controlPointLen)</double>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	UINT cpCount = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint newP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
	UINT debugVariable = controlPointLen.size();
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
	assert(controlPointLen.size() == cpCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (UINT i = 0; i < cpCount; ++i) {
Toshihiro Shimizu 890ddd
		newP = stroke.getControlPoint(i) + deformer.getDisplacementForControlPointLen(stroke, controlPointLen[i]);
Toshihiro Shimizu 890ddd
		if (isAlmostZero(newP.thick, 0.005))
Toshihiro Shimizu 890ddd
			newP.thick = 0;
Toshihiro Shimizu 890ddd
		stroke.setControlPoint(i, newP);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void modifyThickness(TStroke &stroke, const TStrokeDeformation &deformer,
Toshihiro Shimizu 890ddd
					 vector<double> &controlPointLen, bool exponentially)</double>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	UINT cpCount = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
	assert(controlPointLen.size() == cpCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double disp;
Toshihiro Shimizu 890ddd
	double thick;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (UINT i = 0; i < cpCount; ++i) {
Toshihiro Shimizu 890ddd
		disp = (deformer.getDisplacementForControlPointLen(stroke, controlPointLen[i])).thick;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		thick = stroke.getControlPoint(i).thick;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//The additive version is straightforward.
Toshihiro Shimizu 890ddd
		//The exponential version is devised to keep derivative 1 at disp == 0;
Toshihiro Shimizu 890ddd
		//it is typically used when the thickness decreases.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		thick = (exponentially && thick >= 0.005) ? thick * exp(disp / thick) : thick + disp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (thick < 0.005)
Toshihiro Shimizu 890ddd
			thick = 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		stroke.setControlPoint(i, TThickPoint(stroke.getControlPoint(i), thick));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void transform_thickness(TStroke &stroke, const double poly[], int deg)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int cp, cpCount = stroke.getControlPointCount();
Toshihiro Shimizu 890ddd
	for (cp = 0; cp != cpCount; ++cp) {
Toshihiro Shimizu 890ddd
		TThickPoint cpPoint = stroke.getControlPoint(cp);
Toshihiro Shimizu 890ddd
		cpPoint.thick = tmax(
Toshihiro Shimizu 890ddd
			tcg::poly_ops::evaluate(poly, deg, cpPoint.thick),
Toshihiro Shimizu 890ddd
			0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		stroke.setControlPoint(cp, cpPoint);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStroke *Toonz::merge(const std::vector<tstroke *=""> &strokes)</tstroke>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (strokes.empty())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<tthickpoint></tthickpoint>
Toshihiro Shimizu 890ddd
		new_stroke_cp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int
Toshihiro Shimizu 890ddd
		size_stroke_array = strokes.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int
Toshihiro Shimizu 890ddd
		size_cp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TStroke *
Toshihiro Shimizu 890ddd
		ref;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint
Toshihiro Shimizu 890ddd
		last = TConsts::natp;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!strokes[0])
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	new_stroke_cp.push_back(strokes[0]->getControlPoint(0));
Toshihiro Shimizu 890ddd
	int i, j;
Toshihiro Shimizu 890ddd
	for (i = 0;
Toshihiro Shimizu 890ddd
		 i < size_stroke_array;
Toshihiro Shimizu 890ddd
		 i++) {
Toshihiro Shimizu 890ddd
		ref = strokes[i];
Toshihiro Shimizu 890ddd
		if (!ref)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		size_cp = ref->getControlPointCount();
Toshihiro Shimizu 890ddd
		for (j = 0;
Toshihiro Shimizu 890ddd
			 j < size_cp - 1;
Toshihiro Shimizu 890ddd
			 j++) {
Toshihiro Shimizu 890ddd
			const TThickPoint &
Toshihiro Shimizu 890ddd
				pnt = ref->getControlPoint(j);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (last != TConsts::natp &&
Toshihiro Shimizu 890ddd
				j == 0) {
Toshihiro Shimizu 890ddd
				//new_stroke_cp.push_back( (last+pnt)*0.5 );
Toshihiro Shimizu 890ddd
				new_stroke_cp.push_back(last);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (j > 0)
Toshihiro Shimizu 890ddd
				new_stroke_cp.push_back(pnt);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		// last point needs to be merged
Toshihiro Shimizu 890ddd
		last = ref->getControlPoint(size_cp - 1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	new_stroke_cp.push_back(ref->getControlPoint(size_cp - 1));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStroke *out = new TStroke(new_stroke_cp);
Toshihiro Shimizu 890ddd
	return out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class CpsReader
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<tthickpoint> &m_cps;</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef TPointD value_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	CpsReader(std::vector<tthickpoint> &cps) : m_cps(cps) {}</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void openContainer(const TPointD &point) { addElement(point); }
Toshihiro Shimizu 890ddd
	void addElement(const TPointD &point) { m_cps.push_back(TThickPoint(point, 0.0)); }
Toshihiro Shimizu 890ddd
	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>
Toshihiro Shimizu 890ddd
double buildLength(const iter_type &begin, const iter_type &end, double tol)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Build direction
Toshihiro Shimizu 890ddd
	iter_type it = begin, jt;
Toshihiro Shimizu 890ddd
	++it;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPointD &a = *begin, &b = *it;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD dir(normalize(b - a)), segDir;
Toshihiro Shimizu 890ddd
	double dist;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (jt = it, ++it; it != end; jt = it, ++it) {
Toshihiro Shimizu 890ddd
		segDir = *it - *jt;
Toshihiro Shimizu 890ddd
		if (dir * segDir < 0)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dist = tcg::point_ops::lineSignedDist(*it, a, dir);
Toshihiro Shimizu 890ddd
		if (fabs(dist) > tol) {
Toshihiro Shimizu 890ddd
			double s, t;
Toshihiro Shimizu 890ddd
			if (dist > 0) {
Toshihiro Shimizu 890ddd
				tcg::point_ops::intersectionCoords(*jt, segDir,
Toshihiro Shimizu 890ddd
												   a + tol * tcg::point_ops::ortLeft(dir), dir, s, t);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				tcg::point_ops::intersectionCoords(*jt, segDir,
Toshihiro Shimizu 890ddd
												   a + tol * tcg::point_ops::ortRight(dir), dir, s, t);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			s = tcrop(s, 0.0, 1.0);
Toshihiro Shimizu 890ddd
			return (*jt + s * segDir - a) * dir;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (*jt - a) * dir;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Converts the specified points triplet into a sequence of quadratics' CPs (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
Toshihiro Shimizu 890ddd
class TripletsConverter
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef std::vector<tpointd>::const_iterator iter_type;</tpointd>
Toshihiro Shimizu 890ddd
	typedef std::reverse_iterator<iter_type> riter_type;</iter_type>
Toshihiro Shimizu 890ddd
	typedef tcg::cyclic_iterator<iter_type> cyclic_iter_type;</iter_type>
Toshihiro Shimizu 890ddd
	typedef std::reverse_iterator<cyclic_iter_type> rcyclic_iter_type;</cyclic_iter_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_circular;
Toshihiro Shimizu 890ddd
	iter_type m_first, m_end, m_last;
Toshihiro Shimizu 890ddd
	double m_adherenceTol, m_angleTol, m_relativeTol, m_relativeDistTol;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TripletsConverter(const iter_type &begin, const iter_type &end,
Toshihiro Shimizu 890ddd
					  double adherenceTol, double angleTol,
Toshihiro Shimizu 890ddd
					  double relativeTol, double relativeDistTol)
Toshihiro Shimizu 890ddd
		: m_circular(*begin == *(end - 1)), m_first(m_circular ? begin + 1 : begin), m_end(end), m_adherenceTol(adherenceTol), m_angleTol(angleTol), m_relativeTol(relativeTol), m_relativeDistTol(relativeDistTol) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Using bisector to convert a triplet
Toshihiro Shimizu 890ddd
	void operator()(const TPointD &a, const iter_type &bt, const TPointD &c,
Toshihiro Shimizu 890ddd
					tcg::sequential_reader<std::vector<tpointd>> &output)</std::vector<tpointd>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const TPointD &b = *bt;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double prod = tcg::point_ops::direction(b, a) * tcg::point_ops::direction(b, c);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (prod > m_angleTol) {
Toshihiro Shimizu 890ddd
			//Full corner
Toshihiro Shimizu 890ddd
			output.addElement(0.5 * (a + b));
Toshihiro Shimizu 890ddd
			output.addElement(b);
Toshihiro Shimizu 890ddd
			output.addElement(0.5 * (b + c));
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			//Build the angle bisector
Toshihiro Shimizu 890ddd
			TPointD a_b(a - b);
Toshihiro Shimizu 890ddd
			TPointD c_b(c - b);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double norm_a_b = norm(a_b);
Toshihiro Shimizu 890ddd
			double norm_c_b = norm(c_b);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a_b = a_b * (1.0 / norm_a_b);
Toshihiro Shimizu 890ddd
			c_b = c_b * (1.0 / norm_c_b);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TPointD v(tcg::point_ops::normalized(a_b + c_b));
Toshihiro Shimizu 890ddd
			double cos_v_dir = fabs(a_b * v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double t1 = tcrop(m_adherenceTol / (cos_v_dir * norm_a_b), 0.0, 0.5);
Toshihiro Shimizu 890ddd
			double t2 = tcrop(m_adherenceTol / (cos_v_dir * norm_c_b), 0.0, 0.5);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (t1 == 0.5 && t2 == 0.5) {
Toshihiro Shimizu 890ddd
				//Direct conversion
Toshihiro Shimizu 890ddd
				output.addElement(b);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				//Build the quadratic split
Toshihiro Shimizu 890ddd
				TPointD d(b + t1 * (a - b)), f(b + t2 * (c - b)), e(0.5 * (d + f));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Build curvature radiuses at the corner
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//NOTE: Both speed and acceleration would hold 2.0 as multiplier, which
Toshihiro Shimizu 890ddd
				//is calculated implicitly.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TPointD speed(f - d);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double num = norm(speed);
Toshihiro Shimizu 890ddd
				if (num <= TConsts::epsilon) {
Toshihiro Shimizu 890ddd
					//Curvature radius is 0 - full corner
Toshihiro Shimizu 890ddd
					output.addElement(0.5 * (a + b));
Toshihiro Shimizu 890ddd
					output.addElement(b);
Toshihiro Shimizu 890ddd
					output.addElement(0.5 * (b + c));
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					num = 2.0 * num * num * num; // would be * 8 = 2^3, divided by the 4 below
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					double den1 = fabs(cross(speed, a - d)); // * 4, from both args of the cross
Toshihiro Shimizu 890ddd
					double den2 = fabs(cross(speed, c - f));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					double radius1 = (den1 == 0.0) ? 0.0 : num / den1;
Toshihiro Shimizu 890ddd
					double radius2 = (den1 == 0.0) ? 0.0 : num / den2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					//Build edges length
Toshihiro Shimizu 890ddd
					double length1, length2;
Toshihiro Shimizu 890ddd
					if (m_circular) {
Toshihiro Shimizu 890ddd
						cyclic_iter_type it(bt, m_first, m_end, 0);
Toshihiro Shimizu 890ddd
						cyclic_iter_type it1(bt, m_first, m_end, 1);
Toshihiro Shimizu 890ddd
						cyclic_iter_type it_1(bt, m_first, m_end, -1);
Toshihiro Shimizu 890ddd
						rcyclic_iter_type rit(it + 1), rit1(it_1 + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						length1 = buildLength(rit, rit1, 0.25);
Toshihiro Shimizu 890ddd
						length2 = buildLength(it, it1, 0.25);
Toshihiro Shimizu 890ddd
					} else {
Toshihiro Shimizu 890ddd
						riter_type rit(bt + 1), rend(m_first);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						length1 = buildLength(rit, rend, m_relativeDistTol);
Toshihiro Shimizu 890ddd
						length2 = buildLength(bt, m_end, m_relativeDistTol);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					//Test curvature radiuses against edge length
Toshihiro Shimizu 890ddd
					if (radius1 / length1 < m_relativeTol && // both must hold
Toshihiro Shimizu 890ddd
						radius2 / length2 < m_relativeTol) {
Toshihiro Shimizu 890ddd
						//Full corner
Toshihiro Shimizu 890ddd
						output.addElement(0.5 * (a + b));
Toshihiro Shimizu 890ddd
						output.addElement(b);
Toshihiro Shimizu 890ddd
						output.addElement(0.5 * (b + c));
Toshihiro Shimizu 890ddd
					} else {
Toshihiro Shimizu 890ddd
						//Quadratic split
Toshihiro Shimizu 890ddd
						output.addElement(d);
Toshihiro Shimizu 890ddd
						output.addElement(e);
Toshihiro Shimizu 890ddd
						output.addElement(f);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		output.addElement(c);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void polylineToQuadratics(const std::vector<tpointd> &polyline,</tpointd>
Toshihiro Shimizu 890ddd
						  std::vector<tthickpoint> &cps,</tthickpoint>
Toshihiro Shimizu 890ddd
						  double adherenceTol, double angleTol,
Toshihiro Shimizu 890ddd
						  double relativeTol, double relativeDistTol,
Toshihiro Shimizu 890ddd
						  double mergeTol)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	CpsReader cpsReader(cps);
Toshihiro Shimizu 890ddd
	TripletsConverter op(polyline.begin(), polyline.end(),
Toshihiro Shimizu 890ddd
						 adherenceTol, angleTol, relativeTol, relativeDistTol);
Toshihiro Shimizu 890ddd
	tcg::polyline_ops::toQuadratics(polyline.begin(), polyline.end(), cpsReader, op, mergeTol);
Toshihiro Shimizu 890ddd
}