diff options
Diffstat (limited to 'measureit/measureit_main.py')
-rw-r--r-- | measureit/measureit_main.py | 2061 |
1 files changed, 2061 insertions, 0 deletions
diff --git a/measureit/measureit_main.py b/measureit/measureit_main.py new file mode 100644 index 00000000..798bb5b7 --- /dev/null +++ b/measureit/measureit_main.py @@ -0,0 +1,2061 @@ +# ##### 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 ##### + +# <pep8 compliant> + +# ---------------------------------------------------------- +# File: measureit_main.py +# Main panel for different Measureit general actions +# Author: Antonio Vazquez (antonioya) +# +# ---------------------------------------------------------- +# noinspection PyUnresolvedReferences +import bpy +# noinspection PyUnresolvedReferences +import bmesh +# noinspection PyUnresolvedReferences +import bgl +# noinspection PyUnresolvedReferences +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): + RunHintDisplayButton.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(bpy.types.PropertyGroup): + glidx = bpy.props.IntProperty(name="index", + description="vertex index") + +# Register +bpy.utils.register_class(MeasureitIndex) + + +# ------------------------------------------------------------------ +# Define property group class for measureit faces +# ------------------------------------------------------------------ +class MeasureitFaces(bpy.types.PropertyGroup): + glface = bpy.props.IntProperty(name="glface", + description="Face number") + # Array of index + measureit_index = bpy.props.CollectionProperty(type=MeasureitIndex) + +# Register +bpy.utils.register_class(MeasureitFaces) + + +# ------------------------------------------------------------------ +# Define property group class for measureit data +# ------------------------------------------------------------------ +class MeasureitProperties(bpy.types.PropertyGroup): + gltype = bpy.props.IntProperty(name="gltype", + description="Measure type (1-Segment, 2-Label, etc..)", default=1) + glpointa = bpy.props.IntProperty(name="glpointa", + description="Hidden property for opengl") + glpointb = bpy.props.IntProperty(name="glpointb", + description="Hidden property for opengl") + glpointc = bpy.props.IntProperty(name="glpointc", + description="Hidden property for opengl") + glcolor = bpy.props.FloatVectorProperty(name="glcolor", + description="Color for the measure", + default=(0.173, 0.545, 1.0, 1.0), + min=0.1, + max=1, + subtype='COLOR', + size=4) + glview = bpy.props.BoolProperty(name="glview", + description="Measure visible/hide", + default=True) + glspace = bpy.props.FloatProperty(name='glspace', min=-100, max=100, default=0.1, + precision=3, + description='Distance to display measure') + glwidth = bpy.props.IntProperty(name='glwidth', min=1, max=10, default=1, + description='line width') + glfree = bpy.props.BoolProperty(name="glfree", + description="This measure is free and can be deleted", + default=False) + gltxt = bpy.props.StringProperty(name="gltxt", maxlen=256, + description="Short description (use | for line break)") + gladvance = bpy.props.BoolProperty(name="gladvance", + description="Advanced options as line width or position", + default=False) + gldefault = bpy.props.BoolProperty(name="gldefault", + description="Display measure in position calculated by default", + default=True) + glnormalx = bpy.props.FloatProperty(name="glnormalx", + description="Change orientation in X axis", + default=1, min=-1, max=1, precision=2) + glnormaly = bpy.props.FloatProperty(name="glnormaly", + description="Change orientation in Y axis", + default=0, min=-1, max=1, precision=2) + glnormalz = bpy.props.FloatProperty(name="glnormalz", + description="Change orientation in Z axis", + default=0, min=-1, max=1, precision=2) + glfont_size = bpy.props.IntProperty(name="Text Size", + description="Text size", + default=14, min=6, max=150) + gllink = bpy.props.StringProperty(name="gllink", + description="linked object for linked measures") + glocwarning = bpy.props.BoolProperty(name="glocwarning", + description="Display a warning if some axis is not used in distance", + default=True) + glocx = bpy.props.BoolProperty(name="glocx", + description="Include changes in X axis for calculating the distance", + default=True) + glocy = bpy.props.BoolProperty(name="glocy", + description="Include changes in Y axis for calculating the distance", + default=True) + glocz = bpy.props.BoolProperty(name="glocz", + description="Include changes in Z axis for calculating the distance", + default=True) + glfontx = bpy.props.IntProperty(name="glfontx", + description="Change font position in X axis", + default=0, min=-3000, max=3000) + glfonty = bpy.props.IntProperty(name="glfonty", + description="Change font position in Y axis", + default=0, min=-3000, max=3000) + gldist = bpy.props.BoolProperty(name="gldist", + description="Display distance for this measure", + default=True) + glnames = bpy.props.BoolProperty(name="glnames", + description="Display text for this measure", + default=True) + gltot = bpy.props.EnumProperty(items=(('99', "-", "Select a group for sum"), + ('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 = bpy.props.EnumProperty(items=(('99', "None", ""), + ('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 = bpy.props.BoolProperty(name="ox", + description="Copy X location", + default=False) + glorto_y = bpy.props.BoolProperty(name="oy", + description="Copy Y location", + default=False) + glorto_z = bpy.props.BoolProperty(name="oz", + description="Copy Z location", + default=False) + glarrow_a = bpy.props.EnumProperty(items=(('99', "--", "No arrow"), + ('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 = bpy.props.EnumProperty(items=(('99', "--", "No arrow"), + ('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 = bpy.props.IntProperty(name="Size", + description="Arrow size", + default=15, min=6, max=500) + + glarc_full = bpy.props.BoolProperty(name="arcfull", + description="Create full circunference", + default=False) + glarc_extrad = bpy.props.BoolProperty(name="arcextrad", + description="Adapt radio lengh to arc line", + default=True) + glarc_rad = bpy.props.BoolProperty(name="arc rad", + description="Show arc radius", + default=True) + glarc_len = bpy.props.BoolProperty(name="arc len", + description="Show arc length", + default=True) + glarc_ang = bpy.props.BoolProperty(name="arc ang", + description="Show arc angle", + default=True) + + glarc_a = bpy.props.EnumProperty(items=(('99', "--", "No arrow"), + ('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 = bpy.props.EnumProperty(items=(('99', "--", "No arrow"), + ('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 = bpy.props.IntProperty(name="Size", + description="Arrow size", + default=15, min=6, max=500) + glarc_txradio = bpy.props.StringProperty(name="txradio", + description="Text for radius", default="r=") + glarc_txlen = bpy.props.StringProperty(name="txlen", + description="Text for length", default="L=") + glarc_txang = bpy.props.StringProperty(name="txang", + description="Text for angle", default="A=") + glcolorarea = bpy.props.FloatVectorProperty(name="glcolorarea", + 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) + + # Array of faces + measureit_faces = bpy.props.CollectionProperty(type=MeasureitFaces) + +# Register +bpy.utils.register_class(MeasureitProperties) + + +# ------------------------------------------------------------------ +# Define object class (container of segments) +# Measureit +# ------------------------------------------------------------------ +class MeasureContainer(bpy.types.PropertyGroup): + measureit_num = bpy.props.IntProperty(name='Number of measures', min=0, max=1000, default=0, + description='Number total of measureit elements') + # Array of segments + measureit_segments = bpy.props.CollectionProperty(type=MeasureitProperties) + + +bpy.utils.register_class(MeasureContainer) +bpy.types.Object.MeasureGenerator = bpy.props.CollectionProperty(type=MeasureContainer) + + +# ------------------------------------------------------------------ +# Define UI class +# Measureit +# ------------------------------------------------------------------ +class MeasureitEditPanel(bpy.types.Panel): + bl_idname = "measureit.editpanel" + bl_label = "Measureit" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = 'MesureIt' + + # ----------------------------------------------------- + # 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(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") + row.prop(scene, 'measureit_gl_show_n', text="Texts", toggle=True, icon="FONT_DATA") + + # Scale factor + row = box.row() + row.prop(scene, 'measureit_scale', text="Scale") + if scene.measureit_scale is True: + row.prop(scene, 'measureit_scale_factor', text="1") + row.prop(scene, 'measureit_scale_precision', text="") + row.prop(scene, 'measureit_gl_scaletxt', text="") + row = box.row() + row.prop(scene, 'measureit_scale_color') + row.prop(scene, 'measureit_scale_font') + row = box.row() + 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: + row.prop(scene, 'measureit_ovr_color', text="") + row.prop(scene, 'measureit_ovr_font', text="Font") + row.prop(scene, 'measureit_ovr_width', text="Width") + + mp = context.object.MeasureGenerator[0] + # ----------------- + # loop + # ----------------- + if mp.measureit_num > 0: + box = layout.box() + for idx in range(0, 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.deleteallsegmentbutton", 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 + for idx in range(0, 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 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("Totals", icon='SOLO_ON') + final = 0 + for idx in range(0, len(tot)): + if ac[idx] is True: + final += tot[idx] + tx_dist = format_distance(fmt, units, tot[idx]) + row = box.row(True) + row.label("Group " + tx[idx] + ":") + row.label(" ") + row.label(tx_dist) + + # Grand total + row = box.row(True) + row.label("") + row.label(" ") + row.label("-" * 20) + tx_dist = format_distance(fmt, units, final) + + row = box.row(True) + row.label("") + row.label(" ") + row.label(tx_dist) + # delete all + row = box.row() + row.operator("measureit.deleteallsumbutton", text="Delete all", icon="X") + + +# ----------------------------------------------------- +# Add segment to the panel. +# ----------------------------------------------------- +def add_item(box, idx, segment): + row = box.row(True) + if segment.glview is True: + icon = "VISIBLE_IPO_ON" + else: + icon = "VISIBLE_IPO_OFF" + + row.prop(segment, 'glview', text="", toggle=True, icon=icon) + row.prop(segment, 'gladvance', text="", toggle=True, icon="MANIPUL") + row.prop(segment, 'gltxt', text="") + row.prop(segment, 'glcolor', text="") + op = row.operator("measureit.deletesegmentbutton", text="", icon="X") + op.tag = idx # saves internal data + if segment.gladvance is True: + row = box.row(True) + if segment.gltype != 10 and segment.gltype != 20: + row.prop(segment, 'glspace', text="Distance") + + row.prop(segment, 'glfont_size', text="Font") + 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(True) + row.prop(segment, 'glarrow_a', text="") + row.prop(segment, 'glarrow_b', text="") + row.prop(segment, 'glarrow_s', text="Size") + + if segment.gltype != 2 and segment.gltype != 10: + row = box.row(True) + row.prop(segment, 'gldist', text="Distance", toggle=True, icon="ALIGN") + 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 != 10 and segment.gltype != 20: + row = box.row(True) + row.prop(segment, 'glwidth', text="Line") + row.prop(segment, 'gldefault', text="Automatic position") + if segment.gldefault is False: + row = box.row(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 != 10 \ + and segment.gltype != 12 and segment.gltype != 13 and segment.gltype != 14 and segment.gltype != 20: + row = box.row(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") + # ortogonal (only segments) + if segment.gltype == 1: + if segment.glorto != "99": + row = box.row(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(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(True) + row.prop(segment, 'glarc_txradio', text="") + row.prop(segment, 'glarc_txlen', text="") + row.prop(segment, 'glarc_txang', text="") + row = box.row(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(True) + row.prop(segment, 'glarc_a', text="") + row.prop(segment, 'glarc_b', text="") + row.prop(segment, 'glarc_s', text="Size") + + # Area special + if segment.gltype == 20: + row = box.row(True) + row.prop(segment, 'glcolorarea', text="") + + +# ------------------------------------------------------------------ +# Define panel class for main functions. +# ------------------------------------------------------------------ +class MeasureitMainPanel(bpy.types.Panel): + bl_idname = "measureit_main_panel" + bl_label = "Tools" + bl_space_type = 'VIEW_3D' + bl_region_type = "TOOLS" + bl_category = 'Measureit' + + # ------------------------------ + # 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.runopenglbutton", text=txt, icon=icon) + row.prop(scene, "measureit_gl_ghost", text="", icon='GHOST_ENABLED') + + # Tools + box = layout.box() + row = box.row() + row.operator("measureit.addsegmentbutton", text="Segment", icon="ALIGN") + row.prop(scene, "measureit_sum", text="Sum") + + # To origin + row = box.row() + op = row.operator("measureit.addsegmentortobutton", text="X", icon="ALIGN") + op.tag = 0 # saves internal data + op = row.operator("measureit.addsegmentortobutton", text="Y", icon="ALIGN") + op.tag = 1 # saves internal data + op = row.operator("measureit.addsegmentortobutton", text="Z", icon="ALIGN") + op.tag = 2 # saves internal data + + row = box.row() + row.operator("measureit.addanglebutton", text="Angle", icon="LINCURVE") + row.operator("measureit.addarcbutton", text="Arc", icon="MAN_ROT") + + row = box.row() + row.operator("measureit.addlabelbutton", text="Label", icon="FONT_DATA") + row.operator("measureit.addnotebutton", text="Annotation", icon="NEW") + + row = box.row() + row.operator("measureit.addlinkbutton", text="Link", icon="ROTATECENTER") + row.operator("measureit.addoriginbutton", text="Origin", icon="CURSOR") + + row = box.row() + row.operator("measureit.addareabutton", text="Area", icon="MESH_GRID") + + # ------------------------------ + # Debug data + # ------------------------------ + box = layout.box() + row = box.row(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() + row.prop(scene, "measureit_debug_vertices", icon="LOOPSEL") + row.prop(scene, "measureit_debug_location", icon="EMPTY_DATA") + row.prop(scene, "measureit_debug_faces", icon="FACESEL") + row = box.row() + row.prop(scene, "measureit_debug_select", icon="GHOST_ENABLED") + row.prop(scene, "measureit_debug_normals", icon="MAN_TRANS") + if scene.measureit_debug_normals is True: + row.prop(scene, "measureit_debug_normal_size") + row.prop(scene, "measureit_debug_normal_details") + row = box.row() + row.prop(scene, 'measureit_debug_color', text="") + row.prop(scene, 'measureit_debug_color2', text="") + row.prop(scene, 'measureit_debug_color3', text="") + row = box.row() + row.prop(scene, 'measureit_debug_font', text="Font") + row.prop(scene, 'measureit_debug_width', text="Thickness") + row.prop(scene, 'measureit_debug_precision', text="Precision") + + +# ------------------------------------------------------------------ +# Define panel class for conf functions. +# ------------------------------------------------------------------ +class MeasureitConfPanel(bpy.types.Panel): + bl_idname = "measureit_conf_panel" + bl_label = "Configuration" + bl_space_type = 'VIEW_3D' + bl_region_type = "TOOLS" + bl_category = 'Measureit' + + # ------------------------------ + # Draw UI + # ------------------------------ + def draw(self, context): + layout = self.layout + scene = context.scene + + # Configuration data + box = layout.box() + row = box.row() + row.prop(scene, "measureit_gl_txt", text="Text") + row = box.row() + row.prop(scene, "measureit_default_color", text="") + row.prop(scene, "measureit_hint_space") + # Arrow + row = box.row(True) + row.prop(scene, "measureit_glarrow_a", text="") + row.prop(scene, "measureit_glarrow_b", text="") + row.prop(scene, "measureit_glarrow_s", text="Size") + + row = box.row() + row.prop(scene, "measureit_font_size") + + +# ------------------------------------------------------------------ +# Define panel class for render functions. +# ------------------------------------------------------------------ +class MeasureitRenderPanel(bpy.types.Panel): + bl_idname = "measureit_render_panel" + bl_label = "Render" + bl_space_type = 'VIEW_3D' + bl_region_type = "TOOLS" + bl_category = 'Measureit' + + # ------------------------------ + # 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.rendersegmentbutton", 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 for add a measure segment +# +# ------------------------------------------------------------- +class AddSegmentButton(bpy.types.Operator): + bl_idname = "measureit.addsegmentbutton" + bl_label = "Add" + bl_description = "(EDITMODE only) Add a new measure segment between 2 vertices (select 2 vertices or more)" + bl_category = 'Measureit' + + # ------------------------------ + # 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 + # 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 for add area measure +# +# ------------------------------------------------------------- +class AddAreaButton(bpy.types.Operator): + bl_idname = "measureit.addareabutton" + bl_label = "Area" + bl_description = "(EDITMODE only) Add a new measure for area (select 1 o more faces)" + bl_category = 'Measureit' + + # ------------------------------ + # 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 + # 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 for add a measure segment to x/y/z origin +# +# ------------------------------------------------------------- +class AddSegmentOrtoButton(bpy.types.Operator): + bl_idname = "measureit.addsegmentortobutton" + bl_label = "Add" + bl_description = "(EDITMODE only) Add a new measure segment from vertex to object origin for one " \ + "axis (select 1 vertex)" + bl_category = 'Measureit' + tag = bpy.props.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': + # Add properties + scene = context.scene + mainobject = context.object + mylist = get_smart_selected(mainobject) + if len(mylist) < 1: # if not selected linked vertex + mylist = get_selected_vertex(mainobject) + + if len(mylist) >= 1: + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + for x in range(0, len(mylist)): + # ----------------------- + # Only if not exist + # ----------------------- + if exist_segment(mp, mylist[x], mylist[x], 12 + int(self.tag)) 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 = 12 + int(self.tag) + ms.glpointa = mylist[x] + ms.glpointb = mylist[x] + 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 + # 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 vertex for creating measure segment.") + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for add a angle +# +# ------------------------------------------------------------- +class AddAngleButton(bpy.types.Operator): + bl_idname = "measureit.addanglebutton" + bl_label = "Angle" + bl_description = "(EDITMODE only) Add a new angle measure (select 3 vertices, 2nd is angle vertex)" + bl_category = 'Measureit' + + # ------------------------------ + # 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_vertex_history(mainobject) + if len(mylist) == 3: + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + # ----------------------- + # Only if not exist + # ----------------------- + if exist_segment(mp, mylist[0], mylist[1], 9, mylist[2]) 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 = 9 + ms.glpointa = mylist[0] + ms.glpointb = mylist[1] + ms.glpointc = mylist[2] + # 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 + # Add index + mp.measureit_num += 1 + + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'ERROR'}, + "MeasureIt: Select three vertices for creating angle measure") + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for add a arc +# +# ------------------------------------------------------------- +class AddArcButton(bpy.types.Operator): + bl_idname = "measureit.addarcbutton" + bl_label = "Angle" + bl_description = "(EDITMODE only) Add a new arc measure (select 3 vertices of the arc," \ + " vertices 1st and 3rd are arc extremes)" + bl_category = 'Measureit' + + # ------------------------------ + # 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_vertex_history(mainobject) + if len(mylist) == 3: + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + # ----------------------- + # Only if not exist + # ----------------------- + if exist_segment(mp, mylist[0], mylist[1], 11, mylist[2]) 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 = 11 + ms.glpointa = mylist[0] + ms.glpointb = mylist[1] + ms.glpointc = mylist[2] + 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 + # Add index + mp.measureit_num += 1 + + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'ERROR'}, + "MeasureIt: Select three vertices for creating arc measure") + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for add a label segment +# +# ------------------------------------------------------------- +class AddLabelButton(bpy.types.Operator): + bl_idname = "measureit.addlabelbutton" + bl_label = "Add" + bl_description = "(EDITMODE only) Add a new measure label (select 1 vertex)" + bl_category = 'Measureit' + + # ------------------------------ + # 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_vertex(mainobject) + if len(mylist) == 1: + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + # ----------------------- + # Only if not exist + # ----------------------- + if exist_segment(mp, mylist[0], mylist[0], 2) is False: # Both equal + # 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 = 2 + ms.glpointa = mylist[0] + ms.glpointb = mylist[0] # Equal + 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 + # Add index + mp.measureit_num += 1 + + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'ERROR'}, + "MeasureIt: Select one vertex for creating measure label") + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for add a link +# +# ------------------------------------------------------------- +class AddLinkButton(bpy.types.Operator): + bl_idname = "measureit.addlinkbutton" + bl_label = "Add" + bl_description = "(OBJECT mode only) Add a new measure between objects (select 2 " \ + "objects and optionally 1 or 2 vertices)" + bl_category = 'Measureit' + + # ------------------------------ + # Poll + # ------------------------------ + @classmethod + def poll(cls, context): + o = context.object + if o is None: + return False + else: + if o.type == "MESH" or o.type == "EMPTY" or o.type == "CAMERA" or o.type == "LAMP": + if bpy.context.mode == 'OBJECT': + return True + else: + return False + else: + return False + + # ------------------------------ + # Execute button action + # ------------------------------ + def execute(self, context): + if context.area.type == 'VIEW_3D': + scene = context.scene + mainobject = context.object + # ------------------------------- + # Verify number of objects + # ------------------------------- + if len(context.selected_objects) != 2: + self.report({'ERROR'}, + "MeasureIt: Select two objects only, and optionally 1 vertex or 2 vertices " + "(one of each object)") + return {'FINISHED'} + # Locate other object + linkobject = None + for o in context.selected_objects: + if o.name != mainobject.name: + linkobject = o.name + # Verify destination vertex + lkobj = bpy.data.objects[linkobject] + mylinkvertex = get_selected_vertex(lkobj) + if len(mylinkvertex) > 1: + self.report({'ERROR'}, + "MeasureIt: The destination object has more than one vertex selected. " + "Select only 1 or none") + return {'FINISHED'} + # Verify origin vertex + myobjvertex = get_selected_vertex(mainobject) + if len(mylinkvertex) > 1: + self.report({'ERROR'}, + "MeasureIt: The active object has more than one vertex selected. Select only 1 or none") + return {'FINISHED'} + + # ------------------------------- + # Add properties + # ------------------------------- + flag = False + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + + # if exist_segment(mp, mylist[0], mylist[0], 3) is False: + # flag = True + # 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] + # ----------------------- + # Vertex to Vertex + # ----------------------- + if len(myobjvertex) == 1 and len(mylinkvertex) == 1: + ms.gltype = 3 + ms.glpointa = myobjvertex[0] + ms.glpointb = mylinkvertex[0] + flag = True + # ----------------------- + # Vertex to Object + # ----------------------- + if len(myobjvertex) == 1 and len(mylinkvertex) == 0: + ms.gltype = 4 + ms.glpointa = myobjvertex[0] + ms.glpointb = 0 + flag = True + # ----------------------- + # Object to Vertex + # ----------------------- + if len(myobjvertex) == 0 and len(mylinkvertex) == 1: + ms.gltype = 5 + ms.glpointa = 0 + ms.glpointb = mylinkvertex[0] + flag = True + # ----------------------- + # Object to Object + # ----------------------- + if len(myobjvertex) == 0 and len(mylinkvertex) == 0: + ms.gltype = 8 + ms.glpointa = 0 + ms.glpointb = 0 # Equal + flag = True + + # ------------------ + # only if created + # ------------------ + if flag is True: + 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 + # link + ms.gllink = linkobject + # Add index + mp.measureit_num += 1 + + # ----------------------- + # Only if not exist + # ----------------------- + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for add a origin segment +# +# ------------------------------------------------------------- +class AddOriginButton(bpy.types.Operator): + bl_idname = "measureit.addoriginbutton" + bl_label = "Add" + bl_description = "(OBJECT mode only) Add a new measure to origin (select object and optionally 1 vertex)" + bl_category = 'Measureit' + + # ------------------------------ + # Poll + # ------------------------------ + @classmethod + def poll(cls, context): + o = context.object + if o is None: + return False + else: + if o.type == "MESH" or o.type == "EMPTY" or o.type == "CAMERA" or o.type == "LAMP": + if bpy.context.mode == 'OBJECT': + 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_vertex(mainobject) + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + # 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] + flag = False + if len(mylist) > 0: + if len(mylist) == 1: + if exist_segment(mp, mylist[0], mylist[0], 6) is False: # Both equal + flag = True + # Vertex to origin + ms.gltype = 6 + ms.glpointa = mylist[0] + ms.glpointb = mylist[0] + else: + self.report({'ERROR'}, + "MeasureIt: Enter in EDITMODE and select one vertex only for creating " + "measure from vertex to origin") + return {'FINISHED'} + else: + # Object to origin + if exist_segment(mp, 0, 0, 7) is False: # Both equal + flag = True + ms.gltype = 7 + ms.glpointa = 0 + ms.glpointb = 0 + # ------------------ + # only if created + # ------------------ + if flag is True: + 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 + # Add index + mp.measureit_num += 1 + + # redraw + context.area.tag_redraw() + + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for delete a measure segment +# +# ------------------------------------------------------------- +class DeleteSegmentButton(bpy.types.Operator): + bl_idname = "measureit.deletesegmentbutton" + bl_label = "Delete" + bl_description = "Delete a measure" + bl_category = 'Measureit' + tag = bpy.props.IntProperty() + + # ------------------------------ + # Execute button action + # ------------------------------ + def execute(self, context): + if context.area.type == 'VIEW_3D': + # Add properties + mainobject = context.object + mp = mainobject.MeasureGenerator[0] + ms = mp.measureit_segments[self.tag] + ms.glfree = True + # Delete element + mp.measureit_segments.remove(self.tag) + mp.measureit_num -= 1 + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for delete all measure segment +# +# ------------------------------------------------------------- +class DeleteAllSegmentButton(bpy.types.Operator): + bl_idname = "measureit.deleteallsegmentbutton" + bl_label = "Delete" + bl_description = "Delete all measures (it cannot be undone)" + bl_category = 'Measureit' + tag = bpy.props.IntProperty() + + # ------------------------------ + # Execute button action + # ------------------------------ + def execute(self, context): + if context.area.type == 'VIEW_3D': + # Add properties + mainobject = context.object + mp = mainobject.MeasureGenerator[0] + + while len(mp.measureit_segments) > 0: + mp.measureit_segments.remove(0) + + # reset size + mp.measureit_num = len(mp.measureit_segments) + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for delete all measure segment +# +# ------------------------------------------------------------- +class DeleteAllSumButton(bpy.types.Operator): + bl_idname = "measureit.deleteallsumbutton" + bl_label = "Delete" + bl_description = "Delete all sum groups" + bl_category = 'Measureit' + tag = bpy.props.IntProperty() + + # ------------------------------ + # Execute button action + # ------------------------------ + # noinspection PyMethodMayBeStatic + def execute(self, context): + if context.object is not None: + if 'MeasureGenerator' in context.object: + mp = context.object.MeasureGenerator[0] + for idx in range(0, mp.measureit_num): + ms = mp.measureit_segments[idx] + ms.gltot = '99' + + return {'FINISHED'} + + +# ------------------------------------------------------------- +# Defines button for render +# +# ------------------------------------------------------------- +class RenderSegmentButton(bpy.types.Operator): + bl_idname = "measureit.rendersegmentbutton" + bl_label = "Render" + bl_description = "Create a render image with measures. Use UV/Image editor to view image generated" + bl_category = 'Measureit' + tag = bpy.props.IntProperty() + + # ------------------------------ + # Execute button action + # ------------------------------ + # noinspection PyMethodMayBeStatic,PyUnusedLocal + def execute(self, context): + scene = context.scene + msg = "New image created with measures. Open it in UV/image editor" + camera_msg = "Unable to render. No camera found" + # ----------------------------- + # Check camera + # ----------------------------- + if scene.camera is None: + self.report({'ERROR'}, camera_msg) + return {'FINISHED'} + # ----------------------------- + # Use default render + # ----------------------------- + if scene.measureit_render_type == "1": + # noinspection PyBroadException + try: + result = bpy.data.images['Render Result'] + if result.has_data is False: + bpy.ops.render.render() + except: + bpy.ops.render.render() + print("MeasureIt: Using current render image on buffer") + if render_main(self, context) is True: + self.report({'INFO'}, msg) + + # ----------------------------- + # OpenGL image + # ----------------------------- + if scene.measureit_render_type == "2": + self.set_camera_view() + self.set_only_render(True) + + print("MeasureIt: Rendering opengl image") + bpy.ops.render.opengl() + if render_main(self, context) is True: + self.report({'INFO'}, msg) + + self.set_only_render(False) + + # ----------------------------- + # OpenGL Animation + # ----------------------------- + if scene.measureit_render_type == "3": + oldframe = scene.frame_current + self.set_camera_view() + self.set_only_render(True) + flag = False + # loop frames + for frm in range(scene.frame_start, scene.frame_end + 1): + scene.frame_set(frm) + print("MeasureIt: Rendering opengl frame %04d" % frm) + bpy.ops.render.opengl() + flag = render_main(self, context, True) + if flag is False: + break + + self.set_only_render(False) + scene.frame_current = oldframe + if flag is True: + self.report({'INFO'}, msg) + + # ----------------------------- + # Image + # ----------------------------- + if scene.measureit_render_type == "4": + print("MeasureIt: Rendering image") + bpy.ops.render.render() + if render_main(self, context) is True: + self.report({'INFO'}, msg) + + # ----------------------------- + # Animation + # ----------------------------- + if scene.measureit_render_type == "5": + oldframe = scene.frame_current + flag = False + # loop frames + for frm in range(scene.frame_start, scene.frame_end + 1): + scene.frame_set(frm) + print("MeasureIt: Rendering frame %04d" % frm) + bpy.ops.render.render() + flag = render_main(self, context, True) + if flag is False: + break + + scene.frame_current = oldframe + if flag is True: + self.report({'INFO'}, msg) + + return {'FINISHED'} + + # --------------------- + # Set cameraView + # --------------------- + # noinspection PyMethodMayBeStatic + def set_camera_view(self): + for area in bpy.context.screen.areas: + if area.type == 'VIEW_3D': + area.spaces[0].region_3d.view_perspective = 'CAMERA' + + # ------------------------------------- + # Set only render status + # ------------------------------------- + # noinspection PyMethodMayBeStatic + def set_only_render(self, status): + screen = bpy.context.screen + + v3d = False + s = None + # get spaceview_3d in current screen + for a in screen.areas: + if a.type == 'VIEW_3D': + for s in a.spaces: + if s.type == 'VIEW_3D': + v3d = s + break + + if v3d is not False: + s.show_only_render = status + + +# ------------------------------------------------------------- +# Defines a new note +# +# ------------------------------------------------------------- +class AddNoteButton(bpy.types.Operator): + bl_idname = "measureit.addnotebutton" + bl_label = "Note" + bl_description = "(OBJECT mode only) Add a new annotation" + bl_category = 'Measureit' + tag = bpy.props.IntProperty() + + # ------------------------------ + # Poll + # ------------------------------ + # noinspection PyUnusedLocal + @classmethod + def poll(cls, context): + if bpy.context.mode == 'OBJECT': + return True + else: + return False + + # ------------------------------ + # Execute button action + # ------------------------------ + def execute(self, context): + if context.area.type == 'VIEW_3D': + bpy.ops.object.empty_add(type='PLAIN_AXES') + myempty = bpy.data.objects[bpy.context.active_object.name] + myempty.location = bpy.context.scene.cursor_location + myempty.empty_draw_size = 0.01 + myempty.name = "Annotation" + # Add properties + scene = context.scene + mainobject = myempty + if 'MeasureGenerator' not in mainobject: + mainobject.MeasureGenerator.add() + + mp = mainobject.MeasureGenerator[0] + # 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 = 10 + ms.glpointa = 0 + ms.glpointb = 0 # Equal + # 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 + # Add index + mp.measureit_num += 1 + + # redraw + context.area.tag_redraw() + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Defines button for enable/disable the tip display +# +# ------------------------------------------------------------- +class RunHintDisplayButton(bpy.types.Operator): + bl_idname = "measureit.runopenglbutton" + bl_label = "Display hint data manager" + bl_description = "Main control for enabling or disabling the display of measurements in the viewport" + bl_category = 'Measureit' + + _handle = None # keep function handler + + # ---------------------------------- + # Enable gl drawing adding handler + # ---------------------------------- + @staticmethod + def handle_add(self, context): + if RunHintDisplayButton._handle is None: + RunHintDisplayButton._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (self, context), + 'WINDOW', + 'POST_PIXEL') + context.window_manager.measureit_run_opengl = True + + # ------------------------------------ + # Disable gl drawing removing handler + # ------------------------------------ + # noinspection PyUnusedLocal + @staticmethod + def handle_remove(self, context): + if RunHintDisplayButton._handle is not None: + bpy.types.SpaceView3D.draw_handler_remove(RunHintDisplayButton._handle, 'WINDOW') + RunHintDisplayButton._handle = None + context.window_manager.measureit_run_opengl = False + + # ------------------------------ + # Execute button action + # ------------------------------ + def execute(self, context): + if context.area.type == 'VIEW_3D': + if context.window_manager.measureit_run_opengl is False: + self.handle_add(self, context) + context.area.tag_redraw() + else: + self.handle_remove(self, context) + context.area.tag_redraw() + + return {'FINISHED'} + else: + self.report({'WARNING'}, + "View3D not found, cannot run operator") + + return {'CANCELLED'} + + +# ------------------------------------------------------------- +# Handle all draw routines (OpenGL main entry point) +# +# ------------------------------------------------------------- +def draw_main(context): + region = bpy.context.region + # Detect if Quadview to get drawing area + if not context.space_data.region_quadviews: + rv3d = bpy.context.space_data.region_3d + else: + # verify area + if context.area.type != 'VIEW_3D' or context.space_data.type != 'VIEW_3D': + return + i = -1 + for region in context.area.regions: + if region.type == 'WINDOW': + i += 1 + if context.region.id == region.id: + break + else: + return + + rv3d = context.space_data.region_quadviews[i] + + scene = bpy.context.scene + # Get visible layers + layers = [] + for x in range(0, 20): + if bpy.context.scene.layers[x] is True: + layers.extend([x]) + + # Display selected or all + if scene.measureit_gl_ghost is False: + objlist = context.selected_objects + else: + objlist = context.scene.objects + + # Enable GL drawing + bgl.glEnable(bgl.GL_BLEND) + # --------------------------------------- + # Generate all OpenGL calls for measures + # --------------------------------------- + for myobj in objlist: + if myobj.hide is False: + if 'MeasureGenerator' in myobj: + # verify visible layer + for x in range(0, 20): + if myobj.layers[x] is True: + if x in layers: + op = myobj.MeasureGenerator[0] + draw_segments(context, myobj, op, region, rv3d) + break + # --------------------------------------- + # Generate all OpenGL calls for debug + # --------------------------------------- + if scene.measureit_debug is True: + selobj = bpy.context.selected_objects + for myobj in selobj: + if scene.measureit_debug_vertices is True: + draw_vertices(context, myobj, region, rv3d) + if scene.measureit_debug_faces is True or scene.measureit_debug_normals is True: + draw_faces(context, myobj, region, rv3d) + + # ----------------------- + # restore opengl defaults + # ----------------------- + bgl.glLineWidth(1) + bgl.glDisable(bgl.GL_BLEND) + bgl.glColor4f(0.0, 0.0, 0.0, 1.0) + + +# ------------------------------------------------------------- +# Handler for drawing OpenGl +# ------------------------------------------------------------- +# noinspection PyUnusedLocal +def draw_callback_px(self, context): + draw_main(context) + + +# ------------------------------------------------------------- +# Check if the segment already exist +# +# ------------------------------------------------------------- +def exist_segment(mp, pointa, pointb, typ=1, pointc=None): + # for ms in mp.measureit_segments[mp.measureit_num] + for ms in mp.measureit_segments: + if ms.gltype == typ and ms.glfree is False: + if typ != 9: + if ms.glpointa == pointa and ms.glpointb == pointb: + return True + if ms.glpointa == pointb and ms.glpointb == pointa: + return True + else: + if ms.glpointa == pointa and ms.glpointb == pointb and ms.glpointc == pointc: + return True + + return False + + +# ------------------------------------------------------------- +# Get vertex selected +# ------------------------------------------------------------- +def get_selected_vertex(myobject): + mylist = [] + # if not mesh, no vertex + if myobject.type != "MESH": + return mylist + # -------------------- + # meshes + # -------------------- + oldobj = bpy.context.object + bpy.context.scene.objects.active = myobject + flag = False + if myobject.mode != 'EDIT': + bpy.ops.object.mode_set(mode='EDIT') + flag = True + + bm = bmesh.from_edit_mesh(myobject.data) + tv = len(bm.verts) + for v in bm.verts: + if v.select: + mylist.extend([v.index]) + + if flag is True: + bpy.ops.object.editmode_toggle() + # Back context object + bpy.context.scene.objects.active = oldobj + + # if select all vertices, then use origin + if tv == len(mylist): + return [] + + return mylist + + +# ------------------------------------------------------------- +# Get vertex selected +# ------------------------------------------------------------- +def get_selected_vertex_history(myobject): + mylist = [] + # if not mesh, no vertex + if myobject.type != "MESH": + return mylist + # -------------------- + # meshes + # -------------------- + oldobj = bpy.context.object + bpy.context.scene.objects.active = myobject + flag = False + if myobject.mode != 'EDIT': + bpy.ops.object.mode_set(mode='EDIT') + flag = True + + bm = bmesh.from_edit_mesh(myobject.data) + for v in bm.select_history: + mylist.extend([v.index]) + + if flag is True: + bpy.ops.object.editmode_toggle() + # Back context object + bpy.context.scene.objects.active = oldobj + + return mylist + + +# ------------------------------------------------------------- +# Get vertex selected segments +# ------------------------------------------------------------- +def get_smart_selected(myobject): + mylist = [] + # if not mesh, no vertex + if myobject.type != "MESH": + return mylist + # -------------------- + # meshes + # -------------------- + oldobj = bpy.context.object + bpy.context.scene.objects.active = myobject + flag = False + if myobject.mode != 'EDIT': + bpy.ops.object.mode_set(mode='EDIT') + flag = True + + bm = bmesh.from_edit_mesh(myobject.data) + for e in bm.edges: + if e.select is True: + mylist.extend([e.verts[0].index]) + mylist.extend([e.verts[1].index]) + + if flag is True: + bpy.ops.object.editmode_toggle() + # Back context object + bpy.context.scene.objects.active = oldobj + + return mylist + + +# ------------------------------------------------------------- +# Get vertex selected faces +# ------------------------------------------------------------- +def get_selected_faces(myobject): + mylist = [] + # if not mesh, no vertex + if myobject.type != "MESH": + return mylist + # -------------------- + # meshes + # -------------------- + oldobj = bpy.context.object + bpy.context.scene.objects.active = myobject + flag = False + if myobject.mode != 'EDIT': + bpy.ops.object.mode_set(mode='EDIT') + flag = True + + bm = bmesh.from_edit_mesh(myobject.data) + for e in bm.faces: + myface = [] + if e.select is True: + for i in range(0, len(e.verts)): + myface.extend([e.verts[i].index]) + + mylist.extend([myface]) + + if flag is True: + bpy.ops.object.editmode_toggle() + # Back context object + bpy.context.scene.objects.active = oldobj + + return mylist |