00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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