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