Code

Update to 2geom rev. 1538
authordvlierop2 <dvlierop2@users.sourceforge.net>
Fri, 15 Aug 2008 20:23:54 +0000 (20:23 +0000)
committerdvlierop2 <dvlierop2@users.sourceforge.net>
Fri, 15 Aug 2008 20:23:54 +0000 (20:23 +0000)
src/2geom/CMakeLists.txt
src/2geom/angle.h
src/2geom/elliptical-arc.cpp
src/2geom/geom.cpp
src/2geom/geom.h
src/2geom/path-intersection.h
src/2geom/path.cpp
src/2geom/path.h
src/2geom/pathvector.h
src/2geom/svg-elliptical-arc.cpp

index e94c5c673443bd3e3d74dc9bf3de240ed15cb057..cd2f4a71282bde000de5969bb94d27c725de881f 100644 (file)
-SET(2geom_SRC
-basic-intersection.cpp
-bezier-utils.cpp
+#generate parser file with ragel
+SET(SVG_PARSER_CPP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.cpp")
+SET(SVG_PARSER_TMP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.tmp")
+SET(SVG_PARSER_RL "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.rl")
+SET(GENERATE_SVG_PARSER NOT EXISTS "${SVG_PARSER_CPP}")
+SET(REGENERATE_SVG_PARSER "${SVG_PARSER_CPP}" IS_NEWER_THAN "${SVG_PARSER_RL}")
+IF( EXISTS "/usr/bin/ragel" OR EXISTS "/usr/local/bin/ragel" )
+IF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER)
+  EXECUTE_PROCESS(COMMAND ragel --version      OUTPUT_VARIABLE CMD_OUTPUT ERROR_QUIET)
+  STRING(REGEX MATCH "version [0-9]+[.]*[0-9]*" RALEG_VERSION ${CMD_OUTPUT})
+  STRING(REGEX REPLACE "version ([0-9]+).*" "\\1" RALEG_MAJOR ${RALEG_VERSION})
+  STRING(REGEX MATCH "[0-9]+$" RALEG_MINOR ${RALEG_VERSION})
+  IF( ${RALEG_MAJOR} LESS 6 AND ${RALEG_MINOR} LESS 18 )
+    SET(RLCODEGEN_CMD  rlcodegen)
+  ELSE( ${RALEG_MAJOR} LESS 6 AND ${RALEG_MINOR} LESS 18 )
+    SET(RLCODEGEN_CMD rlgen-cd)
+  ENDIF( ${RALEG_MAJOR} LESS 6 AND ${RALEG_MINOR} LESS 18 )
+  ADD_CUSTOM_COMMAND(OUTPUT "${SVG_PARSER_CPP}"
+                     COMMAND ragel -o "${SVG_PARSER_TMP}" "${SVG_PARSER_RL}"
+                     COMMAND ${RLCODEGEN_CMD} -T0 -o "${SVG_PARSER_CPP}" "${SVG_PARSER_TMP}"
+                     DEPENDS "${SVG_PARSER_RL}"
+                     WORKING_DIRECTORY "${CURRENT_SOURCE_DIR}"
+                     COMMENT "Generating svg_path_parser.cpp with ragel"
+                     )
+ENDIF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER)
+ENDIF( EXISTS "/usr/bin/ragel" OR EXISTS "/usr/local/bin/ragel" )
+
+SET(2GEOM_SRC
+
+svg-path.h
+svg-path.cpp
+svg-path-parser.h
+svg-path-parser.cpp
+
+ord.h
+
+#nearestpoint.cpp
+nearest-point.cpp
+nearest-point.h
+
+bezier-curve.h
 circle.cpp
-circle-circle.cpp
-conjugate_gradient.cpp
-convex-cover.cpp
-crossing.cpp
+circle.h
+curve.h
+curves.h
 curve-helpers.cpp
-d2-sbasis.cpp
+ellipse.cpp
+ellipse.h
 elliptical-arc.cpp
-geom.cpp
-matrix.cpp
-nearest-point.cpp
-numeric
+elliptical-arc.h
+hvlinesegment.h
+sbasis-curve.h
 path.cpp
+path.h
 path-intersection.cpp
+path-intersection.h
 pathvector.cpp
-piecewise.cpp
-point.cpp
+pathvector.h
+
+forward.h
+
+shape.cpp
+shape.h
+region.cpp
+region.h
+crossing.h
+crossing.cpp
+sweep.cpp
+sweep.h
+
 poly.cpp
+poly.h
 poly-dk-solve.cpp
+poly-dk-solve.h
 poly-laguerre-solve.cpp
+poly-laguerre-solve.h
+
 quadtree.cpp
-region.cpp
-sbasis-2d.cpp
+quadtree.h
+
+matrix.cpp
+matrix.h
+transforms.cpp
+transforms.h
+
+point.h
+point.cpp
+point-l.h
+
+coord.h
+
+d2.h
+d2-sbasis.h
+d2-sbasis.cpp
+rect.h
+
+piecewise.h
+piecewise.cpp
+
 sbasis.cpp
+sbasis.h
+sbasis-2d.h
+sbasis-2d.cpp
 sbasis-geometric.cpp
+sbasis-geometric.h
+sbasis-math.h
 sbasis-math.cpp
 sbasis-poly.cpp
+sbasis-poly.h
+#chebyshev.cpp # requires gsl, not useful, I think
+#chebyshev.h
 sbasis-roots.cpp
 sbasis-to-bezier.cpp
-shape.cpp
+sbasis-to-bezier.h
+
+bezier-to-sbasis.h
+
+basic-intersection.h
+basic-intersection.cpp
+
+geom.cpp
+geom.h
+
+utils.cpp
+utils.h
+exception.h
+angle.h
+
+bezier-utils.cpp
+bezier-utils.h
+choose.h
+circulator.h
+conjugate_gradient.cpp
+conjugate_gradient.h
+convex-cover.cpp
+convex-cover.h
 solve-bezier-one-d.cpp
 solve-bezier-parametric.cpp
-svg-path.cpp
-svg-path-parser.cpp
-sweep.cpp
-transforms.cpp
+solver.h
+sturm.h
+svg-elliptical-arc.cpp
+svg-elliptical-arc.h
+
+#arc-length.cpp
+#arc-length.h
+
+numeric/matrix.cpp
+)
+
+# make lib for 2geom
+ADD_LIBRARY(2geom ${LIB_TYPE} ${2GEOM_SRC})
+#TARGET_LINK_LIBRARIES(2geom blas gsl)
+TARGET_LINK_LIBRARIES(2geom "${LINK_GSL} ${GTK2_LINK_FLAGS}")
+INSTALL(TARGETS 2geom
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
 )
+FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
+INSTALL(FILES ${files} DESTINATION include/2geom/2geom)
 
-ADD_LIBRARY(2geom STATIC ${2geom_SRC})
+CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/2geom.pc.in
+                ${CMAKE_BINARY_DIR}/2geom.pc @ONLY IMMEDIATE )
+INSTALL(FILES "${CMAKE_BINARY_DIR}/2geom.pc" DESTINATION lib/pkgconfig)
+ADD_SUBDIRECTORY (toys)
+ADD_SUBDIRECTORY (tests)
+ADD_SUBDIRECTORY (py2geom)
index e95300a174f6dc87575c569af654619b8006a370..621235a5ec7496243be5c042d14afe60f9cce6d5 100644 (file)
@@ -31,7 +31,7 @@
  * the specific language governing rights and limitations.
  *
  */
