| 
 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.
 
 
 
 |