Curve Fitting: add high-quality flag

When this flag is set - even when the curve error is under the threshold,
keep attempting a better fit.

Enable this for freehand drawing, since it gives nicer results and isn't noticeably slower.
This commit is contained in:
Campbell Barton 2016-06-14 02:11:57 +10:00
parent b0985b393c
commit abb9d0b0ad
3 changed files with 38 additions and 23 deletions

@ -60,6 +60,7 @@ int curve_fit_cubic_to_points_db(
const unsigned int points_len, const unsigned int points_len,
const unsigned int dims, const unsigned int dims,
const double error_threshold, const double error_threshold,
const unsigned int calc_flag,
const unsigned int *corners, const unsigned int *corners,
unsigned int corners_len, unsigned int corners_len,
@ -72,6 +73,7 @@ int curve_fit_cubic_to_points_fl(
const unsigned int points_len, const unsigned int points_len,
const unsigned int dims, const unsigned int dims,
const float error_threshold, const float error_threshold,
const unsigned int calc_flag,
const unsigned int *corners, const unsigned int *corners,
const unsigned int corners_len, const unsigned int corners_len,
@ -117,6 +119,10 @@ int curve_fit_cubic_to_points_single_fl(
float r_handle_r[], float r_handle_r[],
float *r_error_sq); float *r_error_sq);
enum {
CURVE_FIT_CALC_HIGH_QUALIY = (1 << 0),
};
/* curve_fit_corners_detect.c */ /* curve_fit_corners_detect.c */
/** /**

@ -1086,11 +1086,7 @@ static bool fit_cubic_to_points(
*r_error_max_sq = error_max_sq; *r_error_max_sq = error_max_sq;
*r_split_index = split_index; *r_split_index = split_index;
if (error_max_sq < error_threshold_sq) { if (!(error_max_sq < error_threshold_sq)) {
free(u);
return true;
}
else {
cubic_copy(cubic_test, r_cubic, dims); cubic_copy(cubic_test, r_cubic, dims);
/* If error not too large, try some reparameterization and iteration */ /* If error not too large, try some reparameterization and iteration */
@ -1108,25 +1104,28 @@ static bool fit_cubic_to_points(
points_offset_coords_length, points_offset_coords_length,
#endif #endif
u_prime, tan_l, tan_r, dims, cubic_test); u_prime, tan_l, tan_r, dims, cubic_test);
error_max_sq = cubic_calc_error(
const double error_max_sq_test = cubic_calc_error(
cubic_test, points_offset, points_offset_len, u_prime, dims, cubic_test, points_offset, points_offset_len, u_prime, dims,
&split_index); &split_index);
if (error_max_sq < error_threshold_sq) { if (error_max_sq > error_max_sq_test) {
free(u_prime); error_max_sq = error_max_sq_test;
free(u);
cubic_copy(r_cubic, cubic_test, dims);
*r_error_max_sq = error_max_sq;
*r_split_index = split_index;
return true;
}
else if (error_max_sq < *r_error_max_sq) {
cubic_copy(r_cubic, cubic_test, dims); cubic_copy(r_cubic, cubic_test, dims);
*r_error_max_sq = error_max_sq; *r_error_max_sq = error_max_sq;
*r_split_index = split_index; *r_split_index = split_index;
} }
if (!(error_max_sq < error_threshold_sq)) {
/* continue */
}
else {
assert((error_max_sq < error_threshold_sq));
free(u_prime);
free(u);
return true;
}
SWAP(double *, u, u_prime); SWAP(double *, u, u_prime);
} }
free(u_prime); free(u_prime);
@ -1134,6 +1133,10 @@ static bool fit_cubic_to_points(
return false; return false;
} }
else {
free(u);
return true;
}
} }
static void fit_cubic_to_points_recursive( static void fit_cubic_to_points_recursive(
@ -1145,6 +1148,7 @@ static void fit_cubic_to_points_recursive(
const double tan_l[], const double tan_l[],
const double tan_r[], const double tan_r[],
const double error_threshold_sq, const double error_threshold_sq,
const uint calc_flag,
const uint dims, const uint dims,
/* fill in the list */ /* fill in the list */
CubicList *clist) CubicList *clist)
@ -1158,8 +1162,11 @@ static void fit_cubic_to_points_recursive(
#ifdef USE_LENGTH_CACHE #ifdef USE_LENGTH_CACHE
points_length_cache, points_length_cache,
#endif #endif
tan_l, tan_r, error_threshold_sq, dims, tan_l, tan_r,
cubic, &error_max_sq, &split_index)) (calc_flag & CURVE_FIT_CALC_HIGH_QUALIY) ? DBL_EPSILON : error_threshold_sq,
dims,
cubic, &error_max_sq, &split_index) ||
(error_max_sq < error_threshold_sq))
{ {
cubic_list_prepend(clist, cubic); cubic_list_prepend(clist, cubic);
return; return;
@ -1211,13 +1218,13 @@ static void fit_cubic_to_points_recursive(
#ifdef USE_LENGTH_CACHE #ifdef USE_LENGTH_CACHE
points_length_cache, points_length_cache,
#endif #endif
tan_l, tan_center, error_threshold_sq, dims, clist); tan_l, tan_center, error_threshold_sq, calc_flag, dims, clist);
fit_cubic_to_points_recursive( fit_cubic_to_points_recursive(
&points_offset[split_index * dims], points_offset_len - split_index, &points_offset[split_index * dims], points_offset_len - split_index,
#ifdef USE_LENGTH_CACHE #ifdef USE_LENGTH_CACHE
points_length_cache + split_index, points_length_cache + split_index,
#endif #endif
tan_center, tan_r, error_threshold_sq, dims, clist); tan_center, tan_r, error_threshold_sq, calc_flag, dims, clist);
} }
@ -1240,6 +1247,7 @@ int curve_fit_cubic_to_points_db(
const uint points_len, const uint points_len,
const uint dims, const uint dims,
const double error_threshold, const double error_threshold,
const uint calc_flag,
const uint *corners, const uint *corners,
uint corners_len, uint corners_len,
@ -1315,7 +1323,7 @@ int curve_fit_cubic_to_points_db(
#ifdef USE_LENGTH_CACHE #ifdef USE_LENGTH_CACHE
points_length_cache, points_length_cache,
#endif #endif
tan_l, tan_r, error_threshold_sq, dims, &clist); tan_l, tan_r, error_threshold_sq, calc_flag, dims, &clist);
} }
else if (points_len == 1) { else if (points_len == 1) {
assert(points_offset_len == 1); assert(points_offset_len == 1);
@ -1382,6 +1390,7 @@ int curve_fit_cubic_to_points_fl(
const uint points_len, const uint points_len,
const uint dims, const uint dims,
const float error_threshold, const float error_threshold,
const uint calc_flag,
const uint *corners, const uint *corners,
const uint corners_len, const uint corners_len,
@ -1399,7 +1408,7 @@ int curve_fit_cubic_to_points_fl(
uint cubic_array_len = 0; uint cubic_array_len = 0;
int result = curve_fit_cubic_to_points_db( int result = curve_fit_cubic_to_points_db(
points_db, points_len, dims, error_threshold, corners, corners_len, points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len,
&cubic_array_db, &cubic_array_len, &cubic_array_db, &cubic_array_len,
r_cubic_orig_index, r_cubic_orig_index,
r_corner_index_array, r_corner_index_len); r_corner_index_array, r_corner_index_len);

@ -911,7 +911,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int corners_index_len = 0; unsigned int corners_index_len = 0;
const int result = curve_fit_cubic_to_points_fl( const int result = curve_fit_cubic_to_points_fl(
coords, stroke_len, dims, error_threshold, coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY,
corners, corners_len, corners, corners_len,
&cubic_spline, &cubic_spline_len, &cubic_spline, &cubic_spline_len,
NULL, NULL,