Skip to content
Snippets Groups Projects
space_view3d_panel_measure.py 53.2 KiB
Newer Older
  • Learn to ignore specific revisions
  •             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
    
            mode = context.mode
    
    
            # Get a single selected object (or nothing).
    
            obj = getSingleObject()
    
            drawTansformButtons = 1
    
    
            if mode == 'EDIT_MESH':
    
                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.
    
                    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.
    
                        layout.label(text="Distance")
    
                        box = layout.box()
                        row = box.row()
    
                        row = box.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]")
    
    
                        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.
    
                        layout.label(text="Distance")
    
                        box = layout.box()
                        row = box.row()
    
                        row = box.row()
    
                        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.
    
                        layout.label(text="Distance")
    
                        box = layout.box()
                        row = box.row()
    
                        row = box.row()
    
                        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.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 len(polys_selected) > 0:
    
                                if sce.measure_panel_area1 >= 0:
    
                                    box = layout.box()
                                    row = box.row()
    
                                        text=str(len(polys_selected)),
    
    
                                    row = box.row()
                                    row.label(text="Area")
    
                                    row = box.row()
                                    row.label(text="Normal")
                                    row = box.row()
                                    row.prop(sce, "measure_panel_normal1")
    
    
                                row.label(text="Selection not supported",
    
                    if drawTansformButtons:
                        row = layout.row()
                        row.prop(sce,
                            "measure_panel_transform",
                            expand=True)
    
            elif mode == 'OBJECT':
    
                # We are working in object mode.
    
                mesh_objects = [o for o in context.selected_objects
    
                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",
    
                            text="Surface 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))
    
    #                                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.
    
                    layout.label(text="Distance")
    
                    box = layout.box()
                    row = box.row()
    
                    row = box.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="")
    
    
                    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",
    
                        text="Surface 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 = 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 = 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",
    
                        text="Volume")
    
                    if sce.measure_panel_calc_volume:
    
                        # Display volume of the objects.
    
                        if sce.measure_panel_volume1 >= -2:
    
                            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')
    
                            else:  # -2
                                row = box.row()
    
                                row.label(text="Mesh has n-gons (faces with " \
                                    "more than 4 edges)!",
    
                                    icon='INFO')
    
                        if sce.measure_panel_volume2 >= -2:
    
                            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')
    
                            else:  # -2
                                row = box.row()
    
                                row.label(text="Mesh has n-gons (faces with " \
                                    "more than 4 edges)!",
    
                                    icon='INFO')
    
                    # One object selected.
                    # We measure the distance from the object to the 3D cursor.
    
                    layout.label(text="Distance")
    
                    box = layout.box()
                    row = box.row()
    
                    row = box.row()
    
                    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",
    
                        text="Surface 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 = 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",
    
                        text="Volume")
    
                    if sce.measure_panel_calc_volume:
    
                        # Display volume of the objects.
    
                        if sce.measure_panel_volume1 >= -2:
    
                            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')
    
                            else:  # -2
                                row = box.row()
    
                                row.label(text="Mesh has n-gons (faces with " \
                                    "more than 4 edges)!",
    
                                    icon='INFO')
    
    
                elif not context.selected_objects:
                    # Nothing selected.
                    # We measure the distance from the origin to the 3D cursor.
    
                    layout.label(text="Distance")
    
                    box = layout.box()
                    row = box.row()
    
                    row = box.row()
    
                    row.label(text="", icon='CURSOR')
                    row.label(text="", icon='ARROW_LEFTRIGHT')
                    row.label(text="Origin [0,0,0]")
    
    
                    layout.prop(sce, "measure_panel_draw")
    
    
                    row.label(text="Selection not supported",
    
                        icon='INFO')
    
                if drawTansformButtons:
                    row = layout.row()
                    row.prop(sce,
    
                        "measure_panel_transform",
                        expand=True)
    
        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"),
    
            ("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')
    
        # Define property for the draw setting.
        bpy.types.Scene.measure_panel_draw = bpy.props.BoolProperty(
    
            name="Draw distance",
    
            description="Draw distances in 3D View",
    
            default=1)
    
        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)
    
    
        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