Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGermano <germano.costa@ig.com.br>2017-09-10 02:24:12 +0300
committerGermano <germano.costa@ig.com.br>2017-09-10 02:24:12 +0300
commitc5de2c524908ff9efe30bfe6ecd15f3d1f873298 (patch)
tree4b46052452821fa88279a416933505892e90ea5d /mesh_snap_utilities_line.py
parent136a8f839aab01c23a809eba13db014d654511c3 (diff)
[mesh_snap_utilities] use new `snap_context` module
Diffstat (limited to 'mesh_snap_utilities_line.py')
-rw-r--r--mesh_snap_utilities_line.py345
1 files changed, 161 insertions, 184 deletions
diff --git a/mesh_snap_utilities_line.py b/mesh_snap_utilities_line.py
index d7c7bf23..c5e9a825 100644
--- a/mesh_snap_utilities_line.py
+++ b/mesh_snap_utilities_line.py
@@ -19,10 +19,11 @@
# Email: germano.costa@ig.com.br
# Twitter: wii_mano @mano_wii
+
bl_info = {
"name": "Snap Utilities Line",
"author": "Germano Cavalcante",
- "version": (5, 7, 2),
+ "version": (5, 7, 5),
"blender": (2, 75, 0),
"location": "View3D > TOOLS > Snap Utilities > snap utilities",
"description": "Extends Blender Snap controls",
@@ -51,6 +52,13 @@ from bpy.props import (
StringProperty,
)
+from snap_context import SnapContext
+
+##DEBUG = False
+##if DEBUG:
+## from .snap_framebuffer_debug import screenTexture
+## from .snap_context import mesh_drawing
+
def get_units_info(scale, unit_system, separate_units):
if unit_system == 'METRIC':
@@ -106,51 +114,6 @@ def location_3d_to_region_2d(region, rv3d, coord):
))
-def fac_nearest_to_segment_2d(co2v, v2d0, v2d1):
- u = v2d1.xy - v2d0.xy
- h = co2v.xy - v2d0.xy
- return u.dot(h) / u.length_squared
-
-
-def region_2d_to_orig_and_view_vector(region, rv3d, coord, clamp=None):
- viewinv = rv3d.view_matrix.inverted()
- persinv = rv3d.perspective_matrix.inverted()
-
- dx = (2.0 * coord[0] / region.width) - 1.0
- dy = (2.0 * coord[1] / region.height) - 1.0
-
- if rv3d.is_perspective:
- origin_start = viewinv.translation.copy()
-
- out = Vector((dx, dy, -0.5))
-
- w = out.dot(persinv[3].xyz) + persinv[3][3]
-
- view_vector = ((persinv * out) / w) - origin_start
- else:
- view_vector = -viewinv.col[2].xyz
-
- origin_start = ((persinv.col[0].xyz * dx) +
- (persinv.col[1].xyz * dy) +
- viewinv.translation)
-
- if clamp != 0.0:
- if rv3d.view_perspective != 'CAMERA':
- # this value is scaled to the far clip already
- origin_offset = persinv.col[2].xyz
- if clamp is not None:
- if clamp < 0.0:
- origin_offset.negate()
- clamp = -clamp
- if origin_offset.length > clamp:
- origin_offset.length = clamp
-
- origin_start -= origin_offset
-
- view_vector.normalize()
- return origin_start, view_vector
-
-
def out_Location(rv3d, region, orig, vector):
view_matrix = rv3d.view_matrix
v1 = Vector((int(view_matrix[0][0] * 1.5), int(view_matrix[0][1] * 1.5), int(view_matrix[0][2] * 1.5)))
@@ -166,7 +129,7 @@ def out_Location(rv3d, region, orig, vector):
return hit
-def get_closest_edge(bm, point, dist):
+def get_closest_edge(bm, point, dist_sq):
r_edge = None
for edge in bm.edges:
v1 = edge.verts[0].co
@@ -190,9 +153,9 @@ def get_closest_edge(bm, point, dist):
else:
tmp = ret[0]
- new_dist = (point - tmp).length
- if new_dist <= dist:
- dist = new_dist
+ new_dist_sq = (point - tmp).length_squared
+ if new_dist_sq <= dist_sq:
+ dist_sq = new_dist_sq
r_edge = edge
return r_edge
@@ -212,23 +175,16 @@ class SnapCache():
v2dmid = None
v2dperp = None
- bface = None
- fmid = None
- fnor = None
-
- out_obj = None
- out_obmat = None
- out_obimat = None
+ bm_geom_selected = None
def snap_utilities(
- cache, context, obj_matrix_world,
- bm, mcursor,
- outer_verts=False,
- constrain=None,
- previous_vert=None,
- ignore_obj=None,
- increment=0.0):
+ sctx, obj,
+ cache, context, obj_matrix_world,
+ bm, mcursor,
+ constrain = None,
+ previous_vert = None,
+ increment = 0.0):
rv3d = context.region_data
region = context.region
@@ -239,62 +195,89 @@ def snap_utilities(
r_len = 0.0
bm_geom = None
- if bm.select_history:
- bm.select_history[0].select = False
- bm.select_history.clear()
+ if cache.bm_geom_selected:
+ try:
+ cache.bm_geom_selected.select = False
+ except ReferenceError as e:
+ print(e)
+
+ snp_obj, loc, elem = sctx.snap_get(mcursor)
+ view_vector, orig = sctx.last_ray
+
+ if not snp_obj:
+ is_increment = True
+ r_type = 'OUT'
+ r_loc = out_Location(rv3d, region, orig, view_vector)
- bpy.ops.view3d.select(location=(int(mcursor.x), int(mcursor.y)))
+ elif snp_obj.data[0] != obj: #OUT
+ r_loc = loc
- if bm.select_history:
- bm_geom = bm.select_history[0]
+ if constrain:
+ is_increment = False
+ r_loc = intersect_point_line(r_loc, constrain[0], constrain[1])[0]
+ if not r_loc:
+ r_loc = out_Location(rv3d, region, orig, view_vector)
+ elif len(elem) == 1:
+ is_increment = False
+ r_type = 'VERT'
+ elif len(elem) == 2:
+ is_increment = True
+ r_type = 'EDGE'
+ else:
+ is_increment = True
+ r_type = 'FACE'
- if isinstance(bm_geom, bmesh.types.BMVert):
+ elif len(elem) == 1:
r_type = 'VERT'
+ bm_geom = bm.verts[elem[0]]
if cache.bvert != bm_geom:
cache.bvert = bm_geom
- cache.vco = obj_matrix_world * cache.bvert.co
- # cache.v2d = location_3d_to_region_2d(region, rv3d, cache.vco)
+ cache.vco = loc
+ #cache.v2d = location_3d_to_region_2d(region, rv3d, cache.vco)
if constrain:
location = intersect_point_line(cache.vco, constrain[0], constrain[1])
- # factor = location[1]
+ #factor = location[1]
r_loc = location[0]
else:
r_loc = cache.vco
- elif isinstance(bm_geom, bmesh.types.BMEdge):
+ elif len(elem) == 2:
+ v1 = bm.verts[elem[0]]
+ v2 = bm.verts[elem[1]]
+ bm_geom = bm.edges.get([v1, v2])
+
if cache.bedge != bm_geom:
cache.bedge = bm_geom
- cache.v0 = obj_matrix_world * bm_geom.verts[0].co
- cache.v1 = obj_matrix_world * bm_geom.verts[1].co
+ cache.v0 = obj_matrix_world * v1.co
+ cache.v1 = obj_matrix_world * v2.co
cache.vmid = 0.5 * (cache.v0 + cache.v1)
cache.v2d0 = location_3d_to_region_2d(region, rv3d, cache.v0)
cache.v2d1 = location_3d_to_region_2d(region, rv3d, cache.v1)
cache.v2dmid = location_3d_to_region_2d(region, rv3d, cache.vmid)
- if previous_vert and previous_vert not in bm_geom.verts:
+ if previous_vert and previous_vert not in {v1, v2}:
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]
+ #factor = point_perpendicular[1]
cache.v2dperp = location_3d_to_region_2d(region, rv3d, perp_point[0])
- # else: cache.v2dperp = None
+ #else: cache.v2dperp = None
if constrain:
location = intersect_line_line(constrain[0], constrain[1], cache.v0, cache.v1)
- if location is None:
+ if location == None:
is_increment = True
- orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor)
end = orig + view_vector
location = intersect_line_line(constrain[0], constrain[1], orig, end)
r_loc = location[0]
- elif cache.v2dperp and \
- abs(cache.v2dperp[0] - mcursor[0]) < 10 and abs(cache.v2dperp[1] - mcursor[1]) < 10:
- r_type = 'PERPENDICULAR'
- r_loc = cache.vperp
+ elif cache.v2dperp and\
+ abs(cache.v2dperp[0] - mcursor[0]) < 10 and abs(cache.v2dperp[1] - mcursor[1]) < 10:
+ r_type = 'PERPENDICULAR'
+ r_loc = cache.vperp
elif abs(cache.v2dmid[0] - mcursor[0]) < 10 and abs(cache.v2dmid[1] - mcursor[1]) < 10:
r_type = 'CENTER'
@@ -305,94 +288,41 @@ def snap_utilities(
is_increment = True
r_type = 'EDGE'
- 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]
+ r_loc = loc
- elif isinstance(bm_geom, bmesh.types.BMFace):
+ elif len(elem) == 3:
is_increment = True
r_type = 'FACE'
+ tri = [
+ bm.verts[elem[0]],
+ bm.verts[elem[1]],
+ bm.verts[elem[2]],
+ ]
+
+ faces = set(tri[0].link_faces).intersection(tri[1].link_faces, tri[2].link_faces)
+ if len(faces) == 1:
+ bm_geom = faces.pop()
+ else:
+ i = -2
+ edge = None
+ while not edge and i != 1:
+ edge = bm.edges.get([tri[i], tri[i + 1]])
+ i += 1
+ if edge:
+ for l in edge.link_loops:
+ if l.link_loop_next.vert == tri[i] or l.link_loop_prev.vert == tri[i - 2]:
+ bm_geom = l.face
+ break
+ else: # This should never happen!!!!
+ raise
+ bm_geom = faces.pop()
- 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
-
- orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor)
- end = orig + view_vector
- r_loc = intersect_line_plane(orig, end, cache.fmid, cache.fnor, False)
+ r_loc = loc
if constrain:
is_increment = False
r_loc = intersect_point_line(r_loc, constrain[0], constrain[1])[0]
- else: # OUT
- is_increment = True
- r_type = 'OUT'
-
- orig, view_vector = region_2d_to_orig_and_view_vector(region, rv3d, mcursor)
-
- 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'
- cache.out_obimat = cache.out_obmat.inverted()
- else:
- face_index = -1
- r_loc = None
-
- if cache.out_obj and cache.out_obj != ignore_obj:
- if not r_loc or outer_verts:
- location = None
- if face_index == -1:
- # get the ray relative to the cache.out_obj
- ray_origin_obj = cache.out_obimat * orig
- end = orig + view_vector * 1000
- ray_target_obj = cache.out_obimat * end
- result, location, normal, face_index = cache.out_obj.ray_cast(ray_origin_obj, ray_target_obj)
-
- if face_index == -1:
- cache.out_obj = None
-
- elif outer_verts:
- vloc = None
- try:
- me = cache.out_obj.data
- verts = me.polygons[face_index].vertices
- v_dist = 100
-
- for i in verts:
- v_co = cache.out_obmat * me.vertices[i].co
- v_2d = location_3d_to_region_2d(region, rv3d, v_co)
- dist = (Vector(mcursor) - v_2d.xy).length_squared
- if dist < v_dist:
- v_dist = dist
- vloc = v_co
- except Exception as e:
- print('Fail', e)
-
- if vloc:
- is_increment = False
- r_type = 'VERT'
- r_loc = vloc
-
- if not r_loc:
- r_type = 'FACE'
- r_loc = cache.out_obmat * location
-
- if constrain:
- if r_loc:
- 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, orig + view_vector)[0]
-
- elif not r_loc:
- r_loc = out_Location(rv3d, region, orig, view_vector)
-
if previous_vert:
pv_co = obj_matrix_world * previous_vert.co
vec = r_loc - pv_co
@@ -402,6 +332,11 @@ def snap_utilities(
else:
r_len = vec.length
+ if bm_geom:
+ bm_geom.select = True
+
+ cache.bm_geom_selected = bm_geom
+
return r_loc, r_type, bm_geom, r_len
@@ -421,6 +356,7 @@ def draw_line(self, obj, bm, bm_geom, location):
split_faces = set()
+ drawing_is_dirt = False
update_edit_mesh = False
tessface = False
@@ -435,6 +371,7 @@ def draw_line(self, obj, bm, bm_geom, location):
else:
vert = bm.verts.new(location)
self.list_verts.append(vert)
+ drawing_is_dirt = True
elif isinstance(bm_geom, bmesh.types.BMEdge):
self.list_edges.append(bm_geom)
@@ -447,40 +384,46 @@ def draw_line(self, obj, bm, bm_geom, location):
vert = bm_geom.verts[1]
else:
edge, vert = bmesh.utils.edge_split(bm_geom, bm_geom.verts[0], ret[1])
+ drawing_is_dirt = True
self.list_verts.append(vert)
# self.list_edges.append(edge)
else: # constrain point is near
vert = bm.verts.new(location)
self.list_verts.append(vert)
+ drawing_is_dirt = True
elif isinstance(bm_geom, bmesh.types.BMFace):
split_faces.add(bm_geom)
vert = bm.verts.new(location)
self.list_verts.append(vert)
+ drawing_is_dirt = True
# draw, split and create face
if len(self.list_verts) >= 2:
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:
+ edge = bm.edges.get([v1, v2])
+ if edge:
self.list_edges.append(edge)
- break
+
else: # if v1 not in v2_link_verts:
if not v2.link_edges:
edge = bm.edges.new([v1, v2])
self.list_edges.append(edge)
+ drawing_is_dirt = True
else: # split face
- if v1.link_faces and v2.link_faces:
- split_faces.update({f for f in v2.link_faces if f in v1.link_faces})
+ v1_link_faces = v1.link_faces
+ v2_link_faces = v2.link_faces
+ if v1_link_faces and v2_link_faces:
+ split_faces.update(set(v1_link_faces).intersection(v2_link_faces))
else:
- if v1.link_faces:
- faces = v1.link_faces
+ if v1_link_faces:
+ faces = v1_link_faces
co2 = v2.co.copy()
else:
- faces = v2.link_faces
+ faces = v2_link_faces
co2 = v1.co.copy()
for face in faces:
@@ -505,9 +448,12 @@ def draw_line(self, obj, bm, bm_geom, location):
if not self.intersect or not facesp['edges']:
edge = bm.edges.new([v1, v2])
self.list_edges.append(edge)
+ drawing_is_dirt = True
else:
for edge in facesp['edges']:
self.list_edges.append(edge)
+ update_edit_mesh = True
+ tessface = True
# create face
if self.create_face:
@@ -519,7 +465,7 @@ def draw_line(self, obj, bm, bm_geom, location):
break
else:
continue
- # Inner loop was broken, break the outer
+ # Inner loop had a break, break the outer
break
ed_list.update(get_loose_linked_edges(v2))
@@ -529,7 +475,13 @@ def draw_line(self, obj, bm, bm_geom, location):
tessface = True
# print('face created')
if update_edit_mesh:
- bmesh.update_edit_mesh(obj.data, tessface = tessface, destructive=True)
+ bmesh.update_edit_mesh(obj.data, tessface = tessface)
+ self.sctx.update_drawn_snap_object(self.snap_obj)
+ #bm.verts.index_update()
+ elif drawing_is_dirt:
+ self.obj.update_from_editmode()
+ self.sctx.update_drawn_snap_object(self.snap_obj)
+
return [obj.matrix_world * v.co for v in self.list_verts]
@@ -621,6 +573,11 @@ class SnapUtilitiesLine(Operator):
# bgl.glPushMatrix()
# bgl.glMultMatrixf(self.obj_glmatrix)
+## if DEBUG:
+## mesh_drawing._store_current_shader_state(mesh_drawing.PreviousGLState)
+## self.screen.Draw(self.sctx._texture)
+## mesh_drawing._restore_shader_state(mesh_drawing.PreviousGLState)
+
if self.vector_constrain:
vc = self.vector_constrain
if hasattr(self, 'preloc') and self.type in {'VERT', 'FACE'}:
@@ -727,6 +684,7 @@ class SnapUtilitiesLine(Operator):
self.obj = bpy.context.active_object
self.obj_matrix = self.obj.matrix_world.copy()
self.bm = bmesh.from_edit_mesh(self.obj.data)
+ self.sctx.update_drawn_snap_object(self.snap_obj)
return {'RUNNING_MODAL'}
if event.type == 'MOUSEMOVE' or self.bool_update:
@@ -740,13 +698,11 @@ class SnapUtilitiesLine(Operator):
mval = Vector((event.mouse_region_x, event.mouse_region_y))
self.location, self.type, self.geom, self.len = snap_utilities(
- self.cache, context, self.obj_matrix,
+ self.sctx, self.obj, self.cache, context, self.obj_matrix,
self.bm, mval,
- outer_verts=(self.outer_verts and not self.keytab),
- constrain=self.vector_constrain,
- previous_vert=(self.list_verts[-1] if self.list_verts else None),
- ignore_obj=self.obj,
- increment=self.incremental
+ constrain = self.vector_constrain,
+ previous_vert = (self.list_verts[-1] if self.list_verts else None),
+ increment = self.incremental
)
if self.snap_to_grid and self.type == 'OUT':
loc = self.location / self.rd
@@ -756,7 +712,7 @@ class SnapUtilitiesLine(Operator):
if self.keyf8 and self.list_verts_co:
lloc = self.list_verts_co[-1]
- orig, view_vec = region_2d_to_orig_and_view_vector(self.region, self.rv3d, mval)
+ view_vec, orig = self.sctx.last_ray
location = intersect_point_line(lloc, orig, (orig + view_vec))
vec = (location[0] - lloc)
ax, ay, az = abs(vec.x), abs(vec.y), abs(vec.z)
@@ -805,7 +761,7 @@ class SnapUtilitiesLine(Operator):
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)
+ geom2 = get_closest_edge(self.bm, point, 1e-06)
else:
geom2 = self.geom
@@ -816,8 +772,10 @@ class SnapUtilitiesLine(Operator):
elif event.type == 'TAB':
self.keytab = self.keytab is False
if self.keytab:
+ self.sctx.set_snap_mode(False, False, True)
context.tool_settings.mesh_select_mode = (False, False, True)
else:
+ self.sctx.set_snap_mode(True, True, True)
context.tool_settings.mesh_select_mode = (True, True, True)
elif event.type == 'F8':
@@ -845,6 +803,7 @@ class SnapUtilitiesLine(Operator):
context.tool_settings.mesh_select_mode = self.select_mode
context.area.header_text_set()
context.user_preferences.view.use_rotate_around_active = self.use_rotate_around_active
+ self.sctx.free()
if not self.is_editmode:
bpy.ops.object.editmode_toggle()
return {'FINISHED'}
@@ -863,6 +822,7 @@ class SnapUtilitiesLine(Operator):
length = self.len
length = convert_distance(length, self.uinfo)
a = 'length: ' + length
+
context.area.header_text_set(
"hit: %.3f %.3f %.3f %s" % (self.location[0],
self.location[1], self.location[2], a)
@@ -947,6 +907,23 @@ class SnapUtilitiesLine(Operator):
self.outer_verts = preferences.outer_verts
self.snap_to_grid = preferences.increments_grid
+ self.sctx = SnapContext(context.region, context.space_data)
+ self.sctx.set_pixel_dist(12)
+ self.sctx.use_clip_planes(True)
+
+ act_base = context.active_base
+ self.snap_obj = self.sctx.add_obj(act_base.object, act_base.object.matrix_world)
+
+ if self.outer_verts:
+ for base in context.visible_bases:
+ if base != act_base:
+ self.sctx.add_obj(base.object, base.object.matrix_world)
+
+## if DEBUG:
+## self.screen = screenTexture()
+
+ bpy.ops.mesh.select_all(action='DESELECT')
+
self._handle = bpy.types.SpaceView3D.draw_handler_add(
self.draw_callback_px,
(context,),
@@ -1067,7 +1044,7 @@ class SnapAddonPreferences(AddonPreferences):
category = StringProperty(
name="Category",
description="Choose a name for the category of the panel",
- default="Tools",
+ default="Snap Utilities",
update=update_panel
)
incremental = FloatProperty(