From 643b498e25fe6fdac9904562a3ad339f4ecb2f23 Mon Sep 17 00:00:00 2001 From: micheus Date: Mon, 17 Nov 2025 14:52:21 -0300 Subject: [PATCH 1/2] New AutoUV Scale->Normalize RMB option It's intended to normalize a set of charts relative to a reference one. This is option is useful in cases where we need to remap a portion of an already unwrapped object, or when someone unwraps a composite object in parts. In these situations, we want the new charts to remain consistent in scale with the previously unwrapped ones. To achieve this, we simply select one of them as a reference. NOTE: New AutoUV option to Normalize a set of charts using another as reference. It's accessed via RMB option. Thanks to envelupo and Vaughan for the suggestion --- plugins_src/autouv/wpc_autouv.erl | 90 +++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/plugins_src/autouv/wpc_autouv.erl b/plugins_src/autouv/wpc_autouv.erl index 92be1e41..3aa83659 100644 --- a/plugins_src/autouv/wpc_autouv.erl +++ b/plugins_src/autouv/wpc_autouv.erl @@ -615,10 +615,7 @@ command_menu(body, X, Y) -> ?__(3,"Move selected charts")}, {?__(4,"Scale"), {scale, scale_directions(false) ++ [separator] ++ stretch_directions() ++ - [separator, - {?__(411,"Normalize Sizes"), normalize, - ?__(412,"Normalize Chart Sizes so that each" - "chart get it's corresponding 2d area")}]}, + [separator] ++ normalize()}, ?__(5,"Scale selected charts")}, {?__(6,"Rotate"), {rotate,rotate_free(false)}, {?__(7,"Rotate selected charts"),[],?__(59,"Pick rotation center")},[]}, @@ -752,6 +749,12 @@ stretch_directions() -> {?__(3,"Max Horizontal"), max_x, ?__(4,"Maximize horizontally (X dir)")}, {?__(5,"Max Vertical"), max_y, ?__(6,"Maximize vertically (Y dir)")}]. +normalize() -> + [{?__(411,"Normalize Sizes"), normalize_fun(), + {?__(412,"Normalize Chart Sizes so that each " + "chart get it's corresponding 2d area"),[], + ?__(413,"Normalize chart sizes by taking a reference into account")}}]. + move_directions(true) -> [{?__(1,"Free"), free_2d, ?__(2,"Move in both directions"), [magnet]}, {?__(3,"Horizontal"), x, ?__(4,"Move horizontally (X dir)"), [magnet]}, @@ -831,6 +834,12 @@ max_uniform() -> (3, _Ns) -> {auv,{scale,{max_uniform,y}}} end. +normalize_fun() -> + fun + (1, _Ns) -> {auv,{scale,normalize}}; + (3, _Ns) -> {auv,{scale,normalize_ref}} + end. + option_menu() -> [separator, {?__(1,"Create Texture"),create_texture,?__(2,"Make and Attach a texture to the model")}]. @@ -1222,6 +1231,9 @@ handle_command_1({scale,normalize}, St0) -> %% Normalize chart sizes Sh = lists:foldl(Scale, Sh0, List), St = update_selected_uvcoords(St0#st{shapes=Sh}), get_event(St); +handle_command_1({scale,normalize_ref}, St) -> %% Normalize chart sizes using a reference + Sel = wings_sel:selected_ids(St), + wings:ask(normalize_ask(Sel), St, fun normalize_by_ref/2); handle_command_1({scale, {'ASK', Ask}}, St) -> wings:ask(Ask, St, fun({Dir,M},St0) when is_tuple(M), element(1,M) == magnet -> do_drag(wings_scale:setup({Dir,center,M}, St0)); @@ -1510,6 +1522,76 @@ do_drag({drag,Drag}) -> do_drag(Other) -> Other. +normalize_ask(OrigSel) -> + Fun = fun(check, St) -> + case check_selection(OrigSel, St) of + {Result,Msg} -> + {Result,Msg}; + Msg -> + {none,Msg} + end; + (exit, {_,_,St}) -> + case check_selection(OrigSel, St) of + {{_,_,Id},_} -> + {result,Id}; + _ -> + error + end + end, + {[{Fun,?__(1,"Pick the chart to be used as reference")}],[],[],[body]}. + +check_selection(Ids, #st{selmode=Mode}=St) -> + Sel = case Mode of + body -> Ids; + _ -> [] + end, + MF = fun(_Items, #we{id=Id}) -> + case lists:member(Id, Sel) of + true -> + [wrong]; + false -> + [{0,0,Id}] + end; + (_, _) -> + [wrong] + end, + RF = fun erlang:'++'/2, + case wings_sel:dfold(MF, RF, [], St) of + [] -> + ?__(1,"Nothing selected"); + [wrong] -> + ?__(2,"Only unselected charts are allowed"); + [Result] when is_tuple(Result) -> + {Result, ?__(3,"Reference chart picked")}; + [_|_] -> + ?__(4,"Select only one chart") + end. + +normalize_by_ref(RefId, St0) -> + #st{shapes=Sh0, bb=#uvstate{id=Id,st=#st{shapes=Orig}}} = St0, + OWe = gb_trees:get(Id, Orig), + RWe = gb_trees:get(RefId, Sh0), + {RA2D,RA3D,_} = calc_areas(RWe,OWe,{0.0,0.0,[]}), + RScale = RA2D/RA3D, + + {_,_,List} = wings_sel:fold(fun(_,We,Areas) -> + calc_areas(We,OWe,Areas) + end, {0.0,0.0,[]}, St0), + Scale = fun({A2D,A3D,We0 = #we{id=WId}},Sh) -> + Ri = A2D / wings_util:nonzero(A3D), + Scale = math:sqrt(RScale / Ri), + Center = wings_vertex:center(We0), + T0 = e3d_mat:translate(e3d_vec:neg(Center)), + SM = e3d_mat:scale(Scale, Scale, 1.0), + T1 = e3d_mat:mul(SM, T0), + T = e3d_mat:mul(e3d_mat:translate(Center), T1), + We = wings_we:transform_vs(T, We0), + gb_trees:update(WId,We,Sh) + end, + Sh = lists:foldl(Scale, Sh0, List), + St = update_selected_uvcoords(St0#st{shapes=Sh}), + get_event(St). + tighten(#st{selmode=vertex}=St) -> tighten_1(fun vertex_tighten/2, St); tighten(#st{selmode=body}=St) -> From 829a86886ed020265c3cebbc04b2965a0765f5e9 Mon Sep 17 00:00:00 2001 From: micheus Date: Tue, 16 Dec 2025 20:14:11 -0300 Subject: [PATCH 2/2] - Worked on Copilot suggestions --- plugins_src/autouv/wpc_autouv.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins_src/autouv/wpc_autouv.erl b/plugins_src/autouv/wpc_autouv.erl index 3aa83659..5c599175 100644 --- a/plugins_src/autouv/wpc_autouv.erl +++ b/plugins_src/autouv/wpc_autouv.erl @@ -752,7 +752,7 @@ stretch_directions() -> normalize() -> [{?__(411,"Normalize Sizes"), normalize_fun(), {?__(412,"Normalize Chart Sizes so that each " - "chart get it's corresponding 2d area"),[], + "chart get its corresponding 2d area"),[], ?__(413,"Normalize chart sizes by taking a reference into account")}}]. move_directions(true) -> @@ -1572,17 +1572,17 @@ normalize_by_ref(RefId, St0) -> OWe = gb_trees:get(Id, Orig), RWe = gb_trees:get(RefId, Sh0), {RA2D,RA3D,_} = calc_areas(RWe,OWe,{0.0,0.0,[]}), - RScale = RA2D/RA3D, + RScale = RA2D/wings_util:nonzero(RA3D), {_,_,List} = wings_sel:fold(fun(_,We,Areas) -> calc_areas(We,OWe,Areas) end, {0.0,0.0,[]}, St0), Scale = fun({A2D,A3D,We0 = #we{id=WId}},Sh) -> Ri = A2D / wings_util:nonzero(A3D), - Scale = math:sqrt(RScale / Ri), + ScaleFactor = math:sqrt(RScale / wings_util:nonzero(Ri)), Center = wings_vertex:center(We0), T0 = e3d_mat:translate(e3d_vec:neg(Center)), - SM = e3d_mat:scale(Scale, Scale, 1.0), + SM = e3d_mat:scale(ScaleFactor, ScaleFactor, 1.0), T1 = e3d_mat:mul(SM, T0), T = e3d_mat:mul(e3d_mat:translate(Center), T1), We = wings_we:transform_vs(T, We0),