+
 #ifndef LIB2GEOM_SEEN_ANGLE_H
 #define LIB2GEOM_SEEN_ANGLE_H
 
@@ -55,12 +55,14 @@ double map_circular_arc_on_unit_interval( double angle, double start_angle, doub
 {
     double d = end_angle - start_angle;
     double t = angle - start_angle;
-    if ( !cw ) 
+    if ( !cw )
     {
        d = -d;
        t = -t;
     }
-    if ( d < 0 ) d += 2*M_PI;  
+    d = std::fmod(d, 2*M_PI);
+    t = std::fmod(t, 2*M_PI);
+    if ( d < 0 ) d += 2*M_PI;
     if ( t < 0 ) t += 2*M_PI;
     return t / d;
 }
@@ -70,21 +72,21 @@ Coord map_unit_interval_on_circular_arc(Coord t, double start_angle, double end_
 {
        double sweep_angle = end_angle - start_angle;
        if ( !cw ) sweep_angle = -sweep_angle;
+       sweep_angle = std::fmod(sweep_angle, 2*M_PI);
        if ( sweep_angle < 0 ) sweep_angle += 2*M_PI;
-       
+
+       Coord angle = start_angle;
     if ( cw )
     {
-        Coord angle = start_angle + sweep_angle * t;
-        if ( !(angle < 2*M_PI) )
-            angle -= 2*M_PI;
-        return angle;
+        angle += sweep_angle * t;
     }
     else
     {
-        Coord angle = start_angle - sweep_angle * t;
-        if ( angle < 0 ) angle += 2*M_PI;
-        return angle;
+        angle -= sweep_angle * t;
     }
+    angle = std::fmod(angle, 2*M_PI);
+    if (angle < 0) angle += 2*M_PI;
+    return angle;
 }
 
 
index 552cdf5b3188f23c0b8c3e53ebb32b2cf26b252b..bf2b72b63bc1f7e66fe65aea2a5b965ffc7ad28a 100644 (file)
@@ -49,23 +49,23 @@ Rect EllipticalArc::boundsExact() const
        double sinrot = std::sin(rotation_angle());
        extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot );
        extremes[1] = extremes[0] + M_PI;
-       if ( extremes[0] < 0 ) extremes[0] += 2*M_PI;   
+       if ( extremes[0] < 0 ) extremes[0] += 2*M_PI;
        extremes[2] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot );
        extremes[3] = extremes[2] + M_PI;
        if ( extremes[2] < 0 ) extremes[2] += 2*M_PI;
