ultimatepp/uppdev/ScanLine/Stroker.cpp
cxl 2e4b276e07 Merge continued
git-svn-id: svn://ultimatepp.org/upp/trunk@10263 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-10-04 08:34:39 +00:00

168 lines
3 KiB
C++

#include "ScanLine.h"
#define LLOG(x) LOG(x)
void LinearPathConsumer::End()
{
}
void LinearPathFilter::End()
{
PutEnd();
}
Stroker::Stroker(double width, double miterlimit, double tolerance, int linecap, int linejoin)
: linecap(linecap),
linejoin(linejoin)
{
w2 = width / 2;
qmiter = miterlimit * w2;
qmiter *= qmiter;
fid = acos(1 - tolerance / w2);
p0 = p1 = p2 = Null;
}
void Stroker::Move(const Pointf& p)
{
LLOG("Stroker::Move " << p);
Finish();
p1 = p;
p0 = p2 = Null;
}
void Stroker::Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r)
{
double tolerance = 0.3;
double a1 = Bearing(v1);
double a2 = Bearing(v2);
if(a1 < a2)
a1 += 2 * M_PI;
while(a1 > a2) {
PutLine(Polar(p, r, a1));
a1 -= fid;
}
}
void Stroker::Line(const Pointf& p3)
{
LLOG("Stroker::Line " << p3);
if(IsNull(p1)) {
Move(p3);
return;
}
if(IsNull(p2)) {
Pointf v = p3 - p1;
double l = Length(v);
if(l < 1e-30)
return;
p2 = p3;
v1 = v;
o1 = Ortogonal(v1) * w2 / l;
a1 = p1 + o1;
b1 = p1 - o1;
if(IsNull(p0)) {
p0 = p1;
v0 = v1;
o0 = o1;
a0 = a1;
b0 = b1;
}
return;
}
Pointf v2 = p3 - p2;
double l = Length(v2);
if(l < 1e-30)
return;
Pointf o2 = Ortogonal(v2) * w2 / l;
Pointf a2 = p2 + o2;
Pointf b2 = p2 - o2;
double d = v1.y * v2.x - v2.y * v1.x;
if(d > 1e-30) {
Pointf ts = a1 + v1 * (v2.y * (a1.x - a2.x) - v2.x * (a1.y - a2.y)) / d;
PutMove(a1);
if(linejoin != LINEJOIN_MITER || SquareDistance(ts, p2) > qmiter) {
PutLine(a1 + v1);
if(linejoin == LINEJOIN_ROUND)
Round(p2, o1, o2, w2);
}
else
PutLine(ts);
PutLine(a2);
PutMove(b2);
PutLine(p2);
PutLine(b1 + v1);
PutLine(b1);
}
else
if(d < -1e-30) {
Pointf ts = b2 + v2 * (v1.y * (a2.x - a1.x) - v1.x * (a2.y - a1.y)) / d;
PutMove(b2);
if(linejoin != LINEJOIN_MITER || SquareDistance(ts, p2) > qmiter) {
if(linejoin == LINEJOIN_ROUND)
Round(p2, -o2, -o1, w2);
PutLine(b1 + v1);
}
else
PutLine(ts);
PutLine(b1);
PutMove(a1);
PutLine(a1 + v1);
PutLine(p2);
PutLine(a2);
}
else {
PutMove(a1);
PutLine(a1 + v1);
if(linejoin == LINEJOIN_ROUND)
Round(p2, o1, o2, w2);
PutLine(a2);
PutMove(b2);
PutLine(b1 + v1);
PutLine(b1);
}
p1 = p2;
v1 = v2;
o1 = o2;
a1 = a2;
b1 = b2;
p2 = p3;
}
void Stroker::Cap(const Pointf& p, const Pointf& v, const Pointf& o,
const Pointf& a, const Pointf& b)
{
PutMove(a);
if(linecap == LINECAP_SQUARE) {
Pointf nv = Ortogonal(o);
PutLine(a + nv);
PutLine(b + nv);
}
if(linecap == LINECAP_ROUND)
Round(p, -o, o, w2);
PutLine(b);
}
void Stroker::Finish()
{
if(IsNull(p1) || IsNull(p2) || IsNull(p0))
return;
if(p2 == p0)
Line(p0 + v0);
else {
PutMove(a1);
PutLine(a1 + v1);
PutMove(b1 + v1);
PutLine(b1);
Cap(p0, v0, o0, b0, a0);
Cap(p2, -v1, -o1, a1 + v1, b1 + v1);
}
p0 = p1 = p2 = Null;
}
void Stroker::End()
{
Finish();
PutEnd();
}