From a6a9c00dc77a3e34d9c50c67328e11b8f8be9aae Mon Sep 17 00:00:00 2001 From: cxl Date: Fri, 16 Jan 2009 16:08:14 +0000 Subject: [PATCH] Painter fixed to work in X11 and GCC git-svn-id: svn://ultimatepp.org/upp/trunk@759 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Painter/BufferPainter.cpp | 310 +-- uppsrc/Painter/FontX11.cpp | 302 +-- uppsrc/Painter/Mask.cpp | 100 +- uppsrc/Painter/Painter.cpp | 532 ++--- uppsrc/Painter/Painter.hpp | 370 ++-- uppsrc/Painter/agg_path_storage.h | 3086 ++++++++++++++--------------- 6 files changed, 2350 insertions(+), 2350 deletions(-) diff --git a/uppsrc/Painter/BufferPainter.cpp b/uppsrc/Painter/BufferPainter.cpp index e842f472c..3e2e6148a 100644 --- a/uppsrc/Painter/BufferPainter.cpp +++ b/uppsrc/Painter/BufferPainter.cpp @@ -1,155 +1,155 @@ -#include "Painter.h" - -NAMESPACE_UPP - -#define LTIMING(x) RTIMING(x) - -void BufferPainter::ClearOp(const RGBA& color) -{ - Upp::Fill(~buffer, color, buffer.GetLength()); -} - -inline void BufferPainter::PathPoint0(double x, double y) -{ - pathrect.left = min(pathrect.left, x); - pathrect.top = min(pathrect.top, y); - pathrect.right = max(pathrect.right, x); - pathrect.bottom = max(pathrect.bottom, y); -} - -inline void BufferPainter::PathPoint(double& x, double& y, bool rel) -{ - x = IsNull(x) ? current.x : rel ? x + current.x : x; - y = IsNull(y) ? current.y : rel ? y + current.y : y; - if(inpath) - PathPoint0(x, y); - else { - path.remove_all(); - pathrect.left = pathrect.right = x; - pathrect.top = pathrect.bottom = y; - pathattr = attr; - } - inpath = true; -} - -inline void BufferPainter::EndPoint(double& x, double& y, bool rel) -{ - PathPoint(x, y, rel); - current = Pointf(x, y); -} - -void BufferPainter::MoveOp(double x, double y, bool rel) -{ - EndPoint(x, y, rel); - ccontrol = qcontrol = current; - path.move_to(x, y); - inpath = true; -} - -void BufferPainter::LineOp(double x, double y, bool rel) -{ - EndPoint(x, y, rel); - ccontrol = qcontrol = current; - path.line_to(x, y); - inpath = true; -} - -void BufferPainter::QuadraticOp(double x1, double y1, double x, double y, bool rel) -{ - PathPoint(x1, y1, rel); - qcontrol = Pointf(x1, y1); - EndPoint(x, y, rel); - ccontrol = current; - path.curve3(x1, y1, x, y); -} - -void BufferPainter::QuadraticOp(double x, double y, bool rel) -{ - qcontrol = current + current - qcontrol; - PathPoint0(qcontrol.x, qcontrol.y); - EndPoint(x, y, rel); - ccontrol = current; - path.curve3(qcontrol.x, qcontrol.y, x, y); -} - -void BufferPainter::CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel) -{ - PathPoint(x1, y1, rel); - PathPoint(x2, y2, rel); - ccontrol = Pointf(x2, y2); - EndPoint(x, y, rel); - qcontrol = current; - path.curve4(x1, y1, x2, y2, x, y); -} - -void BufferPainter::CubicOp(double x2, double y2, double x, double y, bool rel) -{ - Pointf c = current + current - ccontrol; - PathPoint0(c.x, c.y); - PathPoint(x2, y2, rel); - ccontrol = Pointf(x2, y2); - EndPoint(x, y, rel); - qcontrol = current; - path.curve4(c.x, c.y, x2, y2, x, y); -} - -void BufferPainter::CloseOp() -{ - path.close_polygon(); -} - -inline void BufferPainter::MinMax(Pointf& minv, Pointf& maxv, Pointf p) const -{ - p = pathattr.mtx.Transformed(p); - minv.x = min(minv.x, p.x); - minv.y = min(minv.y, p.y); - maxv.x = max(maxv.x, p.x); - maxv.y = max(maxv.y, p.y); -} - -bool BufferPainter::PathVisible(double w) const -{ - Pointf h = pathattr.mtx.Transformed(w, w); - w = max(abs(h.x), abs(h.y)); - Pointf min; - Pointf max; - min = max = pathattr.mtx.Transformed(pathrect.TopLeft()); - MinMax(min, max, pathrect.TopRight()); - MinMax(min, max, pathrect.BottomLeft()); - MinMax(min, max, pathrect.BottomRight()); - return max.x + w >= 0 && max.y + w >= 0 && min.x - w <= sizef.cx && min.y - w <= sizef.cy; -} - -void BufferPainter::SetRbuf() -{ - pixf.attach(buffer); - renb.attach(pixf); - renderer.attach(renb); -} - -BufferPainter::BufferPainter(ImageBuffer& ib) -: buffer(ib), - curved(path), - curved_trans(curved, attr.mtx) -{ - size = ib.GetSize(); - sizef = size; - inpath = false; - pathrect = Null; - ccontrol = qcontrol = current = Point(0, 0); - - attr.cap = LINECAP_BUTT; - attr.join = LINEJOIN_MITER; - attr.miter_limit = 4; - attr.evenodd = false; - attr.hasclip = false; - attr.cliplevel = 0; - attr.dash_start = 0.0; - attr.opacity = 1.0; - attr.mask = false; - pathattr = attr; - - SetRbuf(); -} - -END_UPP_NAMESPACE +#include "Painter.h" + +NAMESPACE_UPP + +#define LTIMING(x) RTIMING(x) + +void BufferPainter::ClearOp(const RGBA& color) +{ + Upp::Fill(~buffer, color, buffer.GetLength()); +} + +inline void BufferPainter::PathPoint0(double x, double y) +{ + pathrect.left = min(pathrect.left, x); + pathrect.top = min(pathrect.top, y); + pathrect.right = max(pathrect.right, x); + pathrect.bottom = max(pathrect.bottom, y); +} + +inline void BufferPainter::PathPoint(double& x, double& y, bool rel) +{ + x = IsNull(x) ? current.x : rel ? x + current.x : x; + y = IsNull(y) ? current.y : rel ? y + current.y : y; + if(inpath) + PathPoint0(x, y); + else { + path.remove_all(); + pathrect.left = pathrect.right = x; + pathrect.top = pathrect.bottom = y; + pathattr = attr; + } + inpath = true; +} + +inline void BufferPainter::EndPoint(double& x, double& y, bool rel) +{ + PathPoint(x, y, rel); + current = Pointf(x, y); +} + +void BufferPainter::MoveOp(double x, double y, bool rel) +{ + EndPoint(x, y, rel); + ccontrol = qcontrol = current; + path.move_to(x, y); + inpath = true; +} + +void BufferPainter::LineOp(double x, double y, bool rel) +{ + EndPoint(x, y, rel); + ccontrol = qcontrol = current; + path.line_to(x, y); + inpath = true; +} + +void BufferPainter::QuadraticOp(double x1, double y1, double x, double y, bool rel) +{ + PathPoint(x1, y1, rel); + qcontrol = Pointf(x1, y1); + EndPoint(x, y, rel); + ccontrol = current; + path.curve3(x1, y1, x, y); +} + +void BufferPainter::QuadraticOp(double x, double y, bool rel) +{ + qcontrol = current + current - qcontrol; + PathPoint0(qcontrol.x, qcontrol.y); + EndPoint(x, y, rel); + ccontrol = current; + path.curve3(qcontrol.x, qcontrol.y, x, y); +} + +void BufferPainter::CubicOp(double x1, double y1, double x2, double y2, double x, double y, bool rel) +{ + PathPoint(x1, y1, rel); + PathPoint(x2, y2, rel); + ccontrol = Pointf(x2, y2); + EndPoint(x, y, rel); + qcontrol = current; + path.curve4(x1, y1, x2, y2, x, y); +} + +void BufferPainter::CubicOp(double x2, double y2, double x, double y, bool rel) +{ + Pointf c = current + current - ccontrol; + PathPoint0(c.x, c.y); + PathPoint(x2, y2, rel); + ccontrol = Pointf(x2, y2); + EndPoint(x, y, rel); + qcontrol = current; + path.curve4(c.x, c.y, x2, y2, x, y); +} + +void BufferPainter::CloseOp() +{ + path.close_polygon(); +} + +inline void BufferPainter::MinMax(Pointf& minv, Pointf& maxv, Pointf p) const +{ + p = pathattr.mtx.Transformed(p); + minv.x = min(minv.x, p.x); + minv.y = min(minv.y, p.y); + maxv.x = max(maxv.x, p.x); + maxv.y = max(maxv.y, p.y); +} + +bool BufferPainter::PathVisible(double w) const +{ + Pointf h = pathattr.mtx.Transformed(w, w); + w = max(fabs(h.x), fabs(h.y)); + Pointf min; + Pointf max; + min = max = pathattr.mtx.Transformed(pathrect.TopLeft()); + MinMax(min, max, pathrect.TopRight()); + MinMax(min, max, pathrect.BottomLeft()); + MinMax(min, max, pathrect.BottomRight()); + return max.x + w >= 0 && max.y + w >= 0 && min.x - w <= sizef.cx && min.y - w <= sizef.cy; +} + +void BufferPainter::SetRbuf() +{ + pixf.attach(buffer); + renb.attach(pixf); + renderer.attach(renb); +} + +BufferPainter::BufferPainter(ImageBuffer& ib) +: buffer(ib), + curved(path), + curved_trans(curved, attr.mtx) +{ + size = ib.GetSize(); + sizef = size; + inpath = false; + pathrect = Null; + ccontrol = qcontrol = current = Point(0, 0); + + attr.cap = LINECAP_BUTT; + attr.join = LINEJOIN_MITER; + attr.miter_limit = 4; + attr.evenodd = false; + attr.hasclip = false; + attr.cliplevel = 0; + attr.dash_start = 0.0; + attr.opacity = 1.0; + attr.mask = false; + pathattr = attr; + + SetRbuf(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/FontX11.cpp b/uppsrc/Painter/FontX11.cpp index 59aa9a5e2..a4319ff1d 100644 --- a/uppsrc/Painter/FontX11.cpp +++ b/uppsrc/Painter/FontX11.cpp @@ -1,151 +1,151 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all coM_PIes. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -// Recycled for U++ by Miroslav Fidler 2008 - -#include "Painter.h" - -NAMESPACE_UPP - -#ifdef PLATFORM_X11 - -static inline double ft_dbl(int p) -{ - return double(p) / 64.0; -} - -bool RenderOutline(const FT_Outline& outline, SDraw& path) -{ - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - double x1, y1, x2, y2, x3, y3; - FT_Vector* point; - FT_Vector* limit; - char* tags; - int n; // index of contour in outline - char tag; // current point's state - int first = 0; // index of first point in contour - for(n = 0; n < outline.n_contours; n++) { - int last = outline.contours[n]; - limit = outline.points + last; - v_start = outline.points[first]; - v_last = outline.points[last]; - v_control = v_start; - point = outline.points + first; - tags = outline.tags + first; - tag = FT_CURVE_TAG(tags[0]); - if(tag == FT_CURVE_TAG_CUBIC) return false; - if(tag == FT_CURVE_TAG_CONIC) { - if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { - // start at last point if it is on the curve - v_start = v_last; - limit--; - } - else { - // if both first and last points are conic, - // start at their middle and record its position - // for closure - v_start.x = (v_start.x + v_last.x) / 2; - v_start.y = (v_start.y + v_last.y) / 2; - v_last = v_start; - } - point--; - tags--; - } - path.MoveTo(ft_dbl(v_start.x), -ft_dbl(v_start.y)); - while(point < limit) { - point++; - tags++; - - tag = FT_CURVE_TAG(tags[0]); - switch(tag) { - case FT_CURVE_TAG_ON: - path.LineTo(ft_dbl(point->x), -ft_dbl(point->y)); - continue; - case FT_CURVE_TAG_CONIC: - v_control.x = point->x; - v_control.y = point->y; - Do_Conic: - if(point < limit) { - FT_Vector vec; - FT_Vector v_middle; - point++; - tags++; - tag = FT_CURVE_TAG(tags[0]); - vec.x = point->x; - vec.y = point->y; - if(tag == FT_CURVE_TAG_ON) { - path.Quadratic(ft_dbl(v_control.x), -ft_dbl(v_control.y), - ft_dbl(vec.x), -ft_dbl(vec.y)); - continue; - } - if(tag != FT_CURVE_TAG_CONIC) return false; - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; - path.Quadratic(ft_dbl(v_control.x), -ft_dbl(v_control.y), - ft_dbl(v_middle.x), -ft_dbl(v_middle.y)); - v_control = vec; - goto Do_Conic; - } - path.Quadratic(ft_dbl(v_control.x), -ft_dbl(v_control.y), - ft_dbl(v_start.x), -ft_dbl(v_start.y)); - goto Close; - - default: - FT_Vector vec1, vec2; - if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) - return false; - vec1.x = point[0].x; - vec1.y = point[0].y; - vec2.x = point[1].x; - vec2.y = point[1].y; - point += 2; - tags += 2; - if(point <= limit) { - FT_Vector vec; - vec.x = point->x; - vec.y = point->y; - path.Cubic(ft_dbl(vec1.x), -ft_dbl(vec1.y), - ft_dbl(vec2.x), -ft_dbl(vec2.y), - ft_dbl(vec.x), -ft_dbl(vec.y)); - continue; - } - path.Cubic(ft_dbl(vec1.x), -ft_dbl(vec1.y), - ft_dbl(vec2.x), -ft_dbl(vec2.y), - ft_dbl(v_start.x), -ft_dbl(v_start.y)); - goto Close; - } - } - Close: - path.Close(); - first = last + 1; - } - return true; -} - -void RenderCharacter(Painter& sw, int ch, Font fnt) -{ - FontInfo fi = fnt.Info(); - FT_Face face = XftLockFace(fi.GetXftFont()); - int glyph_index = FT_Get_Char_Index(face, ch); - if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) - RenderOutline(face->glyph->outline, sw); - XftUnlockFace(fi.GetXftFont()); -} - -#endif - -END_UPP_NAMESPACE +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +static inline double ft_dbl(int p) +{ + return double(p) / 64.0; +} + +bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy) +{ + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + double x1, y1, x2, y2, x3, y3; + FT_Vector* point; + FT_Vector* limit; + char* tags; + int n; // index of contour in outline + char tag; // current point's state + int first = 0; // index of first point in contour + for(n = 0; n < outline.n_contours; n++) { + int last = outline.contours[n]; + limit = outline.points + last; + v_start = outline.points[first]; + v_last = outline.points[last]; + v_control = v_start; + point = outline.points + first; + tags = outline.tags + first; + tag = FT_CURVE_TAG(tags[0]); + if(tag == FT_CURVE_TAG_CUBIC) return false; + if(tag == FT_CURVE_TAG_CONIC) { + if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { + // start at last point if it is on the curve + v_start = v_last; + limit--; + } + else { + // if both first and last points are conic, + // start at their middle and record its position + // for closure + v_start.x = (v_start.x + v_last.x) / 2; + v_start.y = (v_start.y + v_last.y) / 2; + v_last = v_start; + } + point--; + tags--; + } + path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + while(point < limit) { + point++; + tags++; + + tag = FT_CURVE_TAG(tags[0]); + switch(tag) { + case FT_CURVE_TAG_ON: + path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy); + continue; + case FT_CURVE_TAG_CONIC: + v_control.x = point->x; + v_control.y = point->y; + Do_Conic: + if(point < limit) { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG(tags[0]); + vec.x = point->x; + vec.y = point->y; + if(tag == FT_CURVE_TAG_ON) { + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + if(tag != FT_CURVE_TAG_CONIC) return false; + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy); + v_control = vec; + goto Do_Conic; + } + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + + default: + FT_Vector vec1, vec2; + if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) + return false; + vec1.x = point[0].x; + vec1.y = point[0].y; + vec2.x = point[1].x; + vec2.y = point[1].y; + point += 2; + tags += 2; + if(point <= limit) { + FT_Vector vec; + vec.x = point->x; + vec.y = point->y; + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + } + } + Close: + path.Close(); + first = last + 1; + } + return true; +} + +void Painter::CharacterOp(double x, double y, int ch, Font fnt) +{ + FontInfo fi = fnt.Info(); + FT_Face face = XftLockFace(fi.GetXftFont()); + int glyph_index = FT_Get_Char_Index(face, ch); + if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) + RenderOutline(face->glyph->outline, *this, x, y); + XftUnlockFace(fi.GetXftFont()); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/Mask.cpp b/uppsrc/Painter/Mask.cpp index 107a528a1..669d859ac 100644 --- a/uppsrc/Painter/Mask.cpp +++ b/uppsrc/Painter/Mask.cpp @@ -1,50 +1,50 @@ -#include "Painter.h" - -NAMESPACE_UPP - -void BufferPainter::BeginMaskOp() -{ - attr.mask = true; - Size sz = buffer.GetSize(); - mask.Add() = buffer; - buffer.Create(sz); - SetRbuf(); - Clear(RGBAZero()); - Begin(); -} - -void BufferPainter::FinishMask() -{ - RGBA *s = ~buffer; - RGBA *e = ~buffer + buffer.GetLength(); - byte *t, *cs; - if(clip.GetCount()) - cs = ~clip.Top(); - if(!attr.hasclip) { - clip.Add().Alloc(size.cx * size.cy); - attr.hasclip = true; - attr.cliplevel = clip.GetCount(); - } - t = ~clip.Top(); - if(clip.GetCount() == 1) - while(s < e) { - byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16; - *t = v; - s++; - t++; - } - else - while(s < e) { - byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16; - *t = (*cs * (v + (v >> 7))) >> 8; - s++; - t++; - cs++; - } - buffer = mask.Top(); - mask.Drop(); - SetRbuf(); - attr.mask = false; -} - -END_UPP_NAMESPACE \ No newline at end of file +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::BeginMaskOp() +{ + attr.mask = true; + Size sz = buffer.GetSize(); + mask.Add() = buffer; + buffer.Create(sz); + SetRbuf(); + Clear(RGBAZero()); + Begin(); +} + +void BufferPainter::FinishMask() +{ + RGBA *s = ~buffer; + RGBA *e = ~buffer + buffer.GetLength(); + byte *t, *cs; + if(clip.GetCount()) + cs = ~clip.Top(); + if(!attr.hasclip) { + clip.Add().Alloc(size.cx * size.cy); + attr.hasclip = true; + attr.cliplevel = clip.GetCount(); + } + t = ~clip.Top(); + if(clip.GetCount() == 1) + while(s < e) { + byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16; + *t = v; + s++; + t++; + } + else + while(s < e) { + byte v = ((s->a + (s->a >> 7)) * (77 * s->r + 151 * s->g + 28 * s->b)) >> 16; + *t = (*cs * (v + (v >> 7))) >> 8; + s++; + t++; + cs++; + } + buffer = mask.Top(); + mask.Drop(); + SetRbuf(); + attr.mask = false; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/Painter.cpp b/uppsrc/Painter/Painter.cpp index b2e2e416b..1086c5b5a 100644 --- a/uppsrc/Painter/Painter.cpp +++ b/uppsrc/Painter/Painter.cpp @@ -1,266 +1,266 @@ -#include "Painter.h" - -NAMESPACE_UPP - -void Painter::OffsetOp(Point p) -{ - Begin(); - Translate(p.x, p.y); -} - -void Painter::RectPath(int x, int y, int cx, int cy) -{ - Move(x, y).Line(x + cx - 1, y).Line(x + cx - 1, y + cy - 1).Line(x, y + cy - 1).Close(); -} - -void Painter::RectPath(const Rect& r) -{ - RectPath(r.left, r.top, r.GetWidth(), r.GetHeight()); -} - -bool Painter::ClipOp(const Rect& r) -{ - Begin(); - RectPath(r); - Clip(); - return true; -} - -bool Painter::ClipoffOp(const Rect& r) -{ - Begin(); - RectPath(r); - Clip(); - Translate(r.left, r.top); - return true; -} - -bool Painter::ExcludeClipOp(const Rect& r) -{ - return true; -} - -bool Painter::IntersectClipOp(const Rect& r) -{ - RectPath(r); - Clip(); - return true; -} - -Rect Painter::GetClipOp() const -{ - return Rect(0, 0, 0, 0); -} - -bool Painter::IsPaintingOp(const Rect& r) const -{ - return true; -} - -void Painter::DrawRectOp(int x, int y, int cx, int cy, Color color) -{ - RTIMING("Rect"); - RectPath(x, y, cx, cy); - Fill(color); -} - -void Painter::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) -{ - RectPath(x, y, cx, cy); - Fill(img, Translate2D(x, y)); -} - -void Painter::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) -{ -} - -void Painter::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) -{ - Move(x1, y1); - Line(x2, y2); - Stroke(width, color); -} - -void Painter::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, - int count_count, int width, Color color, Color doxor) -{ -} - -void Painter::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, - const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, - int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) -{ -} - -void Painter::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) -{ -} - -void Painter::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) -{ -} - -void Painter::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) -{ - RTIMING("DrawTextOp"); - Begin(); - EvenOdd(true); - if(angle) - Rotate(angle * M_2PI / 36000); - if(n < 0) - n = wstrlen(text); - double *ddx = NULL; - Buffer h; - if(dx) { - h.Alloc(n); - ddx = h; - for(int i = 0; i < n; i++) - ddx[i] = dx[i]; - } - Text(x, y, text, font, n, ddx); - Fill(ink); - End(); -} - -Painter& Painter::Move(double x, double y) -{ - return Move(x, y, false); -} - -Painter& Painter::Line(double x, double y) -{ - return Line(x, y, false); -} - -Painter& Painter::Quadratic(double x1, double y1, double x, double y) -{ - return Quadratic(x1, y1, x, y, false); -} - -Painter& Painter::Quadratic(double x, double y) -{ - return Quadratic(x, y, false); -} - -Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y) -{ - return Cubic(x1, y1, x2, y2, x, y, false); -} - -Painter& Painter::Cubic(double x2, double y2, double x, double y) -{ - return Cubic(x2, y2, x, y, false); -} - -Painter& Painter::RelMove(double x, double y) -{ - return Move(x, y, true); -} - -Painter& Painter::RelLine(double x, double y) -{ - return Line(x, y, true); -} - -Painter& Painter::RelQuadratic(double x1, double y1, double x, double y) -{ - return Quadratic(x1, y1, x, y, true); -} - -Painter& Painter::RelQuadratic(double x, double y) -{ - return Quadratic(x, y, true); -} - -Painter& Painter::RelCubic(double x1, double y1, double x2, double y2, double x, double y) -{ - return Cubic(x1, y1, x2, y2, x, y, true); -} - -Painter& Painter::RelCubic(double x2, double y2, double x, double y) -{ - return Cubic(x2, y2, x, y, true); -} - -Matrix2D GetImageLineMatrix(double x1, double y1, double x2, double y2, const Image& image) -{ - Matrix2D m; - Size sz = image.GetSize(); - m.scale(agg::calc_distance(x1, y1, x2, y2) / sz.cx); - if(abs(x2 - x1) < abs(y2 - y1) * 1e-6) - m.rotate(y2 > y1 ? M_PI_2 : -M_PI_2); - else - m.rotate(atan((y2 - y1) / (x2 - x1))); - m.translate(x1, y1); - return m; -} - -Painter& Painter::Fill(const Image& image, double x1, double y1, - double x2, double y2, dword flags) -{ - return Fill(image, GetImageLineMatrix(x1, y1, x2, y2, image), flags); -} - -Painter& Painter::Stroke(double width, const Image& image, double x1, double y1, - double x2, double y2, dword flags) -{ - return Stroke(width, image, GetImageLineMatrix(x1, y1, x2, y2, image), flags); -} - -Painter& Painter::Dash(const char *dash, double start) -{ - Vector d; - CParser p(dash); - try { - while(!p.IsEof()) - if(p.Char(':')) - start = p.ReadDouble(); - else - d.Add(p.ReadDouble()); - } - catch(CParser::Error) {} - Dash(d, start); - return *this; -} - -void Painter::Translate(double x, double y) -{ - Transform(Translate2D(x, y)); -} - -void Painter::Rotate(double a) -{ - Transform(Rotate2D(a)); -} - -void Painter::Scale(double scalex, double scaley) -{ - Transform(Scale2D(scalex, scaley)); -} - -void Painter::Scale(double scale) -{ - Transform(Scale2D(scale)); -} - -Painter& Painter::Ellipse(double x, double y, double rx, double ry) -{ - return Arc(x, y, rx, ry, 0, M_2PI); -} - -Painter& Painter::Circle(double x, double y, double r) -{ - return Ellipse(x, y, r, r); -} - -Painter& Painter::Rectangle(double x, double y, double cx, double cy) -{ - Move(x, y); - Line(x + cx, y); - Line(x + cx, y + cy); - Line(x, y + cy); - Close(); - return *this; -} - -END_UPP_NAMESPACE +#include "Painter.h" + +NAMESPACE_UPP + +void Painter::OffsetOp(Point p) +{ + Begin(); + Translate(p.x, p.y); +} + +void Painter::RectPath(int x, int y, int cx, int cy) +{ + Move(x, y).Line(x + cx - 1, y).Line(x + cx - 1, y + cy - 1).Line(x, y + cy - 1).Close(); +} + +void Painter::RectPath(const Rect& r) +{ + RectPath(r.left, r.top, r.GetWidth(), r.GetHeight()); +} + +bool Painter::ClipOp(const Rect& r) +{ + Begin(); + RectPath(r); + Clip(); + return true; +} + +bool Painter::ClipoffOp(const Rect& r) +{ + Begin(); + RectPath(r); + Clip(); + Translate(r.left, r.top); + return true; +} + +bool Painter::ExcludeClipOp(const Rect& r) +{ + return true; +} + +bool Painter::IntersectClipOp(const Rect& r) +{ + RectPath(r); + Clip(); + return true; +} + +Rect Painter::GetClipOp() const +{ + return Rect(0, 0, 0, 0); +} + +bool Painter::IsPaintingOp(const Rect& r) const +{ + return true; +} + +void Painter::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + RTIMING("Rect"); + RectPath(x, y, cx, cy); + Fill(color); +} + +void Painter::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + RectPath(x, y, cx, cy); + Fill(img, Translate2D(x, y)); +} + +void Painter::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) +{ +} + +void Painter::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + Move(x1, y1); + Line(x2, y2); + Stroke(width, color); +} + +void Painter::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, + int count_count, int width, Color color, Color doxor) +{ +} + +void Painter::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, + int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) +{ +} + +void Painter::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ +} + +void Painter::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ +} + +void Painter::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) +{ + RTIMING("DrawTextOp"); + Begin(); + EvenOdd(true); + if(angle) + Rotate(angle * M_2PI / 36000); + if(n < 0) + n = wstrlen(text); + double *ddx = NULL; + Buffer h; + if(dx) { + h.Alloc(n); + ddx = h; + for(int i = 0; i < n; i++) + ddx[i] = dx[i]; + } + Text(x, y, text, font, n, ddx); + Fill(ink); + End(); +} + +Painter& Painter::Move(double x, double y) +{ + return Move(x, y, false); +} + +Painter& Painter::Line(double x, double y) +{ + return Line(x, y, false); +} + +Painter& Painter::Quadratic(double x1, double y1, double x, double y) +{ + return Quadratic(x1, y1, x, y, false); +} + +Painter& Painter::Quadratic(double x, double y) +{ + return Quadratic(x, y, false); +} + +Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y) +{ + return Cubic(x1, y1, x2, y2, x, y, false); +} + +Painter& Painter::Cubic(double x2, double y2, double x, double y) +{ + return Cubic(x2, y2, x, y, false); +} + +Painter& Painter::RelMove(double x, double y) +{ + return Move(x, y, true); +} + +Painter& Painter::RelLine(double x, double y) +{ + return Line(x, y, true); +} + +Painter& Painter::RelQuadratic(double x1, double y1, double x, double y) +{ + return Quadratic(x1, y1, x, y, true); +} + +Painter& Painter::RelQuadratic(double x, double y) +{ + return Quadratic(x, y, true); +} + +Painter& Painter::RelCubic(double x1, double y1, double x2, double y2, double x, double y) +{ + return Cubic(x1, y1, x2, y2, x, y, true); +} + +Painter& Painter::RelCubic(double x2, double y2, double x, double y) +{ + return Cubic(x2, y2, x, y, true); +} + +Matrix2D GetImageLineMatrix(double x1, double y1, double x2, double y2, const Image& image) +{ + Matrix2D m; + Size sz = image.GetSize(); + m.scale(agg::calc_distance(x1, y1, x2, y2) / sz.cx); + if(fabs(x2 - x1) < fabs(y2 - y1) * 1e-6) + m.rotate(y2 > y1 ? M_PI_2 : -M_PI_2); + else + m.rotate(atan((y2 - y1) / (x2 - x1))); + m.translate(x1, y1); + return m; +} + +Painter& Painter::Fill(const Image& image, double x1, double y1, + double x2, double y2, dword flags) +{ + return Fill(image, GetImageLineMatrix(x1, y1, x2, y2, image), flags); +} + +Painter& Painter::Stroke(double width, const Image& image, double x1, double y1, + double x2, double y2, dword flags) +{ + return Stroke(width, image, GetImageLineMatrix(x1, y1, x2, y2, image), flags); +} + +Painter& Painter::Dash(const char *dash, double start) +{ + Vector d; + CParser p(dash); + try { + while(!p.IsEof()) + if(p.Char(':')) + start = p.ReadDouble(); + else + d.Add(p.ReadDouble()); + } + catch(CParser::Error) {} + Dash(d, start); + return *this; +} + +void Painter::Translate(double x, double y) +{ + Transform(Translate2D(x, y)); +} + +void Painter::Rotate(double a) +{ + Transform(Rotate2D(a)); +} + +void Painter::Scale(double scalex, double scaley) +{ + Transform(Scale2D(scalex, scaley)); +} + +void Painter::Scale(double scale) +{ + Transform(Scale2D(scale)); +} + +Painter& Painter::Ellipse(double x, double y, double rx, double ry) +{ + return Arc(x, y, rx, ry, 0, M_2PI); +} + +Painter& Painter::Circle(double x, double y, double r) +{ + return Ellipse(x, y, r, r); +} + +Painter& Painter::Rectangle(double x, double y, double cx, double cy) +{ + Move(x, y); + Line(x + cx, y); + Line(x + cx, y + cy); + Line(x, y + cy); + Close(); + return *this; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/Painter.hpp b/uppsrc/Painter/Painter.hpp index c502ff80d..e0df7ede5 100644 --- a/uppsrc/Painter/Painter.hpp +++ b/uppsrc/Painter/Painter.hpp @@ -1,185 +1,185 @@ -NAMESPACE_UPP - -inline void Painter::Clear(const RGBA& color) -{ - ClearOp(color); -} - -inline Painter& Painter::Move(double x, double y, bool rel) -{ - MoveOp(x, y, rel); - return *this; -} - -inline Painter& Painter::Line(double x, double y, bool rel) -{ - LineOp(x, y, rel); - return *this; -} - -inline Painter& Painter::Quadratic(double x1, double y1, double x, double y, bool rel) -{ - QuadraticOp(x1, y1, x, y, rel); - return *this; -} - -inline Painter& Painter::Quadratic(double x, double y, bool rel) -{ - QuadraticOp(x, y, rel); - return *this; -} - -inline Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel) -{ - CubicOp(x1, y1, x2, y2, x, y, rel); - return *this; -} - -inline Painter& Painter::Cubic(double x2, double y2, double x, double y, bool rel) -{ - CubicOp(x2, y2, x, y, rel); - return *this; -} - -inline Painter& Painter::Close() -{ - CloseOp(); - return *this; -} - -inline Painter& Painter::Fill(const RGBA& color) -{ - FillOp(color); - return *this; -} - -inline Painter& Painter::Fill(const Image& image, const Matrix2D& transsrc, dword flags) -{ - FillOp(image, transsrc, flags); - return *this; -} - -inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1, - double x2, double y2, const RGBA& color2, int style) -{ - FillOp(x1, y1, color1, x2, y2, color2, style); - return *this; -} - -inline Painter& Painter::Fill(double fx, double fy, const RGBA& color1, double x1, double y1, double r, const RGBA& color2, int style) -{ - FillOp(fx, fy, color1, x1, y1, r, color2, style); - return *this; -} - -inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style) -{ - return Fill(x1, y1, color1, x1, y1, r, color2, style); -} - -inline Painter& Painter::Stroke(double width, const RGBA& color) -{ - StrokeOp(width, color); - return *this; -} - -inline Painter& Painter::Stroke(double width, const Image& image, const Matrix2D& transsrc, dword flags) -{ - StrokeOp(width, image, transsrc, flags); - return *this; -} - -inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, - double x2, double y2, const RGBA& color2, int style) -{ - StrokeOp(width, x1, y1, color1, x2, y2, color2, style); - return *this; -} - -inline Painter& Painter::Stroke(double width, double fx, double fy, const RGBA& color1, - double x1, double y1, double r, const RGBA& color2, int style) -{ - StrokeOp(width, fx, fy, color1, x1, y1, r, color2, style); - return *this; -} - -inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style) -{ - return Stroke(width, x1, y1, color1, x1, y1, r, color2, style); -} - -inline Painter& Painter::Clip() -{ - ClipOp(); - return *this; -} - -inline Painter& Painter::ColorStop(double pos, const RGBA& color) -{ - ColorStopOp(pos, color); - return *this; -} - -inline Painter& Painter::ClearStops() -{ - ClearStopsOp(); - return *this; -} - -inline Painter& Painter::Opacity(double o) -{ - OpacityOp(o); - return *this; -} - -inline Painter& Painter::LineCap(int linecap) -{ - LineCapOp(linecap); - return *this; -} - -inline Painter& Painter::LineJoin(int linejoin) -{ - LineJoinOp(linejoin); - return *this; -} - -inline Painter& Painter::MiterLimit(double l) -{ - MiterLimitOp(l); - return *this; -} - -inline Painter& Painter::EvenOdd(bool evenodd) -{ - EvenOddOp(evenodd); - return *this; -} - -inline Painter& Painter::Dash(const Vector& dash, double start) -{ - DashOp(dash, start); - return *this; -} - -inline void Painter::Transform(const Matrix2D& m) -{ - TransformOp(m); -} - -inline void Painter::Begin() -{ - BeginOp(); -} - -inline void Painter::End() -{ - EndOp(); -} - -inline void Painter::BeginMask() -{ - BeginMaskOp(); -} - -END_UPP_NAMESPACE \ No newline at end of file +NAMESPACE_UPP + +inline void Painter::Clear(const RGBA& color) +{ + ClearOp(color); +} + +inline Painter& Painter::Move(double x, double y, bool rel) +{ + MoveOp(x, y, rel); + return *this; +} + +inline Painter& Painter::Line(double x, double y, bool rel) +{ + LineOp(x, y, rel); + return *this; +} + +inline Painter& Painter::Quadratic(double x1, double y1, double x, double y, bool rel) +{ + QuadraticOp(x1, y1, x, y, rel); + return *this; +} + +inline Painter& Painter::Quadratic(double x, double y, bool rel) +{ + QuadraticOp(x, y, rel); + return *this; +} + +inline Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel) +{ + CubicOp(x1, y1, x2, y2, x, y, rel); + return *this; +} + +inline Painter& Painter::Cubic(double x2, double y2, double x, double y, bool rel) +{ + CubicOp(x2, y2, x, y, rel); + return *this; +} + +inline Painter& Painter::Close() +{ + CloseOp(); + return *this; +} + +inline Painter& Painter::Fill(const RGBA& color) +{ + FillOp(color); + return *this; +} + +inline Painter& Painter::Fill(const Image& image, const Matrix2D& transsrc, dword flags) +{ + FillOp(image, transsrc, flags); + return *this; +} + +inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style) +{ + FillOp(x1, y1, color1, x2, y2, color2, style); + return *this; +} + +inline Painter& Painter::Fill(double fx, double fy, const RGBA& color1, double x1, double y1, double r, const RGBA& color2, int style) +{ + FillOp(fx, fy, color1, x1, y1, r, color2, style); + return *this; +} + +inline Painter& Painter::Fill(double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Fill(x1, y1, color1, x1, y1, r, color2, style); +} + +inline Painter& Painter::Stroke(double width, const RGBA& color) +{ + StrokeOp(width, color); + return *this; +} + +inline Painter& Painter::Stroke(double width, const Image& image, const Matrix2D& transsrc, dword flags) +{ + StrokeOp(width, image, transsrc, flags); + return *this; +} + +inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style) +{ + StrokeOp(width, x1, y1, color1, x2, y2, color2, style); + return *this; +} + +inline Painter& Painter::Stroke(double width, double fx, double fy, const RGBA& color1, + double x1, double y1, double r, const RGBA& color2, int style) +{ + StrokeOp(width, fx, fy, color1, x1, y1, r, color2, style); + return *this; +} + +inline Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Stroke(width, x1, y1, color1, x1, y1, r, color2, style); +} + +inline Painter& Painter::Clip() +{ + ClipOp(); + return *this; +} + +inline Painter& Painter::ColorStop(double pos, const RGBA& color) +{ + ColorStopOp(pos, color); + return *this; +} + +inline Painter& Painter::ClearStops() +{ + ClearStopsOp(); + return *this; +} + +inline Painter& Painter::Opacity(double o) +{ + OpacityOp(o); + return *this; +} + +inline Painter& Painter::LineCap(int linecap) +{ + LineCapOp(linecap); + return *this; +} + +inline Painter& Painter::LineJoin(int linejoin) +{ + LineJoinOp(linejoin); + return *this; +} + +inline Painter& Painter::MiterLimit(double l) +{ + MiterLimitOp(l); + return *this; +} + +inline Painter& Painter::EvenOdd(bool evenodd) +{ + EvenOddOp(evenodd); + return *this; +} + +inline Painter& Painter::Dash(const Vector& dash, double start) +{ + DashOp(dash, start); + return *this; +} + +inline void Painter::Transform(const Matrix2D& m) +{ + TransformOp(m); +} + +inline void Painter::Begin() +{ + BeginOp(); +} + +inline void Painter::End() +{ + EndOp(); +} + +inline void Painter::BeginMask() +{ + BeginMaskOp(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Painter/agg_path_storage.h b/uppsrc/Painter/agg_path_storage.h index 5267df200..fc8dedd36 100644 --- a/uppsrc/Painter/agg_path_storage.h +++ b/uppsrc/Painter/agg_path_storage.h @@ -1,1543 +1,1543 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -#ifndef AGG_PATH_STORAGE_INCLUDED -#define AGG_PATH_STORAGE_INCLUDED - -#include -#include -#include "agg_math.h" -#include "agg_array.h" -//#include "agg_bezier_arc.h" - -namespace agg -{ - - - //----------------------------------------------------vertex_block_storage - template - class vertex_block_storage - { - public: - // Allocation parameters - enum block_scale_e - { - block_shift = BlockShift, - block_size = 1 << block_shift, - block_mask = block_size - 1, - block_pool = BlockPool - }; - - typedef T value_type; - typedef vertex_block_storage self_type; - - ~vertex_block_storage(); - vertex_block_storage(); - vertex_block_storage(const self_type& v); - const self_type& operator = (const self_type& ps); - - void remove_all(); - void free_all(); - - void add_vertex(double x, double y, unsigned cmd); - void modify_vertex(unsigned idx, double x, double y); - void modify_vertex(unsigned idx, double x, double y, unsigned cmd); - void modify_command(unsigned idx, unsigned cmd); - void swap_vertices(unsigned v1, unsigned v2); - - unsigned last_command() const; - unsigned last_vertex(double* x, double* y) const; - unsigned prev_vertex(double* x, double* y) const; - - double last_x() const; - double last_y() const; - - unsigned total_vertices() const; - unsigned vertex(unsigned idx, double* x, double* y) const; - unsigned command(unsigned idx) const; - - private: - void allocate_block(unsigned nb); - int8u* storage_ptrs(T** xy_ptr); - - private: - unsigned m_total_vertices; - unsigned m_total_blocks; - unsigned m_max_blocks; - T** m_coord_blocks; - int8u** m_cmd_blocks; - }; - - - //------------------------------------------------------------------------ - template - void vertex_block_storage::free_all() - { - if(m_total_blocks) - { - T** coord_blk = m_coord_blocks + m_total_blocks - 1; - while(m_total_blocks--) - { - pod_allocator::deallocate( - *coord_blk, - block_size * 2 + - block_size / (sizeof(T) / sizeof(unsigned char))); - --coord_blk; - } - pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); - m_total_blocks = 0; - m_max_blocks = 0; - m_coord_blocks = 0; - m_cmd_blocks = 0; - m_total_vertices = 0; - } - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::~vertex_block_storage() - { - free_all(); - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::vertex_block_storage() : - m_total_vertices(0), - m_total_blocks(0), - m_max_blocks(0), - m_coord_blocks(0), - m_cmd_blocks(0) - { - } - - //------------------------------------------------------------------------ - template - vertex_block_storage::vertex_block_storage(const vertex_block_storage& v) : - m_total_vertices(0), - m_total_blocks(0), - m_max_blocks(0), - m_coord_blocks(0), - m_cmd_blocks(0) - { - *this = v; - } - - //------------------------------------------------------------------------ - template - const vertex_block_storage& - vertex_block_storage::operator = (const vertex_block_storage& v) - { - remove_all(); - unsigned i; - for(i = 0; i < v.total_vertices(); i++) - { - double x, y; - unsigned cmd = v.vertex(i, &x, &y); - add_vertex(x, y, cmd); - } - return *this; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::remove_all() - { - m_total_vertices = 0; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::add_vertex(double x, double y, - unsigned cmd) - { - T* coord_ptr = 0; - *storage_ptrs(&coord_ptr) = (int8u)cmd; - coord_ptr[0] = T(x); - coord_ptr[1] = T(y); - m_total_vertices++; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_vertex(unsigned idx, - double x, double y) - { - T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); - pv[0] = T(x); - pv[1] = T(y); - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_vertex(unsigned idx, - double x, double y, - unsigned cmd) - { - unsigned block = idx >> block_shift; - unsigned offset = idx & block_mask; - T* pv = m_coord_blocks[block] + (offset << 1); - pv[0] = T(x); - pv[1] = T(y); - m_cmd_blocks[block][offset] = (int8u)cmd; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::modify_command(unsigned idx, - unsigned cmd) - { - m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; - } - - //------------------------------------------------------------------------ - template - inline void vertex_block_storage::swap_vertices(unsigned v1, unsigned v2) - { - unsigned b1 = v1 >> block_shift; - unsigned b2 = v2 >> block_shift; - unsigned o1 = v1 & block_mask; - unsigned o2 = v2 & block_mask; - T* pv1 = m_coord_blocks[b1] + (o1 << 1); - T* pv2 = m_coord_blocks[b2] + (o2 << 1); - T val; - val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val; - val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val; - int8u cmd = m_cmd_blocks[b1][o1]; - m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2]; - m_cmd_blocks[b2][o2] = cmd; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::last_command() const - { - if(m_total_vertices) return command(m_total_vertices - 1); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::last_vertex(double* x, double* y) const - { - if(m_total_vertices) return vertex(m_total_vertices - 1, x, y); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::prev_vertex(double* x, double* y) const - { - if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y); - return path_cmd_stop; - } - - //------------------------------------------------------------------------ - template - inline double vertex_block_storage::last_x() const - { - if(m_total_vertices) - { - unsigned idx = m_total_vertices - 1; - return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1]; - } - return 0.0; - } - - //------------------------------------------------------------------------ - template - inline double vertex_block_storage::last_y() const - { - if(m_total_vertices) - { - unsigned idx = m_total_vertices - 1; - return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1]; - } - return 0.0; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::total_vertices() const - { - return m_total_vertices; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::vertex(unsigned idx, - double* x, double* y) const - { - unsigned nb = idx >> block_shift; - const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); - *x = pv[0]; - *y = pv[1]; - return m_cmd_blocks[nb][idx & block_mask]; - } - - //------------------------------------------------------------------------ - template - inline unsigned vertex_block_storage::command(unsigned idx) const - { - return m_cmd_blocks[idx >> block_shift][idx & block_mask]; - } - - //------------------------------------------------------------------------ - template - void vertex_block_storage::allocate_block(unsigned nb) - { - if(nb >= m_max_blocks) - { - T** new_coords = - pod_allocator::allocate((m_max_blocks + block_pool) * 2); - - unsigned char** new_cmds = - (unsigned char**)(new_coords + m_max_blocks + block_pool); - - if(m_coord_blocks) - { - memcpy(new_coords, - m_coord_blocks, - m_max_blocks * sizeof(T*)); - - memcpy(new_cmds, - m_cmd_blocks, - m_max_blocks * sizeof(unsigned char*)); - - pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); - } - m_coord_blocks = new_coords; - m_cmd_blocks = new_cmds; - m_max_blocks += block_pool; - } - m_coord_blocks[nb] = - pod_allocator::allocate(block_size * 2 + - block_size / (sizeof(T) / sizeof(unsigned char))); - - m_cmd_blocks[nb] = - (unsigned char*)(m_coord_blocks[nb] + block_size * 2); - - m_total_blocks++; - } - - //------------------------------------------------------------------------ - template - int8u* vertex_block_storage::storage_ptrs(T** xy_ptr) - { - unsigned nb = m_total_vertices >> block_shift; - if(nb >= m_total_blocks) - { - allocate_block(nb); - } - *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); - return m_cmd_blocks[nb] + (m_total_vertices & block_mask); - } - - - - - //-----------------------------------------------------poly_plain_adaptor - template class poly_plain_adaptor - { - public: - typedef T value_type; - - poly_plain_adaptor() : - m_data(0), - m_ptr(0), - m_end(0), - m_closed(false), - m_stop(false) - {} - - poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : - m_data(data), - m_ptr(data), - m_end(data + num_points * 2), - m_closed(closed), - m_stop(false) - {} - - void init(const T* data, unsigned num_points, bool closed) - { - m_data = data; - m_ptr = data; - m_end = data + num_points * 2; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_ptr = m_data; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_ptr < m_end) - { - bool first = m_ptr == m_data; - *x = *m_ptr++; - *y = *m_ptr++; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const T* m_data; - const T* m_ptr; - const T* m_end; - bool m_closed; - bool m_stop; - }; - - - - - - //-------------------------------------------------poly_container_adaptor - template class poly_container_adaptor - { - public: - typedef typename Container::value_type vertex_type; - - poly_container_adaptor() : - m_container(0), - m_index(0), - m_closed(false), - m_stop(false) - {} - - poly_container_adaptor(const Container& data, bool closed) : - m_container(&data), - m_index(0), - m_closed(closed), - m_stop(false) - {} - - void init(const Container& data, bool closed) - { - m_container = &data; - m_index = 0; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_index = 0; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_index < m_container->size()) - { - bool first = m_index == 0; - const vertex_type& v = (*m_container)[m_index++]; - *x = v.x; - *y = v.y; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const Container* m_container; - unsigned m_index; - bool m_closed; - bool m_stop; - }; - - - - //-----------------------------------------poly_container_reverse_adaptor - template class poly_container_reverse_adaptor - { - public: - typedef typename Container::value_type vertex_type; - - poly_container_reverse_adaptor() : - m_container(0), - m_index(-1), - m_closed(false), - m_stop(false) - {} - - poly_container_reverse_adaptor(const Container& data, bool closed) : - m_container(&data), - m_index(-1), - m_closed(closed), - m_stop(false) - {} - - void init(const Container& data, bool closed) - { - m_container = &data; - m_index = m_container->size() - 1; - m_closed = closed; - m_stop = false; - } - - void rewind(unsigned) - { - m_index = m_container->size() - 1; - m_stop = false; - } - - unsigned vertex(double* x, double* y) - { - if(m_index >= 0) - { - bool first = m_index == int(m_container->size() - 1); - const vertex_type& v = (*m_container)[m_index--]; - *x = v.x; - *y = v.y; - return first ? path_cmd_move_to : path_cmd_line_to; - } - *x = *y = 0.0; - if(m_closed && !m_stop) - { - m_stop = true; - return path_cmd_end_poly | path_flags_close; - } - return path_cmd_stop; - } - - private: - const Container* m_container; - int m_index; - bool m_closed; - bool m_stop; - }; - - - - - - //--------------------------------------------------------line_adaptor - class line_adaptor - { - public: - typedef double value_type; - - line_adaptor() : m_line(m_coord, 2, false) {} - line_adaptor(double x1, double y1, double x2, double y2) : - m_line(m_coord, 2, false) - { - m_coord[0] = x1; - m_coord[1] = y1; - m_coord[2] = x2; - m_coord[3] = y2; - } - - void init(double x1, double y1, double x2, double y2) - { - m_coord[0] = x1; - m_coord[1] = y1; - m_coord[2] = x2; - m_coord[3] = y2; - m_line.rewind(0); - } - - void rewind(unsigned) - { - m_line.rewind(0); - } - - unsigned vertex(double* x, double* y) - { - return m_line.vertex(x, y); - } - - private: - double m_coord[4]; - poly_plain_adaptor m_line; - }; - - - - - - - - - - - - - - //---------------------------------------------------------------path_base - // A container to store vertices with their flags. - // A path consists of a number of contours separated with "move_to" - // commands. The path storage can keep and maintain more than one - // path. - // To navigate to the beginning of a particular path, use rewind(path_id); - // Where path_id is what start_new_path() returns. So, when you call - // start_new_path() you need to store its return value somewhere else - // to navigate to the path afterwards. - // - // See also: vertex_source concept - //------------------------------------------------------------------------ - template class path_base - { - public: - typedef VertexContainer container_type; - typedef path_base self_type; - - //-------------------------------------------------------------------- - path_base() : m_vertices(), m_iterator(0) {} - void remove_all() { m_vertices.remove_all(); m_iterator = 0; } - void free_all() { m_vertices.free_all(); m_iterator = 0; } - - // Make path functions - //-------------------------------------------------------------------- - unsigned start_new_path(); - - void move_to(double x, double y); - void move_rel(double dx, double dy); - - void line_to(double x, double y); - void line_rel(double dx, double dy); - - void hline_to(double x); - void hline_rel(double dx); - - void vline_to(double y); - void vline_rel(double dy); - - void arc_to(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x, double y); - - void arc_rel(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double dx, double dy); - - void curve3(double x_ctrl, double y_ctrl, - double x_to, double y_to); - - void curve3_rel(double dx_ctrl, double dy_ctrl, - double dx_to, double dy_to); - - void curve3(double x_to, double y_to); - - void curve3_rel(double dx_to, double dy_to); - - void curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - void curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to); - - void curve4(double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - void curve4_rel(double x_ctrl2, double y_ctrl2, - double x_to, double y_to); - - - void end_poly(unsigned flags = path_flags_close); - void close_polygon(unsigned flags = path_flags_none); - - // Accessors - //-------------------------------------------------------------------- - const container_type& vertices() const { return m_vertices; } - container_type& vertices() { return m_vertices; } - - unsigned total_vertices() const; - - void rel_to_abs(double* x, double* y) const; - - unsigned last_vertex(double* x, double* y) const; - unsigned prev_vertex(double* x, double* y) const; - - double last_x() const; - double last_y() const; - - unsigned vertex(unsigned idx, double* x, double* y) const; - unsigned command(unsigned idx) const; - - void modify_vertex(unsigned idx, double x, double y); - void modify_vertex(unsigned idx, double x, double y, unsigned cmd); - void modify_command(unsigned idx, unsigned cmd); - - // VertexSource interface - //-------------------------------------------------------------------- - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - - // Arrange the orientation of a polygon, all polygons in a path, - // or in all paths. After calling arrange_orientations() or - // arrange_orientations_all_paths(), all the polygons will have - // the same orientation, i.e. path_flags_cw or path_flags_ccw - //-------------------------------------------------------------------- - unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); - unsigned arrange_orientations(unsigned path_id, path_flags_e orientation); - void arrange_orientations_all_paths(path_flags_e orientation); - void invert_polygon(unsigned start); - - // Flip all vertices horizontally or vertically, - // between x1 and x2, or between y1 and y2 respectively - //-------------------------------------------------------------------- - void flip_x(double x1, double x2); - void flip_y(double y1, double y2); - - // Concatenate path. The path is added as is. - //-------------------------------------------------------------------- - template - void concat_path(VertexSource& vs, unsigned path_id = 0) - { - double x, y; - unsigned cmd; - vs.rewind(path_id); - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - m_vertices.add_vertex(x, y, cmd); - } - } - - //-------------------------------------------------------------------- - // Join path. The path is joined with the existing one, that is, - // it behaves as if the pen of a plotter was always down (drawing) - template - void join_path(VertexSource& vs, unsigned path_id = 0) - { - double x, y; - unsigned cmd; - vs.rewind(path_id); - cmd = vs.vertex(&x, &y); - if(!is_stop(cmd)) - { - if(is_vertex(cmd)) - { - double x0, y0; - unsigned cmd0 = last_vertex(&x0, &y0); - if(is_vertex(cmd0)) - { - if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) - { - if(is_move_to(cmd)) cmd = path_cmd_line_to; - m_vertices.add_vertex(x, y, cmd); - } - } - else - { - if(is_stop(cmd0)) - { - cmd = path_cmd_move_to; - } - else - { - if(is_move_to(cmd)) cmd = path_cmd_line_to; - } - m_vertices.add_vertex(x, y, cmd); - } - } - while(!is_stop(cmd = vs.vertex(&x, &y))) - { - m_vertices.add_vertex(x, y, is_move_to(cmd) ? - unsigned(path_cmd_line_to) : - cmd); - } - } - } - - // Concatenate polygon/polyline. - //-------------------------------------------------------------------- - template void concat_poly(const T* data, - unsigned num_points, - bool closed) - { - poly_plain_adaptor poly(data, num_points, closed); - concat_path(poly); - } - - // Join polygon/polyline continuously. - //-------------------------------------------------------------------- - template void join_poly(const T* data, - unsigned num_points, - bool closed) - { - poly_plain_adaptor poly(data, num_points, closed); - join_path(poly); - } - - //-------------------------------------------------------------------- - void translate(double dx, double dy, unsigned path_id=0); - void translate_all_paths(double dx, double dy); - - //-------------------------------------------------------------------- - template - void transform(const Trans& trans, unsigned path_id=0) - { - unsigned num_ver = m_vertices.total_vertices(); - for(; path_id < num_ver; path_id++) - { - double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); - if(is_stop(cmd)) break; - if(is_vertex(cmd)) - { - trans.transform(&x, &y); - m_vertices.modify_vertex(path_id, x, y); - } - } - } - - //-------------------------------------------------------------------- - template - void transform_all_paths(const Trans& trans) - { - unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); - for(idx = 0; idx < num_ver; idx++) - { - double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) - { - trans.transform(&x, &y); - m_vertices.modify_vertex(idx, x, y); - } - } - } - - private: - unsigned perceive_polygon_orientation(unsigned start, unsigned end); - void invert_polygon(unsigned start, unsigned end); - - VertexContainer m_vertices; - unsigned m_iterator; - }; - - //------------------------------------------------------------------------ - template - unsigned path_base::start_new_path() - { - if(!is_stop(m_vertices.last_command())) - { - m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); - } - return m_vertices.total_vertices(); - } - - - //------------------------------------------------------------------------ - template - inline void path_base::rel_to_abs(double* x, double* y) const - { - if(m_vertices.total_vertices()) - { - double x2; - double y2; - if(is_vertex(m_vertices.last_vertex(&x2, &y2))) - { - *x += x2; - *y += y2; - } - } - } - - //------------------------------------------------------------------------ - template - inline void path_base::move_to(double x, double y) - { - m_vertices.add_vertex(x, y, path_cmd_move_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::move_rel(double dx, double dy) - { - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_move_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::line_to(double x, double y) - { - m_vertices.add_vertex(x, y, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::line_rel(double dx, double dy) - { - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::hline_to(double x) - { - m_vertices.add_vertex(x, last_y(), path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::hline_rel(double dx) - { - double dy = 0; - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::vline_to(double y) - { - m_vertices.add_vertex(last_x(), y, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::vline_rel(double dy) - { - double dx = 0; - rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); - } - - //------------------------------------------------------------------------ - template - void path_base::arc_to(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double x, double y) - { - if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) - { - const double epsilon = 1e-30; - double x0 = 0.0; - double y0 = 0.0; - m_vertices.last_vertex(&x0, &y0); - - rx = fabs(rx); - ry = fabs(ry); - - // Ensure radii are valid - //------------------------- - if(rx < epsilon || ry < epsilon) - { - line_to(x, y); - return; - } - - if(calc_distance(x0, y0, x, y) < epsilon) - { - // If the endpoints (x, y) and (x0, y0) are identical, then this - // is equivalent to omitting the elliptical arc segment entirely. - return; - } - bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); - if(a.radii_ok()) - { - join_path(a); - } - else - { - line_to(x, y); - } - } - else - { - move_to(x, y); - } - } - - //------------------------------------------------------------------------ - template - void path_base::arc_rel(double rx, double ry, - double angle, - bool large_arc_flag, - bool sweep_flag, - double dx, double dy) - { - rel_to_abs(&dx, &dy); - arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3(double x_ctrl, double y_ctrl, - double x_to, double y_to) - { - m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl, &dy_ctrl); - rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); - } - - //------------------------------------------------------------------------ - template - void path_base::curve3(double x_to, double y_to) - { - double x0; - double y0; - if(is_vertex(m_vertices.last_vertex(&x0, &y0))) - { - double x_ctrl; - double y_ctrl; - unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); - if(is_curve(cmd)) - { - x_ctrl = x0 + x0 - x_ctrl; - y_ctrl = y0 + y0 - y_ctrl; - } - else - { - x_ctrl = x0; - y_ctrl = y0; - } - curve3(x_ctrl, y_ctrl, x_to, y_to); - } - } - - //------------------------------------------------------------------------ - template - void path_base::curve3_rel(double dx_to, double dy_to) - { - rel_to_abs(&dx_to, &dy_to); - curve3(dx_to, dy_to); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl1, double y_ctrl1, - double x_ctrl2, double y_ctrl2, - double x_to, double y_to) - { - m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, - double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl1, &dy_ctrl1); - rel_to_abs(&dx_ctrl2, &dy_ctrl2); - rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); - } - - //------------------------------------------------------------------------ - template - void path_base::curve4(double x_ctrl2, double y_ctrl2, - double x_to, double y_to) - { - double x0; - double y0; - if(is_vertex(last_vertex(&x0, &y0))) - { - double x_ctrl1; - double y_ctrl1; - unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); - if(is_curve(cmd)) - { - x_ctrl1 = x0 + x0 - x_ctrl1; - y_ctrl1 = y0 + y0 - y_ctrl1; - } - else - { - x_ctrl1 = x0; - y_ctrl1 = y0; - } - curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); - } - } - - //------------------------------------------------------------------------ - template - void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, - double dx_to, double dy_to) - { - rel_to_abs(&dx_ctrl2, &dy_ctrl2); - rel_to_abs(&dx_to, &dy_to); - curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); - } - - //------------------------------------------------------------------------ - template - inline void path_base::end_poly(unsigned flags) - { - if(is_vertex(m_vertices.last_command())) - { - m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); - } - } - - //------------------------------------------------------------------------ - template - inline void path_base::close_polygon(unsigned flags) - { - end_poly(path_flags_close | flags); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::total_vertices() const - { - return m_vertices.total_vertices(); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::last_vertex(double* x, double* y) const - { - return m_vertices.last_vertex(x, y); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::prev_vertex(double* x, double* y) const - { - return m_vertices.prev_vertex(x, y); - } - - //------------------------------------------------------------------------ - template - inline double path_base::last_x() const - { - return m_vertices.last_x(); - } - - //------------------------------------------------------------------------ - template - inline double path_base::last_y() const - { - return m_vertices.last_y(); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::vertex(unsigned idx, double* x, double* y) const - { - return m_vertices.vertex(idx, x, y); - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::command(unsigned idx) const - { - return m_vertices.command(idx); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_vertex(unsigned idx, double x, double y) - { - m_vertices.modify_vertex(idx, x, y); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_vertex(unsigned idx, double x, double y, unsigned cmd) - { - m_vertices.modify_vertex(idx, x, y, cmd); - } - - //------------------------------------------------------------------------ - template - void path_base::modify_command(unsigned idx, unsigned cmd) - { - m_vertices.modify_command(idx, cmd); - } - - //------------------------------------------------------------------------ - template - inline void path_base::rewind(unsigned path_id) - { - m_iterator = path_id; - } - - //------------------------------------------------------------------------ - template - inline unsigned path_base::vertex(double* x, double* y) - { - if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; - return m_vertices.vertex(m_iterator++, x, y); - } - - //------------------------------------------------------------------------ - template - unsigned path_base::perceive_polygon_orientation(unsigned start, - unsigned end) - { - // Calculate signed area (double area to be exact) - //--------------------- - unsigned np = end - start; - double area = 0.0; - unsigned i; - for(i = 0; i < np; i++) - { - double x1, y1, x2, y2; - m_vertices.vertex(start + i, &x1, &y1); - m_vertices.vertex(start + (i + 1) % np, &x2, &y2); - area += x1 * y2 - y1 * x2; - } - return (area < 0.0) ? path_flags_cw : path_flags_ccw; - } - - //------------------------------------------------------------------------ - template - void path_base::invert_polygon(unsigned start, unsigned end) - { - unsigned i; - unsigned tmp_cmd = m_vertices.command(start); - - --end; // Make "end" inclusive - - // Shift all commands to one position - for(i = start; i < end; i++) - { - m_vertices.modify_command(i, m_vertices.command(i + 1)); - } - - // Assign starting command to the ending command - m_vertices.modify_command(end, tmp_cmd); - - // Reverse the polygon - while(end > start) - { - m_vertices.swap_vertices(start++, end--); - } - } - - //------------------------------------------------------------------------ - template - void path_base::invert_polygon(unsigned start) - { - // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; - - // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; - - // Find the last vertex - unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; - - invert_polygon(start, end); - } - - //------------------------------------------------------------------------ - template - unsigned path_base::arrange_polygon_orientation(unsigned start, - path_flags_e orientation) - { - if(orientation == path_flags_none) return start; - - // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; - - // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; - - // Find the last vertex - unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; - - if(end - start > 2) - { - if(perceive_polygon_orientation(start, end) != unsigned(orientation)) - { - // Invert polygon, set orientation flag, and skip all end_poly - invert_polygon(start, end); - unsigned cmd; - while(end < m_vertices.total_vertices() && - is_end_poly(cmd = m_vertices.command(end))) - { - m_vertices.modify_command(end++, set_orientation(cmd, orientation)); - } - } - } - return end; - } - - //------------------------------------------------------------------------ - template - unsigned path_base::arrange_orientations(unsigned start, - path_flags_e orientation) - { - if(orientation != path_flags_none) - { - while(start < m_vertices.total_vertices()) - { - start = arrange_polygon_orientation(start, orientation); - if(is_stop(m_vertices.command(start))) - { - ++start; - break; - } - } - } - return start; - } - - //------------------------------------------------------------------------ - template - void path_base::arrange_orientations_all_paths(path_flags_e orientation) - { - if(orientation != path_flags_none) - { - unsigned start = 0; - while(start < m_vertices.total_vertices()) - { - start = arrange_orientations(start, orientation); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::flip_x(double x1, double x2) - { - unsigned i; - double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) - { - unsigned cmd = m_vertices.vertex(i, &x, &y); - if(is_vertex(cmd)) - { - m_vertices.modify_vertex(i, x2 - x + x1, y); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::flip_y(double y1, double y2) - { - unsigned i; - double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) - { - unsigned cmd = m_vertices.vertex(i, &x, &y); - if(is_vertex(cmd)) - { - m_vertices.modify_vertex(i, x, y2 - y + y1); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::translate(double dx, double dy, unsigned path_id) - { - unsigned num_ver = m_vertices.total_vertices(); - for(; path_id < num_ver; path_id++) - { - double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); - if(is_stop(cmd)) break; - if(is_vertex(cmd)) - { - x += dx; - y += dy; - m_vertices.modify_vertex(path_id, x, y); - } - } - } - - //------------------------------------------------------------------------ - template - void path_base::translate_all_paths(double dx, double dy) - { - unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); - for(idx = 0; idx < num_ver; idx++) - { - double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) - { - x += dx; - y += dy; - m_vertices.modify_vertex(idx, x, y); - } - } - } - - //-----------------------------------------------------vertex_stl_storage - template class vertex_stl_storage - { - public: - typedef typename Container::value_type vertex_type; - typedef typename vertex_type::value_type value_type; - - void remove_all() { m_vertices.clear(); } - void free_all() { m_vertices.clear(); } - - void add_vertex(double x, double y, unsigned cmd) - { - m_vertices.push_back(vertex_type(value_type(x), - value_type(y), - int8u(cmd))); - } - - void modify_vertex(unsigned idx, double x, double y) - { - vertex_type& v = m_vertices[idx]; - v.x = value_type(x); - v.y = value_type(y); - } - - void modify_vertex(unsigned idx, double x, double y, unsigned cmd) - { - vertex_type& v = m_vertices[idx]; - v.x = value_type(x); - v.y = value_type(y); - v.cmd = int8u(cmd); - } - - void modify_command(unsigned idx, unsigned cmd) - { - m_vertices[idx].cmd = int8u(cmd); - } - - void swap_vertices(unsigned v1, unsigned v2) - { - vertex_type t = m_vertices[v1]; - m_vertices[v1] = m_vertices[v2]; - m_vertices[v2] = t; - } - - unsigned last_command() const - { - return m_vertices.size() ? - m_vertices[m_vertices.size() - 1].cmd : - path_cmd_stop; - } - - unsigned last_vertex(double* x, double* y) const - { - if(m_vertices.size() == 0) - { - *x = *y = 0.0; - return path_cmd_stop; - } - return vertex(m_vertices.size() - 1, x, y); - } - - unsigned prev_vertex(double* x, double* y) const - { - if(m_vertices.size() < 2) - { - *x = *y = 0.0; - return path_cmd_stop; - } - return vertex(m_vertices.size() - 2, x, y); - } - - double last_x() const - { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; - } - - double last_y() const - { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; - } - - unsigned total_vertices() const - { - return m_vertices.size(); - } - - unsigned vertex(unsigned idx, double* x, double* y) const - { - const vertex_type& v = m_vertices[idx]; - *x = v.x; - *y = v.y; - return v.cmd; - } - - unsigned command(unsigned idx) const - { - return m_vertices[idx].cmd; - } - - private: - Container m_vertices; - }; - - //-----------------------------------------------------------path_storage - typedef path_base > path_storage; - - // Example of declarations path_storage with pod_bvector as a container - //----------------------------------------------------------------------- - //typedef path_base > > path_storage; - -} - - - -// Example of declarations path_storage with std::vector as a container -//--------------------------------------------------------------------------- -//#include -//namespace agg -//{ -// typedef path_base > > stl_path_storage; -//} - - - - -#endif +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +#ifndef AGG_PATH_STORAGE_INCLUDED +#define AGG_PATH_STORAGE_INCLUDED + +#include +#include +#include "agg_math.h" +#include "agg_array.h" +//#include "agg_bezier_arc.h" + +namespace agg +{ + + + //----------------------------------------------------vertex_block_storage + template + class vertex_block_storage + { + public: + // Allocation parameters + enum block_scale_e + { + block_shift = BlockShift, + block_size = 1 << block_shift, + block_mask = block_size - 1, + block_pool = BlockPool + }; + + typedef T value_type; + typedef vertex_block_storage self_type; + + ~vertex_block_storage(); + vertex_block_storage(); + vertex_block_storage(const self_type& v); + const self_type& operator = (const self_type& ps); + + void remove_all(); + void free_all(); + + void add_vertex(double x, double y, unsigned cmd); + void modify_vertex(unsigned idx, double x, double y); + void modify_vertex(unsigned idx, double x, double y, unsigned cmd); + void modify_command(unsigned idx, unsigned cmd); + void swap_vertices(unsigned v1, unsigned v2); + + unsigned last_command() const; + unsigned last_vertex(double* x, double* y) const; + unsigned prev_vertex(double* x, double* y) const; + + double last_x() const; + double last_y() const; + + unsigned total_vertices() const; + unsigned vertex(unsigned idx, double* x, double* y) const; + unsigned command(unsigned idx) const; + + private: + void allocate_block(unsigned nb); + int8u* storage_ptrs(T** xy_ptr); + + private: + unsigned m_total_vertices; + unsigned m_total_blocks; + unsigned m_max_blocks; + T** m_coord_blocks; + int8u** m_cmd_blocks; + }; + + + //------------------------------------------------------------------------ + template + void vertex_block_storage::free_all() + { + if(m_total_blocks) + { + T** coord_blk = m_coord_blocks + m_total_blocks - 1; + while(m_total_blocks--) + { + pod_allocator::deallocate( + *coord_blk, + block_size * 2 + + block_size / (sizeof(T) / sizeof(unsigned char))); + --coord_blk; + } + pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); + m_total_blocks = 0; + m_max_blocks = 0; + m_coord_blocks = 0; + m_cmd_blocks = 0; + m_total_vertices = 0; + } + } + + //------------------------------------------------------------------------ + template + vertex_block_storage::~vertex_block_storage() + { + free_all(); + } + + //------------------------------------------------------------------------ + template + vertex_block_storage::vertex_block_storage() : + m_total_vertices(0), + m_total_blocks(0), + m_max_blocks(0), + m_coord_blocks(0), + m_cmd_blocks(0) + { + } + + //------------------------------------------------------------------------ + template + vertex_block_storage::vertex_block_storage(const vertex_block_storage& v) : + m_total_vertices(0), + m_total_blocks(0), + m_max_blocks(0), + m_coord_blocks(0), + m_cmd_blocks(0) + { + *this = v; + } + + //------------------------------------------------------------------------ + template + const vertex_block_storage& + vertex_block_storage::operator = (const vertex_block_storage& v) + { + remove_all(); + unsigned i; + for(i = 0; i < v.total_vertices(); i++) + { + double x, y; + unsigned cmd = v.vertex(i, &x, &y); + add_vertex(x, y, cmd); + } + return *this; + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::remove_all() + { + m_total_vertices = 0; + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::add_vertex(double x, double y, + unsigned cmd) + { + T* coord_ptr = 0; + *storage_ptrs(&coord_ptr) = (int8u)cmd; + coord_ptr[0] = T(x); + coord_ptr[1] = T(y); + m_total_vertices++; + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::modify_vertex(unsigned idx, + double x, double y) + { + T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); + pv[0] = T(x); + pv[1] = T(y); + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::modify_vertex(unsigned idx, + double x, double y, + unsigned cmd) + { + unsigned block = idx >> block_shift; + unsigned offset = idx & block_mask; + T* pv = m_coord_blocks[block] + (offset << 1); + pv[0] = T(x); + pv[1] = T(y); + m_cmd_blocks[block][offset] = (int8u)cmd; + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::modify_command(unsigned idx, + unsigned cmd) + { + m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; + } + + //------------------------------------------------------------------------ + template + inline void vertex_block_storage::swap_vertices(unsigned v1, unsigned v2) + { + unsigned b1 = v1 >> block_shift; + unsigned b2 = v2 >> block_shift; + unsigned o1 = v1 & block_mask; + unsigned o2 = v2 & block_mask; + T* pv1 = m_coord_blocks[b1] + (o1 << 1); + T* pv2 = m_coord_blocks[b2] + (o2 << 1); + T val; + val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val; + val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val; + int8u cmd = m_cmd_blocks[b1][o1]; + m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2]; + m_cmd_blocks[b2][o2] = cmd; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::last_command() const + { + if(m_total_vertices) return command(m_total_vertices - 1); + return path_cmd_stop; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::last_vertex(double* x, double* y) const + { + if(m_total_vertices) return vertex(m_total_vertices - 1, x, y); + return path_cmd_stop; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::prev_vertex(double* x, double* y) const + { + if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y); + return path_cmd_stop; + } + + //------------------------------------------------------------------------ + template + inline double vertex_block_storage::last_x() const + { + if(m_total_vertices) + { + unsigned idx = m_total_vertices - 1; + return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1]; + } + return 0.0; + } + + //------------------------------------------------------------------------ + template + inline double vertex_block_storage::last_y() const + { + if(m_total_vertices) + { + unsigned idx = m_total_vertices - 1; + return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1]; + } + return 0.0; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::total_vertices() const + { + return m_total_vertices; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::vertex(unsigned idx, + double* x, double* y) const + { + unsigned nb = idx >> block_shift; + const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); + *x = pv[0]; + *y = pv[1]; + return m_cmd_blocks[nb][idx & block_mask]; + } + + //------------------------------------------------------------------------ + template + inline unsigned vertex_block_storage::command(unsigned idx) const + { + return m_cmd_blocks[idx >> block_shift][idx & block_mask]; + } + + //------------------------------------------------------------------------ + template + void vertex_block_storage::allocate_block(unsigned nb) + { + if(nb >= m_max_blocks) + { + T** new_coords = + pod_allocator::allocate((m_max_blocks + block_pool) * 2); + + unsigned char** new_cmds = + (unsigned char**)(new_coords + m_max_blocks + block_pool); + + if(m_coord_blocks) + { + memcpy(new_coords, + m_coord_blocks, + m_max_blocks * sizeof(T*)); + + memcpy(new_cmds, + m_cmd_blocks, + m_max_blocks * sizeof(unsigned char*)); + + pod_allocator::deallocate(m_coord_blocks, m_max_blocks * 2); + } + m_coord_blocks = new_coords; + m_cmd_blocks = new_cmds; + m_max_blocks += block_pool; + } + m_coord_blocks[nb] = + pod_allocator::allocate(block_size * 2 + + block_size / (sizeof(T) / sizeof(unsigned char))); + + m_cmd_blocks[nb] = + (unsigned char*)(m_coord_blocks[nb] + block_size * 2); + + m_total_blocks++; + } + + //------------------------------------------------------------------------ + template + int8u* vertex_block_storage::storage_ptrs(T** xy_ptr) + { + unsigned nb = m_total_vertices >> block_shift; + if(nb >= m_total_blocks) + { + allocate_block(nb); + } + *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); + return m_cmd_blocks[nb] + (m_total_vertices & block_mask); + } + + + + + //-----------------------------------------------------poly_plain_adaptor + template class poly_plain_adaptor + { + public: + typedef T value_type; + + poly_plain_adaptor() : + m_data(0), + m_ptr(0), + m_end(0), + m_closed(false), + m_stop(false) + {} + + poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : + m_data(data), + m_ptr(data), + m_end(data + num_points * 2), + m_closed(closed), + m_stop(false) + {} + + void init(const T* data, unsigned num_points, bool closed) + { + m_data = data; + m_ptr = data; + m_end = data + num_points * 2; + m_closed = closed; + m_stop = false; + } + + void rewind(unsigned) + { + m_ptr = m_data; + m_stop = false; + } + + unsigned vertex(double* x, double* y) + { + if(m_ptr < m_end) + { + bool first = m_ptr == m_data; + *x = *m_ptr++; + *y = *m_ptr++; + return first ? path_cmd_move_to : path_cmd_line_to; + } + *x = *y = 0.0; + if(m_closed && !m_stop) + { + m_stop = true; + return path_cmd_end_poly | path_flags_close; + } + return path_cmd_stop; + } + + private: + const T* m_data; + const T* m_ptr; + const T* m_end; + bool m_closed; + bool m_stop; + }; + + + + + + //-------------------------------------------------poly_container_adaptor + template class poly_container_adaptor + { + public: + typedef typename Container::value_type vertex_type; + + poly_container_adaptor() : + m_container(0), + m_index(0), + m_closed(false), + m_stop(false) + {} + + poly_container_adaptor(const Container& data, bool closed) : + m_container(&data), + m_index(0), + m_closed(closed), + m_stop(false) + {} + + void init(const Container& data, bool closed) + { + m_container = &data; + m_index = 0; + m_closed = closed; + m_stop = false; + } + + void rewind(unsigned) + { + m_index = 0; + m_stop = false; + } + + unsigned vertex(double* x, double* y) + { + if(m_index < m_container->size()) + { + bool first = m_index == 0; + const vertex_type& v = (*m_container)[m_index++]; + *x = v.x; + *y = v.y; + return first ? path_cmd_move_to : path_cmd_line_to; + } + *x = *y = 0.0; + if(m_closed && !m_stop) + { + m_stop = true; + return path_cmd_end_poly | path_flags_close; + } + return path_cmd_stop; + } + + private: + const Container* m_container; + unsigned m_index; + bool m_closed; + bool m_stop; + }; + + + + //-----------------------------------------poly_container_reverse_adaptor + template class poly_container_reverse_adaptor + { + public: + typedef typename Container::value_type vertex_type; + + poly_container_reverse_adaptor() : + m_container(0), + m_index(-1), + m_closed(false), + m_stop(false) + {} + + poly_container_reverse_adaptor(const Container& data, bool closed) : + m_container(&data), + m_index(-1), + m_closed(closed), + m_stop(false) + {} + + void init(const Container& data, bool closed) + { + m_container = &data; + m_index = m_container->size() - 1; + m_closed = closed; + m_stop = false; + } + + void rewind(unsigned) + { + m_index = m_container->size() - 1; + m_stop = false; + } + + unsigned vertex(double* x, double* y) + { + if(m_index >= 0) + { + bool first = m_index == int(m_container->size() - 1); + const vertex_type& v = (*m_container)[m_index--]; + *x = v.x; + *y = v.y; + return first ? path_cmd_move_to : path_cmd_line_to; + } + *x = *y = 0.0; + if(m_closed && !m_stop) + { + m_stop = true; + return path_cmd_end_poly | path_flags_close; + } + return path_cmd_stop; + } + + private: + const Container* m_container; + int m_index; + bool m_closed; + bool m_stop; + }; + + + + + + //--------------------------------------------------------line_adaptor + class line_adaptor + { + public: + typedef double value_type; + + line_adaptor() : m_line(m_coord, 2, false) {} + line_adaptor(double x1, double y1, double x2, double y2) : + m_line(m_coord, 2, false) + { + m_coord[0] = x1; + m_coord[1] = y1; + m_coord[2] = x2; + m_coord[3] = y2; + } + + void init(double x1, double y1, double x2, double y2) + { + m_coord[0] = x1; + m_coord[1] = y1; + m_coord[2] = x2; + m_coord[3] = y2; + m_line.rewind(0); + } + + void rewind(unsigned) + { + m_line.rewind(0); + } + + unsigned vertex(double* x, double* y) + { + return m_line.vertex(x, y); + } + + private: + double m_coord[4]; + poly_plain_adaptor m_line; + }; + + + + + + + + + + + + + + //---------------------------------------------------------------path_base + // A container to store vertices with their flags. + // A path consists of a number of contours separated with "move_to" + // commands. The path storage can keep and maintain more than one + // path. + // To navigate to the beginning of a particular path, use rewind(path_id); + // Where path_id is what start_new_path() returns. So, when you call + // start_new_path() you need to store its return value somewhere else + // to navigate to the path afterwards. + // + // See also: vertex_source concept + //------------------------------------------------------------------------ + template class path_base + { + public: + typedef VertexContainer container_type; + typedef path_base self_type; + + //-------------------------------------------------------------------- + path_base() : m_vertices(), m_iterator(0) {} + void remove_all() { m_vertices.remove_all(); m_iterator = 0; } + void free_all() { m_vertices.free_all(); m_iterator = 0; } + + // Make path functions + //-------------------------------------------------------------------- + unsigned start_new_path(); + + void move_to(double x, double y); + void move_rel(double dx, double dy); + + void line_to(double x, double y); + void line_rel(double dx, double dy); + + void hline_to(double x); + void hline_rel(double dx); + + void vline_to(double y); + void vline_rel(double dy); + + void arc_to(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double x, double y); + + void arc_rel(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double dx, double dy); + + void curve3(double x_ctrl, double y_ctrl, + double x_to, double y_to); + + void curve3_rel(double dx_ctrl, double dy_ctrl, + double dx_to, double dy_to); + + void curve3(double x_to, double y_to); + + void curve3_rel(double dx_to, double dy_to); + + void curve4(double x_ctrl1, double y_ctrl1, + double x_ctrl2, double y_ctrl2, + double x_to, double y_to); + + void curve4_rel(double dx_ctrl1, double dy_ctrl1, + double dx_ctrl2, double dy_ctrl2, + double dx_to, double dy_to); + + void curve4(double x_ctrl2, double y_ctrl2, + double x_to, double y_to); + + void curve4_rel(double x_ctrl2, double y_ctrl2, + double x_to, double y_to); + + + void end_poly(unsigned flags = path_flags_close); + void close_polygon(unsigned flags = path_flags_none); + + // Accessors + //-------------------------------------------------------------------- + const container_type& vertices() const { return m_vertices; } + container_type& vertices() { return m_vertices; } + + unsigned total_vertices() const; + + void rel_to_abs(double* x, double* y) const; + + unsigned last_vertex(double* x, double* y) const; + unsigned prev_vertex(double* x, double* y) const; + + double last_x() const; + double last_y() const; + + unsigned vertex(unsigned idx, double* x, double* y) const; + unsigned command(unsigned idx) const; + + void modify_vertex(unsigned idx, double x, double y); + void modify_vertex(unsigned idx, double x, double y, unsigned cmd); + void modify_command(unsigned idx, unsigned cmd); + + // VertexSource interface + //-------------------------------------------------------------------- + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + // Arrange the orientation of a polygon, all polygons in a path, + // or in all paths. After calling arrange_orientations() or + // arrange_orientations_all_paths(), all the polygons will have + // the same orientation, i.e. path_flags_cw or path_flags_ccw + //-------------------------------------------------------------------- + unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); + unsigned arrange_orientations(unsigned path_id, path_flags_e orientation); + void arrange_orientations_all_paths(path_flags_e orientation); + void invert_polygon(unsigned start); + + // Flip all vertices horizontally or vertically, + // between x1 and x2, or between y1 and y2 respectively + //-------------------------------------------------------------------- + void flip_x(double x1, double x2); + void flip_y(double y1, double y2); + + // Concatenate path. The path is added as is. + //-------------------------------------------------------------------- + template + void concat_path(VertexSource& vs, unsigned path_id = 0) + { + double x, y; + unsigned cmd; + vs.rewind(path_id); + while(!is_stop(cmd = vs.vertex(&x, &y))) + { + m_vertices.add_vertex(x, y, cmd); + } + } + + //-------------------------------------------------------------------- + // Join path. The path is joined with the existing one, that is, + // it behaves as if the pen of a plotter was always down (drawing) + template + void join_path(VertexSource& vs, unsigned path_id = 0) + { + double x, y; + unsigned cmd; + vs.rewind(path_id); + cmd = vs.vertex(&x, &y); + if(!is_stop(cmd)) + { + if(is_vertex(cmd)) + { + double x0, y0; + unsigned cmd0 = last_vertex(&x0, &y0); + if(is_vertex(cmd0)) + { + if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) + { + if(is_move_to(cmd)) cmd = path_cmd_line_to; + m_vertices.add_vertex(x, y, cmd); + } + } + else + { + if(is_stop(cmd0)) + { + cmd = path_cmd_move_to; + } + else + { + if(is_move_to(cmd)) cmd = path_cmd_line_to; + } + m_vertices.add_vertex(x, y, cmd); + } + } + while(!is_stop(cmd = vs.vertex(&x, &y))) + { + m_vertices.add_vertex(x, y, is_move_to(cmd) ? + unsigned(path_cmd_line_to) : + cmd); + } + } + } + + // Concatenate polygon/polyline. + //-------------------------------------------------------------------- + template void concat_poly(const T* data, + unsigned num_points, + bool closed) + { + poly_plain_adaptor poly(data, num_points, closed); + concat_path(poly); + } + + // Join polygon/polyline continuously. + //-------------------------------------------------------------------- + template void join_poly(const T* data, + unsigned num_points, + bool closed) + { + poly_plain_adaptor poly(data, num_points, closed); + join_path(poly); + } + + //-------------------------------------------------------------------- + void translate(double dx, double dy, unsigned path_id=0); + void translate_all_paths(double dx, double dy); + + //-------------------------------------------------------------------- + template + void transform(const Trans& trans, unsigned path_id=0) + { + unsigned num_ver = m_vertices.total_vertices(); + for(; path_id < num_ver; path_id++) + { + double x, y; + unsigned cmd = m_vertices.vertex(path_id, &x, &y); + if(is_stop(cmd)) break; + if(is_vertex(cmd)) + { + trans.transform(&x, &y); + m_vertices.modify_vertex(path_id, x, y); + } + } + } + + //-------------------------------------------------------------------- + template + void transform_all_paths(const Trans& trans) + { + unsigned idx; + unsigned num_ver = m_vertices.total_vertices(); + for(idx = 0; idx < num_ver; idx++) + { + double x, y; + if(is_vertex(m_vertices.vertex(idx, &x, &y))) + { + trans.transform(&x, &y); + m_vertices.modify_vertex(idx, x, y); + } + } + } + + private: + unsigned perceive_polygon_orientation(unsigned start, unsigned end); + void invert_polygon(unsigned start, unsigned end); + + VertexContainer m_vertices; + unsigned m_iterator; + }; + + //------------------------------------------------------------------------ + template + unsigned path_base::start_new_path() + { + if(!is_stop(m_vertices.last_command())) + { + m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); + } + return m_vertices.total_vertices(); + } + + + //------------------------------------------------------------------------ + template + inline void path_base::rel_to_abs(double* x, double* y) const + { + if(m_vertices.total_vertices()) + { + double x2; + double y2; + if(is_vertex(m_vertices.last_vertex(&x2, &y2))) + { + *x += x2; + *y += y2; + } + } + } + + //------------------------------------------------------------------------ + template + inline void path_base::move_to(double x, double y) + { + m_vertices.add_vertex(x, y, path_cmd_move_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::move_rel(double dx, double dy) + { + rel_to_abs(&dx, &dy); + m_vertices.add_vertex(dx, dy, path_cmd_move_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::line_to(double x, double y) + { + m_vertices.add_vertex(x, y, path_cmd_line_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::line_rel(double dx, double dy) + { + rel_to_abs(&dx, &dy); + m_vertices.add_vertex(dx, dy, path_cmd_line_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::hline_to(double x) + { + m_vertices.add_vertex(x, last_y(), path_cmd_line_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::hline_rel(double dx) + { + double dy = 0; + rel_to_abs(&dx, &dy); + m_vertices.add_vertex(dx, dy, path_cmd_line_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::vline_to(double y) + { + m_vertices.add_vertex(last_x(), y, path_cmd_line_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::vline_rel(double dy) + { + double dx = 0; + rel_to_abs(&dx, &dy); + m_vertices.add_vertex(dx, dy, path_cmd_line_to); + } + + //------------------------------------------------------------------------ +/* template + void path_base::arc_to(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double x, double y) + { + if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) + { + const double epsilon = 1e-30; + double x0 = 0.0; + double y0 = 0.0; + m_vertices.last_vertex(&x0, &y0); + + rx = fabs(rx); + ry = fabs(ry); + + // Ensure radii are valid + //------------------------- + if(rx < epsilon || ry < epsilon) + { + line_to(x, y); + return; + } + + if(calc_distance(x0, y0, x, y) < epsilon) + { + // If the endpoints (x, y) and (x0, y0) are identical, then this + // is equivalent to omitting the elliptical arc segment entirely. + return; + } + bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); + if(a.radii_ok()) + { + join_path(a); + } + else + { + line_to(x, y); + } + } + else + { + move_to(x, y); + } + } +*/ + //------------------------------------------------------------------------ + template + void path_base::arc_rel(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double dx, double dy) + { + rel_to_abs(&dx, &dy); + arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); + } + + //------------------------------------------------------------------------ + template + void path_base::curve3(double x_ctrl, double y_ctrl, + double x_to, double y_to) + { + m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); + m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); + } + + //------------------------------------------------------------------------ + template + void path_base::curve3_rel(double dx_ctrl, double dy_ctrl, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl, &dy_ctrl); + rel_to_abs(&dx_to, &dy_to); + m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); + m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); + } + + //------------------------------------------------------------------------ + template + void path_base::curve3(double x_to, double y_to) + { + double x0; + double y0; + if(is_vertex(m_vertices.last_vertex(&x0, &y0))) + { + double x_ctrl; + double y_ctrl; + unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); + if(is_curve(cmd)) + { + x_ctrl = x0 + x0 - x_ctrl; + y_ctrl = y0 + y0 - y_ctrl; + } + else + { + x_ctrl = x0; + y_ctrl = y0; + } + curve3(x_ctrl, y_ctrl, x_to, y_to); + } + } + + //------------------------------------------------------------------------ + template + void path_base::curve3_rel(double dx_to, double dy_to) + { + rel_to_abs(&dx_to, &dy_to); + curve3(dx_to, dy_to); + } + + //------------------------------------------------------------------------ + template + void path_base::curve4(double x_ctrl1, double y_ctrl1, + double x_ctrl2, double y_ctrl2, + double x_to, double y_to) + { + m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); + m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); + m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); + } + + //------------------------------------------------------------------------ + template + void path_base::curve4_rel(double dx_ctrl1, double dy_ctrl1, + double dx_ctrl2, double dy_ctrl2, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl1, &dy_ctrl1); + rel_to_abs(&dx_ctrl2, &dy_ctrl2); + rel_to_abs(&dx_to, &dy_to); + m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); + m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); + m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); + } + + //------------------------------------------------------------------------ + template + void path_base::curve4(double x_ctrl2, double y_ctrl2, + double x_to, double y_to) + { + double x0; + double y0; + if(is_vertex(last_vertex(&x0, &y0))) + { + double x_ctrl1; + double y_ctrl1; + unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); + if(is_curve(cmd)) + { + x_ctrl1 = x0 + x0 - x_ctrl1; + y_ctrl1 = y0 + y0 - y_ctrl1; + } + else + { + x_ctrl1 = x0; + y_ctrl1 = y0; + } + curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); + } + } + + //------------------------------------------------------------------------ + template + void path_base::curve4_rel(double dx_ctrl2, double dy_ctrl2, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl2, &dy_ctrl2); + rel_to_abs(&dx_to, &dy_to); + curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); + } + + //------------------------------------------------------------------------ + template + inline void path_base::end_poly(unsigned flags) + { + if(is_vertex(m_vertices.last_command())) + { + m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); + } + } + + //------------------------------------------------------------------------ + template + inline void path_base::close_polygon(unsigned flags) + { + end_poly(path_flags_close | flags); + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::total_vertices() const + { + return m_vertices.total_vertices(); + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::last_vertex(double* x, double* y) const + { + return m_vertices.last_vertex(x, y); + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::prev_vertex(double* x, double* y) const + { + return m_vertices.prev_vertex(x, y); + } + + //------------------------------------------------------------------------ + template + inline double path_base::last_x() const + { + return m_vertices.last_x(); + } + + //------------------------------------------------------------------------ + template + inline double path_base::last_y() const + { + return m_vertices.last_y(); + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::vertex(unsigned idx, double* x, double* y) const + { + return m_vertices.vertex(idx, x, y); + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::command(unsigned idx) const + { + return m_vertices.command(idx); + } + + //------------------------------------------------------------------------ + template + void path_base::modify_vertex(unsigned idx, double x, double y) + { + m_vertices.modify_vertex(idx, x, y); + } + + //------------------------------------------------------------------------ + template + void path_base::modify_vertex(unsigned idx, double x, double y, unsigned cmd) + { + m_vertices.modify_vertex(idx, x, y, cmd); + } + + //------------------------------------------------------------------------ + template + void path_base::modify_command(unsigned idx, unsigned cmd) + { + m_vertices.modify_command(idx, cmd); + } + + //------------------------------------------------------------------------ + template + inline void path_base::rewind(unsigned path_id) + { + m_iterator = path_id; + } + + //------------------------------------------------------------------------ + template + inline unsigned path_base::vertex(double* x, double* y) + { + if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; + return m_vertices.vertex(m_iterator++, x, y); + } + + //------------------------------------------------------------------------ + template + unsigned path_base::perceive_polygon_orientation(unsigned start, + unsigned end) + { + // Calculate signed area (double area to be exact) + //--------------------- + unsigned np = end - start; + double area = 0.0; + unsigned i; + for(i = 0; i < np; i++) + { + double x1, y1, x2, y2; + m_vertices.vertex(start + i, &x1, &y1); + m_vertices.vertex(start + (i + 1) % np, &x2, &y2); + area += x1 * y2 - y1 * x2; + } + return (area < 0.0) ? path_flags_cw : path_flags_ccw; + } + + //------------------------------------------------------------------------ + template + void path_base::invert_polygon(unsigned start, unsigned end) + { + unsigned i; + unsigned tmp_cmd = m_vertices.command(start); + + --end; // Make "end" inclusive + + // Shift all commands to one position + for(i = start; i < end; i++) + { + m_vertices.modify_command(i, m_vertices.command(i + 1)); + } + + // Assign starting command to the ending command + m_vertices.modify_command(end, tmp_cmd); + + // Reverse the polygon + while(end > start) + { + m_vertices.swap_vertices(start++, end--); + } + } + + //------------------------------------------------------------------------ + template + void path_base::invert_polygon(unsigned start) + { + // Skip all non-vertices at the beginning + while(start < m_vertices.total_vertices() && + !is_vertex(m_vertices.command(start))) ++start; + + // Skip all insignificant move_to + while(start+1 < m_vertices.total_vertices() && + is_move_to(m_vertices.command(start)) && + is_move_to(m_vertices.command(start+1))) ++start; + + // Find the last vertex + unsigned end = start + 1; + while(end < m_vertices.total_vertices() && + !is_next_poly(m_vertices.command(end))) ++end; + + invert_polygon(start, end); + } + + //------------------------------------------------------------------------ + template + unsigned path_base::arrange_polygon_orientation(unsigned start, + path_flags_e orientation) + { + if(orientation == path_flags_none) return start; + + // Skip all non-vertices at the beginning + while(start < m_vertices.total_vertices() && + !is_vertex(m_vertices.command(start))) ++start; + + // Skip all insignificant move_to + while(start+1 < m_vertices.total_vertices() && + is_move_to(m_vertices.command(start)) && + is_move_to(m_vertices.command(start+1))) ++start; + + // Find the last vertex + unsigned end = start + 1; + while(end < m_vertices.total_vertices() && + !is_next_poly(m_vertices.command(end))) ++end; + + if(end - start > 2) + { + if(perceive_polygon_orientation(start, end) != unsigned(orientation)) + { + // Invert polygon, set orientation flag, and skip all end_poly + invert_polygon(start, end); + unsigned cmd; + while(end < m_vertices.total_vertices() && + is_end_poly(cmd = m_vertices.command(end))) + { + m_vertices.modify_command(end++, set_orientation(cmd, orientation)); + } + } + } + return end; + } + + //------------------------------------------------------------------------ + template + unsigned path_base::arrange_orientations(unsigned start, + path_flags_e orientation) + { + if(orientation != path_flags_none) + { + while(start < m_vertices.total_vertices()) + { + start = arrange_polygon_orientation(start, orientation); + if(is_stop(m_vertices.command(start))) + { + ++start; + break; + } + } + } + return start; + } + + //------------------------------------------------------------------------ + template + void path_base::arrange_orientations_all_paths(path_flags_e orientation) + { + if(orientation != path_flags_none) + { + unsigned start = 0; + while(start < m_vertices.total_vertices()) + { + start = arrange_orientations(start, orientation); + } + } + } + + //------------------------------------------------------------------------ + template + void path_base::flip_x(double x1, double x2) + { + unsigned i; + double x, y; + for(i = 0; i < m_vertices.total_vertices(); i++) + { + unsigned cmd = m_vertices.vertex(i, &x, &y); + if(is_vertex(cmd)) + { + m_vertices.modify_vertex(i, x2 - x + x1, y); + } + } + } + + //------------------------------------------------------------------------ + template + void path_base::flip_y(double y1, double y2) + { + unsigned i; + double x, y; + for(i = 0; i < m_vertices.total_vertices(); i++) + { + unsigned cmd = m_vertices.vertex(i, &x, &y); + if(is_vertex(cmd)) + { + m_vertices.modify_vertex(i, x, y2 - y + y1); + } + } + } + + //------------------------------------------------------------------------ + template + void path_base::translate(double dx, double dy, unsigned path_id) + { + unsigned num_ver = m_vertices.total_vertices(); + for(; path_id < num_ver; path_id++) + { + double x, y; + unsigned cmd = m_vertices.vertex(path_id, &x, &y); + if(is_stop(cmd)) break; + if(is_vertex(cmd)) + { + x += dx; + y += dy; + m_vertices.modify_vertex(path_id, x, y); + } + } + } + + //------------------------------------------------------------------------ + template + void path_base::translate_all_paths(double dx, double dy) + { + unsigned idx; + unsigned num_ver = m_vertices.total_vertices(); + for(idx = 0; idx < num_ver; idx++) + { + double x, y; + if(is_vertex(m_vertices.vertex(idx, &x, &y))) + { + x += dx; + y += dy; + m_vertices.modify_vertex(idx, x, y); + } + } + } + + //-----------------------------------------------------vertex_stl_storage + template class vertex_stl_storage + { + public: + typedef typename Container::value_type vertex_type; + typedef typename vertex_type::value_type value_type; + + void remove_all() { m_vertices.clear(); } + void free_all() { m_vertices.clear(); } + + void add_vertex(double x, double y, unsigned cmd) + { + m_vertices.push_back(vertex_type(value_type(x), + value_type(y), + int8u(cmd))); + } + + void modify_vertex(unsigned idx, double x, double y) + { + vertex_type& v = m_vertices[idx]; + v.x = value_type(x); + v.y = value_type(y); + } + + void modify_vertex(unsigned idx, double x, double y, unsigned cmd) + { + vertex_type& v = m_vertices[idx]; + v.x = value_type(x); + v.y = value_type(y); + v.cmd = int8u(cmd); + } + + void modify_command(unsigned idx, unsigned cmd) + { + m_vertices[idx].cmd = int8u(cmd); + } + + void swap_vertices(unsigned v1, unsigned v2) + { + vertex_type t = m_vertices[v1]; + m_vertices[v1] = m_vertices[v2]; + m_vertices[v2] = t; + } + + unsigned last_command() const + { + return m_vertices.size() ? + m_vertices[m_vertices.size() - 1].cmd : + path_cmd_stop; + } + + unsigned last_vertex(double* x, double* y) const + { + if(m_vertices.size() == 0) + { + *x = *y = 0.0; + return path_cmd_stop; + } + return vertex(m_vertices.size() - 1, x, y); + } + + unsigned prev_vertex(double* x, double* y) const + { + if(m_vertices.size() < 2) + { + *x = *y = 0.0; + return path_cmd_stop; + } + return vertex(m_vertices.size() - 2, x, y); + } + + double last_x() const + { + return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; + } + + double last_y() const + { + return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; + } + + unsigned total_vertices() const + { + return m_vertices.size(); + } + + unsigned vertex(unsigned idx, double* x, double* y) const + { + const vertex_type& v = m_vertices[idx]; + *x = v.x; + *y = v.y; + return v.cmd; + } + + unsigned command(unsigned idx) const + { + return m_vertices[idx].cmd; + } + + private: + Container m_vertices; + }; + + //-----------------------------------------------------------path_storage + typedef path_base > path_storage; + + // Example of declarations path_storage with pod_bvector as a container + //----------------------------------------------------------------------- + //typedef path_base > > path_storage; + +} + + + +// Example of declarations path_storage with std::vector as a container +//--------------------------------------------------------------------------- +//#include +//namespace agg +//{ +// typedef path_base > > stl_path_storage; +//} + + + + +#endif