1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
26 from . import cad_module
as cm
29 'SHARED_VERTEX': 'Shared Vertex, no intersection possible',
30 'PARALLEL_EDGES': 'Edges Parallel, no intersection possible',
31 'NON_PLANAR_EDGES': 'Non Planar Edges, no clean intersection point'
35 def add_edges(bm
, pt
, idxs
, fdp
):
37 this function is a disaster --
38 index updates and ensure_lookup_table() are called before this function
39 and after, and i've tried doing this less verbose but results tend to be
40 less predictable. I'm obviously a terrible coder, but can only spend so
41 much time figuring out this stuff.
46 bm
.verts
.ensure_lookup_table()
47 bm
.edges
.ensure_lookup_table()
48 bm
.verts
.index_update()
52 bm
.edges
.index_update()
54 bm
.edges
.new((v1
, v2
))
56 bm
.edges
.index_update()
57 bm
.verts
.ensure_lookup_table()
58 bm
.edges
.ensure_lookup_table()
60 except Exception as err
:
61 print('some failure: details')
65 sys
.stderr
.write('ERROR: %s\n' % str(err
))
66 print(sys
.exc_info()[-1].tb_frame
.f_code
)
67 print('Error on line {}'.format(sys
.exc_info()[-1].tb_lineno
))
70 def remove_earmarked_edges(bm
, earmarked
):
71 edges_select
= [e
for e
in bm
.edges
if e
.index
in earmarked
]
72 bmesh
.ops
.delete(bm
, geom
=edges_select
, context
=2)
75 def perform_vtx(bm
, pt
, edges
, pts
, vertex_indices
):
76 idx1
, idx2
= edges
[0].index
, edges
[1].index
77 fdp
= pt
, edges
, pts
, vertex_indices
79 # this list will hold those edges that pt lies on
80 edges_indices
= cm
.find_intersecting_edges(bm
, pt
, idx1
, idx2
)
81 mode
= 'VTX'[len(edges_indices
)]
84 cl_vert1
= cm
.closest_idx(pt
, edges
[0])
85 cl_vert2
= cm
.closest_idx(pt
, edges
[1])
86 add_edges(bm
, pt
, [cl_vert1
, cl_vert2
], fdp
)
89 to_edge_idx
= edges_indices
[0]
90 from_edge_idx
= idx1
if to_edge_idx
== idx2
else idx2
92 cl_vert
= cm
.closest_idx(pt
, bm
.edges
[from_edge_idx
])
93 to_vert1
, to_vert2
= cm
.vert_idxs_from_edge_idx(bm
, to_edge_idx
)
94 add_edges(bm
, pt
, [cl_vert
, to_vert1
, to_vert2
], fdp
)
97 add_edges(bm
, pt
, vertex_indices
, fdp
)
99 # final refresh before returning to user.
101 remove_earmarked_edges(bm
, edges_indices
)
103 bm
.edges
.index_update()
107 def do_vtx_if_appropriate(bm
, edges
):
108 vertex_indices
= cm
.get_vert_indices_from_bmedges(edges
)
110 # test 1, are there shared vers? if so return non-viable
111 if not len(set(vertex_indices
)) == 4:
112 return {'SHARED_VERTEX'}
114 # test 2, is parallel?
115 p1
, p2
, p3
, p4
= [bm
.verts
[i
].co
for i
in vertex_indices
]
116 point
= cm
.get_intersection([p1
, p2
], [p3
, p4
])
118 return {'PARALLEL_EDGES'}
120 # test 3, coplanar edges?
121 coplanar
= cm
.test_coplanar([p1
, p2
], [p3
, p4
])
123 return {'NON_PLANAR_EDGES'}
125 # point must lie on an edge or the virtual extention of an edge
126 bm
= perform_vtx(bm
, point
, edges
, (p1
, p2
, p3
, p4
), vertex_indices
)
130 class TCAutoVTX(bpy
.types
.Operator
):
131 '''Weld intersecting edges, project converging edges towards their intersection'''
132 bl_idname
= 'tinycad.autovtx'
133 bl_label
= 'VTX autoVTX'
136 def poll(cls
, context
):
137 obj
= context
.active_object
138 return bool(obj
) and obj
.type == 'MESH'
140 def cancel_message(self
, msg
):
142 self
.report({"WARNING"}, msg
)
145 def execute(self
, context
):
147 # final attempt to enter unfragmented bm/mesh
148 # ghastly, but what can I do? it works with these
150 bpy
.ops
.object.mode_set(mode
='OBJECT')
151 bpy
.ops
.object.mode_set(mode
='EDIT')
153 obj
= context
.active_object
156 bm
= bmesh
.from_edit_mesh(me
)
157 bm
.verts
.ensure_lookup_table()
158 bm
.edges
.ensure_lookup_table()
160 edges
= [e
for e
in bm
.edges
if e
.select
and not e
.hide
]
163 message
= do_vtx_if_appropriate(bm
, edges
)
164 if isinstance(message
, set):
165 msg
= messages
.get(message
.pop())
166 return self
.cancel_message(msg
)
169 return self
.cancel_message('select two edges!')
171 bm
.verts
.index_update()
172 bm
.edges
.index_update()
173 bmesh
.update_edit_mesh(me
, True)