Gnash 0.8.9

Geometry.h

Go to the documentation of this file.
00001 //
00002 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
00003 //   2011 Free Software Foundation, Inc
00004 // 
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 3 of the License, or
00008 // (at your option) any later version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 //
00019 
00020 #ifndef GNASH_GEOMETRY_H
00021 #define GNASH_GEOMETRY_H
00022 
00023 #include "dsodefs.h"
00024 #include "SWFMatrix.h"
00025 #include "SWFRect.h"
00026 #include "Point2d.h"
00027 
00028 #include <vector> // for path composition
00029 #include <cmath> // sqrt
00030 
00031 
00032 // Forward declarations
00033 namespace gnash {
00034     class LineStyle;
00035 }
00036 
00037 namespace gnash { 
00038 
00044 class Edge
00045 {
00046 public:
00047     
00048     // Quadratic bezier: point = p0 * t^2 + p1 * 2t(1-t) + p2 * (1-t)^2
00049     point cp; // control point, TWIPS
00050     point ap; // anchor    point, TWIPS
00051 
00052     Edge() 
00053         :
00054         cp(0, 0),
00055         ap(0, 0)
00056     {}
00057     
00058     Edge(boost::int32_t cx, boost::int32_t cy, boost::int32_t ax,
00059             boost::int32_t ay)
00060         :
00061         cp(cx, cy),
00062         ap(ax, ay)
00063     {}
00064 
00065     Edge(const Edge& from)
00066         : 
00067         cp(from.cp),
00068         ap(from.ap)
00069     {}
00070 
00071     Edge(const point& ncp, const point& nap)
00072         :
00073         cp(ncp),
00074         ap(nap)
00075     {}
00076 
00077     bool straight() const
00078     {
00079         return cp == ap;
00080     }
00081     
00083     void transform(const SWFMatrix& mat)
00084     {
00085         mat.transform(ap);
00086         mat.transform(cp);
00087     }
00088 
00090     static double
00091     squareDistancePtSeg(const point& p, const point& A, const point& B)
00092     {
00093         boost::int32_t dx = B.x - A.x;
00094         boost::int32_t dy = B.y - A.y;
00095 
00096         if ( dx == 0 && dy == 0 ) 
00097         {
00098             return p.squareDistance(A);
00099         }
00100 
00101         boost::int32_t pdx = p.x - A.x;
00102         boost::int32_t pdy = p.y - A.y;
00103 
00104         double u = (static_cast<double>(pdx) * dx + static_cast<double>(pdy) * dy ) /
00105             (static_cast<double>(dx)*dx + static_cast<double>(dy)*dy );
00106 
00107         if (u <= 0)
00108         {
00109             return p.squareDistance(A); 
00110         }
00111 
00112         if (u >= 1)
00113         {
00114             return p.squareDistance(B);
00115         }
00116 
00117         point px(A, B, u); // FIXME: this interpolation introduce a precision loss (point is int-based)
00118         return p.squareDistance(px);
00119     }
00120 
00122     static double
00123     distancePtSeg(const point& pt, const point& A, const point& B)
00124     {
00125         double square = squareDistancePtSeg(pt, A, B);
00126         return std::sqrt(square);
00127     }
00128 
00130     //
00137 
00138     static point
00139     pointOnCurve(const point& A, const point& C, const point& B, float t)
00140     {
00141         point Q1(A, C, t);
00142         point Q2(C, B, t);
00143         point R(Q1, Q2, t);
00144 
00145         return R;
00146     }
00147 
00150     //
00157     static boost::int64_t squareDistancePtCurve(const point& A,
00158                          const point& C,
00159                          const point& B,
00160                          const point& p, float t)
00161     {
00162         return p.squareDistance( pointOnCurve(A, C, B, t) );
00163     }
00164 };
00165 
00166 
00168 class DSOEXPORT Path
00169 {
00170 public:
00172     unsigned m_fill0;
00173 
00175     unsigned m_fill1;
00176 
00178     unsigned m_line;
00179 
00181     point ap; 
00182 
00184     std::vector<Edge> m_edges;
00185 
00190     bool m_new_shape;
00191     
00193     //
00197     Path(bool newShape = false)
00198         : 
00199         m_new_shape(newShape)
00200     {
00201         reset(0, 0, 0, 0, 0);
00202     }
00203 
00204     Path(const Path& from)
00205         : 
00206         m_fill0(from.m_fill0),
00207         m_fill1(from.m_fill1),
00208         m_line(from.m_line),
00209         ap(from.ap),
00210         m_edges(from.m_edges),
00211         m_new_shape(from.m_new_shape)                
00212     {
00213     }
00214     
00216     //
00237     Path(boost::int32_t ax, boost::int32_t ay, 
00238             unsigned fill0, unsigned fill1, unsigned line, 
00239             bool newShape)
00240         :
00241         m_new_shape(newShape)
00242     {
00243         reset(ax, ay, fill0, fill1, line);
00244     }
00245 
00247     //
00259     //
00263     void reset(boost::int32_t ax, boost::int32_t ay, 
00264             unsigned fill0, unsigned fill1, unsigned line)
00265     // Reset all our members to the given values, and clear our edge list.
00266     {
00267         ap.x = ax;
00268         ap.y = ay;
00269         m_fill0 = fill0;
00270         m_fill1 = fill1;
00271         m_line = line;
00272 
00273         m_edges.resize(0);
00274         assert(empty());
00275     }
00276 
00278     //
00290     void
00291     expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const
00292     {
00293         const Path&    p = *this;
00294         size_t nedges = m_edges.size();
00295         
00296         if ( ! nedges ) return; // this path adds nothing
00297 
00298         if (thickness)
00299         {
00300             // NOTE: Half of thickness would be enough (and correct) for
00301             // radius, but that would not match how Flash calculates the
00302             // bounds using the drawing API.                                                
00303             unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
00304 
00305             r.expand_to_circle(ap.x, ap.y, radius);
00306             for (unsigned int j = 0; j<nedges; j++)
00307             {
00308                 r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
00309                 r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
00310             }
00311         }
00312         else
00313         {
00314             r.expand_to_point(ap.x, ap.y);
00315             for (unsigned int j = 0; j<nedges; j++)
00316             {
00317                 r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
00318                 r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
00319             }
00320         }
00321     }
00322 
00327 
00329     //
00339     void 
00340     drawLineTo(boost::int32_t dx, boost::int32_t dy)
00341     {
00342         m_edges.push_back(Edge(dx, dy, dx, dy)); 
00343     }
00344 
00346     //
00362     void 
00363     drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady)
00364     {
00365         m_edges.push_back(Edge(cdx, cdy, adx, ady)); 
00366     }
00367 
00369     void clear()
00370     {
00371         m_edges.resize(0);
00372         m_fill0 = m_fill1 = m_line = 0;
00373     }
00374 
00376 
00377 
00379     bool isClosed() const 
00380     {
00381         if (m_edges.empty()) return true;
00382         return m_edges.back().ap == ap; 
00383     }
00384 
00386     void close()
00387     {
00388         if ( m_edges.empty() ) return;
00389 
00390         // Close it with a straight edge if needed
00391         const Edge& lastedge = m_edges.back();
00392         if ( lastedge.ap != ap )
00393         {
00394             Edge newedge(ap, ap);
00395             m_edges.push_back(newedge);
00396         }
00397     }
00398 
00402     //
00405     bool
00406     withinSquareDistance(const point& p, double dist) const
00407     {
00408         size_t nedges = m_edges.size();
00409 
00410         if ( ! nedges ) return false;
00411 
00412         point px(ap);
00413         for (size_t i=0; i<nedges; ++i)
00414         {
00415             const Edge& e = m_edges[i];
00416             point np(e.ap);
00417 
00418             if (e.straight())
00419             {
00420                 double d = Edge::squareDistancePtSeg(p, px, np);
00421                 if ( d <= dist ) return true;
00422             }
00423             else
00424             {
00425 
00426                 const point& A = px;
00427                 const point& C = e.cp;
00428                 const point& B = e.ap;
00429 
00430                 // Approximate the curve to segCount segments
00431                 // and compute distance of query point from each
00432                 // segment.
00433                 //
00434                 // TODO: find an apprpriate value for segCount based
00435                 //             on rendering scale ?
00436                 //
00437                 int segCount = 10; 
00438                 point p0(A.x, A.y);
00439                 for (int i=1; i<=segCount; ++i)
00440                 {
00441                     float t1 = static_cast<float>(i) / segCount;
00442                     point p1 = Edge::pointOnCurve(A, C, B, t1);
00443 
00444                     // distance from point and segment being an approximation 
00445                     // of the curve 
00446                     double d = Edge::squareDistancePtSeg(p, p0, p1);
00447                     if ( d <= dist ) return true;
00448 
00449                     p0.setTo(p1.x, p1.y);
00450                 }
00451             }
00452             px = np;
00453         }
00454 
00455         return false;
00456     }
00457 
00459     void transform(const SWFMatrix& mat)
00460     {
00461         mat.transform(ap);
00462         std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end();
00463         for(; it != ie; it++)
00464         {
00465             (*it).transform(mat);
00466         }
00467     }        
00468 
00470     void setNewShape() 
00471     { 
00472             m_new_shape=true; 
00473     }
00474 
00476     bool getNewShape() const 
00477     { 
00478         return m_new_shape; 
00479     }
00480 
00482     bool empty() const
00483     {
00484         return m_edges.empty();
00485     }
00486 
00488     //
00496     void setLeftFill(unsigned f)
00497     {
00498         m_fill0 = f;
00499     }
00500 
00501     unsigned getLeftFill() const
00502     {
00503         return m_fill0;
00504     }
00505 
00507     //
00515     void setRightFill(unsigned f)
00516     {
00517         m_fill1 = f;
00518     }
00519 
00520     unsigned getRightFill() const
00521     {
00522         return m_fill1;
00523     }
00524 
00526     //
00534     void setLineStyle(unsigned i)
00535     {
00536         m_line = i;
00537     }
00538 
00539     unsigned getLineStyle() const
00540     {
00541         return m_line;
00542     }
00543 
00545     size_t size() const
00546     {
00547         return m_edges.size();
00548     }
00549 
00551     Edge& operator[] (size_t n)
00552     {
00553         return m_edges[n];
00554     }
00555 
00557     const Edge& operator[] (size_t n) const
00558     {
00559         return m_edges[n];
00560     }
00561 
00563     bool isNewShape() const
00564     {
00565         return m_new_shape;
00566     }
00567 
00568 }; // end of class Path
00569 
00570 namespace geometry
00571 {
00572 
00573 bool pointTest(const std::vector<Path>& paths,
00574     const std::vector<LineStyle>& lineStyles, boost::int32_t x,
00575     boost::int32_t y, const SWFMatrix& wm);
00576 
00577 } // namespace geometry
00578 
00579 
00580 } // namespace gnash
00581 
00582 #endif // GNASH_GEOMETRY_H
00583 
00584 
00585 // Local Variables:
00586 // mode: C++
00587 // c-basic-offset: 8 
00588 // tab-width: 8
00589 // indent-tabs-mode: t
00590 // End: