From d6e516de456466c42419ea74d0d2c1a8305b0f90 Mon Sep 17 00:00:00 2001 From: micheus Date: Sat, 4 Oct 2025 05:53:33 -0300 Subject: [PATCH] Updated the Align to Target command adding new options It was discussed about this command at Discord where some users asked for it to be used to directly align an object to the regular axis (X,Y,Z) working similar to PutOn. I realise when I first implemented it that it was a missing feature that could speeded up that operation. I also reorgnized the code by better naming the functions and moving the option to the context menu for body selection mode - just next to the Absolute Commands, instead of inside it. That give it more visibility to new users and also seems to be the appropriated place by considering the kind of operations that are under that option. NOTE: Updated the 'Align To Target' command with new options. It's now called 'Align To' and it was put out of the 'Absolute Commands' option. Thanks to envelupo, Vaughan, Arclite and LLugnuto779 --- plugins_src/commands/wpc_align_to_axis.erl | 225 +++++++++++++++------ 1 file changed, 160 insertions(+), 65 deletions(-) diff --git a/plugins_src/commands/wpc_align_to_axis.erl b/plugins_src/commands/wpc_align_to_axis.erl index b3a2c9b0..29cf44e5 100644 --- a/plugins_src/commands/wpc_align_to_axis.erl +++ b/plugins_src/commands/wpc_align_to_axis.erl @@ -18,71 +18,123 @@ init() -> true. %%%% Menu -menu({Mode,absolute},Menu) when Mode =:= body -> - [Menu|[separator,align_to_axis_menu()]]; +menu({Mode},Menu) when Mode=:=body -> + parse(Menu, Mode); menu(_,Menu) -> Menu. -align_to_axis_menu() -> - {?__(2,"Align to Target"), {rotate_to_axis, fun align_to_axis_options/2},[],[]}. +parse(Menu, Mode) -> + lists:reverse(parse(Menu, Mode, [], false)). -align_to_axis_options(help, _) -> - {?__(1,"Rotate around specified center by an angle defined by Vector A and a default axis"), [], - ?__(2,"Rotate around specified center by an angle defined by Vector A and Vector B")}; -align_to_axis_options(1, _Ns) -> - rotate_def_axis(); -align_to_axis_options(3, _Ns) -> - {body,{rotate_to_axis,{'ASK',[center,point_A,point_B,point_C,point_D]}}}; -align_to_axis_options(_,_) -> +parse([], _, NewMenu, true) -> + NewMenu; +parse([{_, {absolute, _}}=AbsCMD|Rest], Mode, NewMenu, false) -> + parse(Rest, Mode, [align_to_menu()|[AbsCMD|NewMenu]], true); +parse([Elem|Rest], Mode, NewMenu, Found) -> + parse(Rest, Mode, [Elem|NewMenu], Found). + +align_to_menu() -> + [{?__(2,"Align to"), {align_to, align_to_axis()}}]. + +align_to_axis() -> + RotAxisStrL = ?__(1,"Align the object to ~s axis by using a reference axis"), + RotAxisStrR = ?__(2,"Align the object to ~s axis by setting the reference direction"), + [{wings_s:dir(x),align_to_axis_fun(x), {io_lib:format(RotAxisStrL, [wings_s:dir(x)]),[], + io_lib:format(RotAxisStrR, [wings_s:dir(x)])}}, + {wings_s:dir(y),align_to_axis_fun(y), {io_lib:format(RotAxisStrL, [wings_s:dir(y)]),[], + io_lib:format(RotAxisStrR, [wings_s:dir(y)])}}, + {wings_s:dir(z),align_to_axis_fun(z), {io_lib:format(RotAxisStrL, [wings_s:dir(z)]),[], + io_lib:format(RotAxisStrR, [wings_s:dir(z)])}}, + separator, + {?__(3,"Target"), {target, fun align_to_target_opt/2},[],[]}]. + +align_to_target_opt(help, _) -> + {?__(1,"Rotate around the specified center by an angle defined by the reference vector and a default axis"), [], + ?__(2,"Rotate around the specified center using an angle defined by the reference and target vectors")}; +align_to_target_opt(1, _Ns) -> + align_to_target(); +align_to_target_opt(3, _Ns) -> + {body,{align_to_target,{'ASK',[center,point_A,point_B,point_C,point_D]}}}; +align_to_target_opt(_,_) -> ignore. -rotate_def_axis() -> +align_to_target() -> RotAxisStr = ?__(1,"Align the vector to ~s axis"), OrientAxisStr = ?__(2,"Point the vector to ~s axis"), - [{wings_s:dir(x),rotate_def_fun(x), {io_lib:format(RotAxisStr, [wings_s:dir(x)]), [], - io_lib:format(OrientAxisStr, [wings_s:dir(x)])}}, - {wings_s:dir(y),rotate_def_fun(y), {io_lib:format(RotAxisStr, [wings_s:dir(y)]), [], - io_lib:format(OrientAxisStr, [wings_s:dir(y)])}}, - {wings_s:dir(z),rotate_def_fun(z), {io_lib:format(RotAxisStr, [wings_s:dir(z)]), [], - io_lib:format(OrientAxisStr, [wings_s:dir(z)])}}]. + [{wings_s:dir(x),align_to_target_fun(x), {io_lib:format(RotAxisStr, [wings_s:dir(x)]), [], + io_lib:format(OrientAxisStr, [wings_s:dir(x)])}}, + {wings_s:dir(y),align_to_target_fun(y), {io_lib:format(RotAxisStr, [wings_s:dir(y)]), [], + io_lib:format(OrientAxisStr, [wings_s:dir(y)])}}, + {wings_s:dir(z),align_to_target_fun(z), {io_lib:format(RotAxisStr, [wings_s:dir(z)]), [], + io_lib:format(OrientAxisStr, [wings_s:dir(z)])}}]. -rotate_def_fun(Axis) -> +align_to_target_fun(Axis) -> fun - (1,_Ns) -> {body,{{rotate_to_axis,{lmb,Axis}},{'ASK',[center,point_A,point_B]}}}; -%% (2,_Ns) -> {body,{{rotate_to_axis,Axis},{'ASK',[center,point_A,point_B]}}}; - (3,_Ns) -> {body,{{rotate_to_axis,{rmb,Axis}},{'ASK',[center,vector]}}}; + (1,_Ns) -> {body,{{align_to_target,{lmb,Axis}},{'ASK',[center,point_A,point_B]}}}; + (3,_Ns) -> {body,{{align_to_target,{rmb,Axis}},{'ASK',[center,vector]}}}; + (_,_) -> ignore + end. + +align_to_axis_fun(Axis) -> + fun + (1,_Ns) -> {body,{{align_to_axis,{lmb,Axis}},{'ASK',[axis_point]}}}; + (3,_Ns) -> {body,{{align_to_axis,{rmb,Axis}},{'ASK',[center,point_A,point_B]}}}; (_,_) -> ignore end. %%%% Commands -command({_,{{rotate_to_axis,{lmb,Axis}},{'ASK',Ask}}}, St) -> +command({_,{{align_to_target,{lmb,Axis}},{'ASK',Ask}}}, St) -> wings:ask(selection_ask(Ask), St, case Axis of - x -> fun rotate_axis_x_lmb/2; - y -> fun rotate_axis_y_lmb/2; - z -> fun rotate_axis_z_lmb/2 + x -> fun rot_target_x_lmb/2; + y -> fun rot_target_y_lmb/2; + z -> fun rot_target_z_lmb/2 end); -command({_,{{rotate_to_axis,{lmb,Axis}},Data}}, St) -> +command({_,{{align_to_target,{lmb,Axis}},Data}}, St) -> case Axis of - x -> rotate_axis_x_lmb(Data,St); - y -> rotate_axis_y_lmb(Data,St); - z -> rotate_axis_z_lmb(Data,St) + x -> rot_target_x_lmb(Data,St); + y -> rot_target_y_lmb(Data,St); + z -> rot_target_z_lmb(Data,St) end; -command({_,{{rotate_to_axis,{rmb,Axis}},{'ASK',Ask}}}, St) -> +command({_,{{align_to_target,{rmb,Axis}},{'ASK',Ask}}}, St) -> wings:ask(selection_ask(Ask), St, case Axis of - x -> fun rotate_axis_x_rmb/2; - y -> fun rotate_axis_y_rmb/2; - z -> fun rotate_axis_z_rmb/2 + x -> fun rot_target_x_rmb/2; + y -> fun rot_target_y_rmb/2; + z -> fun rot_target_z_rmb/2 end); -command({_,{{rotate_to_axis,{rmb,Axis}},Data}}, St) -> +command({_,{{align_to_target,{rmb,Axis}},Data}}, St) -> case Axis of - x -> rotate_axis_x_rmb(Data,St); - y -> rotate_axis_y_rmb(Data,St); - z -> rotate_axis_z_rmb(Data,St) + x -> rot_target_x_rmb(Data,St); + y -> rot_target_y_rmb(Data,St); + z -> rot_target_z_rmb(Data,St) + end; +command({_,{align_to_target,{'ASK',Ask}}}, St) -> + wings:ask(selection_ask(Ask), St, fun rot_target_setup/2); +command({_,{align_to_target,Data}}, St) -> + rot_target_setup(Data,St); +command({_,{{align_to_axis,{lmb,Axis}},{'ASK',Ask}}}, St) -> + wings:ask(selection_ask(Ask), St, case Axis of + x -> fun rot_axis_x_lmb/2; + y -> fun rot_axis_y_lmb/2; + z -> fun rot_axis_z_lmb/2 + end); +command({_,{{align_to_axis,{lmb,Axis}},Data}}, St) -> + case Axis of + x -> rot_axis_x_lmb(Data,St); + y -> rot_axis_y_lmb(Data,St); + z -> rot_axis_z_lmb(Data,St) + end; +command({_,{{align_to_axis,{rmb,Axis}},{'ASK',Ask}}}, St) -> + wings:ask(selection_ask(Ask), St, case Axis of + x -> fun rot_axis_x_rmb/2; + y -> fun rot_axis_y_rmb/2; + z -> fun rot_axis_z_rmb/2 + end); +command({_,{{align_to_axis,{rmb,Axis}},Data}}, St) -> + case Axis of + x -> rot_axis_x_rmb(Data,St); + y -> rot_axis_y_rmb(Data,St); + z -> rot_axis_z_rmb(Data,St) end; -command({_,{rotate_to_axis,{'ASK',Ask}}}, St) -> - wings:ask(selection_ask(Ask), St, fun rotate_axis_setup/2); -command({_,{rotate_to_axis,Data}}, St) -> - rotate_axis_setup(Data,St); command(_Ev,_) -> next. @@ -96,38 +148,41 @@ selection_ask([center|Rest],Ask) -> Desc = ?__(1,"Pick center of rotation"), selection_ask(Rest,[{point,Desc}|Ask]); selection_ask([point_A|Rest],Ask) -> - Desc = ?__(2,"Pick Point A for Vector A"), + Desc = ?__(2,"Pick Point A for reference vector"), selection_ask(Rest,[{point,Desc}|Ask]); selection_ask([point_B|Rest],Ask) -> - Desc = ?__(3,"Pick Point B for Vector A"), + Desc = ?__(3,"Pick Point B for reference vector"), selection_ask(Rest,[{point,Desc}|Ask]); selection_ask([point_C|Rest],Ask) -> - Desc = ?__(4,"Pick Point A for Vector B"), + Desc = ?__(4,"Pick Point A for target vector"), selection_ask(Rest,[{point,Desc}|Ask]); selection_ask([point_D|Rest],Ask) -> - Desc = ?__(5,"Pick Point B for Vector B"), + Desc = ?__(5,"Pick Point B for target vector"), selection_ask(Rest,[{point,Desc}|Ask]); selection_ask([vector|Rest],Ask) -> - Desc = ?__(6,"Pick the vector"), - selection_ask(Rest,[{axis_point,Desc}|Ask]). + Desc = ?__(6,"Pick the reference vector"), + selection_ask(Rest,[{axis_point,Desc}|Ask]); +selection_ask([axis_point|Rest],Ask) -> + Desc = ?__(7,"Pick the reference axis"), + selection_ask(Rest,[{axis,Desc}|Ask]). -%%%% Setup +%%%% Setup Align to Target %%%% LMB -rotate_axis_x_lmb({Center,A,B},St) -> - rotate_axis_lmb({x,Center,A,B},St). -rotate_axis_y_lmb({Center,A,B},St) -> - rotate_axis_lmb({y,Center,A,B},St). -rotate_axis_z_lmb({Center,A,B},St) -> - rotate_axis_lmb({z,Center,A,B},St). - -rotate_axis_x_rmb({Center,Normal,_CNormal},St) -> +rot_target_x_lmb({Center,A,B},St) -> + rot_target_lmb({x,Center,A,B},St). +rot_target_y_lmb({Center,A,B},St) -> + rot_target_lmb({y,Center,A,B},St). +rot_target_z_lmb({Center,A,B},St) -> + rot_target_lmb({z,Center,A,B},St). +%%%% RMB +rot_target_x_rmb({Center,Normal,_CNormal},St) -> rotate_vector_rmb({x,Normal,Center},St). -rotate_axis_y_rmb({Center,Normal,_CNormal},St) -> +rot_target_y_rmb({Center,Normal,_CNormal},St) -> rotate_vector_rmb({y,Normal,Center},St). -rotate_axis_z_rmb({Center,Normal,_CNormal},St) -> +rot_target_z_rmb({Center,Normal,_CNormal},St) -> rotate_vector_rmb({z,Normal,Center},St). -rotate_axis_lmb({Axis0,Center,A,B},St) -> +rot_target_lmb({Axis0,Center,A,B},St) -> Vec0 = e3d_vec:sub(B,A), Vec = e3d_vec:norm(project(Axis0,Vec0)), Axis = wings_util:make_vector(Axis0), @@ -177,7 +232,7 @@ rotate_vector_rmb({Axis,Vec,Center}, St) -> end. %%%% LMB -rotate_axis_setup({Center,A,B,C,D},St) -> +rot_target_setup({Center,A,B,C,D},St) -> VecD0 = e3d_vec:sub(D,C), %% checking if the Destination vector is laying on a system axis (X/Y/Z) DAxis0 = e3d_vec:largest_dir(VecD0), @@ -185,8 +240,8 @@ rotate_axis_setup({Center,A,B,C,D},St) -> case OnAxis of true -> case e3d_vec:plane_side(VecD0,{wings_util:make_vector(DAxis0),0.0}) of - 1 -> rotate_axis_lmb({DAxis0,Center,A,B},St); - -1 -> rotate_axis_lmb({DAxis0,Center,B,A},St) + 1 -> rot_target_lmb({DAxis0,Center,A,B},St); + -1 -> rot_target_lmb({DAxis0,Center,B,A},St) end; false -> VecS = e3d_vec:norm(e3d_vec:sub(B,A)), @@ -226,9 +281,49 @@ rotate_axis_setup({Center,A,B,C,D},St) -> end end. +%%%% Setup Align to Target +%%%% LMB +rot_axis_x_lmb(A,St) -> + rot_axis({x,center,A},St). +rot_axis_y_lmb(A,St) -> + rot_axis({y,center,A},St). +rot_axis_z_lmb(A,St) -> + rot_axis({z,center,A},St). + +%%%% RMB +rot_axis_x_rmb({Center,A,B},St) -> + rot_axis({x,Center,e3d_vec:sub(B,A)},St). +rot_axis_y_rmb({Center,A,B},St) -> + rot_axis({y,Center,e3d_vec:sub(B,A)},St). +rot_axis_z_rmb({Center,A,B},St) -> + rot_axis({z,Center,e3d_vec:sub(B,A)},St). + +rot_axis({Axis0,Center,A},St) -> + Vec = e3d_vec:norm(A), + Axis = wings_util:make_vector(Axis0), + RotAxis0 = e3d_vec:norm(e3d_vec:cross(Vec,Axis)), + Valid = valid_vec(RotAxis0), + RotAxis = + if not Valid -> + if (Axis0=:=x) or (Axis0=:=z) -> + wings_util:make_vector(y); + true -> + wings_util:make_vector(z) + end; + true -> RotAxis0 + end, + Deg = e3d_vec:degrees(Axis,Vec), + Mr = e3d_mat:rotate(Deg, RotAxis), + rotate_axis(Center, Mr, St). + %%%% Rotate functions -rotate_axis(Center, Mr, St0) -> +rotate_axis(Center0, Mr, St0) -> F = fun(_, #we{vp=Vtab0}=We, Acc0) -> + Center = + case Center0 of + center -> wings_we:centroid(We); + _ -> Center0 + end, VsPos0 = array:sparse_to_orddict(Vtab0), VsPos1 = rotate_axis_fun(Center, Mr, VsPos0), Vtab = array:from_orddict(VsPos1),