1%% 2%% wpc_intersect_vertex.erl -- 3%% 4%% Plug-in for moving vertice(s) to the intersection of a line and plane 5%% 6%% Copyright (c) 2004-2011 Bjorn Gustavsson. 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%% Contributed by elrond79. 12%% 13%% $Id$ 14%% 15%% 2000-10-01: Changed help text to incorporate suggestions by Puzzled Paul 16%% 2000-09-21: Normalized LD and PN (so dot product not <.001 if either is very 17%% short) 18%% 2000-09-17: Tried to make more compliant w/ wings API (Paul Molodowitch) 19 20-module(wpc_intersect_vertex). 21 22-export([init/0,menu/2,command/2,intersect_vertex/3]). 23 24-include_lib("wpc_intersect.hrl"). 25-import(lists, [foldl/3,splitwith/2]). 26 27init() -> 28 true. 29 30 31% If we can find the "flatten" menu item, stick it in after that; otherwise, put at end 32menu({vertex}, Menu) -> 33 {SplitMenu1, SplitMenu2} = splitwith(fun isNotFlattenMenuItem/1, Menu), 34 if 35 length(SplitMenu1) < length(SplitMenu2) -> 36 [FlattenMenuItem|MenuTail] = SplitMenu2, 37 SplitMenu1 ++ [FlattenMenuItem|menu_item()] ++ MenuTail; 38 true -> 39 Menu ++ [separator] ++ menu_item() 40 end; 41menu(_,Menu) -> Menu. 42 43isNotFlattenMenuItem({"Flatten",_}) -> 44 false; 45isNotFlattenMenuItem({_,{flatten,_}}) -> 46 false; 47isNotFlattenMenuItem(_) -> 48 true. 49 50 51command({vertex,{intersect,{Type,{'ASK',Ask}}}}, St) -> 52 intersect({Type,{'ASK',Ask}}, St); 53%% command for repeat drag args 54command({vertex,{intersect,{Type,Data}}},St) -> 55 intersect_ask_callback({Type,Data},St); 56 57command(_,_) -> next. 58 59%% creates the menu item for the vertex intersect command. 60 61menu_item() -> 62 [{?__(8,"Intersect"),{intersect,fun adv_submenu/2}}]. 63 64submenu_items(1) -> 65 {stay_on_line, 66 {'ASK',{[{axis, ?__(1,"Pick direction of line - line will pass through selected vertex(es)")}, 67 {axis_point, ?__(2,"Pick plane to intersect")}],[],[]}}}; 68submenu_items(2) -> 69 {stay_on_plane, 70 {'ASK',{[{axis, ?__(3,"Pick plane normal - plane will pass through selected vertex(es)")}, 71 {axis_point, ?__(4,"Pick line to intersect")}],[],[]}}}; 72submenu_items(3) -> 73 {pick_all, 74 {'ASK',{[{axis, ?__(5,"Pick direction of line")}, 75 {point, ?__(6,"Pick point for line to pass through")}, 76 {axis, ?__(7,"Pick plane normal")}, 77 {point, ?__(8,"Pick point for plane to pass through")}],[],[]}}}. 78 79adv_submenu(help, _) -> 80 {?__(1,"Stay on line, move to intersection with plane"), 81 ?__(2,"Stay on plane, move to line"), 82 ?__(3,"Pick line and plane")}; 83adv_submenu(Button, NS) -> 84 wings_menu:build_command(submenu_items(Button), NS). 85 86intersect({stay_on_line, {'ASK',Ask}}, St0) -> 87 wings:ask(Ask, St0, fun (AskResult, St) -> intersect_ask_callback({stay_on_line, AskResult}, St) end); 88intersect({stay_on_plane, {'ASK',Ask}}, St0) -> 89 wings:ask(Ask, St0, fun (AskResult, St) -> intersect_ask_callback({stay_on_plane, AskResult}, St) end); 90intersect({pick_all, {'ASK',Ask}}, St0) -> 91 wings:ask(Ask, St0, fun (AskResult, St) -> intersect_ask_callback({pick_all, AskResult}, St) end). 92 93intersect_ask_callback({stay_on_line, {LineDir, PlaneNorm, PlanePoint}}, St) -> 94 intersect(LineDir, selection, PlaneNorm, PlanePoint, St); 95intersect_ask_callback({stay_on_plane, {PlaneNorm, LineDir, LinePoint}}, St) -> 96 intersect(LineDir, LinePoint, PlaneNorm, selection, St); 97intersect_ask_callback({pick_all, {LineDir, LinePoint, PlaneNorm, PlanePoint}}, St) -> 98 intersect(LineDir, LinePoint, PlaneNorm, PlanePoint, St). 99 100 101intersect(LineDir0, LinePoint, PlaneNorm0, PlanePoint, St) -> 102 PlaneNorm = e3d_vec:norm(PlaneNorm0), 103 LineDir = e3d_vec:norm(LineDir0), 104 DotProd = e3d_vec:dot(LineDir, PlaneNorm), 105 if 106 abs(DotProd) > 0.001 -> 107 IntersectData = #intersect_data{lineDir = LineDir, linePoint = LinePoint, 108 planeNorm = PlaneNorm, planePoint = PlanePoint, 109 lineDotPlane = DotProd}, 110 {save_state, 111 wpa:sel_map( 112 fun(Vs, We) -> 113 intersect_body(Vs, We, IntersectData) 114 end, St)}; 115 true -> 116 wpa:error_msg(?__(1,"Line and plane are nearly parallel:\n" 117 "can't find intersection.")), 118 keep 119 end. 120 121intersect_body(Vs, #we{vp=Vtab0}=We0, #intersect_data{} = IntersectData) when is_list(Vs) -> 122 Vtab = foldl(fun(V, VTabAcc) -> 123 intersect_vertex(V, VTabAcc, IntersectData) 124 end, Vtab0, Vs), 125 We = We0#we{vp=Vtab}, 126 wings_we:mirror_flatten(We0, We); 127intersect_body(Vs, We, #intersect_data{} = IntersectData) -> 128 intersect_body(gb_sets:to_list(Vs), We, IntersectData). 129 130 131intersect_vertex(V, Tab, #intersect_data{linePoint = selection} = IntersectData0) -> 132 IntersectData = IntersectData0#intersect_data{linePoint = array:get(V, Tab)}, 133 intersect_vertex(V, Tab, IntersectData); 134intersect_vertex(V, Tab, #intersect_data{planePoint = selection} = IntersectData0) -> 135 IntersectData = IntersectData0#intersect_data{planePoint = array:get(V, Tab)}, 136 intersect_vertex(V, Tab, IntersectData); 137intersect_vertex(V, Tab, #intersect_data{lineDir = LD, linePoint = LP, 138 planeNorm = PN, planePoint = PP, lineDotPlane = LDdotPN}) -> 139 %% The vector equation for the line is 140 %% LP + xLD 141 %% for any scalar x; we need to find x st we have a point on the plane. 142 %% For any point P on the plane, we know that P - PP is perpendicular 143 %% to the plane normal, ie that 144 %% (P - PP).PN = 0 145 %% So sticking in our line equation for P, we have 146 %% (LP + xLD - PP).PN = 0 -> x = (PP - LP).PN 147 %% ------------ 148 %% LD.PN 149 150 X = e3d_vec:dot(e3d_vec:sub(PP, LP),PN)/LDdotPN, 151 Intersection = e3d_vec:add(LP, e3d_vec:mul(LD, X)), 152 array:set(V, Intersection, Tab). 153 154