@@ -2106,38 +2106,49 @@ static bool can_approximate_bezier_curve(FloatPoint p1, FloatPoint p2, FloatPoin
2106
2106
return error <= tolerance;
2107
2107
}
2108
2108
2109
+ static float approximate_bezier_curve_length (FloatPoint control_point, FloatPoint p1, FloatPoint p2)
2110
+ {
2111
+ return p1.distance_from (control_point) + control_point.distance_from (p2);
2112
+ }
2113
+
2109
2114
// static
2110
2115
void Painter::for_each_line_segment_on_bezier_curve (FloatPoint control_point, FloatPoint p1, FloatPoint p2, Function<void (FloatPoint, FloatPoint)>& callback)
2111
2116
{
2112
2117
struct SegmentDescriptor {
2113
2118
FloatPoint control_point;
2114
2119
FloatPoint p1;
2115
2120
FloatPoint p2;
2116
- };
2121
+ int depth { 0 };
2117
2122
2118
- static constexpr auto split_quadratic_bezier_curve = [](FloatPoint original_control, FloatPoint p1, FloatPoint p2, auto & segments) {
2119
- auto po1_midpoint = original_control + p1;
2120
- po1_midpoint /= 2 ;
2123
+ void split (Vector<SegmentDescriptor>& segments)
2124
+ {
2125
+ auto po1_midpoint = control_point + p1;
2126
+ po1_midpoint /= 2 ;
2121
2127
2122
- auto po2_midpoint = original_control + p2;
2123
- po2_midpoint /= 2 ;
2128
+ auto po2_midpoint = control_point + p2;
2129
+ po2_midpoint /= 2 ;
2124
2130
2125
- auto new_segment = po1_midpoint + po2_midpoint;
2126
- new_segment /= 2 ;
2131
+ auto new_segment = po1_midpoint + po2_midpoint;
2132
+ new_segment /= 2 ;
2127
2133
2128
- segments.append ({ po2_midpoint, new_segment, p2 });
2129
- segments.append ({ po1_midpoint, p1, new_segment });
2134
+ segments.append ({ po2_midpoint, new_segment, p2, depth + 1 });
2135
+ segments.append ({ po1_midpoint, p1, new_segment, depth + 1 });
2136
+ }
2130
2137
};
2131
2138
2139
+ // Limit splitting to the point where curves are approximately half a pixel in length.
2140
+ int max_split_depth = ceilf (log2 (approximate_bezier_curve_length (control_point, p1, p2))) + 1 ;
2141
+
2132
2142
Vector<SegmentDescriptor> segments;
2133
2143
segments.append ({ control_point, p1, p2 });
2134
2144
while (!segments.is_empty ()) {
2135
2145
auto segment = segments.take_last ();
2136
2146
2137
- if (can_approximate_bezier_curve (segment.p1 , segment.p2 , segment.control_point ))
2147
+ if (segment.depth >= max_split_depth
2148
+ || can_approximate_bezier_curve (segment.p1 , segment.p2 , segment.control_point ))
2138
2149
callback (segment.p1 , segment.p2 );
2139
2150
else
2140
- split_quadratic_bezier_curve ( segment.control_point , segment. p1 , segment. p2 , segments);
2151
+ segment.split ( segments);
2141
2152
}
2142
2153
}
2143
2154
@@ -2184,6 +2195,11 @@ static bool can_approximate_cubic_bezier_curve(FloatPoint p1, FloatPoint p2, Flo
2184
2195
return error <= tolerance;
2185
2196
}
2186
2197
2198
+ static float approximate_cubic_bezier_curve_length (FloatPoint control_point_0, FloatPoint control_point_1, FloatPoint p1, FloatPoint p2)
2199
+ {
2200
+ return p1.distance_from (control_point_0) + control_point_0.distance_from (control_point_1) + control_point_1.distance_from (p2);
2201
+ }
2202
+
2187
2203
// static
2188
2204
void Painter::for_each_line_segment_on_cubic_bezier_curve (FloatPoint control_point_0, FloatPoint control_point_1, FloatPoint p1, FloatPoint p2, Function<void (FloatPoint, FloatPoint)>& callback)
2189
2205
{
@@ -2195,33 +2211,38 @@ void Painter::for_each_line_segment_on_cubic_bezier_curve(FloatPoint control_poi
2195
2211
ControlPair control_points;
2196
2212
FloatPoint p1;
2197
2213
FloatPoint p2;
2198
- };
2214
+ int depth { 0 };
2199
2215
2200
- static constexpr auto split_cubic_bezier_curve = [](ControlPair const & original_controls, FloatPoint p1, FloatPoint p2, auto & segments) {
2201
- Array level_1_midpoints {
2202
- (p1 + original_controls.control_point_0 ) / 2 ,
2203
- (original_controls.control_point_0 + original_controls.control_point_1 ) / 2 ,
2204
- (original_controls.control_point_1 + p2) / 2 ,
2205
- };
2206
- Array level_2_midpoints {
2207
- (level_1_midpoints[0 ] + level_1_midpoints[1 ]) / 2 ,
2208
- (level_1_midpoints[1 ] + level_1_midpoints[2 ]) / 2 ,
2209
- };
2210
- auto level_3_midpoint = (level_2_midpoints[0 ] + level_2_midpoints[1 ]) / 2 ;
2211
-
2212
- segments.append ({ { level_2_midpoints[1 ], level_1_midpoints[2 ] }, level_3_midpoint, p2 });
2213
- segments.append ({ { level_1_midpoints[0 ], level_2_midpoints[0 ] }, p1, level_3_midpoint });
2216
+ void split (Vector<SegmentDescriptor>& segments)
2217
+ {
2218
+ Array level_1_midpoints {
2219
+ (p1 + control_points.control_point_0 ) / 2 ,
2220
+ (control_points.control_point_0 + control_points.control_point_1 ) / 2 ,
2221
+ (control_points.control_point_1 + p2) / 2 ,
2222
+ };
2223
+ Array level_2_midpoints {
2224
+ (level_1_midpoints[0 ] + level_1_midpoints[1 ]) / 2 ,
2225
+ (level_1_midpoints[1 ] + level_1_midpoints[2 ]) / 2 ,
2226
+ };
2227
+ auto level_3_midpoint = (level_2_midpoints[0 ] + level_2_midpoints[1 ]) / 2 ;
2228
+
2229
+ segments.append ({ { level_2_midpoints[1 ], level_1_midpoints[2 ] }, level_3_midpoint, p2, depth + 1 });
2230
+ segments.append ({ { level_1_midpoints[0 ], level_2_midpoints[0 ] }, p1, level_3_midpoint, depth + 1 });
2231
+ }
2214
2232
};
2215
2233
2234
+ // Limit splitting to the point where curves are approximately half a pixel in length.
2235
+ int max_split_depth = ceilf (log2 (approximate_cubic_bezier_curve_length (control_point_0, control_point_1, p1, p2))) + 1 ;
2236
+
2216
2237
Vector<SegmentDescriptor> segments;
2217
2238
segments.append ({ { control_point_0, control_point_1 }, p1, p2 });
2218
2239
while (!segments.is_empty ()) {
2219
2240
auto segment = segments.take_last ();
2220
-
2221
- if ( can_approximate_cubic_bezier_curve (segment.p1 , segment.p2 , segment.control_points .control_point_0 , segment.control_points .control_point_1 ))
2241
+ if (segment. depth >= max_split_depth
2242
+ || can_approximate_cubic_bezier_curve (segment.p1 , segment.p2 , segment.control_points .control_point_0 , segment.control_points .control_point_1 ))
2222
2243
callback (segment.p1 , segment.p2 );
2223
2244
else
2224
- split_cubic_bezier_curve ( segment.control_points , segment. p1 , segment. p2 , segments);
2245
+ segment.split ( segments);
2225
2246
}
2226
2247
}
2227
2248
0 commit comments