Gnash  0.8.11dev
Geometry.h
Go to the documentation of this file.
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
18 //
19 
20 #ifndef GNASH_GEOMETRY_H
21 #define GNASH_GEOMETRY_H
22 
23 #include "dsodefs.h"
24 #include "SWFMatrix.h"
25 #include "SWFRect.h"
26 #include "Point2d.h"
27 
28 #include <vector> // for path composition
29 #include <cmath> // sqrt
30 
31 
32 // Forward declarations
33 namespace gnash {
34  class LineStyle;
35 }
36 
37 namespace gnash {
38 
44 class Edge
45 {
46 public:
47 
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
51 
52  Edge()
53  :
54  cp(0, 0),
55  ap(0, 0)
56  {}
57 
58  Edge(boost::int32_t cx, boost::int32_t cy, boost::int32_t ax,
59  boost::int32_t ay)
60  :
61  cp(cx, cy),
62  ap(ax, ay)
63  {}
64 
65  Edge(const Edge& from)
66  :
67  cp(from.cp),
68  ap(from.ap)
69  {}
70 
71  Edge(const point& ncp, const point& nap)
72  :
73  cp(ncp),
74  ap(nap)
75  {}
76 
77  bool straight() const
78  {
79  return cp == ap;
80  }
81 
83  void transform(const SWFMatrix& mat)
84  {
85  mat.transform(ap);
86  mat.transform(cp);
87  }
88 
90  static double
91  squareDistancePtSeg(const point& p, const point& A, const point& B)
92  {
93  boost::int32_t dx = B.x - A.x;
94  boost::int32_t dy = B.y - A.y;
95 
96  if ( dx == 0 && dy == 0 )
97  {
98  return p.squareDistance(A);
99  }
100 
101  boost::int32_t pdx = p.x - A.x;
102  boost::int32_t pdy = p.y - A.y;
103 
104  double u = (static_cast<double>(pdx) * dx + static_cast<double>(pdy) * dy ) /
105  (static_cast<double>(dx)*dx + static_cast<double>(dy)*dy );
106 
107  if (u <= 0)
108  {
109  return p.squareDistance(A);
110  }
111 
112  if (u >= 1)
113  {
114  return p.squareDistance(B);
115  }
116 
117  point px(A, B, u); // FIXME: this interpolation introduce a precision loss (point is int-based)
118  return p.squareDistance(px);
119  }
120 
122  static double
123  distancePtSeg(const point& pt, const point& A, const point& B)
124  {
125  const double square = squareDistancePtSeg(pt, A, B);
126  return std::sqrt(square);
127  }
128 
130  //
136  static point
137  pointOnCurve(const point& A, const point& C, const point& B, float t)
138  {
139  point Q1(A, C, t);
140  point Q2(C, B, t);
141  point R(Q1, Q2, t);
142 
143  return R;
144  }
145 
148  //
155  static boost::int64_t squareDistancePtCurve(const point& A,
156  const point& C,
157  const point& B,
158  const point& p, float t)
159  {
160  return p.squareDistance( pointOnCurve(A, C, B, t) );
161  }
162 };
163 
164 
167 {
168 public:
170  unsigned m_fill0;
171 
173  unsigned m_fill1;
174 
176  unsigned m_line;
177 
180 
182  std::vector<Edge> m_edges;
183 
188 
190  //
195  {
196  reset(0, 0, 0, 0, 0);
197  }
198 
199  Path(const Path& from)
200  :
201  m_fill0(from.m_fill0),
202  m_fill1(from.m_fill1),
203  m_line(from.m_line),
204  ap(from.ap),
205  m_edges(from.m_edges)
206  {
207  }
208 
210  //
231  Path(boost::int32_t ax, boost::int32_t ay,
232  unsigned fill0, unsigned fill1, unsigned line)
233  {
234  reset(ax, ay, fill0, fill1, line);
235  }
236 
238  //
250  //
254  void reset(boost::int32_t ax, boost::int32_t ay,
255  unsigned fill0, unsigned fill1, unsigned line)
256  // Reset all our members to the given values, and clear our edge list.
257  {
258  ap.x = ax;
259  ap.y = ay;
260  m_fill0 = fill0;
261  m_fill1 = fill1;
262  m_line = line;
263 
264  m_edges.resize(0);
265  assert(empty());
266  }
267 
269  //
281  void
282  expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const
283  {
284  const Path& p = *this;
285  size_t nedges = m_edges.size();
286 
287  if ( ! nedges ) return; // this path adds nothing
288 
289  if (thickness)
290  {
291  // NOTE: Half of thickness would be enough (and correct) for
292  // radius, but that would not match how Flash calculates the
293  // bounds using the drawing API.
294  unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
295 
296  r.expand_to_circle(ap.x, ap.y, radius);
297  for (unsigned int j = 0; j<nedges; j++)
298  {
299  r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
300  r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
301  }
302  }
303  else
304  {
305  r.expand_to_point(ap.x, ap.y);
306  for (unsigned int j = 0; j<nedges; j++)
307  {
308  r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
309  r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
310  }
311  }
312  }
313 
318 
320  //
330  void
331  drawLineTo(boost::int32_t dx, boost::int32_t dy)
332  {
333  m_edges.push_back(Edge(dx, dy, dx, dy));
334  }
335 
337  //
353  void
354  drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady)
355  {
356  m_edges.push_back(Edge(cdx, cdy, adx, ady));
357  }
358 
360  void clear()
361  {
362  m_edges.resize(0);
363  m_fill0 = m_fill1 = m_line = 0;
364  }
365 
367 
368 
370  bool isClosed() const
371  {
372  if (m_edges.empty()) return true;
373  return m_edges.back().ap == ap;
374  }
375 
377  void close()
378  {
379  if ( m_edges.empty() ) return;
380 
381  // Close it with a straight edge if needed
382  const Edge& lastedge = m_edges.back();
383  if ( lastedge.ap != ap )
384  {
385  Edge newedge(ap, ap);
386  m_edges.push_back(newedge);
387  }
388  }
389 
393  //
396  bool
397  withinSquareDistance(const point& p, double dist) const
398  {
399  size_t nedges = m_edges.size();
400 
401  if ( ! nedges ) return false;
402 
403  point px(ap);
404  for (size_t i=0; i<nedges; ++i)
405  {
406  const Edge& e = m_edges[i];
407  point np(e.ap);
408 
409  if (e.straight())
410  {
411  double d = Edge::squareDistancePtSeg(p, px, np);
412  if ( d <= dist ) return true;
413  }
414  else
415  {
416 
417  const point& A = px;
418  const point& C = e.cp;
419  const point& B = e.ap;
420 
421  // Approximate the curve to segCount segments
422  // and compute distance of query point from each
423  // segment.
424  //
425  // TODO: find an apprpriate value for segCount based
426  // on rendering scale ?
427  //
428  int segCount = 10;
429  point p0(A.x, A.y);
430  for (int i=1; i<=segCount; ++i)
431  {
432  float t1 = static_cast<float>(i) / segCount;
433  point p1 = Edge::pointOnCurve(A, C, B, t1);
434 
435  // distance from point and segment being an approximation
436  // of the curve
437  double d = Edge::squareDistancePtSeg(p, p0, p1);
438  if ( d <= dist ) return true;
439 
440  p0.setTo(p1.x, p1.y);
441  }
442  }
443  px = np;
444  }
445 
446  return false;
447  }
448 
450  void transform(const SWFMatrix& mat)
451  {
452  mat.transform(ap);
453  std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end();
454  for(; it != ie; ++it)
455  {
456  (*it).transform(mat);
457  }
458  }
459 
461  bool empty() const
462  {
463  return m_edges.empty();
464  }
465 
467  //
475  void setLeftFill(unsigned f)
476  {
477  m_fill0 = f;
478  }
479 
480  unsigned getLeftFill() const
481  {
482  return m_fill0;
483  }
484 
486  //
494  void setRightFill(unsigned f)
495  {
496  m_fill1 = f;
497  }
498 
499  unsigned getRightFill() const
500  {
501  return m_fill1;
502  }
503 
505  //
513  void setLineStyle(unsigned i)
514  {
515  m_line = i;
516  }
517 
518  unsigned getLineStyle() const
519  {
520  return m_line;
521  }
522 
524  size_t size() const
525  {
526  return m_edges.size();
527  }
528 
530  Edge& operator[] (size_t n)
531  {
532  return m_edges[n];
533  }
534 
536  const Edge& operator[] (size_t n) const
537  {
538  return m_edges[n];
539  }
540 }; // end of class Path
541 
542 namespace geometry
543 {
544 
545 bool pointTest(const std::vector<Path>& paths,
546  const std::vector<LineStyle>& lineStyles, boost::int32_t x,
547  boost::int32_t y, const SWFMatrix& wm);
548 
549 } // namespace geometry
550 
551 
552 } // namespace gnash
553 
554 #endif // GNASH_GEOMETRY_H
555 
556 
557 // Local Variables:
558 // mode: C++
559 // c-basic-offset: 8
560 // tab-width: 8
561 // indent-tabs-mode: t
562 // End: