Snap Utilities Line: Calculate the nearest edges in a loop (instead of using the selection operator)
In addition to indentation and rearrangement of some functions
This commit is contained in:
parent
08de0de45e
commit
ccfde7b1b8
|
@ -55,15 +55,15 @@ from bpy.props import (
|
|||
|
||||
def get_units_info(scale, unit_system, separate_units):
|
||||
if unit_system == 'METRIC':
|
||||
scale_steps = ((1000, 'km'), (1, 'm'), (1 / 100, 'cm'),
|
||||
(1 / 1000, 'mm'), (1 / 1000000, '\u00b5m'))
|
||||
scale_steps = ((1000, 'km'), (1, 'm'), (1 / 100, 'cm'),
|
||||
(1 / 1000, 'mm'), (1 / 1000000, '\u00b5m'))
|
||||
elif unit_system == 'IMPERIAL':
|
||||
scale_steps = ((5280, 'mi'), (1, '\''),
|
||||
(1 / 12, '"'), (1 / 12000, 'thou'))
|
||||
scale /= 0.3048 # BU to feet
|
||||
scale_steps = ((5280, 'mi'), (1, '\''),
|
||||
(1 / 12, '"'), (1 / 12000, 'thou'))
|
||||
scale /= 0.3048 # BU to feet
|
||||
else:
|
||||
scale_steps = ((1, ' BU'),)
|
||||
separate_units = False
|
||||
scale_steps = ((1, ' BU'),)
|
||||
separate_units = False
|
||||
|
||||
return (scale, scale_steps, separate_units)
|
||||
|
||||
|
@ -73,26 +73,27 @@ def convert_distance(val, units_info, precision=5):
|
|||
sval = val * scale
|
||||
idx = 0
|
||||
while idx < len(scale_steps) - 1:
|
||||
if sval >= scale_steps[idx][0]:
|
||||
break
|
||||
idx += 1
|
||||
if sval >= scale_steps[idx][0]:
|
||||
break
|
||||
idx += 1
|
||||
factor, suffix = scale_steps[idx]
|
||||
sval /= factor
|
||||
if not separate_units or idx == len(scale_steps) - 1:
|
||||
dval = str(round(sval, precision)) + suffix
|
||||
dval = str(round(sval, precision)) + suffix
|
||||
else:
|
||||
ival = int(sval)
|
||||
dval = str(round(ival, precision)) + suffix
|
||||
fval = sval - ival
|
||||
ival = int(sval)
|
||||
dval = str(round(ival, precision)) + suffix
|
||||
fval = sval - ival
|
||||
idx += 1
|
||||
while idx < len(scale_steps):
|
||||
fval *= scale_steps[idx - 1][0] / scale_steps[idx][0]
|
||||
if fval >= 1:
|
||||
dval += ' ' \
|
||||
+ ("%.1f" % fval) \
|
||||
+ scale_steps[idx][1]
|
||||
break
|
||||
idx += 1
|
||||
while idx < len(scale_steps):
|
||||
fval *= scale_steps[idx - 1][0] / scale_steps[idx][0]
|
||||
if fval >= 1:
|
||||
dval += ' ' \
|
||||
+ ("%.1f" % fval) \
|
||||
+ scale_steps[idx][1]
|
||||
break
|
||||
idx += 1
|
||||
|
||||
return dval
|
||||
|
||||
|
||||
|
@ -166,6 +167,38 @@ def out_Location(rv3d, region, orig, vector):
|
|||
return hit
|
||||
|
||||
|
||||
def get_closest_edge(bm, point, dist):
|
||||
r_edge = None
|
||||
for edge in bm.edges:
|
||||
v1 = edge.verts[0].co
|
||||
v2 = edge.verts[1].co
|
||||
# Test the BVH (AABB) first
|
||||
for i in range(3):
|
||||
if v1[i] <= v2[i]:
|
||||
isect = v1[i] - dist <= point[i] <= v2[i] + dist
|
||||
else:
|
||||
isect = v2[i] - dist <= point[i] <= v1[i] + dist
|
||||
|
||||
if not isect:
|
||||
break
|
||||
else:
|
||||
ret = intersect_point_line(point, v1, v2)
|
||||
|
||||
if ret[1] < 0.0:
|
||||
tmp = v1
|
||||
elif ret[1] > 1.0:
|
||||
tmp = v2
|
||||
else:
|
||||
tmp = ret[0]
|
||||
|
||||
new_dist = (point - tmp).length
|
||||
if new_dist <= dist:
|
||||
dist = new_dist
|
||||
r_edge = edge
|
||||
|
||||
return r_edge
|
||||
|
||||
|
||||
class SnapCache():
|
||||
bvert = None
|
||||
vco = None
|
||||
|
@ -242,11 +275,11 @@ def snap_utilities(
|
|||
cache.v2dmid = location_3d_to_region_2d(region, rv3d, cache.vmid)
|
||||
|
||||
if previous_vert and previous_vert not in bm_geom.verts:
|
||||
pvert_co = obj_matrix_world * previous_vert.co
|
||||
perp_point = intersect_point_line(pvert_co, cache.v0, cache.v1)
|
||||
cache.vperp = perp_point[0]
|
||||
# factor = point_perpendicular[1]
|
||||
cache.v2dperp = location_3d_to_region_2d(region, rv3d, perp_point[0])
|
||||
pvert_co = obj_matrix_world * previous_vert.co
|
||||
perp_point = intersect_point_line(pvert_co, cache.v0, cache.v1)
|
||||
cache.vperp = perp_point[0]
|
||||
# factor = point_perpendicular[1]
|
||||
cache.v2dperp = location_3d_to_region_2d(region, rv3d, perp_point[0])
|
||||
|
||||
# else: cache.v2dperp = None
|
||||
|
||||
|
@ -273,9 +306,8 @@ def snap_utilities(
|
|||
is_increment = True
|
||||
|
||||
r_type = 'EDGE'
|
||||
fac = fac_nearest_to_segment_2d(mcursor, cache.v2d0, cache.v2d1)
|
||||
fac *= cache.v2d0.z / cache.v2d1.z # convert to fac3d
|
||||
r_loc = cache.v0 + fac * (cache.v1 - cache.v0)
|
||||
orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor)
|
||||
r_loc = intersect_line_line(cache.v0, cache.v1, orig, orig + view_vector)[0]
|
||||
|
||||
elif isinstance(bm_geom, bmesh.types.BMFace):
|
||||
is_increment = True
|
||||
|
@ -284,7 +316,7 @@ def snap_utilities(
|
|||
if cache.bface != bm_geom:
|
||||
cache.bface = bm_geom
|
||||
cache.fmid = obj_matrix_world * bm_geom.calc_center_median()
|
||||
cache.fnor = bm_geom.normal * obj_matrix_world.inverted()
|
||||
cache.fnor = bm_geom.normal * obj_matrix_world
|
||||
|
||||
orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor)
|
||||
end = orig + view_vector
|
||||
|
@ -302,6 +334,9 @@ def snap_utilities(
|
|||
|
||||
face_index = -1
|
||||
if cache.out_obj is None:
|
||||
## TODO: The Scene.raycast also tests the edited object.
|
||||
# This is highly inefficient because the edited object
|
||||
# does not keep DerivedMesh which forces rebuilding the bvhtree.
|
||||
result, r_loc, normal, face_index, cache.out_obj, cache.out_obmat = scene.ray_cast(orig, view_vector)
|
||||
if result:
|
||||
r_type = 'FACE'
|
||||
|
@ -354,7 +389,7 @@ def snap_utilities(
|
|||
is_increment = False
|
||||
r_loc = intersect_point_line(r_loc, constrain[0], constrain[1])[0]
|
||||
else:
|
||||
r_loc = intersect_line_line(constrain[0], constrain[1], orig, end)[0]
|
||||
r_loc = intersect_line_line(constrain[0], constrain[1], orig, orig + view_vector)[0]
|
||||
|
||||
elif not r_loc:
|
||||
r_loc = out_Location(rv3d, region, orig, view_vector)
|
||||
|
@ -371,117 +406,153 @@ def snap_utilities(
|
|||
return r_loc, r_type, bm_geom, r_len
|
||||
|
||||
|
||||
def get_isolated_edges(bmvert):
|
||||
def get_loose_linked_edges(bmvert):
|
||||
linked = [e for e in bmvert.link_edges if not e.link_faces]
|
||||
for e in linked:
|
||||
linked += [le for v in e.verts if not v.link_faces for le in v.link_edges if le not in linked]
|
||||
return linked
|
||||
|
||||
|
||||
def draw_line(self, obj, Bmesh, bm_geom, location):
|
||||
def draw_line(self, obj, bm, bm_geom, location):
|
||||
if not hasattr(self, 'list_verts'):
|
||||
self.list_verts = []
|
||||
|
||||
if not hasattr(self, 'list_edges'):
|
||||
self.list_edges = []
|
||||
|
||||
if not hasattr(self, 'list_faces'):
|
||||
self.list_faces = []
|
||||
update_edit_mesh = False
|
||||
tessface = False
|
||||
|
||||
if bm_geom is None:
|
||||
vertices = (bmesh.ops.create_vert(Bmesh, co=(location)))
|
||||
self.list_verts.append(vertices['vert'][0])
|
||||
vert = bm.verts.new(location)
|
||||
self.list_verts.append(vert)
|
||||
|
||||
elif isinstance(bm_geom, bmesh.types.BMVert):
|
||||
if (bm_geom.co - location).length < .01:
|
||||
if (bm_geom.co - location).length_squared < .001:
|
||||
if self.list_verts == [] or self.list_verts[-1] != bm_geom:
|
||||
self.list_verts.append(bm_geom)
|
||||
else:
|
||||
vertices = bmesh.ops.create_vert(Bmesh, co=(location))
|
||||
self.list_verts.append(vertices['vert'][0])
|
||||
vert = bm.verts.new(location)
|
||||
self.list_verts.append(vert)
|
||||
|
||||
elif isinstance(bm_geom, bmesh.types.BMEdge):
|
||||
self.list_edges.append(bm_geom)
|
||||
vector_p0_l = (bm_geom.verts[0].co - location)
|
||||
vector_p1_l = (bm_geom.verts[1].co - location)
|
||||
cross = vector_p0_l.cross(vector_p1_l) / bm_geom.calc_length()
|
||||
ret = intersect_point_line(location, bm_geom.verts[0].co, bm_geom.verts[1].co)
|
||||
|
||||
if cross < Vector((0.001, 0, 0)): # or round(vector_p0_l.angle(vector_p1_l), 2) == 3.14:
|
||||
factor = vector_p0_l.length / bm_geom.calc_length()
|
||||
vertex0 = bmesh.utils.edge_split(bm_geom, bm_geom.verts[0], factor)
|
||||
self.list_verts.append(vertex0[1])
|
||||
# self.list_edges.append(vertex0[0])
|
||||
if (ret[0] - location).length_squared < .001:
|
||||
if ret[1] == 0.0:
|
||||
vert = bm_geom.verts[0]
|
||||
elif ret[1] == 1.0:
|
||||
vert = bm_geom.verts[1]
|
||||
else:
|
||||
edge, vert = bmesh.utils.edge_split(bm_geom, bm_geom.verts[0], ret[1])
|
||||
self.list_verts.append(vert)
|
||||
# self.list_edges.append(edge)
|
||||
|
||||
else: # constrain point is near
|
||||
vertices = bmesh.ops.create_vert(Bmesh, co=(location))
|
||||
self.list_verts.append(vertices['vert'][0])
|
||||
vert = bm.verts.new(location)
|
||||
self.list_verts.append(vert)
|
||||
|
||||
elif isinstance(bm_geom, bmesh.types.BMFace):
|
||||
self.list_faces.append(bm_geom)
|
||||
vertices = (bmesh.ops.create_vert(Bmesh, co=(location)))
|
||||
self.list_verts.append(vertices['vert'][0])
|
||||
vert = bm.verts.new(location)
|
||||
self.list_verts.append(vert)
|
||||
|
||||
# draw, split and create face
|
||||
if len(self.list_verts) >= 2:
|
||||
V1 = self.list_verts[-2]
|
||||
V2 = self.list_verts[-1]
|
||||
# V2_link_verts = [x for y in [a.verts for a in V2.link_edges] for x in y if x != V2]
|
||||
for edge in V2.link_edges:
|
||||
if V1 in edge.verts:
|
||||
v1, v2 = self.list_verts[-2:]
|
||||
# v2_link_verts = [x for y in [a.verts for a in v2.link_edges] for x in y if x != v2]
|
||||
for edge in v2.link_edges:
|
||||
if v1 in edge.verts:
|
||||
self.list_edges.append(edge)
|
||||
break
|
||||
else: # if V1 not in V2_link_verts:
|
||||
if not V2.link_edges:
|
||||
edge = Bmesh.edges.new([V1, V2])
|
||||
else: # if v1 not in v2_link_verts:
|
||||
if not v2.link_edges:
|
||||
edge = bm.edges.new([v1, v2])
|
||||
self.list_edges.append(edge)
|
||||
else:
|
||||
link_two_faces = V1.link_faces and V2.link_faces
|
||||
if link_two_faces:
|
||||
self.list_faces = [f for f in V2.link_faces if f in V1.link_faces]
|
||||
else: # split face
|
||||
if v1.link_faces and v2.link_faces:
|
||||
split_faces = {f for f in v2.link_faces if f in v1.link_faces}
|
||||
|
||||
else:
|
||||
split_faces = set()
|
||||
if v1.link_faces:
|
||||
faces = v1.link_faces
|
||||
co2 = v2.co.copy()
|
||||
else:
|
||||
faces = v2.link_faces
|
||||
co2 = v1.co.copy()
|
||||
|
||||
elif not self.list_faces:
|
||||
faces, co2 = (V1.link_faces, V2.co.copy()) if V1.link_faces else (V2.link_faces, V1.co.copy())
|
||||
for face in faces:
|
||||
if bmesh.geometry.intersect_face_point(face, co2):
|
||||
co = co2 - face.calc_center_median()
|
||||
if co.dot(face.normal) < 0.001:
|
||||
self.list_faces.append(face)
|
||||
split_faces.add(face)
|
||||
|
||||
if self.list_faces:
|
||||
edge = Bmesh.edges.new([V1, V2])
|
||||
if split_faces:
|
||||
edge = bm.edges.new([v1, v2])
|
||||
self.list_edges.append(edge)
|
||||
ed_list = get_isolated_edges(V2)
|
||||
for face in set(self.list_faces):
|
||||
facesp = bmesh.utils.face_split_edgenet(face, list(set(ed_list)))
|
||||
self.list_faces = []
|
||||
ed_list = get_loose_linked_edges(v2)
|
||||
for face in split_faces:
|
||||
facesp = bmesh.utils.face_split_edgenet(face, ed_list)
|
||||
del split_faces
|
||||
update_edit_mesh = True
|
||||
tessface = True
|
||||
else:
|
||||
if self.intersect:
|
||||
facesp = bmesh.ops.connect_vert_pair(Bmesh, verts=[V1, V2], verts_exclude=Bmesh.verts)
|
||||
facesp = bmesh.ops.connect_vert_pair(bm, verts=[v1, v2], verts_exclude=bm.verts)
|
||||
# print(facesp)
|
||||
if not self.intersect or not facesp['edges']:
|
||||
edge = Bmesh.edges.new([V1, V2])
|
||||
edge = bm.edges.new([v1, v2])
|
||||
self.list_edges.append(edge)
|
||||
else:
|
||||
for edge in facesp['edges']:
|
||||
self.list_edges.append(edge)
|
||||
bmesh.update_edit_mesh(obj.data, tessface=True, destructive=True)
|
||||
|
||||
# create face
|
||||
if self.create_face:
|
||||
ed_list = self.list_edges.copy()
|
||||
for edge in V2.link_edges:
|
||||
ed_list = set(self.list_edges)
|
||||
for edge in v2.link_edges:
|
||||
for vert in edge.verts:
|
||||
if vert in self.list_verts:
|
||||
ed_list.append(edge)
|
||||
for edge in get_isolated_edges(V2):
|
||||
if edge not in ed_list:
|
||||
ed_list.append(edge)
|
||||
bmesh.ops.edgenet_fill(Bmesh, edges=list(set(ed_list)))
|
||||
bmesh.update_edit_mesh(obj.data, tessface=True, destructive=True)
|
||||
if vert != v2 and vert in self.list_verts:
|
||||
ed_list.add(edge)
|
||||
break
|
||||
# print('face created')
|
||||
else:
|
||||
continue
|
||||
# Inner loop was broken, break the outer
|
||||
break
|
||||
|
||||
return [obj.matrix_world * a.co for a in self.list_verts]
|
||||
ed_list.update(get_loose_linked_edges(v2))
|
||||
|
||||
bmesh.ops.edgenet_fill(bm, edges=list(ed_list))
|
||||
update_edit_mesh = True
|
||||
tessface = True
|
||||
# print('face created')
|
||||
if update_edit_mesh:
|
||||
bmesh.update_edit_mesh(obj.data, tessface = tessface, destructive=True)
|
||||
return [obj.matrix_world * v.co for v in self.list_verts]
|
||||
|
||||
|
||||
class NavigationKeys:
|
||||
def __init__(self, context):
|
||||
# TO DO:
|
||||
# 'View Orbit', 'View Pan', 'NDOF Orbit View', 'NDOF Pan View'
|
||||
self._rotate = set()
|
||||
self._move = set()
|
||||
self._zoom = set()
|
||||
for key in context.window_manager.keyconfigs.user.keymaps['3D View'].keymap_items:
|
||||
if key.idname == 'view3d.rotate':
|
||||
#self.keys_rotate[key.id]={'Alt': key.alt, 'Ctrl': key.ctrl, 'Shift':key.shift, 'Type':key.type, 'Value':key.value}
|
||||
self._rotate.add((key.alt, key.ctrl, key.shift, key.type, key.value))
|
||||
if key.idname == 'view3d.move':
|
||||
self._move.add((key.alt, key.ctrl, key.shift, key.type, key.value))
|
||||
if key.idname == 'view3d.zoom':
|
||||
if key.type == 'WHEELINMOUSE':
|
||||
self._zoom.add((key.alt, key.ctrl, key.shift, 'WHEELUPMOUSE', key.value, key.properties.delta))
|
||||
elif key.type == 'WHEELOUTMOUSE':
|
||||
self._zoom.add((key.alt, key.ctrl, key.shift, 'WHEELDOWNMOUSE', key.value, key.properties.delta))
|
||||
else:
|
||||
self._zoom.add((key.alt, key.ctrl, key.shift, key.type, key.value, key.properties.delta))
|
||||
|
||||
|
||||
class CharMap:
|
||||
|
@ -542,62 +613,13 @@ class SnapUtilitiesLine(Operator):
|
|||
(context.object is not None and
|
||||
context.object.type == 'MESH'))
|
||||
|
||||
def modal_navigation(self, context, event):
|
||||
# TO DO:
|
||||
# 'View Orbit', 'View Pan', 'NDOF Orbit View', 'NDOF Pan View'
|
||||
rv3d = context.region_data
|
||||
if not hasattr(self, 'navigation_cache'): # or self.navigation_cache == False:
|
||||
# print('update navigation')
|
||||
self.navigation_cache = True
|
||||
self.keys_rotate = set()
|
||||
self.keys_move = set()
|
||||
self.keys_zoom = set()
|
||||
for key in context.window_manager.keyconfigs.user.keymaps['3D View'].keymap_items:
|
||||
if key.idname == 'view3d.rotate':
|
||||
# self.keys_rotate[key.id] = {'Alt': key.alt, 'Ctrl': key.ctrl,
|
||||
# 'Shift':key.shift, 'Type':key.type, 'Value':key.value}
|
||||
self.keys_rotate.add((key.alt, key.ctrl, key.shift, key.type, key.value))
|
||||
if key.idname == 'view3d.move':
|
||||
self.keys_move.add((key.alt, key.ctrl, key.shift, key.type, key.value))
|
||||
if key.idname == 'view3d.zoom':
|
||||
self.keys_zoom.add(
|
||||
(key.alt, key.ctrl, key.shift, key.type,
|
||||
key.value, key.properties.delta)
|
||||
)
|
||||
if key.type == 'WHEELINMOUSE':
|
||||
self.keys_zoom.add(
|
||||
(key.alt, key.ctrl, key.shift, 'WHEELDOWNMOUSE',
|
||||
key.value, key.properties.delta)
|
||||
)
|
||||
if key.type == 'WHEELOUTMOUSE':
|
||||
self.keys_zoom.add(
|
||||
(key.alt, key.ctrl, key.shift, 'WHEELUPMOUSE',
|
||||
key.value, key.properties.delta)
|
||||
)
|
||||
|
||||
evkey = (event.alt, event.ctrl, event.shift, event.type, event.value)
|
||||
if evkey in self.keys_rotate:
|
||||
bpy.ops.view3d.rotate('INVOKE_DEFAULT')
|
||||
elif evkey in self.keys_move:
|
||||
if event.shift and self.vector_constrain and \
|
||||
self.vector_constrain[2] in {'RIGHT_SHIFT', 'LEFT_SHIFT', 'shift'}:
|
||||
self.vector_constrain = None
|
||||
bpy.ops.view3d.move('INVOKE_DEFAULT')
|
||||
else:
|
||||
for key in self.keys_zoom:
|
||||
if evkey == key[0:5]:
|
||||
delta = key[5]
|
||||
if delta == 0:
|
||||
bpy.ops.view3d.zoom('INVOKE_DEFAULT')
|
||||
else:
|
||||
rv3d.view_distance += delta * rv3d.view_distance / 6
|
||||
rv3d.view_location -= delta * (self.location - rv3d.view_location) / 6
|
||||
break
|
||||
|
||||
def draw_callback_px(self, context):
|
||||
# draw 3d point OpenGL in the 3D View
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glDisable(bgl.GL_DEPTH_TEST)
|
||||
# bgl.glPushMatrix()
|
||||
# bgl.glMultMatrixf(self.obj_glmatrix)
|
||||
|
||||
if self.vector_constrain:
|
||||
vc = self.vector_constrain
|
||||
|
@ -628,6 +650,8 @@ class SnapUtilitiesLine(Operator):
|
|||
Color4f = self.center_color
|
||||
elif self.type == 'PERPENDICULAR':
|
||||
Color4f = self.perpendicular_color
|
||||
else: # self.type == None
|
||||
Color4f = self.out_color
|
||||
|
||||
bgl.glColor4f(*Color4f)
|
||||
bgl.glPointSize(10)
|
||||
|
@ -648,6 +672,7 @@ class SnapUtilitiesLine(Operator):
|
|||
bgl.glEnd()
|
||||
|
||||
# restore opengl defaults
|
||||
# bgl.glPopMatrix()
|
||||
bgl.glDepthRange(0, 1)
|
||||
bgl.glPointSize(1)
|
||||
bgl.glLineWidth(1)
|
||||
|
@ -655,6 +680,32 @@ class SnapUtilitiesLine(Operator):
|
|||
bgl.glDisable(bgl.GL_LINE_STIPPLE)
|
||||
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
|
||||
|
||||
|
||||
def modal_navigation(self, context, event):
|
||||
evkey = (event.alt, event.ctrl, event.shift, event.type, event.value)
|
||||
if evkey in self.navigation_keys._rotate:
|
||||
bpy.ops.view3d.rotate('INVOKE_DEFAULT')
|
||||
elif evkey in self.navigation_keys._move:
|
||||
if event.shift and self.vector_constrain and \
|
||||
self.vector_constrain[2] in {'RIGHT_SHIFT', 'LEFT_SHIFT', 'shift'}:
|
||||
self.vector_constrain = None
|
||||
bpy.ops.view3d.move('INVOKE_DEFAULT')
|
||||
else:
|
||||
for key in self.navigation_keys._zoom:
|
||||
if evkey == key[0:5]:
|
||||
if True: # TODO: Use Zoom to mouse position
|
||||
v3d = context.space_data
|
||||
dist_range = (v3d.clip_start, v3d.clip_end)
|
||||
rv3d = context.region_data
|
||||
if (key[5] < 0 and rv3d.view_distance < dist_range[1]) or\
|
||||
(key[5] > 0 and rv3d.view_distance > dist_range[0]):
|
||||
rv3d.view_location += key[5] * (self.location - rv3d.view_location) / 6
|
||||
rv3d.view_distance -= key[5] * rv3d.view_distance / 6
|
||||
else:
|
||||
bpy.ops.view3d.zoom('INVOKE_DEFAULT', delta = key[5])
|
||||
break
|
||||
|
||||
|
||||
def modal(self, context, event):
|
||||
context.area.tag_redraw()
|
||||
|
||||
|
@ -680,18 +731,12 @@ class SnapUtilitiesLine(Operator):
|
|||
|
||||
mval = Vector((event.mouse_region_x, event.mouse_region_y))
|
||||
|
||||
if self.list_verts != []:
|
||||
previous_vert = self.list_verts[-1]
|
||||
else:
|
||||
previous_vert = None
|
||||
|
||||
outer_verts = self.outer_verts and not self.keytab # is this used?
|
||||
self.location, self.type, self.geom, self.len = snap_utilities(
|
||||
self.cache, context, self.obj_matrix,
|
||||
self.bm, mval,
|
||||
outer_verts=self.outer_verts,
|
||||
outer_verts=(self.outer_verts and not self.keytab),
|
||||
constrain=self.vector_constrain,
|
||||
previous_vert=previous_vert,
|
||||
previous_vert=(self.list_verts[-1] if self.list_verts else None),
|
||||
ignore_obj=self.obj,
|
||||
increment=self.incremental
|
||||
)
|
||||
|
@ -749,20 +794,15 @@ class SnapUtilitiesLine(Operator):
|
|||
self.vector_constrain = [loc, loc + self.constrain_keys[event.type]] + [event.type]
|
||||
|
||||
elif event.type == 'LEFTMOUSE':
|
||||
# SNAP 2D
|
||||
snap_3d = self.location
|
||||
Lsnap_3d = self.obj_matrix.inverted() * snap_3d
|
||||
Snap_2d = location_3d_to_region_2d(self.region, self.rv3d, snap_3d)
|
||||
if self.vector_constrain and isinstance(self.geom, bmesh.types.BMVert): # SELECT FIRST
|
||||
bpy.ops.view3d.select(location=(int(Snap_2d[0]), int(Snap_2d[1])))
|
||||
try:
|
||||
geom2 = self.bm.select_history[0]
|
||||
except: # IndexError or AttributeError:
|
||||
geom2 = None
|
||||
point = self.obj_matinv * self.location
|
||||
# with constraint the intersection can be in a different element of the selected one
|
||||
if self.vector_constrain and self.geom:
|
||||
geom2 = get_closest_edge(self.bm, point, .001)
|
||||
else:
|
||||
geom2 = self.geom
|
||||
|
||||
self.vector_constrain = None
|
||||
self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, Lsnap_3d)
|
||||
self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, point)
|
||||
bpy.ops.ed.undo_push(message="Undo draw line*")
|
||||
|
||||
elif event.type == 'TAB':
|
||||
|
@ -783,7 +823,7 @@ class SnapUtilitiesLine(Operator):
|
|||
text_value = bpy.utils.units.to_value(self.unit_system, 'LENGTH', self.length_entered)
|
||||
vector = (self.location - self.list_verts_co[-1]).normalized()
|
||||
location = (self.list_verts_co[-1] + (vector * text_value))
|
||||
G_location = self.obj_matrix.inverted() * location
|
||||
G_location = self.obj_matinv * location
|
||||
self.list_verts_co = draw_line(self, self.obj, self.bm, self.geom, G_location)
|
||||
self.length_entered = ""
|
||||
self.vector_constrain = None
|
||||
|
@ -865,6 +905,8 @@ class SnapUtilitiesLine(Operator):
|
|||
self.rotMat = self.rv3d.view_matrix.copy()
|
||||
self.obj = bpy.context.active_object
|
||||
self.obj_matrix = self.obj.matrix_world.copy()
|
||||
self.obj_matinv = self.obj_matrix.inverted()
|
||||
# self.obj_glmatrix = bgl.Buffer(bgl.GL_FLOAT, [4, 4], self.obj_matrix.transposed())
|
||||
self.bm = bmesh.from_edit_mesh(self.obj.data)
|
||||
self.cache = SnapCache()
|
||||
|
||||
|
@ -873,6 +915,7 @@ class SnapUtilitiesLine(Operator):
|
|||
self.list_verts_co = []
|
||||
self.bool_update = False
|
||||
self.vector_constrain = ()
|
||||
self.navigation_keys = NavigationKeys(context)
|
||||
self.keytab = False
|
||||
self.keyf8 = False
|
||||
self.type = 'OUT'
|
||||
|
@ -957,14 +1000,15 @@ panels = (
|
|||
|
||||
def update_panel(self, context):
|
||||
message = "Snap Utilities Line: Updating Panel locations has failed"
|
||||
addon_prefs = context.user_preferences.addons[__name__].preferences
|
||||
try:
|
||||
for panel in panels:
|
||||
if "bl_rna" in panel.__dict__:
|
||||
bpy.utils.unregister_class(panel)
|
||||
if addon_prefs.category != panel.bl_category:
|
||||
if "bl_rna" in panel.__dict__:
|
||||
bpy.utils.unregister_class(panel)
|
||||
|
||||
for panel in panels:
|
||||
panel.bl_category = context.user_preferences.addons[__name__].preferences.category
|
||||
bpy.utils.register_class(panel)
|
||||
panel.bl_category = addon_prefs.category
|
||||
bpy.utils.register_class(panel)
|
||||
|
||||
except Exception as e:
|
||||
print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
|
||||
|
@ -1004,7 +1048,7 @@ class SnapAddonPreferences(AddonPreferences):
|
|||
default=False
|
||||
)
|
||||
expand_color_settings = BoolProperty(
|
||||
name="Expand Color Settings",
|
||||
name="Color Settings",
|
||||
description="Expand, to display the color settings",
|
||||
default=False
|
||||
)
|
||||
|
@ -1087,11 +1131,11 @@ class SnapAddonPreferences(AddonPreferences):
|
|||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
icon = "TRIA_DOWN" if self.expand_color_settings else "TRIA_RIGHT"
|
||||
|
||||
box = layout.box()
|
||||
box.prop(self, "expand_color_settings", toggle=True, emboss=False)
|
||||
box.prop(self, "expand_color_settings", icon=icon, toggle=True, emboss=False)
|
||||
if self.expand_color_settings:
|
||||
box.label(text="Snap Colors:")
|
||||
split = box.split()
|
||||
|
||||
col = split.column()
|
||||
|
@ -1104,7 +1148,6 @@ class SnapAddonPreferences(AddonPreferences):
|
|||
col.prop(self, "edge_color")
|
||||
col.prop(self, "perpendicular_color")
|
||||
col = split.column()
|
||||
col.scale_y = 1.5
|
||||
col.prop(self, "vert_color")
|
||||
|
||||
row = layout.row()
|
||||
|
@ -1113,8 +1156,8 @@ class SnapAddonPreferences(AddonPreferences):
|
|||
box = col.box()
|
||||
box.label(text="Snap Items:")
|
||||
box.prop(self, "incremental")
|
||||
box.prop(self, "outer_verts", toggle=True)
|
||||
box.prop(self, "increments_grid", toggle=True)
|
||||
box.prop(self, "outer_verts")
|
||||
box.prop(self, "increments_grid")
|
||||
if self.increments_grid:
|
||||
box.prop(self, "relative_scale")
|
||||
else:
|
||||
|
@ -1124,9 +1167,9 @@ class SnapAddonPreferences(AddonPreferences):
|
|||
col = row.column(align=True)
|
||||
box = col.box()
|
||||
box.label(text="Line Tool:")
|
||||
box.prop(self, "intersect", toggle=True)
|
||||
box.prop(self, "create_face", toggle=True)
|
||||
box.prop(self, "create_new_obj", toggle=True)
|
||||
box.prop(self, "intersect")
|
||||
box.prop(self, "create_face")
|
||||
box.prop(self, "create_new_obj")
|
||||
box.separator()
|
||||
box.separator()
|
||||
|
||||
|
|
Loading…
Reference in New Issue