SvgArc support

git-svn-id: svn://ultimatepp.org/upp/trunk@863 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-14 20:21:26 +00:00
parent 511dc40a45
commit 30b677638f
13 changed files with 303 additions and 11 deletions

View file

@ -225,6 +225,8 @@ protected:
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel); virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel);
virtual void CloseOp(); virtual void CloseOp();
virtual void DivOp(); virtual void DivOp();

View file

@ -28,6 +28,7 @@ void Painter::Paint(const Painting& pic)
double r, w; double r, w;
Font fnt; Font fnt;
int ii = 0; int ii = 0;
bool large, sweep;
for(;;) { for(;;) {
int cmd = ss.Get(); int cmd = ss.Get();
if(cmd < 0) if(cmd < 0)
@ -79,6 +80,15 @@ void Painter::Paint(const Painting& pic)
sGet(w, ss); sGet(w, ss);
ArcOp(p, p1, r, w, rel); ArcOp(p, p1, r, w, rel);
break; break;
case PAINTING_SVGARC:
case PAINTING_SVGARC_REL:
sGet(p1, ss);
sGet(r, ss);
sGet(large, ss);
sGet(sweep, ss);
sGet(p, ss);
SvgArcOp(p1, r, large, sweep, p, rel);
break;
case PAINTING_CLOSE: case PAINTING_CLOSE:
CloseOp(); CloseOp();
break; break;

View file

@ -253,6 +253,46 @@ Painter& Painter::RelArc(double x, double y, double r, double angle, double swee
return Arc(x, y, r, angle, sweep, true); return Arc(x, y, r, angle, sweep, true);
} }
Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p, bool rel)
{
return SvgArc(Pointf(rx, ry), xangle, large, sweep, p, rel);
}
Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y, bool rel)
{
return SvgArc(Pointf(rx, ry), xangle, large, sweep, Pointf(x, y), rel);
}
Painter& Painter::SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p)
{
return SvgArc(r, xangle, large, sweep, p, false);
}
Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p)
{
return SvgArc(rx, ry, xangle, large, sweep, p, false);
}
Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y)
{
return SvgArc(rx, ry, xangle, large, sweep, x, y, false);
}
Painter& Painter::RelSvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p)
{
return SvgArc(r, xangle, large, sweep, p, true);
}
Painter& Painter::RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p)
{
return SvgArc(rx, ry, xangle, large, sweep, p, true);
}
Painter& Painter::RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y)
{
return SvgArc(rx, ry, xangle, large, sweep, x, y, true);
}
Xform2D GetLineSzXform(const Pointf& p1, const Pointf& p2, const Sizef& sz) Xform2D GetLineSzXform(const Pointf& p1, const Pointf& p2, const Sizef& sz)
{ {
Xform2D m = Xform2D::Scale(Distance(p1, p2) / sz.cx); Xform2D m = Xform2D::Scale(Distance(p1, p2) / sz.cx);

View file

@ -14,6 +14,7 @@ struct Xform2D {
double GetScale() const; double GetScale() const;
bool IsRegular() const; bool IsRegular() const;
Pointf Transform(const Pointf& f) const; Pointf Transform(const Pointf& f) const;
Pointf Transform(double x, double y) const;
static Xform2D Identity(); static Xform2D Identity();
static Xform2D Translation(double x, double y); static Xform2D Translation(double x, double y);
@ -93,6 +94,8 @@ protected:
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) = 0; virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) = 0;
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel) = 0; virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel) = 0;
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) = 0; virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) = 0;
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel) = 0;
virtual void CloseOp() = 0; virtual void CloseOp() = 0;
virtual void DivOp() = 0; virtual void DivOp() = 0;
@ -140,7 +143,16 @@ protected:
virtual void BeginMaskOp() = 0; virtual void BeginMaskOp() = 0;
protected: protected:
Pointf ReadPoint(CParser& p); static bool ReadBool(CParser& p);
static double ReadDouble(CParser& p);
static Pointf ReadPoint(CParser& p);
void ArcSegment(const Pointf& c, double th0, double th1, const Pointf& r, double xAxisRotation);
void DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle);
void DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p, const Pointf& p0);
// void DoSvgArc(double rx, double ry, double x_axis_rotation,
// int large_arc_flag, int sweep_flag,
// double x, double y, double curx, double cury);
public: public:
void Clear(const RGBA& color); void Clear(const RGBA& color);
@ -201,6 +213,16 @@ public:
Painter& RelArc(double x, double y, double rx, double ry, double angle, double sweep); Painter& RelArc(double x, double y, double rx, double ry, double angle, double sweep);
Painter& RelArc(double x, double y, double r, double angle, double sweep); Painter& RelArc(double x, double y, double r, double angle, double sweep);
Painter& SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel);
Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p, bool rel);
Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y, bool rel);
Painter& SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p);
Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p);
Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y);
Painter& RelSvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p);
Painter& RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p);
Painter& RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y);
Painter& Close(); Painter& Close();
Painter& Div(); Painter& Div();

