RE: The Connect surface tool by Dimitri. - ggaliens - 03-20-2016
I could ... if all the parts and function would pass the Quality tests.
Still waiting for some feedback in it as-is.
It does not seem to depend on many items that would be new to WINGS ... so I think at the very least ... I could put some comments in the code that describe the process so you could have a read.
RE: The Connect surface tool by Dimitri. - ggaliens - 03-20-2016
Code is a little heavy. Want it to read better. Could use a bit of your help Dan. I think there is at least one thing I'd break out and put into wings_vertex.
Code: command({vertex,{manifoldlab,connect_surface_norm}},#st{sel=[{WeID,Set}]}=St0) ->
#we{es=Etab} = We = gb_trees:get(WeID,St0#st.shapes),
[VS0,VE0|_] = gb_sets:to_list(Set),
Pt1a = wings_vertex:pos(VS0,We),
Pt2a = wings_vertex:pos(VE0,We),
Mid0 = e3d_vec:average([Pt1a,Pt2a]),
V1 = e3d_vec:sub(Pt2a,Pt1a),
Norm0 = e3d_vec:average([wings_vertex:normal(VS0,We), wings_vertex:normal(VE0,We)]),
Cross = e3d_vec:norm(e3d_vec:cross(V1,Norm0)),
A_B_C_D = e3d_vec:plane(Mid0,Cross), %% slicer plane
Plane1 = e3d_vec:plane(Pt1a,e3d_vec:norm(V1)),
Plane2 = e3d_vec:plane(Pt2a,e3d_vec:norm(V1)),
MyAcc = fun(Ei, _Val, Acc) ->
#edge{vs=VS,ve=VE} = array:get(Ei,Etab),
Pt1 = wings_vertex:pos(VS,We),
Pt2 = wings_vertex:pos(VE,We),
S1 = e3d_vec:plane_side(Pt1, A_B_C_D),
S2 = e3d_vec:plane_side(Pt2, A_B_C_D),
if (S1 /= S2) ->
D1 = abs(e3d_vec:plane_dist(Pt1, A_B_C_D)),
D2 = abs(e3d_vec:plane_dist(Pt2, A_B_C_D)),
Dir = e3d_vec:norm(e3d_vec:sub(Pt2,Pt1)),
Percent = D1/(D1+D2),
PtX = e3d_vec:add(Pt1, e3d_vec:mul(Dir, Percent*wings_edge:length(Ei,We))),
gb_trees:enter(Ei,PtX,Acc);
true ->
Acc
end
end,
ETree = array:sparse_foldl(MyAcc, gb_trees:empty(), Etab),
Es = gb_sets:from_list(gb_trees:keys(ETree)),
St2 = St0#st{selmode=edge,sel=[{WeID,Es}]},
#st{sel=[{WeID,FaceSet}]} = St3 = wings_sel_conv:mode(face,St2),
MyFs = fun(Fi, Acc) ->
Center = wings_face:center(Fi, We),
S1a = e3d_vec:plane_side(Mid0, Plane1),
S2a = e3d_vec:plane_side(Center, Plane1),
S1b = e3d_vec:plane_side(Mid0, Plane2),
S2b = e3d_vec:plane_side(Center, Plane2),
if (S1a ==S2a) andalso (S1b ==S2b) -> gb_sets:add(Fi,Acc); true -> Acc end
end,
FaceSet2 = gb_sets:fold(MyFs, gb_sets:empty(), FaceSet),
%% if the initial verts are on in the face region ... remove edges.
FaceRgns = wings_sel:strict_face_regions(FaceSet2, We),
EsIa = wings_edge:from_faces(FaceSet2, We),
EsIb = gb_sets:intersection(EsIa,Es),
ConnectsOnly = fun(Region, Acc) -> %% if the initial verts are on in the face region ... remove edges.
_Vs = wings_face:to_vertices(Region,We),
_Es = wings_edge:from_faces(Region,We),
I = gb_sets:intersection(gb_sets:from_list(_Vs),gb_sets:from_list([VS0,VE0])),
case gb_sets:is_empty(I) of
true -> gb_sets:subtract(Acc,_Es);
false -> Acc
end
end,
EsI = lists:foldl(ConnectsOnly, EsIb, FaceRgns),
MyCuts = fun(Ei, {#we{}=WeAcc,AccVs}) ->
Pos = gb_trees:get(Ei,ETree),
{We1,Idx} = wings_edge:screaming_cut(Ei, Pos, WeAcc),
{We1,gb_sets:add(Idx,AccVs)}
end,
{We2,Vs} = gb_sets:fold(MyCuts, {We,gb_sets:empty()}, EsI),
St4 = wings_shape:replace(WeID,We2,St0#st{selmode=vertex,sel=[{WeID,Vs}]}),
{save_state,#st{}=St5} = wings_vertex_cmd:command(connect,St4),
#we{} = We5 = gb_trees:get(WeID,St5#st.shapes),
MyBetweens = fun(Ei,#edge{vs=_VS,ve=_VE}, Acc) ->
Two = gb_sets:from_list([_VS,_VE]),
_I = gb_sets:intersection(Two,Vs),
case gb_sets:size(_I) /= 2 of
true -> Acc;
false -> gb_sets:add(Ei,Acc)
end
end,
EsConn = array:sparse_foldl(MyBetweens, gb_sets:empty(), We5#we.es),
%{_,StCleaned} = wings_body:command({cleanup, [{short_edges,true},1.0E-5,{isolated_vs,true}]}, St7),
St5#st{selmode=edge,sel=[{WeID,EsConn}]};
RE: The Connect surface tool by Dimitri. - dgud - 03-21-2016
Something like this?
EDIT: (untested of course)...
Code: command({vertex,{manifoldlab,connect_surface_norm}},#st{sel=[{WeID,Set}]}=St0) ->
We = gb_trees:get(WeID,St0#st.shapes),
case gb_sets:to_list(Set) of
[Vs,Ve] ->
connect_surface(Vs, Ve, We, St0);
_ ->
wings_util:error("only two verts can be selected..") %% FIXME
end.
connect_surface(VS0, VE0, #wx{id=WeID}=We, St0) ->
{Mid, A_B_C_D, Plane1, Plane2} = calc_planes(VS0, VE0, We),
ETree = collect_edges(A_B_C_D, We),
Es = gb_sets:from_list(gb_trees:keys(ETree)),
FaceSet2 = collect_faces(Mid, Plane1, Plane2, Es, We, St0),
{We2,Vs} = make_cuts(ETree, We, limit_edges(VS0, VE0, FaceSet2, Es, We)),
St4 = wings_shape:replace(WeID,We2,St0#st{selmode=vertex,sel=[{WeID,Vs}]}),
{save_state,#st{}=St5} = wings_vertex_cmd:command(connect,St4),
#we{} = We5 = gb_trees:get(WeID,St5#st.shapes),
MyBetweens = fun(Ei,#edge{vs=_VS,ve=_VE}, Acc) ->
Two = gb_sets:from_list([_VS,_VE]),
_I = gb_sets:intersection(Two,Vs),
case gb_sets:size(_I) /= 2 of
true -> Acc;
false -> gb_sets:add(Ei,Acc)
end
end,
EsConn = array:sparse_foldl(MyBetweens, gb_sets:empty(), We5#we.es),
%%{_,StCleaned} = wings_body:command({cleanup, [{short_edges,true},1.0E-5,{isolated_vs,true}]}, St7),
St5#st{selmode=edge,sel=[{WeID,EsConn}]}.
calc_planes(VS0, VE0, We) ->
Pt1a = wings_vertex:pos(VS0,We),
Pt2a = wings_vertex:pos(VE0,We),
V1 = e3d_vec:sub(Pt2a,Pt1a),
Mid0 = e3d_vec:average([Pt1a,Pt2a]),
Norm0 = e3d_vec:average([wings_vertex:normal(VS0,We), wings_vertex:normal(VE0,We)]),
Cross = e3d_vec:norm(e3d_vec:cross(V1,Norm0)),
A_B_C_D = e3d_vec:plane(Mid0,Cross), %% slicer plane
Plane1 = e3d_vec:plane(Pt1a,e3d_vec:norm(V1)),
Plane2 = e3d_vec:plane(Pt2a,e3d_vec:norm(V1)),
{Mid0, A_B_C_D, Plane1, Plane2}.
collect_edges(Plane, #we{es=Etab}=We) ->
MyAcc = fun(Ei, _Val, Acc) ->
#edge{vs=VS,ve=VE} = array:get(Ei,Etab),
Pt1 = wings_vertex:pos(VS,We),
Pt2 = wings_vertex:pos(VE,We),
S1 = e3d_vec:plane_side(Pt1, Plane),
S2 = e3d_vec:plane_side(Pt2, Plane),
if (S1 /= S2) ->
D1 = abs(e3d_vec:plane_dist(Pt1, Plane)),
D2 = abs(e3d_vec:plane_dist(Pt2, Plane)),
Dir = e3d_vec:norm(e3d_vec:sub(Pt2,Pt1)),
Percent = D1/(D1+D2),
PtX = e3d_vec:add(Pt1, e3d_vec:mul(Dir, Percent*wings_edge:length(Ei,We))),
gb_trees:enter(Ei,PtX,Acc);
true ->
Acc
end
end,
array:sparse_foldl(MyAcc, gb_trees:empty(), Etab).
collect_faces(Mid, Plane1, Plane2, Es, #we{id=Id} = We, St0) ->
St1 = St0#st{selmode=edge,sel=[{Id,Es}]},
#st{sel=[{Id,FaceSet}]} = wings_sel_conv:mode(face,St1),
MyFs = fun(Fi, Acc) ->
Center = wings_face:center(Fi, We),
S1a = e3d_vec:plane_side(Mid, Plane1),
S2a = e3d_vec:plane_side(Center, Plane1),
S1b = e3d_vec:plane_side(Mid, Plane2),
S2b = e3d_vec:plane_side(Center, Plane2),
if (S1a ==S2a) andalso (S1b ==S2b) ->
gb_sets:add(Fi,Acc);
true -> Acc end
end,
gb_sets:fold(MyFs, gb_sets:empty(), FaceSet).
limit_edges(VS0, VE0, FaceSet2, Es, #{} = We) ->
%% if the initial verts are on in the face region ... remove edges.
FaceRgns = wings_sel:strict_face_regions(FaceSet2, We),
EsIa = wings_edge:from_faces(FaceSet2, We),
EsIb = gb_sets:intersection(EsIa,Es),
ConnectsOnly = fun(Region, Acc) ->
%% if the initial verts are on in the face region ... remove edges.
_Vs = wings_face:to_vertices(Region,We),
_Es = wings_edge:from_faces(Region,We),
I = gb_sets:intersection(gb_sets:from_list(_Vs),
gb_sets:from_list([VS0,VE0])),
case gb_sets:is_empty(I) of
true -> gb_sets:subtract(Acc,_Es);
false -> Acc
end
end,
lists:foldl(ConnectsOnly, EsIb, FaceRgns).
make_cuts(ETree, We, EsI) ->
MyCuts = fun(Ei, {#we{}=WeAcc,AccVs}) ->
Pos = gb_trees:get(Ei,ETree),
{We1,Idx} = wings_edge:screaming_cut(Ei, Pos, WeAcc),
{We1,gb_sets:add(Idx,AccVs)}
end,
gb_sets:fold(MyCuts, {We,gb_sets:empty()}, EsI).
RE: The Connect surface tool by Dimitri. - ggaliens - 03-21-2016
Yes. More function breakout as you have show is definitely a good step. Let me make that change.
Is there enough here to warrant a new module ?
Like wings_connect_surface ? I kinda think it might be a good idea.
RE: The Connect surface tool by Dimitri. - dgud - 03-22-2016
Hmm, re-thought (new english word?),
I think you should patch the current vertex/connect to use the new code
if two verts which are not in the same face are selected.
Good idea?
RE: The Connect surface tool by Dimitri. - ggaliens - 03-23-2016
Code: %% Connect vertices (which must share a face).
connect(Vs, #we{}=We) when not(is_list(Vs)) ->
connect(gb_sets:to_list(Vs),We);
connect([], #we{}=We) -> We;
connect(Vs, #we{}=We) when is_list(Vs) ->
Fs = wings_face:from_vs(Vs, We),
connect(Fs,Vs,We).
%% connect verts on all faces as possible
connect([],_, #we{}=We) -> We;
connect([Fi|FsMore],Vs,#we{}=We) when is_list(Vs) ->
VsFace = wings_face:to_vertices([Fi],We),
case I = gb_sets:intersection(gb_sets:from_list(VsFace),gb_sets:from_list(Vs)) of
[_,_|_]=I ->
We2 = connect(Fi,I,We),
connect(FsMore,Vs,We2);
_ -> connect(FsMore,Vs,We)
end;
connect(_Face, [_], We) -> We;
connect(Face, Vs, #we{} = We0) ->
case polygon_pairs(Face, Vs, We0) of
no -> min_distance_pairs(Face, Vs, We0);
#we{} = We -> We
end.
RE: The Connect surface tool by Dimitri. - ggaliens - 03-23-2016
RE: The Connect surface tool by Dimitri. - Dimitri - 03-27-2016
A lot of progress! Very nice! : - )
A few more changes to support polygon connects ... - ggaliens - 04-04-2016
A few more changes to support polygon connects ...
RE: The Connect surface tool by Dimitri. - Dimitri - 04-07-2016
Progress! This tool may be a very significant tool for many uses. Other than easily drawing geometrical shapes on objects and coloring or extruding them, it can be used -with the aid of a small group of other commands- as a good tool for producing new topology too.
There are some bugs in its workings as far as I detect in experimenting with it but I have no any conclusion yet as to when exactly they appear. When having a conclusion I will report it.
|