Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--measureit/__init__.py403
-rw-r--r--measureit/measureit_geometry.py1350
-rw-r--r--measureit/measureit_main.py2061
-rw-r--r--measureit/measureit_render.py343
4 files changed, 4157 insertions, 0 deletions
diff --git a/measureit/__init__.py b/measureit/__init__.py
new file mode 100644
index 00000000..3401a6a6
--- /dev/null
+++ b/measureit/__init__.py
@@ -0,0 +1,403 @@
+# ##### 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>
+
+# ----------------------------------------------------------
+# Author: Antonio Vazquez (antonioya)
+# ----------------------------------------------------------
+
+# ----------------------------------------------
+# Define Addon info
+# ----------------------------------------------
+bl_info = {
+ "name": "MeasureIt",
+ "author": "Antonio Vazquez (antonioya)",
+ "location": "View3D > Tools Panel /Properties panel",
+ "version": (1, 6, 6),
+ "blender": (2, 7, 4),
+ "description": "Tools for measuring objects.",
+ 'warning': 'Temporary: pending review fixes T48704',
+ "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
+ "category": "3D View"}
+
+import sys
+import os
+
+# ----------------------------------------------
+# Add to Phyton path (once only)
+# ----------------------------------------------
+path = sys.path
+flag = False
+for item in path:
+ if "measureit" in item:
+ flag = True
+if flag is False:
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'measureit'))
+ print("measureit: added to phytonpath")
+
+# ----------------------------------------------
+# Import modules
+# ----------------------------------------------
+if "bpy" in locals():
+ import imp
+
+ imp.reload(measureit_main)
+ print("measureit: Reloaded multifiles")
+else:
+ import measureit_main
+
+ print("measureit: Imported multifiles")
+
+# noinspection PyUnresolvedReferences
+import bpy
+# noinspection PyUnresolvedReferences
+from bpy.props import *
+
+
+# --------------------------------------------------------------
+# Register all operators and panels
+# --------------------------------------------------------------
+def register():
+ bpy.utils.register_class(measureit_main.RunHintDisplayButton)
+ bpy.utils.register_class(measureit_main.AddSegmentButton)
+ bpy.utils.register_class(measureit_main.AddAreaButton)
+ bpy.utils.register_class(measureit_main.AddSegmentOrtoButton)
+ bpy.utils.register_class(measureit_main.AddAngleButton)
+ bpy.utils.register_class(measureit_main.AddArcButton)
+ bpy.utils.register_class(measureit_main.AddLabelButton)
+ bpy.utils.register_class(measureit_main.AddNoteButton)
+ bpy.utils.register_class(measureit_main.AddLinkButton)
+ bpy.utils.register_class(measureit_main.AddOriginButton)
+ bpy.utils.register_class(measureit_main.DeleteSegmentButton)
+ bpy.utils.register_class(measureit_main.DeleteAllSegmentButton)
+ bpy.utils.register_class(measureit_main.DeleteAllSumButton)
+ bpy.utils.register_class(measureit_main.MeasureitEditPanel)
+ bpy.utils.register_class(measureit_main.MeasureitMainPanel)
+ bpy.utils.register_class(measureit_main.MeasureitConfPanel)
+ bpy.utils.register_class(measureit_main.MeasureitRenderPanel)
+ bpy.utils.register_class(measureit_main.RenderSegmentButton)
+
+ # Define properties
+ bpy.types.Scene.measureit_default_color = bpy.props.FloatVectorProperty(
+ name="Default color",
+ description="Default Color",
+ default=(0.173, 0.545, 1.0, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_font_size = bpy.props.IntProperty(name="Text Size",
+ description="Default text size",
+ default=14, min=10, max=150)
+ bpy.types.Scene.measureit_hint_space = bpy.props.FloatProperty(name='Separation', min=0, max=100, default=0.1,
+ precision=3,
+ description="Default distance to display measure")
+ bpy.types.Scene.measureit_gl_ghost = bpy.props.BoolProperty(name="All",
+ description="Display measures for all objects,"
+ " not only selected",
+ default=True)
+ bpy.types.Scene.measureit_gl_txt = bpy.props.StringProperty(name="Text", maxlen=256,
+ description="Short description (use | for line break)")
+
+ bpy.types.Scene.measureit_gl_precision = bpy.props.IntProperty(name='Precision', min=0, max=5, default=2,
+ description="Number of decimal precision")
+ bpy.types.Scene.measureit_gl_show_d = bpy.props.BoolProperty(name="ShowDist",
+ description="Display distances",
+ default=True)
+ bpy.types.Scene.measureit_gl_show_n = bpy.props.BoolProperty(name="ShowName",
+ description="Display texts",
+ default=False)
+ bpy.types.Scene.measureit_scale = bpy.props.BoolProperty(name="Scale",
+ description="Use scale factor",
+ default=False)
+ bpy.types.Scene.measureit_scale_factor = bpy.props.FloatProperty(name='Factor', min=0.001, max=9999999,
+ default=1.0,
+ precision=3,
+ description="Scale factor 1:x")
+ bpy.types.Scene.measureit_scale_color = bpy.props.FloatVectorProperty(name="Scale color",
+ description="Scale Color",
+ default=(1, 1, 0, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_scale_font = bpy.props.IntProperty(name="Font",
+ description="Text size",
+ default=14, min=10, max=150)
+ bpy.types.Scene.measureit_scale_pos_x = bpy.props.IntProperty(name="Position X",
+ description="Margin on the X axis",
+ default=5,
+ min=0,
+ max=100)
+ bpy.types.Scene.measureit_scale_pos_y = bpy.props.IntProperty(name="Position Y",
+ description="Margin on the Y axis",
+ default=5,
+ min=0,
+ max=100)
+ bpy.types.Scene.measureit_gl_scaletxt = bpy.props.StringProperty(name="ScaleText", maxlen=48,
+ description="Scale title",
+ default="Scale:")
+ bpy.types.Scene.measureit_scale_precision = bpy.props.IntProperty(name='Precision', min=0, max=5, default=0,
+ description="Number of decimal precision")
+
+ bpy.types.Scene.measureit_ovr = bpy.props.BoolProperty(name="Override",
+ description="Override colors and fonts",
+ default=False)
+ bpy.types.Scene.measureit_ovr_font = bpy.props.IntProperty(name="Font",
+ description="Override text size",
+ default=14, min=10, max=150)
+ bpy.types.Scene.measureit_ovr_color = bpy.props.FloatVectorProperty(name="Override color",
+ description="Override Color",
+ default=(1, 0, 0, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_ovr_width = bpy.props.IntProperty(name='Override width', min=1, max=10, default=1,
+ description='override line width')
+
+ bpy.types.Scene.measureit_units = bpy.props.EnumProperty(items=(('1', "Automatic", "Use scene units"),
+ ('2', "Meters", ""),
+ ('3', "Centimeters", ""),
+ ('4', "Milimiters", ""),
+ ('5', "Feet", ""),
+ ('6', "Inches", "")),
+ name="Units",
+ default="2",
+ description="Units")
+ bpy.types.Scene.measureit_render = bpy.props.BoolProperty(name="Render",
+ description="Save an image with measures over"
+ " render image",
+ default=False)
+ bpy.types.Scene.measureit_render_type = bpy.props.EnumProperty(items=(('1', "*Current", "Use current render"),
+ ('2', "OpenGL", ""),
+ ('3', "Animation OpenGL", ""),
+ ('4', "Image", ""),
+ ('5', "Animation", "")),
+ name="Render type",
+ description="Type of render image")
+ bpy.types.Scene.measureit_sum = 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")
+
+ bpy.types.Scene.measureit_rf = bpy.props.BoolProperty(name="render_frame",
+ description="Add a frame in render output",
+ default=False)
+ bpy.types.Scene.measureit_rf_color = bpy.props.FloatVectorProperty(name="Fcolor",
+ description="Frame Color",
+ default=(0.9, 0.9, 0.9, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_rf_border = bpy.props.IntProperty(name='fborder ', min=1, max=1000, default=10,
+ description='Frame space from border')
+ bpy.types.Scene.measureit_rf_line = bpy.props.IntProperty(name='fline', min=1, max=10, default=1,
+ description='Line width for border')
+
+ bpy.types.Scene.measureit_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")
+ bpy.types.Scene.measureit_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")
+ bpy.types.Scene.measureit_glarrow_s = bpy.props.IntProperty(name="Size",
+ description="Arrow size",
+ default=15, min=6, max=500)
+
+ bpy.types.Scene.measureit_debug = bpy.props.BoolProperty(name="Debug",
+ description="Display information for debuging"
+ " (expand/collapse for enabling or disabling)"
+ " this information is only renderered for "
+ "selected objects",
+ default=False)
+ bpy.types.Scene.measureit_debug_select = bpy.props.BoolProperty(name="Selected",
+ description="Display information "
+ "for selected vertices/faces",
+ default=False)
+ bpy.types.Scene.measureit_debug_vertices = bpy.props.BoolProperty(name="Vertices",
+ description="Display vertex number",
+ default=True)
+ bpy.types.Scene.measureit_debug_location = bpy.props.BoolProperty(name="Location",
+ description="Display vertex location",
+ default=False)
+ bpy.types.Scene.measureit_debug_faces = bpy.props.BoolProperty(name="Faces",
+ description="Display face number",
+ default=False)
+ bpy.types.Scene.measureit_debug_normals = bpy.props.BoolProperty(name="Normals",
+ description="Display face normal "
+ "vector and creation order",
+ default=False)
+ bpy.types.Scene.measureit_debug_normal_details = bpy.props.BoolProperty(name="Details",
+ description="Display face normal details",
+ default=True)
+ bpy.types.Scene.measureit_debug_font = bpy.props.IntProperty(name="Font",
+ description="Debug text size",
+ default=14, min=10, max=150)
+ bpy.types.Scene.measureit_debug_color = bpy.props.FloatVectorProperty(name="Debug color",
+ description="Debug Color",
+ default=(1, 0, 0, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_debug_color2 = bpy.props.FloatVectorProperty(name="Debug face color",
+ description="Debug face Color",
+ default=(0, 1, 0, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_debug_color3 = bpy.props.FloatVectorProperty(name="Debug vector color",
+ description="Debug vector Color",
+ default=(1.0, 1.0, 0.1, 1.0),
+ min=0.1,
+ max=1,
+ subtype='COLOR',
+ size=4)
+ bpy.types.Scene.measureit_debug_normal_size = bpy.props.FloatProperty(name='Len', min=0.001, max=9,
+ default=0.5,
+ precision=2,
+ description="Normal arrow size")
+ bpy.types.Scene.measureit_debug_width = bpy.props.IntProperty(name='Debug width', min=1, max=10, default=2,
+ description='Vector line thickness')
+ bpy.types.Scene.measureit_debug_precision = bpy.props.IntProperty(name='Precision', min=0, max=5, default=1,
+ description="Number of decimal precision")
+
+ # OpenGL flag
+ wm = bpy.types.WindowManager
+ # register internal property
+ wm.measureit_run_opengl = bpy.props.BoolProperty(default=False)
+
+
+def unregister():
+ bpy.utils.unregister_class(measureit_main.RunHintDisplayButton)
+ bpy.utils.unregister_class(measureit_main.AddSegmentButton)
+ bpy.utils.unregister_class(measureit_main.AddAreaButton)
+ bpy.utils.unregister_class(measureit_main.AddSegmentOrtoButton)
+ bpy.utils.unregister_class(measureit_main.AddAngleButton)
+ bpy.utils.unregister_class(measureit_main.AddArcButton)
+ bpy.utils.unregister_class(measureit_main.AddLabelButton)
+ bpy.utils.unregister_class(measureit_main.AddNoteButton)
+ bpy.utils.unregister_class(measureit_main.AddLinkButton)
+ bpy.utils.unregister_class(measureit_main.AddOriginButton)
+ bpy.utils.unregister_class(measureit_main.DeleteSegmentButton)
+ bpy.utils.unregister_class(measureit_main.DeleteAllSegmentButton)
+ bpy.utils.unregister_class(measureit_main.DeleteAllSumButton)
+ bpy.utils.unregister_class(measureit_main.MeasureitEditPanel)
+ bpy.utils.unregister_class(measureit_main.MeasureitMainPanel)
+ bpy.utils.unregister_class(measureit_main.MeasureitConfPanel)
+ bpy.utils.unregister_class(measureit_main.MeasureitRenderPanel)
+ bpy.utils.unregister_class(measureit_main.RenderSegmentButton)
+
+ # Remove properties
+ del bpy.types.Scene.measureit_default_color
+ del bpy.types.Scene.measureit_font_size
+ del bpy.types.Scene.measureit_hint_space
+ del bpy.types.Scene.measureit_gl_ghost
+ del bpy.types.Scene.measureit_gl_txt
+ del bpy.types.Scene.measureit_gl_precision
+ del bpy.types.Scene.measureit_gl_show_d
+ del bpy.types.Scene.measureit_gl_show_n
+ del bpy.types.Scene.measureit_scale
+ del bpy.types.Scene.measureit_scale_factor
+ del bpy.types.Scene.measureit_scale_color
+ del bpy.types.Scene.measureit_scale_font
+ del bpy.types.Scene.measureit_scale_pos_x
+ del bpy.types.Scene.measureit_scale_pos_y
+ del bpy.types.Scene.measureit_gl_scaletxt
+ del bpy.types.Scene.measureit_scale_precision
+ del bpy.types.Scene.measureit_ovr
+ del bpy.types.Scene.measureit_ovr_font
+ del bpy.types.Scene.measureit_ovr_color
+ del bpy.types.Scene.measureit_ovr_width
+ del bpy.types.Scene.measureit_units
+ del bpy.types.Scene.measureit_render
+ del bpy.types.Scene.measureit_render_type
+ del bpy.types.Scene.measureit_sum
+ del bpy.types.Scene.measureit_rf
+ del bpy.types.Scene.measureit_rf_color
+ del bpy.types.Scene.measureit_rf_border
+ del bpy.types.Scene.measureit_rf_line
+ del bpy.types.Scene.measureit_glarrow_a
+ del bpy.types.Scene.measureit_glarrow_b
+ del bpy.types.Scene.measureit_glarrow_s
+ del bpy.types.Scene.measureit_debug
+ del bpy.types.Scene.measureit_debug_select
+ del bpy.types.Scene.measureit_debug_vertices
+ del bpy.types.Scene.measureit_debug_faces
+ del bpy.types.Scene.measureit_debug_normals
+ del bpy.types.Scene.measureit_debug_normal_details
+ del bpy.types.Scene.measureit_debug_font
+ del bpy.types.Scene.measureit_debug_color
+ del bpy.types.Scene.measureit_debug_color2
+ del bpy.types.Scene.measureit_debug_color3
+ del bpy.types.Scene.measureit_debug_normal_size
+ del bpy.types.Scene.measureit_debug_width
+ del bpy.types.Scene.measureit_debug_precision
+ del bpy.types.Scene.measureit_debug_location
+
+ # remove OpenGL data
+ measureit_main.RunHintDisplayButton.handle_remove(measureit_main.RunHintDisplayButton, bpy.context)
+ wm = bpy.context.window_manager
+ p = 'measureit_run_opengl'
+ if p in wm:
+ del wm[p]
+
+
+if __name__ == '__main__':
+ register()
diff --git a/measureit/measureit_geometry.py b/measureit/measureit_geometry.py
new file mode 100644
index 00000000..c8c6170d
--- /dev/null
+++ b/measureit/measureit_geometry.py
@@ -0,0 +1,1350 @@
+# ##### 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>
+
+# ----------------------------------------------------------
+# support routines for OpenGL
+# Author: Antonio Vazquez (antonioya)
+#
+# ----------------------------------------------------------
+# noinspection PyUnresolvedReferences
+import bpy
+# noinspection PyUnresolvedReferences
+import bgl
+# noinspection PyUnresolvedReferences
+import blf
+import math
+# noinspection PyUnresolvedReferences
+import mathutils
+# noinspection PyUnresolvedReferences
+import bmesh
+# noinspection PyUnresolvedReferences
+from bpy_extras import view3d_utils, mesh_utils
+# noinspection PyUnresolvedReferences
+import bpy_extras.object_utils as object_utils
+import sys
+
+
+# -------------------------------------------------------------
+# Draw segments
+#
+# rgb: Color
+# fsize: Font size
+# -------------------------------------------------------------
+# noinspection PyUnresolvedReferences,PyUnboundLocalVariable
+def draw_segments(context, myobj, op, region, rv3d):
+ if op.measureit_num > 0:
+ a_code = "\u00b0" # degree
+ scale = bpy.context.scene.unit_settings.scale_length
+ scene = bpy.context.scene
+ pr = scene.measureit_gl_precision
+ fmt = "%1." + str(pr) + "f"
+ ovr = scene.measureit_ovr
+ ovrcolor = scene.measureit_ovr_color
+ ovrfsize = scene.measureit_ovr_font
+ ovrline = scene.measureit_ovr_width
+ units = scene.measureit_units
+ # --------------------
+ # Scene Scale
+ # --------------------
+ if scene.measureit_scale is True:
+ prs = scene.measureit_scale_precision
+ fmts = "%1." + str(prs) + "f"
+ pos_x, pos_y = get_scale_txt_location(context)
+ tx_dsp = fmts % scene.measureit_scale_factor
+ tx_scale = scene.measureit_gl_scaletxt + " 1:" + tx_dsp
+ draw_text(myobj, pos_x, pos_y,
+ tx_scale, scene.measureit_scale_color, scene.measureit_scale_font)
+ # --------------------
+ # Loop
+ # --------------------
+ for idx in range(0, op.measureit_num):
+ ms = op.measureit_segments[idx]
+ if ovr is False:
+ fsize = ms.glfont_size
+ else:
+ fsize = ovrfsize
+ # ------------------------------
+ # only active and visible
+ # ------------------------------
+ if ms.glview is True and ms.glfree is False:
+ # Arrow data
+ a_size = ms.glarrow_s
+ a_type = ms.glarrow_a
+ b_type = ms.glarrow_b
+ # noinspection PyBroadException
+ try:
+ if ovr is False:
+ rgb = ms.glcolor
+ else:
+ rgb = ovrcolor
+ # ----------------------
+ # Segment or Label
+ # ----------------------
+ if ms.gltype == 1 or ms.gltype == 2:
+ obverts = get_mesh_vertices(myobj)
+
+ if ms.glpointa <= len(obverts) and ms.glpointb <= len(obverts):
+ a_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ b_p1 = get_point(obverts[ms.glpointb].co, myobj)
+ # ----------------------
+ # Segment or Label
+ # ----------------------
+ if ms.gltype == 12 or ms.gltype == 13 or ms.gltype == 14:
+ obverts = get_mesh_vertices(myobj)
+ if ms.glpointa <= len(obverts):
+ a_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ if ms.gltype == 12: # X
+ b_p1 = get_point((0.0,
+ obverts[ms.glpointa].co[1],
+ obverts[ms.glpointa].co[2]), myobj)
+ elif ms.gltype == 13: # Y
+ b_p1 = get_point((obverts[ms.glpointa].co[0],
+ 0.0,
+ obverts[ms.glpointa].co[2]), myobj)
+ else: # Z
+ b_p1 = get_point((obverts[ms.glpointa].co[0],
+ obverts[ms.glpointa].co[1],
+ 0.0), myobj)
+ # ----------------------
+ # Vertex to Vertex (link)
+ # ----------------------
+ if ms.gltype == 3:
+ obverts = get_mesh_vertices(myobj)
+ linkverts = bpy.data.objects[ms.gllink].data.vertices
+ a_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ b_p1 = get_point(linkverts[ms.glpointb].co, bpy.data.objects[ms.gllink])
+ # ----------------------
+ # Vertex to Object (link)
+ # ----------------------
+ if ms.gltype == 4:
+ obverts = get_mesh_vertices(myobj)
+ a_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ b_p1 = get_location(bpy.data.objects[ms.gllink])
+ # ----------------------
+ # Object to Vertex (link)
+ # ----------------------
+ if ms.gltype == 5:
+ linkverts = bpy.data.objects[ms.gllink].data.vertices
+ a_p1 = get_location(myobj)
+ b_p1 = get_point(linkverts[ms.glpointb].co, bpy.data.objects[ms.gllink])
+ # ----------------------
+ # Object to Object (link)
+ # ----------------------
+ if ms.gltype == 8:
+ a_p1 = get_location(myobj)
+ b_p1 = get_location(bpy.data.objects[ms.gllink])
+ # ----------------------
+ # Vertex to origin
+ # ----------------------
+ if ms.gltype == 6:
+ obverts = get_mesh_vertices(myobj)
+ a_p1 = (0, 0, 0)
+ b_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ # ----------------------
+ # Object to origin
+ # ----------------------
+ if ms.gltype == 7:
+ a_p1 = (0, 0, 0)
+ b_p1 = get_location(myobj)
+ # ----------------------
+ # Angle
+ # ----------------------
+ if ms.gltype == 9:
+ obverts = get_mesh_vertices(myobj)
+ if ms.glpointa <= len(obverts) and ms.glpointb <= len(obverts) and ms.glpointc <= len(obverts):
+ an_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ an_p2 = get_point(obverts[ms.glpointb].co, myobj)
+ an_p3 = get_point(obverts[ms.glpointc].co, myobj)
+
+ ang_1 = mathutils.Vector((an_p1[0] - an_p2[0], an_p1[1] - an_p2[1], an_p1[2] - an_p2[2]))
+ ang_2 = mathutils.Vector((an_p3[0] - an_p2[0], an_p3[1] - an_p2[1], an_p3[2] - an_p2[2]))
+
+ ang_3 = ang_1 + ang_2 # Result vector
+
+ a_p1 = (an_p2[0], an_p2[1], an_p2[2])
+ b_p1 = (0, 0, 0)
+ # ----------------------
+ # Annotation
+ # ----------------------
+ if ms.gltype == 10:
+ a_p1 = get_location(myobj)
+ b_p1 = get_location(myobj)
+
+ # ----------------------
+ # Arc
+ # ----------------------
+ if ms.gltype == 11:
+ obverts = get_mesh_vertices(myobj)
+ if ms.glpointa <= len(obverts) and ms.glpointb <= len(obverts) and ms.glpointc <= len(obverts):
+ an_p1 = get_point(obverts[ms.glpointa].co, myobj)
+ an_p2 = get_point(obverts[ms.glpointb].co, myobj)
+ an_p3 = get_point(obverts[ms.glpointc].co, myobj)
+ # reference for maths: http://en.wikipedia.org/wiki/Circumscribed_circle
+ an_p12 = mathutils.Vector((an_p1[0] - an_p2[0], an_p1[1] - an_p2[1], an_p1[2] - an_p2[2]))
+ an_p13 = mathutils.Vector((an_p1[0] - an_p3[0], an_p1[1] - an_p3[1], an_p1[2] - an_p3[2]))
+ an_p21 = mathutils.Vector((an_p2[0] - an_p1[0], an_p2[1] - an_p1[1], an_p2[2] - an_p1[2]))
+ an_p23 = mathutils.Vector((an_p2[0] - an_p3[0], an_p2[1] - an_p3[1], an_p2[2] - an_p3[2]))
+ an_p31 = mathutils.Vector((an_p3[0] - an_p1[0], an_p3[1] - an_p1[1], an_p3[2] - an_p1[2]))
+ an_p32 = mathutils.Vector((an_p3[0] - an_p2[0], an_p3[1] - an_p2[1], an_p3[2] - an_p2[2]))
+ an_p12xp23 = an_p12.copy().cross(an_p23)
+
+ # radius = an_p12.length * an_p23.length * an_p31.length / (2 * an_p12xp23.length)
+
+ alpha = pow(an_p23.length, 2) * an_p12.dot(an_p13) / (2 * pow(an_p12xp23.length, 2))
+ beta = pow(an_p13.length, 2) * an_p21.dot(an_p23) / (2 * pow(an_p12xp23.length, 2))
+ gamma = pow(an_p12.length, 2) * an_p31.dot(an_p32) / (2 * pow(an_p12xp23.length, 2))
+
+ a_p1 = (alpha * an_p1[0] + beta * an_p2[0] + gamma * an_p3[0],
+ alpha * an_p1[1] + beta * an_p2[1] + gamma * an_p3[1],
+ alpha * an_p1[2] + beta * an_p2[2] + gamma * an_p3[2])
+
+ b_p1 = (an_p2[0], an_p2[1], an_p2[2])
+ a_n = an_p12.cross(an_p23)
+ a_n.normalize() # normal vector
+ arc_angle, arc_length = get_arc_data(an_p1, a_p1, an_p2, an_p3)
+ # Apply scale to arc_length
+ arc_length *= scene.measureit_scale_factor
+
+ # ----------------------
+ # Area
+ # ----------------------
+ if ms.gltype == 20:
+ a_p1 = get_location(myobj) # Not used
+ b_p1 = get_location(myobj) # Not used
+
+ # Calculate distance
+ dist, distloc = distance(a_p1, b_p1, ms.glocx, ms.glocy, ms.glocz)
+ # ------------------------------------
+ # get normal vector
+ # ------------------------------------
+ if ms.gldefault is True:
+ if ms.gltype == 9:
+ vn = ang_3 # if angle, vector is angle position
+ elif ms.gltype == 11:
+ vn = a_n # if arc, vector is perpendicular to surface of the three vertices
+ else:
+ loc = get_location(myobj)
+ midpoint3d = interpolate3d(a_p1, b_p1, math.fabs(dist / 2))
+ vn = mathutils.Vector((midpoint3d[0] - loc[0],
+ midpoint3d[1] - loc[1],
+ midpoint3d[2] - loc[2]))
+ else:
+ vn = mathutils.Vector((ms.glnormalx, ms.glnormaly, ms.glnormalz))
+
+ vn.normalize()
+ # ------------------------------------
+ # position vector
+ # ------------------------------------
+ vi = vn * ms.glspace
+ s = (14 / 200)
+ if s > ms.glspace:
+ s = ms.glspace / 5
+ vi2 = vn * (ms.glspace + s)
+ # ------------------------------------
+ # apply vector
+ # ------------------------------------
+ v1 = [a_p1[0] + vi[0], a_p1[1] + vi[1], a_p1[2] + vi[2]]
+ v2 = [b_p1[0] + vi[0], b_p1[1] + vi[1], b_p1[2] + vi[2]]
+
+ # Segment extreme
+ v11 = [a_p1[0] + vi2[0], a_p1[1] + vi2[1], a_p1[2] + vi2[2]]
+ v22 = [b_p1[0] + vi2[0], b_p1[1] + vi2[1], b_p1[2] + vi2[2]]
+
+ # Labeling
+ v11a = (a_p1[0] + vi2[0], a_p1[1] + vi2[1], a_p1[2] + vi2[2] + s / 30)
+ v11b = (a_p1[0] + vi2[0], a_p1[1] + vi2[1], a_p1[2] + vi2[2] - s / 40)
+
+ # Annotation
+ vn1 = (a_p1[0], a_p1[1], a_p1[2])
+
+ # -------------------------------------------
+ # Orthogonal
+ # -------------------------------------------
+ if ms.gltype == 1 and ms.glorto != "99":
+ if ms.glorto == "0": # A
+ if ms.glorto_x is True:
+ v1[0] = v2[0]
+ v11[0] = v22[0]
+ if ms.glorto_y is True:
+ v1[1] = v2[1]
+ v11[1] = v22[1]
+ if ms.glorto_z is True:
+ v1[2] = v2[2]
+ v11[2] = v22[2]
+
+ if ms.glorto == "1": # B
+ if ms.glorto_x is True:
+ v2[0] = v1[0]
+ v22[0] = v11[0]
+ if ms.glorto_y is True:
+ v2[1] = v1[1]
+ v22[1] = v11[1]
+ if ms.glorto_z is True:
+ v2[2] = v1[2]
+ v22[2] = v11[2]
+
+ # ------------------------------------
+ # converting to screen coordinates
+ # ------------------------------------
+ screen_point_ap1 = get_2d_point(region, rv3d, a_p1)
+ screen_point_bp1 = get_2d_point(region, rv3d, b_p1)
+
+ screen_point_v1 = get_2d_point(region, rv3d, v1)
+ screen_point_v2 = get_2d_point(region, rv3d, v2)
+ screen_point_v11 = get_2d_point(region, rv3d, v11)
+ screen_point_v22 = get_2d_point(region, rv3d, v22)
+ screen_point_v11a = get_2d_point(region, rv3d, v11a)
+ screen_point_v11b = get_2d_point(region, rv3d, v11b)
+ # ------------------------------------
+ # colour + line setup
+ # ------------------------------------
+ if ovr is False:
+ bgl.glLineWidth(ms.glwidth)
+ else:
+ bgl.glLineWidth(ovrline)
+
+ bgl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3])
+
+ # ------------------------------------
+ # Text (distance)
+ # ------------------------------------
+ # noinspection PyBroadException
+ if ms.gltype != 2 and ms.gltype != 9 and ms.gltype != 10 and ms.gltype != 11 and ms.gltype != 20:
+ # noinspection PyBroadException
+ try:
+ midpoint3d = interpolate3d(v1, v2, math.fabs(dist / 2))
+ gap3d = (midpoint3d[0], midpoint3d[1], midpoint3d[2] + s / 2)
+ txtpoint2d = get_2d_point(region, rv3d, gap3d)
+ # Scale
+ if scene.measureit_scale is True:
+ dist = dist * scene.measureit_scale_factor
+ distloc = distloc * scene.measureit_scale_factor
+
+ # decide dist to use
+ if dist == distloc:
+ locflag = False
+ usedist = dist
+ else:
+ usedist = distloc
+ locflag = True
+ # Apply scene scale
+ usedist *= scale
+ tx_dist = str(format_distance(fmt, units, usedist))
+ # -----------------------------------
+ # Draw text
+ # -----------------------------------
+ if scene.measureit_gl_show_d is True and ms.gldist is True:
+ msg = tx_dist + " "
+ else:
+ msg = " "
+ if scene.measureit_gl_show_n is True and ms.glnames is True:
+ msg += ms.gltxt
+ if scene.measureit_gl_show_d is True or scene.measureit_gl_show_n is True:
+ draw_text(myobj, txtpoint2d[0] + ms.glfontx, txtpoint2d[1] + ms.glfonty,
+ msg, rgb, fsize)
+
+ # ------------------------------
+ # if axis loc, show a indicator
+ # ------------------------------
+ if locflag is True and ms.glocwarning is True:
+ txtpoint2d = get_2d_point(region, rv3d, (v2[0], v2[1], v2[2]))
+ txt = "["
+ if ms.glocx is True:
+ txt += "X"
+ if ms.glocy is True:
+ txt += "Y"
+ if ms.glocz is True:
+ txt += "Z"
+ txt += "]"
+ draw_text(myobj, txtpoint2d[0], txtpoint2d[1], txt, rgb, fsize - 1)
+
+ except:
+ pass
+ # ------------------------------------
+ # Text (label) and Angles
+ # ------------------------------------
+ # noinspection PyBroadException
+ if ms.gltype == 2 or ms.gltype == 9 or ms.gltype == 11:
+ right = False
+ tx_dist = ""
+ # noinspection PyBroadException
+ try:
+ if ms.gltype == 2:
+ tx_dist = ms.gltxt
+ right = False
+ if ms.gltype == 9: # Angles
+ ang = ang_1.angle(ang_2)
+ right = True
+ if bpy.context.scene.unit_settings.system_rotation == "DEGREES":
+ ang = math.degrees(ang)
+
+ tx_dist = " " + fmt % ang
+ # Add degree symbol
+ if bpy.context.scene.unit_settings.system_rotation == "DEGREES":
+ tx_dist += a_code
+
+ if scene.measureit_gl_show_n is True:
+ tx_dist += " " + ms.gltxt
+ if ms.gltype == 11: # arc
+ right = True
+ # print length or arc and angle
+ if ms.glarc_len is True:
+ tx_dist = ms.glarc_txlen + format_distance(fmt, units, arc_length)
+ else:
+ tx_dist = " "
+
+ if bpy.context.scene.unit_settings.system_rotation == "DEGREES":
+ arc_d = math.degrees(arc_angle)
+ else:
+ arc_d = arc_angle
+
+ if ms.glarc_ang is True:
+ tx_dist += " " + ms.glarc_txang + format_distance(fmt, 9, arc_d)
+ # Add degree symbol
+ if bpy.context.scene.unit_settings.system_rotation == "DEGREES":
+ tx_dist += a_code
+
+ if scene.measureit_gl_show_d is True and ms.gldist is True:
+ msg = tx_dist + " "
+ else:
+ msg = " "
+ if scene.measureit_gl_show_n is True and ms.glnames is True:
+ msg += ms.gltxt
+
+ if scene.measureit_gl_show_d is True or scene.measureit_gl_show_n is True:
+ # Normal vector
+ vna = mathutils.Vector((b_p1[0] - a_p1[0],
+ b_p1[1] - a_p1[1],
+ b_p1[2] - a_p1[2]))
+ vna.normalize()
+ via = vna * ms.glspace
+
+ gap3d = (b_p1[0] + via[0], b_p1[1] + via[1], b_p1[2] + via[2])
+ txtpoint2d = get_2d_point(region, rv3d, gap3d)
+ draw_text(myobj, txtpoint2d[0] + ms.glfontx, txtpoint2d[1] + ms.glfonty, msg, rgb,
+ fsize, right)
+ # Radius
+ if scene.measureit_gl_show_d is True and ms.gldist is True and ms.glarc_rad is True:
+ tx_dist = ms.glarc_txradio + format_distance(fmt, units,
+ dist * scene.measureit_scale_factor)
+ else:
+ tx_dist = " "
+ if ms.gltype == 2:
+ gap3d = (v11a[0], v11a[1], v11a[2])
+ else:
+ gap3d = (a_p1[0], a_p1[1], a_p1[2])
+
+ txtpoint2d = get_2d_point(region, rv3d, gap3d)
+ draw_text(myobj, txtpoint2d[0] + ms.glfontx, txtpoint2d[1] + ms.glfonty, tx_dist, rgb,
+ fsize, right)
+ except:
+ pass
+ # ------------------------------------
+ # Annotation
+ # ------------------------------------
+ # noinspection PyBroadException
+ if ms.gltype == 10:
+ # noinspection PyBroadException
+ try:
+ tx_dist = ms.gltxt
+ gap3d = (vn1[0], vn1[1], vn1[2])
+ txtpoint2d = get_2d_point(region, rv3d, gap3d)
+ draw_text(myobj, txtpoint2d[0] + ms.glfontx, txtpoint2d[1] + ms.glfonty,
+ tx_dist, rgb, fsize)
+ except:
+ pass
+ # ------------------------------------
+ # Draw lines
+ # ------------------------------------
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3])
+
+ if ms.gltype == 1: # Segment
+ draw_line(screen_point_ap1, screen_point_v11)
+ draw_line(screen_point_bp1, screen_point_v22)
+ draw_arrow(screen_point_v1, screen_point_v2, a_size, a_type, b_type)
+
+ if ms.gltype == 12 or ms.gltype == 13 or ms.gltype == 14: # Segment to origin
+ draw_line(screen_point_ap1, screen_point_v11)
+ draw_line(screen_point_bp1, screen_point_v22)
+ draw_arrow(screen_point_v1, screen_point_v2, a_size, a_type, b_type)
+
+ if ms.gltype == 2: # Label
+ draw_line(screen_point_v11a, screen_point_v11b)
+ draw_arrow(screen_point_ap1, screen_point_v11, a_size, a_type, b_type)
+
+ if ms.gltype == 3 or ms.gltype == 4 or ms.gltype == 5 or ms.gltype == 8 \
+ or ms.gltype == 6 or ms.gltype == 7: # Origin and Links
+ draw_arrow(screen_point_ap1, screen_point_bp1, a_size, a_type, b_type)
+
+ if ms.gltype == 9: # Angle
+ dist, distloc = distance(an_p1, an_p2)
+ mp1 = interpolate3d(an_p1, an_p2, math.fabs(dist / 1.1))
+
+ dist, distloc = distance(an_p3, an_p2)
+ mp2 = interpolate3d(an_p3, an_p2, math.fabs(dist / 1.1))
+
+ screen_point_an_p1 = get_2d_point(region, rv3d, mp1)
+ screen_point_an_p2 = get_2d_point(region, rv3d, an_p2)
+ screen_point_an_p3 = get_2d_point(region, rv3d, mp2)
+
+ draw_line(screen_point_an_p1, screen_point_an_p2)
+ draw_line(screen_point_an_p2, screen_point_an_p3)
+ draw_line(screen_point_an_p1, screen_point_an_p3)
+
+ if ms.gltype == 11: # arc
+ # draw line from center of arc second point
+ c = mathutils.Vector(a_p1)
+ if ms.glarc_rad is True:
+ if ms.glarc_extrad is False:
+ draw_arrow(screen_point_ap1, screen_point_bp1, a_size, a_type, b_type)
+ else:
+ vne = mathutils.Vector((b_p1[0] - a_p1[0],
+ b_p1[1] - a_p1[1],
+ b_p1[2] - a_p1[2]))
+ vne.normalize()
+ vie = vne * ms.glspace
+ pe = (b_p1[0] + vie[0], b_p1[1] + vie[1], b_p1[2] + vie[2])
+ screen_point_pe = get_2d_point(region, rv3d, pe)
+ draw_arrow(screen_point_ap1, screen_point_pe, a_size, a_type, b_type)
+
+ # create arc around the centerpoint
+ # rotation matrix around normal vector at center point
+ mat_trans1 = mathutils.Matrix.Translation(-c)
+ # get step
+ n_step = 36.0
+ if ms.glarc_full is False:
+ step = arc_angle / n_step
+ else:
+ step = math.radians(360.0) / n_step
+ #
+ mat_rot1 = mathutils.Matrix.Rotation(step, 4, vn)
+ mat_trans2 = mathutils.Matrix.Translation(c)
+ p1 = mathutils.Vector(an_p1) # first point of arc
+ # Normal vector
+ vn = mathutils.Vector((p1[0] - a_p1[0],
+ p1[1] - a_p1[1],
+ p1[2] - a_p1[2]))
+ vn.normalize()
+ vi = vn * ms.glspace
+
+ p_01a = None
+ p_01b = None
+ p_02a = None
+ p_02b = None
+ # draw the arc
+ for i in range(0, int(n_step)):
+ p2 = mat_trans2 * mat_rot1 * mat_trans1 * p1
+ p1_ = (p1[0] + vi[0], p1[1] + vi[1], p1[2] + vi[2])
+ # First Point
+ if i == 0:
+ p_01a = (p1_[0], p1_[1], p1_[2])
+ p_01b = (p1[0], p1[1], p1[2])
+
+ # Normal vector
+ vn = mathutils.Vector((p2[0] - a_p1[0],
+ p2[1] - a_p1[1],
+ p2[2] - a_p1[2]))
+ vn.normalize()
+ vi = vn * ms.glspace
+
+ p2_ = (p2[0] + vi[0], p2[1] + vi[1], p2[2] + vi[2])
+ # convert to screen coordinates
+ screen_point_p1 = get_2d_point(region, rv3d, p1_)
+ screen_point_p2 = get_2d_point(region, rv3d, p2_)
+ if i == 0:
+ draw_arrow(screen_point_p1, screen_point_p2, ms.glarc_s, ms.glarc_a, "99")
+ elif i == int(n_step) - 1:
+ draw_arrow(screen_point_p1, screen_point_p2, ms.glarc_s, "99", ms.glarc_b)
+ else:
+ draw_line(screen_point_p1, screen_point_p2)
+
+ p1 = p2.copy()
+
+ # Last Point
+ if i == int(n_step) - 1:
+ p_02a = (p2_[0], p2_[1], p2_[2])
+ p_02b = (p2[0], p2[1], p2[2])
+
+ # Draw close lines
+ if ms.glarc_full is False:
+ screen_point_p1a = get_2d_point(region, rv3d, p_01a)
+ screen_point_p1b = get_2d_point(region, rv3d, p_01b)
+ screen_point_p2a = get_2d_point(region, rv3d, p_02a)
+ screen_point_p2b = get_2d_point(region, rv3d, p_02b)
+
+ draw_line(screen_point_p1a, screen_point_p1b)
+ draw_line(screen_point_p2a, screen_point_p2b)
+
+ if ms.gltype == 20: # Area
+ obverts = get_mesh_vertices(myobj)
+ tot = 0
+ for face in ms.measureit_faces:
+ myvertices = []
+ for v in face.measureit_index:
+ myvertices.extend([v.glidx])
+
+ area = get_area_and_paint(myvertices, myobj, obverts, region, rv3d)
+ tot += area
+ # Draw Area number over first face
+ if len(ms.measureit_faces) > 0:
+ face = ms.measureit_faces[0]
+ a = face.measureit_index[0].glidx
+ b = face.measureit_index[2].glidx
+
+ p1 = get_point(obverts[a].co, myobj)
+ p2 = get_point(obverts[b].co, myobj)
+
+ d1, dn = distance(p1, p2)
+ midpoint3d = interpolate3d(p1, p2, math.fabs(d1 / 2))
+ txtpoint2d = get_2d_point(region, rv3d, midpoint3d)
+ # Scale
+ if scene.measureit_scale is True:
+ tot = tot * scene.measureit_scale_factor
+
+ # mult by world scale
+ tot *= scale
+ tx_dist = str(format_distance(fmt, units, tot, 2))
+ # -----------------------------------
+ # Draw text
+ # -----------------------------------
+ if scene.measureit_gl_show_d is True and ms.gldist is True:
+ msg = tx_dist + " "
+ else:
+ msg = " "
+ if scene.measureit_gl_show_n is True and ms.glnames is True:
+ msg += ms.gltxt
+ if scene.measureit_gl_show_d is True or scene.measureit_gl_show_n is True:
+ draw_text(myobj, txtpoint2d[0] + ms.glfontx, txtpoint2d[1] + ms.glfonty,
+ msg, ms.glcolorarea,
+ fsize)
+
+ except IndexError:
+ ms.glfree = True
+ except:
+ # print("Unexpected error:" + str(sys.exc_info()))
+ # if error, disable segment
+ pass
+
+ return
+
+
+# ------------------------------------------
+# Get polygon area and paint area
+#
+# ------------------------------------------
+def get_area_and_paint(myvertices, myobj, obverts, region, rv3d):
+ mymesh = myobj.data
+ totarea = 0
+ if len(myvertices) > 3:
+ # Tessellate the polygon
+ if myobj.mode != 'EDIT':
+ tris = mesh_utils.ngon_tessellate(mymesh, myvertices)
+ else:
+ bm = bmesh.from_edit_mesh(myobj.data)
+ myv = []
+ for v in bm.verts:
+ myv.extend([v.co])
+ tris = mesh_utils.ngon_tessellate(myv, myvertices)
+
+ for t in tris:
+ v1, v2, v3 = t
+ p1 = get_point(obverts[myvertices[v1]].co, myobj)
+ p2 = get_point(obverts[myvertices[v2]].co, myobj)
+ p3 = get_point(obverts[myvertices[v3]].co, myobj)
+
+ screen_point_p1 = get_2d_point(region, rv3d, p1)
+ screen_point_p2 = get_2d_point(region, rv3d, p2)
+ screen_point_p3 = get_2d_point(region, rv3d, p3)
+ draw_triangle(screen_point_p1, screen_point_p2, screen_point_p3)
+
+ # Area
+ area = get_triangle_area(p1, p2, p3)
+
+ totarea += area
+ elif len(myvertices) == 3:
+ v1, v2, v3 = myvertices
+ p1 = get_point(obverts[v1].co, myobj)
+ p2 = get_point(obverts[v2].co, myobj)
+ p3 = get_point(obverts[v3].co, myobj)
+
+ screen_point_p1 = get_2d_point(region, rv3d, p1)
+ screen_point_p2 = get_2d_point(region, rv3d, p2)
+ screen_point_p3 = get_2d_point(region, rv3d, p3)
+ draw_triangle(screen_point_p1, screen_point_p2, screen_point_p3)
+
+ # Area
+ area = get_triangle_area(p1, p2, p3)
+ totarea += area
+ else:
+ return 0.0
+
+ return totarea
+
+
+# ------------------------------------------
+# Get area using Heron formula
+#
+# ------------------------------------------
+def get_triangle_area(p1, p2, p3):
+ d1, dn = distance(p1, p2)
+ d2, dn = distance(p2, p3)
+ d3, dn = distance(p1, p3)
+ per = (d1 + d2 + d3) / 2.0
+ area = math.sqrt(per * (per - d1) * (per - d2) * (per - d3))
+ return area
+
+
+# ------------------------------------------
+# Get point in 2d space
+#
+# ------------------------------------------
+def get_2d_point(region, rv3d, point3d):
+ if rv3d is not None and region is not None:
+ return view3d_utils.location_3d_to_region_2d(region, rv3d, point3d)
+ else:
+ return get_render_location(point3d)
+
+
+# -------------------------------------------------------------
+# Get sum of a group
+#
+# myobj: Current object
+# Tag: group
+# -------------------------------------------------------------
+def get_group_sum(myobj, tag):
+ # noinspection PyBroadException
+ try:
+ 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"]
+ g = tag[2:3]
+ mp = myobj.MeasureGenerator[0]
+ flag = False
+ # -----------------
+ # Sum loop segments
+ # -----------------
+ scale = bpy.context.scene.unit_settings.scale_length
+ tot = 0.0
+ obverts = get_mesh_vertices(myobj)
+ 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 and g == tx[int(ms.gltot)]: # 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 += usedist
+ flag = True
+
+ if flag is True:
+ # Return value
+ pr = bpy.context.scene.measureit_gl_precision
+ fmt = "%1." + str(pr) + "f"
+ units = bpy.context.scene.measureit_units
+
+ return format_distance(fmt, units, tot)
+ else:
+ return " "
+ except:
+ return " "
+
+
+# -------------------------------------------------------------
+# Create OpenGL text
+#
+# right: Align to right
+# -------------------------------------------------------------
+def draw_text(myobj, x_pos, y_pos, display_text, rgb, fsize, right=False):
+ gap = 12
+ font_id = 0
+ blf.size(font_id, fsize, 72)
+ # height of one line
+ mwidth, mheight = blf.dimensions(font_id, "Tp") # uses high/low letters
+
+ # Calculate sum groups
+ m = 0
+ while "<#" in display_text:
+ m += 1
+ if m > 10: # limit loop
+ break
+ i = display_text.index("<#")
+ tag = display_text[i:i + 4]
+ display_text = display_text.replace(tag, get_group_sum(myobj, tag.upper()))
+
+ # split lines
+ mylines = display_text.split("|")
+ idx = len(mylines) - 1
+ maxwidth = 0
+ maxheight = len(mylines) * mheight
+ # -------------------
+ # Draw all lines
+ # -------------------
+ for line in mylines:
+ text_width, text_height = blf.dimensions(font_id, line)
+ if right is True:
+ newx = x_pos - text_width - gap
+ else:
+ newx = x_pos
+ # calculate new Y position
+ new_y = y_pos + (mheight * idx)
+ # Draw
+ blf.position(font_id, newx, new_y, 0)
+ bgl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3])
+ blf.draw(font_id, " " + line)
+ # sub line
+ idx -= 1
+ # saves max width
+ if maxwidth < text_width:
+ maxwidth = text_width
+
+ return maxwidth, maxheight
+
+
+# -------------------------------------------------------------
+# Draw an OpenGL line
+#
+# -------------------------------------------------------------
+def draw_line(v1, v2):
+ # noinspection PyBroadException
+ try:
+ if v1 is not None and v2 is not None:
+ bgl.glBegin(bgl.GL_LINES)
+ bgl.glVertex2f(*v1)
+ bgl.glVertex2f(*v2)
+ bgl.glEnd()
+ except:
+ pass
+
+
+# -------------------------------------------------------------
+# Draw an OpenGL triangle
+#
+# -------------------------------------------------------------
+def draw_triangle(v1, v2, v3):
+ # noinspection PyBroadException
+ try:
+ if v1 is not None and v2 is not None and v3 is not None:
+ bgl.glBegin(bgl.GL_TRIANGLES)
+ bgl.glVertex2f(*v1)
+ bgl.glVertex2f(*v2)
+ bgl.glVertex2f(*v3)
+ bgl.glEnd()
+ except:
+ pass
+
+
+# -------------------------------------------------------------
+# Draw an Arrow
+#
+# -------------------------------------------------------------
+def draw_arrow(v1, v2, size=20, a_typ="1", b_typ="1"):
+
+ rad45 = math.radians(45)
+ rad315 = math.radians(315)
+ rad90 = math.radians(90)
+ rad270 = math.radians(270)
+
+ v = interpolate3d((v1[0], v1[1], 0.0), (v2[0], v2[1], 0.0), size)
+
+ v1i = (v[0] - v1[0], v[1] - v1[1])
+
+ v = interpolate3d((v2[0], v2[1], 0.0), (v1[0], v1[1], 0.0), size)
+ v2i = (v[0] - v2[0], v[1] - v2[1])
+
+ # Point A
+ if a_typ == "3":
+ rad_a = rad90
+ rad_b = rad270
+ else:
+ rad_a = rad45
+ rad_b = rad315
+
+ v1a = (int(v1i[0] * math.cos(rad_a) - v1i[1] * math.sin(rad_a) + v1[0]),
+ int(v1i[1] * math.cos(rad_a) + v1i[0] * math.sin(rad_a)) + v1[1])
+ v1b = (int(v1i[0] * math.cos(rad_b) - v1i[1] * math.sin(rad_b) + v1[0]),
+ int(v1i[1] * math.cos(rad_b) + v1i[0] * math.sin(rad_b) + v1[1]))
+
+ # Point B
+ if b_typ == "3":
+ rad_a = rad90
+ rad_b = rad270
+ else:
+ rad_a = rad45
+ rad_b = rad315
+
+ v2a = (int(v2i[0] * math.cos(rad_a) - v2i[1] * math.sin(rad_a) + v2[0]),
+ int(v2i[1] * math.cos(rad_a) + v2i[0] * math.sin(rad_a)) + v2[1])
+ v2b = (int(v2i[0] * math.cos(rad_b) - v2i[1] * math.sin(rad_b) + v2[0]),
+ int(v2i[1] * math.cos(rad_b) + v2i[0] * math.sin(rad_b) + v2[1]))
+
+ # Triangle o Lines
+ if a_typ == "1" or a_typ == "3":
+ draw_line(v1, v1a)
+ draw_line(v1, v1b)
+
+ if b_typ == "1" or b_typ == "3":
+ draw_line(v2, v2a)
+ draw_line(v2, v2b)
+
+ if a_typ == "2":
+ draw_triangle(v1, v1a, v1b)
+ if b_typ == "2":
+ draw_triangle(v2, v2a, v2b)
+
+ draw_line(v1, v2)
+
+
+# -------------------------------------------------------------
+# Draw an OpenGL Rectangle
+#
+# v1, v2 are corners (bottom left / top right)
+# -------------------------------------------------------------
+def draw_rectangle(v1, v2):
+ # noinspection PyBroadException
+ try:
+ if v1 is not None and v2 is not None:
+ v1b = (v2[0], v1[1])
+ v2b = (v1[0], v2[1])
+ draw_line(v1, v1b)
+ draw_line(v1b, v2)
+ draw_line(v2, v2b)
+ draw_line(v2b, v1)
+ except:
+ pass
+
+
+# -------------------------------------------------------------
+# format a point as (x, y, z) for display
+#
+# -------------------------------------------------------------
+def format_point(mypoint, pr):
+ pf = "%1." + str(pr) + "f"
+ fmt = " ("
+ fmt += pf % mypoint[0]
+ fmt += ", "
+ fmt += pf % mypoint[1]
+ fmt += ", "
+ fmt += pf % mypoint[2]
+ fmt += ")"
+
+ return fmt
+
+
+# -------------------------------------------------------------
+# Draw vertex num for debug
+#
+# -------------------------------------------------------------
+# noinspection PyUnresolvedReferences,PyUnboundLocalVariable,PyUnusedLocal
+def draw_vertices(context, myobj, region, rv3d):
+ # Only meshes
+ if myobj.type != "MESH":
+ return
+
+ scene = bpy.context.scene
+ rgb = scene.measureit_debug_color
+ fsize = scene.measureit_debug_font
+ precision = scene.measureit_debug_precision
+ # --------------------
+ # vertex Loop
+ # --------------------
+ if myobj.mode == 'EDIT':
+ bm = bmesh.from_edit_mesh(myobj.data)
+ obverts = bm.verts
+ else:
+ obverts = myobj.data.vertices
+
+ for v in obverts:
+ # Display only selected
+ if scene.measureit_debug_select is True:
+ if v.select is False:
+ continue
+ # noinspection PyBroadException
+ try:
+ a_p1 = get_point(v.co, myobj)
+ # colour
+ bgl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3])
+ # converting to screen coordinates
+ txtpoint2d = get_2d_point(region, rv3d, a_p1)
+ # Text
+ txt = str(v.index)
+ if scene.measureit_debug_location is True:
+ txt += format_point(v.co, precision)
+ draw_text(myobj, txtpoint2d[0], txtpoint2d[1], txt, rgb, fsize)
+ except:
+ print("Unexpected error:" + str(sys.exc_info()))
+ pass
+
+ return
+
+
+# -------------------------------------------------------------
+# Draw face num for debug
+#
+# -------------------------------------------------------------
+# noinspection PyUnresolvedReferences,PyUnboundLocalVariable,PyUnusedLocal
+def draw_faces(context, myobj, region, rv3d):
+ # Only meshes
+ if myobj.type != "MESH":
+ return
+
+ scene = bpy.context.scene
+ rgb = scene.measureit_debug_color2
+ rgb2 = scene.measureit_debug_color3
+ fsize = scene.measureit_debug_font
+ ln = scene.measureit_debug_normal_size
+ th = scene.measureit_debug_width
+ precision = scene.measureit_debug_precision
+
+ # --------------------
+ # face Loop
+ # --------------------
+ if myobj.mode == 'EDIT':
+ bm = bmesh.from_edit_mesh(myobj.data)
+ obverts = bm.verts
+ myfaces = bm.faces
+ else:
+ obverts = myobj.data.vertices
+ myfaces = myobj.data.polygons
+
+ for f in myfaces:
+ normal = f.normal
+ # Display only selected
+ if scene.measureit_debug_select is True:
+ if f.select is False:
+ continue
+ # noinspection PyBroadException
+ try:
+ if myobj.mode == 'EDIT':
+ a_p1 = get_point(f.calc_center_median(), myobj)
+ else:
+ a_p1 = get_point(f.center, myobj)
+
+ a_p2 = (a_p1[0] + normal[0] * ln, a_p1[1] + normal[1] * ln, a_p1[2] + normal[2] * ln)
+ # colour + line setup
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glLineWidth(th)
+ bgl.glColor4f(rgb[0], rgb[1], rgb[2], rgb[3])
+ # converting to screen coordinates
+ txtpoint2d = get_2d_point(region, rv3d, a_p1)
+ point2 = get_2d_point(region, rv3d, a_p2)
+ # Text
+ if scene.measureit_debug_faces is True:
+ draw_text(myobj, txtpoint2d[0], txtpoint2d[1], str(f.index), rgb, fsize)
+ # Draw Normal
+ if scene.measureit_debug_normals is True:
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glColor4f(rgb2[0], rgb2[1], rgb2[2], rgb2[3])
+ draw_arrow(txtpoint2d, point2, 10, "99", "1")
+
+ if len(obverts) > 2 and scene.measureit_debug_normal_details is True:
+ if myobj.mode == 'EDIT':
+ i1 = f.verts[0].index
+ i2 = f.verts[1].index
+ i3 = f.verts[2].index
+ else:
+ i1 = f.vertices[0]
+ i2 = f.vertices[1]
+ i3 = f.vertices[2]
+
+ a_p1 = get_point(obverts[i1].co, myobj)
+ a_p2 = get_point(obverts[i2].co, myobj)
+ a_p3 = get_point(obverts[i3].co, myobj)
+ # converting to screen coordinates
+ a2d = get_2d_point(region, rv3d, a_p1)
+ b2d = get_2d_point(region, rv3d, a_p2)
+ c2d = get_2d_point(region, rv3d, a_p3)
+ # draw vectors
+ draw_arrow(a2d, b2d, 10, "99", "1")
+ draw_arrow(b2d, c2d, 10, "99", "1")
+ # Normal vector data
+ txt = format_point(normal, precision)
+ draw_text(myobj, point2[0], point2[1], txt, rgb2, fsize)
+
+ except:
+ print("Unexpected error:" + str(sys.exc_info()))
+ pass
+
+ return
+
+
+# --------------------------------------------------------------------
+# Distance between 2 points in 3D space
+# v1: first point
+# v2: second point
+# locx/y/z: Use this axis
+# return: distance
+# --------------------------------------------------------------------
+def distance(v1, v2, locx=True, locy=True, locz=True):
+ x = math.sqrt((v2[0] - v1[0]) ** 2 + (v2[1] - v1[1]) ** 2 + (v2[2] - v1[2]) ** 2)
+
+ # If axis is not used, make equal both (no distance)
+ v1b = [v1[0], v1[1], v1[2]]
+ v2b = [v2[0], v2[1], v2[2]]
+ if locx is False:
+ v2b[0] = v1b[0]
+ if locy is False:
+ v2b[1] = v1b[1]
+ if locz is False:
+ v2b[2] = v1b[2]
+
+ xloc = math.sqrt((v2b[0] - v1b[0]) ** 2 + (v2b[1] - v1b[1]) ** 2 + (v2b[2] - v1b[2]) ** 2)
+
+ return x, xloc
+
+
+# --------------------------------------------------------------------
+# Interpolate 2 points in 3D space
+# v1: first point
+# v2: second point
+# d1: distance
+# return: interpolate point
+# --------------------------------------------------------------------
+def interpolate3d(v1, v2, d1):
+ # calculate vector
+ v = (v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2])
+ # calculate distance between points
+ d0, dloc = distance(v1, v2)
+
+ # calculate interpolate factor (distance from origin / distance total)
+ # if d1 > d0, the point is projected in 3D space
+ if d0 > 0:
+ x = d1 / d0
+ else:
+ x = d1
+
+ final = (v1[0] + (v[0] * x), v1[1] + (v[1] * x), v1[2] + (v[2] * x))
+ return final
+
+
+# --------------------------------------------------------------------
+# Get point rotated and relative to parent
+# v1: point
+# mainobject
+# --------------------------------------------------------------------
+def get_point(v1, mainobject):
+ # Using World Matrix
+ vt = mathutils.Vector((v1[0], v1[1], v1[2], 1))
+ m4 = mainobject.matrix_world
+ vt2 = m4 * vt
+ v2 = [vt2[0], vt2[1], vt2[2]]
+
+ return v2
+
+
+# --------------------------------------------------------------------
+# Get location in world space
+# v1: point
+# mainobject
+# --------------------------------------------------------------------
+def get_location(mainobject):
+ # Using World Matrix
+ m4 = mainobject.matrix_world
+
+ return [m4[0][3], m4[1][3], m4[2][3]]
+
+
+# --------------------------------------------------------------------
+# Get vertex data
+# mainobject
+# --------------------------------------------------------------------
+def get_mesh_vertices(myobj):
+ try:
+ if myobj.mode == 'EDIT':
+ bm = bmesh.from_edit_mesh(myobj.data)
+ obverts = bm.verts
+ else:
+ obverts = myobj.data.vertices
+
+ return obverts
+ except AttributeError:
+ return None
+
+
+# --------------------------------------------------------------------
+# Get position for scale text
+#
+# --------------------------------------------------------------------
+def get_scale_txt_location(context):
+ scene = context.scene
+ pos_x = int(context.region.width * scene.measureit_scale_pos_x / 100)
+ pos_y = int(context.region.height * scene.measureit_scale_pos_y / 100)
+
+ return pos_x, pos_y
+
+
+# --------------------------------------------------------------------
+# Get position in final render image
+# (Z < 0 out of camera)
+# return 2d position
+# --------------------------------------------------------------------
+def get_render_location(mypoint):
+
+ v1 = mathutils.Vector(mypoint)
+ scene = bpy.context.scene
+ co_2d = object_utils.world_to_camera_view(scene, scene.camera, v1)
+ # Get pixel coords
+ render_scale = scene.render.resolution_percentage / 100
+ render_size = (int(scene.render.resolution_x * render_scale),
+ int(scene.render.resolution_y * render_scale))
+
+ return [round(co_2d.x * render_size[0]), round(co_2d.y * render_size[1])]
+
+
+# ---------------------------------------------------------
+# Get center of circle base on 3 points
+#
+# Point a: (x,y,z) arc start
+# Point b: (x,y,z) center
+# Point c: (x,y,z) midle point in the arc
+# Point d: (x,y,z) arc end
+# Return:
+# ang: angle (radians)
+# len: len of arc
+#
+# ---------------------------------------------------------
+def get_arc_data(pointa, pointb, pointc, pointd):
+ v1 = mathutils.Vector((pointa[0] - pointb[0], pointa[1] - pointb[1], pointa[2] - pointb[2]))
+ v2 = mathutils.Vector((pointc[0] - pointb[0], pointc[1] - pointb[1], pointc[2] - pointb[2]))
+ v3 = mathutils.Vector((pointd[0] - pointb[0], pointd[1] - pointb[1], pointd[2] - pointb[2]))
+
+ angle = v1.angle(v2) + v2.angle(v3)
+
+ rclength = math.pi * 2 * v2.length * (angle / (math.pi * 2))
+
+ return angle, rclength
+
+
+# -------------------------------------------------------------
+# Format a number to the right unit
+#
+# -------------------------------------------------------------
+def format_distance(fmt, units, value, factor=1):
+ s_code = "\u00b2" # Superscript two
+ # ------------------------
+ # Units automatic
+ # ------------------------
+ if units == "1":
+ # Units
+ if bpy.context.scene.unit_settings.system == "IMPERIAL":
+ feet = value * (3.2808399 ** factor)
+ if round(feet, 2) >= 1.0:
+ fmt += " ft"
+ if factor == 2:
+ fmt += s_code
+ tx_dist = fmt % feet
+ else:
+ inches = value * (39.3700787 ** factor)
+ fmt += " in"
+ if factor == 2:
+ fmt += s_code
+ tx_dist = fmt % inches
+ elif bpy.context.scene.unit_settings.system == "METRIC":
+ if round(value, 2) >= 1.0:
+ fmt += " m"
+ if factor == 2:
+ fmt += s_code
+ tx_dist = fmt % value
+ else:
+ if round(value, 2) >= 0.01:
+ fmt += " cm"
+ if factor == 2:
+ fmt += s_code
+ d_cm = value * (100 ** factor)
+ tx_dist = fmt % d_cm
+ else:
+ fmt += " mm"
+ if factor == 2:
+ fmt += s_code
+ d_mm = value * (1000 ** factor)
+ tx_dist = fmt % d_mm
+ else:
+ tx_dist = fmt % value
+ # ------------------------
+ # Units meters
+ # ------------------------
+ elif units == "2":
+ fmt += " m"
+ if factor == 2:
+ fmt += s_code
+ tx_dist = fmt % value
+ # ------------------------
+ # Units centimeters
+ # ------------------------
+ elif units == "3":
+ fmt += " cm"
+ if factor == 2:
+ fmt += s_code
+ d_cm = value * (100 ** factor)
+ tx_dist = fmt % d_cm
+ # ------------------------
+ # Units milimiters
+ # ------------------------
+ elif units == "4":
+ fmt += " mm"
+ if factor == 2:
+ fmt += s_code
+ d_mm = value * (1000 ** factor)
+ tx_dist = fmt % d_mm
+ # ------------------------
+ # Units feet
+ # ------------------------
+ elif units == "5":
+ fmt += " ft"
+ if factor == 2:
+ fmt += s_code
+ feet = value * (3.2808399 ** factor)
+ tx_dist = fmt % feet
+ # ------------------------
+ # Units inches
+ # ------------------------
+ elif units == "6":
+ fmt += " in"
+ if factor == 2:
+ fmt += s_code
+ inches = value * (39.3700787 ** factor)
+ tx_dist = fmt % inches
+ # ------------------------
+ # Default
+ # ------------------------
+ else:
+ tx_dist = fmt % value
+
+ return tx_dist
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
diff --git a/measureit/measureit_render.py b/measureit/measureit_render.py
new file mode 100644
index 00000000..6c9733df
--- /dev/null
+++ b/measureit/measureit_render.py
@@ -0,0 +1,343 @@
+# ##### 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>
+
+# ----------------------------------------------------------
+# support routines for render measures in final image
+# Author: Antonio Vazquez (antonioya)
+#
+# ----------------------------------------------------------
+# noinspection PyUnresolvedReferences
+import bpy
+# noinspection PyUnresolvedReferences
+import bgl
+# noinspection PyUnresolvedReferences
+import blf
+# noinspection PyUnresolvedReferences
+import mathutils
+# noinspection PyUnresolvedReferences
+import bmesh
+import os
+import sys
+# noinspection PyUnresolvedReferences
+import bpy_extras.image_utils as img_utils
+# noinspection PyUnresolvedReferences
+import bpy_extras.object_utils as object_utils
+# noinspection PyUnresolvedReferences
+from bpy_extras import view3d_utils
+from math import ceil
+from measureit_geometry import *
+
+
+# -------------------------------------------------------------
+# Render image main entry point
+#
+# -------------------------------------------------------------
+def render_main(self, context, animation=False):
+ # noinspection PyBroadException,PyBroadException
+ # Save old info
+ settings = bpy.context.scene.render.image_settings
+ depth = settings.color_depth
+ settings.color_depth = '8'
+ # noinspection PyBroadException
+ try:
+ # Get visible layers
+ layers = []
+ scene = context.scene
+ for x in range(0, 20):
+ if scene.layers[x] is True:
+ layers.extend([x])
+
+ # Get object list
+ objlist = context.scene.objects
+ # --------------------
+ # Get resolution
+ # --------------------
+ scene = bpy.context.scene
+ render_scale = scene.render.resolution_percentage / 100
+
+ width = int(scene.render.resolution_x * render_scale)
+ height = int(scene.render.resolution_y * render_scale)
+ # ---------------------------------------
+ # Get output path
+ # ---------------------------------------
+ ren_path = bpy.context.scene.render.filepath
+ if len(ren_path) > 0:
+ if ren_path.endswith(os.path.sep):
+ initpath = os.path.realpath(ren_path) + os.path.sep
+ else:
+ (initpath, filename) = os.path.split(ren_path)
+ outpath = os.path.join(initpath, "measureit_tmp_render.png")
+ else:
+ self.report({'ERROR'},
+ "MeasureIt: Unable to save temporary render image. Define a valid render path")
+ settings.color_depth = depth
+ return False
+
+ # Get Render Image
+ img = get_render_image(outpath)
+ if img is None:
+ self.report({'ERROR'},
+ "MeasureIt: Unable to save temporary render image. Define a valid render path")
+ settings.color_depth = depth
+ return False
+
+ # -----------------------------
+ # Calculate rows and columns
+ # -----------------------------
+ tile_x = 240
+ tile_y = 216
+ row_num = ceil(height / tile_y)
+ col_num = ceil(width / tile_x)
+ print("MeasureIt: Image divided in " + str(row_num) + "x" + str(col_num) + " tiles")
+
+ # pixels out of visible area
+ cut4 = (col_num * tile_x * 4) - width * 4 # pixels aout of drawing area
+ totpixel4 = width * height * 4 # total pixels RGBA
+
+ viewport_info = bgl.Buffer(bgl.GL_INT, 4)
+ bgl.glGetIntegerv(bgl.GL_VIEWPORT, viewport_info)
+
+ # Load image on memory
+ img.gl_load(0, bgl.GL_NEAREST, bgl.GL_NEAREST)
+
+ # 2.77 API change
+ if bpy.app.version >= (2, 77, 0):
+ tex = img.bindcode[0]
+ else:
+ tex = img.bindcode
+
+ # --------------------------------------------
+ # Create output image (to apply texture)
+ # --------------------------------------------
+ if "measureit_output" in bpy.data.images:
+ out_img = bpy.data.images["measureit_output"]
+ if out_img is not None:
+ out_img.user_clear()
+ bpy.data.images.remove(out_img)
+
+ out = bpy.data.images.new("measureit_output", width, height)
+ tmp_pixels = [1] * totpixel4
+
+ # --------------------------------
+ # Loop for all tiles
+ # --------------------------------
+ for row in range(0, row_num):
+ for col in range(0, col_num):
+ buffer = bgl.Buffer(bgl.GL_FLOAT, width * height * 4)
+ bgl.glDisable(bgl.GL_SCISSOR_TEST) # if remove this line, get blender screenshot not image
+ bgl.glViewport(0, 0, tile_x, tile_y)
+
+ bgl.glMatrixMode(bgl.GL_PROJECTION)
+ bgl.glLoadIdentity()
+
+ # defines ortographic view for single tile
+ x1 = tile_x * col
+ y1 = tile_y * row
+ bgl.gluOrtho2D(x1, x1 + tile_x, y1, y1 + tile_y)
+
+ # Clear
+ bgl.glClearColor(0.0, 0.0, 0.0, 0.0)
+ bgl.glClear(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT)
+
+ bgl.glEnable(bgl.GL_TEXTURE_2D)
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, tex)
+
+ # defines drawing area
+ bgl.glBegin(bgl.GL_QUADS)
+
+ bgl.glColor3f(1.0, 1.0, 1.0)
+ bgl.glTexCoord2f(0.0, 0.0)
+ bgl.glVertex2f(0.0, 0.0)
+
+ bgl.glTexCoord2f(1.0, 0.0)
+ bgl.glVertex2f(width, 0.0)
+
+ bgl.glTexCoord2f(1.0, 1.0)
+ bgl.glVertex2f(width, height)
+
+ bgl.glTexCoord2f(0.0, 1.0)
+ bgl.glVertex2f(0.0, height)
+
+ bgl.glEnd()
+
+ # -----------------------------
+ # Loop to draw all lines
+ # -----------------------------
+ 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, None, None)
+ break
+
+ # -----------------------------
+ # Loop to draw all 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, None, None)
+ if scene.measureit_debug_faces is True or scene.measureit_debug_normals is True:
+ draw_faces(context, myobj, None, None)
+
+ if scene.measureit_rf is True:
+ bgl.glColor3f(1.0, 1.0, 1.0)
+ rfcolor = scene.measureit_rf_color
+ rfborder = scene.measureit_rf_border
+ rfline = scene.measureit_rf_line
+
+ bgl.glLineWidth(rfline)
+ bgl.glColor4f(rfcolor[0], rfcolor[1], rfcolor[2], rfcolor[3])
+
+ x1 = rfborder
+ x2 = width - rfborder
+ y1 = int(math.ceil(rfborder / (width / height)))
+ y2 = height - y1
+ draw_rectangle((x1, y1), (x2, y2))
+
+ # --------------------------------
+ # copy pixels to temporary area
+ # --------------------------------
+ bgl.glFinish()
+ bgl.glReadPixels(0, 0, width, height, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) # read image data
+ for y in range(0, tile_y):
+ # final image pixels position
+ p1 = (y * width * 4) + (row * tile_y * width * 4) + (col * tile_x * 4)
+ p2 = p1 + (tile_x * 4)
+ # buffer pixels position
+ b1 = y * width * 4
+ b2 = b1 + (tile_x * 4)
+
+ if p1 < totpixel4: # avoid pixel row out of area
+ if col == col_num - 1: # avoid pixel columns out of area
+ p2 -= cut4
+ b2 -= cut4
+
+ tmp_pixels[p1:p2] = buffer[b1:b2]
+
+ # -----------------------
+ # Copy temporary to final
+ # -----------------------
+ out.pixels = tmp_pixels[:] # Assign image data
+ img.gl_free() # free opengl image memory
+
+ # delete image
+ img.user_clear()
+ bpy.data.images.remove(img)
+ # remove temp file
+ os.remove(outpath)
+ # reset
+ bgl.glEnable(bgl.GL_SCISSOR_TEST)
+ # -----------------------
+ # restore opengl defaults
+ # -----------------------
+ bgl.glLineWidth(1)
+ bgl.glDisable(bgl.GL_BLEND)
+ bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
+ # Saves image
+ if out is not None and (scene.measureit_render is True or animation is True):
+ ren_path = bpy.context.scene.render.filepath
+ filename = "mit_frame"
+ if len(ren_path) > 0:
+ if ren_path.endswith(os.path.sep):
+ initpath = os.path.realpath(ren_path) + os.path.sep
+ else:
+ (initpath, filename) = os.path.split(ren_path)
+
+ ftxt = "%04d" % scene.frame_current
+ outpath = os.path.join(initpath, filename + ftxt + ".png")
+
+ save_image(self, outpath, out)
+
+ settings.color_depth = depth
+ return True
+
+ except:
+ settings.color_depth = depth
+ print("Unexpected error:" + str(sys.exc_info()))
+ self.report({'ERROR'}, "MeasureIt: Unable to create render image")
+ return False
+
+
+# --------------------------------------------------------------------
+# Get the final render image and return as image object
+#
+# return None if no render available
+# --------------------------------------------------------------------
+def get_render_image(outpath):
+ saved = False
+ # noinspection PyBroadException
+ try:
+ # noinspection PyBroadException
+ try:
+ result = bpy.data.images['Render Result']
+ if result.has_data is False:
+ # this save produce to fill data image
+ result.save_render(outpath)
+ saved = True
+ except:
+ print("No render image found")
+ return None
+
+ # Save and reload
+ if saved is False:
+ result.save_render(outpath)
+
+ img = img_utils.load_image(outpath)
+
+ return img
+ except:
+ print("Unexpected render image error")
+ return None
+
+
+# -------------------------------------
+# Save image to file
+# -------------------------------------
+def save_image(self, filepath, myimage):
+ # noinspection PyBroadException
+ try:
+
+ # Save old info
+ settings = bpy.context.scene.render.image_settings
+ myformat = settings.file_format
+ mode = settings.color_mode
+ depth = settings.color_depth
+
+ # Apply new info and save
+ settings.file_format = 'PNG'
+ settings.color_mode = "RGBA"
+ settings.color_depth = '8'
+ myimage.save_render(filepath)
+ print("MeasureIt: Image " + filepath + " saved")
+
+ # Restore old info
+ settings.file_format = myformat
+ settings.color_mode = mode
+ settings.color_depth = depth
+ except:
+ print("Unexpected error:" + str(sys.exc_info()))
+ self.report({'ERROR'}, "MeasureIt: Unable to save render image")
+ return