Gnash  0.8.10
Geometry.h
Go to the documentation of this file.
00001 //
00002 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
00003 //   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         const double square = squareDistancePtSeg(pt, A, B);
00126         return std::sqrt(square);
00127     }
00128 
00130     //
00136     static point
00137     pointOnCurve(const point& A, const point& C, const point& B, float t)
00138     {
00139         point Q1(A, C, t);
00140         point Q2(C, B, t);
00141         point R(Q1, Q2, t);
00142 
00143         return R;
00144     }
00145 
00148     //
00155     static boost::int64_t squareDistancePtCurve(const point& A,
00156                          const point& C,
00157                          const point& B,
00158                          const point& p, float t)
00159     {
00160         return p.squareDistance( pointOnCurve(A, C, B, t) );
00161     }
00162 };
00163 
00164 
00166 class DSOEXPORT Path
00167 {
00168 public:
00170     unsigned m_fill0;
00171 
00173     unsigned m_fill1;
00174 
00176     unsigned m_line;
00177 
00179     point ap; 
00180 
00182     std::vector<Edge> m_edges;
00183 
00188     bool m_new_shape;
00189     
00191     //
00195     Path(bool newShape = false)
00196         : 
00197         m_new_shape(newShape)
00198     {
00199         reset(0, 0, 0, 0, 0);
00200     }
00201 
00202     Path(const Path& from)
00203         : 
00204         m_fill0(from.m_fill0),
00205         m_fill1(from.m_fill1),
00206         m_line(from.m_line),
00207         ap(from.ap),
00208         m_edges(from.m_edges),
00209         m_new_shape(from.m_new_shape)                
00210     {
00211     }
00212     
00214     //
00235     Path(boost::int32_t ax, boost::int32_t ay, 
00236             unsigned fill0, unsigned fill1, unsigned line, 
00237             bool newShape)
00238         :
00239         m_new_shape(newShape)
00240     {
00241         reset(ax, ay, fill0, fill1, line);
00242     }
00243 
00245     //
00257     //
00261     void reset(boost::int32_t ax, boost::int32_t ay, 
00262             unsigned fill0, unsigned fill1, unsigned line)
00263     // Reset all our members to the given values, and clear our edge list.
00264     {
00265         ap.x = ax;
00266         ap.y = ay;
00267         m_fill0 = fill0;
00268         m_fill1 = fill1;
00269         m_line = line;
00270 
00271         m_edges.resize(0);
00272         assert(empty());
00273     }
00274 
00276     //
00288     void
00289     expandBounds(SWFRect& r, unsigned int thickness, int swfVersion) const
00290     {
00291         const Path&    p = *this;
00292         size_t nedges = m_edges.size();
00293         
00294         if ( ! nedges ) return; // this path adds nothing
00295 
00296         if (thickness)
00297         {
00298             // NOTE: Half of thickness would be enough (and correct) for
00299             // radius, but that would not match how Flash calculates the
00300             // bounds using the drawing API.                                                
00301             unsigned int radius = swfVersion < 8 ? thickness : thickness/2;
00302 
00303             r.expand_to_circle(ap.x, ap.y, radius);
00304             for (unsigned int j = 0; j<nedges; j++)
00305             {
00306                 r.expand_to_circle(m_edges[j].ap.x, m_edges[j].ap.y, radius);
00307                 r.expand_to_circle(m_edges[j].cp.x, m_edges[j].cp.y, radius);
00308             }
00309         }
00310         else
00311         {
00312             r.expand_to_point(ap.x, ap.y);
00313             for (unsigned int j = 0; j<nedges; j++)
00314             {
00315                 r.expand_to_point(m_edges[j].ap.x, p.m_edges[j].ap.y);
00316                 r.expand_to_point(m_edges[j].cp.x, p.m_edges[j].cp.y);
00317             }
00318         }
00319     }
00320 
00325 
00327     //
00337     void 
00338     drawLineTo(boost::int32_t dx, boost::int32_t dy)
00339     {
00340         m_edges.push_back(Edge(dx, dy, dx, dy)); 
00341     }
00342 
00344     //
00360     void 
00361     drawCurveTo(boost::int32_t cdx, boost::int32_t cdy, boost::int32_t adx, boost::int32_t ady)
00362     {
00363         m_edges.push_back(Edge(cdx, cdy, adx, ady)); 
00364     }
00365 
00367     void clear()
00368     {
00369         m_edges.resize(0);
00370         m_fill0 = m_fill1 = m_line = 0;
00371     }
00372 
00374 
00375 
00377     bool isClosed() const 
00378     {
00379         if (m_edges.empty()) return true;
00380         return m_edges.back().ap == ap; 
00381     }
00382 
00384     void close()
00385     {
00386         if ( m_edges.empty() ) return;
00387 
00388         // Close it with a straight edge if needed
00389         const Edge& lastedge = m_edges.back();
00390         if ( lastedge.ap != ap )
00391         {
00392             Edge newedge(ap, ap);
00393             m_edges.push_back(newedge);
00394         }
00395     }
00396 
00400     //
00403     bool
00404     withinSquareDistance(const point& p, double dist) const
00405     {
00406         size_t nedges = m_edges.size();
00407 
00408         if ( ! nedges ) return false;
00409 
00410         point px(ap);
00411         for (size_t i=0; i<nedges; ++i)
00412         {
00413             const Edge& e = m_edges[i];
00414             point np(e.ap);
00415 
00416             if (e.straight())
00417             {
00418                 double d = Edge::squareDistancePtSeg(p, px, np);
00419                 if ( d <= dist ) return true;
00420             }
00421             else
00422             {
00423 
00424                 const point& A = px;
00425                 const point& C = e.cp;
00426                 const point& B = e.ap;
00427 
00428                 // Approximate the curve to segCount segments
00429                 // and compute distance of query point from each
00430                 // segment.
00431                 //
00432                 // TODO: find an apprpriate value for segCount based
00433                 //             on rendering scale ?
00434                 //
00435                 int segCount = 10; 
00436                 point p0(A.x, A.y);
00437                 for (int i=1; i<=segCount; ++i)
00438                 {
00439                     float t1 = static_cast<float>(i) / segCount;
00440                     point p1 = Edge::pointOnCurve(A, C, B, t1);
00441 
00442                     // distance from point and segment being an approximation 
00443                     // of the curve 
00444                     double d = Edge::squareDistancePtSeg(p, p0, p1);
00445                     if ( d <= dist ) return true;
00446 
00447                     p0.setTo(p1.x, p1.y);
00448                 }
00449             }
00450             px = np;
00451         }
00452 
00453         return false;
00454     }
00455 
00457     void transform(const SWFMatrix& mat)
00458     {
00459         mat.transform(ap);
00460         std::vector<Edge>::iterator it = m_edges.begin(), ie = m_edges.end();
00461         for(; it != ie; ++it)
00462         {
00463             (*it).transform(mat);
00464         }
00465     }        
00466 
00468     void setNewShape() 
00469     { 
00470             m_new_shape=true; 
00471     }
00472 
00474     bool getNewShape() const 
00475     { 
00476         return m_new_shape; 
00477     }
00478 
00480     bool empty() const
00481     {
00482         return m_edges.empty();
00483     }
00484 
00486     //
00494     void setLeftFill(unsigned f)
00495     {
00496         m_fill0 = f;
00497     }
00498 
00499     unsigned getLeftFill() const
00500     {
00501         return m_fill0;
00502     }
00503 
00505     //
00513     void setRightFill(unsigned f)
00514     {
00515         m_fill1 = f;
00516     }
00517 
00518     unsigned getRightFill() const
00519     {
00520         return m_fill1;
00521     }
00522 
00524     //
00532     void setLineStyle(unsigned i)
00533     {
00534         m_line = i;
00535     }
00536 
00537     unsigned getLineStyle() const
00538     {
00539         return m_line;
00540     }
00541 
00543     size_t size() const
00544     {
00545         return m_edges.size();
00546     }
00547 
00549     Edge& operator[] (size_t n)
00550     {
00551         return m_edges[n];
00552     }
00553 
00555     const Edge& operator[] (size_t n) const
00556     {
00557         return m_edges[n];
00558     }
00559 
00561     bool isNewShape() const
00562     {
00563         return m_new_shape;
00564     }
00565 
00566 }; // end of class Path
00567 
00568 namespace geometry
00569 {
00570 
00571 bool pointTest(const std::vector<Path>& paths,
00572     const std::vector<LineStyle>& lineStyles, boost::int32_t x,
00573     boost::int32_t y, const SWFMatrix& wm);
00574 
00575 } // namespace geometry
00576 
00577 
00578 } // namespace gnash
00579 
00580 #endif // GNASH_GEOMETRY_H
00581 
00582 
00583 // Local Variables:
00584 // mode: C++
00585 // c-basic-offset: 8 
00586 // tab-width: 8
00587 // indent-tabs-mode: t
00588 // End: