Update with current status
[gnash.git] / libcore / Geometry.h
blobf421ed5a9b8f83b892526357dec6046e7c03ea8c
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #ifndef GNASH_GEOMETRY_H
21 #define GNASH_GEOMETRY_H
23 #include "dsodefs.h"
24 #include "SWFMatrix.h"
25 #include "SWFRect.h"
26 #include "Point2d.h"
28 #include <vector> // for path composition
29 #include <cmath> // sqrt
32 // Forward declarations
33 namespace gnash {
34 class LineStyle;
37 namespace gnash {
39 /// \brief
40 /// Defines an edge with a control point and an anchor point.
41 ///
42 /// Could be a quadratic bezier curve, or a straight line(degenerated curve).
43 ///
44 class Edge
46 public:
48 // Quadratic bezier: point = p0 * t^2 + p1 * 2t(1-t) + p2 * (1-t)^2
49 point cp; // control point, TWIPS
50 point ap; // anchor point, TWIPS
52 constexpr Edge()
54 cp(0, 0),
55 ap(0, 0)
58 constexpr Edge(std::int32_t cx, std::int32_t cy, std::int32_t ax,
59 std::int32_t ay)
61 cp(cx, cy),
62 ap(ax, ay)
65 constexpr Edge(const Edge& from)
67 cp(from.cp),
68 ap(from.ap)
71 constexpr Edge(const point& ncp, const point& nap)
73 cp(ncp),
74 ap(nap)
77 bool straight() const
79 return cp == ap;
82 /// Transform the edge according to the given SWFMatrix.
83 void transform(const SWFMatrix& mat)
85 mat.transform(ap);
86 mat.transform(cp);
89 /// Return squared distance between point pt and segment A-B
90 static double
91 squareDistancePtSeg(const point& p, const point& A, const point& B)
93 std::int32_t dx = B.x - A.x;
94 std::int32_t dy = B.y - A.y;
96 if ( dx == 0 && dy == 0 )
98 return p.squareDistance(A);
101 std::int32_t pdx = p.x - A.x;
102 std::int32_t pdy = p.y - A.y;
104 double u = (static_cast<double>(pdx) * dx + static_cast<double>(pdy) * dy ) /
105 (static_cast<double>(dx)*dx + static_cast<double>(dy)*dy );
107 if (u <= 0)
109 return p.squareDistance(A);
112 if (u >= 1)
114 return p.squareDistance(B);
117 point px(A, B, u); // FIXME: this interpolation introduce a precision loss (point is int-based)
118 return p.squareDistance(px);
121 /// Return distance between point pt and segment A-B
122 static double
123 distancePtSeg(const point& pt, const point& A, const point& B)
125 const double square = squareDistancePtSeg(pt, A, B);
126 return std::sqrt(square);
129 /// Find point of the quadratic curve defined by points A,C,B
131 /// @param A The first point
132 /// @param C The second point (control point)
133 /// @param B The third point (anchor point)
134 /// @return The point.
135 /// @param t the step factor between 0 and 1
136 static point
137 pointOnCurve(const point& A, const point& C, const point& B, float t)
139 point Q1(A, C, t);
140 point Q2(C, B, t);
141 point R(Q1, Q2, t);
143 return R;
146 /// Return square distance between point pt and the point on curve found by
147 /// applying the T parameter to the quadratic bezier curve function
149 /// @param A The first point of the bezier curve
150 /// @param C The second point of the bezier curve (control point)
151 /// @param B The third point of the bezier curve (anchor point)
152 /// @param p The point we want to compute distance from
153 /// @param t the step factor between 0 and 1
155 static std::int64_t squareDistancePtCurve(const point& A,
156 const point& C,
157 const point& B,
158 const point& p, float t)
160 return p.squareDistance( pointOnCurve(A, C, B, t) );
165 /// A subset of a shape, a series of edges sharing a single set of styles.
166 class DSOEXPORT Path
168 public:
169 /// Left fill style index (1-based)
170 unsigned m_fill0;
172 /// Right fill style index (1-based)
173 unsigned m_fill1;
175 /// Line style index (1-based)
176 unsigned m_line;
178 /// Start point of the path
179 point ap;
181 /// Edges forming the path
182 std::vector<Edge> m_edges;
184 /// This flag is set when the path is the first one of a new "sub-shape".
185 /// All paths with a higher index in the list belong to the same
186 /// shape unless they have m_new_shape==true on their own.
187 /// Sub-shapes affect the order in which outlines and shapes are rendered.
189 /// Default constructor
191 Path()
193 reset(0, 0, 0, 0, 0);
196 Path(const Path& from)
198 m_fill0(from.m_fill0),
199 m_fill1(from.m_fill1),
200 m_line(from.m_line),
201 ap(from.ap),
202 m_edges(from.m_edges)
206 /// Initialize a path
208 /// @param ax
209 /// X coordinate of path origin in TWIPS
211 /// @param ay
212 /// Y coordinate in path origin in TWIPS
214 /// @param fill0
215 /// Fill style index for left fill (1-based).
216 /// Zero means NO style.
218 /// @param fill1
219 /// Fill style index for right fill (1-based)
220 /// Zero means NO style.
222 /// @param line
223 /// Line style index for right fill (1-based).
224 /// Zero means NO style.
225 Path(std::int32_t ax, std::int32_t ay,
226 unsigned fill0, unsigned fill1, unsigned line)
228 reset(ax, ay, fill0, fill1, line);
231 /// Re-initialize a path, maintaining the "new shape" flag untouched
233 /// @param ax
234 /// X coordinate of path origin in TWIPS
236 /// @param ay
237 /// Y coordinate in path origin in TWIPS
239 /// @param fill0
240 /// Fill style index for left fill
242 /// @param fill1
243 /// Fill style index for right fill
245 /// @param line
246 /// Line style index for right fill
248 void reset(std::int32_t ax, std::int32_t ay,
249 unsigned fill0, unsigned fill1, unsigned line)
250 // Reset all our members to the given values, and clear our edge list.
252 ap.x = ax;
253 ap.y = ay;
254 m_fill0 = fill0;
255 m_fill1 = fill1;
256 m_line = line;
258 m_edges.resize(0);
259 assert(empty());
262 /// Expand given SWFRect to include bounds of this path
264 /// @param r
265 /// The rectangle to expand with our own bounds
267 /// @param thickness
268 /// The thickess of our lines, half the thickness will
269 /// be added in all directions in swf8+, all of it will
270 /// in swf7-
272 /// @param swfVersion
273 /// SWF version to use.
275 void
276 expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const
278 const Path& p = *this;
279 size_t nedges = m_edges.size();
281 if ( ! nedges ) return; // this path adds nothing
283 if (thickness)
285 // NOTE: Half of thickness would be enough (and correct) for
286 // radius, but that would not match how Flash calculates the
287 // bounds using the drawing API.
288 unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
290 r.expand_to_circle(ap.x, ap.y, radius);
291 for (unsigned int j = 0; j<nedges; j++)
293 r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
294 r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
297 else
299 r.expand_to_point(ap.x, ap.y);
300 for (unsigned int j = 0; j<nedges; j++)
302 r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
303 r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
308 /// @{ Primitives for the Drawing API
310 /// Name of these functions track Ming interface
313 /// Draw a straight line.
315 /// Point coordinates are relative to path origin
316 /// and expressed in TWIPS.
318 /// @param x
319 /// X coordinate in TWIPS
321 /// @param y
322 /// Y coordinate in TWIPS
324 void
325 drawLineTo(std::int32_t dx, std::int32_t dy)
327 m_edges.emplace_back(dx, dy, dx, dy);
330 /// Draw a curve.
332 /// Offset values are relative to path origin and
333 /// expressed in TWIPS.
335 /// @param cx
336 /// Control point's X coordinate.
338 /// @param cy
339 /// Control point's Y coordinate.
341 /// @param ax
342 /// Anchor point's X ordinate.
344 /// @param ay
345 /// Anchor point's Y ordinate.
347 void
348 drawCurveTo(std::int32_t cdx, std::int32_t cdy, std::int32_t adx, std::int32_t ady)
350 m_edges.emplace_back(cdx, cdy, adx, ady);
353 /// Remove all edges and reset style infomation
354 void clear()
356 m_edges.resize(0);
357 m_fill0 = m_fill1 = m_line = 0;
360 /// @} Primitives for the Drawing API
363 /// Returns true if the last and the first point of the path match
364 bool isClosed() const
366 if (m_edges.empty()) return true;
367 return m_edges.back().ap == ap;
370 /// Close this path with a straight line, if not already closed
371 void close()
373 if ( m_edges.empty() ) return;
375 // Close it with a straight edge if needed
376 const Edge& lastedge = m_edges.back();
377 if ( lastedge.ap != ap )
379 m_edges.emplace_back(ap, ap);
383 /// \brief
384 /// Return true if the given point is within the given squared distance
385 /// from this path edges.
387 /// NOTE: if the path is empty, false is returned.
389 bool
390 withinSquareDistance(const point& p, double dist) const
392 size_t nedges = m_edges.size();
394 if ( ! nedges ) return false;
396 point px(ap);
397 for (size_t i=0; i<nedges; ++i)
399 const Edge& e = m_edges[i];
400 point np(e.ap);
402 if (e.straight())
404 double d = Edge::squareDistancePtSeg(p, px, np);
405 if ( d <= dist ) return true;
407 else
410 const point& A = px;
411 const point& C = e.cp;
412 const point& B = e.ap;
414 // Approximate the curve to segCount segments
415 // and compute distance of query point from each
416 // segment.
418 // TODO: find an apprpriate value for segCount based
419 // on rendering scale ?
421 int segCount = 10;
422 point p0(A.x, A.y);
423 for (int i=1; i<=segCount; ++i)
425 float t1 = static_cast<float>(i) / segCount;
426 point p1 = Edge::pointOnCurve(A, C, B, t1);
428 // distance from point and segment being an approximation
429 // of the curve
430 double d = Edge::squareDistancePtSeg(p, p0, p1);
431 if ( d <= dist ) return true;
433 p0.setTo(p1.x, p1.y);
436 px = np;
439 return false;
442 /// Transform all path coordinates according to the given SWFMatrix.
443 void transform(const SWFMatrix& mat)
445 mat.transform(ap);
446 std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end();
447 for(; it != ie; ++it)
449 (*it).transform(mat);
453 /// Return true if this path contains no edges
454 bool empty() const
456 return m_edges.empty();
459 /// Set the fill to use on the left side
461 /// @param f
462 /// The fill index (1-based).
463 /// When this path is added to a DefineShapeTag,
464 /// the index (decremented by 1) will reference an element
465 /// in the FillStyle vector defined for that shape.
466 /// If zero, no fill will be active.
468 void setLeftFill(unsigned f)
470 m_fill0 = f;
473 unsigned getLeftFill() const
475 return m_fill0;
478 /// Set the fill to use on the left side
480 /// @param f
481 /// The fill index (1-based).
482 /// When this path is added to a DefineShapeTag,
483 /// the index (decremented by 1) will reference an element
484 /// in the FillStyle vector defined for that shape.
485 /// If zero, no fill will be active.
487 void setRightFill(unsigned f)
489 m_fill1 = f;
492 unsigned getRightFill() const
494 return m_fill1;
497 /// Set the line style to use for this path
499 /// @param f
500 /// The LineStyle index (1-based).
501 /// When this path is added to a DefineShapeTag,
502 /// the index (decremented by 1) will reference an element
503 /// in the LineStyle vector defined for that shape.
504 /// If zero, no fill will be active.
506 void setLineStyle(unsigned i)
508 m_line = i;
511 unsigned getLineStyle() const
513 return m_line;
516 /// Return the number of edges in this path
517 size_t size() const
519 return m_edges.size();
522 /// Return a reference to the Nth edge
523 Edge& operator[] (size_t n)
525 return m_edges[n];
528 /// Return a const reference to the Nth edge
529 const Edge& operator[] (size_t n) const
531 return m_edges[n];
533 }; // end of class Path
535 namespace geometry
538 bool pointTest(const std::vector<Path>& paths,
539 const std::vector<LineStyle>& lineStyles, std::int32_t x,
540 std::int32_t y, const SWFMatrix& wm);
542 } // namespace geometry
545 } // namespace gnash
547 #endif // GNASH_GEOMETRY_H
550 // Local Variables:
551 // mode: C++
552 // c-basic-offset: 8
553 // tab-width: 8
554 // indent-tabs-mode: t
555 // End: