1%% 2%% wings_face.erl -- 3%% 4%% This module contains help routines for faces, such as fold functions 5%% face iterators. 6%% 7 8-module(wings_face). 9 10-export([delete_bad_faces/2, fold/4, fold_faces/4, from_edges/2, 11 inner_edges/2, to_edges/2, other/2]). 12 13-include("wings.hrl"). 14 15from_edges(Es, #we{es=Etab}) when is_list(Es) -> 16 from_edges_1(Es, Etab, []); 17from_edges(Es, We) -> 18 from_edges(gb_sets:to_list(Es), We). 19 20from_edges_1([E|Es], Etab, Acc) -> 21 #edge{lf=Lf,rf=Rf} = gb_trees:get(E, Etab), 22 from_edges_1(Es, Etab, [Lf,Rf|Acc]); 23from_edges_1([], _, Acc) -> gb_sets:from_list(Acc). 24 25%% other(Face, EdgeRecord) -> OtherFace 26%% Pick up the "other face" from an edge record. 27other(Face, #edge{lf=Face,rf=Other}) -> Other; 28other(Face, #edge{rf=Face,lf=Other}) -> Other. 29 30%% to_edges(Faces, We) -> [Edge] 31%% Convert a set or list of faces to a list of edges. 32to_edges(Fs, We) -> 33 ordsets:from_list(to_edges_raw(Fs, We)). 34 35%% inner_edges(Faces, We) -> [Edge] 36%% Given a set of faces, return all inner edges. 37inner_edges(Faces, We) -> 38 S = to_edges_raw(Faces, We), 39 inner_edges_1(lists:sort(S), []). 40 41inner_edges_1([E,E|T], In) -> 42 inner_edges_1(T, [E|In]); 43inner_edges_1([_|T], In) -> 44 inner_edges_1(T, In); 45inner_edges_1([], In) -> lists:reverse(In). 46 47%% Fold over all edges surrounding a face. 48 49fold(F, Acc, Face, #we{es=Etab,fs=Ftab}) -> 50 Edge = gb_trees:get(Face, Ftab), 51 fold(Edge, Etab, F, Acc, Face, Edge, not_done). 52 53fold(LastEdge, _, _, Acc, _, LastEdge, done) -> Acc; 54fold(Edge, Etab, F, Acc0, Face, LastEdge, _) -> 55 case gb_trees:get(Edge, Etab) of 56 #edge{ve=V,lf=Face,ltsu=NextEdge}=E -> 57 Acc = F(V, Edge, E, Acc0), 58 fold(NextEdge, Etab, F, Acc, Face, LastEdge, done); 59 #edge{vs=V,rf=Face,rtsu=NextEdge}=E -> 60 Acc = F(V, Edge, E, Acc0), 61 fold(NextEdge, Etab, F, Acc, Face, LastEdge, done) 62 end. 63 64%% Fold over a set of faces. 65 66fold_faces(F, Acc0, [Face|Faces], #we{es=Etab,fs=Ftab}=We) -> 67 Edge = gb_trees:get(Face, Ftab), 68 Acc = fold_faces_1(Edge, Etab, F, Acc0, Face, Edge, not_done), 69 fold_faces(F, Acc, Faces, We); 70fold_faces(_F, Acc, [], _We) -> Acc; 71fold_faces(F, Acc, Faces, We) -> 72 fold_faces(F, Acc, gb_sets:to_list(Faces), We). 73 74fold_faces_1(LastEdge, _, _, Acc, _, LastEdge, done) -> Acc; 75fold_faces_1(Edge, Etab, F, Acc0, Face, LastEdge, _) -> 76 case gb_trees:get(Edge, Etab) of 77 #edge{ve=V,lf=Face,ltsu=NextEdge}=E -> 78 Acc = F(Face, V, Edge, E, Acc0), 79 fold_faces_1(NextEdge, Etab, F, Acc, Face, LastEdge, done); 80 #edge{vs=V,rf=Face,rtsu=NextEdge}=E -> 81 Acc = F(Face, V, Edge, E, Acc0), 82 fold_faces_1(NextEdge, Etab, F, Acc, Face, LastEdge, done) 83 end. 84 85%% Return an unsorted list of edges for the faces (with duplicates). 86 87to_edges_raw(Faces, #we{es=Etab,fs=Ftab}) when is_list(Faces) -> 88 to_edges_raw(Faces, Ftab, Etab, []); 89to_edges_raw(Faces, We) -> 90 to_edges_raw(gb_sets:to_list(Faces), We). 91 92to_edges_raw([Face|Faces], Ftab, Etab, Acc0) -> 93 Edge = gb_trees:get(Face, Ftab), 94 Acc = to_edges_raw_1(Edge, Etab, Acc0, Face, Edge, not_done), 95 to_edges_raw(Faces, Ftab, Etab, Acc); 96to_edges_raw([], _, _, Acc) -> Acc. 97 98to_edges_raw_1(LastEdge, _, Acc, _, LastEdge, done) -> Acc; 99to_edges_raw_1(Edge, Etab, Acc, Face, LastEdge, _) -> 100 case gb_trees:get(Edge, Etab) of 101 #edge{lf=Face,ltsu=NextEdge} -> 102 to_edges_raw_1(NextEdge, Etab, [Edge|Acc], Face, LastEdge, done); 103 #edge{rf=Face,rtsu=NextEdge} -> 104 to_edges_raw_1(NextEdge, Etab, [Edge|Acc], Face, LastEdge, done) 105 end. 106 107delete_bad_faces(Fs, #we{fs=Ftab,es=Etab}=We) when is_list(Fs) -> 108 Es = bad_edges(Fs, Ftab, Etab, []), 109 wings_edge:dissolve_edges(Es, We); 110delete_bad_faces(Fs, We) -> 111 delete_bad_faces(gb_sets:to_list(Fs), We). 112 113bad_edges([F|Fs], Ftab, Etab, Acc) -> 114 case gb_trees:lookup(F, Ftab) of 115 {value,Edge} -> 116 case gb_trees:get(Edge, Etab) of 117 #edge{ltpr=Same,ltsu=Same,rtpr=Same,rtsu=Same} -> 118 erlang:error({internal_error,one_edged_face,F}); 119 #edge{ltpr=Same,ltsu=Same} -> 120 bad_edges(Fs, Ftab, Etab, [Edge|Acc]); 121 #edge{rtpr=Same,rtsu=Same} -> 122 bad_edges(Fs, Ftab, Etab, [Edge|Acc]); 123 _ -> bad_edges(Fs, Ftab, Etab, Acc) 124 end; 125 none -> bad_edges(Fs, Ftab, Etab, Acc) 126 end; 127bad_edges([], _, _, Acc) -> Acc. 128