Skip to content
Snippets Groups Projects
measureit_main.py 82.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    
    # ----------------------------------------------------------
    # File: measureit_main.py
    # Main panel for different Measureit general actions
    # Author: Antonio Vazquez (antonioya)
    #
    # ----------------------------------------------------------
    # noinspection PyUnresolvedReferences
    import bpy
    
    from bmesh import from_edit_mesh
    
    # noinspection PyUnresolvedReferences
    
    from bpy.types import PropertyGroup, Panel, Object, Operator, SpaceView3D
    
    Antonioya's avatar
    Antonioya committed
    from bpy.props import IntProperty, CollectionProperty, FloatVectorProperty, BoolProperty, StringProperty, \
                          FloatProperty, EnumProperty
    
    from bpy.app.handlers import persistent
    # noinspection PyUnresolvedReferences
    
    from .measureit_geometry import *
    from .measureit_render import *
    
    
    
    # ------------------------------------------------------
    # Handler to detect new Blend load
    #
    # ------------------------------------------------------
    # noinspection PyUnusedLocal
    @persistent
    def load_handler(dummy):
    
        MEASUREIT_OT_RunHintDisplay.handle_remove(None, bpy.context)
    
    
    
    # ------------------------------------------------------
    # Handler to detect save Blend
    # Clear not used measured
    #
    # ------------------------------------------------------
    # noinspection PyUnusedLocal
    @persistent
    def save_handler(dummy):
        # noinspection PyBroadException
        try:
            print("MeasureIt: Cleaning data")
            objlist = bpy.context.scene.objects
            for myobj in objlist:
                if 'MeasureGenerator' in myobj:
                    mp = myobj.MeasureGenerator[0]
                    x = 0
                    for ms in mp.measureit_segments:
                        ms.name = "segment_" + str(x)
                        x += 1
                        if ms.glfree is True:
                            idx = mp.measureit_segments.find(ms.name)
                            if idx > -1:
                                print("MeasureIt: Removed segment not used")
                                mp.measureit_segments.remove(idx)
    
                    # reset size
                    mp.measureit_num = len(mp.measureit_segments)
        except:
            pass
    
    
    bpy.app.handlers.load_post.append(load_handler)
    bpy.app.handlers.save_pre.append(save_handler)
    
    
    # ------------------------------------------------------------------
    # Define property group class for measureit faces index
    # ------------------------------------------------------------------
    
    class MeasureitIndex(PropertyGroup):
    
        glidx: IntProperty(name="index", description="vertex index")
    
    
    # Register
    bpy.utils.register_class(MeasureitIndex)
    
    
    # ------------------------------------------------------------------
    # Define property group class for measureit faces
    # ------------------------------------------------------------------
    
    class MeasureitFaces(PropertyGroup):
    
        glface: IntProperty(name="glface", description="Face number")
    
        measureit_index: CollectionProperty(type=MeasureitIndex)
    
    # Register
    bpy.utils.register_class(MeasureitFaces)
    
    
    # ------------------------------------------------------------------
    # Define property group class for measureit data
    # ------------------------------------------------------------------
    
    class MeasureitProperties(PropertyGroup):
    
        gltype: IntProperty(name="gltype",
                           description="Measure type (1-Segment, 2-Label, etc..)", default=1)
        glpointa: IntProperty(name="glpointa",
                             description="Hidden property for opengl")
        glpointb: IntProperty(name="glpointb",
                             description="Hidden property for opengl")
        glpointc: IntProperty(name="glpointc",
                             description="Hidden property for opengl")
        glcolor: FloatVectorProperty(name="glcolor",
    
    Antonioya's avatar
    Antonioya committed
                                      description="Color for the measure",
                                      default=(0.173, 0.545, 1.0, 1.0),
                                      min=0.1,
                                      max=1,
                                      subtype='COLOR',
                                      size=4)
    
        glview: BoolProperty(name="glview",
    
    Antonioya's avatar
    Antonioya committed
                              description="Measure visible/hide",
                              default=True)
    
        glspace: FloatProperty(name='glspace', min=-100, max=100, default=0.1,
    
    Antonioya's avatar
    Antonioya committed
                                precision=3,
                                description='Distance to display measure')
    
        glwidth: IntProperty(name='glwidth', min=1, max=10, default=1,
    
    Antonioya's avatar
    Antonioya committed
                              description='line width')
    
        glfree: BoolProperty(name="glfree",
    
    Antonioya's avatar
    Antonioya committed
                              description="This measure is free and can be deleted",
                              default=False)
    
        gltxt: StringProperty(name="gltxt", maxlen=256,
    
    Antonioya's avatar
    Antonioya committed
                               description="Short description (use | for line break)")
    
        gladvance: BoolProperty(name="gladvance",
    
    Antonioya's avatar
    Antonioya committed
                                 description="Advanced options as line width or position",
                                 default=False)
    
        gldefault: BoolProperty(name="gldefault",
    
    Antonioya's avatar
    Antonioya committed
                                 description="Display measure in position calculated by default",
                                 default=True)
    
        glnormalx: FloatProperty(name="glnormalx",
    
    Antonioya's avatar
    Antonioya committed
                                  description="Change orientation in X axis",
                                  default=1, min=-1, max=1, precision=2)
    
        glnormaly: FloatProperty(name="glnormaly",
    
    Antonioya's avatar
    Antonioya committed
                                  description="Change orientation in Y axis",
                                  default=0, min=-1, max=1, precision=2)
    
        glnormalz: FloatProperty(name="glnormalz",
    
    Antonioya's avatar
    Antonioya committed
                                  description="Change orientation in Z axis",
                                  default=0, min=-1, max=1, precision=2)
    
        glfont_size: IntProperty(name="Text Size",
    
    Antonioya's avatar
    Antonioya committed
                                  description="Text size",
                                  default=14, min=6, max=150)
    
        glfont_align: EnumProperty(items=(('L', "Left Align", ""),
    
                                           ('C', "Center Align", ""),
                                           ('R', "Right Align", "")),
                                    name="Align Font",
                                    description="Set Font Alignment")
    
        glfont_rotat: IntProperty(name='Rotate', min=0, max=360, default=0,
    
                                    description="Text rotation in degrees")
    
        gllink: StringProperty(name="gllink",
    
    Antonioya's avatar
    Antonioya committed
                                description="linked object for linked measures")
    
        glocwarning: BoolProperty(name="glocwarning",
    
    Antonioya's avatar
    Antonioya committed
                                   description="Display a warning if some axis is not used in distance",
                                   default=True)
    
        glocx: BoolProperty(name="glocx",
    
    Antonioya's avatar
    Antonioya committed
                             description="Include changes in X axis for calculating the distance",
                             default=True)
    
        glocy: BoolProperty(name="glocy",
    
    Antonioya's avatar
    Antonioya committed
                             description="Include changes in Y axis for calculating the distance",
                             default=True)
    
        glocz: BoolProperty(name="glocz",
    
    Antonioya's avatar
    Antonioya committed
                             description="Include changes in Z axis for calculating the distance",
                             default=True)
    
        glfontx: IntProperty(name="glfontx",
    
    Antonioya's avatar
    Antonioya committed
                              description="Change font position in X axis",
                              default=0, min=-3000, max=3000)
    
        glfonty: IntProperty(name="glfonty",
    
    Antonioya's avatar
    Antonioya committed
                              description="Change font position in Y axis",
                              default=0, min=-3000, max=3000)
    
        gldist: BoolProperty(name="gldist",
    
    Antonioya's avatar
    Antonioya committed
                              description="Display distance for this measure",
                              default=True)
    
        glnames: BoolProperty(name="glnames",
    
    Antonioya's avatar
    Antonioya committed
                               description="Display text for this measure",
                               default=True)
    
        gltot: EnumProperty(items=(('99', "-", "Select a group for sum"),
    
    Antonioya's avatar
    Antonioya committed
                                    ('0', "A", ""),
                                    ('1', "B", ""),
                                    ('2', "C", ""),
                                    ('3', "D", ""),
                                    ('4', "E", ""),
                                    ('5', "F", ""),
                                    ('6', "G", ""),
                                    ('7', "H", ""),
                                    ('8', "I", ""),
                                    ('9', "J", ""),
                                    ('10', "K", ""),
                                    ('11', "L", ""),
                                    ('12', "M", ""),
                                    ('13', "N", ""),
                                    ('14', "O", ""),
                                    ('15', "P", ""),
                                    ('16', "Q", ""),
                                    ('17', "R", ""),
                                    ('18', "S", ""),
                                    ('19', "T", ""),
                                    ('20', "U", ""),
                                    ('21', "V", ""),
                                    ('22', "W", ""),
                                    ('23', "X", ""),
                                    ('24', "Y", ""),
                                    ('25', "Z", "")),
                             name="Sum in Group",
                             description="Add segment length in selected group")
    
        glorto: EnumProperty(items=(('99', "None", ""),
    
    Antonioya's avatar
    Antonioya committed
                                     ('0', "A", "Point A must use selected point B location"),
                                     ('1', "B", "Point B must use selected point A location")),
                              name="Orthogonal",
                              description="Display point selected as orthogonal (select axis to copy)")
    
        glorto_x: BoolProperty(name="ox",
    
    Antonioya's avatar
    Antonioya committed
                                description="Copy X location",
                                default=False)
    
        glorto_y: BoolProperty(name="oy",
    
    Antonioya's avatar
    Antonioya committed
                                description="Copy Y location",
                                default=False)
    
        glorto_z: BoolProperty(name="oz",
    
    Antonioya's avatar
    Antonioya committed
                                description="Copy Z location",
                                default=False)
    
        glarrow_a: EnumProperty(items=(('99', "--", "No arrow"),
    
    Antonioya's avatar
    Antonioya committed
                                        ('1', "Line", "The point of the arrow are lines"),
                                        ('2', "Triangle", "The point of the arrow is triangle"),
                                        ('3', "TShape", "The point of the arrow is a T")),
                                 name="A end",
                                 description="Add arrows to point A")
    
        glarrow_b: EnumProperty(items=(('99', "--", "No arrow"),
    
    Antonioya's avatar
    Antonioya committed
                                        ('1', "Line", "The point of the arrow are lines"),
                                        ('2', "Triangle", "The point of the arrow is triangle"),
                                        ('3', "TShape", "The point of the arrow is a T")),
                                 name="B end",
                                 description="Add arrows to point B")
    
        glarrow_s: IntProperty(name="Size",
    
    Antonioya's avatar
    Antonioya committed
                                description="Arrow size",
                                default=15, min=6, max=500)
    
        glarc_full: BoolProperty(name="arcfull",
    
    Brecht Van Lommel's avatar
    Brecht Van Lommel committed
                                  description="Create full circumference",
    
    Antonioya's avatar
    Antonioya committed
                                  default=False)
    
        glarc_extrad: BoolProperty(name="arcextrad",
    
                                    description="Adapt radio length to arc line",
    
    Antonioya's avatar
    Antonioya committed
                                    default=True)
    
        glarc_rad: BoolProperty(name="arc rad",
    
    Antonioya's avatar
    Antonioya committed
                                 description="Show arc radius",
                                 default=True)
    
        glarc_len: BoolProperty(name="arc len",
    
    Antonioya's avatar
    Antonioya committed
                                 description="Show arc length",
                                 default=True)
    
        glarc_ang: BoolProperty(name="arc ang",
    
    Antonioya's avatar
    Antonioya committed
                                 description="Show arc angle",
                                 default=True)
    
        glarc_a: EnumProperty(items=(('99', "--", "No arrow"),
    
    Antonioya's avatar
    Antonioya committed
                                      ('1', "Line", "The point of the arrow are lines"),
                                      ('2', "Triangle", "The point of the arrow is triangle"),
                                      ('3', "TShape", "The point of the arrow is a T")),
                               name="Ar end",
                               description="Add arrows to point A")
    
        glarc_b: EnumProperty(items=(('99', "--", "No arrow"),
    
    Antonioya's avatar
    Antonioya committed
                                      ('1', "Line", "The point of the arrow are lines"),
                                      ('2', "Triangle", "The point of the arrow is triangle"),
                                      ('3', "TShape", "The point of the arrow is a T")),
                               name="Br end",
                               description="Add arrows to point B")
    
        glarc_s: IntProperty(name="Size",
    
    Antonioya's avatar
    Antonioya committed
                              description="Arrow size",
                              default=15, min=6, max=500)
    
        glarc_txradio: StringProperty(name="txradio",
    
    Antonioya's avatar
    Antonioya committed
                                       description="Text for radius", default="r=")
    
        glarc_txlen: StringProperty(name="txlen",
    
    Antonioya's avatar
    Antonioya committed
                                     description="Text for length", default="L=")
    
        glarc_txang: StringProperty(name="txang",
    
    Antonioya's avatar
    Antonioya committed
                                     description="Text for angle", default="A=")
    
        glcolorarea: FloatVectorProperty(name="glcolorarea",
    
    Antonioya's avatar
    Antonioya committed
                                          description="Color for the measure of area",
                                          default=(0.1, 0.1, 0.1, 1.0),
                                          min=0.1,
                                          max=1,
                                          subtype='COLOR',
                                          size=4)
    
        measureit_faces: CollectionProperty(type=MeasureitFaces)
    
    # Register
    bpy.utils.register_class(MeasureitProperties)
    
    
    # ------------------------------------------------------------------
    # Define object class (container of segments)
    # Measureit
    # ------------------------------------------------------------------
    
    class MeasureContainer(PropertyGroup):
    
        measureit_num: IntProperty(name='Number of measures', min=0, max=1000, default=0,
    
    Antonioya's avatar
    Antonioya committed
                                    description='Number total of measureit elements')
    
        measureit_segments: CollectionProperty(type=MeasureitProperties)
    
    
    
    bpy.utils.register_class(MeasureContainer)
    
    Object.MeasureGenerator = CollectionProperty(type=MeasureContainer)
    
    
    
    # ------------------------------------------------------------------
    # Define UI class
    # Measureit
    # ------------------------------------------------------------------
    
    class MEASUREIT_PT_Edit(Panel):
        bl_idname = "MEASUREIT_PT_Edit"
        bl_label = "Items"
    
        bl_space_type = 'VIEW_3D'
        bl_region_type = 'UI'
    
    meta-androcto's avatar
    meta-androcto committed
        bl_category= 'View'
    
        bl_parent_id = 'MEASUREIT_PT_Main'
    
    
        # -----------------------------------------------------
        # Verify if visible
        # -----------------------------------------------------
        @classmethod
        def poll(cls, context):
            o = context.object
            if o is None:
                return False
            if 'MeasureGenerator' not in o:
                return False
            else:
                mp = context.object.MeasureGenerator[0]
                if mp.measureit_num > 0:
                    return True
                else:
                    return False
    
        # -----------------------------------------------------
        # Draw (create UI interface)
        # -----------------------------------------------------
        # noinspection PyUnusedLocal
        def draw(self, context):
            layout = self.layout
            scene = context.scene
            if context.object is not None:
                if 'MeasureGenerator' in context.object:
                    box = layout.box()
                    row = box.row()
    
                    row.label(text=context.object.name)
    
                    row = box.row()
                    row.prop(scene, 'measureit_gl_precision', text="Precision")
                    row.prop(scene, 'measureit_units')
                    row = box.row()
    
                    row.prop(scene, 'measureit_gl_show_d', text="Distances", toggle=True, icon="ALIGN_CENTER")
    
                    row.prop(scene, 'measureit_gl_show_n', text="Texts", toggle=True, icon="FONT_DATA")
    
                    row = box.row()
                    row.prop(scene, 'measureit_hide_units', text="Hide measurement unit")
    
                    # Scale factor
                    row = box.row()
                    row.prop(scene, 'measureit_scale', text="Scale")
                    if scene.measureit_scale is True:
    
                        split = row.split(factor=0.25, align=False)
    
                        split.prop(scene, 'measureit_scale_color', text="")
                        split.prop(scene, 'measureit_scale_factor', text="1")
    
                        row.separator()
                        row.prop(scene, 'measureit_gl_scaletxt', text="")
    
                        row.prop(scene, 'measureit_scale_font')
    
                        row.prop(scene, 'measureit_scale_precision', text="")
    
                        row.prop(scene, 'measureit_scale_pos_x')
                        row.prop(scene, 'measureit_scale_pos_y')
    
                    # Override
                    row = box.row()
                    row.prop(scene, 'measureit_ovr', text="Override")
                    if scene.measureit_ovr is True:
    
                        split = row.split(factor=0.25, align=False)
    
                        split.prop(scene, 'measureit_ovr_color', text="")
                        split.prop(scene, 'measureit_ovr_width', text="Width")
                        row = box.row()
                        row.separator()
    
                        row.prop(scene, 'measureit_ovr_font', text="Font")
    
                        row.prop(scene, 'measureit_ovr_font_align', text="")
                        if scene.measureit_ovr_font_align == 'L':
                            row.prop(scene, 'measureit_ovr_font_rotation', text="Rotate")
    
    
                    mp = context.object.MeasureGenerator[0]
                    # -----------------
                    # loop
                    # -----------------
                    if mp.measureit_num > 0:
                        box = layout.box()
    
                        row = box.row(align=True)
                        row.operator("measureit.expandallsegment", text="Expand all", icon="ZOOM_IN")
                        row.operator("measureit.collapseallsegment", text="Collapse all", icon="ZOOM_OUT")
    
    NBurn's avatar
    NBurn committed
                        for idx in range(mp.measureit_num):
    
                            if mp.measureit_segments[idx].glfree is False:
                                add_item(box, idx, mp.measureit_segments[idx])
    
                    row = box.row()
    
                    row.operator("measureit.deleteallsegment", text="Delete all", icon="X")
    
                    # -----------------
                    # Sum loop segments
                    # -----------------
                    if mp.measureit_num > 0:
                        scale = bpy.context.scene.unit_settings.scale_length
                        tx = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
                              "T", "U", "V", "W", "X", "Y", "Z"]
                        tot = [0.0] * len(tx)
                        ac = [False] * len(tx)
                        myobj = context.object
                        obverts = get_mesh_vertices(myobj)
                        viewtot = False
    
    NBurn's avatar
    NBurn committed
                        for idx in range(mp.measureit_num):
    
                            ms = mp.measureit_segments[idx]
                            if (ms.gltype == 1 or ms.gltype == 12
                                or ms.gltype == 13 or ms.gltype == 14) and ms.gltot != '99' \
                                    and ms.glfree is False:  # only segments
    
                                if bpy.context.mode == "EDIT_MESH":
                                    bm = bmesh.from_edit_mesh(bpy.context.edit_object.data)
                                    if hasattr(bm.verts, "ensure_lookup_table"):
                                        bm.verts.ensure_lookup_table()
    
                                if ms.glpointa <= len(obverts) and ms.glpointb <= len(obverts):
                                    p1 = get_point(obverts[ms.glpointa].co, myobj)
                                    if ms.gltype == 1:
                                        p2 = get_point(obverts[ms.glpointb].co, myobj)
                                    elif ms.gltype == 12:
                                        p2 = get_point((0.0,
                                                        obverts[ms.glpointa].co[1],
                                                        obverts[ms.glpointa].co[2]), myobj)
                                    elif ms.gltype == 13:
                                        p2 = get_point((obverts[ms.glpointa].co[0],
                                                        0.0,
                                                        obverts[ms.glpointa].co[2]), myobj)
                                    else:
                                        p2 = get_point((obverts[ms.glpointa].co[0],
                                                        obverts[ms.glpointa].co[1],
                                                        0.0), myobj)
    
                                    dist, distloc = distance(p1, p2, ms.glocx, ms.glocy, ms.glocz)
                                    if dist == distloc:
                                        usedist = dist
                                    else:
                                        usedist = distloc
                                    usedist *= scale
                                    tot[int(ms.gltot)] += usedist
                                    ac[int(ms.gltot)] = True
                                    viewtot = True
                        # -----------------
                        # Print values
                        # -----------------
                        if viewtot is True:
                            pr = scene.measureit_gl_precision
                            fmt = "%1." + str(pr) + "f"
                            units = scene.measureit_units
    
                            box = layout.box()
    
                            box.label(text="Totals", icon='SOLO_ON')
    
    NBurn's avatar
    NBurn committed
                            for idx in range(len(tot)):
    
                                if ac[idx] is True:
                                    final += tot[idx]
                                    tx_dist = format_distance(fmt, units, tot[idx])
    
                                    row = box.row(align=True)
                                    row.label(text="Group " + tx[idx] + ":")
                                    row.label(text=" ")
                                    row.label(text=tx_dist)
    
                            row = box.row(align=True)
                            row.label(text="")
                            row.label(text=" ")
                            row.label(text="-" * 20)
    
                            tx_dist = format_distance(fmt, units, final)
    
    
                            row = box.row(align=True)
                            row.label(text="")
                            row.label(text=" ")
                            row.label(text=tx_dist)
    
                            row.operator("measureit.deleteallsum", text="Delete all", icon="X")
    
    
    
    # -----------------------------------------------------
    
    # Add segment options to the panel.
    
    # -----------------------------------------------------
    def add_item(box, idx, segment):
    
        scene = bpy.context.scene
    
        row = box.row(align=True)
    
    
        row.prop(segment, 'glview', text="", toggle=True, icon=icon)
    
        row.prop(segment, 'gladvance', text="", toggle=True, icon="PREFERENCES")
    
        if segment.gltype == 20:  # Area special
    
            split = row.split(factor=0.15, align=True)
    
            split.prop(segment, 'glcolorarea', text="")
    
            split = split.split(factor=0.20, align=True)
    
            split.prop(segment, 'glcolor', text="")
        else:
    
            split = row.split(factor=0.25, align=True)
    
            split.prop(segment, 'glcolor', text="")
        split.prop(segment, 'gltxt', text="")
    
        op = row.operator("measureit.deletesegment", text="", icon="X")
    
        op.tag = idx  # saves internal data
        if segment.gladvance is True:
    
            row = box.row(align=True)
    
            row.prop(segment, 'glfont_size', text="Font")
    
            row.prop(segment, 'glfont_align', text="")
            if segment.glfont_align == 'L':
                row.prop(segment, 'glfont_rotat', text="Rotate")
    
            row = box.row(align=True)
    
            if segment.gltype != 9 and segment.gltype != 10 and segment.gltype != 20:
                row.prop(segment, 'glspace', text="Distance")
    
            row.prop(segment, 'glfontx', text="X")
            row.prop(segment, 'glfonty', text="Y")
    
            # Arrows
            if segment.gltype != 9 and segment.gltype != 10 and segment.gltype != 20:
    
                row = box.row(align=True)
    
                row.prop(segment, 'glarrow_a', text="")
                row.prop(segment, 'glarrow_b', text="")
    
                if segment.glarrow_a != '99' or segment.glarrow_b != '99':
    
                    row.prop(segment, 'glarrow_s', text="Size")
    
    
            if segment.gltype != 2 and segment.gltype != 10:
    
                row = box.row(align=True)
    
                if scene.measureit_gl_show_d is True and segment.gltype != 9:
    
                    row.prop(segment, 'gldist', text="Distance", toggle=True, icon="ALIGN_CENTER")
    
                if scene.measureit_gl_show_n is True:
                    row.prop(segment, 'glnames', text="Text", toggle=True, icon="FONT_DATA")
    
                # sum distances
                if segment.gltype == 1 or segment.gltype == 12 or segment.gltype == 13 or segment.gltype == 14:
                    row.prop(segment, 'gltot', text="Sum")
    
    
            if segment.gltype != 9 and segment.gltype != 10 and segment.gltype != 20:
    
                row = box.row(align=True)
    
                row.prop(segment, 'glwidth', text="Line")
                row.prop(segment, 'gldefault', text="Automatic position")
                if segment.gldefault is False:
    
                    row = box.row(align=True)
    
                    row.prop(segment, 'glnormalx', text="X")
                    row.prop(segment, 'glnormaly', text="Y")
                    row.prop(segment, 'glnormalz', text="Z")
    
            # Loc axis
    
            if segment.gltype != 2 and segment.gltype != 9 and segment.gltype != 10 \
                    and segment.gltype != 11 and segment.gltype != 12 and segment.gltype != 13 \
                    and segment.gltype != 14 and segment.gltype != 20:
    
                row = box.row(align=True)
    
                row.prop(segment, 'glocx', text="X", toggle=True)
                row.prop(segment, 'glocy', text="Y", toggle=True)
                row.prop(segment, 'glocz', text="Z", toggle=True)
                if segment.glocx is False or segment.glocy is False or segment.glocz is False:
                    row = box.row()
                    if segment.gltype == 1:
                        row.prop(segment, 'glorto', text="Orthogonal")
                    row.prop(segment, 'glocwarning', text="Warning")
    
    Brecht Van Lommel's avatar
    Brecht Van Lommel committed
                    # orthogonal (only segments)
    
                    if segment.gltype == 1:
                        if segment.glorto != "99":
    
                            row = box.row(align=True)
    
                            row.prop(segment, 'glorto_x', text="X", toggle=True)
                            row.prop(segment, 'glorto_y', text="Y", toggle=True)
                            row.prop(segment, 'glorto_z', text="Z", toggle=True)
    
            # Arc special
            if segment.gltype == 11:
    
                row = box.row(align=True)
    
                row.prop(segment, 'glarc_rad', text="Radius")
                row.prop(segment, 'glarc_len', text="Length")
                row.prop(segment, 'glarc_ang', text="Angle")
    
    
                row = box.row(align=True)
    
                row.prop(segment, 'glarc_txradio', text="")
                row.prop(segment, 'glarc_txlen', text="")
                row.prop(segment, 'glarc_txang', text="")
    
                row = box.row(align=True)
    
                row.prop(segment, 'glarc_full', text="Full Circle")
                if segment.glarc_rad is True:
                    row.prop(segment, 'glarc_extrad', text="Adapt radio")
    
    
                row = box.row(align=True)
    
                row.prop(segment, 'glarc_a', text="")
                row.prop(segment, 'glarc_b', text="")
    
                if segment.glarc_a != '99' or segment.glarc_b != '99':
                    row.prop(segment, 'glarc_s', text="Size")
    
    
    
    # ------------------------------------------------------------------
    # Define panel class for main functions.
    # ------------------------------------------------------------------
    
    class MEASUREIT_PT_Main(Panel):
    
        bl_idname = "MEASUREIT_PT_Main"
    
        bl_label = "MeasureIt Tools"
    
        bl_region_type = 'UI'
    
    meta-androcto's avatar
    meta-androcto committed
        bl_category= 'View'
    
        bl_options = {'DEFAULT_CLOSED'}
    
    
        # ------------------------------
        # Draw UI
        # ------------------------------
        def draw(self, context):
            layout = self.layout
            scene = context.scene
    
            # ------------------------------
            # Tool Buttons
            # ------------------------------
            box = layout.box()
            # ------------------------------
            # Display Buttons
            # ------------------------------
            row = box.row()
            if context.window_manager.measureit_run_opengl is False:
                icon = 'PLAY'
                txt = 'Show'
            else:
                icon = "PAUSE"
                txt = 'Hide'
    
    
            row.operator("measureit.runopengl", text=txt, icon=icon)
    
            row.prop(scene, "measureit_gl_ghost", text="", icon='GHOST_ENABLED')
    
            # Tools
            box = layout.box()
    
            box.label(text="Add Measures")
    
    Antonioya's avatar
    Antonioya committed
            row = box.row()
    
            row.operator("measureit.addsegment", text="Segment")
    
            row.prop(scene, "measureit_sum", text="Sum")
    
            # To origin
            row = box.row()
    
            op = row.operator("measureit.addsegmentorto", text="X")
    
            op.tag = 0  # saves internal data
    
            op = row.operator("measureit.addsegmentorto", text="Y")
    
            op.tag = 1  # saves internal data
    
            op = row.operator("measureit.addsegmentorto", text="Z")
    
            op.tag = 2  # saves internal data
    
            row = box.row()
    
            row.operator("measureit.addangle", text="Angle", icon="LINCURVE")
            row.operator("measureit.addarc", text="Arc")
    
            row.operator("measureit.addlabel", text="Label", icon="FONT_DATA")
            row.operator("measureit.addnote", text="Annotation")
    
            row.operator("measureit.addlink", text="Link")
            row.operator("measureit.addorigin", text="Origin")
    
            row.operator("measureit.addarea", text="Area", icon="MESH_GRID")
    
    
            # ------------------------------
            # Debug data
            # ------------------------------
            box = layout.box()
    
            row = box.row(align=False)
    
            if scene.measureit_debug is False:
                row.prop(scene, "measureit_debug", icon="TRIA_RIGHT",
                         text="Mesh Debug", emboss=False)
            else:
                row.prop(scene, "measureit_debug", icon="TRIA_DOWN",
                         text="Mesh Debug", emboss=False)
    
                row = box.row()
    
                split = row.split(factor=0.10, align=True)
    
                split.prop(scene, 'measureit_debug_obj_color', text="")
                split.prop(scene, "measureit_debug_objects", icon="OBJECT_DATA")
                split.prop(scene, "measureit_debug_object_loc", icon="EMPTY_DATA")
    
    
                split = row.split(factor=0.10, align=True)
    
                split.prop(scene, 'measureit_debug_vert_color', text="")
    
                split.prop(scene, "measureit_debug_vertices", icon="VERTEXSEL")
    
                split.prop(scene, "measureit_debug_vert_loc", icon="EMPTY_DATA")
                if scene.measureit_debug_vert_loc is True:
                    split.prop(scene, 'measureit_debug_vert_loc_toggle', text="")
    
    
                split = row.split(factor=0.10, align=True)
    
                split.prop(scene, 'measureit_debug_edge_color', text="")
    
                split = split.split(factor=0.5, align=True)
    
                split.prop(scene, "measureit_debug_edges", icon="EDGESEL")
    
                row = box.row()
    
                split = row.split(factor=0.10, align=True)
    
                split.prop(scene, 'measureit_debug_face_color', text="")
    
                split = split.split(factor=0.5, align=True)
    
                split.prop(scene, "measureit_debug_faces", icon="FACESEL")
    
    
                split = row.split(factor=0.10, align=True)
    
                split.prop(scene, 'measureit_debug_norm_color', text="")
                if scene.measureit_debug_normals is False:
    
                    split = split.split(factor=0.50, align=True)
                    split.prop(scene, "measureit_debug_normals", icon="OBJECT_ORIGIN")
    
                    split = split.split(factor=0.5, align=True)
                    split.prop(scene, "measureit_debug_normals", icon="OBJECT_ORIGIN")
    
                    split.prop(scene, "measureit_debug_normal_size")
                    row = box.row()
    
                    split = row.split(factor=0.10, align=True)
    
                    split.separator()
                    split.prop(scene, "measureit_debug_normal_details")
                    split.prop(scene, 'measureit_debug_width', text="Thickness")
    
                row = box.row(align=True)
                row.prop(scene, "measureit_debug_select", icon="GHOST_ENABLED")
    
                row.prop(scene, 'measureit_debug_font', text="Font")
                row.prop(scene, 'measureit_debug_precision', text="Precision")
    
    
    # ------------------------------------------------------------------
    # Define panel class for conf functions.
    # ------------------------------------------------------------------
    
    class MEASUREIT_PT_Conf(Panel):
    
        bl_idname = "MEASUREIT_PT_Conf"
    
        bl_label = "Configuration"
    
        bl_region_type = 'UI'
    
    meta-androcto's avatar
    meta-androcto committed
        bl_category= 'View'
    
        bl_parent_id = 'MEASUREIT_PT_Main'
    
        bl_options = {'DEFAULT_CLOSED'}
    
    
        # ------------------------------
        # Draw UI
        # ------------------------------
        def draw(self, context):
            layout = self.layout
            scene = context.scene
    
            # Configuration data
            box = layout.box()
            row = box.row()
    
            split = row.split(factor=0.2, align=True)
            split.label(text="Text")
            split = split.split(factor=0.2, align=True)
    
            split.prop(scene, "measureit_default_color", text="")
            split.prop(scene, "measureit_gl_txt", text="")
    
            row = box.row(align=True)
    
            row.prop(scene, "measureit_hint_space")
    
            row.prop(scene, "measureit_font_align", text="")
    
            row = box.row(align=True)
    
            row.prop(scene, "measureit_glarrow_a", text="")
            row.prop(scene, "measureit_glarrow_b", text="")
    
            if scene.measureit_glarrow_a != '99' or scene.measureit_glarrow_b != '99':
                row.prop(scene, "measureit_glarrow_s", text="Size")
    
            row = box.row(align=True)
    
            row.prop(scene, "measureit_font_size")
    
            if scene.measureit_font_align == 'L':
                row.prop(scene, "measureit_font_rotation", text="Rotate")
    
    
    
    # ------------------------------------------------------------------
    # Define panel class for render functions.
    # ------------------------------------------------------------------
    
    class MEASUREIT_PT_Render(Panel):
    
        bl_idname = "MEASUREIT_PT_Render"
    
        bl_label = "Render"
    
        bl_region_type = 'UI'
    
        bl_category= 'Display'
        bl_parent_id = 'MEASUREIT_PT_Main'
    
        bl_options = {'DEFAULT_CLOSED'}
    
    
        # ------------------------------
        # Draw UI
        # ------------------------------
        def draw(self, context):
            layout = self.layout
            scene = context.scene
    
            # Render settings
            box = layout.box()
            row = box.row()
            row.prop(scene, "measureit_render_type")
            row = box.row()
    
            row.operator("measureit.rendersegment", icon='SCRIPT')
    
            row = box.row()
            row.prop(scene, "measureit_render", text="Save render image")
            row = box.row()
            row.prop(scene, "measureit_rf", text="Frame")
            if scene.measureit_rf is True:
                row.prop(scene, "measureit_rf_color", text="Color")
                row = box.row()
                row.prop(scene, "measureit_rf_border", text="Space")
                row.prop(scene, "measureit_rf_line", text="Width")
    
    
    # -------------------------------------------------------------
    
    # Defines button that adds a measure segment
    
    #
    # -------------------------------------------------------------
    
    class MEASUREIT_OT_AddSegment(Operator):
        bl_idname = "measureit.addsegment"
    
        bl_label = "Add"
        bl_description = "(EDITMODE only) Add a new measure segment between 2 vertices (select 2 vertices or more)"
    
        # ------------------------------
        # Poll
        # ------------------------------
        @classmethod
        def poll(cls, context):
            o = context.object
            if o is None:
                return False
            else:
                if o.type == "MESH":
                    if bpy.context.mode == 'EDIT_MESH':
                        return True
                    else:
                        return False
                else:
                    return False
    
        # ------------------------------
        # Execute button action
        # ------------------------------
        def execute(self, context):
            if context.area.type == 'VIEW_3D':
                # Add properties
                scene = context.scene
                mainobject = context.object
                mylist = get_smart_selected(mainobject)
                if len(mylist) < 2:  # if not selected linked vertex
                    mylist = get_selected_vertex(mainobject)
    
                if len(mylist) >= 2:
                    if 'MeasureGenerator' not in mainobject:
                        mainobject.MeasureGenerator.add()
    
                    mp = mainobject.MeasureGenerator[0]
                    for x in range(0, len(mylist) - 1, 2):
                        # -----------------------
                        # Only if not exist
                        # -----------------------
                        if exist_segment(mp, mylist[x], mylist[x + 1]) is False:
                            # Create all array elements
                            for cont in range(len(mp.measureit_segments) - 1, mp.measureit_num):
                                mp.measureit_segments.add()
    
                            # Set values
                            ms = mp.measureit_segments[mp.measureit_num]
                            ms.gltype = 1
                            ms.glpointa = mylist[x]
                            ms.glpointb = mylist[x + 1]
                            ms.glarrow_a = scene.measureit_glarrow_a
                            ms.glarrow_b = scene.measureit_glarrow_b
                            ms.glarrow_s = scene.measureit_glarrow_s
                            # color
                            ms.glcolor = scene.measureit_default_color
                            # dist
                            ms.glspace = scene.measureit_hint_space
                            # text
                            ms.gltxt = scene.measureit_gl_txt
                            ms.glfont_size = scene.measureit_font_size
    
                            ms.glfont_align = scene.measureit_font_align
                            ms.glfont_rotat = scene.measureit_font_rotation
    
                            # Sum group
                            ms.gltot = scene.measureit_sum
                            # Add index
                            mp.measureit_num += 1
    
                    # redraw
                    context.area.tag_redraw()
                    return {'FINISHED'}
                else:
                    self.report({'ERROR'},
                                "MeasureIt: Select at least two vertices for creating measure segment.")
                    return {'FINISHED'}
            else:
                self.report({'WARNING'},
                            "View3D not found, cannot run operator")
    
            return {'CANCELLED'}
    
    
    # -------------------------------------------------------------
    
    # Defines button that adds an area measure
    
    #
    # -------------------------------------------------------------
    
    class MEASUREIT_OT_AddArea(Operator):
        bl_idname = "measureit.addarea"
    
        bl_label = "Area"
        bl_description = "(EDITMODE only) Add a new measure for area (select 1 o more faces)"
    
        # ------------------------------
        # Poll
        # ------------------------------
        @classmethod
        def poll(cls, context):
            o = context.object
            if o is None:
                return False
            else:
                if o.type == "MESH":
                    if bpy.context.mode == 'EDIT_MESH':
                        return True
                    else:
                        return False
                else:
                    return False
    
        # ------------------------------
        # Execute button action
        # ------------------------------
        def execute(self, context):
            if context.area.type == 'VIEW_3D':
                # Add properties
                scene = context.scene
                mainobject = context.object
                mylist = get_selected_faces(mainobject)
                if len(mylist) >= 1:
                    if 'MeasureGenerator' not in mainobject:
                        mainobject.MeasureGenerator.add()
    
                    mp = mainobject.MeasureGenerator[0]
                    mp.measureit_segments.add()
                    ms = mp.measureit_segments[mp.measureit_num]
                    ms.gltype = 20
    
                    f = -1
                    for face in mylist:
                        # Create array elements
                        ms.measureit_faces.add()
                        f += 1
                        # Set values
                        mf = ms.measureit_faces[f]
                        mf.glface = f
                        i = 0
                        for v in face:
                            mf.measureit_index.add()
                            mi = mf.measureit_index[i]
                            mi.glidx = v
                            i += 1
    
                    # color
                    rgb = scene.measureit_default_color
                    ms.glcolor = (rgb[0], rgb[1], rgb[2], 0.4)
                    # dist
                    ms.glspace = scene.measureit_hint_space
                    # text
                    ms.gltxt = scene.measureit_gl_txt
                    ms.glfont_size = scene.measureit_font_size
    
                    ms.glfont_align = scene.measureit_font_align
                    ms.glfont_rotat = scene.measureit_font_rotation
    
                    # Sum group
                    ms.gltot = scene.measureit_sum
                    # Add index
                    mp.measureit_num += 1
                    # redraw
                    context.area.tag_redraw()
                    return {'FINISHED'}
                else:
                    self.report({'ERROR'},
                                "MeasureIt: Select at least one face for creating area measure. ")
                    return {'FINISHED'}
            else:
                self.report({'WARNING'},
                            "View3D not found, cannot run operator")
    
            return {'CANCELLED'}
    
    
    # -------------------------------------------------------------
    
    # Defines button that adds a measure segment to x/y/z origin
    
    #
    # -------------------------------------------------------------
    
    class MEASUREIT_OT_AddSegmentOrto(Operator):
        bl_idname = "measureit.addsegmentorto"
    
        bl_label = "Add"
        bl_description = "(EDITMODE only) Add a new measure segment from vertex to object origin for one " \
                         "axis (select 1 vertex)"
    
        tag: IntProperty()
    
    
        # ------------------------------
        # Poll
        # ------------------------------
        @classmethod
        def poll(cls, context):
            o = context.object
            if o is None:
                return False
            else:
                if o.type == "MESH":
                    if bpy.context.mode == 'EDIT_MESH':
                        return True
                    else:
                        return False
                else:
                    return False
    
        # ------------------------------
        # Execute button action
        # ------------------------------
        def execute(self, context):
            if context.area.type == 'VIEW_3D':