2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
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.
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.
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
24 #include "SWFMatrix.h"
28 #include <vector> // for path composition
29 #include <cmath> // sqrt
32 // Forward declarations
40 /// Defines an edge with a control point and an anchor point.
42 /// Could be a quadratic bezier curve, or a straight line(degenerated curve).
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
58 constexpr Edge(std::int32_t cx
, std::int32_t cy
, std::int32_t ax
,
65 constexpr Edge(const Edge
& from
)
71 constexpr Edge(const point
& ncp
, const point
& nap
)
82 /// Transform the edge according to the given SWFMatrix.
83 void transform(const SWFMatrix
& mat
)
89 /// Return squared distance between point pt and segment A-B
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
);
109 return p
.squareDistance(A
);
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
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
137 pointOnCurve(const point
& A
, const point
& C
, const point
& B
, float t
)
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
,
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.
169 /// Left fill style index (1-based)
172 /// Right fill style index (1-based)
175 /// Line style index (1-based)
178 /// Start point of the path
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
193 reset(0, 0, 0, 0, 0);
196 Path(const Path
& from
)
198 m_fill0(from
.m_fill0
),
199 m_fill1(from
.m_fill1
),
202 m_edges(from
.m_edges
)
206 /// Initialize a path
209 /// X coordinate of path origin in TWIPS
212 /// Y coordinate in path origin in TWIPS
215 /// Fill style index for left fill (1-based).
216 /// Zero means NO style.
219 /// Fill style index for right fill (1-based)
220 /// Zero means NO style.
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
234 /// X coordinate of path origin in TWIPS
237 /// Y coordinate in path origin in TWIPS
240 /// Fill style index for left fill
243 /// Fill style index for right fill
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.
262 /// Expand given SWFRect to include bounds of this path
265 /// The rectangle to expand with our own bounds
268 /// The thickess of our lines, half the thickness will
269 /// be added in all directions in swf8+, all of it will
272 /// @param swfVersion
273 /// SWF version to use.
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
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
);
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.
319 /// X coordinate in TWIPS
322 /// Y coordinate in TWIPS
325 drawLineTo(std::int32_t dx
, std::int32_t dy
)
327 m_edges
.emplace_back(dx
, dy
, dx
, dy
);
332 /// Offset values are relative to path origin and
333 /// expressed in TWIPS.
336 /// Control point's X coordinate.
339 /// Control point's Y coordinate.
342 /// Anchor point's X ordinate.
345 /// Anchor point's Y ordinate.
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
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
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
);
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.
390 withinSquareDistance(const point
& p
, double dist
) const
392 size_t nedges
= m_edges
.size();
394 if ( ! nedges
) return false;
397 for (size_t i
=0; i
<nedges
; ++i
)
399 const Edge
& e
= m_edges
[i
];
404 double d
= Edge::squareDistancePtSeg(p
, px
, np
);
405 if ( d
<= dist
) return true;
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
418 // TODO: find an apprpriate value for segCount based
419 // on rendering scale ?
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
430 double d
= Edge::squareDistancePtSeg(p
, p0
, p1
);
431 if ( d
<= dist
) return true;
433 p0
.setTo(p1
.x
, p1
.y
);
442 /// Transform all path coordinates according to the given SWFMatrix.
443 void transform(const SWFMatrix
& mat
)
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
456 return m_edges
.empty();
459 /// Set the fill to use on the left side
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
)
473 unsigned getLeftFill() const
478 /// Set the fill to use on the left side
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
)
492 unsigned getRightFill() const
497 /// Set the line style to use for this path
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
)
511 unsigned getLineStyle() const
516 /// Return the number of edges in this path
519 return m_edges
.size();
522 /// Return a reference to the Nth edge
523 Edge
& operator[] (size_t n
)
528 /// Return a const reference to the Nth edge
529 const Edge
& operator[] (size_t n
) const
533 }; // end of class Path
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
547 #endif // GNASH_GEOMETRY_H
554 // indent-tabs-mode: t