View file

@ -53,6 +53,13 @@ Painter& Painter::Arc(const Pointf& c, const Pointf& r, double angle, double swe
return *this; return *this;
} }
inline
Painter& Painter::SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel)
{
SvgArcOp(r, xangle, large, sweep, p, rel);
return *this;
}
inline inline
Painter& Painter::Close() Painter& Painter::Close()
{ {

View file

@ -8,6 +8,7 @@ file
Painter.h, Painter.h,
Painter.hpp, Painter.hpp,
Painter.cpp, Painter.cpp,
SvgArc.cpp,
PainterPath.cpp, PainterPath.cpp,
FontWin32.cpp optimize_speed, FontWin32.cpp optimize_speed,
FontX11.cpp optimize_speed, FontX11.cpp optimize_speed,

View file

@ -2,12 +2,25 @@
NAMESPACE_UPP NAMESPACE_UPP
bool Painter::ReadBool(CParser& p)
{
while(p.Char(','));
if(p.Char('1')) return true;
p.Char('0');
return false;
}
double Painter::ReadDouble(CParser& p)
{
while(p.Char(','));
return p.IsDouble() ? p.ReadDouble() : 0;
}
Pointf Painter::ReadPoint(CParser& p) Pointf Painter::ReadPoint(CParser& p)
{ {
Pointf t; Pointf t;
t.x = p.IsDouble() ? p.ReadDouble() : 0; t.x = ReadDouble(p);
p.Char(','); t.y = ReadDouble(p);
t.y = p.IsDouble() ? p.ReadDouble() : 0;
return t; return t;
} }
@ -21,11 +34,11 @@ Painter& Painter::Path(CParser& p)
switch(ToUpper(c)) { switch(ToUpper(c)) {
case 'M': case 'M':
t = ReadPoint(p); t = ReadPoint(p);
Move(t.x, t.y); Move(t, rel);
case 'L': case 'L':
while(p.IsDouble()) { while(p.IsDouble()) {
t = ReadPoint(p); t = ReadPoint(p);
Line(t.x, t.y, rel); Line(t, rel);
} }
break; break;
case 'Z': case 'Z':
@ -44,27 +57,37 @@ Painter& Painter::Path(CParser& p)
t1 = ReadPoint(p); t1 = ReadPoint(p);
t2 = ReadPoint(p); t2 = ReadPoint(p);
t = ReadPoint(p); t = ReadPoint(p);
Cubic(t1.x, t1.y, t2.x, t2.y, t.x, t.y, rel); Cubic(t1, t2, t, rel);
} }
break; break;
case 'S': case 'S':
while(p.IsDouble()) { while(p.IsDouble()) {
t2 = ReadPoint(p); t2 = ReadPoint(p);
t = ReadPoint(p); t = ReadPoint(p);
Cubic(t2.x, t2.y, t.x, t.y, rel); Cubic(t2, t, rel);
} }
break; break;
case 'Q': case 'Q':
while(p.IsDouble()) { while(p.IsDouble()) {
t1 = ReadPoint(p); t1 = ReadPoint(p);
t = ReadPoint(p); t = ReadPoint(p);
Quadratic(t1.x, t1.y, t.x, t.y, rel); Quadratic(t1, t, rel);
} }
break; break;
case 'T': case 'T':
while(p.IsDouble()) { while(p.IsDouble()) {
t = ReadPoint(p); t = ReadPoint(p);
Quadratic(t.x, t.y, rel); Quadratic(t, rel);
}
break;
case 'A':
while(p.IsDouble()) {
t1 = ReadPoint(p);
double xangle = ReadDouble(p);
bool large = ReadBool(p);
bool sweep = ReadBool(p);
t = ReadPoint(p);
SvgArc(t1, xangle * M_PI / 180.0, large, sweep, t, rel);
} }
break; break;
default: default:

View file

@ -57,6 +57,16 @@ void PaintingPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, doub
Putf(sweep); Putf(sweep);
} }
void PaintingPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel)
{
Put(PAINTING_SVGARC + rel);
Putf(r);
Putf(xangle);
Put(large);
Put(sweep);
Putf(p);
}
void PaintingPainter::CloseOp() void PaintingPainter::CloseOp()
{ {
Put(PAINTING_CLOSE); Put(PAINTING_CLOSE);

View file

@ -15,6 +15,8 @@ enum {
PAINTING_CUBIC_S_REL, PAINTING_CUBIC_S_REL,
PAINTING_ARC, PAINTING_ARC,
PAINTING_ARC_REL, PAINTING_ARC_REL,
PAINTING_SVGARC,
PAINTING_SVGARC_REL,
PAINTING_CLOSE, PAINTING_CLOSE,
PAINTING_DIV, PAINTING_DIV,
@ -72,6 +74,8 @@ protected:
virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel);
virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel); virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel);
virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel);
virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel);
virtual void CloseOp(); virtual void CloseOp();
virtual void DivOp(); virtual void DivOp();

