Stroker finished!

git-svn-id: svn://ultimatepp.org/upp/trunk@839 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-06 18:31:20 +00:00
parent 9e72828045
commit f9554adb2d
15 changed files with 549 additions and 143 deletions

View file

@ -1,16 +1,7 @@
#include "ScanLine.h"
double SquareDist(Pointf p1, Pointf p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
Pointf Mid(Pointf a, Pointf b)
{
return (a + b) / 2;
}
static void sQuadratic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, double qt, int lvl)
static void sQuadratic(VertexTarget& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
double qt, int lvl)
{
if(lvl < 32) {
Pointf d = p3 - p1;
@ -31,14 +22,16 @@ static void sQuadratic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, double
t.Line(p3);
}
void ApproximateQuadratic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, double tolerance)
void ApproximateQuadratic(VertexTarget& 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(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, Pointf p4, double qt,
int lvl)
static void sCubic(VertexTarget& t,
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
double qt, int lvl)
{
if(lvl < 32) {
Pointf d = p4 - p1;
@ -66,7 +59,9 @@ static void sCubic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, Pointf p4,
t.Line(p4);
}
void ApproximateCubic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, Pointf p4, double tolerance)
void ApproximateCubic(VertexTarget& 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);

51
uppdev/ScanLine/Math.cpp Normal file
View file

@ -0,0 +1,51 @@
#include "ScanLine.h"
double SquareDist(const Pointf& p1, const Pointf& p2)
{
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
Pointf Mid(const Pointf& a, const Pointf& b)
{
return (a + b) / 2;
}
Pointf Ortogonal(const Pointf& p)
{
return Pointf(-p.y, p.x);
}
double SquareLength(const Pointf& p)
{
return p.x * p.x + p.y * p.y;
}
double Length(const Pointf& p)
{
return sqrt(SquareLength(p));
}
double Bearing(const Pointf& p)
{
return atan2(p.y, p.x);
}
double Distance(const Pointf& p1, const Pointf& p2)
{
return Length(p1 - p2);
}
double SquareDistance(const Pointf& p1, const Pointf& p2)
{
return SquareLength(p1 - p2);
}
Pointf PolarPointf(double a)
{
return Pointf(cos(a), sin(a));
}
Pointf Polar(const Pointf& p, double r, double a)
{
return p + r * PolarPointf(a);
}

View file

@ -8,7 +8,7 @@ void Rasterizer::Move(double x, double y)
inline int Cv(double x)
{
return int(x * 256 + 0.5);
return fround(x * 256);
}
void Rasterizer::CvLine(double x1, double y1, double x2, double y2)

View file

@ -65,28 +65,66 @@ struct ScanLine {
void Render(ImageBuffer& ib, Rasterizer& r, const RGBA& color, bool evenodd);
double SquareDist(const Pointf& p1, const Pointf& p2);
Pointf Mid(const Pointf& a, const Pointf& b);
Pointf Ortogonal(const Pointf& p);
double SquareLength(const Pointf& p);
double Length(const Pointf& p);
double Bearing(const Pointf& p);
double Distance(const Pointf& p1, const Pointf& p2);
double SquareDistance(const Pointf& p1, const Pointf& p2);
Pointf PolarPointf(double a);
Pointf Polar(const Pointf& p, double r, double a);
struct VertexTarget {
virtual void Move(Pointf p) = 0;
virtual void Line(Pointf p) = 0;
virtual void Move(const Pointf& p) = 0;
virtual void Line(const Pointf& p) = 0;
virtual void End() = 0;
};
struct VertexProcessor : VertexTarget {
VertexTarget *target;
void PutMove(const Pointf& p) { target->Move(p); }
void PutLine(const Pointf& p) { target->Line(p); }
void PutEnd() { target->End(); }
VertexProcessor& operator|(VertexProcessor& b) { target = &b; return b; }
void operator|(VertexTarget& b) { target = &b; }
};
class Stroker : VertexProcessor {
public:
virtual void Move(double x, double y);
virtual void Line(double x, double y);
virtual void End();
enum {
LINECAP_BUTT,
LINECAP_SQUARE,
LINECAP_ROUND,
LINEJOIN_MITER,
LINEJOIN_ROUND,
LINEJOIN_BEVEL,
};
class Dasher : VertexProcessor {
class Stroker : public VertexProcessor {
double w2;
double qmiter;
double fid;
Pointf p0, v0, o0, a0, b0;
Pointf p1, v1, o1, a1, b1;
Pointf p2;
int linecap;
int linejoin;
void Finish();
void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r);
void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0,
const Pointf& a0, const Pointf& b0);
public:
virtual void Move(double x, double y);
virtual void Line(double x, double y);
virtual void Move(const Pointf& p);
virtual void Line(const Pointf& p);
virtual void End();
Stroker(double width, double miterlimit, double tolerance, int linecap, int linejoin);
};
class Transformer : VertexProcessor {
@ -96,10 +134,8 @@ public:
virtual void End();
};
double SquareDist(Pointf p1, Pointf p2);
void ApproximateQuadratic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, double tolerance);
void ApproximateCubic(VertexTarget& t, Pointf x0, Pointf x1, Pointf x2, Pointf x, double tolerance);
void ApproximateQuadratic(VertexTarget& t, const Pointf& p1, const Pointf& p2, const Pointf& p3, double tolerance);
void ApproximateCubic(VertexTarget& t, const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x, double tolerance);
#define Painter NewPainter

View file

@ -14,7 +14,9 @@ file
Rasterizer3.h,
Rasterizer3.cpp,
RasterizerClip.cpp,
Math.cpp,
Bezier.cpp,
Stroker.cpp,
Path.cpp,
help.txt,
Lion.cpp,

150
uppdev/ScanLine/Stroker.cpp Normal file
View file

@ -0,0 +1,150 @@
#include "ScanLine.h"
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)
{
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)
{
if(p3 == p2)
return;
if(IsNull(p1)) {
Move(p3);
return;
}
if(IsNull(p2)) {
p2 = p3;
v1 = p2 - p1;
o1 = Ortogonal(v1) * w2 / Length(v1);
a1 = p1 + o1;
b1 = p1 - o1;
if(IsNull(p0)) {
p0 = p1;
v0 = v1;
o0 = o1;
a0 = a1;
b0 = b1;
}
return;
}
Pointf v2 = p3 - p2;
Pointf o2 = Ortogonal(v2) * w2 / Length(v2);
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))
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);
}
p1 = p2 = Null;
PutEnd();
}
void Stroker::End()
{
Finish();
}

