Newer
Older
in [op.bl_idname for op in mgr_ops]):
layout.operator("view3d.activate_measure_panel",
text="Activate")
def draw(self, context):
layout = self.layout
sce = context.scene
# Get a single selected object (or nothing).
obj = context.active_object
row = layout.row()
row.operator("view3d.reenter_editmode",
text="Update selection")
# @todo
# description="The calculated values can" \
# " not be updated in mesh edit mode" \
# " automatically. Press this button" \
# " to do this manually, after you changed" \
# " the selection")
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.
# 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.
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
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]")
layout.prop(sce, "measure_panel_draw")
elif len(verts_selected) == 1:
# One vertex selected.
# We measure the distance from the
# selected vertex object to the 3D cursor.
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
row.label(text="", icon='CURSOR')
row.label(text="", icon='ARROW_LEFTRIGHT')
row.label(text="", icon='VERTEXSEL')
layout.prop(sce, "measure_panel_draw")
elif len(verts_selected) == 2:
# Two vertices selected.
# We measure the distance between the
# two selected vertices.
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
row.label(text="", icon='VERTEXSEL')
row.label(text="", icon='ARROW_LEFTRIGHT')
row.label(text="", icon='VERTEXSEL')
layout.prop(sce, "measure_panel_draw")
edges_selected = [ed for ed in mesh.edges if ed.select == 1]
if len(edges_selected) >= 1:
row = layout.row()
row.prop(sce, "measure_panel_calc_edge_length",
text="Edge Length (selected edges)")
if sce.measure_panel_calc_edge_length:
if sce.measure_panel_edge_length >= 0:
box = layout.box()
row = box.row()
row.label(
text=str(len(edges_selected)),
icon='EDGESEL')
row = box.row()
row.label(text="Length")
row.prop(sce, "measure_panel_edge_length")
if len(verts_selected) > 2:
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?
polys_selected = [p for p in mesh.polygons
if p.select == 1]
if sce.measure_panel_area1 >= 0:
box = layout.box()
row = box.row()
row.label(
icon='FACESEL')
row = box.row()
row.label(text="Area")
row.prop(sce, "measure_panel_area1")
row = box.row()
row.label(text="Normal")
row = box.row()
row.prop(sce, "measure_panel_normal1")
else:
row = layout.row()
row.label(text="Selection not supported",
icon='INFO')
if drawTansformButtons:
row = layout.row()
row.prop(sce,
"measure_panel_transform",
expand=True)
mesh_objects = [o for o in context.selected_objects
if o.type == 'MESH']
if len(context.selected_objects) > 2:
# We have more that 2 objects selected...
# EDGES
row = layout.row()
row.prop(sce, "measure_panel_calc_edge_length",
text="Edge Length")
if sce.measure_panel_calc_edge_length:
if len(mesh_objects) > 0:
box = layout.box()
row = box.row()
row.label(text="Total edge length")
row.prop(sce, "measure_panel_edge_length")
# AREA
row = layout.row()
row.prop(sce, "measure_panel_calc_area",
if sce.measure_panel_calc_area:
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()
row.label(text="Multiple objects not yet supported",
icon='INFO')
row = layout.row()
row.label(text="(= More than two meshes)",
icon='INFO')
# @todo Make this work again.
# 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")
elif len(context.selected_objects) == 2:
# 2 objects selected.
# We measure the distance between the 2 selected objects.
obj1, obj2 = context.selected_objects
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
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="")
layout.prop(sce, "measure_panel_draw")
# EDGES
row = layout.row()
row.prop(sce, "measure_panel_calc_edge_length",
text="Edge Length")
if sce.measure_panel_calc_edge_length:
if sce.measure_panel_edge_length >= 0:
if len(mesh_objects) > 0:
box = layout.box()
row = box.row()
row.label(text="Total edge length")
row.prop(sce, "measure_panel_edge_length")
# AREA
row = layout.row()
row.prop(sce, "measure_panel_calc_area",
if sce.measure_panel_calc_area:
# Display surface area of the objects.
if (sce.measure_panel_area1 >= 0
or sce.measure_panel_area2 >= 0):
if sce.measure_panel_area1 >= 0:
box = layout.box()
row = box.row()
row.label(text=obj1.name, icon='OBJECT_DATA')
row = box.row()
row.label(text="Area")
row.prop(sce, "measure_panel_area1")
row = box.row()
row.label(text="Normal")
row = box.row()
row.prop(sce, "measure_panel_normal1")
if sce.measure_panel_area2 >= 0:
box = layout.box()
row = box.row()
row.label(text=obj2.name, icon='OBJECT_DATA')
row = box.row()
row.label(text="Area")
row.prop(sce, "measure_panel_area2")
row = box.row()
row.label(text="Normal")
row = box.row()
row.prop(sce, "measure_panel_normal2")
row = layout.row()
row.prop(sce, "measure_panel_calc_volume",
if sce.measure_panel_calc_volume:
box = layout.box()
row = box.row()
row.label(text=obj1.name, icon='OBJECT_DATA')
if sce.measure_panel_volume1 >= 0:
row = box.row()
row.label(text="Volume")
row.prop(sce, "measure_panel_volume1")
elif sce.measure_panel_volume1 >= -1:
row = box.row()
row.label(text="Mesh is non-manifold!",
icon='INFO')
row.label(text="Mesh has n-gons (faces with " \
"more than 4 edges)!",
box = layout.box()
row = box.row()
row.label(text=obj2.name, icon='OBJECT_DATA')
if sce.measure_panel_volume2 >= 0:
row = box.row()
row.label(text="Volume")
row.prop(sce, "measure_panel_volume2")
elif sce.measure_panel_volume2 >= -1:
row = box.row()
row.label(text="Mesh is non-manifold!",
icon='INFO')
row.label(text="Mesh has n-gons (faces with " \
"more than 4 edges)!",
# One object selected.
# We measure the distance from the object to the 3D cursor.
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
row.label(text="", icon='CURSOR')
row.label(text="", icon='ARROW_LEFTRIGHT')
row.label(text="", icon='OBJECT_DATA')
row.prop(obj, "name", text="")
layout.prop(sce, "measure_panel_draw")
# EDGES
row = layout.row()
row.prop(sce, "measure_panel_calc_edge_length",
text="Edge Length")
if sce.measure_panel_calc_edge_length:
if sce.measure_panel_edge_length >= 0:
if len(mesh_objects) > 0:
box = layout.box()
row = box.row()
row.label(text="Total edge length")
row.prop(sce, "measure_panel_edge_length")
# AREA
row = layout.row()
row.prop(sce, "measure_panel_calc_area",
if sce.measure_panel_calc_area:
# Display surface area of the object.
if sce.measure_panel_area1 >= 0.0:
box = layout.box()
row = box.row()
row.label(text=obj.name, icon='OBJECT_DATA')
row = box.row()
row.label(text="Area")
row.prop(sce, "measure_panel_area1")
row = box.row()
row.label(text="Normal")
row = box.row()
row.prop(sce, "measure_panel_normal1")
row = layout.row()
row.prop(sce, "measure_panel_calc_volume",
if sce.measure_panel_calc_volume:
box = layout.box()
row = box.row()
row.label(text=obj.name, icon='OBJECT_DATA')
if sce.measure_panel_volume1 >= 0:
row = box.row()
row.label(text="Volume")
row.prop(sce, "measure_panel_volume1")
elif sce.measure_panel_volume1 >= -1:
row = box.row()
row.label(text="Mesh is non-manifold!",
icon='INFO')
row.label(text="Mesh has n-gons (faces with " \
"more than 4 edges)!",
elif not context.selected_objects:
# Nothing selected.
# We measure the distance from the origin to the 3D cursor.
box = layout.box()
row = box.row()
row.prop(sce, "measure_panel_dist")
row.label(text="", icon='CURSOR')
row.label(text="", icon='ARROW_LEFTRIGHT')
row.label(text="Origin [0,0,0]")
layout.prop(sce, "measure_panel_draw")
else:
row = layout.row()
row.label(text="Selection not supported",
if drawTansformButtons:
row = layout.row()
row.prop(sce,
"measure_panel_transform",
expand=True)
def register():
Campbell Barton
committed
bpy.utils.register_module(__name__)
bpy.app.handlers.scene_update_post.append(scene_update)
# Define a temporary attribute for the distance value
bpy.types.Scene.measure_panel_dist = bpy.props.FloatProperty(
name="Distance",
precision=PRECISION,
unit="LENGTH")
bpy.types.Scene.measure_panel_edge_length = bpy.props.FloatProperty(
precision=PRECISION,
unit="LENGTH")
bpy.types.Scene.measure_panel_area1 = bpy.props.FloatProperty(
precision=PRECISION,
unit="AREA")
bpy.types.Scene.measure_panel_area2 = bpy.props.FloatProperty(
precision=PRECISION,
unit="AREA")
bpy.types.Scene.measure_panel_normal1 = bpy.props.FloatVectorProperty(
precision=PRECISION,
subtype="XYZ")
bpy.types.Scene.measure_panel_normal2 = bpy.props.FloatVectorProperty(
precision=PRECISION,
subtype="XYZ")
bpy.types.Scene.measure_panel_volume1 = bpy.props.FloatProperty(
precision=PRECISION,
unit="VOLUME")
bpy.types.Scene.measure_panel_volume2 = bpy.props.FloatProperty(
precision=PRECISION,
unit="VOLUME")
TRANSFORM = [
("measure_global", "Global",
"Calculate values in global space"),
"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')
# Define property for the draw setting.
bpy.types.Scene.measure_panel_draw = bpy.props.BoolProperty(
description="Draw distances in 3D View",
bpy.types.Scene.measure_panel_calc_edge_length = bpy.props.BoolProperty(
description="Calculate total length of (selected) edges",
default=0)
# 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)",
# Define property for the calc-volume setting.
bpy.types.Scene.measure_panel_calc_volume = bpy.props.BoolProperty(
description="Calculate mesh volume (heavy CPU "
"usage on bigger meshes)",
# Define dropdown for the global/local setting
bpy.types.Scene.measure_panel_update = bpy.props.BoolProperty(
description="Update CPU heavy calculations",
default=0)
def unregister():
Campbell Barton
committed
bpy.utils.unregister_module(__name__)
bpy.app.handlers.scene_update_post.remove(scene_update)
# Remove properties.
del bpy.types.Scene.measure_panel_dist
del bpy.types.Scene.measure_panel_edge_length
del bpy.types.Scene.measure_panel_area1
del bpy.types.Scene.measure_panel_area2
del bpy.types.Scene.measure_panel_normal1
del bpy.types.Scene.measure_panel_normal2
del bpy.types.Scene.measure_panel_volume1
del bpy.types.Scene.measure_panel_volume2
del bpy.types.Scene.measure_panel_transform
del bpy.types.Scene.measure_panel_draw
del bpy.types.Scene.measure_panel_calc_edge_length
del bpy.types.Scene.measure_panel_calc_area
del bpy.types.Scene.measure_panel_calc_volume
del bpy.types.Scene.measure_panel_update
if __name__ == "__main__":
register()