diff options
author | Hans Goudey <h.goudey@me.com> | 2020-09-04 18:56:56 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2020-09-04 18:56:56 +0300 |
commit | 417695e4a8bff7927a936797ca01c6461ce0eaf7 (patch) | |
tree | 1d7a1ff4b95d09bbb6319f4378520e43f170e6ac | |
parent | ce67a9d39f0feef89bbb9f7835b52884921e66ed (diff) |
Curve Profile: Miscellaneous cleanup
- Declare variables where they are initialized
- Use consistent variable and static function names
- Use helper functions more for common operations
- Remove use of BezTriple struct, use CurveProfilePoint instead
- Apply small simplifications to code in some situations
-rw-r--r-- | source/blender/blenkernel/BKE_curveprofile.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curveprofile.c | 473 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 7 |
3 files changed, 199 insertions, 285 deletions
diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h index 9c72a866fa9..08d3da7123c 100644 --- a/source/blender/blenkernel/BKE_curveprofile.h +++ b/source/blender/blenkernel/BKE_curveprofile.h @@ -23,6 +23,8 @@ * \ingroup bke */ +#include "DNA_curveprofile_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -34,7 +36,7 @@ struct CurveProfilePoint; void BKE_curveprofile_set_defaults(struct CurveProfile *profile); -struct CurveProfile *BKE_curveprofile_add(int preset); +struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset); void BKE_curveprofile_free_data(struct CurveProfile *profile); diff --git a/source/blender/blenkernel/intern/curveprofile.c b/source/blender/blenkernel/intern/curveprofile.c index 068f8845e64..f52619f8c3a 100644 --- a/source/blender/blenkernel/intern/curveprofile.c +++ b/source/blender/blenkernel/intern/curveprofile.c @@ -143,6 +143,14 @@ bool BKE_curveprofile_move_point(struct CurveProfile *profile, const bool snap, const float delta[2]) { + /* Don't move the final point. */ + if (point == &profile->path[profile->path_len - 1]) { + return false; + } + /* Don't move the first point. */ + if (point == profile->path) { + return false; + } float origx = point->x; float origy = point->y; @@ -183,8 +191,6 @@ bool BKE_curveprofile_move_point(struct CurveProfile *profile, */ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *point) { - CurveProfilePoint *pts; - /* Must have 2 points minimum. */ if (profile->path_len <= 2) { return false; @@ -195,18 +201,20 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi return false; } - pts = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, "path points"); + CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, + "profile path"); - uint i_delete = (uint)(point - profile->path); + int i_delete = (int)(point - profile->path); + BLI_assert(i_delete > 0); /* Copy the before and after the deleted point. */ - memcpy(pts, profile->path, sizeof(CurveProfilePoint) * i_delete); - memcpy(pts + i_delete, + memcpy(new_path, profile->path, sizeof(CurveProfilePoint) * i_delete); + memcpy(new_path + i_delete, profile->path + i_delete + 1, sizeof(CurveProfilePoint) * (profile->path_len - i_delete - 1)); MEM_freeN(profile->path); - profile->path = pts; + profile->path = new_path; profile->path_len -= 1; return true; } @@ -220,31 +228,44 @@ bool BKE_curveprofile_remove_point(CurveProfile *profile, CurveProfilePoint *poi */ void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag) { - int i_old, i_new, n_removed = 0; - /* Copy every point without the flag into the new path. */ - CurveProfilePoint *new_pts = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, - "profile path"); + CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, + "profile path"); /* Build the new list without any of the points with the flag. Keep the first and last points. */ - new_pts[0] = profile->path[0]; - for (i_old = 1, i_new = 1; i_old < profile->path_len - 1; i_old++) { + int i_new = 1; + int i_old = 1; + int n_removed = 0; + new_path[0] = profile->path[0]; + for (; i_old < profile->path_len - 1; i_old++) { if (!(profile->path[i_old].flag & flag)) { - new_pts[i_new] = profile->path[i_old]; + new_path[i_new] = profile->path[i_old]; i_new++; } else { n_removed++; } } - new_pts[i_new] = profile->path[i_old]; + new_path[i_new] = profile->path[i_old]; MEM_freeN(profile->path); - profile->path = new_pts; + profile->path = new_path; profile->path_len -= n_removed; } /** + * Shorthand helper function for setting location and interpolation of a point. + */ +static void point_init(CurveProfilePoint *point, float x, float y, short flag, char h1, char h2) +{ + point->x = x; + point->y = y; + point->flag = flag; + point->h1 = h1; + point->h2 = h2; +} + +/** * Adds a new point at the specified location. The choice for which points to place the new vertex * between is made by checking which control point line segment is closest to the new point and * placing the new vertex in between that segment's points. @@ -253,7 +274,6 @@ void BKE_curveprofile_remove_by_flag(CurveProfile *profile, const short flag) */ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float y) { - CurveProfilePoint *new_pt = NULL; const float new_loc[2] = {x, y}; /* Don't add more control points than the maximum size of the higher resolution table. */ @@ -262,14 +282,13 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float } /* Find the index at the line segment that's closest to the new position. */ - float distance; float min_distance = FLT_MAX; int i_insert = 0; for (int i = 0; i < profile->path_len - 1; i++) { const float loc1[2] = {profile->path[i].x, profile->path[i].y}; const float loc2[2] = {profile->path[i + 1].x, profile->path[i + 1].y}; - distance = dist_squared_to_line_segment_v2(new_loc, loc1, loc2); + float distance = dist_squared_to_line_segment_v2(new_loc, loc1, loc2); if (distance < min_distance) { min_distance = distance; i_insert = i + 1; @@ -278,28 +297,25 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float /* Insert the new point at the location we found and copy all of the old points in as well. */ profile->path_len++; - CurveProfilePoint *new_pts = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, - "profile path"); + CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, + "profile path"); + CurveProfilePoint *new_pt = NULL; for (int i_new = 0, i_old = 0; i_new < profile->path_len; i_new++) { if (i_new != i_insert) { /* Insert old points. */ - memcpy(&new_pts[i_new], &profile->path[i_old], sizeof(CurveProfilePoint)); - new_pts[i_new].flag &= ~PROF_SELECT; /* Deselect old points. */ + new_path[i_new] = profile->path[i_old]; + new_path[i_new].flag &= ~PROF_SELECT; /* Deselect old points. */ i_old++; } else { /* Insert new point. */ - new_pts[i_new].x = x; - new_pts[i_new].y = y; - new_pts[i_new].flag = PROF_SELECT; - new_pt = &new_pts[i_new]; /* Set handles of new point based on its neighbors. */ - if (new_pts[i_new - 1].h2 == HD_VECT && profile->path[i_insert].h1 == HD_VECT) { - new_pt->h1 = new_pt->h2 = HD_VECT; - } - else { - new_pt->h1 = new_pt->h2 = HD_AUTO; - } + char new_handle_type = (new_path[i_new - 1].h2 == HD_VECT && + profile->path[i_insert].h1 == HD_VECT) ? + HD_VECT : + HD_AUTO; + point_init(&new_path[i_new], x, y, PROF_SELECT, new_handle_type, new_handle_type); + new_pt = &new_path[i_new]; /* Give new point a reference to the profile. */ new_pt->profile = profile; } @@ -307,7 +323,7 @@ CurveProfilePoint *BKE_curveprofile_insert(CurveProfile *profile, float x, float /* Free the old path and use the new one. */ MEM_freeN(profile->path); - profile->path = new_pts; + profile->path = new_path; return new_pt; } @@ -331,6 +347,13 @@ void BKE_curveprofile_selected_handle_set(CurveProfile *profile, int type_1, int } } +static CurveProfilePoint mirror_point(const CurveProfilePoint *point) +{ + CurveProfilePoint new_point = *point; + point_init(&new_point, point->y, point->x, point->flag, point->h2, point->h1); + return new_point; +} + /** * Flips the profile across the diagonal so that its orientation is reversed. * @@ -342,135 +365,86 @@ void BKE_curveprofile_reverse(CurveProfile *profile) if (profile->path_len == 2) { return; } - CurveProfilePoint *new_pts = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, - "profile path"); + CurveProfilePoint *new_path = MEM_mallocN(sizeof(CurveProfilePoint) * profile->path_len, + "profile path"); /* Mirror the new points across the y = x line */ for (int i = 0; i < profile->path_len; i++) { int i_reversed = profile->path_len - i - 1; BLI_assert(i_reversed >= 0); - new_pts[i_reversed].x = profile->path[i].y; - new_pts[i_reversed].y = profile->path[i].x; - new_pts[i_reversed].flag = profile->path[i].flag; - new_pts[i_reversed].h1 = profile->path[i].h2; - new_pts[i_reversed].h2 = profile->path[i].h1; - new_pts[i_reversed].profile = profile; + new_path[i_reversed] = mirror_point(&profile->path[i]); + new_path[i_reversed].profile = profile; /* Mirror free handles, they can't be recalculated. */ if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { - new_pts[i_reversed].h1_loc[0] = profile->path[i].h2_loc[1]; - new_pts[i_reversed].h1_loc[1] = profile->path[i].h2_loc[0]; + new_path[i_reversed].h1_loc[0] = profile->path[i].h2_loc[1]; + new_path[i_reversed].h1_loc[1] = profile->path[i].h2_loc[0]; } if (ELEM(profile->path[i].h2, HD_FREE, HD_ALIGN)) { - new_pts[i_reversed].h2_loc[0] = profile->path[i].h1_loc[1]; - new_pts[i_reversed].h2_loc[1] = profile->path[i].h1_loc[0]; + new_path[i_reversed].h2_loc[0] = profile->path[i].h1_loc[1]; + new_path[i_reversed].h2_loc[1] = profile->path[i].h1_loc[0]; } } /* Free the old points and use the new ones */ MEM_freeN(profile->path); - profile->path = new_pts; + profile->path = new_path; } /** * Builds a quarter circle profile with space on each side for 'support loops.' */ -static void CurveProfile_build_supports(CurveProfile *profile) +static void curveprofile_build_supports(CurveProfile *profile) { int n = profile->path_len; - profile->path[0].x = 1.0; - profile->path[0].y = 0.0; - profile->path[0].flag = 0; - profile->path[0].h1 = HD_VECT; - profile->path[0].h2 = HD_VECT; - profile->path[1].x = 1.0; - profile->path[1].y = 0.5; - profile->path[1].flag = 0; - profile->path[1].h1 = HD_VECT; - profile->path[1].h2 = HD_VECT; + point_init(&profile->path[0], 1.0f, 0.0f, 0, HD_VECT, HD_VECT); + point_init(&profile->path[1], 1.0f, 0.5f, 0, HD_VECT, HD_VECT); for (int i = 1; i < n - 2; i++) { - profile->path[i + 1].x = 1.0f - (0.5f * (1.0f - cosf((float)((i / (float)(n - 3))) * M_PI_2))); - profile->path[i + 1].y = 0.5f + 0.5f * sinf((float)((i / (float)(n - 3)) * M_PI_2)); - profile->path[i + 1].flag = 0; - profile->path[i + 1].h1 = HD_AUTO; - profile->path[i + 1].h2 = HD_AUTO; + const float x = 1.0f - (0.5f * (1.0f - cosf((float)((i / (float)(n - 3))) * M_PI_2))); + const float y = 0.5f + 0.5f * sinf((float)((i / (float)(n - 3)) * M_PI_2)); + point_init(&profile->path[i], x, y, 0, HD_AUTO, HD_AUTO); } - profile->path[n - 2].x = 0.5; - profile->path[n - 2].y = 1.0; - profile->path[n - 2].flag = 0; - profile->path[n - 2].h1 = HD_VECT; - profile->path[n - 2].h2 = HD_VECT; - profile->path[n - 1].x = 0.0; - profile->path[n - 1].y = 1.0; - profile->path[n - 1].flag = 0; - profile->path[n - 1].h1 = HD_VECT; - profile->path[n - 1].h2 = HD_VECT; + point_init(&profile->path[n - 2], 0.5f, 1.0f, 0, HD_VECT, HD_VECT); + point_init(&profile->path[n - 1], 0.0f, 1.0f, 0, HD_VECT, HD_VECT); } /** * Puts the widgets control points in a step pattern. * Uses vector handles for each point. */ -static void CurveProfile_build_steps(CurveProfile *profile) +static void curveprofile_build_steps(CurveProfile *profile) { - int n, step_x, step_y; - float n_steps_x, n_steps_y; - - n = profile->path_len; + int n = profile->path_len; /* Special case for two points to avoid dividing by zero later. */ if (n == 2) { - profile->path[0].x = 1.0f; - profile->path[0].y = 0.0f; - profile->path[0].flag = 0; - profile->path[0].h1 = HD_VECT; - profile->path[0].h2 = HD_VECT; - profile->path[1].x = 0.0f; - profile->path[1].y = 1.0f; - profile->path[1].flag = 0; - profile->path[1].h1 = HD_VECT; - profile->path[1].h2 = HD_VECT; + point_init(&profile->path[0], 1.0f, 0.0f, 0, HD_VECT, HD_VECT); + point_init(&profile->path[0], 0.0f, 1.0f, 0, HD_VECT, HD_VECT); return; } - n_steps_x = (n % 2 == 0) ? n : (n - 1); - n_steps_y = (n % 2 == 0) ? (n - 2) : (n - 1); + float n_steps_x = (n % 2 == 0) ? n : (n - 1); + float n_steps_y = (n % 2 == 0) ? (n - 2) : (n - 1); for (int i = 0; i < n; i++) { - step_x = (i + 1) / 2; - step_y = i / 2; - profile->path[i].x = 1.0f - ((float)(2 * step_x) / n_steps_x); - profile->path[i].y = (float)(2 * step_y) / n_steps_y; - profile->path[i].flag = 0; - profile->path[i].h1 = HD_VECT; - profile->path[i].h2 = HD_VECT; + int step_x = (i + 1) / 2; + int step_y = i / 2; + const float x = 1.0f - ((float)(2 * step_x) / n_steps_x); + const float y = (float)(2 * step_y) / n_steps_y; + point_init(&profile->path[i], x, y, 0, HD_VECT, HD_VECT); } } /** - * Shorthand helper function for setting location and interpolation of a point. - */ -static void point_init(CurveProfilePoint *point, float x, float y, short flag, char h1, char h2) -{ - point->x = x; - point->y = y; - point->flag = flag; - point->h1 = h1; - point->h2 = h2; -} - -/** * Resets the profile to the current preset. * * \note Requires #BKE_curveprofile_update call after. */ void BKE_curveprofile_reset(CurveProfile *profile) { - if (profile->path) { - MEM_freeN(profile->path); - } + MEM_SAFE_FREE(profile->path); - int preset = profile->preset; + eCurveProfilePresets preset = profile->preset; switch (preset) { case PROF_PRESET_LINE: profile->path_len = 2; @@ -511,7 +485,7 @@ void BKE_curveprofile_reset(CurveProfile *profile) point_init(&profile->path[1], 0.0f, 1.0f, 0, HD_AUTO, HD_AUTO); break; case PROF_PRESET_SUPPORTS: - CurveProfile_build_supports(profile); + curveprofile_build_supports(profile); break; case PROF_PRESET_CORNICE: point_init(&profile->path[0], 1.0f, 0.0f, 0, HD_VECT, HD_VECT); @@ -542,7 +516,7 @@ void BKE_curveprofile_reset(CurveProfile *profile) point_init(&profile->path[10], 0.0f, 1.0f, 0, HD_VECT, HD_VECT); break; case PROF_PRESET_STEPS: - CurveProfile_build_steps(profile); + curveprofile_build_steps(profile); break; } @@ -553,68 +527,61 @@ void BKE_curveprofile_reset(CurveProfile *profile) profile->path[i].profile = profile; } - if (profile->table) { - MEM_freeN(profile->table); - profile->table = NULL; - } + MEM_SAFE_FREE(profile->table); + profile->table = NULL; } /** * Helper for 'curve_profile_create' samples. * Returns whether both handles that make up the edge are vector handles. */ -static bool is_curved_edge(BezTriple *bezt, int i) +static bool is_curved_edge(CurveProfilePoint *path, int i) { - return (bezt[i].h2 != HD_VECT || bezt[i + 1].h1 != HD_VECT); + return (path[i].h2 != HD_VECT || path[i + 1].h1 != HD_VECT); } /** * Used to set bezier handle locations in the sample creation process. Reduced copy of * #calchandleNurb_intern code in curve.c, mostly changed by removing the third dimension. */ -static void calchandle_profile(BezTriple *bezt, const BezTriple *prev, const BezTriple *next) +static void point_calculate_handle(CurveProfilePoint *point, + const CurveProfilePoint *prev, + const CurveProfilePoint *next) { -#define point_handle1 ((point_loc)-3) -#define point_handle2 ((point_loc) + 3) - - const float *prev_loc, *next_loc; - float *point_loc; - float pt[3]; - float len, len_a, len_b; - float dvec_a[2], dvec_b[2]; - - if (bezt->h1 == 0 && bezt->h2 == 0) { + if (point->h1 == HD_FREE && point->h2 == HD_FREE) { return; } - point_loc = bezt->vec[1]; + float *point_loc = &point->x; + float pt[2]; + const float *prev_loc, *next_loc; if (prev == NULL) { - next_loc = next->vec[1]; + next_loc = &next->x; pt[0] = 2.0f * point_loc[0] - next_loc[0]; pt[1] = 2.0f * point_loc[1] - next_loc[1]; prev_loc = pt; } else { - prev_loc = prev->vec[1]; + prev_loc = &prev->x; } if (next == NULL) { - prev_loc = prev->vec[1]; + prev_loc = &prev->x; pt[0] = 2.0f * point_loc[0] - prev_loc[0]; pt[1] = 2.0f * point_loc[1] - prev_loc[1]; next_loc = pt; } else { - next_loc = next->vec[1]; + next_loc = &next->x; } + float dvec_a[2], dvec_b[2]; sub_v2_v2v2(dvec_a, point_loc, prev_loc); sub_v2_v2v2(dvec_b, next_loc, point_loc); - len_a = len_v2(dvec_a); - len_b = len_v2(dvec_b); - + float len_a = len_v2(dvec_a); + float len_b = len_v2(dvec_b); if (len_a == 0.0f) { len_a = 1.0f; } @@ -622,60 +589,65 @@ static void calchandle_profile(BezTriple *bezt, const BezTriple *prev, const Bez len_b = 1.0f; } - if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */ + if (point->h1 == HD_AUTO || point->h2 == HD_AUTO) { float tvec[2]; tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a; tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a; - len = len_v2(tvec) * 2.5614f; + float len = len_v2(tvec) * 2.5614f; if (len != 0.0f) { - - if (bezt->h1 == HD_AUTO) { + if (point->h1 == HD_AUTO) { len_a /= len; - madd_v2_v2v2fl(point_handle1, point_loc, tvec, -len_a); + madd_v2_v2v2fl(point->h1_loc, point_loc, tvec, -len_a); } - if (bezt->h2 == HD_AUTO) { + if (point->h2 == HD_AUTO) { len_b /= len; - madd_v2_v2v2fl(point_handle2, point_loc, tvec, len_b); + madd_v2_v2v2fl(point->h2_loc, point_loc, tvec, len_b); } } } - if (bezt->h1 == HD_VECT) { /* vector */ - madd_v2_v2v2fl(point_handle1, point_loc, dvec_a, -1.0f / 3.0f); + if (point->h1 == HD_VECT) { + madd_v2_v2v2fl(point->h1_loc, point_loc, dvec_a, -1.0f / 3.0f); + } + if (point->h2 == HD_VECT) { + madd_v2_v2v2fl(point->h2_loc, point_loc, dvec_b, 1.0f / 3.0f); } - if (bezt->h2 == HD_VECT) { - madd_v2_v2v2fl(point_handle2, point_loc, dvec_b, 1.0f / 3.0f); +} + +static void calculate_path_handles(CurveProfilePoint *path, int path_len) +{ + point_calculate_handle(&path[0], NULL, &path[1]); + for (int i = 1; i < path_len - 1; i++) { + point_calculate_handle(&path[i], &path[i - 1], &path[i + 1]); } -#undef point_handle1 -#undef point_handle2 + point_calculate_handle(&path[path_len - 1], &path[path_len - 2], NULL); } /** - * Helper function for 'BKE_CurveProfile_create_samples.' Calculates the angle between the + * Helper function for 'BKE_curveprofile_create_samples.' Calculates the angle between the * handles on the inside of the edge starting at index i. A larger angle means the edge is * more curved. * \param i_edge: The start index of the edge to calculate the angle for. */ -static float bezt_edge_handle_angle(const BezTriple *bezt, int i_edge) +static float bezt_edge_handle_angle(const CurveProfilePoint *path, int i_edge) { /* Find the direction of the handles that define this edge along the direction of the path. */ float start_handle_direction[2], end_handle_direction[2]; /* Handle 2 - point location. */ - sub_v2_v2v2(start_handle_direction, bezt[i_edge].vec[2], bezt[i_edge].vec[1]); + sub_v2_v2v2(start_handle_direction, path[i_edge].h2_loc, &path[i_edge].x); /* Point location - handle 1. */ - sub_v2_v2v2(end_handle_direction, bezt[i_edge + 1].vec[1], bezt[i_edge + 1].vec[0]); + sub_v2_v2v2(end_handle_direction, &path[i_edge + 1].x, path[i_edge + 1].h1_loc); - float angle = angle_v2v2(start_handle_direction, end_handle_direction); - return angle; + return angle_v2v2(start_handle_direction, end_handle_direction); } /** Struct to sort curvature of control point edges. */ typedef struct { - /** The index of the corresponding bezier point. */ - int bezt_index; + /** The index of the corresponding profile point. */ + int point_index; /** The curvature of the edge with the above index. */ - float bezt_curvature; + float point_curvature; } CurvatureSortPoint; /** @@ -686,7 +658,7 @@ static int sort_points_curvature(const void *in_a, const void *in_b) const CurvatureSortPoint *a = (const CurvatureSortPoint *)in_a; const CurvatureSortPoint *b = (const CurvatureSortPoint *)in_b; - if (a->bezt_curvature > b->bezt_curvature) { + if (a->point_curvature > b->point_curvature) { return 0; } @@ -698,82 +670,52 @@ static int sort_points_curvature(const void *in_a, const void *in_b) * user-defined points will be evenly distributed among the curved edges. * Then the remainders will be distributed to the most curved edges. * - * \param n_segments: The number of segments to sample along the path. It must be higher than the - * number of points used to define the profile (profile->path_len). - * \param sample_straight_edges: Whether to sample points between vector handle control points. If - * this is true and there are only vector edges the straight edges will still be sampled. - * \param r_samples: An array of points to put the sampled positions. Must have length n_segments. - * \return r_samples: Fill the array with the sampled locations and if the point corresponds - * to a control point, its handle type. + * \param n_segments: The number of segments to sample along the path. Ideally it is higher than + * the number of points used to define the profile (profile->path_len). + * \param sample_straight_edges: Whether to sample points between vector handle control points. + * If this is true and there are only vector edges the straight edges will still be sampled. + * \param r_samples: Return array of points to put the sampled positions. Must have length + * n_segments. Fill the array with the sampled locations and if the point corresponds to a + * control point, its handle type. */ void BKE_curveprofile_create_samples(CurveProfile *profile, int n_segments, bool sample_straight_edges, CurveProfilePoint *r_samples) { - BezTriple *bezt; - int i, n_left, n_common, i_sample, n_curved_edges; - int *n_samples; - CurvatureSortPoint *curve_sorted; + CurveProfilePoint *path = profile->path; int totpoints = profile->path_len; - int totedges = totpoints - 1; - BLI_assert(n_segments > 0); - /* Create Bezier points for calculating the higher resolution path. */ - bezt = MEM_callocN(sizeof(BezTriple) * totpoints, "beztarr"); - for (i = 0; i < totpoints; i++) { - bezt[i].vec[1][0] = profile->path[i].x; - bezt[i].vec[1][1] = profile->path[i].y; - bezt[i].h1 = profile->path[i].h1; - bezt[i].h2 = profile->path[i].h2; - /* Copy handle locations if the handle type is free. */ - if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { - bezt[i].vec[0][0] = profile->path[i].h1_loc[0]; - bezt[i].vec[0][1] = profile->path[i].h1_loc[1]; - } - if (ELEM(profile->path[i].h1, HD_FREE, HD_ALIGN)) { - bezt[i].vec[2][0] = profile->path[i].h2_loc[0]; - bezt[i].vec[2][1] = profile->path[i].h2_loc[1]; - } - } - /* Get handle positions for the non-free bezier points. */ - calchandle_profile(&bezt[0], NULL, &bezt[1]); - for (i = 1; i < totpoints - 1; i++) { - calchandle_profile(&bezt[i], &bezt[i - 1], &bezt[i + 1]); - } - calchandle_profile(&bezt[totpoints - 1], &bezt[totpoints - 2], NULL); - - /* Copy the handle locations back to the control points. */ - for (i = 0; i < totpoints; i++) { - profile->path[i].h1_loc[0] = bezt[i].vec[0][0]; - profile->path[i].h1_loc[1] = bezt[i].vec[0][1]; - profile->path[i].h2_loc[0] = bezt[i].vec[2][0]; - profile->path[i].h2_loc[1] = bezt[i].vec[2][1]; - } + int totedges = totpoints - 1; + + calculate_path_handles(path, totpoints); /* Create a list of edge indices with the most curved at the start, least curved at the end. */ - curve_sorted = MEM_callocN(sizeof(CurvatureSortPoint) * totedges, "curve sorted"); - for (i = 0; i < totedges; i++) { - curve_sorted[i].bezt_index = i; + CurvatureSortPoint *curve_sorted = MEM_callocN(sizeof(CurvatureSortPoint) * totedges, + "curve sorted"); + for (int i = 0; i < totedges; i++) { + curve_sorted[i].point_index = i; /* Calculate the curvature of each edge once for use when sorting for curvature. */ - curve_sorted[i].bezt_curvature = bezt_edge_handle_angle(bezt, i); + curve_sorted[i].point_curvature = bezt_edge_handle_angle(path, i); } - qsort(curve_sorted, (size_t)totedges, sizeof(CurvatureSortPoint), sort_points_curvature); + qsort(curve_sorted, totedges, sizeof(CurvatureSortPoint), sort_points_curvature); /* Assign the number of sampled points for each edge. */ - n_samples = MEM_callocN(sizeof(int) * totedges, "create samples numbers"); + int16_t *n_samples = MEM_callocN(sizeof(int16_t) * totedges, "samples numbers"); int n_added = 0; + int n_left; if (n_segments >= totedges) { if (sample_straight_edges) { /* Assign an even number to each edge if it’s possible, then add the remainder of sampled * points starting with the most curved edges. */ - n_common = n_segments / totedges; + int n_common = n_segments / totedges; n_left = n_segments % totedges; /* Assign the points that fill fit evenly to the edges. */ if (n_common > 0) { - for (i = 0; i < totedges; i++) { + BLI_assert(n_common < INT16_MAX); + for (int i = 0; i < totedges; i++) { n_samples[i] = n_common; n_added += n_common; } @@ -781,9 +723,9 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, } else { /* Count the number of curved edges */ - n_curved_edges = 0; - for (i = 0; i < totedges; i++) { - if (is_curved_edge(bezt, i)) { + int n_curved_edges = 0; + for (int i = 0; i < totedges; i++) { + if (is_curved_edge(path, i)) { n_curved_edges++; } } @@ -792,11 +734,12 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, /* Give all of the curved edges the same number of points and straight edges one point. */ n_left = n_segments - (totedges - n_curved_edges); /* Left after 1 for each straight edge. */ - n_common = n_left / n_curved_edges; /* Number assigned to all curved edges */ + int n_common = n_left / n_curved_edges; /* Number assigned to all curved edges */ if (n_common > 0) { - for (i = 0; i < totedges; i++) { + for (int i = 0; i < totedges; i++) { /* Add the common number if it's a curved edge or if edges are curved. */ - if (is_curved_edge(bezt, i) || n_curved_edges == totedges) { + if (is_curved_edge(path, i) || n_curved_edges == totedges) { + BLI_assert(n_common + n_samples[i] < INT16_MAX); n_samples[i] += n_common; n_added += n_common; } @@ -815,19 +758,20 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, } /* Assign the remainder of the points that couldn't be spread out evenly. */ BLI_assert(n_left < totedges); - for (i = 0; i < n_left; i++) { - n_samples[curve_sorted[i].bezt_index]++; + for (int i = 0; i < n_left; i++) { + BLI_assert(n_samples[curve_sorted[i].point_index] < INT16_MAX); + n_samples[curve_sorted[i].point_index]++; n_added++; } BLI_assert(n_added == n_segments); /* n_added is just used for this assert, could remove it. */ /* Sample the points and add them to the locations table. */ - for (i_sample = 0, i = 0; i < totedges; i++) { + for (int i_sample = 0, i = 0; i < totedges; i++) { if (n_samples[i] > 0) { /* Carry over the handle types from the control point to its first corresponding sample. */ - r_samples[i_sample].h1 = profile->path[i].h1; - r_samples[i_sample].h2 = profile->path[i].h2; + r_samples[i_sample].h1 = path[i].h1; + r_samples[i_sample].h2 = path[i].h2; /* All extra sample points for this control point get "auto" handles. */ for (int j = i_sample + 1; j < i_sample + n_samples[i]; j++) { r_samples[j].flag = 0; @@ -837,17 +781,17 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, } /* Sample from the bezier points. X then Y values. */ - BKE_curve_forward_diff_bezier(bezt[i].vec[1][0], - bezt[i].vec[2][0], - bezt[i + 1].vec[0][0], - bezt[i + 1].vec[1][0], + BKE_curve_forward_diff_bezier(path[i].x, + path[i].h2_loc[0], + path[i + 1].h1_loc[0], + path[i + 1].x, &r_samples[i_sample].x, n_samples[i], sizeof(CurveProfilePoint)); - BKE_curve_forward_diff_bezier(bezt[i].vec[1][1], - bezt[i].vec[2][1], - bezt[i + 1].vec[0][1], - bezt[i + 1].vec[1][1], + BKE_curve_forward_diff_bezier(path[i].y, + path[i].h2_loc[1], + path[i + 1].h1_loc[1], + path[i + 1].y, &r_samples[i_sample].y, n_samples[i], sizeof(CurveProfilePoint)); @@ -856,25 +800,6 @@ void BKE_curveprofile_create_samples(CurveProfile *profile, BLI_assert(i_sample <= n_segments); } -#ifdef DEBUG_PROFILE_TABLE - printf("CURVEPROFILE CREATE SAMPLES\n"); - printf("n_segments: %d\n", n_segments); - printf("totedges: %d\n", totedges); - printf("n_common: %d\n", n_common); - printf("n_left: %d\n", n_left); - printf("n_samples: "); - for (i = 0; i < totedges; i++) { - printf("%d, ", n_samples[i]); - } - printf("\n"); - printf("i_curved_sorted: "); - for (i = 0; i < totedges; i++) { - printf("(%d %.2f), ", curve_sorted[i].bezt_index, curve_sorted[i].bezt_curvature); - } - printf("\n"); -#endif - - MEM_freeN(bezt); MEM_freeN(curve_sorted); MEM_freeN(n_samples); } @@ -887,16 +812,14 @@ static void curveprofile_make_table(CurveProfile *profile) { int n_samples = PROF_TABLE_LEN(profile->path_len); CurveProfilePoint *new_table = MEM_callocN(sizeof(CurveProfilePoint) * (n_samples + 1), - "high-res table"); + __func__); BKE_curveprofile_create_samples(profile, n_samples - 1, false, new_table); /* Manually add last point at the end of the profile */ new_table[n_samples - 1].x = 0.0f; new_table[n_samples - 1].y = 1.0f; - if (profile->table) { - MEM_freeN(profile->table); - } + MEM_SAFE_FREE(profile->table); profile->table = new_table; } @@ -904,14 +827,14 @@ static void curveprofile_make_table(CurveProfile *profile) * Creates the table of points used for displaying a preview of the sampled segment locations on * the widget itself. */ -static void CurveProfile_make_segments_table(CurveProfile *profile) +static void curveprofile_make_segments_table(CurveProfile *profile) { int n_samples = profile->segments_len; if (n_samples <= 0) { return; } CurveProfilePoint *new_table = MEM_callocN(sizeof(CurveProfilePoint) * (n_samples + 1), - "samples table"); + __func__); if (profile->flag & PROF_SAMPLE_EVEN_LENGTHS) { /* Even length sampling incompatible with only straight edge sampling for now. */ @@ -922,9 +845,7 @@ static void CurveProfile_make_segments_table(CurveProfile *profile) profile, n_samples, profile->flag & PROF_SAMPLE_STRAIGHT_EDGES, new_table); } - if (profile->segments) { - MEM_freeN(profile->segments); - } + MEM_SAFE_FREE(profile->segments); profile->segments = new_table; } @@ -954,9 +875,8 @@ void BKE_curveprofile_set_defaults(CurveProfile *profile) /** * Returns a pointer to a newly allocated curve profile, using the given preset. - * \param preset: Value in #eCurveProfilePresets. */ -struct CurveProfile *BKE_curveprofile_add(int preset) +struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset) { CurveProfile *profile = MEM_callocN(sizeof(CurveProfile), "curve profile"); @@ -978,8 +898,6 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags) { CurveProfilePoint *points = profile->path; rctf *clipr = &profile->clip_rect; - float thresh; - int i; profile->changed_timestamp++; @@ -987,11 +905,9 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags) if (profile->flag & PROF_USE_CLIP) { /* Move points inside the clip rectangle. */ if (update_flags & PROF_UPDATE_CLIP) { - for (i = 0; i < profile->path_len; i++) { - points[i].x = max_ff(points[i].x, clipr->xmin); - points[i].x = min_ff(points[i].x, clipr->xmax); - points[i].y = max_ff(points[i].y, clipr->ymin); - points[i].y = min_ff(points[i].y, clipr->ymax); + for (int i = 0; i < profile->path_len; i++) { + points[i].x = clamp_f(points[i].x, clipr->xmin, clipr->xmax); + points[i].y = clamp_f(points[i].y, clipr->ymin, clipr->ymax); /* Extra sanity assert to make sure the points have the right profile pointer. */ BLI_assert(points[i].profile == profile); @@ -1009,9 +925,9 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags) } /* Remove doubles with a threshold set at 1% of default range. */ - thresh = pow2f(0.01f * BLI_rctf_size_x(clipr)); + float thresh = pow2f(0.01f * BLI_rctf_size_x(clipr)); if (update_flags & PROF_UPDATE_REMOVE_DOUBLES && profile->path_len > 2) { - for (i = 0; i < profile->path_len - 1; i++) { + for (int i = 0; i < profile->path_len - 1; i++) { if (len_squared_v2v2(&points[i].x, &points[i + 1].x) < thresh) { if (i == 0) { BKE_curveprofile_remove_point(profile, &points[1]); @@ -1029,7 +945,7 @@ void BKE_curveprofile_update(CurveProfile *profile, const int update_flags) /* Store a table of samples for the segment locations for a preview and the table's user. */ if (profile->segments_len > 0) { - CurveProfile_make_segments_table(profile); + curveprofile_make_segments_table(profile); } } @@ -1094,7 +1010,6 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile, float length_travelled = 0.0f; float distance_to_next_table_point = curveprofile_distance_to_next_table_point(profile, 0); float distance_to_previous_table_point = 0.0f; - float segment_left, factor; int i_table = 0; /* Set the location for the first point. */ @@ -1102,7 +1017,7 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile, r_samples[0].y = profile->table[0].y; /* Travel along the path, recording the locations of segments as we pass them. */ - segment_left = segment_length; + float segment_left = segment_length; for (int i = 1; i < n_segments; i++) { /* Travel over all of the points that fit inside this segment. */ while (distance_to_next_table_point < segment_left) { @@ -1113,12 +1028,12 @@ void BKE_curveprofile_create_samples_even_spacing(CurveProfile *profile, distance_to_previous_table_point = 0.0f; } /* We're at the last table point that fits inside the current segment, use interpolation. */ - factor = (distance_to_previous_table_point + segment_left) / - (distance_to_previous_table_point + distance_to_next_table_point); + float factor = (distance_to_previous_table_point + segment_left) / + (distance_to_previous_table_point + distance_to_next_table_point); r_samples[i].x = interpf(profile->table[i_table + 1].x, profile->table[i_table].x, factor); r_samples[i].y = interpf(profile->table[i_table + 1].y, profile->table[i_table].y, factor); -#ifdef DEBUG_CURVEPROFILE_EVALUATE BLI_assert(factor <= 1.0f && factor >= 0.0f); +#ifdef DEBUG_CURVEPROFILE_EVALUATE printf("segment_left: %.3f\n", segment_left); printf("i_table: %d\n", i_table); printf("distance_to_previous_table_point: %.3f\n", distance_to_previous_table_point); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index bf38f8bf12f..83cbdeff0d8 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6954,10 +6954,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, const float zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect); if (snap) { - float d[2]; - - d[0] = mx - data->dragstartx; - d[1] = my - data->dragstarty; + float d[2] = {mx - data->dragstartx, data->dragstarty}; if (len_squared_v2(d) < (9.0f * U.dpi_fac)) { snap = false; @@ -6979,7 +6976,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, const float delta[2] = {fx, fy}; for (int a = 0; a < profile->path_len; a++) { /* Don't move the last and first control points. */ - if ((pts[a].flag & PROF_SELECT) && (a != 0) && (a != profile->path_len)) { + if (pts[a].flag & PROF_SELECT) { moved_point |= BKE_curveprofile_move_point(profile, &pts[a], snap, delta); last_x = pts[a].x; last_y = pts[a].y; |