From 30b677638f061c3281f4db38412a3cbabeaaf639 Mon Sep 17 00:00:00 2001 From: cxl Date: Sat, 14 Feb 2009 20:21:26 +0000 Subject: [PATCH] SvgArc support git-svn-id: svn://ultimatepp.org/upp/trunk@863 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Painter/BufferPainter.h | 2 + uppsrc/Painter/PaintPainting.icpp | 10 ++ uppsrc/Painter/Painter.cpp | 40 ++++++++ uppsrc/Painter/Painter.h | 24 ++++- uppsrc/Painter/Painter.hpp | 7 ++ uppsrc/Painter/Painter.upp | 1 + uppsrc/Painter/PainterPath.cpp | 41 ++++++-- uppsrc/Painter/Painting.cpp | 10 ++ uppsrc/Painter/Painting.h | 4 + uppsrc/Painter/Path.cpp | 8 ++ uppsrc/Painter/SvgArc.cpp | 160 ++++++++++++++++++++++++++++++ uppsrc/Painter/Xform2D.cpp | 5 + uppsrc/Painter/init | 2 +- 13 files changed, 303 insertions(+), 11 deletions(-) create mode 100644 uppsrc/Painter/SvgArc.cpp diff --git a/uppsrc/Painter/BufferPainter.h b/uppsrc/Painter/BufferPainter.h index fd4abd0a4..ff6d7bc49 100644 --- a/uppsrc/Painter/BufferPainter.h +++ b/uppsrc/Painter/BufferPainter.h @@ -225,6 +225,8 @@ protected: 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 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 DivOp(); diff --git a/uppsrc/Painter/PaintPainting.icpp b/uppsrc/Painter/PaintPainting.icpp index f543762a5..01ba02b86 100644 --- a/uppsrc/Painter/PaintPainting.icpp +++ b/uppsrc/Painter/PaintPainting.icpp @@ -28,6 +28,7 @@ void Painter::Paint(const Painting& pic) double r, w; Font fnt; int ii = 0; + bool large, sweep; for(;;) { int cmd = ss.Get(); if(cmd < 0) @@ -79,6 +80,15 @@ void Painter::Paint(const Painting& pic) sGet(w, ss); ArcOp(p, p1, r, w, rel); 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: CloseOp(); break; diff --git a/uppsrc/Painter/Painter.cpp b/uppsrc/Painter/Painter.cpp index 6c81e1acd..09b2f8041 100644 --- a/uppsrc/Painter/Painter.cpp +++ b/uppsrc/Painter/Painter.cpp @@ -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); } +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 m = Xform2D::Scale(Distance(p1, p2) / sz.cx); diff --git a/uppsrc/Painter/Painter.h b/uppsrc/Painter/Painter.h index bc4aefc1a..259c325c2 100644 --- a/uppsrc/Painter/Painter.h +++ b/uppsrc/Painter/Painter.h @@ -14,6 +14,7 @@ struct Xform2D { double GetScale() const; bool IsRegular() const; Pointf Transform(const Pointf& f) const; + Pointf Transform(double x, double y) const; static Xform2D Identity(); 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& 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 SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel) = 0; virtual void CloseOp() = 0; virtual void DivOp() = 0; @@ -140,7 +143,16 @@ protected: virtual void BeginMaskOp() = 0; 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: 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 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& Div(); diff --git a/uppsrc/Painter/Painter.hpp b/uppsrc/Painter/Painter.hpp index 9bb87f8eb..f71782592 100644 --- a/uppsrc/Painter/Painter.hpp +++ b/uppsrc/Painter/Painter.hpp @@ -53,6 +53,13 @@ Painter& Painter::Arc(const Pointf& c, const Pointf& r, double angle, double swe 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 Painter& Painter::Close() { diff --git a/uppsrc/Painter/Painter.upp b/uppsrc/Painter/Painter.upp index 1eca83717..483f97be2 100644 --- a/uppsrc/Painter/Painter.upp +++ b/uppsrc/Painter/Painter.upp @@ -8,6 +8,7 @@ file Painter.h, Painter.hpp, Painter.cpp, + SvgArc.cpp, PainterPath.cpp, FontWin32.cpp optimize_speed, FontX11.cpp optimize_speed, diff --git a/uppsrc/Painter/PainterPath.cpp b/uppsrc/Painter/PainterPath.cpp index 09a13f899..71a9d0cbf 100644 --- a/uppsrc/Painter/PainterPath.cpp +++ b/uppsrc/Painter/PainterPath.cpp @@ -2,12 +2,25 @@ 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 t; - t.x = p.IsDouble() ? p.ReadDouble() : 0; - p.Char(','); - t.y = p.IsDouble() ? p.ReadDouble() : 0; + t.x = ReadDouble(p); + t.y = ReadDouble(p); return t; } @@ -21,11 +34,11 @@ Painter& Painter::Path(CParser& p) switch(ToUpper(c)) { case 'M': t = ReadPoint(p); - Move(t.x, t.y); + Move(t, rel); case 'L': while(p.IsDouble()) { t = ReadPoint(p); - Line(t.x, t.y, rel); + Line(t, rel); } break; case 'Z': @@ -44,27 +57,37 @@ Painter& Painter::Path(CParser& p) t1 = ReadPoint(p); t2 = 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; case 'S': while(p.IsDouble()) { t2 = ReadPoint(p); t = ReadPoint(p); - Cubic(t2.x, t2.y, t.x, t.y, rel); + Cubic(t2, t, rel); } break; case 'Q': while(p.IsDouble()) { t1 = ReadPoint(p); t = ReadPoint(p); - Quadratic(t1.x, t1.y, t.x, t.y, rel); + Quadratic(t1, t, rel); } break; case 'T': while(p.IsDouble()) { 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; default: diff --git a/uppsrc/Painter/Painting.cpp b/uppsrc/Painter/Painting.cpp index eb8755fe4..9e3eac914 100644 --- a/uppsrc/Painter/Painting.cpp +++ b/uppsrc/Painter/Painting.cpp @@ -57,6 +57,16 @@ void PaintingPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, doub 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() { Put(PAINTING_CLOSE); diff --git a/uppsrc/Painter/Painting.h b/uppsrc/Painter/Painting.h index ae551b2bd..09fc3bcd2 100644 --- a/uppsrc/Painter/Painting.h +++ b/uppsrc/Painter/Painting.h @@ -15,6 +15,8 @@ enum { PAINTING_CUBIC_S_REL, PAINTING_ARC, PAINTING_ARC_REL, + PAINTING_SVGARC, + PAINTING_SVGARC_REL, PAINTING_CLOSE, 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& p2, const Pointf& p, 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 DivOp(); diff --git a/uppsrc/Painter/Path.cpp b/uppsrc/Painter/Path.cpp index 07a4d4933..323816277 100644 --- a/uppsrc/Painter/Path.cpp +++ b/uppsrc/Painter/Path.cpp @@ -105,6 +105,14 @@ void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double 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() { if(!IsNull(move) && current != move) { diff --git a/uppsrc/Painter/SvgArc.cpp b/uppsrc/Painter/SvgArc.cpp new file mode 100644 index 000000000..e3ec3660d --- /dev/null +++ b/uppsrc/Painter/SvgArc.cpp @@ -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 diff --git a/uppsrc/Painter/Xform2D.cpp b/uppsrc/Painter/Xform2D.cpp index d7cb2c945..bc19b470b 100644 --- a/uppsrc/Painter/Xform2D.cpp +++ b/uppsrc/Painter/Xform2D.cpp @@ -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); } +Pointf Xform2D::Transform(double x, double y) const +{ + return Transform(Pointf(x, y)); +} + Pointf Xform2D::GetScaleXY() const { return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y)); diff --git a/uppsrc/Painter/init b/uppsrc/Painter/init index a2b52881e..e5a2008f0 100644 --- a/uppsrc/Painter/init +++ b/uppsrc/Painter/init @@ -2,7 +2,7 @@ #define _Painter_icpp_init_stub #include "Core/init" #include "CtrlLib/init" -#define BLITZ_INDEX__ FB97560702FE0F85B954F5A6632CEB2DB +#define BLITZ_INDEX__ F41D82715284B94932890A06EF04E4CA5 #include "PaintPainting.icpp" #undef BLITZ_INDEX__ #endif