-       
-       
+
+
        std::vector<double>arc_extremes(4);
        arc_extremes[0] = initialPoint()[X];
        arc_extremes[1] = finalPoint()[X];
-       if ( arc_extremes[0] < arc_extremes[1] ) 
+       if ( arc_extremes[0] < arc_extremes[1] )
                std::swap(arc_extremes[0], arc_extremes[1]);
        arc_extremes[2] = initialPoint()[Y];
        arc_extremes[3] = finalPoint()[Y];
-       if ( arc_extremes[2] < arc_extremes[3] ) 
+       if ( arc_extremes[2] < arc_extremes[3] )
                std::swap(arc_extremes[2], arc_extremes[3]);
-       
-       
+
+
        if ( start_angle() < end_angle() )
        {
                if ( sweep_flag() )
@@ -109,24 +109,24 @@ Rect EllipticalArc::boundsExact() const
                                {
                                        arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1];
                                }
-                       }               
+                       }
                }
        }
-       
-       return Rect( Point(arc_extremes[1], arc_extremes[3]) , 
+
+       return Rect( Point(arc_extremes[1], arc_extremes[3]) ,
                             Point(arc_extremes[0], arc_extremes[2]) );
 
 }
 
 
-std::vector<double> 
+std::vector<double>
 EllipticalArc::roots(double v, Dim2 d) const
 {
        if ( d > Y )
        {
                THROW_RANGEERROR("dimention out of range");
        }
-       
+
        std::vector<double> sol;
        if ( are_near(ray(X), 0) && are_near(ray(Y), 0) )
        {
@@ -134,8 +134,8 @@ EllipticalArc::roots(double v, Dim2 d) const
                        sol.push_back(0);
                return sol;
        }
-       
-       const char* msg[2][2] = 
+
+       const char* msg[2][2] =
        {
                { "d == X; ray(X) == 0; "
                  "s = (v - center(X)) / ( -ray(Y) * std::sin(rotation_angle()) ); "
@@ -151,13 +151,13 @@ EllipticalArc::roots(double v, Dim2 d) const
                  "s = (v - center(X)) / ( ray(X) * std::sin(rotation_angle()) ); "
                  "s should be contained in [-1,1]"
                },
-       };        
-       
+       };
+
        for ( unsigned int dim = 0; dim < 2; ++dim )
        {
                if ( are_near(ray(dim), 0) )
                {
-                       
+
                        if ( initialPoint()[d] == v && finalPoint()[d] == v )
                        {
                                THROW_INFINITESOLUTIONS(0);
@@ -175,9 +175,9 @@ EllipticalArc::roots(double v, Dim2 d) const
                        double ray_prj;
                        switch(d)
                        {
-                               case X:         
+                               case X:
                                        switch(dim)
-                                       {       
+                                       {
                                                case X: ray_prj = -ray(Y) * std::sin(rotation_angle());
                                                                break;
                                                case Y: ray_prj = ray(X) * std::cos(rotation_angle());
@@ -186,7 +186,7 @@ EllipticalArc::roots(double v, Dim2 d) const
                                        break;
                                case Y:
                                        switch(dim)
-                                       {       
+                                       {
                                                case X: ray_prj = ray(Y) * std::cos(rotation_angle());
                                                                break;
                                                case Y: ray_prj = ray(X) * std::sin(rotation_angle());
@@ -194,15 +194,15 @@ EllipticalArc::roots(double v, Dim2 d) const
                                        }
                                        break;
                        }
-                       
+
                        double s = (v - center(d)) / ray_prj;
                        if ( s < -1 || s > 1 )
                        {
                                THROW_LOGICALERROR(msg[d][dim]);
                        }
                        switch(dim)
-                       {       
-                               case X: 
+                       {
+                               case X:
                                        s = std::asin(s); // return a value in [-PI/2,PI/2]
                                        if ( logical_xor( sweep_flag(), are_near(start_angle(), M_PI/2) )  )
                                        {
@@ -214,7 +214,7 @@ EllipticalArc::roots(double v, Dim2 d) const
                                                if (!(s < 2*M_PI) ) s -= 2*M_PI;
                                        }
                                        break;
-                               case Y: 
+                               case Y:
                                        s = std::acos(s); // return a value in [0,PI]
                                        if ( logical_xor( sweep_flag(), are_near(start_angle(), 0) ) )
                                        {
@@ -223,7 +223,7 @@ EllipticalArc::roots(double v, Dim2 d) const
                                        }
                                        break;
                        }
-                       
+
                        //std::cerr << "s = " << rad_to_deg(s);
                        s = map_to_01(s);
                        //std::cerr << " -> t: " << s << std::endl;
@@ -232,11 +232,11 @@ EllipticalArc::roots(double v, Dim2 d) const
                        return sol;
                }
        }
-               
+
        double rotx, roty;
        switch(d)
        {
-               case X: 
+               case X:
                        rotx = std::cos(rotation_angle());
                        roty = -std::sin(rotation_angle());
                        break;
@@ -254,7 +254,7 @@ EllipticalArc::roots(double v, Dim2 d) const
        //std::cerr << "a = " << a << std::endl;
        //std::cerr << "b = " << b << std::endl;
        //std::cerr << "c = " << c << std::endl;
-       
+
        if ( are_near(a,0) )
        {
                sol.push_back(M_PI);
@@ -276,7 +276,7 @@ EllipticalArc::roots(double v, Dim2 d) const
                        sol.push_back(s);
                }
                else if ( delta > 0 )
-               {               
+               {
                        double sq = std::sqrt(delta);
                        double s = 2 * std::atan( (-b - sq) / a );
                        if ( s < 0 ) s += 2*M_PI;
@@ -286,7 +286,7 @@ EllipticalArc::roots(double v, Dim2 d) const
                        sol.push_back(s);
                }
        }
-       
+
        std::vector<double> arc_sol;
        for (unsigned int i = 0; i < sol.size(); ++i )
        {
@@ -297,8 +297,8 @@ EllipticalArc::roots(double v, Dim2 d) const
                        arc_sol.push_back(sol[i]);
        }
        return arc_sol;
-       
-       
+
+
 //     return SBasisCurve(toSBasis()).roots(v, d);
 }
 
@@ -320,16 +320,16 @@ Curve* EllipticalArc::derivative() const
        result->m_initial_point = result->pointAtAngle( result->start_angle() );
        result->m_final_point = result->pointAtAngle( result->end_angle() );
        return result;
-       
+
 }
 
-std::vector<Point> 
+std::vector<Point>
 EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const
 {
     unsigned int nn = n+1; // nn represents the size of the result vector.
        std::vector<Point> result;
        result.reserve(nn);
-       double angle = map_unit_interval_on_circular_arc(t, start_angle(), 
+       double angle = map_unit_interval_on_circular_arc(t, start_angle(),
                                                                 end_angle(), sweep_flag());
        EllipticalArc ea(*this);
        ea.m_center = Point(0,0);
@@ -396,21 +396,21 @@ double EllipticalArc::valueAtAngle(Coord t, Dim2 d) const
     double cos_rot_angle = std::cos(rotation_angle());
     if ( d == X )
     {
-        return    ray(X) * cos_rot_angle * std::cos(t) 
-                - ray(Y) * sin_rot_angle * std::sin(t) 
+        return    ray(X) * cos_rot_angle * std::cos(t)
+                - ray(Y) * sin_rot_angle * std::sin(t)
                 + center(X);
     }
     else if ( d == Y )
     {
-        return    ray(X) * sin_rot_angle * std::cos(t) 
-                + ray(Y) * cos_rot_angle * std::sin(t) 
+        return    ray(X) * sin_rot_angle * std::cos(t)
+                + ray(Y) * cos_rot_angle * std::sin(t)
                 + center(Y);
     }
     THROW_RANGEERROR("dimension parameter out of range");
 }
 
 
-Curve* EllipticalArc::portion(double f, double t) const 
+Curve* EllipticalArc::portion(double f, double t) const
 {
        if (f < 0) f = 0;
        if (f > 1) f = 1;
@@ -448,6 +448,11 @@ Curve* EllipticalArc::portion(double f, double t) const
 // NOTE: doesn't work with 360 deg arcs
 void EllipticalArc::calculate_center_and_extreme_angles()
 {
+    // as stated in the svg standard the rotation angle parameter
+    // value must be modulo 2*PI
+    m_rot_angle = std::fmod(m_rot_angle, 2*M_PI);
+    if (m_rot_angle < 0) m_rot_angle += 2*M_PI;
+
     if ( are_near(initialPoint(), finalPoint()) )
     {
        if ( are_near(ray(X), 0) && are_near(ray(Y), 0) )
@@ -512,9 +517,9 @@ void EllipticalArc::calculate_center_and_extreme_angles()
                                "ray(Y) == 0  and distance(initialPoint, finalPoint) < 2*ray(X)"
                        );
                }
-               
+
        }
-       
+
        if ( are_near(ray(X), 0) )
        {
                Point v = initialPoint() - finalPoint();
@@ -561,9 +566,9 @@ void EllipticalArc::calculate_center_and_extreme_angles()
                                "ray(X) == 0  and distance(initialPoint, finalPoint) < 2*ray(Y)"
                        );
                }
-               
+
        }
-       
+
     double sin_rot_angle = std::sin(rotation_angle());
     double cos_rot_angle = std::cos(rotation_angle());
 
@@ -593,7 +598,7 @@ void EllipticalArc::calculate_center_and_extreme_angles()
                                "there is no ellipse that satisfies the given constraints"
                        );
             // assert( -1 < arg && arg < 1 );
-            // if it fails 
+            // if it fails
             // => there is no ellipse that satisfies the given constraints
             half_diff_angle = std::acos( arg );
         }
@@ -604,7 +609,7 @@ void EllipticalArc::calculate_center_and_extreme_angles()
     {
         double  arg = sol[Y] / ( 2 * std::cos(half_sum_angle) );
         // if |arg| is a little bit > 1 asin returns nan
-        if ( are_near(arg, 1) ) 
+        if ( are_near(arg, 1) )
             half_diff_angle = M_PI/2;
         else if ( are_near(arg, -1) )
             half_diff_angle = -M_PI/2;
@@ -615,20 +620,20 @@ void EllipticalArc::calculate_center_and_extreme_angles()
                                "there is no ellipse that satisfies the given constraints"
                        );
             // assert( -1 < arg && arg < 1 );
-            // if it fails 
+            // if it fails
             // => there is no ellipse that satisfies the given constraints
             half_diff_angle = std::asin( arg );
         }
     }
 