View file

@ -14,6 +14,8 @@ struct Raget : VertexTarget {
struct App : TopWindow {
double x1, y1, x2, y2, x3, y3;
Pointf p1, p2, p3, p4;
String Text() {
return Format("r.Move(%f, %f);\nr.Line(%f, %f);\nr.Line(%f, %f);\nr.Line(%f, %f);\n", x1, y1, x2, y2, x3, y3, x1, y1);
@ -21,30 +23,24 @@ struct App : TopWindow {
virtual void LeftDown(Point p, dword keyflags)
{
x1 = p.x;
y1 = p.y;
(keyflags & K_ALT ? p4 : p1) = p;
Refresh();
ClearClipboard();
AppendClipboardText(Text());
}
virtual void RightDown(Point p, dword)
{
x2 = p.x;
y2 = p.y;
p2 = p;
Refresh();
ClearClipboard();
AppendClipboardText(Text());
}
virtual void MouseMove(Point p, dword keyflags)
{
x3 = p.x;
y3 = p.y;
p2 = p;
Refresh();
ClearClipboard();
AppendClipboardText(Text());
}
virtual Image CursorImage(Point p, dword keyflags) { return Image::Cross(); }
virtual void Paint(Draw& w) {
virtual void Paint(Draw& w);
virtual void Paint1(Draw& w) {
ImageBuffer ib(600, 600);
Fill(~ib, White(), ib.GetLength());
/* Apply(ib[20], 100, Black(), a);
@ -72,15 +68,14 @@ struct App : TopWindow {
r.Line(x1, y1);
#endif
Raget q(r);
#if 1
r.Move(200, 300);
ApproximateQuadratic(q, Pointf(200, 300), Pointf(400, 50), Pointf(600, 300), 0.3);
// ApproximateQuadratic(q, Pointf(200, 300), Pointf(400, 50), Pointf(600, 300), 0.3);
r.Line(200, 300);
Render(ib, r, Red(), false);
#endif
r.Move(100, 200);
ApproximateCubic(q, Pointf(100, 200), Pointf(100, 100), Pointf(250, 100), Pointf(250, 200), 2);
// ApproximateCubic(q, Pointf(100, 200), Pointf(100, 100), Pointf(250, 100), Pointf(250, 200), 2);
r.Line(150, 400);
r.Line(100, 200);
Render(ib, r, Blue(), false);
@ -99,10 +94,87 @@ struct App : TopWindow {
}
App() {
x1 = y1 = x2 = y2 = 0;
p1 = p4 = Pointf(100, 100);
p2 = Pointf(200, 100);
p3 = Pointf(150, 200);
}
};
struct RasterizerTarget : VertexTarget {
Rasterizer& r;
ImageBuffer& ib;
virtual void Line(const Pointf& p)
{
r.Line(p.x, p.y);
}
virtual void Move(const Pointf& p)
{
r.Move(p.x, p.y);
}
virtual void End()
{
Render(ib, r, Black(), false);
}
RasterizerTarget(ImageBuffer& ib, Rasterizer& r) : ib(ib), r(r) {}
};
#if 1
void App::Paint(Draw& w)
{
Size sz = GetSize();
ImageBuffer ib(sz.cx, sz.cy);
Rasterizer r(sz.cx, sz.cy);
Fill(~ib, White(), ib.GetLength());
RasterizerTarget tgt(ib, r);
Stroker s(20, 4, 0.3, LINECAP_ROUND, LINEJOIN_ROUND);
s|tgt;
s.Move(p1);
s.Line(p2);
// s.Line(p3);
// s.Line(p4);
s.End();
w.DrawImage(0, 0, ib);
}
#else
struct LineTarget : VertexTarget {
Draw& w;
Pointf p;
virtual void Line(const Pointf& p1)
{
w.DrawLine(p.x, p.y, p1.x, p1.y);
p = p1;
}
virtual void Move(const Pointf& p1)
{
p = p1;
}
virtual void End() {}
LineTarget(Draw& w) : w(w) {}
};
void App::Paint(Draw& w)
{
w.DrawRect(GetSize(), White());
LineTarget ltg(w);
Stroker s(20, 4, 0.3, LINECAP_ROUND, LINEJOIN_ROUND);
s|ltg;
s.Move(p1);
s.Line(p2);
// s.Line(p3);
// s.Line(p4);
s.End();
}
#endif
GUI_APP_MAIN {
App().Run();
#ifdef _DEBUG