View file

@ -105,6 +105,14 @@ void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double
current = m.EndPoint(); current = m.EndPoint();
} }
void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep,
const Pointf& p, bool rel)
{
DoMove0();
Pointf c = current;
DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c);
}
void BufferPainter::CloseOp() void BufferPainter::CloseOp()
{ {
if(!IsNull(move) && current != move) { if(!IsNull(move) && current != move) {

160
uppsrc/Painter/SvgArc.cpp Normal file
View file

@ -0,0 +1,160 @@
#include "Painter.h"
NAMESPACE_UPP
void Painter::DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle)
{
int n_segs = int(ceil(fabs(sweep / (M_PI * 0.5 + 0.001))));
for (int i = 0; i < n_segs; i++) {
double th0 = angle + i * sweep / n_segs;
double th1 = angle + (i + 1) * sweep / n_segs;
double thHalf = 0.5 * (th1 - th0);
double t = (8.0 / 3.0) * sin(thHalf * 0.5) * sin(thHalf * 0.5) / sin(thHalf);
double x3 = c.x + cos(th1);
double y3 = c.y + sin(th1);
Xform2D m = Xform2D::Rotation(xangle);
m.x *= r;
m.y *= r;
Cubic(m.Transform(c.x + cos(th0) - t * sin(th0), c.y + sin(th0) + t * cos(th0)),
m.Transform(x3 + t * sin(th1), y3 - t * cos(th1)),
m.Transform(x3, y3));
}
}
// the arc handling code underneath is from XSVG (BSD license)
/*
* Copyright 2002 USC/Information Sciences Institute
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Information Sciences Institute not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. Information Sciences Institute
* makes no representations about the suitability of this software for
* any purpose. It is provided "as is" without express or implied
* warranty.
*
* INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
* INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
* OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
*/
void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep,
const Pointf& p1, const Pointf& p0)
{
Pointf r(fabs(rr.x), fabs(rr.y));
Xform2D m = Xform2D::Rotation(-xangle);
Pointf d1 = m.Transform((p0 - p1) / 2);
Pointf Pr = r * r;
Pointf P = d1 * d1;
double check = P.x / Pr.x + P.y / Pr.y;
if(check > 1)
r *= sqrt(check);
m.x /= r.x;
m.y /= r.y;
Pointf q0 = m.Transform(p0);
Pointf q1 = m.Transform(p1);
double d = SquaredDistance(q1, q0);
double sfactor_sq = 1.0 / d - 0.25;
if(sfactor_sq < 0) sfactor_sq = 0;
double sfactor = sqrt(sfactor_sq);
if (sweep == large) sfactor = -sfactor;
Pointf c(0.5 * (q0.x + q1.x) - sfactor * (q1.y - q0.y),
0.5 * (q0.y + q1.y) + sfactor * (q1.x - q0.x));
double th0 = Bearing(q0 - c);
double th_sweep = Bearing(q1 - c) - th0;
if(th_sweep < 0 && sweep)
th_sweep += 2 * M_PI;
else
if(th_sweep > 0 && !sweep)
th_sweep -= 2 * M_PI;
DoArc(c, r, th0, th_sweep, xangle);
}
#if 0
void Painter::DoSvgArc(double rx, double ry,
double x_axis_rotation, int large_arc_flag, int sweep_flag,
double x, double y, double curx, double cury)
{
double sin_th, cos_th;
double a00, a01, a10, a11;
double x0, y0, x1, y1, xc, yc;
double d, sfactor, sfactor_sq;
double th0, th1, th_arc;
int i, n_segs;
double dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
rx = fabs(rx);
ry = fabs(ry);
sin_th = sin(x_axis_rotation);
cos_th = cos(x_axis_rotation);
dx = (curx - x) / 2.0;
dy = (cury - y) / 2.0;
dx1 = cos_th * dx + sin_th * dy;
dy1 = -sin_th * dx + cos_th * dy;
Pr1 = rx * rx;
Pr2 = ry * ry;
Px = dx1 * dx1;
Py = dy1 * dy1;
/* Spec : check if radii are large enough */
check = Px / Pr1 + Py / Pr2;
if(check > 1) {
rx = rx * sqrt(check);
ry = ry * sqrt(check);
}
a00 = cos_th / rx;
a01 = sin_th / rx;
a10 = -sin_th / ry;
a11 = cos_th / ry;
x0 = a00 * curx + a01 * cury;
y0 = a10 * curx + a11 * cury;
x1 = a00 * x + a01 * y;
y1 = a10 * x + a11 * y;
/* (x0, y0) is current point in transformed coordinate space.
(x1, y1) is new point in transformed coordinate space.
The arc fits a unit-radius circle in this space.
*/
d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
sfactor_sq = 1.0 / d - 0.25;
if (sfactor_sq < 0) sfactor_sq = 0;
sfactor = sqrt(sfactor_sq);
if (sweep_flag == large_arc_flag) sfactor = -sfactor;
xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
/* (xc, yc) is center of the circle. */
th0 = atan2(y0 - yc, x0 - xc);
th1 = atan2(y1 - yc, x1 - xc);
th_arc = th1 - th0;
if (th_arc < 0 && sweep_flag)
th_arc += 2 * M_PI;
else if (th_arc > 0 && !sweep_flag)
th_arc -= 2 * M_PI;
n_segs = int(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))));
for (i = 0; i < n_segs; i++)
ArcSegment(xc, yc,
th0 + i * th_arc / n_segs,
th0 + (i + 1) * th_arc / n_segs,
rx, ry, x_axis_rotation);
}
#endif
END_UPP_NAMESPACE

View file

@ -7,6 +7,11 @@ Pointf Xform2D::Transform(const Pointf& f) const
return Pointf(f.x * x.x + f.y * x.y + t.x, f.x * y.x + f.y * y.y + t.y); return Pointf(f.x * x.x + f.y * x.y + t.x, f.x * y.x + f.y * y.y + t.y);
} }
Pointf Xform2D::Transform(double x, double y) const
{
return Transform(Pointf(x, y));
}
Pointf Xform2D::GetScaleXY() const Pointf Xform2D::GetScaleXY() const
{ {
return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y)); return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y));

View file

@ -2,7 +2,7 @@
#define _Painter_icpp_init_stub #define _Painter_icpp_init_stub
#include "Core/init" #include "Core/init"
#include "CtrlLib/init" #include "CtrlLib/init"
#define BLITZ_INDEX__ FB97560702FE0F85B954F5A6632CEB2DB #define BLITZ_INDEX__ F41D82715284B94932890A06EF04E4CA5
#include "PaintPainting.icpp" #include "PaintPainting.icpp"
#undef BLITZ_INDEX__ #undef BLITZ_INDEX__
#endif #endif