-    if (   ( m_large_arc && half_diff_angle > 0 ) 
+    if (   ( m_large_arc && half_diff_angle > 0 )
         || (!m_large_arc && half_diff_angle < 0 ) )
     {
         half_diff_angle = -half_diff_angle;
     }
     if ( half_sum_angle < 0 ) half_sum_angle += 2*M_PI;
     if ( half_diff_angle < 0 ) half_diff_angle += M_PI;
-    
+
     m_start_angle = half_sum_angle - half_diff_angle;
     m_end_angle =  half_sum_angle + half_diff_angle;
     // 0 <= m_start_angle, m_end_angle < 2PI
@@ -662,9 +667,9 @@ Coord EllipticalArc::map_to_02PI(Coord t) const
     }
 }
 
-Coord EllipticalArc::map_to_01(Coord angle) const 
+Coord EllipticalArc::map_to_01(Coord angle) const
 {
-       return map_circular_arc_on_unit_interval(angle, start_angle(), 
+       return map_circular_arc_on_unit_interval(angle, start_angle(),
                                                         end_angle(), sweep_flag());
 }
 
@@ -689,7 +694,7 @@ allNearestPoints( Point const& p, double from, double to ) const
                Point np = seg.pointAt( seg.nearestPoint(p) );
                if ( are_near(ray(Y), 0) )
                {
-                       if ( are_near(rotation_angle(), M_PI/2) 
+                       if ( are_near(rotation_angle(), M_PI/2)
                                 || are_near(rotation_angle(), 3*M_PI/2) )
                        {
                                result = roots(np[Y], Y);
@@ -701,7 +706,7 @@ allNearestPoints( Point const& p, double from, double to ) const
                }
                else
                {
-                       if ( are_near(rotation_angle(), M_PI/2) 
+                       if ( are_near(rotation_angle(), M_PI/2)
                                 || are_near(rotation_angle(), 3*M_PI/2) )
                        {
                                result = roots(np[X], X);
@@ -739,22 +744,22 @@ allNearestPoints( Point const& p, double from, double to ) const
 //             }
 //             else
 //             {
-//                     
+//
 //             }
        }
-       
+
        // solve the equation <D(E(t),t)|E(t)-p> == 0
-       // that provides min and max distance points 
+       // that provides min and max distance points
        // on the ellipse E wrt the point p
-       // after the substitutions: 
+       // after the substitutions:
        // cos(t) = (1 - s^2) / (1 + s^2)
        // sin(t) = 2t / (1 + s^2)
        // where s = tan(t/2)
        // we get a 4th degree equation in s
        /*
-        *      ry s^4 ((-cy + py) Cos[Phi] + (cx - px) Sin[Phi]) + 
-        *      ry ((cy - py) Cos[Phi] + (-cx + px) Sin[Phi]) + 
-        *      2 s^3 (rx^2 - ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) + 
+        *      ry s^4 ((-cy + py) Cos[Phi] + (cx - px) Sin[Phi]) +
+        *      ry ((cy - py) Cos[Phi] + (-cx + px) Sin[Phi]) +
+        *      2 s^3 (rx^2 - ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) +
         *      2 s (-rx^2 + ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi])
         */
 
@@ -770,14 +775,14 @@ allNearestPoints( Point const& p, double from, double to ) const
        coeff[2] = 0;
        coeff[1] = 2 * ( -rx2_ry2 + expr1 );
        coeff[0] = -coeff[4];
-       
+
 //     for ( unsigned int i = 0; i < 5; ++i )
 //             std::cerr << "c[" << i << "] = " << coeff[i] << std::endl;
-       
+
        std::vector<double> real_sol;
-       // gsl_poly_complex_solve raises an error 
+       // gsl_poly_complex_solve raises an error
        // if the leading coefficient is zero
-       if ( are_near(coeff[4], 0) )  
+       if ( are_near(coeff[4], 0) )
        {
                real_sol.push_back(0);
                if ( !are_near(coeff[3], 0) )
@@ -801,13 +806,13 @@ allNearestPoints( Point const& p, double from, double to ) const
 //             gsl_poly_complex_workspace * w = gsl_poly_complex_workspace_alloc(5);
 //             gsl_poly_complex_solve(coeff, 5, w, sol );
 //             gsl_poly_complex_workspace_free(w);
-//             
+//
 //             for ( unsigned int i = 0; i < 4; ++i )
 //             {
 //                     if ( sol[2*i+1] == 0 ) real_sol.push_back(sol[2*i]);
 //             }
 //     }
-               
+
        for ( unsigned int i = 0; i < real_sol.size(); ++i )
        {
                real_sol[i] = 2 * std::atan(real_sol[i]);
@@ -819,7 +824,7 @@ allNearestPoints( Point const& p, double from, double to ) const
        {
                real_sol.push_back(M_PI);
        }
-       
+
        double mindistsq1 = std::numeric_limits<double>::max();
        double mindistsq2 = std::numeric_limits<double>::max();
        double dsq;
@@ -840,14 +845,14 @@ allNearestPoints( Point const& p, double from, double to ) const
                        mi2 = i;
                }
        }
-       
+
        double t = map_to_01( real_sol[mi1] );
        if ( !(t < from || t > to) )
        {
                result.push_back(t);
        }
-       
-       bool second_sol = false; 
+
+       bool second_sol = false;
        t = map_to_01( real_sol[mi2] );
        if ( real_sol.size() == 4 && !(t < from || t > to) )
        {
@@ -857,7 +862,7 @@ allNearestPoints( Point const& p, double from, double to ) const
                second_sol = true;
        }
        }
-       
+
        // we need to test extreme points too
        double dsq1 = distanceSq(p, pointAt(from));
        double dsq2 = distanceSq(p, pointAt(to));
@@ -882,7 +887,7 @@ allNearestPoints( Point const& p, double from, double to ) const
                {
                        result.push_back(to);
                }
-               
+
        }
        else
        {
@@ -903,7 +908,7 @@ allNearestPoints( Point const& p, double from, double to ) const
                        }
                }
        }
-       
+
        return result;
 }
 
