• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • Examples
  • File List
  • File Members

Geometry.h

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

Generated on Thu Sep 30 2010 14:34:58 for Gnash by  doxygen 1.7.1