1%% 2%% wpc_arc_intersect.erl -- Rotate to Target 3%% 4%% Plugin to rotate selected element to intersect with a secondary selection 5%% 6%% Copyright (c) 2008-2011 Richard Jones. 7%% 8%% See the file "license.terms" for information on usage and redistribution 9%% of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10%% 11%% 12 13-module(wpc_arc_intersect). 14-export([init/0,menu/2,command/2]). 15-include_lib("src/wings.hrl"). 16 17init() -> 18 true. 19 20%%%% Menu 21menu({Mode,rotate},Menu) when Mode =:= vertex; Mode =:= edge; Mode =:= face; Mode =:= body -> 22 [Menu|[separator,arc_intersect_menu(Mode)]]; 23menu(_,Menu) -> 24 Menu. 25 26arc_intersect_menu(Mode) -> 27 Help = {?__(2,"Rotate around specified center from Point A to Point B"), 28 ?__(3,"Rotate Point to Plane"), 29 ?__(4,"Rotate around specified center by an angle defined by Vector A and Vector B")}, 30 {?__(1,"Rotate to Target"), 31 {arc_intersect, arc_intersect_options(Mode, Help)},magnet_possible(Mode)}. 32 33magnet_possible(body) -> []; 34magnet_possible(_) -> [magnet]. 35 36arc_intersect_options(body, Help) -> 37 fun 38 (help,_) -> Help; 39 (1,_Ns) -> {body,{arc_intersect,{lmb,{'ASK',[rotation_axis,center,point_A,point_B]}}}}; 40 (2,_Ns) -> {body,{arc_intersect,{mmb,{'ASK',[rotation_axis,center,point,plane]}}}}; 41 (3,_Ns) -> {body,{arc_intersect,{rmb,{'ASK',[rotation_axis,center,plane_A,plane_B]}}}}; 42 (_,_) -> ignore 43 end; 44arc_intersect_options(Mode, Help) -> 45 fun 46 (help,_) -> Help; 47 (1,_Ns) -> {Mode,{arc_intersect,{lmb,{'ASK',{[rotation_axis,center,point_A,point_B],[],[magnet]}}}}}; 48 (2,_Ns) -> {Mode,{arc_intersect,{mmb,{'ASK',{[rotation_axis,center,point,plane],[],[magnet]}}}}}; 49 (3,_Ns) -> {Mode,{arc_intersect,{rmb,{'ASK',{[rotation_axis,center,plane_A,plane_B],[],[magnet]}}}}}; 50 (_,_) -> ignore 51 end. 52 53%%%% Commands 54command({_,{arc_intersect,{lmb,{'ASK',Ask}}}},St) -> 55 wings:ask(selection_ask(Ask), St, fun arc_intersect_setup/2); 56command({_,{arc_intersect,{lmb,Data}}},St) -> 57 arc_intersect_setup(Data,St); 58 59command({_,{arc_intersect,{mmb,{'ASK',Ask}}}},St) -> 60 wings:ask(selection_ask(Ask), St, fun arc_intersect_point_to_plane_setup/2); 61command({_,{arc_intersect,{mmb,Data}}},St) -> 62 arc_intersect_point_to_plane_setup(Data,St); 63 64command({_,{arc_intersect,{rmb,{'ASK',Ask}}}},St) -> 65 wings:ask(selection_ask(Ask), St, fun arc_intersect_plane_setup/2); 66command({_,{arc_intersect,{rmb,Data}}},St) -> 67 arc_intersect_plane_setup(Data,St); 68 69command(_,_) -> 70 next. 71 72%%%% Asks 73selection_ask({Asks,_,_}) -> 74 selection_ask(Asks); 75selection_ask(Asks) -> 76 Ask = selection_ask(Asks,[]), 77 {Ask,[],[],[vertex, edge, face]}. 78selection_ask([],Ask) -> lists:reverse(Ask); 79 80selection_ask([rotation_axis|Rest],Ask) -> 81 Desc = ?__(1,"Pick rotation axis"), 82 selection_ask(Rest,[{axis,Desc}|Ask]); 83selection_ask([center|Rest],Ask) -> 84 Desc = ?__(2,"Pick center of rotation"), 85 selection_ask(Rest,[{point,Desc}|Ask]); 86 87selection_ask([point_A|Rest],Ask) -> 88 Desc = ?__(3,"Pick Point A"), 89 selection_ask(Rest,[{point,Desc}|Ask]); 90selection_ask([point_B|Rest],Ask) -> 91 Desc = ?__(4,"Pick Point B"), 92 selection_ask(Rest,[{point,Desc}|Ask]); 93 94selection_ask([plane_A|Rest],Ask) -> 95 Desc = ?__(5,"Pick Vector A"), 96 selection_ask(Rest,[{axis,Desc}|Ask]); 97selection_ask([plane_B|Rest],Ask) -> 98 Desc = ?__(6,"Pick Vector B"), 99 selection_ask(Rest,[{axis,Desc}|Ask]); 100 101selection_ask([point|Rest],Ask) -> 102 Desc = ?__(7,"Pick Point"), 103 selection_ask(Rest,[{point,Desc}|Ask]); 104selection_ask([plane|Rest],Ask) -> 105 Desc = ?__(8,"Pick Plane"), 106 selection_ask(Rest,[{axis,Desc}|Ask]); 107 108selection_ask([magnet|Rest],Ask) -> 109 selection_ask(Rest,[magnet|Ask]). 110 111%%%% Setup 112%%%% LMB 113arc_intersect_setup({Axis,Center,A,B},St) -> 114 arc_intersect_setup({Axis,Center,A,B,none},St); 115 116arc_intersect_setup({Axis,Center,A,B,Mag},#st{selmode=body}=St) when Mag =/= none -> 117 arc_intersect_setup({Axis,Center,A,B,none},St); 118 119arc_intersect_setup({Axis,Center,A,B,Mag},St) -> 120 VecA = double_cross(Center,A,Axis), 121 VecB = double_cross(Center,B,Axis), 122 Deg = e3d_vec:degrees(VecA,VecB), 123 finish_setup(Axis, Center, Deg, Mag, St). 124 125%%%% MMB 126arc_intersect_point_to_plane_setup({Axis,Center,A,B},St) -> 127 arc_intersect_point_to_plane_setup({Axis,Center,A,B,none},St); 128 129arc_intersect_point_to_plane_setup({Axis,Center,A,B,Mag},#st{selmode=body}=St) when Mag =/= none -> 130 arc_intersect_point_to_plane_setup({Axis,Center,A,B,none},St); 131 132arc_intersect_point_to_plane_setup({Axis,Center,A,B,Mag},St) -> 133 VecA = double_cross(Center,A,Axis), 134 VecB = e3d_vec:cross(Axis,B), 135 Deg = e3d_vec:degrees(VecA,VecB), 136 finish_setup(Axis, Center, Deg, Mag, St). 137 138%%%% RMB 139arc_intersect_plane_setup({Axis,Center,A,B},St) -> 140 arc_intersect_plane_setup({Axis,Center,A,B,none},St); 141 142arc_intersect_plane_setup({Axis,Center,A,B,Mag},#st{selmode=body}=St) when Mag =/= none -> 143 arc_intersect_plane_setup({Axis,Center,A,B,none},St); 144 145arc_intersect_plane_setup({Axis,Center,A,B,Mag},St) -> 146 Deg = e3d_vec:degrees(A, B), 147 finish_setup(Axis, Center, Deg, Mag, St). 148 149finish_setup(Axis, Center, Deg, Mag, #st{selmode=Selmode}=St0) -> 150 St = case Selmode of 151 vertex -> St0; 152 _Other -> wings_sel_conv:mode(vertex,St0) 153 end, 154 MagType = magnet_type(Mag), 155 State = {none,MagType,{reciprocal,false}}, 156 Units = [percent|magnet_unit(Mag)], 157 Flags = [{mode,{arc_intersect_modes(Mag),State}}], 158 wings_drag:fold( 159 fun(Vs0, We) -> 160 Vs = gb_sets:to_list(Vs0), 161 finish_setup_1(Vs, We, Axis, Center, Deg, Mag, State) 162 end, Units, Flags, St). 163 164finish_setup_1(Vs, We, Axis, Center, Deg, none, State) -> 165 VsPos = wings_util:add_vpos(Vs, We), 166 {Vs,arc_intersect_fun(Axis, Center, Deg, VsPos, none, State)}; 167finish_setup_1(Vs, We, Axis, Center, Deg, Mag, State) -> 168 {VsInf,Magnet,Affected} = wings_magnet:setup(Mag, Vs, We), 169 {Affected,arc_intersect_fun(Axis, Center, Deg, VsInf, Magnet, State)}. 170 171magnet_unit(none) -> []; 172magnet_unit(_) -> [falloff]. 173 174magnet_type(none) -> none; 175magnet_type({_,Type,_,_}) -> Type. 176 177arc_intersect_modes(none) -> 178 fun 179 (help, State) -> arc_intersect_mode_help(State); 180 ({key,$1},{none,none,{reciprocal,false}}) -> {none,none,{reciprocal,true}}; 181 ({key,$1},{none,none,{reciprocal,true}}) -> {none,none,{reciprocal,false}}; 182 (_,_) -> none 183 end; 184 185arc_intersect_modes(_) -> 186 fun 187 (help, State) -> arc_intersect_mode_help(State); 188 ({key,$5},{none,_Type,{reciprocal,false}}) -> {none,_Type,{reciprocal,true}}; 189 ({key,$5},{none,_Type,{reciprocal,true}}) -> {none,_Type,{reciprocal,false}}; 190 ({key, K},{none,_Type,_Recip}) when K =:= $1; K =:= $2; K =:= $3; K =:= $4 -> 191 {none,wings_magnet:hotkey(K),_Recip}; 192 (done,{none,Type,_Recip}) -> wings_pref:set_value(magnet_type, Type); 193 (_,_) -> none 194 end. 195 196arc_intersect_mode_help({_,none,{_,Flip}}) -> 197 ?__(1,"[1] ") ++ flip_help_1(Flip); 198arc_intersect_mode_help({_,Type,{_,Flip}}) -> 199 wings_magnet:drag_help(Type)++flip_help(Flip). 200flip_help(Flip) -> 201 ?__(1," [5] ") ++ flip_help_1(Flip). 202flip_help_1(true) -> 203 ?__(1,"Flip Angle"); 204flip_help_1(false) -> 205 ?__(2,"Flip Back"). 206 207arc_intersect_fun(Axis,Center,Deg,VsPos,none,State) -> 208 fun 209 (new_mode_data,{NewState,_}) -> 210 arc_intersect_fun(Axis,Center,Deg,VsPos,none,NewState); 211 ([Percent|_], A) -> 212 lists:foldl(fun({V,Vpos}, VsAcc) -> 213 [{V,arc_intersect(Axis,Center,Deg,Vpos,State,Percent)}|VsAcc] 214 end, A, VsPos) 215 end; 216 217arc_intersect_fun(Axis,Center,Deg,VsInf0,{_,R}=Magnet0,State0) -> 218 fun 219 (new_falloff, Falloff) -> 220 VsInf = wings_magnet:recalc(Falloff, VsInf0, Magnet0), 221 arc_intersect_fun(Axis,Center,Deg,VsInf,Magnet0,State0); 222 223 %% Magnet Type Switch 224 (new_mode_data, {State, Falloff}) -> 225 {_,MagType,_} = State, 226 Magnet = {MagType,R}, 227 VsInf = wings_magnet:recalc(Falloff, VsInf0, Magnet), 228 arc_intersect_fun(Axis,Center,Deg,VsInf,Magnet,State); 229 230 ([Percent|_], A) -> 231 lists:foldl(fun({V,Vpos,_,Inf}, Acc) -> 232 [{V,arc_intersect(Axis,Center,Deg,Vpos,State0,Percent*Inf)}|Acc] 233 end, A, VsInf0) 234 end. 235 236 237arc_intersect(_Axis,_Center,_Deg,Vpos,_State,0.0) -> 238 Vpos; 239 240arc_intersect(Axis,Center,Deg,Vpos,_State,Percent) when Deg =:= 0.0; Deg =:= 180.0 -> 241 Rotate = 180.0 * Percent, 242 rotate(Vpos,Axis,Center,Rotate); 243 244arc_intersect(Axis,Center,Deg,Vpos,{_,_,{_,false}},Percent) when Percent < 0.0 -> 245 Rotate = Deg * Percent, 246 rotate(Vpos,Axis,Center,Rotate); 247 248arc_intersect(Axis,Center,Deg,Vpos,{_,_,{_,false}},Percent) when Percent > 0.0 -> 249 Rotate = (180.0 - Deg) * Percent, 250 rotate(Vpos,Axis,Center,Rotate); 251 252arc_intersect(Axis,Center,Deg,Vpos,{_,_,{_,true}},Percent) when Percent < 0.0 -> 253 Rotate = (180.0 - Deg) * Percent, 254 rotate(Vpos,Axis,Center,Rotate); 255 256arc_intersect(Axis,Center,Deg,Vpos,{_,_,{_,true}},Percent) when Percent > 0.0 -> 257 Rotate = Deg * Percent, 258 rotate(Vpos,Axis,Center,Rotate). 259 260%%%% Utilities 261double_cross(Center,Point,Axis) -> 262 Vec0 = e3d_vec:sub(Center,Point), 263 Vec1 = e3d_vec:cross(Vec0, Axis), 264 e3d_vec:cross(Vec1, Axis). 265 266rotate(Vpos,Axis,{Cx,Cy,Cz},Angle) -> 267 %% return new position as {x,y,z} 268 A0 = e3d_mat:translate(Cx,Cy,Cz), 269 A1 = e3d_mat:mul(A0, e3d_mat:rotate(Angle, Axis)), 270 A2 = e3d_mat:mul(A1, e3d_mat:translate(-Cx,-Cy,-Cz)), 271 e3d_mat:mul_point(A2,Vpos). 272