%%
%% wings_sel.erl --
%%
%% This module implements selection utilities.
%%
-module(wings_sel).
-export([face_regions/2, fold/3, set/3]).
-include("wings.hrl").
set(Mode, Sel, St) ->
St#st{selmode=Mode, sel=lists:sort(Sel), sh=false}.
%%%
%%% Fold over the selection.
%%%
fold(F, Acc, #st{sel=Sel,shapes=Shapes}) ->
fold_1(F, Acc, Shapes, Sel).
fold_1(F, Acc0, Shapes, [{Id,Items}|T]) ->
We = gb_trees:get(Id, Shapes),
?ASSERT(We#we.id =:= Id),
fold_1(F, F(Items, We, Acc0), Shapes, T);
fold_1(_F, Acc, _Shapes, []) -> Acc.
%%%
%%% Divide the face selection into regions where each face shares at least
%%% one edge with another face in the same region. Two faces can share a
%%% vertex without necessarily being in the same region.
%%%
face_regions(Faces, We) when is_list(Faces) ->
face_regions_1(gb_sets:from_list(Faces), We);
face_regions(Faces, We) ->
face_regions_1(Faces, We).
face_regions_1(Faces, We) ->
find_face_regions(Faces, We, fun collect_face_fun/5, []).
find_face_regions(Faces0, We, Coll, Acc) ->
case gb_sets:is_empty(Faces0) of
true -> Acc;
false ->
{Face,Faces1} = gb_sets:take_smallest(Faces0),
Ws = [Face],
{Reg,Faces} = collect_face_region(Ws, We, Coll, [], Faces1),
find_face_regions(Faces, We, Coll, [Reg|Acc])
end.
collect_face_region([_|_]=Ws0, We, Coll, Reg0, Faces0) ->
Reg = Ws0++Reg0,
{Ws,Faces} = wings_face:fold_faces(Coll, {[],Faces0}, Ws0, We),
collect_face_region(Ws, We, Coll, Reg, Faces);
collect_face_region([], _, _, Reg, Faces) ->
{gb_sets:from_list(Reg),Faces}.
collect_face_fun(Face, _, _, Rec, {Ws,Faces}=A) ->
Of = case Rec of
#edge{lf=Face,rf=Of0} -> Of0;
#edge{rf=Face,lf=Of0} -> Of0
end,
case gb_sets:is_member(Of, Faces) of
true -> {[Of|Ws],gb_sets:delete(Of, Faces)};
false -> A
end.