index 64bf21ee6b4b20bd48dce366d4db0ddbbe2c6e8e..2cbd84a4afce61b55772c79acdaebdac9e4d43e3 100644 (file)
@@ -50,7 +50,7 @@ namespace Geom {
  * x = (fb - ce)/(bd - ae)                \endverbatim
  *
  * If the denominator (bd-ae) is 0 then the lines are parallel, if the
- * numerators are then 0 then the lines coincide.
+ * numerators are 0 then the lines coincide.
  *
  * \todo Why not use existing but outcommented code below
  * (HAVE_NEW_INTERSECTOR_CODE)?
@@ -110,26 +110,64 @@ intersector_ccw(const Geom::Point& p0, const Geom::Point& p1,
     }
 }
 
+/** Determine whether the line segment from p00 to p01 intersects the
+    infinite line passing through p10 and p11. This doesn't find the
+    point of intersection, use the line_intersect function above,
+    or the segment_intersection interface below.
+
+    \pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
+*/
+bool
+line_segment_intersectp(Geom::Point const &p00, Geom::Point const &p01,
+                        Geom::Point const &p10, Geom::Point const &p11)
+{
+    if(p00 == p01) return false;
+    if(p10 == p11) return false;
+
+    return ((intersector_ccw(p00, p01, p10) * intersector_ccw(p00, p01, p11)) <= 0 );
+}
+
+
 /** Determine whether two line segments intersect.  This doesn't find
     the point of intersection, use the line_intersect function above,
     or the segment_intersection interface below.
 
     \pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
 */
