Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "tregionoutline.h"
Toshihiro Shimizu 890ddd
#include "tellipticbrushP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tstrokeoutline.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace tellipticbrush;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define USE_LENGTH
Toshihiro Shimizu 890ddd
//#define DEBUG_DRAW_TANGENTS
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    EXPLANATION
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! \file tellipticbrush.cpp
Toshihiro Shimizu 890ddd
\brief This code performs the outlinization of a \a brush stroke with respect to a
Toshihiro Shimizu 890ddd
       secondary \a path stroke. This is used to draw Adobe Illustrator-like
Toshihiro Shimizu 890ddd
       vectors whose brush is itself a custom vector (and by extension, a complex
Toshihiro Shimizu 890ddd
       vector image).
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
       Generalization: Introduce a repeat % and a superposition % in the algorithm
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* TECHNICAL:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  We have two strokes: one is the 'guideline', the other is the 'brush', and the
Toshihiro Shimizu 890ddd
  purpose of this algorithm is that of bending the brush to follow the guideline.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  The brush is supposed to be lying horizontally, inside a rectangle corresponding
Toshihiro Shimizu 890ddd
  to the bounding box of the image containing the brush.
Toshihiro Shimizu 890ddd
  The line segment connecting the midpoints of the vertical image bbox edges maps
Toshihiro Shimizu 890ddd
  to the guideline's centerline.
Toshihiro Shimizu 890ddd
  Such mapping makes [bbox.x0, bbox.x1] -> [0, 1] in a linear fashion, where the
Toshihiro Shimizu 890ddd
  image interval represents the parametric space of the guideline.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  Each vertical scanline of the bbox is further mapped to the segment extruding from
Toshihiro Shimizu 890ddd
  the guideline's centerline along its normal (multiplied in length by the
