summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 3545be7)
raw | patch | inline | side by side (parent: 3545be7)
author | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Fri, 15 Aug 2008 20:23:54 +0000 (20:23 +0000) | ||
committer | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Fri, 15 Aug 2008 20:23:54 +0000 (20:23 +0000) |
index e94c5c673443bd3e3d74dc9bf3de240ed15cb057..cd2f4a71282bde000de5969bb94d27c725de881f 100644 (file)
--- a/src/2geom/CMakeLists.txt
+++ b/src/2geom/CMakeLists.txt
-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 e95300a174f6dc87575c569af654619b8006a370..621235a5ec7496243be5c042d14afe60f9cce6d5 100644 (file)
--- a/src/2geom/angle.h
+++ b/src/2geom/angle.h
* 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)
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() )
{
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) )
{
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()) ); "
"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);
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());
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());
}
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) ) )
{
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) ) )
{
}
break;
}
-
+
//std::cerr << "s = " << rad_to_deg(s);
s = map_to_01(s);
//std::cerr << " -> t: " << s << std::endl;
return sol;
}
}
-
+
double rotx, roty;
switch(d)
{
- case X:
+ case X:
rotx = std::cos(rotation_angle());
roty = -std::sin(rotation_angle());
break;
//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);
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;
sol.push_back(s);
}
}
-
+
std::vector<double> arc_sol;
for (unsigned int i = 0; i < sol.size(); ++i )
{
arc_sol.push_back(sol[i]);
}
return arc_sol;
-
-
+
+
// return SBasisCurve(toSBasis()).roots(v, d);
}
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);
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;
// 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) )
"ray(Y) == 0 and distance(initialPoint, finalPoint) < 2*ray(X)"
);
}
-
+
}
-
+
if ( are_near(ray(X), 0) )
{
Point v = initialPoint() - finalPoint();
"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());
"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 );
}
{
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;
"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
}
}
-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());
}
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);
}
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);
// }
// 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])
*/
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) )
// 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]);
{
real_sol.push_back(M_PI);
}
-
+
double mindistsq1 = std::numeric_limits<double>::max();
double mindistsq2 = std::numeric_limits<double>::max();
double dsq;
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) )
{
second_sol = true;
}
}
-
+
// we need to test extreme points too
double dsq1 = distanceSq(p, pointAt(from));
double dsq2 = distanceSq(p, pointAt(to));
{
result.push_back(to);
}
-
+
}
else
{
}
}
}
-
+
return result;
}
diff --git a/src/2geom/geom.cpp b/src/2geom/geom.cpp
index 64bf21ee6b4b20bd48dce366d4db0ddbbe2c6e8e..2cbd84a4afce61b55772c79acdaebdac9e4d43e3 100644 (file)
--- a/src/2geom/geom.cpp
+++ b/src/2geom/geom.cpp
* 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)?
}
}
+/** 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;
+ }
}
**/
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();
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
diff --git a/src/2geom/geom.h b/src/2geom/geom.h
index 207d609b09b8568c888d0966e6a16b9b722680a5..1a40c04e184d52ae73194c7f336e7d8350a6501c 100644 (file)
--- a/src/2geom/geom.h
+++ b/src/2geom/geom.h
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)
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);
diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp
index 2943d6a9279142aec5dfe8ba73ae8678a51ddf30..ac45459bd419779d07b6037ad5eac3ee40f76989 100644 (file)
--- a/src/2geom/path.cpp
+++ b/src/2geom/path.cpp
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);
diff --git a/src/2geom/path.h b/src/2geom/path.h
index f4aa560ff6c1e73b4d7f0497889012b6918b4631..97c4ce2bdfbb9aa43d3e70ef1cb4a88273f923be 100644 (file)
--- a/src/2geom/path.h
+++ b/src/2geom/path.h
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; }
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;
diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h
index 23843c52dfeb7c74fc4f099f520a208e98a04fc2..cec1c144a0ebcff0e3f1e3b6e162b6ebc0dbfd13 100644 (file)
--- a/src/2geom/pathvector.h
+++ b/src/2geom/pathvector.h
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)
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