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:
authorStephen Leger <stephen@3dservices.ch>2017-07-22 14:25:28 +0300
committerStephen Leger <stephen@3dservices.ch>2017-07-22 14:26:04 +0300
commitc1ab9b4b9c6c0226f8d7789b92efda9b0f33cfd1 (patch)
tree37d5a97c758fa9af48d1dfb5428edd72072d882a /archipack/archipack_snap.py
parent5638a8783502138500912061dde0e8ee476d7fca (diff)
archipack: T52120 release to official
Diffstat (limited to 'archipack/archipack_snap.py')
-rw-r--r--archipack/archipack_snap.py309
1 files changed, 309 insertions, 0 deletions
diff --git a/archipack/archipack_snap.py b/archipack/archipack_snap.py
new file mode 100644
index 00000000..936a07d8
--- /dev/null
+++ b/archipack/archipack_snap.py
@@ -0,0 +1,309 @@
+# -*- coding:utf-8 -*-
+
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- 1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# ----------------------------------------------------------
+# Author: Stephen Leger (s-leger)
+# Inspired by Okavango's np_point_move
+# ----------------------------------------------------------
+"""
+ Usage:
+ from .archipack_snap import snap_point
+
+ snap_point(takeloc, draw_callback, action_callback, constraint_axis)
+
+ arguments:
+
+ takeloc Vector3d location of point to snap
+
+ constraint_axis boolean tuple for each axis
+ eg: (True, True, False) to constrtaint to xy plane
+
+ draw_callback(context, sp)
+ sp.takeloc
+ sp.placeloc
+ sp.delta
+
+ action_callback(context, event, state, sp)
+ state in {'SUCCESS', 'CANCEL'}
+ sp.takeloc
+ sp.placeloc
+ sp.delta
+
+ with 3d Vectors
+ - delta = placeloc - takeloc
+ - takeloc
+ - placeloc
+
+
+ NOTE:
+ may change grid size to 0.1 round feature (SHIFT)
+ see https://blenderartists.org/forum/showthread.php?205158-Blender-2-5-Snap-mode-increment
+ then use a SHIFT use grid snap
+
+"""
+
+import bpy
+from bpy.types import Operator
+from mathutils import Vector, Matrix
+
+
+def dumb_callback(context, event, state, sp):
+ return
+
+
+def dumb_draw(sp, context):
+ return
+
+
+class SnapStore:
+ """
+ Global store
+ """
+ callback = None
+ draw = None
+ helper = None
+ takeloc = Vector((0, 0, 0))
+ placeloc = Vector((0, 0, 0))
+ constraint_axis = (True, True, False)
+ helper_matrix = Matrix()
+ transform_orientation = 'GLOBAL'
+ release_confirm = True
+ instances_running = 0
+
+ # context related
+ act = None
+ sel = []
+ use_snap = False
+ snap_element = None
+ snap_target = None
+ pivot_point = None
+ trans_orientation = None
+
+
+def snap_point(takeloc=None,
+ draw=dumb_draw,
+ callback=dumb_callback,
+ takemat=None,
+ constraint_axis=(True, True, False),
+ transform_orientation='GLOBAL',
+ mode='OBJECT',
+ release_confirm=True):
+ """
+ Invoke op from outside world
+ in a convenient importable function
+
+ transform_orientation in [‘GLOBAL’, ‘LOCAL’, ‘NORMAL’, ‘GIMBAL’, ‘VIEW’]
+
+ draw(sp, context) a draw callback
+ callback(context, event, state, sp) action callback
+
+ Use either :
+ takeloc Vector, unconstraint or system axis constraints
+ takemat Matrix, constaint to this matrix as 'LOCAL' coordsys
+ The snap source helper use it as world matrix
+ so it is possible to constraint to user defined coordsys.
+ """
+ SnapStore.draw = draw
+ SnapStore.callback = callback
+ SnapStore.constraint_axis = constraint_axis
+ SnapStore.release_confirm = release_confirm
+ if takemat is not None:
+ SnapStore.helper_matrix = takemat
+ takeloc = takemat.translation
+ transform_orientation = 'LOCAL'
+ elif takeloc is not None:
+ SnapStore.helper_matrix = Matrix().Translation(takeloc)
+ else:
+ raise ValueError("ArchipackSnap: Either takeloc or takemat must be defined")
+ SnapStore.takeloc = takeloc
+ SnapStore.placeloc = takeloc
+ SnapStore.transform_orientation = transform_orientation
+
+ # @NOTE: unused mode var to switch between OBJECT and EDIT mode
+ # for ArchipackSnapBase to be able to handle both modes
+ # must implements corresponding helper create and delete actions
+ SnapStore.mode = mode
+ res = bpy.ops.archipack.snap('INVOKE_DEFAULT')
+ # return helper so we are able to move it "live"
+ return SnapStore.helper
+
+class ArchipackSnapBase():
+ """
+ Helper class for snap Operators
+ store and restore context
+ create and destroy helper
+ install and remove a draw_callback working while snapping
+
+ store and provide access to 3d Vectors
+ in draw_callback and action_callback
+ - delta = placeloc - takeloc
+ - takeloc
+ - placeloc
+ """
+ def __init__(self):
+ self._draw_handler = None
+
+ def init(self, context, event):
+ # Store context data
+ if SnapStore.instances_running < 1:
+ SnapStore.sel = [o for o in context.selected_objects]
+ SnapStore.act = context.active_object
+ bpy.ops.object.select_all(action="DESELECT")
+ SnapStore.use_snap = context.tool_settings.use_snap
+ SnapStore.snap_element = context.tool_settings.snap_element
+ SnapStore.snap_target = context.tool_settings.snap_target
+ SnapStore.pivot_point = context.space_data.pivot_point
+ SnapStore.trans_orientation = context.space_data.transform_orientation
+ self.create_helper(context)
+ SnapStore.instances_running += 1
+ # print("ArchipackSnapBase init: %s" % (SnapStore.instances_running))
+ self.set_transform_orientation(context)
+ args = (self, context)
+ self._draw_handler = bpy.types.SpaceView3D.draw_handler_add(SnapStore.draw, args, 'WINDOW', 'POST_PIXEL')
+
+ def exit(self, context):
+ bpy.types.SpaceView3D.draw_handler_remove(self._draw_handler, 'WINDOW')
+ # trick to allow launch 2nd instance
+ # via callback, preserve context as it
+ SnapStore.instances_running -= 1
+ # print("ArchipackSnapBase exit: %s" % (SnapStore.instances_running))
+ if SnapStore.instances_running > 0:
+ return
+
+ self.destroy_helper(context)
+ # Restore original context
+ context.tool_settings.use_snap = SnapStore.use_snap
+ context.tool_settings.snap_element = SnapStore.snap_element
+ context.tool_settings.snap_target = SnapStore.snap_target
+ context.space_data.pivot_point = SnapStore.pivot_point
+ context.space_data.transform_orientation = SnapStore.trans_orientation
+ for o in SnapStore.sel:
+ o.select = True
+ if SnapStore.act is not None:
+ context.scene.objects.active = SnapStore.act
+
+ def set_transform_orientation(self, context):
+ """
+ Allow local constraint orientation to be set
+ """
+ context.space_data.transform_orientation = SnapStore.transform_orientation
+
+ def create_helper(self, context):
+ """
+ Create a helper with fake user
+ or find older one in bpy data and relink to scene
+ currently only support OBJECT mode
+
+ Do target helper be linked to scene in order to work ?
+
+ """
+
+ helper_idx = bpy.data.objects.find('Archipack_snap_helper')
+ if helper_idx > -1:
+ helper = bpy.data.objects[helper_idx]
+ if context.scene.objects.find('Archipack_snap_helper') < 0:
+ context.scene.objects.link(helper)
+ else:
+ bpy.ops.object.add(type='MESH')
+ helper = context.active_object
+ helper.name = 'Archipack_snap_helper'
+ helper.use_fake_user = True
+ helper.data.use_fake_user = True
+ # hide snap helper
+ # helper.hide = True
+ helper.matrix_world = SnapStore.helper_matrix
+ helper.select = True
+ context.scene.objects.active = helper
+ SnapStore.helper = helper
+
+ def destroy_helper(self, context):
+ """
+ Unlink helper
+ currently only support OBJECT mode
+ """
+ if SnapStore.helper is not None:
+ context.scene.objects.unlink(SnapStore.helper)
+ SnapStore.helper = None
+
+ @property
+ def delta(self):
+ return self.placeloc - self.takeloc
+
+ @property
+ def takeloc(self):
+ return SnapStore.takeloc
+
+ @property
+ def placeloc(self):
+ # take from helper when there so the delta
+ # is working even while modal is running
+ if SnapStore.helper is not None:
+ return SnapStore.helper.location
+ else:
+ return SnapStore.placeloc
+
+
+class ARCHIPACK_OT_snap(ArchipackSnapBase, Operator):
+ bl_idname = 'archipack.snap'
+ bl_label = 'Archipack snap'
+ bl_options = {'UNDO'}
+
+ def modal(self, context, event):
+ # print("Snap.modal event %s %s" % (event.type, event.value))
+ context.area.tag_redraw()
+ # NOTE: this part only run after transform LEFTMOUSE RELEASE
+ # or with ESC and RIGHTMOUSE
+ if event.type not in {'ESC', 'RIGHTMOUSE', 'LEFTMOUSE', 'MOUSEMOVE'}:
+ # print("Snap.modal skip unknown event %s %s" % (event.type, event.value))
+ # self.report({'WARNING'}, "ARCHIPACK_OT_snap unknown event")
+ return{'PASS_THROUGH'}
+ if event.type in {'ESC', 'RIGHTMOUSE'}:
+ SnapStore.callback(context, event, 'CANCEL', self)
+ else:
+ SnapStore.placeloc = SnapStore.helper.location
+ SnapStore.callback(context, event, 'SUCCESS', self)
+ self.exit(context)
+ # self.report({'INFO'}, "ARCHIPACK_OT_snap exit")
+ return{'FINISHED'}
+
+ def invoke(self, context, event):
+ if context.area.type == 'VIEW_3D':
+ # print("Snap.invoke event %s %s" % (event.type, event.value))
+ self.init(context, event)
+ context.window_manager.modal_handler_add(self)
+ # print("SnapStore.transform_orientation%s" % (SnapStore.transform_orientation))
+ bpy.ops.transform.translate('INVOKE_DEFAULT',
+ constraint_axis=SnapStore.constraint_axis,
+ constraint_orientation=SnapStore.transform_orientation,
+ release_confirm=SnapStore.release_confirm)
+ return {'RUNNING_MODAL'}
+ else:
+ self.report({'WARNING'}, "View3D not found, cannot run operator")
+ return {'FINISHED'}
+
+
+def register():
+ bpy.utils.register_class(ARCHIPACK_OT_snap)
+
+
+def unregister():
+ bpy.utils.unregister_class(ARCHIPACK_OT_snap)