diff options
Diffstat (limited to 'source/blender/editors/uvedit')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_parametrizer.c | 96 |
1 files changed, 76 insertions, 20 deletions
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index a4ee9a294fe..e83b54ae8bf 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -190,6 +190,9 @@ typedef struct PChart { LinearSolver *context; float *abf_alpha; PVert *pin1, *pin2; + PVert *single_pin; + float single_pin_area; + float single_pin_uv[2]; } lscm; struct PChartPack { float rescale, area; @@ -467,6 +470,17 @@ static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2]) } } +static float p_chart_uv_area(PChart *chart) +{ + float area = 0.0f; + + for (PFace *f = chart->faces; f; f = f->nextlink) { + area += fabsf(p_face_uv_area_signed(f)); + } + + return area; +} + static void p_chart_uv_scale(PChart *chart, float scale) { PVert *v; @@ -3176,7 +3190,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) } } - if ((live && (!select || !deselect)) || (npins == 1)) { + if ((live && (!select || !deselect))) { chart->u.lscm.context = NULL; } else { @@ -3185,6 +3199,16 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) p_chart_topological_sanity_check(chart); #endif + if (npins == 1) { + chart->u.lscm.single_pin_area = p_chart_uv_area(chart); + for (v = chart->verts; v; v = v->nextlink) { + if (v->flag & PVERT_PIN) { + chart->u.lscm.single_pin = v; + break; + } + } + } + if (abf) { if (!p_chart_abf_solve(chart)) { param_warning("ABF solving failed: falling back to LSCM.\n"); @@ -3192,12 +3216,12 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) } if (npins <= 1) { - /* not enough pins, lets find some ourself */ + /* No pins, let's find some ourself. */ PEdge *outer; p_chart_boundaries(chart, NULL, &outer); - /* outer can be NULL with non-finite coords. */ + /* Outer can be NULL with non-finite coords. */ if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) { p_chart_extrema_verts(chart, &pin1, &pin2); } @@ -3235,6 +3259,11 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) } } + if (chart->u.lscm.single_pin) { + /* If only one pin, save area and pin for transform later. */ + copy_v2_v2(chart->u.lscm.single_pin_uv, chart->u.lscm.single_pin->uv); + } + if (chart->u.lscm.pin1) { EIG_linear_solver_variable_lock(context, 2 * pin1->u.id); EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1); @@ -3358,6 +3387,25 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) return P_FALSE; } +static void p_chart_lscm_transform_single_pin(PChart *chart) +{ + PVert *pin = chart->u.lscm.single_pin; + + /* If only one pin, keep UV area the same. */ + const float new_area = p_chart_uv_area(chart); + if (new_area > 0.0f) { + const float scale = chart->u.lscm.single_pin_area / new_area; + if (scale > 0.0f) { + p_chart_uv_scale(chart, sqrtf(scale)); + } + } + + /* Translate to keep the pinned vertex in place. */ + float offset[2]; + sub_v2_v2v2(offset, chart->u.lscm.single_pin_uv, pin->uv); + p_chart_uv_translate(chart, offset); +} + static void p_chart_lscm_end(PChart *chart) { if (chart->u.lscm.context) { @@ -3372,6 +3420,8 @@ static void p_chart_lscm_end(PChart *chart) chart->u.lscm.context = NULL; chart->u.lscm.pin1 = NULL; chart->u.lscm.pin2 = NULL; + chart->u.lscm.single_pin = NULL; + chart->u.lscm.single_pin_area = 0.0f; } /* Stretch */ @@ -3781,6 +3831,23 @@ static void p_chart_rotate_minimum_area(PChart *chart) } } +static void p_chart_rotate_fit_aabb(PChart *chart) +{ + float(*points)[2] = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); + + p_chart_uv_to_array(chart, points); + + float angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); + + MEM_freeN(points); + + if (angle != 0.0f) { + float mat[2][2]; + angle_to_mat2(mat, angle); + p_chart_uv_transform(chart, mat); + } +} + /* Area Smoothing */ /* 2d bsp tree for inverse mapping - that's a bit silly */ @@ -4576,8 +4643,12 @@ void param_lscm_solve(ParamHandle *handle) if (result && !(chart->flag & PCHART_HAS_PINS)) { p_chart_rotate_minimum_area(chart); } + else if (result && chart->u.lscm.single_pin) { + p_chart_rotate_fit_aabb(chart); + p_chart_lscm_transform_single_pin(chart); + } - if (!result || (chart->u.lscm.pin1)) { + if (!result || !(chart->flag & PCHART_HAS_PINS)) { p_chart_lscm_end(chart); } } @@ -4692,28 +4763,13 @@ static void param_pack_rotate(ParamHandle *handle, bool ignore_pinned) PHandle *phandle = (PHandle *)handle; for (i = 0; i < phandle->ncharts; i++) { - float(*points)[2]; - float angle; - chart = phandle->charts[i]; if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) { continue; } - points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); - - p_chart_uv_to_array(chart, points); - - angle = BLI_convexhull_aabb_fit_points_2d(points, chart->nverts); - - MEM_freeN(points); - - if (angle != 0.0f) { - float mat[2][2]; - angle_to_mat2(mat, angle); - p_chart_uv_transform(chart, mat); - } + p_chart_rotate_fit_aabb(chart); } } |