Toshihiro Shimizu 890ddd
  guideline's thickness).
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Geometric helpers
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double getX(const TThickPoint &P0, const TThickPoint &P1, const TThickPoint &P2, double t)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double one_t = 1.0 - t;
Toshihiro Shimizu 890ddd
	return P0.x * sq(one_t) + 2.0 * P1.x * t * one_t + P2.x * sq(t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPointD normal(const TPointD &p, bool left)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPointD n(-p.y, p.x);
Toshihiro Shimizu 890ddd
	return (1.0 / norm(n)) * (left ? n : -n);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPointD normal(const TPointD &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (1.0 / norm(p)) * TPointD(-p.y, p.x);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void getHRange(const TThickQuadratic &ttq, double &x0, double &x1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TPointD &P0 = ttq.getP0();
Toshihiro Shimizu 890ddd
	const TPointD &P1 = ttq.getP1();
Toshihiro Shimizu 890ddd
	const TPointD &P2 = ttq.getP2();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Get the horizontal range of the chunk
Toshihiro Shimizu 890ddd
	x0 = tmin(x0, P0.x, P2.x), x1 = tmax(x1, P0.x, P2.x);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double t = (P0.x - P1.x) / (P0.x + P2.x - 2.0 * P1.x);
Toshihiro Shimizu 890ddd
	if (t > 0.0 && t < 1.0) {
Toshihiro Shimizu 890ddd
		double x = getX(P0, P1, P2, t);
Toshihiro Shimizu 890ddd
		x0 = tmin(x0, x), x1 = tmax(x1, x);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void getHRange(const TThickQuadratic &ttq, double t0, double t1, double &x0, double &x1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TPointD &P0 = ttq.getP0();
Toshihiro Shimizu 890ddd
	const TPointD &P1 = ttq.getP1();
Toshihiro Shimizu 890ddd
	const TPointD &P2 = ttq.getP2();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double x0_ = getX(P0, P1, P2, t0);
Toshihiro Shimizu 890ddd
	double x1_ = getX(P0, P1, P2, t1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Get the horizontal range of the chunk
Toshihiro Shimizu 890ddd
	x0 = tmin(x0, x0_, x1_), x1 = tmax(x1, x0_, x1_);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double t = (P0.x - P1.x) / (P0.x + P2.x - 2.0 * P1.x);
Toshihiro Shimizu 890ddd
	if (t > t0 && t < t1) {
Toshihiro Shimizu 890ddd
		double x = getX(P0, P1, P2, t);
Toshihiro Shimizu 890ddd
		x0 = tmin(x0, x), x1 = tmax(x1, x);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void getHRange(const TStroke &stroke, double &x0, double &x1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i, nChunks = stroke.getChunkCount();
Toshihiro Shimizu 890ddd
	for (i = 0; i < nChunks; ++i)
Toshihiro Shimizu 890ddd
		getHRange(*stroke.getChunk(i), x0, x1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Outlinization Data
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct StrokeOutlinizationData : public tellipticbrush::OutlinizationData {
Toshihiro Shimizu 890ddd
	double m_x0, m_x1, m_xRange;
Toshihiro Shimizu 890ddd
	double m_y0, m_yScale;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	StrokeOutlinizationData()
Toshihiro Shimizu 890ddd
		: OutlinizationData() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokeOutlinizationData(const TStroke &stroke, const TRectD &strokeBox,
Toshihiro Shimizu 890ddd
							const TOutlineUtil::OutlineParameter &options)
Toshihiro Shimizu 890ddd
		: OutlinizationData(options), m_x0(strokeBox.x0), m_x1(strokeBox.x1), m_xRange(m_x1 - m_x0), m_y0(0.5 * (strokeBox.y0 + strokeBox.y1)), m_yScale(1.0 / (strokeBox.y1 - strokeBox.y0)) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void buildPoint(const CenterlinePoint &p, bool isNextD, CenterlinePoint &ref, bool isRefNextD,
Toshihiro Shimizu 890ddd
					CenterlinePoint &out);
Toshihiro Shimizu 890ddd
	int buildPoints(const CenterlinePoint &p, CenterlinePoint &ref, CenterlinePoint *out);
Toshihiro Shimizu 890ddd
	int buildPoints(const TStroke &stroke, const TStroke &path,
Toshihiro Shimizu 890ddd
					CenterlinePoint &cp, CenterlinePoint *out);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool getChunkAndT_param(const TStroke &path, double x, int &chunk, double &t);
Toshihiro Shimizu 890ddd
	bool getChunkAndT_length(const TStroke &path, double x, int &chunk, double &t);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double toW(double x);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double StrokeOutlinizationData::toW(double x)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return tcrop((x - m_x0) / m_xRange, 0.0, 1.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool StrokeOutlinizationData::getChunkAndT_param(const TStroke &path, double x, int &chunk, double &t)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double w = toW(x);
Toshihiro Shimizu 890ddd
	return !path.getChunkAndT(w, chunk, t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool StrokeOutlinizationData::getChunkAndT_length(const TStroke &path, double x, int &chunk, double &t)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double s = toW(x) * path.getLength();
Toshihiro Shimizu 890ddd
	return !path.getChunkAndTAtLength(s, chunk, t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void StrokeOutlinizationData::buildPoint(const CenterlinePoint &p, bool pNextD,
Toshihiro Shimizu 890ddd
										 CenterlinePoint &ref, bool refNextD,
Toshihiro Shimizu 890ddd
										 CenterlinePoint &out)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TThickPoint &refD = refNextD ? ref.m_nextD : ref.m_prevD;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TThickPoint *pD;
Toshihiro Shimizu 890ddd
	TThickPoint *outD;
Toshihiro Shimizu 890ddd
	bool *outHasD;
Toshihiro Shimizu 890ddd
	if (pNextD) {
Toshihiro Shimizu 890ddd
		pD = &p.m_nextD;
Toshihiro Shimizu 890ddd
		outD = &out.m_nextD;
Toshihiro Shimizu 890ddd
		outHasD = &out.m_hasNextD;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		pD = &p.m_prevD;
Toshihiro Shimizu 890ddd
		outD = &out.m_prevD;
Toshihiro Shimizu 890ddd
		outHasD = &out.m_hasPrevD;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build position
Toshihiro Shimizu 890ddd
	refD = (1.0 / norm(refD)) * refD;
Toshihiro Shimizu 890ddd
	TPointD normalDirection(-refD.y, refD.x);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double yPercentage = (p.m_p.y - m_y0) * m_yScale;
Toshihiro Shimizu 890ddd
	double yRelative = yPercentage * ref.m_p.thick;
Toshihiro Shimizu 890ddd
	double yFactor = ref.m_p.thick * m_yScale;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	out.m_p = TThickPoint(
Toshihiro Shimizu 890ddd
		ref.m_p.x + yRelative * normalDirection.x,
Toshihiro Shimizu 890ddd
		ref.m_p.y + yRelative * normalDirection.y,
Toshihiro Shimizu 890ddd
		p.m_p.thick * yFactor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build direction
Toshihiro Shimizu 890ddd
	double stretchedDY = pD->x * yPercentage * refD.thick + pD->y * yFactor;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	*outD = TThickPoint(
Toshihiro Shimizu 890ddd
		refD.x * pD->x - refD.y * stretchedDY,
Toshihiro Shimizu 890ddd
		refD.y * pD->x + refD.x * stretchedDY,
Toshihiro Shimizu 890ddd
		pD->thick * (1.0 + refD.thick));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool covered = (sq(outD->x) + sq(outD->y) < sq(outD->thick) + tolPar);
Toshihiro Shimizu 890ddd
	out.m_covered = out.m_covered && covered;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	*outHasD = *outHasD && !covered;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*    EXPLANATION:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
        \ _   \         The path stroke with centerline point C has 2 outward
Toshihiro Shimizu 890ddd
     \      \  \        directions (prevD and nextD), which may be different.
Toshihiro Shimizu 890ddd
      \      |* \       Therefore, there may also be 2 different envelope directions
Toshihiro Shimizu 890ddd
       \   * .   \      from C (the *s in the drawing).
Toshihiro Shimizu 890ddd
        C    .    |     When the brush stroke 'hits' one envelope direction, it
Toshihiro Shimizu 890ddd
       /   * .   /      transfers on the other e.d., and continues on that side.
Toshihiro Shimizu 890ddd
      /   _ / * /
Toshihiro Shimizu 890ddd
     /  /      /
Toshihiro Shimizu 890ddd
       |      /
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Build points resulting from the association between p (must have pos and dirs
Toshihiro Shimizu 890ddd
//! already built) and ref, returning the number of output points stored in out[] (at max 2).
Toshihiro Shimizu 890ddd
int StrokeOutlinizationData::buildPoints(const CenterlinePoint &p, CenterlinePoint &ref,
Toshihiro Shimizu 890ddd
										 CenterlinePoint *out)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	out[0] = out[1] = p;
Toshihiro Shimizu 890ddd
	out[0].m_covered = out[1].m_covered = true; //Coverage is rebuilt
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool refSymmetric = ref.m_hasPrevD && ref.m_hasNextD && ref.m_nextD == ref.m_prevD;
Toshihiro Shimizu 890ddd
	bool pSymmetric = p.m_hasPrevD && p.m_hasNextD && p.m_nextD == p.m_prevD;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build prev
Toshihiro Shimizu 890ddd
	bool prevSideIsNext = (p.m_prevD.x < 0) ? true : (p.m_prevD.x > 0) ? false : ref.m_hasNextD;
Toshihiro Shimizu 890ddd
	bool hasPrev = p.m_hasPrevD && (prevSideIsNext ? ref.m_hasNextD : ref.m_hasPrevD);
Toshihiro Shimizu 890ddd
	int prevIdx = hasPrev ? 0 : -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (hasPrev) {
Toshihiro Shimizu 890ddd
		CenterlinePoint &outPoint = out[prevIdx];
Toshihiro Shimizu 890ddd
		buildPoint(p, false, ref, prevSideIsNext, outPoint);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (refSymmetric && pSymmetric) {
Toshihiro Shimizu 890ddd
		//Copy prev to next
Toshihiro Shimizu 890ddd
		if (hasPrev) {
Toshihiro Shimizu 890ddd
			CenterlinePoint &outPoint = out[prevIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			outPoint.m_hasNextD = outPoint.m_hasPrevD;
Toshihiro Shimizu 890ddd
			outPoint.m_nextD = outPoint.m_prevD;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return 1;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build next
Toshihiro Shimizu 890ddd
	bool nextSideIsNext = (p.m_nextD.x > 0) ? true : (p.m_nextD.x < 0) ? false : ref.m_hasNextD;
Toshihiro Shimizu 890ddd
	bool hasNext = p.m_hasNextD && (nextSideIsNext ? ref.m_hasNextD : ref.m_hasPrevD);
Toshihiro Shimizu 890ddd
	int nextIdx = hasNext ? hasPrev ? ((int)prevSideIsNext != nextSideIsNext) : 0 : -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (hasNext) {
Toshihiro Shimizu 890ddd
		CenterlinePoint &outPoint = out[nextIdx];
Toshihiro Shimizu 890ddd
		buildPoint(p, true, ref, nextSideIsNext, outPoint);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Fill in unbuilt directions if necessary
Toshihiro Shimizu 890ddd
	if (hasPrev && hasNext && prevIdx != nextIdx) {
Toshihiro Shimizu 890ddd
		CenterlinePoint &outPrev = out[prevIdx];
Toshihiro Shimizu 890ddd
		CenterlinePoint &outNext = out[nextIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (dist(outPrev.m_p, outNext.m_p) > 1e-4) {
Toshihiro Shimizu 890ddd
			//If there are 2 full output points, make their unbuilt directions match
Toshihiro Shimizu 890ddd
			outPrev.m_nextD = outNext.m_prevD = 0.5 * (outNext.m_p - outPrev.m_p);
Toshihiro Shimizu 890ddd
			bool covered = (sq(outPrev.m_nextD.x) + sq(outPrev.m_nextD.y) <
Toshihiro Shimizu 890ddd
							sq(outPrev.m_nextD.thick) + tolPar);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			outPrev.m_hasNextD = outNext.m_hasPrevD = !covered;
Toshihiro Shimizu 890ddd
			outPrev.m_covered = outPrev.m_covered && covered;
Toshihiro Shimizu 890ddd
			outNext.m_covered = outNext.m_covered && covered;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			//Merge the 2 existing ones
Toshihiro Shimizu 890ddd
			nextIdx = prevIdx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			outPrev.m_nextD = outNext.m_nextD;
Toshihiro Shimizu 890ddd
			outPrev.m_hasNextD = outNext.m_hasPrevD;
Toshihiro Shimizu 890ddd
			outPrev.m_covered = outPrev.m_covered && outNext.m_covered;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return tmax(prevIdx, nextIdx) + 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int StrokeOutlinizationData::buildPoints(const TStroke &stroke, const TStroke &path,
Toshihiro Shimizu 890ddd
										 CenterlinePoint &cp, CenterlinePoint *out)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *stroke.getChunk(cp.m_chunkIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TThickPoint &P0 = ttq.getP0();
Toshihiro Shimizu 890ddd
	const TThickPoint &P1 = ttq.getP1();
Toshihiro Shimizu 890ddd
	const TThickPoint &P2 = ttq.getP2();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double x = getX(P0, P1, P2, cp.m_t);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double pathT;
Toshihiro Shimizu 890ddd
	int pathChunk;
Toshihiro Shimizu 890ddd
#ifdef USE_LENGTH
Toshihiro Shimizu 890ddd
	bool ok = getChunkAndT_length(path, x, pathChunk, pathT);
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	bool ok = getChunkAndT_param(path, x, pathChunk, pathT);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
	assert(ok);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CenterlinePoint pathCp(pathChunk, pathT);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cp.buildPos(stroke);
Toshihiro Shimizu 890ddd
	cp.buildDirs(stroke);
Toshihiro Shimizu 890ddd
	pathCp.buildPos(path);
Toshihiro Shimizu 890ddd
	pathCp.buildDirs(path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return buildPoints(cp, pathCp, out);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Path-Altered Brush Linearizator (base class)
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ReferenceLinearizator : public tellipticbrush::StrokeLinearizator
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
protected:
Toshihiro Shimizu 890ddd
	const TStroke *m_path;
Toshihiro Shimizu 890ddd
	StrokeOutlinizationData m_data;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ReferenceLinearizator(const TStroke *stroke, const TStroke *path, const StrokeOutlinizationData &data);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual void linearize(std::vector<centerlinepoint> &cPoints, int chunk, double t1) = 0;</centerlinepoint>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ReferenceLinearizator::ReferenceLinearizator(const TStroke *stroke, const TStroke *path,
Toshihiro Shimizu 890ddd
											 const StrokeOutlinizationData &data)
Toshihiro Shimizu 890ddd
	: StrokeLinearizator(stroke), m_path(path), m_data(data)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Brush Linearizator on Path inter-chunk points
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ReferenceChunksLinearizator : public ReferenceLinearizator
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double m_w0, m_w1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ReferenceChunksLinearizator(const TStroke *stroke, const TStroke *path,
Toshihiro Shimizu 890ddd
								const StrokeOutlinizationData &data)
Toshihiro Shimizu 890ddd
		: ReferenceLinearizator(stroke, path, data) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void linearize(std::vector<centerlinepoint> &cPoints, int chunk);</centerlinepoint>
Toshihiro Shimizu 890ddd
	void linearize(std::vector<centerlinepoint> &cPoints, int chunk, double t1);</centerlinepoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void addCenterlinePoints(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
							 int brushChunk, double x0, double x1);
Toshihiro Shimizu 890ddd
	void addCenterlinePoints(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
							 int strokeChunk, double strokeT, int refChunk);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ReferenceChunksLinearizator::linearize(std::vector<centerlinepoint> &cPoints, int chunk)</centerlinepoint>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Get the stroke chunk
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *this->m_stroke->getChunk(chunk);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Get the chunk's horizontal range
Toshihiro Shimizu 890ddd
	double x0 = (std::numeric_limits<double>::max)(), x1 = -x0;</double>
Toshihiro Shimizu 890ddd
	getHRange(ttq, x0, x1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, we have to add all points corresponding to the intersections between the relative
Toshihiro Shimizu 890ddd
	//vertical projection of path's chunk endpoints, and the stroke
Toshihiro Shimizu 890ddd
	addCenterlinePoints(cPoints, chunk, x0, x1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ReferenceChunksLinearizator::linearize(std::vector<centerlinepoint> &cPoints, int chunk,</centerlinepoint>
Toshihiro Shimizu 890ddd
											double t1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (cPoints.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Get the stroke chunk
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *this->m_stroke->getChunk(chunk);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Get the chunk's horizontal range
Toshihiro Shimizu 890ddd
	double x0 = (std::numeric_limits<double>::max)(), x1 = -x0;</double>
Toshihiro Shimizu 890ddd
	getHRange(ttq, cPoints[0].m_t, t1, x0, x1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, we have to add all points corresponding to the intersections between the relative
Toshihiro Shimizu 890ddd
	//vertical projection of path's chunk endpoints, and the stroke
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	addCenterlinePoints(cPoints, chunk, x0, x1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ReferenceChunksLinearizator::addCenterlinePoints(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
													  int chunk, double x0, double x1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *this->m_stroke->getChunk(chunk);
Toshihiro Shimizu 890ddd
	const TStroke &path = *this->m_path;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int chunk0, chunk1;
Toshihiro Shimizu 890ddd
	double t0, t1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_LENGTH
Toshihiro Shimizu 890ddd
	bool ok0 = m_data.getChunkAndT_length(path, x0, chunk0, t0);
Toshihiro Shimizu 890ddd
	bool ok1 = m_data.getChunkAndT_length(path, x1, chunk1, t1);
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	bool ok0 = m_data.getChunkAndT_param(path, x0, chunk0, t0);
Toshihiro Shimizu 890ddd
	bool ok1 = m_data.getChunkAndT_param(path, x1, chunk1, t1);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ok0 && ok1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPointD &P0 = ttq.getP0();
Toshihiro Shimizu 890ddd
	const TPointD &P1 = ttq.getP1();
Toshihiro Shimizu 890ddd
	const TPointD &P2 = ttq.getP2();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double A = P0.x + P2.x - 2.0 * P1.x;
Toshihiro Shimizu 890ddd
	double B = P1.x - P0.x;
Toshihiro Shimizu 890ddd
	double delta_ = sq(B) - P0.x * A; // actual delta = delta_ + x * A;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i, initialSize = cPoints.size();
Toshihiro Shimizu 890ddd
	for (i = chunk0; i < chunk1; ++i) {
Toshihiro Shimizu 890ddd
#ifdef USE_LENGTH
Toshihiro Shimizu 890ddd
		double s = tmin(path.getLength(i, 1.0) / path.getLength(), 1.0);
Toshihiro Shimizu 890ddd
		double x = m_data.m_x0 + m_data.m_xRange * s;
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
		double w = path.getW(i, 1.0);
Toshihiro Shimizu 890ddd
		double x = m_data.m_x0 + m_data.m_xRange * w;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double delta = delta_ + x * A;
Toshihiro Shimizu 890ddd
		if (delta < 0)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Add first solution
Toshihiro Shimizu 890ddd
		double t = (sqrt(delta) - B) / A;
Toshihiro Shimizu 890ddd
		if (t > 0.0 && t < 1.0) //0 and 1 are dealt outside
Toshihiro Shimizu 890ddd
			addCenterlinePoints(cPoints, chunk, t, i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (delta < tolPar)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Add second solution
Toshihiro Shimizu 890ddd
		t = -(sqrt(delta) + B) / A;
Toshihiro Shimizu 890ddd
		if (t > 0.0 && t < 1.0)
Toshihiro Shimizu 890ddd
			addCenterlinePoints(cPoints, chunk, t, i);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//As points may be mixed (by parameter), sort them.
Toshihiro Shimizu 890ddd
	std::sort(cPoints.begin() + initialSize, cPoints.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ReferenceChunksLinearizator::addCenterlinePoints(
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> &cPoints, int strokeChunk, double strokeT, int refChunk)</centerlinepoint>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	CenterlinePoint p(strokeChunk, strokeT);
Toshihiro Shimizu 890ddd
	CenterlinePoint ref(refChunk, 1.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	p.buildPos(*m_stroke);
Toshihiro Shimizu 890ddd
	p.buildDirs(*m_stroke);
Toshihiro Shimizu 890ddd
	ref.buildPos(*m_path);
Toshihiro Shimizu 890ddd
	ref.buildDirs(*m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i, count = m_data.buildPoints(p, ref, newPoints);
Toshihiro Shimizu 890ddd
	for (i = 0; i < count; ++i)
Toshihiro Shimizu 890ddd
		cPoints.push_back(newPoints[i]);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Recursive (regular) Reference Stroke Linearizator
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RecursiveReferenceLinearizator : public ReferenceLinearizator
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef void (RecursiveReferenceLinearizator::*SubdivisorFuncPtr)(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
																	  CenterlinePoint &cp0, CenterlinePoint &cp1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SubdivisorFuncPtr m_subdivisor;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	void linearize(std::vector<centerlinepoint> &cPoints, int chunk);</centerlinepoint>
Toshihiro Shimizu 890ddd
	void linearize(std::vector<centerlinepoint> &cPoints, int chunk, double t1);</centerlinepoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void subdivide(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
				   CenterlinePoint &cp0, CenterlinePoint &cp1);
Toshihiro Shimizu 890ddd
	void subdivideCenterline(std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
							 CenterlinePoint &cp0, CenterlinePoint &cp1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RecursiveReferenceLinearizator(const TStroke *stroke, const TStroke *path,
Toshihiro Shimizu 890ddd
								   const StrokeOutlinizationData &data)
Toshihiro Shimizu 890ddd
		: ReferenceLinearizator(stroke, path, data), m_subdivisor(&RecursiveReferenceLinearizator::subdivide) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void RecursiveReferenceLinearizator::linearize(
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> &cPoints, int chunk)</centerlinepoint>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	linearize(cPoints, chunk, 1.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void RecursiveReferenceLinearizator::linearize(
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> &cPoints, int chunk, double t1)</centerlinepoint>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (cPoints.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TStroke &stroke = *this->m_stroke;
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *stroke.getChunk(chunk);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TStroke &path = *this->m_path;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Sort the interval (SHOULD BE DONE OUTSIDE?)
Toshihiro Shimizu 890ddd
	std::stable_sort(cPoints.begin(), cPoints.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> addedPoints;</centerlinepoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, size_1 = cPoints.size() - 1;
Toshihiro Shimizu 890ddd
	for (i = 0; i < size_1; ++i) {
Toshihiro Shimizu 890ddd
		CenterlinePoint &cp1 = cPoints[i], cp2 = cPoints[i + 1];
Toshihiro Shimizu 890ddd
		if (cp2.m_t - cp1.m_t > 1e-4)
Toshihiro Shimizu 890ddd
			(this->*m_subdivisor)(addedPoints, cPoints[i], cPoints[i + 1]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (cPoints[size_1].m_t < t1) {
Toshihiro Shimizu 890ddd
		double t, x = (t1 == 1.0) ? ttq.getP2().x : getX(ttq.getP0(), ttq.getP1(), ttq.getP2(), t1);
Toshihiro Shimizu 890ddd
		int refChunk;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_LENGTH
Toshihiro Shimizu 890ddd
		bool ok = m_data.getChunkAndT_length(path, x, refChunk, t);
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
		bool ok = m_data.getChunkAndT_param(path, x, refChunk, t);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CenterlinePoint strokeCpEnd(chunk, t1);
Toshihiro Shimizu 890ddd
		CenterlinePoint refCp(refChunk, t);
Toshihiro Shimizu 890ddd
		CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		strokeCpEnd.buildPos(*m_stroke);
Toshihiro Shimizu 890ddd
		strokeCpEnd.buildDirs(*m_stroke);
Toshihiro Shimizu 890ddd
		refCp.buildPos(*m_path);
Toshihiro Shimizu 890ddd
		refCp.buildDirs(*m_path);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int count = m_data.buildPoints(strokeCpEnd, refCp, newPoints);
Toshihiro Shimizu 890ddd
		if (count == 1) //Otherwise, this is either impossible, or already covered
Toshihiro Shimizu 890ddd
			(this->*m_subdivisor)(addedPoints, cPoints[size_1], newPoints[0]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cPoints.insert(cPoints.end(), addedPoints.begin(), addedPoints.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void RecursiveReferenceLinearizator::subdivide(
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> &cPoints, CenterlinePoint &cp0, CenterlinePoint &cp1)</centerlinepoint>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(cp0.m_hasNextD && cp1.m_hasPrevD))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TStroke &stroke = *this->m_stroke;
Toshihiro Shimizu 890ddd
	const TThickQuadratic &ttq = *stroke.getChunk(cp0.m_chunkIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TStroke &path = *this->m_path;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build the distance of next from the outline of cp's 'envelope extension'
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD envDirL0, envDirR0, envDirL1, envDirR1;
Toshihiro Shimizu 890ddd
	buildEnvelopeDirections(cp0.m_p, cp0.m_nextD, envDirL0, envDirR0);
Toshihiro Shimizu 890ddd
	buildEnvelopeDirections(cp1.m_p, cp1.m_prevD, envDirL1, envDirR1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD diff(convert(cp1.m_p) - convert(cp0.m_p));
Toshihiro Shimizu 890ddd
	double d = tmax(
Toshihiro Shimizu 890ddd
		fabs(envDirL0 * (diff + cp1.m_p.thick * envDirL1 - cp0.m_p.thick * envDirL0)),
Toshihiro Shimizu 890ddd
		fabs(envDirR0 * (diff + cp1.m_p.thick * envDirR1 - cp0.m_p.thick * envDirR0)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (d > m_data.m_pixSize &&
Toshihiro Shimizu 890ddd
		cp1.m_t - cp0.m_t > 1e-4) {
Toshihiro Shimizu 890ddd
		CenterlinePoint strokeMidPoint(cp0.m_chunkIdx, 0.5 * (cp0.m_t + cp1.m_t));
Toshihiro Shimizu 890ddd
		CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int count = m_data.buildPoints(*this->m_stroke, *this->m_path, strokeMidPoint, newPoints);
Toshihiro Shimizu 890ddd
		if (count == 1) //Otherwise, this is either impossible, or already covered
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			subdivide(cPoints, cp0, newPoints[0]); //should I use strokeMidPoint(Prev) here ?
Toshihiro Shimizu 890ddd
			subdivide(cPoints, newPoints[0], cp1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			cPoints.push_back(newPoints[0]);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void RecursiveReferenceLinearizator::subdivideCenterline(
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> &cPoints,</centerlinepoint>
Toshihiro Shimizu 890ddd
	CenterlinePoint &cp0, CenterlinePoint &cp1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (cp0.m_covered || !cp0.m_hasNextD)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build the distance of next from cp's 'direction extension'
Toshihiro Shimizu 890ddd
	TPointD dir((1.0 / norm(cp0.m_nextD)) * cp0.m_nextD);
Toshihiro Shimizu 890ddd
	TPointD diff(convert(cp1.m_p) - convert(cp0.m_p));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double d = fabs(dir.x * diff.y - dir.y * diff.x);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (d > m_data.m_pixSize &&
Toshihiro Shimizu 890ddd
		cp1.m_t - cp0.m_t > 1e-4) {
Toshihiro Shimizu 890ddd
		CenterlinePoint strokeMidPoint(cp0.m_chunkIdx, 0.5 * (cp0.m_t + cp1.m_t));
Toshihiro Shimizu 890ddd
		CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int count = m_data.buildPoints(*this->m_stroke, *this->m_path, strokeMidPoint, newPoints);
Toshihiro Shimizu 890ddd
		if (count == 1) //Otherwise, this is either impossible, or already covered
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			subdivide(cPoints, cp0, newPoints[0]); //should I use strokeMidPoint(Prev) here ?
Toshihiro Shimizu 890ddd
			subdivide(cPoints, newPoints[0], cp1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			cPoints.push_back(newPoints[0]);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Make Outline Implementation (stroke version)
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Make Outline Implementation (stroke version)
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Quick container to store all the linearization features to be supported.
Toshihiro Shimizu 890ddd
  \note The set should be appropriately ordered so that linearizator dependance
Toshihiro Shimizu 890ddd
  can be supported (linearizators may work depending on knowledge of the other
Toshihiro Shimizu 890ddd
  linearized points)
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
struct LinearizatorsSet {
Toshihiro Shimizu 890ddd
	static const int nLinearizators = 2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ReferenceChunksLinearizator m_refChunksLinearizator;
Toshihiro Shimizu 890ddd
	RecursiveReferenceLinearizator m_recursiveRefLinearizator;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ReferenceLinearizator *m_linearizatorPtrs[nLinearizators];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	LinearizatorsSet(const TStroke &stroke, const TStroke &path,
Toshihiro Shimizu 890ddd
					 const StrokeOutlinizationData &data)
Toshihiro Shimizu 890ddd
		: m_refChunksLinearizator(&stroke, &path, data), m_recursiveRefLinearizator(&stroke, &path, data)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_linearizatorPtrs[0] = &m_refChunksLinearizator;
Toshihiro Shimizu 890ddd
		m_linearizatorPtrs[1] = &m_recursiveRefLinearizator;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ReferenceLinearizator *operator[](int i) { return m_linearizatorPtrs[i]; }
Toshihiro Shimizu 890ddd
	const int size() const { return nLinearizators; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TOutlineUtil::makeOutline(const TStroke &path, const TStroke &stroke,
Toshihiro Shimizu 890ddd
							   const TRectD &strokeBox, TStrokeOutline &outline,
Toshihiro Shimizu 890ddd
							   const TOutlineUtil::OutlineParameter &options)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Build outlinization data
Toshihiro Shimizu 890ddd
	StrokeOutlinizationData data(stroke, strokeBox, options);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build a set of linearizators for the specified stroke
Toshihiro Shimizu 890ddd
	LinearizatorsSet linearizators(stroke, path, data);
Toshihiro Shimizu 890ddd
	CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> cPoints, chunkPoints;</centerlinepoint>
Toshihiro Shimizu 890ddd
	int i, chunksCount = stroke.getChunkCount();
Toshihiro Shimizu 890ddd
	for (i = 0; i < chunksCount; ++i) {
Toshihiro Shimizu 890ddd
		chunkPoints.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CenterlinePoint cp(i, 0.0);
Toshihiro Shimizu 890ddd
		int j, count = data.buildPoints(stroke, path, cp, newPoints);
Toshihiro Shimizu 890ddd
		for (j = 0; j < count; ++j)
Toshihiro Shimizu 890ddd
			chunkPoints.push_back(newPoints[j]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int linearsCount = linearizators.size();
Toshihiro Shimizu 890ddd
		for (j = 0; j < linearsCount; ++j) {
Toshihiro Shimizu 890ddd
			StrokeLinearizator *linearizator = linearizators[j];
Toshihiro Shimizu 890ddd
			linearizator->linearize(chunkPoints, i);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//These points are just PUSH_BACK'd to the vector. A sorting must be performed
Toshihiro Shimizu 890ddd
		//before storing them in the overall centerline points vector
Toshihiro Shimizu 890ddd
		std::stable_sort(chunkPoints.begin(), chunkPoints.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cPoints.insert(cPoints.end(), chunkPoints.begin(), chunkPoints.end());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build the final point.
Toshihiro Shimizu 890ddd
	CenterlinePoint cPoint(chunksCount - 1, 1.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int count = data.buildPoints(stroke, path, cPoint, newPoints);
Toshihiro Shimizu 890ddd
	for (i = 0; i < count; ++i)
Toshihiro Shimizu 890ddd
		cPoints.push_back(newPoints[i]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If no centerline point was built, no outline point can, too.
Toshihiro Shimizu 890ddd
	//This specifically happens when the supplied path is a point.
Toshihiro Shimizu 890ddd
	if (cPoints.empty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//In the selfLoop case, use its info to modify the initial point.
Toshihiro Shimizu 890ddd
	if (stroke.isSelfLoop()) {
Toshihiro Shimizu 890ddd
		CenterlinePoint &lastCp = cPoints[cPoints.size() - 1];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		cPoints[0].m_prevD = cPoint.m_prevD;
Toshihiro Shimizu 890ddd
		cPoints[0].m_hasPrevD = true;
Toshihiro Shimizu 890ddd
		lastCp.m_nextD = cPoint.m_prevD;
Toshihiro Shimizu 890ddd
		lastCp.m_hasNextD = true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef DEBUG_DRAW_TANGENTS
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//Debug - draw centerline directions (derivatives)
Toshihiro Shimizu 890ddd
		glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
		glColor3d(1.0, 0.0, 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		unsigned int i, size = cPoints.size();
Toshihiro Shimizu 890ddd
		for (i = 0; i < size; ++i) {
Toshihiro Shimizu 890ddd
			glVertex2d(cPoints[i].m_p.x, cPoints[i].m_p.y);
Toshihiro Shimizu 890ddd
			glVertex2d(
Toshihiro Shimizu 890ddd
				cPoints[i].m_p.x + cPoints[i].m_nextD.x * cPoints[i].m_p.thick,
Toshihiro Shimizu 890ddd
				cPoints[i].m_p.y + cPoints[i].m_nextD.y * cPoints[i].m_p.thick);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		glEnd();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, build the outline associated to the linearized centerline
Toshihiro Shimizu 890ddd
	buildOutline(stroke, cPoints, outline, data);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
TRectD TOutlineUtil::computeBBox(const TStroke &stroke, const TStroke& path)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  typedef TStroke::OutlineOptions OOpts;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //First, calculate the usual stroke bbox
Toshihiro Shimizu 890ddd
  TRectD roundBBox(::computeBBox(stroke));
Toshihiro Shimizu 890ddd
  const OOpts& oOptions(stroke.outlineOptions());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  if(oOptions.m_capStyle != OOpts::PROJECTING_CAP && oOptions.m_joinStyle != OOpts::MITER_JOIN)
Toshihiro Shimizu 890ddd
    return roundBBox;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //Build interesting centerline points (in this case, junction points)
Toshihiro Shimizu 890ddd
  std::vector<centerlinepoint> cPoints;</centerlinepoint>
Toshihiro Shimizu 890ddd
  int i, chunksCount = stroke.getChunkCount();
Toshihiro Shimizu 890ddd
  for(i=0; i
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    CenterlinePoint cPoint(i, 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    cPoint.buildPos(stroke);
Toshihiro Shimizu 890ddd
    cPoint.buildDirs(stroke);
Toshihiro Shimizu 890ddd
    cPoints.push_back(cPoint);
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //Build the final point.
Toshihiro Shimizu 890ddd
  CenterlinePoint cPoint(chunksCount-1, 1.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  cPoint.buildPos(stroke);
Toshihiro Shimizu 890ddd
  cPoint.buildDirs(stroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //In the selfLoop case, use its info to modify the initial point.
Toshihiro Shimizu 890ddd
  if(stroke.isSelfLoop())
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    cPoints[0].m_prevD = cPoint.m_prevD;
Toshihiro Shimizu 890ddd
    cPoints[0].m_hasPrevD = true;
Toshihiro Shimizu 890ddd
    cPoint.m_nextD = cPoint.m_prevD;
Toshihiro Shimizu 890ddd
    cPoint.m_hasNextD = true;
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  cPoints.push_back(cPoint);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //Now, add the associated 'extending' outline points
Toshihiro Shimizu 890ddd
  OutlineBuilder outBuilder(OutlinizationData(), stroke);
Toshihiro Shimizu 890ddd
  TRectD extensionBBox(
Toshihiro Shimizu 890ddd
    (std::numeric_limits<double>::max)(),</double>
Toshihiro Shimizu 890ddd
    (std::numeric_limits<double>::max)(),</double>
Toshihiro Shimizu 890ddd
    -(std::numeric_limits<double>::max)(),</double>
Toshihiro Shimizu 890ddd
    -(std::numeric_limits<double>::max)()</double>
Toshihiro Shimizu 890ddd
  );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  unsigned int j, cPointsCount = cPoints.size();
Toshihiro Shimizu 890ddd
  for(j=0; ; ++j)
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    //Search the next uncovered point
Toshihiro Shimizu 890ddd
    for(; j < cPointsCount && cPoints[j].m_covered; ++j)
Toshihiro Shimizu 890ddd
      ;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    if(j >= cPointsCount)
Toshihiro Shimizu 890ddd
      break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    //Build the associated outline points
Toshihiro Shimizu 890ddd
    outBuilder.buildOutlineExtensions(extensionBBox, cPoints[j]);
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //Finally, merge the 2 bboxes
Toshihiro Shimizu 890ddd
  return roundBBox + extensionBBox;
Toshihiro Shimizu 890ddd
}
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
void makeCenterline(const TStroke &path, const TEdge &edge, const TRectD ®ionBox,
Toshihiro Shimizu 890ddd
					std::vector<t3dpointd> &outline)</t3dpointd>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int initialOutlineSize = outline.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static const TOutlineUtil::OutlineParameter options;
Toshihiro Shimizu 890ddd
	const TStroke &stroke = *edge.m_s;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double w0 = edge.m_w0, w1 = edge.m_w1;
Toshihiro Shimizu 890ddd
	bool reversed = w1 < w0;
Toshihiro Shimizu 890ddd
	if (reversed)
Toshihiro Shimizu 890ddd
		w0 = edge.m_w1, w1 = edge.m_w0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build outlinization data
Toshihiro Shimizu 890ddd
	StrokeOutlinizationData data(stroke, regionBox, options);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build a set of linearizators for the specified stroke
Toshihiro Shimizu 890ddd
	LinearizatorsSet linearizators(stroke, path, data);
Toshihiro Shimizu 890ddd
	CenterlinePoint newPoints[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	linearizators.m_recursiveRefLinearizator.m_subdivisor =
Toshihiro Shimizu 890ddd
		&RecursiveReferenceLinearizator::subdivideCenterline;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<centerlinepoint> chunkPoints;</centerlinepoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i, chunk0, chunk1;
Toshihiro Shimizu 890ddd
	double t0, t1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool ok0 = !edge.m_s->getChunkAndT(w0, chunk0, t0);
Toshihiro Shimizu 890ddd
	bool ok1 = !edge.m_s->getChunkAndT(w1, chunk1, t1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ok0 && ok1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double tStart = t0;
Toshihiro Shimizu 890ddd
	for (i = chunk0; i < chunk1; ++i, tStart = 0.0) {
Toshihiro Shimizu 890ddd
		chunkPoints.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CenterlinePoint cp(i, tStart);
Toshihiro Shimizu 890ddd
		int j, count = data.buildPoints(stroke, path, cp, newPoints);
Toshihiro Shimizu 890ddd
		for (j = 0; j < count; ++j)
Toshihiro Shimizu 890ddd
			chunkPoints.push_back(newPoints[j]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int linearsCount = linearizators.size();
Toshihiro Shimizu 890ddd
		for (j = 0; j < linearsCount; ++j) {
Toshihiro Shimizu 890ddd
			ReferenceLinearizator *linearizator = linearizators[j];
Toshihiro Shimizu 890ddd
			linearizator->linearize(chunkPoints, i, 1.0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//These points are just PUSH_BACK'd to the vector. A sorting must be performed
Toshihiro Shimizu 890ddd
		//before storing them in the overall centerline points vector
Toshihiro Shimizu 890ddd
		std::stable_sort(chunkPoints.begin(), chunkPoints.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int size = chunkPoints.size();
Toshihiro Shimizu 890ddd
		outline.reserve(outline.size() + size);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (j = 0; j < size; ++j) {
Toshihiro Shimizu 890ddd
			const TPointD &point = chunkPoints[j].m_p;
Toshihiro Shimizu 890ddd
			outline.push_back(T3DPointD(point.x, point.y, 0.0));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//The last one with t1 as endpoint
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		chunkPoints.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CenterlinePoint cp(chunk1, tStart);
Toshihiro Shimizu 890ddd
		int j, count = data.buildPoints(stroke, path, cp, newPoints);
Toshihiro Shimizu 890ddd
		for (j = 0; j < count; ++j)
Toshihiro Shimizu 890ddd
			chunkPoints.push_back(newPoints[j]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int linearsCount = linearizators.size();
Toshihiro Shimizu 890ddd
		for (j = 0; j < linearsCount; ++j) {
Toshihiro Shimizu 890ddd
			ReferenceLinearizator *linearizator = linearizators[j];
Toshihiro Shimizu 890ddd
			linearizator->linearize(chunkPoints, chunk1, t1);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::stable_sort(chunkPoints.begin(), chunkPoints.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int size = chunkPoints.size();
Toshihiro Shimizu 890ddd
		outline.reserve(outline.size() + size);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (j = 0; j < size; ++j) {
Toshihiro Shimizu 890ddd
			const TPointD &point = chunkPoints[j].m_p;
Toshihiro Shimizu 890ddd
			outline.push_back(T3DPointD(point.x, point.y, 0.0));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, add the endpoint
Toshihiro Shimizu 890ddd
	CenterlinePoint cp(chunk1, t1);
Toshihiro Shimizu 890ddd
	int j, count = data.buildPoints(stroke, path, cp, newPoints);
Toshihiro Shimizu 890ddd
	for (j = 0; j < count; ++j) {
Toshihiro Shimizu 890ddd
		const TPointD &point = newPoints[j].m_p;
Toshihiro Shimizu 890ddd
		outline.push_back(T3DPointD(point.x, point.y, 0.0));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Eventually, reverse the output
Toshihiro Shimizu 890ddd
	if (reversed)
Toshihiro Shimizu 890ddd
		std::reverse(outline.begin() + initialOutlineSize, outline.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void makeOutlineRaw(const TStroke &path, const TRegion ®ion, const TRectD ®ionBox,
Toshihiro Shimizu 890ddd
					std::vector<t3dpointd> &outline)</t3dpointd>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Deal with each edge independently
Toshihiro Shimizu 890ddd
	int e, edgesCount = region.getEdgeCount();
Toshihiro Shimizu 890ddd
	for (e = 0; e < edgesCount; ++e)
Toshihiro Shimizu 890ddd
		makeCenterline(path, *region.getEdge(e), regionBox, outline);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TOutlineUtil::makeOutline(const TStroke &path, const TRegion ®ion, const TRectD ®ionBox,
Toshihiro Shimizu 890ddd
							   TRegionOutline &outline)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	outline.m_doAntialiasing = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build the external boundary
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		outline.m_exterior.resize(1);
Toshihiro Shimizu 890ddd
		outline.m_exterior[0].clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		makeOutlineRaw(path, region, regionBox, outline.m_exterior[0]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build internal boundaries
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		outline.m_interior.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i, subRegionNumber = region.getSubregionCount();
Toshihiro Shimizu 890ddd
		outline.m_interior.resize(subRegionNumber);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i < subRegionNumber; i++)
Toshihiro Shimizu 890ddd
			makeOutlineRaw(path, *region.getSubregion(i), regionBox, outline.m_interior[i]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	outline.m_bbox = region.getBBox();
Toshihiro Shimizu 890ddd
}