-static bool
+bool
 segment_intersectp(Geom::Point const &p00, Geom::Point const &p01,
-                               Geom::Point const &p10, Geom::Point const &p11)
+                   Geom::Point const &p10, Geom::Point const &p11)
 {
     if(p00 == p01) return false;
     if(p10 == p11) return false;
 
     /* true iff (    (the p1 segment straddles the p0 infinite line)
      *           and (the p0 segment straddles the p1 infinite line) ). */
-    return ((intersector_ccw(p00,p01, p10)
-             *intersector_ccw(p00, p01, p11)) <=0 )
-        &&
-        ((intersector_ccw(p10,p11, p00)
-          *intersector_ccw(p10, p11, p01)) <=0 );
+    return (line_segment_intersectp(p00, p01, p10, p11) &&
+            line_segment_intersectp(p10, p11, p00, p01));
+}
+
+/** Determine whether \& where a line segments intersects an (infinite) line.
+
+If there is no intersection, then \a result remains unchanged.
+
+\pre neither segment is zero-length; i.e. p00 != p01 and p10 != p11.
+**/
+IntersectorKind
+line_segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
+                       Geom::Point const &p10, Geom::Point const &p11,
+                       Geom::Point &result)
+{
+    if(line_segment_intersectp(p00, p01, p10, p11)) {
+        Geom::Point n0 = (p01 - p00).ccw();
+        double d0 = dot(n0,p00);
+
+        Geom::Point n1 = (p11 - p10).ccw();
+        double d1 = dot(n1,p10);
+        return line_intersection(n0, d0, n1, d1, result);
+    } else {
+        return no_intersection;
+    }
 }
 
 
