1%% 2%% wpc_explode.erl -- 3%% 4%% Explode scales distances between whole objects. 5%% Includes standard, user axes, radial and uniform options. 6%% 7%% Copyright (c) 2010-2011 Richard Jones. 8%% 9%% See the file "license.terms" for information on usage and redistribution 10%% of this file, and for a DISCLAIMER OF ALL WARRANTIES. 11%% 12 13-module(wpc_explode). 14-export([init/0,menu/2,command/2]). 15-include_lib("src/wings.hrl"). 16 17-import(lists, [reverse/1]). 18 19init() -> 20 true. 21 22%%% 23%%% Insert menu heading 24%%% 25 26menu({body},Menu) -> 27 reverse(parse(Menu, [], false)); 28menu(_,Menu) -> 29 Menu. 30 31parse([{_,{flip,_}}=A|Rest], NewMenu, false) -> 32 parse(Rest, [menu_heading(),A|NewMenu], true); 33parse([Elem|Rest], NewMenu, Found) -> 34 parse(Rest, [Elem|NewMenu], Found); 35parse([], NewMenu, true) -> 36 NewMenu; 37parse([], NewMenu, false) -> 38 [menu_heading()|NewMenu]. 39 40menu_heading() -> 41 {?__(1,"Explode"),{explode,explode_menu()}}. 42 43%%% 44%%% Build menus 45%%% 46 47explode_menu() -> 48 fun(help,_) -> 49 {?__(1,"Space objects along a standard axis relative to a point"), 50 ?__(2,"Pick axis and point"), 51 ?__(3,"Pick axis and explode from midpoint of the selection")}; 52 (1,_) -> standard_axes(); 53 (2,_) -> {body,{explode,{'ASK',[axis,point]}}}; 54 (3,_) -> {body,{explode,{'ASK',[axis]}}}; 55 (_,_) -> ignore 56 end. 57 58standard_axes() -> 59 [axis_menu(x), 60 axis_menu(y), 61 axis_menu(z), 62 separator, 63 axis_menu(uniform), 64 axis_menu(radial), 65 separator, 66 axis_menu(last_axis), 67 axis_menu(default_axis)]. 68 69axis_menu(radial) -> 70 AxisStr = ?__(6,"Radial"), 71 Fun = fun 72 (help,_) -> 73 {?__(3,"Explode objects along radial of standard axis"), 74 ?__(4,"Pick radial and point"), 75 ?__(5,"Pick radial and explode from midpoint of the selection")}; 76 (1,_) -> radial_axis(); 77 (2,_) -> {body,{explode_radial,{'ASK',[axis,point]}}}; 78 (3,_) -> {body,{explode_radial,{'ASK',[axis]}}}; 79 (_,_) -> ignore 80 end, 81 {AxisStr,{explode_radial,Fun}}; 82axis_menu(uniform) -> 83 AxisStr = wings_s:dir(uniform), 84 Fun = fun 85 (help,_) -> 86 {?__(7,"Explode objects uniformly from midpoint of the selection"),[], 87 ?__(2,"Pick point")}; 88 (1,_) -> {body,explode_uniform}; 89 (3,_) -> {body,{explode_uniform,{'ASK',[point]}}}; 90 (_,_) -> ignore 91 end, 92 {AxisStr,{explode_uniform,Fun}}; 93axis_menu(Axis) -> 94 AxisStr = wings_util:cap(wings_s:dir(Axis)), 95 Fun = fun 96 (help,_) -> 97 Help0 = ?__(1,"Explode objects along ~s axis from midpoint of the selection"), 98 Help = wings_util:format(Help0, [AxisStr]), 99 {Help, [], ?__(2,"Pick point")}; 100 (1,_) -> {body,{explode,Axis}}; 101 (3,_) -> {body,{explode,{Axis,{'ASK',[point]}}}}; 102 (_,_) -> ignore 103 end, 104 {AxisStr,{explode,Fun}}. 105 106radial_axis() -> 107 [radial_menu(x), 108 radial_menu(y), 109 radial_menu(z), 110 separator, 111 radial_menu(last_axis), 112 radial_menu(default_axis)]. 113 114radial_menu(Axis) -> 115 AxisStr = wings_util:cap(wings_s:dir({radial,Axis})), 116 Fun = fun 117 (help,_) -> 118 Help0 = ?__(1,"Explode objects along radial of ~s axis"), 119 Help = wings_util:format(Help0, [AxisStr]), 120 {Help,[],?__(2,"Pick point")}; 121 (1,_) -> {body,{explode_radial,Axis}}; 122 (3,_) -> {body,{explode_radial,{Axis,{'ASK',[point]}}}}; 123 (_,_) -> ignore 124 end, 125 {AxisStr,{explode_radial,Fun}}. 126 127%%% 128%%% Commands 129%%% 130 131%% Explode Axis commands 132command({body,{explode,{Axis,{'ASK',Ask}}}}, St) -> 133 wings:ask({Ask,[]}, St, fun (Res,St0) -> 134 explode({Axis,Res}, St0) 135 end); 136command({body,{explode,{'ASK',Ask}}}, St) -> 137 wings:ask({Ask,[]}, St, fun 138 ({_,_}=Res,St0) -> explode(Res, St0); 139 (Axis,St0)-> 140 Center = wings_sel:center(St0), 141 explode({Axis,Center}, St0) 142 end); 143command({body,{explode,{Axis,Point}}}, St) -> 144 explode({Axis,Point}, St); 145command({body,{explode,Axis}}, St) -> 146 Center = wings_sel:center(St), 147 explode({Axis,Center}, St); 148%% Explode Radial commands 149command({body,{explode_radial,{Axis,{'ASK',Ask}}}}, St) -> 150 wings:ask({Ask,[]}, St, fun (Res,St0) -> 151 explode_radial({Axis,Res}, St0) 152 end); 153command({body,{explode_radial,{'ASK',Ask}}}, St) -> 154 wings:ask({Ask,[]}, St, fun 155 ({_,_}=Res,St0) -> 156 explode_radial(Res, St0); 157 (Axis,St0)-> 158 Center = wings_sel:center(St0), 159 explode_radial({Axis,Center}, St0) 160 end); 161command({body,{explode_radial,{Axis,Point}}}, St) -> 162 explode_radial({Axis,Point}, St); 163command({body,{explode_radial,Axis}}, St) -> 164 Center = wings_sel:center(St), 165 explode_radial({Axis,Center}, St); 166%% Explode Uniform commands 167command({body,{explode_uniform,{'ASK',Ask}}}, St) -> 168 wings:ask({Ask,[]}, St, fun (Point,St0) -> 169 explode_uniform(Point, St0) 170 end); 171command({body,{explode_uniform,Point}}, St) -> 172 explode_uniform(Point, St); 173command({body,explode_uniform}, St) -> 174 Center = wings_sel:center(St), 175 explode_uniform(Center, St); 176command(_,_) -> next. 177 178%%% 179%%% Process commands 180%%% 181 182%% Explode 183explode({Axis0,Point}, St) -> 184 Axis = wings_util:make_vector(Axis0), 185 wings_drag:matrix( 186 fun(We) -> 187 Center = wings_vertex:center(We), 188 explode_fun(Axis, Point, Center) 189 end, [percent], St). 190 191%% Explode Uniform 192explode_uniform(Point, St) -> 193 wings_drag:matrix( 194 fun(We) -> 195 Center = wings_vertex:center(We), 196 explode_uniform_fun(Point, Center) 197 end, [percent], St). 198 199%% Explode Radial 200explode_radial({Axis0,Point}, St) -> 201 Axis = wings_util:make_vector(Axis0), 202 wings_drag:matrix( 203 fun(We) -> 204 Center = wings_vertex:center(We), 205 explode_radial_fun(Axis, Point, Center) 206 end, [percent], St). 207 208 209%%% 210%%% Explode fun 211%%% 212 213explode_fun(Axis, Point, Center) -> 214 Dist = dist_along_vector(Center, Point, Axis), 215 fun(Matrix, [Percent]) -> 216 ScaledAxis = e3d_vec:mul(Axis, Percent * Dist), 217 TransVec = e3d_mat:mul_point(Matrix, ScaledAxis), 218 e3d_mat:translate(TransVec) 219 end. 220 221explode_uniform_fun(Point, Center) -> 222 Axis = e3d_vec:norm_sub(Center, Point), 223 Dist = e3d_vec:dist(Center, Point), 224 fun(Matrix, [Percent]) -> 225 ScaledAxis = e3d_vec:mul(Axis, Percent * Dist), 226 TransVec = e3d_mat:mul_point(Matrix, ScaledAxis), 227 e3d_mat:translate(TransVec) 228 end. 229 230explode_radial_fun(Axis, Point, Center) -> 231 Vec = e3d_vec:sub(Point, Center), 232 Cross = e3d_vec:cross(Vec, Axis), 233 Radial = e3d_vec:norm(e3d_vec:cross(Cross, Axis)), 234 Dist = dist_along_vector(Center, Point, Radial), 235 fun(Matrix, [Percent]) -> 236 ScaledRadial = e3d_vec:mul(Radial, Percent * Dist), 237 TransVec = e3d_mat:mul_point(Matrix, ScaledRadial), 238 e3d_mat:translate(TransVec) 239 end. 240 241%%% 242%%% Utilities 243%%% 244 245dist_along_vector({Xa,Ya,Za},{Xb,Yb,Zb},{Vx,Vy,Vz}) -> 246%% Return Distance between PosA and PosB along Normalized Vector 247 Vx*(Xa-Xb)+Vy*(Ya-Yb)+Vz*(Za-Zb). 248