1%% -*- erlang-indent-level: 2 -*-
2%%----------------------------------------------------------------------------
3%% Copy of inf_loop1.erl, where the calls mentioned below have been
4%% restored.
5
6%% Non-sensical (i.e., stripped-down) program that sends the analysis
7%% into an infinite loop. The #we.es field was originally a gb_trees:tree()
8%% but the programmer declared it as an array in order to change it to
9%% that data type instead. In the file, there are two calls to function
10%% gb_trees:get/2 which seem to be the ones responsible for sending the
11%% analysis into an infinite loop. Currently, these calls are marked and
12%% have been changed to gbee_trees:get/2 in order to be able to see that
13%% the analysis works if these two calls are taken out of the picture.
14%%----------------------------------------------------------------------------
15-module(inf_loop2).
16
17-export([command/1]).
18
19-record(we, {id,
20	     es = array:new() :: array:array(),
21	     vp,
22	     mirror = none}).
23-record(edge, {vs,ve,a = none,b = none,lf,rf,ltpr,ltsu,rtpr,rtsu}).
24
25command(St) ->
26  State = drag_mode(offset_region),
27  SetupSt = wings_sel_conv:more(St),
28  Tvs = wings_sel:fold(fun(Faces, #we{id = Id} = We, Acc) ->
29			   FaceRegions = wings_sel:face_regions(Faces, We),
30			   {AllVs0,VsData} =
31			     collect_offset_regions_data(FaceRegions, We, [], []),
32			   AllVs = ordsets:from_list(AllVs0),
33			   [{Id,{AllVs,offset_regions_fun(VsData, State)}}|Acc]
34                       end,
35                       [],
36                       SetupSt),
37    wings_drag:setup(Tvs, 42, [], St).
38
39drag_mode(Type) ->
40    {Mode,Norm} = wings_pref:get_value(Type, {average,loop}),
41    {Type,Mode,Norm}.
42
43collect_offset_regions_data([Faces|Regions], We, AllVs, VsData) ->
44  {FaceNormTab,OuterEdges,RegVs} =
45    some_fake_module:faces_data_0(Faces, We, [], [], []),
46  {LoopNorm,LoopVsData,LoopVs} =
47    offset_regions_loop_data(OuterEdges, Faces, We, FaceNormTab),
48  Vs = RegVs -- LoopVs,
49  RegVsData = vertex_normals(Vs, FaceNormTab, We, LoopVsData),
50  collect_offset_regions_data(Regions, We, RegVs ++ AllVs,
51			      [{LoopNorm,RegVsData}|VsData]);
52collect_offset_regions_data([], _, AllVs, VsData) ->
53  {AllVs,VsData}.
54
55offset_regions_loop_data(Edges, Faces, We, FNtab) ->
56  EdgeSet = gb_sets:from_list(Edges),
57  offset_loop_data_0(EdgeSet, Faces, We, FNtab, [], [], []).
58
59offset_loop_data_0(EdgeSet0, Faces, We, FNtab, LNorms, VData0, Vs0) ->
60  case gb_sets:is_empty(EdgeSet0) of
61    false ->
62      {Edge,EdgeSet1} = gb_sets:take_smallest(EdgeSet0),
63      {EdgeSet,VData,Links,LoopNorm,Vs} =
64	offset_loop_data_1(Edge, EdgeSet1, Faces, We, FNtab, VData0, Vs0),
65      offset_loop_data_0(EdgeSet, Faces, We, FNtab,
66			 [{Links,LoopNorm}|LNorms], VData, Vs);
67    true ->
68      AvgLoopNorm = average_loop_norm(LNorms),
69      {AvgLoopNorm,VData0,Vs0}
70  end.
71
72offset_loop_data_1(Edge, EdgeSet, _Faces,
73                   #we{es = Etab, vp = Vtab} = We, FNtab, VData, Vs) ->
74  #edge{vs = Va, ve = Vb, lf = Lf, ltsu = NextLeft} = gb_trees:get(Edge, Etab),
75  VposA = gb_trees:get(Va, Vtab),
76  VposB = gb_trees:get(Vb, Vtab),
77  VDir = e3d_vec:sub(VposB, VposA),
78  FNorm = wings_face:normal(Lf, We),
79  EdgeData = gb_trees:get(NextLeft, Etab),
80  offset_loop_data_2(NextLeft, EdgeData, Va, VposA, Lf, Edge, We, FNtab,
81		     EdgeSet, VDir, [], [FNorm], VData, [], Vs, 0).
82
83offset_loop_data_2(CurE, #edge{vs = Va, ve = Vb, lf = PrevFace,
84			       rtsu = NextEdge, ltsu = IfCurIsMember},
85                   Vb, VposB, PrevFace, LastE,
86                   #we{mirror = M} = We,
87                   FNtab, EdgeSet0, VDir, EDir0, VNorms0, VData0, VPs0, Vs0,
88                   Links) ->
89  Mirror = M == PrevFace,
90  offset_loop_is_member(Mirror, Vb, Va, VposB, CurE, IfCurIsMember, VNorms0,
91			NextEdge, EdgeSet0, VDir, EDir0, FNtab, PrevFace,
92			LastE, We, VData0, VPs0, Vs0, Links).
93
94offset_loop_is_member(Mirror, V1, V2, Vpos1, CurE, NextE, VNorms0, NEdge,
95                      EdgeSet0, VDir, EDir0, FNtab, PFace, LastE, We,
96                      VData0, VPs0, Vs0, Links) ->
97  #we{es = Etab, vp = Vtab} = We,
98  Vpos2 = gb_trees:get(V2, Vtab),
99  Dir = e3d_vec:sub(Vpos2, Vpos1),
100  NextVDir = e3d_vec:neg(Dir),
101  EdgeSet = gb_sets:delete(CurE, EdgeSet0),
102  EdgeData = gb_trees:get(NextE, Etab), %% HERE
103  [FNorm|_] = VNorms0,
104  VData = offset_loop_data_3(Mirror, V1, Vpos1, VNorms0, NEdge, VDir,
105			     Dir, EDir0, FNtab, We, VData0),
106  VPs = [Vpos1|VPs0],
107  Vs = [V1|Vs0],
108  offset_loop_data_2(NextE, EdgeData, V2, Vpos2, PFace, LastE, We, FNtab,
109		     EdgeSet, NextVDir, [], [FNorm], VData, VPs, Vs, Links + 1).
110
111offset_loop_data_3(false, V, Vpos, VNorms0, NextEdge,
112                   VDir, Dir, EDir0, FNtab, We, VData0) ->
113  #we{es = Etab} = We,
114  VNorm = e3d_vec:norm(e3d_vec:add(VNorms0)),
115  NV = wings_vertex:other(V, gb_trees:get(NextEdge, Etab)), %% HERE
116  ANorm = vertex_normal(NV, FNtab, We),
117  EDir = some_fake_module:average_edge_dir(VNorm, VDir, Dir, EDir0),
118  AvgDir = some_fake_module:evaluate_vdata(VDir, Dir, VNorm),
119  ScaledDir = some_fake_module:along_edge_scale_factor(VDir, Dir, EDir, ANorm),
120  [{V,{Vpos,AvgDir,EDir,ScaledDir}}|VData0].
121
122average_loop_norm([{_,LNorms}]) ->
123  e3d_vec:norm(LNorms);
124average_loop_norm([{LinksA,LNormA},{LinksB,LNormB}]) ->
125  case LinksA < LinksB of
126    true ->
127      e3d_vec:norm(e3d_vec:add(e3d_vec:neg(LNormA), LNormB));
128    false ->
129      e3d_vec:norm(e3d_vec:add(e3d_vec:neg(LNormB), LNormA))
130  end;
131average_loop_norm(LNorms) ->
132  LoopNorms = [Norm || {_,Norm} <- LNorms],
133  e3d_vec:norm(e3d_vec:neg(e3d_vec:add(LoopNorms))).
134
135vertex_normals([V|Vs], FaceNormTab, #we{vp = Vtab, mirror = M} = We, Acc) ->
136  FaceNorms =
137    wings_vertex:fold(fun(_, Face, _, A) when Face == M ->
138			  [e3d_vec:neg(wings_face:normal(M, We))|A];
139			 (_, Face, _, A) ->
140			  [gb_trees:get(Face, FaceNormTab)|A]
141		      end, [], V, We),
142  VNorm = e3d_vec:norm(e3d_vec:add(FaceNorms)),
143  Vpos = gb_trees:get(V, Vtab),
144  vertex_normals(Vs, FaceNormTab, We, [{V,{Vpos,VNorm}}|Acc]);
145vertex_normals([], _, _, Acc) ->
146  Acc.
147
148vertex_normal(V, FaceNormTab, #we{mirror = M} = We) ->
149  wings_vertex:fold(fun(_, Face, _, A) when Face == M ->
150			[e3d_vec:neg(wings_face:normal(Face, We))|A];
151		       (_, Face, _, A) ->
152			N = gb_trees:get(Face, FaceNormTab),
153			case e3d_vec:is_zero(N) of
154			  true -> A;
155			  false -> [N|A]
156			end
157		    end, [], V, We).
158
159offset_regions_fun(OffsetData, {_,Solution,_} = State) ->
160  fun(new_mode_data, {NewState,_}) ->
161      offset_regions_fun(OffsetData, NewState);
162     ([Dist,_,_,Bump|_], A) ->
163      lists:foldl(fun({LoopNormal,VsData}, VsAcc0) ->
164		      lists:foldl(fun({V,{Vpos0,VNorm}}, VsAcc) ->
165				      [{V,Vpos0}|VsAcc];
166				     ({V,{Vpos0,Dir,EDir,ScaledEDir}}, VsAcc) ->
167				      Vec = case Solution of
168					      average -> Dir;
169					      along_edges -> EDir;
170					      scaled -> ScaledEDir
171					    end,
172				      [{V,Vpos0}|VsAcc]
173				  end, VsAcc0, VsData)
174		  end, A, OffsetData)
175  end.
176