diff options
Diffstat (limited to 'space_view3d_panel_measure.py')
-rw-r--r-- | space_view3d_panel_measure.py | 1065 |
1 files changed, 0 insertions, 1065 deletions
diff --git a/space_view3d_panel_measure.py b/space_view3d_panel_measure.py deleted file mode 100644 index c5df0a03..00000000 --- a/space_view3d_panel_measure.py +++ /dev/null @@ -1,1065 +0,0 @@ -# ##### 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 ##### - -bl_addon_info = { - "name": "Measure Panel", - "author": "Buerbaum Martin (Pontiac)", - "version": (0, 7, 9), - "blender": (2, 5, 3), - "api": 31854, - "location": "View3D > Properties > Measure", - "description": "Measure distances between objects", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" \ - "Scripts/3D_interaction/Panel_Measure", - "tracker_url": "https://projects.blender.org/tracker/index.php?" \ - "func=detail&aid=21445&group_id=153&atid=469", - "category": "3D View"} - -""" -Measure panel - -This script displays in OBJECT MODE: -* The distance of the 3D cursor to the origin of the - 3D space (if NOTHING is selected). -* The distance of the 3D cursor to the center of an object - (if exactly ONE object is selected). -* The distance between 2 object centers - (if exactly TWO objects are selected). -* The surface area of any selected mesh object. - -Display in EDIT MODE (Local and Global space supported): -* The distance of the 3D cursor to the origin - (in Local space it is the object center instead). -* The distance of the 3D cursor to a selected vertex. -* The distance between 2 selected vertices. - -Usage: - -This functionality can be accessed via the -"Properties" panel in 3D View ([N] key). - -It's very helpful to use one or two "Empty" objects with -"Snap during transform" enabled for fast measurement. - -Version history: -v0.7.9 - Updated scene properties for changes in property API. - See http://lists.blender.org/pipermail/bf-committers/ - 2010-September/028654.html - Synced API changes in7from local copy. -v0.7.8 - Various Py API changes by Campbell ... - bl_default_closed -> bl_options = {'DEFAULT_CLOSED'} - x.verts -> x.vertices - @classmethod def poll(cls, context) - No "location" in bl_addon_info->name - bl_addon_info->api -v0.7.7 - One more change to the callback registration code. - Now it should finally work as intended. -v0.7.6 - API changes (r885, r886) - register & unregister function -v0.7.5.3 - Small fix for bug in v0.7.5.1 - (location was off when object was moved) -v0.7.5.2 - Changed callback registration back to original code & - fixed bug in there (use bl_idname instead of bl_label) -v0.7.5.1 - Global mode is now taking rotation into account properly. -v0.7.5 - Fixed lagging and drawing issues. -v0.7.4 - Fixed the add_modal_handler and callback_add code. - Thanks to jesterKing for pointing that out :-) -v0.7.3.1 - Fixed bug that made all lines in Blender stippled :-) -v0.7.3 - Added display of delta x/y/z value in 3d view. - * Inspired by warpi's patch here: - http://blenderartists.org/forum/showpost.php?p=1671033&postcount=47 - * Also added display of dx,dy,dz lines - * Changed the "dist" colors to something not already used - by x/y/z axes. -v0.7.2 - Merged changes from trunk (scripts_addons r847): - * obj.matrix -> obj.matrix_world - * vert.selected -> vert.select - * face.selected -> face.select - * bl_addon_info: warning, wiki_url, tracker_url - * removed __bpydoc__ - * Use fontid=0 for blf functions. 0 is the default font. -v0.7.1 - Merged changes by Campbell: - * Fix for API change: Collections like context.selected_objects - no longer return None for empty lists. - * Update for mathutils, also stripped some redundant - conversions (Mostly "Vector()" stuff) -v0.7 - Initial support for drawing lines. - (Thanks to Algorith for applying my perspective_matrix patch.) - The distance value (in BUs) is also drawn in the 3D view now. - Also fixed some wrong calculations of global/local distances. - Now it's really "what you see is what is calculated". - Use bl_addon_info for Add-On information. - Use "3D View" in category & name - Renamed reenter_editmode to view3d.reenter_editmode. - Renamed panel_measure.py into space_view3d_panel_measure.py - Active object is only used for edit-mode now. Measurement - with exactly one sel. (but not necessarily active) object - now gets the obj via the sel-object array. - API change Mathutils -> mathutils (r557) - Deselecting 1 of 2 objects now works correctly (active object is ignored). - Force a redraw of the area so disabling the "measure_panel_draw" - checkbox will clear the line/text. - Only calculate area (CPU heavy) if a "area" checkbox is enabled. -v0.6.4 - Fixed unneeded meshdata duplication (sometimes crashes Blender). - The script now correctly calculated the surface area (faceAreaGlobal) - of scaled meshes. - http://projects.blender.org/tracker/ - ?func=detail&atid=453&aid=21913&group_id=153 -v0.6.3 - Added register & unregister functions. -v0.6.2 - Fixed precision of second area property. - Reduced display precision to 5 (instead of 6). - Added (commented out code) for shortcut [F5] for - updating EditMode selection & calculation. - Changed the script so it can be managed from the "Add-Ons" tab - in the user preferences. - Corrected FSF address. -v0.6.1 - Updated reenter_editmode operator description. - Fixed search for selected mesh objects. - Added "BU^2" after values that are not yet translated via "unit". -v0.6 - *) Fix: Removed EditMode/ObjectMode toggle stuff. This causes all the - crashes and is generally not stable. - Instead I've added a manual "refresh" button. - I registered a new operator OBJECT_OT_reenter_editmode for this. - *) Use "unit" settings (i.e. none/metric/imperial) - *) Fix: Only display surface area (>=3 objects) if return value is >=0. - *) Minor: Renamed objectFaceArea to objectSurfaceArea - *) Updated Vector() and tuple() usage. - *) Fixed some comments. -v0.5 - Global surface area (object mode) is now calculated as well. - Support area calculation for face selection. - Also made measurement panel closed by default. (Area calculation - may use up a lot of CPU/RAM in extreme cases) -v0.4.1 - Various cleanups. - Using the shorter "scene" instead of "context.scene" - New functions measureGlobal() and measureLocal() for - user-friendly access to the "space" setting. -v0.4 - Calculate & display the surface area of mesh - objects (local space only right now). - Expanded global/local switch. - Made "local" option for 3Dcursor-only in edit mode actually work. - Fixed local/global calculation for 3Dcursor<->vertex in edit mode. -v0.3.2 - Fixed calculation & display of local/global coordinates. - The user can now select via dropdown which space is wanted/needed - Basically this is a bugfix and new feature at the same time :-) -v0.3.1 - Fixed bug where "measure_panel_dist" wasn't defined - before it was used. - Also added the distance calculation "origin -> 3D cursor" for edit mode. -v0.3 - Support for mesh edit mode (1 or 2 selected vertices) -v0.2.1 - Small fix (selecting nothing didn't calculate the distance - of the cursor from the origin anymore) -v0.2 - Distance value is now displayed via a FloatProperty widget (and - therefore saved to file too right now [according to ideasman42]. - The value is save inside the scene right now.) - Thanks goes to ideasman42 (Campbell Barton) for helping me out on this. -v0.1 - Initial revision. Seems to work fine for most purposes. - -More links: -http://gitorious.org/blender-scripts/blender-measure-panel-script -http://blenderartists.org/forum/showthread.php?t=177800 -""" - -import bpy -from bpy.props import * -from mathutils import Vector, Matrix -import bgl -import blf - - -# Precicion for display of float values. -PRECISION = 4 - -# Name of the custom properties as stored in the scene. -COLOR_LOCAL = (1.0, 0.5, 0.0, 0.8) -COLOR_GLOBAL = (0.5, 0.0, 1.0, 0.8) - - -# Returns a single selected object. -# Returns None if more than one (or nothing) is selected. -# Note: Ignores the active object. -def getSingleObject(context): - if len(context.selected_objects) == 1: - return context.selected_objects[0] - - return None - - -# Returns a list with 2 3D points (Vector) and a color (RGBA) -# depending on the current view mode and the selection. -def getMeasurePoints(context): - sce = context.scene - - # Get a single selected object (or nothing). - obj = getSingleObject(context) - - if (context.mode == 'EDIT_MESH'): - obj = context.active_object - - if (obj and obj.type == 'MESH' and obj.data): - # Get mesh data from Object. - mesh = obj.data - - # Get transformation matrix from object. - ob_mat = obj.matrix_world - # Also make an inversed copy! of the matrix. - ob_mat_inv = ob_mat.copy().invert() - # And a transposed one... - ob_mat_trans = ob_mat.copy().transpose() - - # Get the selected vertices. - # @todo: Better (more efficient) way to do this? - verts_selected = [v for v in mesh.vertices if v.select == 1] - - if len(verts_selected) == 0: - # Nothing selected. - # We measure the distance from... - # local ... the object center to the 3D cursor. - # global ... the origin to the 3D cursor. - cur_loc = sce.cursor_location - obj_loc = obj.location.copy() - - # Convert to local space, if needed. - if measureLocal(sce): - p1 = cur_loc - p2 = obj_loc - return (p1, p2, COLOR_GLOBAL) - - else: - p1 = Vector((0.0, 0.0, 0.0)) - p2 = cur_loc - return (p1, p2, COLOR_GLOBAL) - - elif len(verts_selected) == 1: - # One vertex selected. - # We measure the distance from the - # selected vertex object to the 3D cursor. - cur_loc = sce.cursor_location - vert_loc = verts_selected[0].co.copy() - obj_loc = obj.location.copy() - - # Convert to local or global space. - if measureLocal(sce): - p1 = obj_loc + vert_loc - p2 = cur_loc - return (p1, p2, COLOR_LOCAL) - - else: - p1 = vert_loc * ob_mat_trans - p2 = cur_loc - return (p1, p2, COLOR_GLOBAL) - - elif len(verts_selected) == 2: - # Two vertices selected. - # We measure the distance between the - # two selected vertices. - obj_loc = obj.location.copy() - vert1_loc = verts_selected[0].co.copy() - vert2_loc = verts_selected[1].co.copy() - - # Convert to local or global space. - if measureLocal(sce): - p1 = obj_loc + vert1_loc - p2 = obj_loc + vert2_loc - return (p1, p2, COLOR_LOCAL) - - else: - p1 = vert1_loc * ob_mat_trans - p2 = vert2_loc * ob_mat_trans - return (p1, p2, COLOR_GLOBAL) - - else: - return None - - elif (context.mode == 'OBJECT'): - # We are working on object mode. - - if len(context.selected_objects) > 2: - return None - elif len(context.selected_objects) == 2: - # 2 objects selected. - # We measure the distance between the 2 selected objects. - obj1, obj2 = context.selected_objects - obj1_loc = obj1.location.copy() - obj2_loc = obj2.location.copy() - return (obj1_loc, obj2_loc, COLOR_GLOBAL) - - elif (obj): - # One object selected. - # We measure the distance from the object to the 3D cursor. - cur_loc = sce.cursor_location - obj_loc = obj.location.copy() - return (obj_loc, cur_loc, COLOR_GLOBAL) - - elif not context.selected_objects: - # Nothing selected. - # We measure the distance from the origin to the 3D cursor. - p1 = Vector((0.0, 0.0, 0.0)) - p2 = sce.cursor_location - return (p1, p2, COLOR_GLOBAL) - - else: - return None - - -# Return the area of a face (in global space). -# @note Copies the functionality of the following functions, -# but also respects the scaling (via the "obj.matrix_world" parameter): -# @sa: rna_mesh.c:rna_MeshFace_area_get -# @sa: math_geom.c:area_quad_v3 -# @sa: math_geom.c:area_tri_v3 -def faceAreaGlobal(face, obj): - area = 0.0 - - mat = obj.matrix_world - - if len(face.vertices) == 4: - # Quad - - # Get vertex indices - v1, v2, v3, v4 = face.vertices - - # Get vertex data - v1 = obj.data.vertices[v1] - v2 = obj.data.vertices[v2] - v3 = obj.data.vertices[v3] - v4 = obj.data.vertices[v4] - - # Apply transform matrix to vertex coordinates. - v1 = v1.co * mat - v2 = v2.co * mat - v3 = v3.co * mat - v4 = v4.co * mat - - vec1 = v2 - v1 - vec2 = v4 - v1 - - n = vec1.cross(vec2) - - area = n.length / 2.0 - - vec1 = v4 - v3 - vec2 = v2 - v3 - - n = vec1.cross(vec2) - - area += n.length / 2.0 - - elif len(face.vertices) == 3: - # Triangle - - # Get vertex indices - v1, v2, v3 = face.vertices - - # Get vertex data - v1 = obj.data.vertices[v1] - v2 = obj.data.vertices[v2] - v3 = obj.data.vertices[v3] - - # Apply transform matrix to vertex coordinates. - v1 = v1.co * mat - v2 = v2.co * mat - v3 = v3.co * mat - - vec1 = v3 - v2 - vec2 = v1 - v2 - - n = vec1.cross(vec2) - - area = n.length / 2.0 - - return area - - -# Calculate the surface area of a mesh object. -# *) Set selectedOnly=1 if you only want to count selected faces. -# *) Set globalSpace=1 if you want to calculate -# the global surface area (object mode). -# Note: Be sure you have updated the mesh data before -# running this with selectedOnly=1! -# @todo Support other object types (surfaces, etc...)? -def objectSurfaceArea(obj, selectedOnly, globalSpace): - if (obj and obj.type == 'MESH' and obj.data): - areaTotal = 0 - - mesh = obj.data - - # Count the area of all the faces. - for face in mesh.faces: - if not selectedOnly or face.select: - if globalSpace: - areaTotal += faceAreaGlobal(face, obj) - else: - areaTotal += face.area - - return areaTotal - - # We can not calculate an area for this object. - return -1 - - -# User friendly access to the "space" setting. -def measureGlobal(sce): - return (sce.measure_panel_transform == "measure_global") - - -# User friendly access to the "space" setting. -def measureLocal(sce): - return (sce.measure_panel_transform == "measure_local") - - -# Converts 3D coordinates in a 3DRegion -# into 2D screen coordinates for that region. -def region3d_get_2d_coordinates(context, loc_3d): - # Get screen information - mid_x = context.region.width / 2.0 - mid_y = context.region.height / 2.0 - width = context.region.width - height = context.region.height - - # Get matrices - view_mat = context.space_data.region_3d.perspective_matrix - total_mat = view_mat - - # order is important - vec = total_mat * Vector((loc_3d[0], loc_3d[1], loc_3d[2], 1.0)) - - # dehomogenise - vec = Vector(( - vec[0] / vec[3], - vec[1] / vec[3], - vec[2] / vec[3])) - - x = int(mid_x + vec[0] * width / 2.0) - y = int(mid_y + vec[1] * height / 2.0) - - return Vector((x, y, 0)) - - -def draw_measurements_callback(self, context): - sce = context.scene - - draw = 0 - if hasattr(sce, "measure_panel_draw"): - draw = sce.measure_panel_draw - - # 2D drawing code example - #bgl.glBegin(bgl.GL_LINE_STRIP) - #bgl.glVertex2i(0, 0) - #bgl.glVertex2i(80, 100) - #bgl.glEnd() - - # Get measured 3D points and colors. - line = getMeasurePoints(context) - if (line and draw): - p1, p2, color = line - - # Get and convert the Perspective Matrix of the current view/region. - view3d = bpy.context.space_data - region = view3d.region_3d - perspMatrix = region.perspective_matrix - tempMat = [perspMatrix[i][j] for i in range(4) for j in range(4)] - perspBuff = bgl.Buffer(bgl.GL_FLOAT, 16, tempMat) - - # --- - # Store previous OpenGL settings. - # Store MatrixMode - MatrixMode_prev = bgl.Buffer(bgl.GL_INT, [1]) - bgl.glGetIntegerv(bgl.GL_MATRIX_MODE, MatrixMode_prev) - MatrixMode_prev = MatrixMode_prev[0] - - # Store projection matrix - ProjMatrix_prev = bgl.Buffer(bgl.GL_DOUBLE, [16]) - bgl.glGetFloatv(bgl.GL_PROJECTION_MATRIX, ProjMatrix_prev) - - # Store Line width - lineWidth_prev = bgl.Buffer(bgl.GL_FLOAT, [1]) - bgl.glGetFloatv(bgl.GL_LINE_WIDTH, lineWidth_prev) - lineWidth_prev = lineWidth_prev[0] - - # Store GL_BLEND - blend_prev = bgl.Buffer(bgl.GL_BYTE, [1]) - bgl.glGetFloatv(bgl.GL_BLEND, blend_prev) - blend_prev = blend_prev[0] - - line_stipple_prev = bgl.Buffer(bgl.GL_BYTE, [1]) - bgl.glGetFloatv(bgl.GL_LINE_STIPPLE, line_stipple_prev) - line_stipple_prev = line_stipple_prev[0] - - # Store glColor4f - color_prev = bgl.Buffer(bgl.GL_FLOAT, [4]) - bgl.glGetFloatv(bgl.GL_COLOR, color_prev) - - # --- - # Prepare for 3D drawing - bgl.glLoadIdentity() - bgl.glMatrixMode(bgl.GL_PROJECTION) - bgl.glLoadMatrixf(perspBuff) - - bgl.glEnable(bgl.GL_BLEND) - bgl.glEnable(bgl.GL_LINE_STIPPLE) - - # --- - # Draw 3D stuff. - width = 1 - bgl.glLineWidth(width) - # X - bgl.glColor4f(1, 0, 0, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p2[0], p1[1], p1[2]) - bgl.glEnd() - # Y - bgl.glColor4f(0, 1, 0, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p1[0], p2[1], p1[2]) - bgl.glEnd() - # Z - bgl.glColor4f(0, 0, 1, 0.8) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p1[0], p1[1], p2[2]) - bgl.glEnd() - - # Dist - width = 2 - bgl.glLineWidth(width) - bgl.glColor4f(color[0], color[1], color[2], color[3]) - bgl.glBegin(bgl.GL_LINE_STRIP) - bgl.glVertex3f(p1[0], p1[1], p1[2]) - bgl.glVertex3f(p2[0], p2[1], p2[2]) - bgl.glEnd() - - # --- - # Restore previous OpenGL settings - bgl.glLoadIdentity() - bgl.glMatrixMode(MatrixMode_prev) - bgl.glLoadMatrixf(ProjMatrix_prev) - bgl.glLineWidth(lineWidth_prev) - if not blend_prev: - bgl.glDisable(bgl.GL_BLEND) - if not line_stipple_prev: - bgl.glDisable(bgl.GL_LINE_STIPPLE) - bgl.glColor4f(color_prev[0], - color_prev[1], - color_prev[2], - color_prev[3]) - - # --- - # Draw (2D) text - # We do this after drawing the lines so - # we can draw it OVER the line. - coord_2d = region3d_get_2d_coordinates(context, p2 + (p1 - p2) * 0.5) - OFFSET_LINE = 10 # Offset the text a bit to the right. - OFFSET_Y = 15 # Offset of the lines. - OFFSET_VALUE = 30 # Offset of value(s) from the text. - dist = (p1 - p2).length - - texts = [("Dist:", round(dist, PRECISION)), - ("X:", round(abs(p1[0] - p2[0]), PRECISION)), - ("Y:", round(abs(p1[1] - p2[1]), PRECISION)), - ("Z:", round(abs(p1[2] - p2[2]), PRECISION))] - - # Draw all texts - # @todo Get user pref for text color in 3D View - bgl.glColor4f(1.0, 1.0, 1.0, 1.0) - blf.size(0, 12, 72) # Prevent font size to randomly change. - - loc_x = coord_2d[0] + OFFSET_LINE - loc_y = coord_2d[1] - for t in texts: - text = t[0] - value = str(t[1]) + " BU" - - blf.position(0, loc_x, loc_y, 0) - blf.draw(0, text) - blf.position(0, loc_x + OFFSET_VALUE, loc_y, 0) - blf.draw(0, value) - - loc_y -= OFFSET_Y - - -class VIEW3D_OT_display_measurements(bpy.types.Operator): - '''Display the measurements made in the 'Measure' panel''' - # Do not use bl_idname here (class name is used instead), - # so the callback can be added easily. - #bl_idname = "view3d.display_measurements" - bl_label = "Display the measurements made in the" \ - " 'Measure' panel in the 3D View." - bl_options = {'REGISTER'} - - def modal(self, context, event): - context.area.tag_redraw() - - return {'FINISHED'} - - def execute(self, context): - if context.area.type == 'VIEW_3D': - mgr_ops = context.window_manager.operators.values() - if not self.bl_idname in [op.bl_idname for op in mgr_ops]: - # Add the region OpenGL drawing callback - for WINregion in context.area.regions: - if WINregion.type == 'WINDOW': - context.window_manager.add_modal_handler(self) - self._handle = WINregion.callback_add( - draw_measurements_callback, - (self, context), - 'POST_PIXEL') - - print("Measure panel display callback added") - - return {'RUNNING_MODAL'} - - return {'CANCELLED'} - - else: - self.report({'WARNING'}, "View3D not found, cannot run operator") - return {'CANCELLED'} - - -class VIEW3D_OT_reenter_editmode(bpy.types.Operator): - bl_label = "Re-enter EditMode" - bl_idname = "view3d.reenter_editmode" - bl_description = "Update mesh data of an active mesh object." \ - " This is done by exiting and re-entering mesh edit mode." - bl_options = {'REGISTER'} - - def invoke(self, context, event): - - # Get the active object. - obj = context.active_object - - if (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH'): - # Exit and re-enter mesh EditMode. - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.mode_set(mode='EDIT') - return {'FINISHED'} - - return {'CANCELLED'} - - -class VIEW3D_PT_measure(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Measure" - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - # Only display this panel in the object and edit mode 3D view. - if (context.area.type == 'VIEW_3D' and - (context.mode == 'EDIT_MESH' - or context.mode == 'OBJECT')): - return 1 - - return 0 - - def draw_header(self, context): - layout = self.layout - sce = context.scene - - # Force a redraw. - # This prevents the lines still be drawn after - # disabling the "measure_panel_draw" checkbox. - # @todo Better solution? - context.area.tag_redraw() - - # Execute operator (this adds the callback) - # if it wasn't done yet. - bpy.ops.view3d.display_measurements() - - # Define property for the draw setting. - bpy.types.Scene.measure_panel_draw = bpy.props.BoolProperty( - description="Draw distances in 3D View", - default=1) - - # Define property for the calc-area setting. - # @todo prevent double calculations for each refresh automatically? - bpy.types.Scene.measure_panel_calc_area = bpy.props.BoolProperty( - description="Calculate mesh surface area (heavy CPU" \ - " usage on bigger meshes)", - default=0) - - layout.prop(sce, "measure_panel_draw") - - def draw(self, context): - layout = self.layout - sce = context.scene - - # Get a single selected object (or nothing). - obj = getSingleObject(context) - - # Define a temporary attribute for the distance value - bpy.types.Scene.measure_panel_dist = bpy.props.FloatProperty( - name="Distance", - attr="measure_panel_dist", - precision=PRECISION, - unit="LENGTH") - bpy.types.Scene.measure_panel_area1 = bpy.props.FloatProperty( - attr="measure_panel_area1", - precision=PRECISION, - unit="AREA") - bpy.types.Scene.measure_panel_area2 = bpy.props.FloatProperty( - attr="measure_panel_area2", - precision=PRECISION, - unit="AREA") - - TRANSFORM = [ - ("measure_global", "Global", - "Calculate values in global space."), - ("measure_local", "Local", - "Calculate values inside the local object space.")] - - # Define dropdown for the global/local setting - bpy.types.Scene.measure_panel_transform = bpy.props.EnumProperty( - name="Space", - description="Choose in which space you want to measure.", - items=TRANSFORM, - default='measure_global') - - if (context.mode == 'EDIT_MESH'): - obj = context.active_object - - if (obj and obj.type == 'MESH' and obj.data): - # "Note: a Mesh will return the selection state of the mesh - # when EditMode was last exited. A Python script operating - # in EditMode must exit EditMode before getting the current - # selection state of the mesh." - # http://www.blender.org/documentation/249PythonDoc/ - # /Mesh.MVert-class.html#sel - # We can only provide this by existing & re-entering EditMode. - # @todo: Better way to do this? - - # Get mesh data from Object. - mesh = obj.data - - # Get transformation matrix from object. - ob_mat = obj.matrix_world - # Also make an inversed copy! of the matrix. - ob_mat_inv = ob_mat.copy() - Matrix.invert(ob_mat_inv) - - # Get the selected vertices. - # @todo: Better (more efficient) way to do this? - verts_selected = [v for v in mesh.vertices if v.select == 1] - - if len(verts_selected) == 0: - # Nothing selected. - # We measure the distance from... - # local ... the object center to the 3D cursor. - # global ... the origin to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - if measureLocal(sce): - row.label(text="Obj. Center") - else: - row.label(text="Origin [0,0,0]") - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") -# @todo -# description="The surface area value can" \ -# " not be updated in mesh edit mode" \ -# " automatically. Press this button" \ -# " to do this manually, after you changed" \ -# " the selection.") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(verts_selected) == 1: - # One vertex selected. - # We measure the distance from the - # selected vertex object to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="", icon='VERTEXSEL') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(verts_selected) == 2: - # Two vertices selected. - # We measure the distance between the - # two selected vertices. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='VERTEXSEL') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="", icon='VERTEXSEL') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & distance") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - else: - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area (selected faces):") - - if (sce.measure_panel_calc_area): - # Get selected faces - # @todo: Better (more efficient) way to do this? - faces_selected = [f for f in mesh.faces - if f.select == 1] - - if len(faces_selected) > 0: - area = objectSurfaceArea(obj, True, - measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label( - text=str(len(faces_selected)), - icon='FACESEL') - sce.measure_panel_area1 = area - row.prop(sce, "measure_panel_area1") - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection & area") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - else: - row = layout.row() - row.label(text="Selection not supported.", - icon='INFO') - - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection") - - else: - row = layout.row() - row.operator("view3d.reenter_editmode", - text="Update selection") - - elif (context.mode == 'OBJECT'): - # We are working on object mode. - - if len(context.selected_objects) > 2: - # We have more that 2 objects selected... - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area (selected faces):") - - if (sce.measure_panel_calc_area): - - mesh_objects = [o for o in context.selected_objects - if (o.type == 'MESH')] - - if (len(mesh_objects) > 0): - # ... and at least one of them is a mesh. - - # Calculate and display surface area of the objects. - # @todo: Convert to scene units! We do not have a - # FloatProperty field here for automatic conversion. - - row = layout.row() - for o in mesh_objects: - area = objectSurfaceArea(o, False, - measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label(text=o.name, icon='OBJECT_DATA') - row.label(text=str(round(area, PRECISION)) - + " BU^2") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif len(context.selected_objects) == 2: - # 2 objects selected. - # We measure the distance between the 2 selected objects. - - obj1, obj2 = context.selected_objects - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='OBJECT_DATA') - row.prop(obj1, "name", text="") - - row.label(text="", icon='ARROW_LEFTRIGHT') - - row.label(text="", icon='OBJECT_DATA') - row.prop(obj2, "name", text="") - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area:") - - if (sce.measure_panel_calc_area): - # Calculate and display surface area of the objects. - area1 = objectSurfaceArea(obj1, False, measureGlobal(sce)) - area2 = objectSurfaceArea(obj2, False, measureGlobal(sce)) - if (area1 >= 0 or area2 >= 0): - if (area1 >= 0): - row = layout.row() - row.label(text=obj1.name, icon='OBJECT_DATA') - sce.measure_panel_area1 = area1 - row.prop(sce, "measure_panel_area1") - - if (area2 >= 0): - row = layout.row() - row.label(text=obj2.name, icon='OBJECT_DATA') - sce.measure_panel_area2 = area2 - row.prop(sce, "measure_panel_area2") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif (obj): - # One object selected. - # We measure the distance from the object to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - #row.label(text=str(dist_vec.length)) - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - - row.label(text="", icon='ARROW_LEFTRIGHT') - - row.label(text="", icon='OBJECT_DATA') - row.prop(obj, "name", text="") - - row = layout.row() - row.prop(sce, "measure_panel_calc_area", - text="Surface area:") - - if (sce.measure_panel_calc_area): - # Calculate and display surface area of the object. - area = objectSurfaceArea(obj, False, measureGlobal(sce)) - if (area >= 0): - row = layout.row() - row.label(text=obj.name, icon='OBJECT_DATA') - sce.measure_panel_area1 = area - row.prop(sce, "measure_panel_area1") - - row = layout.row() - row.prop(sce, - "measure_panel_transform", - expand=True) - - elif not context.selected_objects: - # Nothing selected. - # We measure the distance from the origin to the 3D cursor. - - # Get the 2 measure points - line = getMeasurePoints(context) - if line != 0: - dist_vec = line[0] - line[1] - - sce.measure_panel_dist = dist_vec.length - - row = layout.row() - row.prop(sce, "measure_panel_dist") - - row = layout.row() - row.label(text="", icon='CURSOR') - row.label(text="", icon='ARROW_LEFTRIGHT') - row.label(text="Origin [0,0,0]") - - else: - row = layout.row() - row.label(text="Selection not supported.", - icon='INFO') - - -def register(): - pass - - -def unregister(): - pass - -if __name__ == "__main__": - register() |