mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Stroker finished!
git-svn-id: svn://ultimatepp.org/upp/trunk@839 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
8cd18d22a0
commit
68c2a1caaa
15 changed files with 549 additions and 143 deletions
|
|
@ -1,12 +1,11 @@
|
||||||
uses
|
uses
|
||||||
CtrlLib;
|
CtrlLib,
|
||||||
|
Geom;
|
||||||
|
|
||||||
file
|
file
|
||||||
"GeomTest.h"
|
GeomTest.h,
|
||||||
, main.cpp
|
main.cpp;
|
||||||
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
mainconfig
|
mainconfig
|
||||||
"" = "GUI ST";
|
"" = "GUI ST";
|
||||||
|
|
||||||
|
|
|
||||||
5
uppdev/GeomTest/init
Normal file
5
uppdev/GeomTest/init
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#ifndef _GeomTest_icpp_init_stub
|
||||||
|
#define _GeomTest_icpp_init_stub
|
||||||
|
#include "CtrlLib/init"
|
||||||
|
#include "Geom/init"
|
||||||
|
#endif
|
||||||
|
|
@ -40,14 +40,14 @@ GUI_APP_MAIN
|
||||||
for(int i = 0; i < 10; i++) {
|
for(int i = 0; i < 10; i++) {
|
||||||
int a, b;
|
int a, b;
|
||||||
do {
|
do {
|
||||||
a = Random(20) + 1;
|
a = Random(35) + 1;
|
||||||
b = Random(20) + 1;
|
b = Random(35) + 1;
|
||||||
}
|
}
|
||||||
while(a + b < 0 || a + b > 20);
|
while(a + b < 0 || a + b > 20);
|
||||||
r.DrawText(10, 10 + isz.cy * 2 * i, Format("%d + %d = ", a, b), fnt);
|
r.DrawText(10, 10 + isz.cy * 2 * i, Format("%d + %d = ", a, b), fnt);
|
||||||
do {
|
do {
|
||||||
a = Random(20) + 1;
|
a = Random(35) + 1;
|
||||||
b = Random(20) + 1;
|
b = Random(35) + 1;
|
||||||
}
|
}
|
||||||
while(a - b < 0);
|
while(a - b < 0);
|
||||||
r.DrawText(2000, 10 + isz.cy * 2 * i, Format("%d - %d = ", a, b), fnt);
|
r.DrawText(2000, 10 + isz.cy * 2 * i, Format("%d - %d = ", a, b), fnt);
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,7 @@
|
||||||
#include "ScanLine.h"
|
#include "ScanLine.h"
|
||||||
|
|
||||||
double SquareDist(Pointf p1, Pointf p2)
|
static void sQuadratic(VertexTarget& t, const Pointf& p1, const Pointf& p2, const Pointf& p3,
|
||||||
{
|
double qt, int lvl)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if(lvl < 32) {
|
if(lvl < 32) {
|
||||||
Pointf d = p3 - p1;
|
Pointf d = p3 - p1;
|
||||||
|
|
@ -31,14 +22,16 @@ static void sQuadratic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, double
|
||||||
t.Line(p3);
|
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);
|
sQuadratic(t, p1, p2, p3, tolerance * tolerance, 0);
|
||||||
t.Line(p3);
|
t.Line(p3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sCubic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, Pointf p4, double qt,
|
static void sCubic(VertexTarget& t,
|
||||||
int lvl)
|
const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4,
|
||||||
|
double qt, int lvl)
|
||||||
{
|
{
|
||||||
if(lvl < 32) {
|
if(lvl < 32) {
|
||||||
Pointf d = p4 - p1;
|
Pointf d = p4 - p1;
|
||||||
|
|
@ -66,7 +59,9 @@ static void sCubic(VertexTarget& t, Pointf p1, Pointf p2, Pointf p3, Pointf p4,
|
||||||
t.Line(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);
|
sCubic(t, p1, p2, p3, p4, tolerance * tolerance, 0);
|
||||||
t.Line(p4);
|
t.Line(p4);
|
||||||
|
|
|
||||||
51
uppdev/ScanLine/Math.cpp
Normal file
51
uppdev/ScanLine/Math.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ void Rasterizer::Move(double x, double y)
|
||||||
|
|
||||||
inline int Cv(double x)
|
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)
|
void Rasterizer::CvLine(double x1, double y1, double x2, double y2)
|
||||||
|
|
|
||||||
|
|
@ -65,28 +65,66 @@ struct ScanLine {
|
||||||
|
|
||||||
void Render(ImageBuffer& ib, Rasterizer& r, const RGBA& color, bool evenodd);
|
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 {
|
struct VertexTarget {
|
||||||
virtual void Move(Pointf p) = 0;
|
virtual void Move(const Pointf& p) = 0;
|
||||||
virtual void Line(Pointf p) = 0;
|
virtual void Line(const Pointf& p) = 0;
|
||||||
virtual void End() = 0;
|
virtual void End() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexProcessor : VertexTarget {
|
struct VertexProcessor : VertexTarget {
|
||||||
VertexTarget *target;
|
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 {
|
enum {
|
||||||
public:
|
LINECAP_BUTT,
|
||||||
virtual void Move(double x, double y);
|
LINECAP_SQUARE,
|
||||||
virtual void Line(double x, double y);
|
LINECAP_ROUND,
|
||||||
virtual void End();
|
|
||||||
|
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:
|
public:
|
||||||
virtual void Move(double x, double y);
|
virtual void Move(const Pointf& p);
|
||||||
virtual void Line(double x, double y);
|
virtual void Line(const Pointf& p);
|
||||||
virtual void End();
|
virtual void End();
|
||||||
|
|
||||||
|
Stroker(double width, double miterlimit, double tolerance, int linecap, int linejoin);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Transformer : VertexProcessor {
|
class Transformer : VertexProcessor {
|
||||||
|
|
@ -96,10 +134,8 @@ public:
|
||||||
virtual void End();
|
virtual void End();
|
||||||
};
|
};
|
||||||
|
|
||||||
double SquareDist(Pointf p1, Pointf p2);
|
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);
|
||||||
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);
|
|
||||||
|
|
||||||
#define Painter NewPainter
|
#define Painter NewPainter
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ file
|
||||||
Rasterizer3.h,
|
Rasterizer3.h,
|
||||||
Rasterizer3.cpp,
|
Rasterizer3.cpp,
|
||||||
RasterizerClip.cpp,
|
RasterizerClip.cpp,
|
||||||
|
Math.cpp,
|
||||||
Bezier.cpp,
|
Bezier.cpp,
|
||||||
|
Stroker.cpp,
|
||||||
Path.cpp,
|
Path.cpp,
|
||||||
help.txt,
|
help.txt,
|
||||||
Lion.cpp,
|
Lion.cpp,
|
||||||
|
|
|
||||||
150
uppdev/ScanLine/Stroker.cpp
Normal file
150
uppdev/ScanLine/Stroker.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
@ -15,36 +15,32 @@ struct Raget : VertexTarget {
|
||||||
struct App : TopWindow {
|
struct App : TopWindow {
|
||||||
double x1, y1, x2, y2, x3, y3;
|
double x1, y1, x2, y2, x3, y3;
|
||||||
|
|
||||||
|
Pointf p1, p2, p3, p4;
|
||||||
|
|
||||||
String Text() {
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void LeftDown(Point p, dword keyflags)
|
virtual void LeftDown(Point p, dword keyflags)
|
||||||
{
|
{
|
||||||
x1 = p.x;
|
(keyflags & K_ALT ? p4 : p1) = p;
|
||||||
y1 = p.y;
|
|
||||||
Refresh();
|
Refresh();
|
||||||
ClearClipboard();
|
|
||||||
AppendClipboardText(Text());
|
|
||||||
}
|
}
|
||||||
virtual void RightDown(Point p, dword)
|
virtual void RightDown(Point p, dword)
|
||||||
{
|
{
|
||||||
x2 = p.x;
|
p2 = p;
|
||||||
y2 = p.y;
|
|
||||||
Refresh();
|
Refresh();
|
||||||
ClearClipboard();
|
|
||||||
AppendClipboardText(Text());
|
|
||||||
}
|
}
|
||||||
virtual void MouseMove(Point p, dword keyflags)
|
virtual void MouseMove(Point p, dword keyflags)
|
||||||
{
|
{
|
||||||
x3 = p.x;
|
p2 = p;
|
||||||
y3 = p.y;
|
|
||||||
Refresh();
|
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);
|
ImageBuffer ib(600, 600);
|
||||||
Fill(~ib, White(), ib.GetLength());
|
Fill(~ib, White(), ib.GetLength());
|
||||||
/* Apply(ib[20], 100, Black(), a);
|
/* Apply(ib[20], 100, Black(), a);
|
||||||
|
|
@ -72,15 +68,14 @@ struct App : TopWindow {
|
||||||
r.Line(x1, y1);
|
r.Line(x1, y1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Raget q(r);
|
|
||||||
#if 1
|
#if 1
|
||||||
r.Move(200, 300);
|
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);
|
r.Line(200, 300);
|
||||||
Render(ib, r, Red(), false);
|
Render(ib, r, Red(), false);
|
||||||
#endif
|
#endif
|
||||||
r.Move(100, 200);
|
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(150, 400);
|
||||||
r.Line(100, 200);
|
r.Line(100, 200);
|
||||||
Render(ib, r, Blue(), false);
|
Render(ib, r, Blue(), false);
|
||||||
|
|
@ -99,10 +94,87 @@ struct App : TopWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
App() {
|
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 {
|
GUI_APP_MAIN {
|
||||||
App().Run();
|
App().Run();
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
#define _Stroke_icpp_init_stub
|
#define _Stroke_icpp_init_stub
|
||||||
#include "CtrlLib/init"
|
#include "CtrlLib/init"
|
||||||
#include "Painter/init"
|
#include "Painter/init"
|
||||||
|
#include "Geom/init"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ struct App : TopWindow {
|
||||||
Pointf p1;
|
Pointf p1;
|
||||||
Pointf p2;
|
Pointf p2;
|
||||||
Pointf p3;
|
Pointf p3;
|
||||||
|
bool round;
|
||||||
|
|
||||||
virtual void LeftDown(Point p, dword keyflags);
|
virtual void LeftDown(Point p, dword keyflags);
|
||||||
virtual void MouseMove(Point p, dword keyflags);
|
virtual void MouseMove(Point p, dword keyflags);
|
||||||
virtual void Paint(Draw& w);
|
virtual void Paint(Draw& w);
|
||||||
|
virtual Image CursorImage(Point p, dword keyflags) { return Image::Cross(); }
|
||||||
|
|
||||||
App() { BackPaint(); p2 = p3 = Pointf(0.0, 0.0); p1 = Pointf(300.0, 300.0); }
|
App() { BackPaint(); p2 = Pointf(1195, 300); p3 = Pointf(500.0, 300.0); p1 = Pointf(300.0, 300.0); round = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
Pointf Ortogonal(Pointf p)
|
Pointf Ortogonal(Pointf p)
|
||||||
|
|
@ -20,41 +22,26 @@ Pointf Ortogonal(Pointf p)
|
||||||
return Pointf(-p.y, p.x);
|
return Pointf(-p.y, p.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SquareLength(Pointf p)
|
||||||
|
{
|
||||||
|
return p.x * p.x + p.y * p.y;
|
||||||
|
}
|
||||||
|
|
||||||
double Length(Pointf p)
|
double Length(Pointf p)
|
||||||
{
|
{
|
||||||
return sqrt(p.x * p.x + p.y * p.y);
|
return sqrt(SquareLength(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
double Intersection0(Pointf p1, Pointf v1, Pointf p2, Pointf v2)
|
double Bearing(Pointf p)
|
||||||
{
|
{
|
||||||
// p1.x + v1.x * t1 = p2.x + v2.x * t2;
|
if(p.y == 0)
|
||||||
// p1.y + v1.y * t1 = p2.y + v2.y * t2;
|
return (p.x >= 0 ? 0 : M_PI);
|
||||||
// t2 = (p1.x + v1.x * t1 - p2.x) / v2.x
|
if(p.x == 0)
|
||||||
// m2 = v2.y / v2.x;
|
return (p.y >= 0 ? M_PI_2 : 3 * M_PI_2);
|
||||||
// p1.y + v1.y * t1 = p2.y + v2.y * (p1.x + v1.x * t1 - p2.x) / v2.x;
|
double b = atan2(p.y, p.x);
|
||||||
// p1.y + v1.y * t1 = p2.y + m2 * p1.x + m2 * v1.x * t1 - m2 * p2.x;
|
if(b < 0)
|
||||||
|
b += 2 * M_PI;
|
||||||
// p1.y + v1.y * t1 = ;
|
return b;
|
||||||
// v1.y * t1 - m2 * v1.x * t1 = p2.y + m2 * p1.x - m2 * p2.x - p1.y;
|
|
||||||
// t1 = (p2.y + m2 * p1.x - m2 * p2.x - p1.y) / (v1.y - m2 * v1.x)
|
|
||||||
double m2 = v2.y / v2.x;
|
|
||||||
return (p2.y - p1.y + m2 * (p1.x - p2.x)) / (v1.y - m2 * v1.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointf Swapped(Pointf p)
|
|
||||||
{
|
|
||||||
return Pointf(p.y, p.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Intersection(Pointf p1, Pointf v1, Pointf p2, Pointf v2)
|
|
||||||
{
|
|
||||||
return v2.x < 1e-30 ? Intersection0(Swapped(p1), Swapped(v1), Swapped(p2), Swapped(v2))
|
|
||||||
: Intersection0(p1, v1, p2, v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointf Mirror(Pointf c, Pointf p)
|
|
||||||
{
|
|
||||||
return 2 * c - p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double Distance(Pointf p1, Pointf p2)
|
double Distance(Pointf p1, Pointf p2)
|
||||||
|
|
@ -62,6 +49,14 @@ double Distance(Pointf p1, Pointf p2)
|
||||||
return Length(p1 - p2);
|
return Length(p1 - p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double SquareDistance(Pointf p1, Pointf p2)
|
||||||
|
{
|
||||||
|
return SquareLength(p1 - p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointf PolarPointf(double a) { return Pointf(cos(a), sin(a)); }
|
||||||
|
Pointf Polar(Pointf p, double r, double a) { return p + r * PolarPointf(a) ; }
|
||||||
|
|
||||||
void App::LeftDown(Point p, dword keyflags)
|
void App::LeftDown(Point p, dword keyflags)
|
||||||
{
|
{
|
||||||
p3 = p;
|
p3 = p;
|
||||||
|
|
@ -74,79 +69,125 @@ void App::MouseMove(Point p, dword keyflags)
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Round(Painter& sw, Pointf p, Pointf v1, Pointf v2, double r)
|
||||||
|
{
|
||||||
|
double tolerance = 0.3;
|
||||||
|
double a1 = Bearing(v1);
|
||||||
|
double a2 = Bearing(v2);
|
||||||
|
double df = acos(1 - tolerance / r);
|
||||||
|
if(a1 < a2)
|
||||||
|
a1 += 2 * M_PI;
|
||||||
|
while(a1 > a2) {
|
||||||
|
sw.Line(Polar(p, r, a1));
|
||||||
|
a1 -= df;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void App::Paint(Draw& w)
|
void App::Paint(Draw& w)
|
||||||
{
|
{
|
||||||
ImageBuffer ib(GetSize());
|
ImageBuffer ib(GetSize());
|
||||||
BufferPainter sw(ib);
|
BufferPainter sw(ib);
|
||||||
sw.Clear(White());
|
sw.Clear(White());
|
||||||
sw.Move(p1.x, p1.y).Line(p2.x, p2.y).Line(p3.x, p3.y);
|
|
||||||
sw.Stroke(40, Gray());
|
int join = 0;
|
||||||
sw.Stroke(2, LtRed());
|
// sw.Move(p1.x, p1.y).Line(p2.x, p2.y).Line(p3.x, p3.y);
|
||||||
|
// sw.Stroke(40, Gray());
|
||||||
|
// sw.Stroke(2, LtRed());
|
||||||
|
|
||||||
sw.Circle(p2.x, p2.y, 3).Fill(White()).Stroke(1, Black());
|
sw.Circle(p2.x, p2.y, 3).Fill(White()).Stroke(1, Black());
|
||||||
|
|
||||||
double w2 = 20;
|
double w2 = 20;
|
||||||
double miterlimit = 4 * w2;
|
double qmiterlimit = 16 * w2 * w2;
|
||||||
|
|
||||||
Pointf v1 = p2 - p1;
|
Pointf v1 = p2 - p1;
|
||||||
Pointf o1 = Ortogonal(v1);
|
Pointf o1 = Ortogonal(v1) * w2 / Length(v1);
|
||||||
double l1 = Length(v1);
|
|
||||||
double u1 = w2 / l1;
|
|
||||||
|
|
||||||
Pointf t1 = p1 + u1 * o1;
|
Pointf t1 = p1 + o1;
|
||||||
Pointf b1 = p1 - u1 * o1;
|
Pointf b1 = p1 - o1;
|
||||||
|
|
||||||
Pointf v2 = p3 - p2;
|
Pointf v2 = p3 - p2;
|
||||||
Pointf o2 = Ortogonal(v2);
|
Pointf o2 = Ortogonal(v2) * w2 / Length(v2);
|
||||||
double l2 = Length(v2);
|
|
||||||
double u2 = w2 / l2;
|
|
||||||
|
|
||||||
Pointf t2 = p2 + u2 * o2;
|
Pointf t2 = p2 + o2;
|
||||||
Pointf b2 = p2 - u2 * o2;
|
Pointf b2 = p2 - o2;
|
||||||
// DrawPoint(w, t2);
|
|
||||||
// DrawPoint(w, b2);
|
|
||||||
|
|
||||||
double s1 = Intersection(t1, v1, t2, v2);
|
Color c;
|
||||||
|
double d = join == 1 ? 0 : v1.y * v2.x - v2.y * v1.x;
|
||||||
Pointf ts = t1 + s1 * v1;
|
if(d > 1e-30) {
|
||||||
Pointf bs = Mirror(p2, ts);
|
Pointf ts = t1 + v1 * (v2.y * (t1.x - t2.x) - v2.x * (t1.y - t2.y)) / d;
|
||||||
|
sw.Move(t1);
|
||||||
Pointf t3 = p3 + u2 * o2;
|
if(join || SquareDistance(ts, p2) > qmiterlimit) {
|
||||||
Pointf b3 = p3 - u2 * o2;
|
sw.Line(t1 + v1);
|
||||||
|
if(join == 2)
|
||||||
if(s1 < 1) {
|
Round(sw, p2, o1, o2, w2);
|
||||||
Swap(t1, b1);
|
sw.Line(t2);
|
||||||
Swap(t2, b2);
|
|
||||||
Swap(ts, bs);
|
|
||||||
Swap(t3, b3);
|
|
||||||
u1 = -u1;
|
|
||||||
u2 = -u2;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if(Distance(ts, p2) > miterlimit) {
|
sw.Line(ts);
|
||||||
Pointf bevel1 = p2 + u1 * o1;
|
sw.Line(t2 + v2);
|
||||||
Pointf bevel2 = p2 + u2 * o2;
|
sw.Move(b2 + v2);
|
||||||
sw.Move(t1.x, t1.y);
|
sw.Line(b2);
|
||||||
sw.Line(bevel1.x, bevel1.y);
|
sw.Line(p2);
|
||||||
sw.Line(bevel2.x, bevel2.y);
|
sw.Line(b1 + v1);
|
||||||
sw.Line(t3.x, t3.y);
|
sw.Line(b1);
|
||||||
|
c = LtBlue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(d < -1e-30) {
|
||||||
|
Pointf ts = b2 + v2 * (v1.y * (t2.x - t1.x) - v1.x * (t2.y - t1.y)) / d;
|
||||||
|
sw.Move(b2 + v2);
|
||||||
|
if(join || SquareDistance(ts, p2) > qmiterlimit) {
|
||||||
|
sw.Line(b2);
|
||||||
|
if(join == 2)
|
||||||
|
Round(sw, p2, -o2, -o1, w2);
|
||||||
|
sw.Line(b1 + v1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sw.Line(ts);
|
||||||
|
sw.Line(b1);
|
||||||
|
sw.Move(t1);
|
||||||
|
sw.Line(t1 + v1);
|
||||||
|
sw.Line(p2);
|
||||||
|
sw.Line(t2);
|
||||||
|
sw.Line(t2 + v2);
|
||||||
|
c = LtGreen();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sw.Move(t1.x, t1.y);
|
sw.Move(t1);
|
||||||
sw.Line(ts.x, ts.y);
|
sw.Line(t1 + v1);
|
||||||
sw.Line(t3.x, t3.y);
|
if(round)
|
||||||
|
Round(sw, p2, o1, o2, w2);
|
||||||
|
sw.Line(t2);
|
||||||
|
sw.Line(t2 + v2);
|
||||||
|
sw.Move(b2 + v2);
|
||||||
|
sw.Line(b2);
|
||||||
|
sw.Line(b1 + v1);
|
||||||
|
sw.Line(b1);
|
||||||
|
c = LtRed();
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Move(b1.x, b1.y);
|
|
||||||
sw.Line(bs.x, bs.y);
|
sw.Move(b1);
|
||||||
sw.Line(b3.x, b3.y);
|
sw.Line(t1);
|
||||||
sw.Stroke(1, LtRed());
|
|
||||||
|
sw.Move(p3 - o2);
|
||||||
|
sw.Line(p3 + o2);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
sw.EvenOdd(true);
|
||||||
|
sw.Fill(c);
|
||||||
|
#else
|
||||||
|
sw.Stroke(1, c);
|
||||||
|
#endif
|
||||||
|
|
||||||
w.DrawImage(0, 0, ib);
|
w.DrawImage(0, 0, ib);
|
||||||
|
|
||||||
|
String s;
|
||||||
|
s << p1 << " - " << p2 << " - " << p3 << ", D=" << d;
|
||||||
|
w.DrawText(0, 0, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI_APP_MAIN
|
GUI_APP_MAIN
|
||||||
{
|
{
|
||||||
App().Run();
|
App().Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
40
uppdev/benchsin/benchsin.cpp
Normal file
40
uppdev/benchsin/benchsin.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <Core/Core.h>
|
||||||
|
|
||||||
|
using namespace Upp;
|
||||||
|
|
||||||
|
CONSOLE_APP_MAIN
|
||||||
|
{
|
||||||
|
double h = 0;
|
||||||
|
{
|
||||||
|
RTIMING("sin");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h += sin(x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RTIMING("asin");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h += asin(x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RTIMING("acos");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h += acos(x);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RTIMING("add");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h += x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RTIMING("mul");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h *= x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RTIMING("sqrt");
|
||||||
|
for(double x = 0; x < 1000000; x += 0.1)
|
||||||
|
h += sqrt(x);
|
||||||
|
}
|
||||||
|
RDUMP(h);
|
||||||
|
}
|
||||||
|
|
||||||
10
uppdev/benchsin/benchsin.upp
Normal file
10
uppdev/benchsin/benchsin.upp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
uses
|
||||||
|
Core;
|
||||||
|
|
||||||
|
file
|
||||||
|
benchsin.cpp;
|
||||||
|
|
||||||
|
mainconfig
|
||||||
|
"" = "SSE2",
|
||||||
|
"" = "";
|
||||||
|
|
||||||
4
uppdev/benchsin/init
Normal file
4
uppdev/benchsin/init
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#ifndef _benchsin_icpp_init_stub
|
||||||
|
#define _benchsin_icpp_init_stub
|
||||||
|
#include "Core/init"
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue