aboutsummaryrefslogtreecommitdiff
path: root/svg-flatten/src/flatten.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'svg-flatten/src/flatten.cpp')
-rw-r--r--svg-flatten/src/flatten.cpp102
1 files changed, 101 insertions, 1 deletions
diff --git a/svg-flatten/src/flatten.cpp b/svg-flatten/src/flatten.cpp
index cb7f427..81a240e 100644
--- a/svg-flatten/src/flatten.cpp
+++ b/svg-flatten/src/flatten.cpp
@@ -19,7 +19,107 @@ static inline double calc_sq_distance(double x1, double y1, double x2, double y2
return dx * dx + dy * dy;
}
-void curve4_div::run(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
+/* Quadratic beziers */
+
+void curve3_div::run(double x1, double y1, double x2, double y2, double x3, double y3)
+{
+ m_points.clear();
+ m_points.emplace_back(d2p{x1, y1});
+ recursive_bezier(x1, y1, x2, y2, x3, y3, 0);
+ m_points.emplace_back(d2p{x3, y3});
+}
+
+void curve3_div::recursive_bezier(double x1, double y1, double x2, double y2, double x3, double y3, unsigned level)
+{
+ if(level > curve_recursion_limit)
+ {
+ return;
+ }
+
+ // Calculate all the mid-points of the line segments
+ //----------------------
+ double x12 = (x1 + x2) / 2;
+ double y12 = (y1 + y2) / 2;
+ double x23 = (x2 + x3) / 2;
+ double y23 = (y2 + y3) / 2;
+ double x123 = (x12 + x23) / 2;
+ double y123 = (y12 + y23) / 2;
+
+ double dx = x3-x1;
+ double dy = y3-y1;
+ double d = fabs(((x2 - x3) * dy - (y2 - y3) * dx));
+ double da;
+ double pi = M_PI;
+
+ if(d > curve_collinearity_epsilon)
+ {
+ // Regular case
+ //-----------------
+ if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy))
+ {
+ // If the curvature doesn't exceed the distance_tolerance value
+ // we tend to finish subdivisions.
+ //----------------------
+ if(m_angle_tolerance < curve_angle_tolerance_epsilon)
+ {
+ m_points.emplace_back(d2p{x123, y123});
+ return;
+ }
+
+ // Angle & Cusp Condition
+ //----------------------
+ da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1));
+ if(da >= pi) da = 2*pi - da;
+
+ if(da < m_angle_tolerance)
+ {
+ // Finally we can stop the recursion
+ //----------------------
+ m_points.emplace_back(d2p{x123, y123});
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Collinear case
+ //------------------
+ da = dx*dx + dy*dy;
+ if(da == 0)
+ {
+ d = calc_sq_distance(x1, y1, x2, y2);
+ }
+ else
+ {
+ d = ((x2 - x1)*dx + (y2 - y1)*dy) / da;
+ if(d > 0 && d < 1)
+ {
+ // Simple collinear case, 1---2---3
+ // We can leave just two endpoints
+ return;
+ }
+ if(d <= 0) d = calc_sq_distance(x2, y2, x1, y1);
+ else if(d >= 1) d = calc_sq_distance(x2, y2, x3, y3);
+ else d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy);
+ }
+ if(d < m_distance_tolerance_square)
+ {
+ m_points.emplace_back(d2p{x2, y2});
+ return;
+ }
+ }
+
+ // Continue subdivision
+ //----------------------
+ recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1);
+ recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1);
+}
+
+
+/* Cubic beziers */
+
+void curve4_div::run(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+{
m_points.clear();
m_points.emplace_back(d2p{x1, y1});
recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0);