Common/Geom/CurveAlg.h

Go to the documentation of this file.
00001 //-------------------------------------------------------------------
00004 // Copyright (c) 2007 Celeritive Technologies, Inc.
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License, or (at your option) any later version.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00019 //
00020 //-------------------------------------------------------------------
00021 #pragma once
00022 #ifndef VOLUMILL_CURVEALG_H
00023 #define VOLUMILL_CURVEALG_H
00024 
00025 #include <Geom/Curve.h>
00026 #include <Util/TypeStripper.h>
00027 #include <boost/variant.hpp>
00028 
00029 namespace geom
00030 {
00031 
00032 template<class P> class BoundingBox;
00033 typedef boost::variant<geom::Point2d, CurvePtr2d> CurveIntersectionResult;
00034 typedef std::vector<CurveIntersectionResult> CurveIntersectionResults;
00035 
00036 namespace detail
00037 {
00038    void getBoundingBoxImpl (const geom::ParametricCurve<2>& c, BoundingBox<geom::Point2d>* pBox);
00039    void intersectCurvesImpl (
00040       const geom::ParametricCurve<2>& c1,
00041       const geom::ParametricCurve<2>& c2,
00042       double tol,
00043       CurveIntersectionResults* pIntersections);
00044    bool projectPointToCurveImpl (
00045       const geom::ParametricCurve<2>& curve, const Point2d& pt, double tol, Point2d* pProjPt=0, double* pParam=0);
00046    void tessellateCurveImpl (
00047       const geom::ParametricCurve<2>& curve,
00048       double tol,
00049       std::vector<Point2d>* pPoints);
00050    double getLengthImpl (
00051       const geom::ParametricCurve<2>& curve);
00052 }
00053 
00054 template<class Curve>
00055 inline void getBoundingBox (const Curve& c, BoundingBox<geom::Point2d>* pBox)
00056 {
00057    detail::getBoundingBoxImpl (util::TypeStripper<Curve>::cstrip (c), pBox);
00058 }
00059 
00060 template<class Curve>
00061 inline void intersectCurves (const Curve& c1, const Curve& c2, double tol, CurveIntersectionResults* pIntersections)
00062 {
00063    detail::intersectCurvesImpl (
00064       util::TypeStripper<Curve>::cstrip (c1),
00065       util::TypeStripper<Curve>::cstrip (c2),
00066       tol,
00067       pIntersections);
00068 }
00069 
00070 template<class Curve>
00071 inline double getLength (const Curve& curve)
00072 {
00073    return detail::getLengthImpl (util::TypeStripper<Curve>::cstrip (curve));
00074 }
00075 
00076 CurvePtr2d createSubCurve (const CurvePtr2d& curve, double startParam, double endParam);
00077 
00078 template<class Curve, class Point>
00079 inline bool projectPointToCurve (
00080    const Curve& curve, const Point& pt, double tol, Point* pProjPt=0, double* pParam=0)
00081 {
00082    return detail::projectPointToCurveImpl (
00083       util::TypeStripper<Curve>::cstrip (curve), pt, tol, pProjPt, pParam);
00084 }
00085 
00086 template<class Curve, class Point>
00087 inline void tessellateCurve (const Curve& curve, double tol, std::vector<Point>* pPoints)
00088 {
00089    detail::tessellateCurveImpl (
00090       util::TypeStripper<Curve>::cstrip (curve), tol, pPoints);
00091 }
00092 
00093 template<class CurveIter, class Point>
00094 inline void tessellateLoop (CurveIter begin, CurveIter end, double tol, std::vector<Point>* pPoints)
00095 {
00096    for (; begin != end; ++begin)
00097    {
00098       if (pPoints->size())
00099          pPoints->pop_back();
00100       tessellateCurve (*begin, tol, pPoints);
00101    }
00102 
00103    if (pPoints->size() >= 2)
00104    {
00105       // Ensure the loop really is closed if it's nearly closed
00106       if (geom::distance (pPoints->front(), pPoints->back()) < util::pointResolution)
00107          pPoints->back() = pPoints->front();
00108    }
00109    else
00110       WARN (pPoints->size() >= 2);
00111 }
00112 
00113 template<class Curves, class Point>
00114 inline void tessellateLoop (const Curves& curves, double tol, std::vector<Point>* pPoints)
00115 {
00116    tessellateLoop (curves.begin(), curves.end(), tol, pPoints);
00117 }
00118 
00119 template<class Curves>
00120 inline void reverseLoop (Curves& curves)
00121 {
00122    std::reverse (curves.begin(), curves.end());
00123    for (typename Curves::iterator it = curves.begin(); it != curves.end(); ++it)
00124    {
00125       util::TypeStripper<typename Curves::value_type>::strip (*it).reverse();
00126    }
00127 }
00128 
00129 template<class CurveIter, class KnotIter>
00130 inline void createKnots (CurveIter begin, CurveIter end, KnotIter outIt)
00131 {
00132    double lastKnot = 0.0;
00133    *outIt++ = lastKnot;
00134    for (; begin != end; ++begin)
00135    {
00136       double knot = lastKnot + getLength (*begin);
00137       *outIt++ = knot;
00138       lastKnot = knot;
00139    }
00140 }
00141 
00142 template<class KnotIter>
00143 int getSpan (KnotIter begin, KnotIter end, double param)
00144 {
00145    KnotIter it = std::upper_bound (begin, end, param);
00146    int idx = (int) (it - begin);
00147    if (it == end)
00148       idx -= 2;
00149    else if (idx != 0)
00150       --idx;
00151    return idx;
00152 }
00153 
00157 template<class Arc, class P>
00158 bool projectPointToArc (const Arc& arc, const P& pt, double tol, P* pProjPt = 0, double* pParam = 0)
00159 {
00160    const P& center = arc.getCenter();
00161    VecNd<P::Dim> dir (pt - center);
00162    double dirLen = length (dir);
00163    if (length (dir) < util::doubleEps)
00164    {
00165       WARN (length (dir) >= util::doubleEps)("Cannot project the center point of an arc to the arc");
00166       util::assignPtr (pParam, 1e30);
00167       return false;
00168    }
00169    double r = arc.getRadius();
00170    // Scale the tolerance so that it is valid in the unitless world of angles
00171    tol /= r;
00172    const std::pair<double, double>& angleRange = arc.getAngleRange();
00173    VecNd<P::Dim> startDir;
00174    bool cw = angleRange.first > angleRange.second;
00175    double totalAngle;
00176    if (cw)
00177    {
00178       startDir[0] = cos (angleRange.second);
00179       startDir[1] = sin (angleRange.second);
00180       totalAngle = angleRange.first - angleRange.second;
00181    }
00182    else
00183    {
00184       startDir[0] = cos (angleRange.first);
00185       startDir[1] = sin (angleRange.first);
00186       totalAngle = angleRange.second - angleRange.first;
00187    }
00188    double cosAngle = startDir * dir;
00189    double sinAngle = dir[1] * startDir[0] - dir[0] * startDir[1];
00190    double angle = atan2 (sinAngle, cosAngle);
00191    if (angle < -tol)
00192       angle += 2 * util::pi;
00193    if (angle < tol)
00194    {
00195       util::assignPtr (pProjPt, cw ? getEndPoint (&arc) : getStartPoint (&arc));
00196       util::assignPtr (pParam, cw ? 1.0 : 0.0);
00197       return true;
00198    }
00199    if (fabs (angle - totalAngle) < tol)
00200    {
00201       util::assignPtr (pProjPt, cw ? getStartPoint (&arc) : getEndPoint (&arc));
00202       util::assignPtr (pParam, cw ? 0.0 : 1.0);
00203       return true;
00204    }
00205    if (angle > totalAngle)
00206    {
00207       P startPt (getStartPoint (&arc));
00208       P endPt (getEndPoint (&arc));
00209       double startDist = geom::distance (pt, startPt);
00210       double endDist = geom::distance (pt, endPt);
00211       if (startDist < endDist)
00212       {
00213          util::assignPtr (pProjPt, startPt);
00214          util::assignPtr (pParam, 0.0);
00215       }
00216       else
00217       {
00218          util::assignPtr (pProjPt, endPt);
00219          util::assignPtr (pParam, 1.0);
00220       }
00221       return false;
00222    }
00223    util::assignPtr (pProjPt, center + (r / dirLen) * dir);
00224    if (cw)
00225       util::assignPtr (pParam, 1 - angle / totalAngle);
00226    else
00227       util::assignPtr (pParam, angle / totalAngle);
00228    VALIDATE (angle > 0 && angle < totalAngle);
00229    return true;
00230 }
00231 }
00232 
00233 #endif

Generated on Tue Jan 29 21:37:56 2008 for VoluMill Universal Client by  doxygen 1.4.6