ultimatepp/uppsrc/Painter/Approximate.cpp
cxl dd88989c82 Painter fixed to work in Linux, MoveableWithSwap removed (GCC problems, possibly undefined behaviour of code)
git-svn-id: svn://ultimatepp.org/upp/trunk@867 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-02-15 13:11:54 +00:00

89 lines
2.4 KiB
C++

#include "Painter.h"
NAMESPACE_UPP
static void sQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p3 - p1;
double q = Squared(d);
if(q > 1e-30) {
Pointf pd = p2 - p1;
double u = (pd.x * d.x + pd.y * d.y) / q;
if(u <= 0 || u >= 1 || SquaredDistance(u * d, pd) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf div = Mid(p12, p23);
sQuadratic(t, p1, p12, div, qt, lvl + 1);
sQuadratic(t, div, p23, p3, qt, lvl + 1);
return;
}
}
}
t.Line(p3);
}
void ApproximateQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double tolerance)
{
sQuadratic(t, p1, p2, p3, tolerance * tolerance, 0);
t.Line(p3);
}
static void sCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double qt, int lvl)
{
if(lvl < 16) {
Pointf d = p4 - p1;
double q = d.x * d.x + d.y * d.y;
if(q >= 1e-30) {
Pointf d2 = p2 - p1;
Pointf d3 = p3 - p1;
double u1 = (d2.x * d.x + d2.y * d.y) / q;
double u2 = (d3.x * d.x + d3.y * d.y) / q;
if(u1 <= 0 || u1 >= 1 || u2 <= 0 || u2 >= 1 ||
SquaredDistance(u1 * d, d2) > qt || SquaredDistance(u2 * d, d3) > qt) {
Pointf p12 = Mid(p1, p2);
Pointf p23 = Mid(p2, p3);
Pointf p34 = Mid(p3, p4);
Pointf p123 = Mid(p12, p23);
Pointf p234 = Mid(p23, p34);
Pointf div = Mid(p123, p234);
Pointf p14 = Mid(p1, p4);
sCubic(t, p1, p12, p123, div, qt, lvl + 1);
sCubic(t, div, p234, p34, p4, qt, lvl + 1);
return;
}
}
}
t.Line(p4);
}
void ApproximateCubic(LinearPathConsumer& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double tolerance)
{
sCubic(t, p1, p2, p3, p4, tolerance * tolerance, 0);
t.Line(p4);
}
void ApproximateArc(LinearPathConsumer& t, const Pointf& c, const Pointf& r,
double angle, double sweep, double tolerance)
{
while(angle + sweep < 0)
angle += 2000 * M_PI;
double fid = acos(1 - tolerance / max(r.x, r.y));
if(fabs(sweep / fid) > 1000)
fid = sweep / 1000;
double a = angle;
double e = angle + sweep;
while(fid > 0 ? a < e : a > e) {
t.Line(Polar(a) * r + c);
a += fid;
}
t.Line(Polar(angle + sweep) * r + c);
}
END_UPP_NAMESPACE