aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl')
-rw-r--r--lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl375
1 files changed, 0 insertions, 375 deletions
diff --git a/lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl b/lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl
deleted file mode 100644
index d7af9bb1d3..0000000000
--- a/lib/dialyzer/test/opaque_tests_SUITE_data/src/wings/wings_dissolve.erl
+++ /dev/null
@@ -1,375 +0,0 @@
-%%
-%% wings_dissolve.erl --
-%%
-%% This module implements dissolve of faces.
-%%
-
--module(wings_dissolve).
-
--export([faces/2, complement/2]).
-
--include("wings.hrl").
-
-%% faces([Face], We) -> We'
-%% Dissolve the given faces.
-faces([], We) -> We;
-faces(Faces, #we{fs=Ftab0}=We) ->
- case gb_sets:is_empty(Faces) of
- true -> We;
- false when is_list(Faces) ->
- Complement = ordsets:subtract(gb_trees:keys(Ftab0),
- ordsets:from_list(Faces)),
- dissolve_1(Faces, Complement, We);
- false ->
- Complement = ordsets:subtract(gb_trees:keys(Ftab0),
- gb_sets:to_list(Faces)),
- dissolve_1(Faces, Complement, We)
- end.
-
-faces([], _, We) -> We;
-faces(Faces,Complement,We) ->
- case gb_sets:is_empty(Faces) of
- true -> We;
- false -> dissolve_1(Faces, Complement,We)
- end.
-
-dissolve_1(Faces, Complement, We0) ->
- We1 = optimistic_dissolve(Faces,Complement,We0#we{vc=undefined}),
- NewFaces = wings_we:new_items_as_ordset(face, We0, We1),
- We2 = wings_face:delete_bad_faces(NewFaces, We1),
- We = wings_we:rebuild(We2),
- case wings_we:is_consistent(We) of
- true ->
- We;
- false ->
- io:format("Dissolving would cause an inconsistent object structure.")
- end.
-
-%% complement([Face], We) -> We'
-%% Dissolve all faces BUT the given faces. Also invalidate the
-%% mirror face if it existed and was dissolved.
-complement(Fs0, #we{fs=Ftab0}=We0) when is_list(Fs0) ->
- Fs = ordsets:subtract(gb_trees:keys(Ftab0), ordsets:from_list(Fs0)),
- case faces(Fs, Fs0, We0) of
- #we{mirror=none}=We -> We;
- #we{mirror=Face,fs=Ftab}=We ->
- case gb_trees:is_defined(Face, Ftab) of
- false -> We;
- true -> We#we{mirror=none}
- end
- end;
-complement(Fs, We) -> complement(gb_sets:to_list(Fs), We).
-
-optimistic_dissolve(Faces0, Compl, We0) ->
- %% Optimistically assume that we have a simple region without
- %% any holes.
- case outer_edge_loop(Faces0, We0) of
- error ->
- %% Assumption was wrong. We need to partition the selection
- %% and dissolve each partition in turn.
- Parts = wings_sel:face_regions(Faces0, We0),
- complex_dissolve(Parts, We0);
- [_|_]=Loop ->
- %% Assumption was correct.
- simple_dissolve(Faces0, Compl, Loop, We0)
- end.
-
-%% simple_dissolve(Faces, Loop, We0) -> We
-%% Dissolve a region of faces with no holes and no
-%% repeated vertices in the outer edge loop.
-
-simple_dissolve(Faces0, Compl, Loop, We0) ->
- Faces = to_gb_set(Faces0),
- OldFace = gb_sets:smallest(Faces),
- Mat = wings_facemat:face(OldFace, We0),
- We1 = fix_materials(Faces, Compl, We0),
- #we{es=Etab0,fs=Ftab0,he=Htab0} = We1,
- {Ftab1,Etab1,Htab} = simple_del(Faces, Ftab0, Etab0, Htab0, We1),
- {NewFace,We2} = wings_we:new_id(We1),
- Ftab = gb_trees:insert(NewFace, hd(Loop), Ftab1),
- Last = lists:last(Loop),
- Etab = update_outer([Last|Loop], Loop, NewFace, Ftab, Etab1),
- We = We2#we{es=Etab,fs=Ftab,he=Htab},
- wings_facemat:assign(Mat, [NewFace], We).
-
-fix_materials(Del,Keep,We) ->
- case gb_sets:size(Del) < length(Keep) of
- true ->
- wings_facemat:delete_faces(Del,We);
- false ->
- wings_facemat:keep_faces(Keep,We)
- end.
-
-to_gb_set(List) when is_list(List) ->
- gb_sets:from_list(List);
-to_gb_set(S) -> S.
-
-%% Delete faces and inner edges for a simple region.
-simple_del(Faces, Ftab0, Etab0, Htab0, We) ->
- case {gb_trees:size(Ftab0),gb_sets:size(Faces)} of
- {AllSz,FaceSz} when AllSz < 2*FaceSz ->
- %% At least half of the faces are selected.
- %% It is faster to find the edges for the
- %% unselected faces.
- UnselFaces = ordsets:subtract(gb_trees:keys(Ftab0),
- gb_sets:to_list(Faces)),
-
- UnselSet = sofs:from_external(UnselFaces, [face]),
- Ftab1 = sofs:from_external(gb_trees:to_list(Ftab0),
- [{face,edge}]),
- Ftab2 = sofs:restriction(Ftab1, UnselSet),
- Ftab = gb_trees:from_orddict(sofs:to_external(Ftab2)),
-
- Keep0 = wings_face:to_edges(UnselFaces, We),
- Keep = sofs:set(Keep0, [edge]),
- Etab1 = sofs:from_external(gb_trees:to_list(Etab0),
- [{edge,info}]),
- Etab2 = sofs:restriction(Etab1, Keep),
- Etab = gb_trees:from_orddict(sofs:to_external(Etab2)),
-
- Htab = simple_del_hard(Htab0, sofs:to_external(Keep), undefined),
- {Ftab,Etab,Htab};
- {_,_} ->
- Ftab = lists:foldl(fun(Face, Ft) ->
- gb_trees:delete(Face, Ft)
- end, Ftab0, gb_sets:to_list(Faces)),
- Inner = wings_face:inner_edges(Faces, We),
- Etab = lists:foldl(fun(Edge, Et) ->
- gb_trees:delete(Edge, Et)
- end, Etab0, Inner),
- Htab = simple_del_hard(Htab0, undefined, Inner),
- {Ftab,Etab,Htab}
- end.
-
-simple_del_hard(Htab, Keep, Remove) ->
- case gb_sets:is_empty(Htab) of
- true -> Htab;
- false -> simple_del_hard_1(Htab, Keep, Remove)
- end.
-
-simple_del_hard_1(Htab, Keep, undefined) ->
- gb_sets:intersection(Htab, gb_sets:from_ordset(Keep));
-simple_del_hard_1(Htab, undefined, Remove) ->
- gb_sets:difference(Htab, gb_sets:from_ordset(Remove)).
-
-%% complex([Partition], We0) -> We0
-%% The general dissolve.
-
-complex_dissolve([Faces|T], We0) ->
- Face = gb_sets:smallest(Faces),
- Mat = wings_facemat:face(Face, We0),
- We1 = wings_facemat:delete_faces(Faces, We0),
- Parts = outer_edge_partition(Faces, We1),
- We = do_dissolve(Faces, Parts, Mat, We0, We1),
- complex_dissolve(T, We);
-complex_dissolve([], We) -> We.
-
-do_dissolve(Faces, Ess, Mat, WeOrig, We0) ->
- We1 = do_dissolve_faces(Faces, We0),
- Inner = wings_face:inner_edges(Faces, WeOrig),
- We2 = delete_inner(Inner, We1),
- #we{he=Htab0} = We = do_dissolve_1(Ess, Mat, We2),
- Htab = gb_sets:difference(Htab0, gb_sets:from_list(Inner)),
- We#we{he=Htab}.
-
-do_dissolve_1([EdgeList|Ess], Mat, #we{es=Etab0,fs=Ftab0}=We0) ->
- {Face,We1} = wings_we:new_id(We0),
- Ftab = gb_trees:insert(Face, hd(EdgeList), Ftab0),
- Last = lists:last(EdgeList),
- Etab = update_outer([Last|EdgeList], EdgeList, Face, Ftab, Etab0),
- We2 = We1#we{es=Etab,fs=Ftab},
- We = wings_facemat:assign(Mat, [Face], We2),
- do_dissolve_1(Ess, Mat, We);
-do_dissolve_1([], _Mat, We) -> We.
-
-do_dissolve_faces(Faces, #we{fs=Ftab0}=We) ->
- Ftab = lists:foldl(fun(Face, Ft) ->
- gb_trees:delete(Face, Ft)
- end, Ftab0, gb_sets:to_list(Faces)),
- We#we{fs=Ftab}.
-
-delete_inner(Inner, #we{es=Etab0}=We) ->
- Etab = lists:foldl(fun(Edge, Et) ->
- gb_trees:delete(Edge, Et)
- end, Etab0, Inner),
- We#we{es=Etab}.
-
-update_outer([Pred|[Edge|Succ]=T], More, Face, Ftab, Etab0) ->
- #edge{rf=Rf} = R0 = gb_trees:get(Edge, Etab0),
- Rec = case gb_trees:is_defined(Rf, Ftab) of
- true ->
- ?ASSERT(false == gb_trees:is_defined(R0#edge.lf, Ftab)),
- LS = succ(Succ, More),
- R0#edge{lf=Face,ltpr=Pred,ltsu=LS};
- false ->
- ?ASSERT(true == gb_trees:is_defined(R0#edge.lf, Ftab)),
- RS = succ(Succ, More),
- R0#edge{rf=Face,rtpr=Pred,rtsu=RS}
- end,
- Etab = gb_trees:update(Edge, Rec, Etab0),
- update_outer(T, More, Face, Ftab, Etab);
-update_outer([_], _More, _Face, _Ftab, Etab) -> Etab.
-
-succ([Succ|_], _More) -> Succ;
-succ([], [Succ|_]) -> Succ.
-
-%% outer_edge_loop(FaceSet,WingedEdge) -> [Edge] | error.
-%% Partition the outer edges of the FaceSet into a single closed loop.
-%% Return 'error' if the faces in FaceSet does not form a
-%% simple region without holes.
-%%
-%% Equvivalent to
-%% case outer_edge_partition(FaceSet,WingedEdge) of
-%% [Loop] -> Loop;
-%% [_|_] -> error
-%% end.
-%% but faster.
-
-outer_edge_loop(Faces, We) ->
- case lists:sort(collect_outer_edges(Faces, We)) of
- [] -> error;
- [{Key,Val}|Es0] ->
- case any_duplicates(Es0, Key) of
- false ->
- Es = gb_trees:from_orddict(Es0),
- N = gb_trees:size(Es),
- outer_edge_loop_1(Val, Es, Key, N, []);
- true -> error
- end
- end.
-
-outer_edge_loop_1({Edge,V}, _, V, 0, Acc) ->
- %% This edge completes the loop, and we have used all possible edges.
- [Edge|Acc];
-outer_edge_loop_1({_,V}, _, V, _N, _) ->
- %% Loop is complete, but we haven't used all edges.
- error;
-outer_edge_loop_1({_,_}, _, _, 0, _) ->
- %% We have used all possible edges, but somehow the loop
- %% is not complete. I can't see how this is possible.
- erlang:error(internal_error);
-outer_edge_loop_1({Edge,Vb}, Es, EndV, N, Acc0) ->
- Acc = [Edge|Acc0],
- outer_edge_loop_1(gb_trees:get(Vb, Es), Es, EndV, N-1, Acc).
-
-any_duplicates([{V,_}|_], V) -> true;
-any_duplicates([_], _) -> false;
-any_duplicates([{V,_}|Es], _) -> any_duplicates(Es, V).
-
-%% outer_edge_partition(FaceSet, WingedEdge) -> [[Edge]].
-%% Partition the outer edges of the FaceSet. Each partion
-%% of edges form a closed loop with no repeated vertices.
-%% Outer edges are edges that have one face in FaceSet
-%% and one outside.
-%% It is assumed that FaceSet consists of one region returned by
-%% wings_sel:face_regions/2.
-
-outer_edge_partition(Faces, We) ->
- F0 = collect_outer_edges(Faces, We),
- F = gb_trees:from_orddict(wings_util:rel2fam(F0)),
- partition_edges(F, []).
-
-collect_outer_edges(Faces, We) when is_list(Faces) ->
- collect_outer_edges_1(Faces, gb_sets:from_list(Faces), We);
-collect_outer_edges(Faces, We) ->
- collect_outer_edges_1(gb_sets:to_list(Faces), Faces, We).
-
-collect_outer_edges_1(Fs0, Faces0, #we{fs=Ftab}=We) ->
- case {gb_trees:size(Ftab),gb_sets:size(Faces0)} of
- {AllSz,FaceSz} when AllSz < 2*FaceSz ->
- Fs = ordsets:subtract(gb_trees:keys(Ftab), Fs0),
- Faces = gb_sets:from_ordset(Fs),
- Coll = collect_outer_edges_a(Faces),
- wings_face:fold_faces(Coll, [], Fs, We);
- {_,_} ->
- Coll = collect_outer_edges_b(Faces0),
- wings_face:fold_faces(Coll, [], Fs0, We)
- end.
-
-collect_outer_edges_a(Faces) ->
- fun(Face, _, Edge, #edge{ve=V,vs=OtherV,lf=Face,rf=Other}, Acc) ->
- case gb_sets:is_member(Other, Faces) of
- false -> [{V,{Edge,OtherV}}|Acc];
- true -> Acc
- end;
- (Face, _, Edge, #edge{ve=OtherV,vs=V,rf=Face,lf=Other}, Acc) ->
- case gb_sets:is_member(Other, Faces) of
- false -> [{V,{Edge,OtherV}}|Acc];
- true -> Acc
- end
- end.
-
-collect_outer_edges_b(Faces) ->
- fun(Face, _, Edge, #edge{vs=V,ve=OtherV,lf=Face,rf=Other}, Acc) ->
- case gb_sets:is_member(Other, Faces) of
- false -> [{V,{Edge,OtherV}}|Acc];
- true -> Acc
- end;
- (Face, _, Edge, #edge{vs=OtherV,ve=V,rf=Face,lf=Other}, Acc) ->
- case gb_sets:is_member(Other, Faces) of
- false -> [{V,{Edge,OtherV}}|Acc];
- true -> Acc
- end
- end.
-
-partition_edges(Es0, Acc) ->
- case gb_trees:is_empty(Es0) of
- true -> Acc;
- false ->
- {Key,Val,Es1} = gb_trees:take_smallest(Es0),
- {Cycle,Es} = part_collect_cycle(Key, Val, Es1, []),
- partition_edges(Es, [Cycle|Acc])
- end.
-
-%% part_collect_cycle(Vertex, VertexInfo, EdgeInfo, Acc0) ->
-%% none | {[Edge],EdgeInfo}
-%% Collect the cycle starting with Vertex.
-%%
-%% Note: This function can only return 'none' when called
-%% recursively.
-
-part_collect_cycle(_, repeated, _, _) ->
- %% Repeated vertex - we are not allowed to go this way.
- %% Can only happen if we were called recursively because
- %% a fork was encountered.
- none;
-part_collect_cycle(_Va, [{Edge,Vb}], Es0, Acc0) ->
- %% Basic case. Only one way to go.
- Acc = [Edge|Acc0],
- case gb_trees:lookup(Vb, Es0) of
- none ->
- {Acc,Es0};
- {value,Val} ->
- Es = gb_trees:delete(Vb, Es0),
- part_collect_cycle(Vb, Val, Es, Acc)
- end;
-part_collect_cycle(Va, [Val|More], Es0, []) ->
- %% No cycle started yet and we have multiple choice of
- %% edges out from this vertex. It doesn't matter which
- %% edge we follow, so we'll follow the first one.
- {Cycle,Es} = part_collect_cycle(Va, [Val], Es0, []),
- {Cycle,gb_trees:insert(Va, More, Es)};
-part_collect_cycle(Va, Edges, Es0, Acc) ->
- %% We have a partially collected cycle and we have a
- %% fork (multiple choice of edges). Here we must choose
- %% an edge that closes the cycle without passing Va
- %% again (because repeated vertices are not allowed).
- Es = gb_trees:insert(Va, repeated, Es0),
- part_fork(Va, Edges, Es, Acc, []).
-
-part_fork(Va, [Val|More], Es0, Acc, Tried) ->
- %% Try to complete the cycle by following this edge.
- case part_collect_cycle(Va, [Val], Es0, Acc) of
- none ->
- %% Failure - try the next edge.
- part_fork(Va, More, Es0, Acc, [Val|Tried]);
- {Cycle,Es} ->
- %% Found a cycle. Update the vertex information
- %% with all edges remaining.
- {Cycle,gb_trees:update(Va, lists:reverse(Tried, More), Es)}
- end;
-part_fork(_, [], _, _, _) ->
- %% None of edges were possible. Can only happen if this function
- %% was called recursively (i.e. if we hit another fork while
- %% processing a fork).
- none.