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 
189 
191  //
195  Path(bool newShape = false)
196  :
197  m_new_shape(newShape)
198  {
199  reset(0, 0, 0, 0, 0);
200  }
201 
202  Path(const Path& from)
203  :
204  m_fill0(from.m_fill0),
205  m_fill1(from.m_fill1),
206  m_line(from.m_line),
207  ap(from.ap),
208  m_edges(from.m_edges),
209  m_new_shape(from.m_new_shape)
210  {
211  }
212 
214  //
235  Path(boost::int32_t ax, boost::int32_t ay,
236  unsigned fill0, unsigned fill1, unsigned line,
237  bool newShape)
238  :
239  m_new_shape(newShape)
240  {
241  reset(ax, ay, fill0, fill1, line);
242  }
243 
245  //
257  //
261  void reset(boost::int32_t ax, boost::int32_t ay,
262  unsigned fill0, unsigned fill1, unsigned line)
263  // Reset all our members to the given values, and clear our edge list.
264  {
265  ap.x = ax;
266  ap.y = ay;
267  m_fill0 = fill0;
268  m_fill1 = fill1;
269  m_line = line;
270 
271  m_edges.resize(0);
272  assert(empty());
273  }
274 
276  //
288  void
289  expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const
290  {
291  const Path& p = *this;
292  size_t nedges = m_edges.size();
293 
294  if ( ! nedges ) return; // this path adds nothing
295 
296  if (thickness)
297  {
298  // NOTE: Half of thickness would be enough (and correct) for
299  // radius, but that would not match how Flash calculates the
300  // bounds using the drawing API.
301  unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
302 
303  r.expand_to_circle(ap.x, ap.y, radius);
304  for (unsigned int j = 0; j<nedges; j++)
305  {
306  r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
307  r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
308  }
309  }
310  else
311  {
312  r.expand_to_point(ap.x, ap.y);
313  for (unsigned int j = 0; j<nedges; j++)
314  {
315  r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
316  r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
317  }
318  }
319  }
320 
325 
327  //
337  void
338  drawLineTo(boost::int32_t dx, boost::int32_t dy)
339  {
340  m_edges.push_back(Edge(dx, dy, dx, dy));
341  }
342 
344  //
360  void
361  drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady)
362  {
363  m_edges.push_back(Edge(cdx, cdy, adx, ady));
364  }
365 
367  void clear()
368  {
369  m_edges.resize(0);
370  m_fill0 = m_fill1 = m_line = 0;
371  }
372 
374 
375 
377  bool isClosed() const
378  {
379  if (m_edges.empty()) return true;
380  return m_edges.back().ap == ap;
381  }
382 
384  void close()
385  {
386  if ( m_edges.empty() ) return;
387 
388  // Close it with a straight edge if needed
389  const Edge& lastedge = m_edges.back();
390  if ( lastedge.ap != ap )
391  {
392  Edge newedge(ap, ap);
393  m_edges.push_back(newedge);
394  }
395  }
396 
400  //
403  bool
404  withinSquareDistance(const point& p, double dist) const
405  {
406  size_t nedges = m_edges.size();
407 
408  if ( ! nedges ) return false;
409 
410  point px(ap);
411  for (size_t i=0; i<nedges; ++i)
412  {
413  const Edge& e = m_edges[i];
414  point np(e.ap);
415 
416  if (e.straight())
417  {
418  double d = Edge::squareDistancePtSeg(p, px, np);
419  if ( d <= dist ) return true;
420  }
421  else
422  {
423 
424  const point& A = px;
425  const point& C = e.cp;
426  const point& B = e.ap;
427 
428  // Approximate the curve to segCount segments
429  // and compute distance of query point from each
430  // segment.
431  //
432  // TODO: find an apprpriate value for segCount based
433  // on rendering scale ?
434  //
435  int segCount = 10;
436  point p0(A.x, A.y);
437  for (int i=1; i<=segCount; ++i)
438  {
439  float t1 = static_cast<float>(i) / segCount;
440  point p1 = Edge::pointOnCurve(A, C, B, t1);
441 
442  // distance from point and segment being an approximation
443  // of the curve
444  double d = Edge::squareDistancePtSeg(p, p0, p1);
445  if ( d <= dist ) return true;
446 
447  p0.setTo(p1.x, p1.y);
448  }
449  }
450  px = np;
451  }
452 
453  return false;
454  }
455 
457  void transform(const SWFMatrix& mat)
458  {
459  mat.transform(ap);
460  std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end();
461  for(; it != ie; ++it)
462  {
463  (*it).transform(mat);
464  }
465  }
466 
468  void setNewShape()
469  {
470  m_new_shape=true;
471  }
472 
474  bool getNewShape() const
475  {
476  return m_new_shape;
477  }
478 
480  bool empty() const
481  {
482  return m_edges.empty();
483  }
484 
486  //
494  void setLeftFill(unsigned f)
495  {
496  m_fill0 = f;
497  }
498 
499  unsigned getLeftFill() const
500  {
501  return m_fill0;
502  }
503 
505  //
513  void setRightFill(unsigned f)
514  {
515  m_fill1 = f;
516  }
517 
518  unsigned getRightFill() const
519  {
520  return m_fill1;
521  }
522 
524  //
532  void setLineStyle(unsigned i)
533  {
534  m_line = i;
535  }
536 
537  unsigned getLineStyle() const
538  {
539  return m_line;
540  }
541 
543  size_t size() const
544  {
545  return m_edges.size();
546  }
547 
549  Edge& operator[] (size_t n)
550  {
551  return m_edges[n];
552  }
553 
555  const Edge& operator[] (size_t n) const
556  {
557  return m_edges[n];
558  }
559 
561  bool isNewShape() const
562  {
563  return m_new_shape;
564  }
565 
566 }; // end of class Path
567 
568 namespace geometry
569 {
570 
571 bool pointTest(const std::vector<Path>& paths,
572  const std::vector<LineStyle>& lineStyles, boost::int32_t x,
573  boost::int32_t y, const SWFMatrix& wm);
574 
575 } // namespace geometry
576 
577 
578 } // namespace gnash
579 
580 #endif // GNASH_GEOMETRY_H
581 
582 
583 // Local Variables:
584 // mode: C++
585 // c-basic-offset: 8
586 // tab-width: 8
587 // indent-tabs-mode: t
588 // End: