From: dvlierop2 Date: Fri, 15 Aug 2008 20:23:54 +0000 (+0000) Subject: Update to 2geom rev. 1538 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=fc69b99d41121cdaab54d55eb2efe2dc3c6ac358;p=inkscape.git Update to 2geom rev. 1538 --- diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index e94c5c673..cd2f4a712 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -1,42 +1,167 @@ -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) diff --git a/src/2geom/angle.h b/src/2geom/angle.h index e95300a17..621235a5e 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -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; } diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index 552cdf5b3..bf2b72b63 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -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::vectorarc_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 +std::vector EllipticalArc::roots(double v, Dim2 d) const { if ( d > Y ) { THROW_RANGEERROR("dimention out of range"); } - + std::vector 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 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 +std::vector EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const { unsigned int nn = n+1; // nn represents the size of the result vector. std::vector 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 == 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 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::max(); double mindistsq2 = std::numeric_limits::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; } diff --git a/src/2geom/geom.cpp b/src/2geom/geom.cpp index 64bf21ee6..2cbd84a4a 100644 --- a/src/2geom/geom.cpp +++ b/src/2geom/geom.cpp @@ -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 &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 +rect_line_intersect(Geom::Point const &c0, Geom::Point const &c1, + Geom::Point const &p0, Geom::Point const &p1) +{ + using namespace Geom; + + std::vector 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 diff --git a/src/2geom/geom.h b/src/2geom/geom.h index 207d609b0..1a40c04e1 100644 --- a/src/2geom/geom.h +++ b/src/2geom/geom.h @@ -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 +rect_line_intersect(Geom::Point const &E, Geom::Point const &F, + Geom::Point const &p0, Geom::Point const &p1); + int centroid(std::vector p, Geom::Point& centroid, double &area); } diff --git a/src/2geom/path-intersection.h b/src/2geom/path-intersection.h index 2094c4beb..73dc3da8b 100644 --- a/src/2geom/path-intersection.h +++ b/src/2geom/path-intersection.h @@ -50,6 +50,11 @@ std::vector path_mono_splits(Path const &p); CrossingSet crossings_among(std::vector 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); diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 2943d6a92..ac45459bd 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -198,6 +198,20 @@ Path::allNearestPoints(Point const& _point, double from, double to) const return all_nearest; } +std::vector +Path::nearestPointPerCurve(Point const& _point) const +{ + //return a single nearest point for each curve in this path + std::vector np; + const Path& _path = *this; + for (Sequence::const_iterator it = _path.get_curves().begin() ; it != _path.get_curves().end()-1 ; ++it) + //for (std::vector::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); diff --git a/src/2geom/path.h b/src/2geom/path.h index f4aa560ff..97c4ce2bd 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -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 + nearestPointPerCurve(Point const& _point) const; double nearestPoint(Point const& _point, double from, double to, double *distance_squared = NULL) const; diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 23843c52d..cec1c144a 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -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); diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/svg-elliptical-arc.cpp index cdf60bc9f..5ae92097e 100644 --- a/src/2geom/svg-elliptical-arc.cpp +++ b/src/2geom/svg-elliptical-arc.cpp @@ -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