-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decompose splines with t flexibly updated #31
Conversation
Replace "See also: #2" with "Close #2" in the git commit message, so that this issue can be closed automatically once this pull request is merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although this approach requires more computation to decompose the
spline into fewer segments, the extra effort is justified for improved
fit.
You can include statistical data such as mean, standard deviation, etc., in the PR and present it simply in the commit. Remember to mention the number of observations used.
original - Average number of _de_casteljau calls per point: 1.99 |
Refine the git commit messages upon your experiments. |
FYI: vector-graphics/src/bezier.h is an interesting implementation. |
b2244c9
to
c782f22
Compare
Google's skia performs subdivision using de Casteljau's algorithm, that is, repeated linear interpolation between adjacent points. See src/base/SkBezierCurves.cpp. |
0f223a0
to
ad161ac
Compare
Assess the appropriate values for tolerance when rendering B´ezier Curve. The following images show the effect of four settings on 56 fonts, which are rendered using curves. Only these fonts are used to calculate the average number of _de_casteljau calls per point and the average points per character. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squash the git commits. A single and informative one is preferable.
@@ -91,16 +92,19 @@ static void _twin_spline_decompose(twin_path_t *path, | |||
{ | |||
/* Draw starting point */ | |||
_twin_path_sdraw(path, spline->a.x, spline->a.y); | |||
|
|||
int shift = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comments.
The previous method for decomposing a spline into fewer segments aimed to identify the optimal value of 't', which corresponds to the location of maximum curvature on the curve. However, using a bisection method to locate this point increases the average number of '_de_casteljau' calls per point, as demonstrated in Experiment 2. Even with the early stopping method applied, the improvement is little. Moreover, given the high cost of finding points with the bisection method, we have decided to abandon the flexible update of 't' using bisection. Therefore, we can reduce computation cost by only using shift operation to determine the coefficients of lerp in the '_de_casteljau' function. Based on the previous experiments, we have identified that the primary issue is the necessity to call the '_de_casteljau' function twice to generate a point, even under the original settings. On average, the number of _de_casteljau calls per point is 1.99. Ideally, we want the rendering process to call the '_de_casteljau' function only once for each point in every iteration, indicating that the first call is redundant. Also, we've observed that during the initial 60 percent of the rendering process, the original method on average requires more than two shift attempts to determine the optimal value in every iteration. Therefore, we propose adjusting the initial 't' value from 0.5 to 0.25 by applying an initial shift of 2. Additionally, as the spline rendering process progresses to the later stages, the amount of shift gradually decreases. Hence, we store the amount of shift used in each iteration as a global variable to record the value of the last shift change. This way allows us to use this value directly in the next iteration, eliminating the need to start from an initial shift of 2 again. Furthermore, instead of merely decreasing 't' by adding the amount of shift, we also reduce the amount of shift to a minimum of 1. Based on Experiment 3, this limitation of the scope can decrease the average number of function '_de_casteljau' calls per point and increase the number of points when rendering. This means that these points do not always have the maximum curvature, and some optimal points with maximum curvature will be overlooked while limiting the scope of 't' to [0, 0.25]. In summary, we have chosen the Original (shift2) setting in this pull request, as demonstrated in Experiment 1. The modified implementation of font-edit, which utilizes fixed-point arithmetic, serves as the evaluation testbed for the following experiments: Experiment 1: Original - Average number of _de_casteljau calls per point: 1.99 Original - Average points per character: 18.89 Original (shift2) - Average number of _de_casteljau calls per point: 1.51 Original (shift2) - Average points per character: 18.98 Experiment 2: Flexible - Average number of _de_casteljau calls per point: 4.53 Flexible - Average points per character: 16.30 Flexible (shift2) - Average number of _de_casteljau calls per point: 4.40 Flexible (shift2) - Average points per character: 21.16 Flexible (early stopping) - Average number of _de_casteljau calls per point: 4.23 Flexible (early stopping) - Average points per character: 16.18 Flexible (early stopping) (shift2) - Average number of _de_casteljau calls per point: 3.99 Flexible (early stopping) (shift2) - Average points per character: 21.09 Experiment 3: Original (shift2) (limit scope) - Average number of _de_casteljau calls per point: 1.18 Original (shift2) (limit scope) - Average points per character: 22.57
Thank @weihsinyeh for the great work! |
The evaluation testbed is font-edit, where I modified the implementation to use fixed-point arithmetic.
The font generated by the original implementation is as follows:
The font generated by the implementation of decomposing splines with flexibly updated t is as follows: