Fix for bl_info blender versions, many addons used (2, 6, x) instead of (2, 6x, x...
[blender-addons-contrib.git] / ewoc_projects_tools / object_fastorigin.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 __bpydoc__ = """\
20 The FastOrigin addon enables one to interactively set the active objects origin, either by 3D
21 manipulator or Gkey with full support for snapping and realtime preview of this.
22
23
24 Documentation
25
26 First go to User Preferences->Addons and enable the FastOrigin addon in the Object category.
27 Select an object.  Invoke addon (button in Tools panel).  When in Object mode, addon will switch into
28 EditMode and create a sinbgl.gle selected vertex which can be translated by standard means with snapping
29 on for vertices (this can be changed in the standard way to other targets or no snap , the snap target
30 mode will be retained when using the addon a second time).  The 3D cursor will move along with the vert
31 to make the chosen position a bit clearer.  The old origin will remain visible during moving, this is
32 perfectly normal.
33 You can transform the view during operation.
34 Press ENTER to consolidate changes. 3D cursor and Editmode/Object mode
35 will be reset to before addon state.
36
37 REMARK - works only for mesh objects
38
39 If you wish to hotkey FastOrigin:
40 In the Input section of User Preferences at the bottom of the 3D View > Object Mode section click 'Add New' button.
41 In the Operator Identifier box put 'object.fastorigin'.
42 Assign a hotkey.
43 Save as Default (Optional).
44 """
45
46
47 bl_info = {
48         "name": "FastOrigin",
49         "author": "Gert De Roost",
50         "version": (0, 4, 0),
51         "blender": (2, 68, 0),
52         "location": "View3D > Tools",
53         "description": "Set object origin with snapping.",
54         "warning": "",
55         "wiki_url": "",
56         "tracker_url": "",
57         "category": "Object"}
58
59
60
61 import bpy
62 from bpy_extras.view3d_utils import location_3d_to_region_2d
63 import bmesh
64 import bgl
65 import blf
66 from mathutils import *
67 import time
68
69
70 class FastOrigin(bpy.types.Operator):
71         bl_idname = "object.fastorigin"
72         bl_label = "Fast Origin"
73         bl_description = "Set object origin with snapping"
74         bl_options = {'REGISTER', 'UNDO'}
75
76         @classmethod
77         def poll(cls, context):
78                 obj = context.active_object
79                 return (obj and obj.type == 'MESH')
80
81         def invoke(self, context, event):
82
83                 bpy.types.Scene.PreSelOff = bpy.props.BoolProperty(
84                                 name = "PreSelOff",
85                                 description = "Switch off PreSel during Straighten operation",
86                                 default = True)
87
88                 self.init_fastorigin(context)
89
90                 context.window_manager.modal_handler_add(self)
91
92                 self._handle = bpy.types.SpaceView3D.draw_handler_add(self.redraw, (), 'WINDOW', 'POST_PIXEL')
93
94                 return {'RUNNING_MODAL'}
95
96
97         def modal(self, context, event):
98
99                 if event.type in {'LEFTMOUSE', 'MIDDLEMOUSE', 'RIGHTMOUSE', 'WHEELDOWNMOUSE', 'WHEELUPMOUSE', 'G', 'X', 'Y', 'Z', 'MOUSEMOVE'}:
100                         return {'PASS_THROUGH'}
101
102                 elif event.type in {'RET', 'NUMPAD_ENTER'}:
103                         del bpy.types.Scene.PreSelOff
104                         # Consolidate changes.
105                         for v in self.vsellist:
106                                 v.select = True
107                         for e in self.esellist:
108                                 e.select = True
109                         for f in self.fsellist:
110                                 f.select = True
111                         self.bm.verts.remove(self.originvert)
112                         bmesh.update_edit_mesh(self.mesh, destructive=True)
113                         self.mesh.update()
114                         self.bm.free()
115                         context.tool_settings.snap_element = self.snapelsave
116                         context.tool_settings.use_snap = self.snapstsave
117                         bpy.ops.object.editmode_toggle()
118                         bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
119                         self.space3d.cursor_location = self.cursorsave
120                         if self.mode == 'EDIT':
121                                 bpy.ops.object.editmode_toggle()
122                         bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
123                         return {'FINISHED'}
124
125                 elif event.type == 'ESC':
126                         del bpy.types.Scene.PreSelOff
127                         # Cancel
128                         for v in self.vsellist:
129                                 v.select = True
130                         for e in self.esellist:
131                                 e.select = True
132                         for f in self.fsellist:
133                                 f.select = True
134                         self.bm.verts.remove(self.originvert)
135                         bmesh.update_edit_mesh(self.mesh, destructive=True)
136                         self.mesh.update()
137                         self.bm.free()
138                         context.tool_settings.snap_element = self.snapelsave
139                         context.tool_settings.use_snap = self.snapstsave
140                         self.space3d.cursor_location = self.cursorsave
141                         if self.mode == 'EDIT':
142                                 bpy.ops.object.editmode_toggle()
143                         bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
144                         return {'CANCELLED'}
145
146                 return {'RUNNING_MODAL'}
147
148
149         def init_fastorigin(self, context):
150
151                 for space in context.area.spaces:
152                         if space.type == 'VIEW_3D':
153                                 self.space3d = space
154                 self.selobj = context.active_object
155                 self.mesh = self.selobj.data
156                 self.region = context.region
157
158                 self.rv3ds = {}
159                 for a in bpy.context.screen.areas:
160                         if not(a.type == "VIEW_3D"):
161                                 continue
162                         for sp in a.spaces:
163                                 if sp.type == "VIEW_3D":
164                                         for r in a.regions:
165                                                 if not(r.type == "WINDOW"):
166                                                         continue
167                                                 self.rv3ds[r] = sp.region_3d
168
169                 self.mode = self.selobj.mode
170                 if self.mode == 'OBJECT':
171                         bpy.ops.object.editmode_toggle()
172                 self.bm = bmesh.from_edit_mesh(self.mesh)
173
174                 self.vsellist = []
175                 self.esellist = []
176                 self.fsellist = []
177                 for v in self.bm.verts:
178                         if v.select:
179                                 self.vsellist.append(v)
180                 for e in self.bm.edges:
181                         if e.select:
182                                 self.esellist.append(e)
183                 for f in self.bm.faces:
184                         if f.select:
185                                 self.fsellist.append(f)
186
187                 self.snapelem = 'VERTEX'
188                 self.snapstate = True
189
190                 self.snapelsave = context.tool_settings.snap_element
191                 self.snapstsave = context.tool_settings.use_snap
192                 context.tool_settings.snap_element = self.snapelem
193                 context.tool_settings.use_snap = self.snapstate
194                 self.cursorsave = self.space3d.cursor_location.copy()
195                 for v in self.bm.verts:
196                         v.select = False
197                 context.tool_settings.mesh_select_mode = [True, False, False]
198                 self.originvert = self.bm.verts.new((0, 0, 0))
199                 self.originvert.select = True
200                 bmesh.update_edit_mesh(self.mesh, destructive=True)
201                 self.mesh.update()
202                 self.space3d.cursor_location = self.originvert.co[:]
203
204
205         def getscreencoords(self, vec, reg, rv3d):
206
207                 # calculate screencoords of given Vector
208                 vec.rotate(self.selobj.matrix_world)
209                 vec.rotate(self.selobj.matrix_world)
210                 vec =  vec * self.selobj.matrix_world + self.selobj.matrix_world.to_translation()
211                 return location_3d_to_region_2d(reg, rv3d, vec)
212
213
214
215         def redraw(self):
216
217                 drawregion = bpy.context.region
218
219                 rv3d = self.rv3ds[drawregion]
220                 vec = self.originvert.co.copy()
221                 vec.rotate(self.selobj.matrix_world)
222                 vec.rotate(self.selobj.matrix_world)
223                 self.space3d.cursor_location =  vec * self.selobj.matrix_world + self.selobj.matrix_world.to_translation()
224
225                 bgl.glColor3f(1.0, 1.0, 0)
226                 bgl.glBegin(bgl.GL_POLYGON)
227                 x, y = self.getscreencoords(Vector(self.originvert.co), drawregion, rv3d)
228                 bgl.glVertex2f(x-2, y-2)
229                 bgl.glVertex2f(x-2, y+2)
230                 bgl.glVertex2f(x+2, y+2)
231                 bgl.glVertex2f(x+2, y-2)
232                 bgl.glEnd()
233
234                 bgl.glColor3f(1, 1, 0.7)
235                 bgl.glMatrixMode(bgl.GL_PROJECTION)
236                 bgl.glLoadIdentity()
237                 bgl.gluOrtho2D(0, self.region.width, 0, self.region.height)
238                 bgl.glMatrixMode(bgl.GL_MODELVIEW)
239                 bgl.glLoadIdentity()
240                 blf.position(0, self.region.width/2 - 80, self.region.height - 20, 0)
241                 blf.size(0, 12, 72)
242                 blf.draw(0, "FastOrigin :  Enter confirms - ESC cancels")
243
244
245 def panel_func(self, context):
246         self.layout.label(text="FastOrigin:")
247         self.layout.operator("object.fastorigin", text="Choose Origin")
248
249
250 def register():
251         bpy.utils.register_module(__name__)
252         bpy.types.VIEW3D_PT_tools_meshedit.append(panel_func)
253         bpy.types.VIEW3D_PT_tools_objectmode.append(panel_func)
254
255
256 def unregister():
257         bpy.utils.unregister_module(__name__)
258         bpy.types.VIEW3D_PT_tools_meshedit.remove(panel_func)
259         bpy.types.VIEW3D_PT_tools_objectmode.remove(panel_func)
260
261 if __name__ == "__main__":
262         register()
263
264
265