@@ -141,8 +179,8 @@ If the two segments don't intersect, then \a result remains unchanged.
 **/
 IntersectorKind
 segment_intersect(Geom::Point const &p00, Geom::Point const &p01,
-                              Geom::Point const &p10, Geom::Point const &p11,
-                              Geom::Point &result)
+                  Geom::Point const &p10, Geom::Point const &p11,
+                  Geom::Point &result)
 {
     if(segment_intersectp(p00, p01, p10, p11)) {
         Geom::Point n0 = (p01 - p00).ccw();
@@ -175,6 +213,105 @@ line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01,
     return line_intersection(n0, d0, n1, d1, result);
 }
 
+// this is used to compare points for std::sort below
+static bool
+is_less(Point const &A, Point const &B)
+{
+    if (A[X] < B[X]) {
+        return true;
+    } else if (A[X] == B[X] && A[Y] < B[Y]) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// TODO: this can doubtlessly be improved
+static void
+eliminate_duplicates_p(std::vector<Point> &pts)
+{
+    unsigned int size = pts.size();
+
+    if (size < 2)
+        return;
+
+    if (size == 2) {
+        if (pts[0] == pts[1]) {
+            pts.pop_back();
+        }
+    } else {
+        std::sort(pts.begin(), pts.end(), &is_less);
+        if (size == 3) {
+            if (pts[0] == pts[1]) {
+                pts.erase(pts.begin());
+            } else if (pts[1] == pts[2]) {
+                pts.pop_back();
+            }
+        } else {
+            // we have size == 4
+            if (pts[2] == pts[3]) {
+                pts.pop_back();
+            }
+            if (pts[0] == pts[1]) {
+                pts.erase(pts.begin());
+            }
+        }
+    }
+}
+
+/** Determine whether \& where an (infinite) line intersects a rectangle.
+ *
+ * \a c0, \a c1 are diagonal corners of the rectangle and
+ * \a p1, \a p1 are distinct points on the line
+ *
+ * \return A list (possibly empty) of points of intersection.  If two such points (say \a r0 and \a
+ * r1) then it is guaranteed that the order of \a r0, \a r1 along the line is the same as the that
+ * of \a c0, \a c1 (i.e., the vectors \a r1 - \a r0 and \a p1 - \a p0 point into the same
+ * direction).
+ */
+std::vector<Geom::Point>
+rect_line_intersect(Geom::Point const &c0, Geom::Point const &c1,
+                    Geom::Point const &p0, Geom::Point const &p1)
+{
+    using namespace Geom;
+
+    std::vector<Point> results;
+
+    Point A(c0);
+    Point C(c1);
+
+    Point B(A[X], C[Y]);
+    Point D(C[X], A[Y]);
+
+    Point res;
+
+    if (line_segment_intersect(p0, p1, A, B, res) == intersects) {
+        results.push_back(res);
+    }
+    if (line_segment_intersect(p0, p1, B, C, res) == intersects) {
+        results.push_back(res);
+    }
+    if (line_segment_intersect(p0, p1, C, D, res) == intersects) {
+        results.push_back(res);
+    }
+    if (line_segment_intersect(p0, p1, D, A, res) == intersects) {
+        results.push_back(res);
+    }
+
+    eliminate_duplicates_p(results);
+
+    if (results.size() == 2) {
+        // sort the results so that the order is the same as that of p0 and p1
+        Point dir1 (results[1] - results[0]);
+        Point dir2 (p1 - p0);
+        if (dot(dir1, dir2) < 0) {
+            std::swap(results[0], results[1]);
+        }
+    }
+
+    return results;
+}
+
 /**
  * polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon, given its
  * vertices (x[0], y[0]) ... (x[n-1], y[n-1]). It is assumed that the contour is closed, i.e., that
index 207d609b09b8568c888d0966e6a16b9b722680a5..1a40c04e184d52ae73194c7f336e7d8350a6501c 100644 (file)
@@ -69,6 +69,10 @@ line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01,
                        Geom::Point const &p10, Geom::Point const &p11,
                        Geom::Point &result);
 
+std::vector<Geom::Point>
+rect_line_intersect(Geom::Point const &E, Geom::Point const &F,
+                    Geom::Point const &p0, Geom::Point const &p1);
+
 int centroid(std::vector<Geom::Point> p, Geom::Point& centroid, double &area);
 
 }
index 2094c4beb501c13879a89562b8fb58b873491b88..73dc3da8bbd48b1c2c2614f8936409f055da4bfc 100644 (file)
@@ -50,6 +50,11 @@ std::vector<double> path_mono_splits(Path const &p);
 CrossingSet crossings_among(std::vector<Path> const & p);
 Crossings self_crossings(Path const & a);
 
+inline Crossings crossings(Curve const & a, Curve const & b) {
+    DefaultCrosser c = DefaultCrosser();
+    return c.crossings(a, b);
+}
+
 inline Crossings crossings(Path const & a, Path const & b) {
     DefaultCrosser c = DefaultCrosser();
     return c.crossings(a, b);
index 2943d6a9279142aec5dfe8ba73ae8678a51ddf30..ac45459bd419779d07b6037ad5eac3ee40f76989 100644 (file)
@@ -198,6 +198,20 @@ Path::allNearestPoints(Point const& _point, double from, double to) const
        return all_nearest;
 }
 
+std::vector<double>
+Path::nearestPointPerCurve(Point const& _point) const
+{
+       //return a single nearest point for each curve in this path
+       std::vector<double> np;
+       const Path& _path = *this;
+       for (Sequence::const_iterator it = _path.get_curves().begin() ; it != _path.get_curves().end()-1 ; ++it)
+       //for (std::vector<Path>::const_iterator it = _path.begin(); it != _path.end(), ++it){
+       {
+           np.push_back((*it)->nearestPoint(_point));
+    }
+       return np;
+}  
+
 double Path::nearestPoint(Point const &_point, double from, double to, double *distance_squared) const
 {
        if ( from > to ) std::swap(from, to);
index f4aa560ff6c1e73b4d7f0497889012b6918b4631..97c4ce2bdfbb9aa43d3e70ef1cb4a88273f923be 100644 (file)
@@ -254,7 +254,7 @@ public:
 
   size_type max_size() const { return get_curves().max_size()-1; }
 
-  bool empty() const { return get_curves().size() == 1; }
+  bool empty() const { return closed() || (get_curves().size() == 1); }
   bool closed() const { return closed_; }
   void close(bool closed=true) { closed_ = closed; }
 
@@ -363,6 +363,8 @@ public:
          return allNearestPoints(_point, 0, sz);
   }
   
+  std::vector<double>
+  nearestPointPerCurve(Point const& _point) const;  
   
   double nearestPoint(Point const& _point, double from, double to, double *distance_squared = NULL) const;
   
index 23843c52dfeb7c74fc4f099f520a208e98a04fc2..cec1c144a0ebcff0e3f1e3b6e162b6ebc0dbfd13 100644 (file)
@@ -87,6 +87,17 @@ PathVector operator+(PathVector const &path_in, Point const &p) {
     return ret;
 }
 
+inline
+Geom::Point initialPoint(PathVector const &path_in)
+{
+    return path_in.front().initialPoint();
+}
+
+inline
+Geom::Point finalPoint(PathVector const &path_in)
+{
+    return path_in.back().finalPoint();
+}
 
 PathVector reverse_paths_and_order (PathVector const & path_in);
 
index cdf60bc9fdc1d6a8180272056c4ab6e11b843002..5ae92097e9c2ac22ab8449e3f98415dc249dec51 100644 (file)
@@ -943,19 +943,18 @@ Curve* SVGEllipticalArc::transformed(Matrix const& m) const
 
 Coord SVGEllipticalArc::map_to_02PI(Coord t) const
 {
+    Coord angle = start_angle();
     if ( sweep_flag() )
     {
-        Coord angle = start_angle() + sweep_angle() * t;
-        if ( !(angle < 2*M_PI) )
-            angle -= 2*M_PI;
-        return angle;
+        angle += sweep_angle() * t;
     }
     else
     {
-        Coord angle = start_angle() - sweep_angle() * t;
-        if ( angle < 0 ) angle += 2*M_PI;
-        return angle;
+        angle -= sweep_angle() * t;
     }
+    angle = std::fmod(angle, 2*M_PI);
+    if ( angle < 0 ) angle += 2*M_PI;
+    return angle;
 }
 
 Coord SVGEllipticalArc::map_to_01(Coord angle) const