1 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ----------------------------------------------------------
6 # File: measureit_main.py
7 # Main panel for different Measureit general actions
8 # Author: Antonio Vazquez (antonioya)
10 # ----------------------------------------------------------
11 # noinspection PyUnresolvedReferences
14 from bmesh
import from_edit_mesh
15 # noinspection PyUnresolvedReferences
17 from bpy
.types
import PropertyGroup
, Panel
, Object
, Operator
, SpaceView3D
18 from bpy
.props
import IntProperty
, CollectionProperty
, FloatVectorProperty
, BoolProperty
, StringProperty
, \
19 FloatProperty
, EnumProperty
20 from bpy
.app
.handlers
import persistent
21 # noinspection PyUnresolvedReferences
22 from .measureit_geometry
import *
23 from .measureit_render
import *
26 # ------------------------------------------------------
27 # Handler to detect new Blend load
29 # ------------------------------------------------------
30 # noinspection PyUnusedLocal
32 def load_handler(dummy
):
33 MEASUREIT_OT_RunHintDisplay
.handle_remove(None, bpy
.context
)
36 # ------------------------------------------------------
37 # Handler to detect save Blend
38 # Clear not used measured
40 # ------------------------------------------------------
41 # noinspection PyUnusedLocal
43 def save_handler(dummy
):
44 # noinspection PyBroadException
46 print("MeasureIt: Cleaning data")
47 objlist
= bpy
.context
.scene
.objects
49 if 'MeasureGenerator' in myobj
:
50 mp
= myobj
.MeasureGenerator
[0]
52 for ms
in mp
.measureit_segments
:
53 ms
.name
= "segment_" + str(x
)
56 idx
= mp
.measureit_segments
.find(ms
.name
)
58 print("MeasureIt: Removed segment not used")
59 mp
.measureit_segments
.remove(idx
)
62 mp
.measureit_num
= len(mp
.measureit_segments
)
67 bpy
.app
.handlers
.load_post
.append(load_handler
)
68 bpy
.app
.handlers
.save_pre
.append(save_handler
)
71 # ------------------------------------------------------------------
72 # Define property group class for measureit faces index
73 # ------------------------------------------------------------------
74 class MeasureitIndex(PropertyGroup
):
75 glidx
: IntProperty(name
="index", description
="vertex index")
79 bpy
.utils
.register_class(MeasureitIndex
)
82 # ------------------------------------------------------------------
83 # Define property group class for measureit faces
84 # ------------------------------------------------------------------
85 class MeasureitFaces(PropertyGroup
):
86 glface
: IntProperty(name
="glface", description
="Face number")
88 measureit_index
: CollectionProperty(type=MeasureitIndex
)
92 bpy
.utils
.register_class(MeasureitFaces
)
95 # ------------------------------------------------------------------
96 # Define property group class for measureit data
97 # ------------------------------------------------------------------
98 class MeasureitProperties(PropertyGroup
):
99 gltype
: IntProperty(name
="gltype",
100 description
="Measure type (1-Segment, 2-Label, etc..)", default
=1)
101 glpointa
: IntProperty(name
="glpointa",
102 description
="Hidden property for opengl")
103 glpointb
: IntProperty(name
="glpointb",
104 description
="Hidden property for opengl")
105 glpointc
: IntProperty(name
="glpointc",
106 description
="Hidden property for opengl")
107 glcolor
: FloatVectorProperty(name
="glcolor",
108 description
="Color for the measure",
109 default
=(0.173, 0.545, 1.0, 1.0),
114 glview
: BoolProperty(name
="glview",
115 description
="Measure visible/hide",
117 glspace
: FloatProperty(name
='glspace', min=-100, max=100, default
=0.1,
119 description
='Distance to display measure')
120 glwidth
: IntProperty(name
='glwidth', min=1, max=10, default
=1,
121 description
='line width')
122 glfree
: BoolProperty(name
="glfree",
123 description
="This measure is free and can be deleted",
125 gltxt
: StringProperty(name
="gltxt", maxlen
=256,
126 description
="Short description (use | for line break)")
127 gladvance
: BoolProperty(name
="gladvance",
128 description
="Advanced options as line width or position",
130 gldefault
: BoolProperty(name
="gldefault",
131 description
="Display measure in position calculated by default",
133 glnormalx
: FloatProperty(name
="glnormalx",
134 description
="Change orientation in X axis",
135 default
=1, min=-1, max=1, precision
=2)
136 glnormaly
: FloatProperty(name
="glnormaly",
137 description
="Change orientation in Y axis",
138 default
=0, min=-1, max=1, precision
=2)
139 glnormalz
: FloatProperty(name
="glnormalz",
140 description
="Change orientation in Z axis",
141 default
=0, min=-1, max=1, precision
=2)
142 glfont_size
: IntProperty(name
="Text Size",
143 description
="Text size",
144 default
=14, min=6, max=150)
145 glfont_align
: EnumProperty(items
=(('L', "Left Align", ""),
146 ('C', "Center Align", ""),
147 ('R', "Right Align", "")),
149 description
="Set Font Alignment")
150 glfont_rotat
: IntProperty(name
='Rotate', min=0, max=360, default
=0,
151 description
="Text rotation in degrees")
152 gllink
: StringProperty(name
="gllink",
153 description
="linked object for linked measures")
154 glocwarning
: BoolProperty(name
="glocwarning",
155 description
="Display a warning if some axis is not used in distance",
157 glocx
: BoolProperty(name
="glocx",
158 description
="Include changes in X axis for calculating the distance",
160 glocy
: BoolProperty(name
="glocy",
161 description
="Include changes in Y axis for calculating the distance",
163 glocz
: BoolProperty(name
="glocz",
164 description
="Include changes in Z axis for calculating the distance",
166 glfontx
: IntProperty(name
="glfontx",
167 description
="Change font position in X axis",
168 default
=0, min=-3000, max=3000)
169 glfonty
: IntProperty(name
="glfonty",
170 description
="Change font position in Y axis",
171 default
=0, min=-3000, max=3000)
172 gldist
: BoolProperty(name
="gldist",
173 description
="Display distance for this measure",
175 glnames
: BoolProperty(name
="glnames",
176 description
="Display text for this measure",
178 gltot
: EnumProperty(items
=(('99', "-", "Select a group for sum"),
206 description
="Add segment length in selected group")
207 glorto
: EnumProperty(items
=(('99', "None", ""),
208 ('0', "A", "Point A must use selected point B location"),
209 ('1', "B", "Point B must use selected point A location")),
211 description
="Display point selected as orthogonal (select axis to copy)")
212 glorto_x
: BoolProperty(name
="ox",
213 description
="Copy X location",
215 glorto_y
: BoolProperty(name
="oy",
216 description
="Copy Y location",
218 glorto_z
: BoolProperty(name
="oz",
219 description
="Copy Z location",
221 glarrow_a
: EnumProperty(items
=(('99', "--", "No arrow"),
222 ('1', "Line", "The point of the arrow are lines"),
223 ('2', "Triangle", "The point of the arrow is triangle"),
224 ('3', "TShape", "The point of the arrow is a T")),
226 description
="Add arrows to point A")
227 glarrow_b
: EnumProperty(items
=(('99', "--", "No arrow"),
228 ('1', "Line", "The point of the arrow are lines"),
229 ('2', "Triangle", "The point of the arrow is triangle"),
230 ('3', "TShape", "The point of the arrow is a T")),
232 description
="Add arrows to point B")
233 glarrow_s
: IntProperty(name
="Size",
234 description
="Arrow size",
235 default
=15, min=6, max=500)
237 glarc_full
: BoolProperty(name
="arcfull",
238 description
="Create full circunference",
240 glarc_extrad
: BoolProperty(name
="arcextrad",
241 description
="Adapt radio length to arc line",
243 glarc_rad
: BoolProperty(name
="arc rad",
244 description
="Show arc radius",
246 glarc_len
: BoolProperty(name
="arc len",
247 description
="Show arc length",
249 glarc_ang
: BoolProperty(name
="arc ang",
250 description
="Show arc angle",
253 glarc_a
: EnumProperty(items
=(('99', "--", "No arrow"),
254 ('1', "Line", "The point of the arrow are lines"),
255 ('2', "Triangle", "The point of the arrow is triangle"),
256 ('3', "TShape", "The point of the arrow is a T")),
258 description
="Add arrows to point A")
259 glarc_b
: EnumProperty(items
=(('99', "--", "No arrow"),
260 ('1', "Line", "The point of the arrow are lines"),
261 ('2', "Triangle", "The point of the arrow is triangle"),
262 ('3', "TShape", "The point of the arrow is a T")),
264 description
="Add arrows to point B")
265 glarc_s
: IntProperty(name
="Size",
266 description
="Arrow size",
267 default
=15, min=6, max=500)
268 glarc_txradio
: StringProperty(name
="txradio",
269 description
="Text for radius", default
="r=")
270 glarc_txlen
: StringProperty(name
="txlen",
271 description
="Text for length", default
="L=")
272 glarc_txang
: StringProperty(name
="txang",
273 description
="Text for angle", default
="A=")
274 glcolorarea
: FloatVectorProperty(name
="glcolorarea",
275 description
="Color for the measure of area",
276 default
=(0.1, 0.1, 0.1, 1.0),
283 measureit_faces
: CollectionProperty(type=MeasureitFaces
)
287 bpy
.utils
.register_class(MeasureitProperties
)
290 # ------------------------------------------------------------------
291 # Define object class (container of segments)
293 # ------------------------------------------------------------------
294 class MeasureContainer(PropertyGroup
):
295 measureit_num
: IntProperty(name
='Number of measures', min=0, max=1000, default
=0,
296 description
='Number total of measureit elements')
298 measureit_segments
: CollectionProperty(type=MeasureitProperties
)
301 bpy
.utils
.register_class(MeasureContainer
)
302 Object
.MeasureGenerator
= CollectionProperty(type=MeasureContainer
)
305 # ------------------------------------------------------------------
308 # ------------------------------------------------------------------
309 class MEASUREIT_PT_Edit(Panel
):
310 bl_idname
= "MEASUREIT_PT_Edit"
312 bl_space_type
= 'VIEW_3D'
313 bl_region_type
= 'UI'
315 bl_parent_id
= 'MEASUREIT_PT_Main'
317 # -----------------------------------------------------
319 # -----------------------------------------------------
321 def poll(cls
, context
):
325 if 'MeasureGenerator' not in o
:
328 mp
= context
.object.MeasureGenerator
[0]
329 if mp
.measureit_num
> 0:
334 # -----------------------------------------------------
335 # Draw (create UI interface)
336 # -----------------------------------------------------
337 # noinspection PyUnusedLocal
338 def draw(self
, context
):
340 scene
= context
.scene
341 if context
.object is not None:
342 if 'MeasureGenerator' in context
.object:
345 row
.label(text
=context
.object.name
)
347 row
.prop(scene
, 'measureit_gl_precision', text
="Precision")
348 row
.prop(scene
, 'measureit_units')
350 row
.prop(scene
, 'measureit_gl_show_d', text
="Distances", toggle
=True, icon
="ALIGN_CENTER")
351 row
.prop(scene
, 'measureit_gl_show_n', text
="Texts", toggle
=True, icon
="FONT_DATA")
353 row
.prop(scene
, 'measureit_hide_units', text
="Hide measurement unit")
356 row
.prop(scene
, 'measureit_scale', text
="Scale")
357 if scene
.measureit_scale
is True:
358 split
= row
.split(factor
=0.25, align
=False)
359 split
.prop(scene
, 'measureit_scale_color', text
="")
360 split
.prop(scene
, 'measureit_scale_factor', text
="1")
363 row
.prop(scene
, 'measureit_gl_scaletxt', text
="")
364 row
.prop(scene
, 'measureit_scale_font')
365 row
.prop(scene
, 'measureit_scale_precision', text
="")
368 row
.prop(scene
, 'measureit_scale_pos_x')
369 row
.prop(scene
, 'measureit_scale_pos_y')
373 row
.prop(scene
, 'measureit_ovr', text
="Override")
374 if scene
.measureit_ovr
is True:
375 split
= row
.split(factor
=0.25, align
=False)
376 split
.prop(scene
, 'measureit_ovr_color', text
="")
377 split
.prop(scene
, 'measureit_ovr_width', text
="Width")
380 row
.prop(scene
, 'measureit_ovr_font', text
="Font")
381 row
.prop(scene
, 'measureit_ovr_font_align', text
="")
382 if scene
.measureit_ovr_font_align
== 'L':
383 row
.prop(scene
, 'measureit_ovr_font_rotation', text
="Rotate")
385 mp
= context
.object.MeasureGenerator
[0]
389 if mp
.measureit_num
> 0:
391 row
= box
.row(align
=True)
392 row
.operator("measureit.expandallsegment", text
="Expand all", icon
="ZOOM_IN")
393 row
.operator("measureit.collapseallsegment", text
="Collapse all", icon
="ZOOM_OUT")
394 for idx
in range(mp
.measureit_num
):
395 if mp
.measureit_segments
[idx
].glfree
is False:
396 add_item(box
, idx
, mp
.measureit_segments
[idx
])
399 row
.operator("measureit.deleteallsegment", text
="Delete all", icon
="X")
403 if mp
.measureit_num
> 0:
404 scale
= bpy
.context
.scene
.unit_settings
.scale_length
405 tx
= ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
406 "T", "U", "V", "W", "X", "Y", "Z"]
407 tot
= [0.0] * len(tx
)
408 ac
= [False] * len(tx
)
409 myobj
= context
.object
410 obverts
= get_mesh_vertices(myobj
)
412 for idx
in range(mp
.measureit_num
):
413 ms
= mp
.measureit_segments
[idx
]
414 if (ms
.gltype
== 1 or ms
.gltype
== 12
415 or ms
.gltype
== 13 or ms
.gltype
== 14) and ms
.gltot
!= '99' \
416 and ms
.glfree
is False: # only segments
417 if bpy
.context
.mode
== "EDIT_MESH":
418 bm
= bmesh
.from_edit_mesh(bpy
.context
.edit_object
.data
)
419 if hasattr(bm
.verts
, "ensure_lookup_table"):
420 bm
.verts
.ensure_lookup_table()
421 if ms
.glpointa
<= len(obverts
) and ms
.glpointb
<= len(obverts
):
422 p1
= get_point(obverts
[ms
.glpointa
].co
, myobj
)
424 p2
= get_point(obverts
[ms
.glpointb
].co
, myobj
)
425 elif ms
.gltype
== 12:
427 obverts
[ms
.glpointa
].co
[1],
428 obverts
[ms
.glpointa
].co
[2]), myobj
)
429 elif ms
.gltype
== 13:
430 p2
= get_point((obverts
[ms
.glpointa
].co
[0],
432 obverts
[ms
.glpointa
].co
[2]), myobj
)
434 p2
= get_point((obverts
[ms
.glpointa
].co
[0],
435 obverts
[ms
.glpointa
].co
[1],
438 dist
, distloc
= distance(p1
, p2
, ms
.glocx
, ms
.glocy
, ms
.glocz
)
444 tot
[int(ms
.gltot
)] += usedist
445 ac
[int(ms
.gltot
)] = True
451 pr
= scene
.measureit_gl_precision
452 fmt
= "%1." + str(pr
) + "f"
453 units
= scene
.measureit_units
456 box
.label(text
="Totals", icon
='SOLO_ON')
458 for idx
in range(len(tot
)):
461 tx_dist
= format_distance(fmt
, units
, tot
[idx
])
462 row
= box
.row(align
=True)
463 row
.label(text
="Group " + tx
[idx
] + ":")
465 row
.label(text
=tx_dist
)
468 row
= box
.row(align
=True)
471 row
.label(text
="-" * 20)
472 tx_dist
= format_distance(fmt
, units
, final
)
474 row
= box
.row(align
=True)
477 row
.label(text
=tx_dist
)
480 row
.operator("measureit.deleteallsum", text
="Delete all", icon
="X")
483 # -----------------------------------------------------
484 # Add segment options to the panel.
485 # -----------------------------------------------------
486 def add_item(box
, idx
, segment
):
487 scene
= bpy
.context
.scene
488 row
= box
.row(align
=True)
489 if segment
.glview
is True:
494 row
.prop(segment
, 'glview', text
="", toggle
=True, icon
=icon
)
495 row
.prop(segment
, 'gladvance', text
="", toggle
=True, icon
="PREFERENCES")
496 if segment
.gltype
== 20: # Area special
497 split
= row
.split(factor
=0.15, align
=True)
498 split
.prop(segment
, 'glcolorarea', text
="")
499 split
= split
.split(factor
=0.20, align
=True)
500 split
.prop(segment
, 'glcolor', text
="")
502 split
= row
.split(factor
=0.25, align
=True)
503 split
.prop(segment
, 'glcolor', text
="")
504 split
.prop(segment
, 'gltxt', text
="")
505 op
= row
.operator("measureit.deletesegment", text
="", icon
="X")
506 op
.tag
= idx
# saves internal data
507 if segment
.gladvance
is True:
508 row
= box
.row(align
=True)
509 row
.prop(segment
, 'glfont_size', text
="Font")
510 row
.prop(segment
, 'glfont_align', text
="")
511 if segment
.glfont_align
== 'L':
512 row
.prop(segment
, 'glfont_rotat', text
="Rotate")
513 row
= box
.row(align
=True)
514 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
515 row
.prop(segment
, 'glspace', text
="Distance")
516 row
.prop(segment
, 'glfontx', text
="X")
517 row
.prop(segment
, 'glfonty', text
="Y")
520 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
521 row
= box
.row(align
=True)
522 row
.prop(segment
, 'glarrow_a', text
="")
523 row
.prop(segment
, 'glarrow_b', text
="")
524 if segment
.glarrow_a
!= '99' or segment
.glarrow_b
!= '99':
525 row
.prop(segment
, 'glarrow_s', text
="Size")
527 if segment
.gltype
!= 2 and segment
.gltype
!= 10:
528 row
= box
.row(align
=True)
529 if scene
.measureit_gl_show_d
is True and segment
.gltype
!= 9:
530 row
.prop(segment
, 'gldist', text
="Distance", toggle
=True, icon
="ALIGN_CENTER")
531 if scene
.measureit_gl_show_n
is True:
532 row
.prop(segment
, 'glnames', text
="Text", toggle
=True, icon
="FONT_DATA")
534 if segment
.gltype
== 1 or segment
.gltype
== 12 or segment
.gltype
== 13 or segment
.gltype
== 14:
535 row
.prop(segment
, 'gltot', text
="Sum")
537 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
538 row
= box
.row(align
=True)
539 row
.prop(segment
, 'glwidth', text
="Line")
540 row
.prop(segment
, 'gldefault', text
="Automatic position")
541 if segment
.gldefault
is False:
542 row
= box
.row(align
=True)
543 row
.prop(segment
, 'glnormalx', text
="X")
544 row
.prop(segment
, 'glnormaly', text
="Y")
545 row
.prop(segment
, 'glnormalz', text
="Z")
548 if segment
.gltype
!= 2 and segment
.gltype
!= 9 and segment
.gltype
!= 10 \
549 and segment
.gltype
!= 11 and segment
.gltype
!= 12 and segment
.gltype
!= 13 \
550 and segment
.gltype
!= 14 and segment
.gltype
!= 20:
551 row
= box
.row(align
=True)
552 row
.prop(segment
, 'glocx', text
="X", toggle
=True)
553 row
.prop(segment
, 'glocy', text
="Y", toggle
=True)
554 row
.prop(segment
, 'glocz', text
="Z", toggle
=True)
555 if segment
.glocx
is False or segment
.glocy
is False or segment
.glocz
is False:
557 if segment
.gltype
== 1:
558 row
.prop(segment
, 'glorto', text
="Orthogonal")
559 row
.prop(segment
, 'glocwarning', text
="Warning")
560 # ortogonal (only segments)
561 if segment
.gltype
== 1:
562 if segment
.glorto
!= "99":
563 row
= box
.row(align
=True)
564 row
.prop(segment
, 'glorto_x', text
="X", toggle
=True)
565 row
.prop(segment
, 'glorto_y', text
="Y", toggle
=True)
566 row
.prop(segment
, 'glorto_z', text
="Z", toggle
=True)
569 if segment
.gltype
== 11:
570 row
= box
.row(align
=True)
571 row
.prop(segment
, 'glarc_rad', text
="Radius")
572 row
.prop(segment
, 'glarc_len', text
="Length")
573 row
.prop(segment
, 'glarc_ang', text
="Angle")
575 row
= box
.row(align
=True)
576 row
.prop(segment
, 'glarc_txradio', text
="")
577 row
.prop(segment
, 'glarc_txlen', text
="")
578 row
.prop(segment
, 'glarc_txang', text
="")
579 row
= box
.row(align
=True)
580 row
.prop(segment
, 'glarc_full', text
="Full Circle")
581 if segment
.glarc_rad
is True:
582 row
.prop(segment
, 'glarc_extrad', text
="Adapt radio")
584 row
= box
.row(align
=True)
585 row
.prop(segment
, 'glarc_a', text
="")
586 row
.prop(segment
, 'glarc_b', text
="")
587 if segment
.glarc_a
!= '99' or segment
.glarc_b
!= '99':
588 row
.prop(segment
, 'glarc_s', text
="Size")
591 # ------------------------------------------------------------------
592 # Define panel class for main functions.
593 # ------------------------------------------------------------------
594 class MEASUREIT_PT_Main(Panel
):
595 bl_idname
= "MEASUREIT_PT_Main"
596 bl_label
= "MeasureIt Tools"
597 bl_space_type
= 'VIEW_3D'
598 bl_region_type
= 'UI'
600 bl_options
= {'DEFAULT_CLOSED'}
602 # ------------------------------
604 # ------------------------------
605 def draw(self
, context
):
607 scene
= context
.scene
609 # ------------------------------
611 # ------------------------------
613 # ------------------------------
615 # ------------------------------
617 if context
.window_manager
.measureit_run_opengl
is False:
624 row
.operator("measureit.runopengl", text
=txt
, icon
=icon
)
625 row
.prop(scene
, "measureit_gl_ghost", text
="", icon
='GHOST_ENABLED')
629 box
.label(text
="Add Measures")
631 row
.operator("measureit.addsegment", text
="Segment")
632 row
.prop(scene
, "measureit_sum", text
="Sum")
636 op
= row
.operator("measureit.addsegmentorto", text
="X")
637 op
.tag
= 0 # saves internal data
638 op
= row
.operator("measureit.addsegmentorto", text
="Y")
639 op
.tag
= 1 # saves internal data
640 op
= row
.operator("measureit.addsegmentorto", text
="Z")
641 op
.tag
= 2 # saves internal data
644 row
.operator("measureit.addangle", text
="Angle", icon
="LINCURVE")
645 row
.operator("measureit.addarc", text
="Arc")
648 row
.operator("measureit.addlabel", text
="Label", icon
="FONT_DATA")
649 row
.operator("measureit.addnote", text
="Annotation")
652 row
.operator("measureit.addlink", text
="Link")
653 row
.operator("measureit.addorigin", text
="Origin")
656 row
.operator("measureit.addarea", text
="Area", icon
="MESH_GRID")
658 # ------------------------------
660 # ------------------------------
662 row
= box
.row(align
=False)
663 if scene
.measureit_debug
is False:
664 row
.prop(scene
, "measureit_debug", icon
="TRIA_RIGHT",
665 text
="Mesh Debug", emboss
=False)
667 row
.prop(scene
, "measureit_debug", icon
="TRIA_DOWN",
668 text
="Mesh Debug", emboss
=False)
671 split
= row
.split(factor
=0.10, align
=True)
672 split
.prop(scene
, 'measureit_debug_obj_color', text
="")
673 split
.prop(scene
, "measureit_debug_objects", icon
="OBJECT_DATA")
674 split
.prop(scene
, "measureit_debug_object_loc", icon
="EMPTY_DATA")
677 split
= row
.split(factor
=0.10, align
=True)
678 split
.prop(scene
, 'measureit_debug_vert_color', text
="")
679 split
.prop(scene
, "measureit_debug_vertices", icon
="VERTEXSEL")
680 split
.prop(scene
, "measureit_debug_vert_loc", icon
="EMPTY_DATA")
681 if scene
.measureit_debug_vert_loc
is True:
682 split
.prop(scene
, 'measureit_debug_vert_loc_toggle', text
="")
685 split
= row
.split(factor
=0.10, align
=True)
686 split
.prop(scene
, 'measureit_debug_edge_color', text
="")
687 split
= split
.split(factor
=0.5, align
=True)
688 split
.prop(scene
, "measureit_debug_edges", icon
="EDGESEL")
691 split
= row
.split(factor
=0.10, align
=True)
692 split
.prop(scene
, 'measureit_debug_face_color', text
="")
693 split
= split
.split(factor
=0.5, align
=True)
694 split
.prop(scene
, "measureit_debug_faces", icon
="FACESEL")
697 split
= row
.split(factor
=0.10, align
=True)
698 split
.prop(scene
, 'measureit_debug_norm_color', text
="")
699 if scene
.measureit_debug_normals
is False:
700 split
= split
.split(factor
=0.50, align
=True)
701 split
.prop(scene
, "measureit_debug_normals", icon
="OBJECT_ORIGIN")
703 split
= split
.split(factor
=0.5, align
=True)
704 split
.prop(scene
, "measureit_debug_normals", icon
="OBJECT_ORIGIN")
705 split
.prop(scene
, "measureit_debug_normal_size")
707 split
= row
.split(factor
=0.10, align
=True)
709 split
.prop(scene
, "measureit_debug_normal_details")
710 split
.prop(scene
, 'measureit_debug_width', text
="Thickness")
712 row
= box
.row(align
=True)
713 row
.prop(scene
, "measureit_debug_select", icon
="GHOST_ENABLED")
714 row
.prop(scene
, 'measureit_debug_font', text
="Font")
715 row
.prop(scene
, 'measureit_debug_precision', text
="Precision")
718 # ------------------------------------------------------------------
719 # Define panel class for conf functions.
720 # ------------------------------------------------------------------
721 class MEASUREIT_PT_Conf(Panel
):
722 bl_idname
= "MEASUREIT_PT_Conf"
723 bl_label
= "Configuration"
724 bl_space_type
= 'VIEW_3D'
725 bl_region_type
= 'UI'
727 bl_parent_id
= 'MEASUREIT_PT_Main'
728 bl_options
= {'DEFAULT_CLOSED'}
730 # ------------------------------
732 # ------------------------------
733 def draw(self
, context
):
735 scene
= context
.scene
740 split
= row
.split(factor
=0.2, align
=True)
741 split
.label(text
="Text")
742 split
= split
.split(factor
=0.2, align
=True)
743 split
.prop(scene
, "measureit_default_color", text
="")
744 split
.prop(scene
, "measureit_gl_txt", text
="")
745 row
= box
.row(align
=True)
746 row
.prop(scene
, "measureit_hint_space")
747 row
.prop(scene
, "measureit_font_align", text
="")
749 row
= box
.row(align
=True)
750 row
.prop(scene
, "measureit_glarrow_a", text
="")
751 row
.prop(scene
, "measureit_glarrow_b", text
="")
752 if scene
.measureit_glarrow_a
!= '99' or scene
.measureit_glarrow_b
!= '99':
753 row
.prop(scene
, "measureit_glarrow_s", text
="Size")
754 row
= box
.row(align
=True)
755 row
.prop(scene
, "measureit_font_size")
756 if scene
.measureit_font_align
== 'L':
757 row
.prop(scene
, "measureit_font_rotation", text
="Rotate")
760 # ------------------------------------------------------------------
761 # Define panel class for render functions.
762 # ------------------------------------------------------------------
763 class MEASUREIT_PT_Render(Panel
):
764 bl_idname
= "MEASUREIT_PT_Render"
766 bl_space_type
= 'VIEW_3D'
767 bl_region_type
= 'UI'
768 bl_category
= 'Display'
769 bl_parent_id
= 'MEASUREIT_PT_Main'
770 bl_options
= {'DEFAULT_CLOSED'}
772 # ------------------------------
774 # ------------------------------
775 def draw(self
, context
):
777 scene
= context
.scene
782 row
.prop(scene
, "measureit_render_type")
784 row
.operator("measureit.rendersegment", icon
='SCRIPT')
786 row
.prop(scene
, "measureit_render", text
="Save render image")
788 row
.prop(scene
, "measureit_rf", text
="Frame")
789 if scene
.measureit_rf
is True:
790 row
.prop(scene
, "measureit_rf_color", text
="Color")
792 row
.prop(scene
, "measureit_rf_border", text
="Space")
793 row
.prop(scene
, "measureit_rf_line", text
="Width")
796 # -------------------------------------------------------------
797 # Defines button that adds a measure segment
799 # -------------------------------------------------------------
800 class MEASUREIT_OT_AddSegment(Operator
):
801 bl_idname
= "measureit.addsegment"
803 bl_description
= "(EDITMODE only) Add a new measure segment between 2 vertices (select 2 vertices or more)"
805 # ------------------------------
807 # ------------------------------
809 def poll(cls
, context
):
815 if bpy
.context
.mode
== 'EDIT_MESH':
822 # ------------------------------
823 # Execute button action
824 # ------------------------------
825 def execute(self
, context
):
826 if context
.area
.type == 'VIEW_3D':
828 scene
= context
.scene
829 mainobject
= context
.object
830 mylist
= get_smart_selected(mainobject
)
831 if len(mylist
) < 2: # if not selected linked vertex
832 mylist
= get_selected_vertex(mainobject
)
835 if 'MeasureGenerator' not in mainobject
:
836 mainobject
.MeasureGenerator
.add()
838 mp
= mainobject
.MeasureGenerator
[0]
839 for x
in range(0, len(mylist
) - 1, 2):
840 # -----------------------
842 # -----------------------
843 if exist_segment(mp
, mylist
[x
], mylist
[x
+ 1]) is False:
844 # Create all array elements
845 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
846 mp
.measureit_segments
.add()
849 ms
= mp
.measureit_segments
[mp
.measureit_num
]
851 ms
.glpointa
= mylist
[x
]
852 ms
.glpointb
= mylist
[x
+ 1]
853 ms
.glarrow_a
= scene
.measureit_glarrow_a
854 ms
.glarrow_b
= scene
.measureit_glarrow_b
855 ms
.glarrow_s
= scene
.measureit_glarrow_s
857 ms
.glcolor
= scene
.measureit_default_color
859 ms
.glspace
= scene
.measureit_hint_space
861 ms
.gltxt
= scene
.measureit_gl_txt
862 ms
.glfont_size
= scene
.measureit_font_size
863 ms
.glfont_align
= scene
.measureit_font_align
864 ms
.glfont_rotat
= scene
.measureit_font_rotation
866 ms
.gltot
= scene
.measureit_sum
868 mp
.measureit_num
+= 1
871 context
.area
.tag_redraw()
874 self
.report({'ERROR'},
875 "MeasureIt: Select at least two vertices for creating measure segment.")
878 self
.report({'WARNING'},
879 "View3D not found, cannot run operator")
884 # -------------------------------------------------------------
885 # Defines button that adds an area measure
887 # -------------------------------------------------------------
888 class MEASUREIT_OT_AddArea(Operator
):
889 bl_idname
= "measureit.addarea"
891 bl_description
= "(EDITMODE only) Add a new measure for area (select 1 o more faces)"
893 # ------------------------------
895 # ------------------------------
897 def poll(cls
, context
):
903 if bpy
.context
.mode
== 'EDIT_MESH':
910 # ------------------------------
911 # Execute button action
912 # ------------------------------
913 def execute(self
, context
):
914 if context
.area
.type == 'VIEW_3D':
916 scene
= context
.scene
917 mainobject
= context
.object
918 mylist
= get_selected_faces(mainobject
)
920 if 'MeasureGenerator' not in mainobject
:
921 mainobject
.MeasureGenerator
.add()
923 mp
= mainobject
.MeasureGenerator
[0]
924 mp
.measureit_segments
.add()
925 ms
= mp
.measureit_segments
[mp
.measureit_num
]
930 # Create array elements
931 ms
.measureit_faces
.add()
934 mf
= ms
.measureit_faces
[f
]
938 mf
.measureit_index
.add()
939 mi
= mf
.measureit_index
[i
]
944 rgb
= scene
.measureit_default_color
945 ms
.glcolor
= (rgb
[0], rgb
[1], rgb
[2], 0.4)
947 ms
.glspace
= scene
.measureit_hint_space
949 ms
.gltxt
= scene
.measureit_gl_txt
950 ms
.glfont_size
= scene
.measureit_font_size
951 ms
.glfont_align
= scene
.measureit_font_align
952 ms
.glfont_rotat
= scene
.measureit_font_rotation
954 ms
.gltot
= scene
.measureit_sum
956 mp
.measureit_num
+= 1
958 context
.area
.tag_redraw()
961 self
.report({'ERROR'},
962 "MeasureIt: Select at least one face for creating area measure. ")
965 self
.report({'WARNING'},
966 "View3D not found, cannot run operator")
971 # -------------------------------------------------------------
972 # Defines button that adds a measure segment to x/y/z origin
974 # -------------------------------------------------------------
975 class MEASUREIT_OT_AddSegmentOrto(Operator
):
976 bl_idname
= "measureit.addsegmentorto"
978 bl_description
= "(EDITMODE only) Add a new measure segment from vertex to object origin for one " \
979 "axis (select 1 vertex)"
982 # ------------------------------
984 # ------------------------------
986 def poll(cls
, context
):
992 if bpy
.context
.mode
== 'EDIT_MESH':
999 # ------------------------------
1000 # Execute button action
1001 # ------------------------------
1002 def execute(self
, context
):
1003 if context
.area
.type == 'VIEW_3D':
1005 scene
= context
.scene
1006 mainobject
= context
.object
1007 mylist
= get_smart_selected(mainobject
)
1008 if len(mylist
) < 1: # if not selected linked vertex
1009 mylist
= get_selected_vertex(mainobject
)
1011 if len(mylist
) >= 1:
1012 if 'MeasureGenerator' not in mainobject
:
1013 mainobject
.MeasureGenerator
.add()
1015 mp
= mainobject
.MeasureGenerator
[0]
1016 for x
in range(len(mylist
)):
1017 # -----------------------
1019 # -----------------------
1020 if exist_segment(mp
, mylist
[x
], mylist
[x
], 12 + int(self
.tag
)) is False:
1021 # Create all array elements
1022 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1023 mp
.measureit_segments
.add()
1026 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1027 ms
.gltype
= 12 + int(self
.tag
)
1028 ms
.glpointa
= mylist
[x
]
1029 ms
.glpointb
= mylist
[x
]
1030 ms
.glarrow_a
= scene
.measureit_glarrow_a
1031 ms
.glarrow_b
= scene
.measureit_glarrow_b
1032 ms
.glarrow_s
= scene
.measureit_glarrow_s
1034 ms
.glcolor
= scene
.measureit_default_color
1036 ms
.glspace
= scene
.measureit_hint_space
1038 ms
.gltxt
= scene
.measureit_gl_txt
1039 ms
.glfont_size
= scene
.measureit_font_size
1040 ms
.glfont_align
= scene
.measureit_font_align
1041 ms
.glfont_rotat
= scene
.measureit_font_rotation
1043 ms
.gltot
= scene
.measureit_sum
1045 mp
.measureit_num
+= 1
1048 context
.area
.tag_redraw()
1051 self
.report({'ERROR'},
1052 "MeasureIt: Select at least one vertex for creating measure segment.")
1055 self
.report({'WARNING'},
1056 "View3D not found, cannot run operator")
1058 return {'CANCELLED'}
1061 # -------------------------------------------------------------
1062 # Defines button that adds an angle measure
1064 # -------------------------------------------------------------
1065 class MEASUREIT_OT_AddAngle(Operator
):
1066 bl_idname
= "measureit.addangle"
1068 bl_description
= "(EDITMODE only) Add a new angle measure (select 3 vertices, 2nd is angle vertex)"
1070 # ------------------------------
1072 # ------------------------------
1074 def poll(cls
, context
):
1079 if o
.type == "MESH":
1080 if bpy
.context
.mode
== 'EDIT_MESH':
1087 # ------------------------------
1088 # Execute button action
1089 # ------------------------------
1090 def execute(self
, context
):
1091 if context
.area
.type == 'VIEW_3D':
1093 scene
= context
.scene
1094 mainobject
= context
.object
1095 mylist
= get_selected_vertex_history(mainobject
)
1096 if len(mylist
) == 3:
1097 if 'MeasureGenerator' not in mainobject
:
1098 mainobject
.MeasureGenerator
.add()
1100 mp
= mainobject
.MeasureGenerator
[0]
1101 # -----------------------
1103 # -----------------------
1104 if exist_segment(mp
, mylist
[0], mylist
[1], 9, mylist
[2]) is False:
1105 # Create all array elements
1106 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1107 mp
.measureit_segments
.add()
1110 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1112 ms
.glpointa
= mylist
[0]
1113 ms
.glpointb
= mylist
[1]
1114 ms
.glpointc
= mylist
[2]
1116 ms
.glcolor
= scene
.measureit_default_color
1118 ms
.glspace
= scene
.measureit_hint_space
1120 ms
.gltxt
= scene
.measureit_gl_txt
1121 ms
.glfont_size
= scene
.measureit_font_size
1122 ms
.glfont_align
= scene
.measureit_font_align
1123 ms
.glfont_rotat
= scene
.measureit_font_rotation
1125 mp
.measureit_num
+= 1
1128 context
.area
.tag_redraw()
1131 self
.report({'ERROR'},
1132 "MeasureIt: Select three vertices for creating angle measure")
1135 self
.report({'WARNING'},
1136 "View3D not found, cannot run operator")
1138 return {'CANCELLED'}
1141 # -------------------------------------------------------------
1142 # Defines button that adds an arc measure
1144 # -------------------------------------------------------------
1145 class MEASUREIT_OT_AddArc(Operator
):
1146 bl_idname
= "measureit.addarc"
1148 bl_description
= "(EDITMODE only) Add a new arc measure (select 3 vertices of the arc," \
1149 " vertices 1st and 3rd are arc extremes)"
1151 # ------------------------------
1153 # ------------------------------
1155 def poll(cls
, context
):
1160 if o
.type == "MESH":
1161 if bpy
.context
.mode
== 'EDIT_MESH':
1168 # ------------------------------
1169 # Execute button action
1170 # ------------------------------
1171 def execute(self
, context
):
1172 if context
.area
.type == 'VIEW_3D':
1174 scene
= context
.scene
1175 mainobject
= context
.object
1176 mylist
= get_selected_vertex_history(mainobject
)
1177 if len(mylist
) == 3:
1178 if 'MeasureGenerator' not in mainobject
:
1179 mainobject
.MeasureGenerator
.add()
1181 mp
= mainobject
.MeasureGenerator
[0]
1182 # -----------------------
1184 # -----------------------
1185 if exist_segment(mp
, mylist
[0], mylist
[1], 11, mylist
[2]) is False:
1186 # Create all array elements
1187 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1188 mp
.measureit_segments
.add()
1191 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1193 ms
.glpointa
= mylist
[0]
1194 ms
.glpointb
= mylist
[1]
1195 ms
.glpointc
= mylist
[2]
1196 ms
.glarrow_a
= scene
.measureit_glarrow_a
1197 ms
.glarrow_b
= scene
.measureit_glarrow_b
1198 ms
.glarrow_s
= scene
.measureit_glarrow_s
1200 ms
.glcolor
= scene
.measureit_default_color
1202 ms
.glspace
= scene
.measureit_hint_space
1204 ms
.gltxt
= scene
.measureit_gl_txt
1205 ms
.glfont_size
= scene
.measureit_font_size
1206 ms
.glfont_align
= scene
.measureit_font_align
1207 ms
.glfont_rotat
= scene
.measureit_font_rotation
1209 mp
.measureit_num
+= 1
1212 context
.area
.tag_redraw()
1215 self
.report({'ERROR'},
1216 "MeasureIt: Select three vertices for creating arc measure")
1219 self
.report({'WARNING'},
1220 "View3D not found, cannot run operator")
1222 return {'CANCELLED'}
1225 # -------------------------------------------------------------
1226 # Defines button that adds a label segment
1228 # -------------------------------------------------------------
1229 class MEASUREIT_OT_AddLabel(Operator
):
1230 bl_idname
= "measureit.addlabel"
1232 bl_description
= "(EDITMODE only) Add a new measure label (select 1 vertex)"
1234 # ------------------------------
1236 # ------------------------------
1238 def poll(cls
, context
):
1243 if o
.type == "MESH":
1244 if bpy
.context
.mode
== 'EDIT_MESH':
1251 # ------------------------------
1252 # Execute button action
1253 # ------------------------------
1254 def execute(self
, context
):
1255 if context
.area
.type == 'VIEW_3D':
1257 scene
= context
.scene
1258 mainobject
= context
.object
1259 mylist
= get_selected_vertex(mainobject
)
1260 if len(mylist
) == 1:
1261 if 'MeasureGenerator' not in mainobject
:
1262 mainobject
.MeasureGenerator
.add()
1264 mp
= mainobject
.MeasureGenerator
[0]
1265 # -----------------------
1267 # -----------------------
1268 if exist_segment(mp
, mylist
[0], mylist
[0], 2) is False: # Both equal
1269 # Create all array elements
1270 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1271 mp
.measureit_segments
.add()
1274 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1276 ms
.glpointa
= mylist
[0]
1277 ms
.glpointb
= mylist
[0] # Equal
1278 ms
.glarrow_a
= scene
.measureit_glarrow_a
1279 ms
.glarrow_b
= scene
.measureit_glarrow_b
1280 ms
.glarrow_s
= scene
.measureit_glarrow_s
1282 ms
.glcolor
= scene
.measureit_default_color
1284 ms
.glspace
= scene
.measureit_hint_space
1286 ms
.gltxt
= scene
.measureit_gl_txt
1287 ms
.glfont_size
= scene
.measureit_font_size
1288 ms
.glfont_align
= scene
.measureit_font_align
1289 ms
.glfont_rotat
= scene
.measureit_font_rotation
1291 mp
.measureit_num
+= 1
1294 context
.area
.tag_redraw()
1297 self
.report({'ERROR'},
1298 "MeasureIt: Select one vertex for creating measure label")
1301 self
.report({'WARNING'},
1302 "View3D not found, cannot run operator")
1304 return {'CANCELLED'}
1307 # -------------------------------------------------------------
1308 # Defines button that adds a link
1310 # -------------------------------------------------------------
1311 class MEASUREIT_OT_AddLink(Operator
):
1312 bl_idname
= "measureit.addlink"
1314 bl_description
= "(OBJECT mode only) Add a new measure between objects (select 2 " \
1315 "objects and optionally 1 or 2 vertices)"
1317 # ------------------------------
1319 # ------------------------------
1321 def poll(cls
, context
):
1326 if o
.type == "MESH" or o
.type == "EMPTY" or o
.type == "CAMERA" or o
.type == "LIGHT":
1327 if bpy
.context
.mode
== 'OBJECT':
1334 # ------------------------------
1335 # Execute button action
1336 # ------------------------------
1337 def execute(self
, context
):
1338 if context
.area
.type == 'VIEW_3D':
1339 scene
= context
.scene
1340 mainobject
= context
.object
1341 # -------------------------------
1342 # Verify number of objects
1343 # -------------------------------
1344 if len(context
.selected_objects
) != 2:
1345 self
.report({'ERROR'},
1346 "MeasureIt: Select two objects only, and optionally 1 vertex or 2 vertices "
1347 "(one of each object)")
1349 # Locate other object
1351 for o
in context
.selected_objects
:
1352 if o
.name
!= mainobject
.name
:
1354 # Verify destination vertex
1355 lkobj
= bpy
.data
.objects
[linkobject
]
1356 mylinkvertex
= get_selected_vertex(lkobj
)
1357 if len(mylinkvertex
) > 1:
1358 self
.report({'ERROR'},
1359 "MeasureIt: The destination object has more than one vertex selected. "
1360 "Select only 1 or none")
1362 # Verify origin vertex
1363 myobjvertex
= get_selected_vertex(mainobject
)
1364 if len(mylinkvertex
) > 1:
1365 self
.report({'ERROR'},
1366 "MeasureIt: The active object has more than one vertex selected. Select only 1 or none")
1369 # -------------------------------
1371 # -------------------------------
1373 if 'MeasureGenerator' not in mainobject
:
1374 mainobject
.MeasureGenerator
.add()
1376 mp
= mainobject
.MeasureGenerator
[0]
1378 # if exist_segment(mp, mylist[0], mylist[0], 3) is False:
1380 # Create all array elements
1381 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1382 mp
.measureit_segments
.add()
1385 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1386 # -----------------------
1388 # -----------------------
1389 if len(myobjvertex
) == 1 and len(mylinkvertex
) == 1:
1391 ms
.glpointa
= myobjvertex
[0]
1392 ms
.glpointb
= mylinkvertex
[0]
1394 # -----------------------
1396 # -----------------------
1397 if len(myobjvertex
) == 1 and len(mylinkvertex
) == 0:
1399 ms
.glpointa
= myobjvertex
[0]
1402 # -----------------------
1404 # -----------------------
1405 if len(myobjvertex
) == 0 and len(mylinkvertex
) == 1:
1408 ms
.glpointb
= mylinkvertex
[0]
1410 # -----------------------
1412 # -----------------------
1413 if len(myobjvertex
) == 0 and len(mylinkvertex
) == 0:
1416 ms
.glpointb
= 0 # Equal
1419 # ------------------
1421 # ------------------
1423 ms
.glarrow_a
= scene
.measureit_glarrow_a
1424 ms
.glarrow_b
= scene
.measureit_glarrow_b
1425 ms
.glarrow_s
= scene
.measureit_glarrow_s
1427 ms
.glcolor
= scene
.measureit_default_color
1429 ms
.glspace
= scene
.measureit_hint_space
1431 ms
.gltxt
= scene
.measureit_gl_txt
1432 ms
.glfont_size
= scene
.measureit_font_size
1433 ms
.glfont_align
= scene
.measureit_font_align
1434 ms
.glfont_rotat
= scene
.measureit_font_rotation
1436 ms
.gllink
= linkobject
1438 mp
.measureit_num
+= 1
1440 # -----------------------
1442 # -----------------------
1444 context
.area
.tag_redraw()
1447 self
.report({'WARNING'},
1448 "View3D not found, cannot run operator")
1450 return {'CANCELLED'}
1453 # -------------------------------------------------------------
1454 # Defines button that adds an origin segment
1456 # -------------------------------------------------------------
1457 class MEASUREIT_OT_AddOrigin(Operator
):
1458 bl_idname
= "measureit.addorigin"
1460 bl_description
= "(OBJECT mode only) Add a new measure to origin (select object and optionally 1 vertex)"
1462 # ------------------------------
1464 # ------------------------------
1466 def poll(cls
, context
):
1471 if o
.type == "MESH" or o
.type == "EMPTY" or o
.type == "CAMERA" or o
.type == "LIGHT":
1472 if bpy
.context
.mode
== 'OBJECT':
1479 # ------------------------------
1480 # Execute button action
1481 # ------------------------------
1482 def execute(self
, context
):
1483 if context
.area
.type == 'VIEW_3D':
1485 scene
= context
.scene
1486 mainobject
= context
.object
1487 mylist
= get_selected_vertex(mainobject
)
1488 if 'MeasureGenerator' not in mainobject
:
1489 mainobject
.MeasureGenerator
.add()
1491 mp
= mainobject
.MeasureGenerator
[0]
1492 # Create all array elements
1493 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1494 mp
.measureit_segments
.add()
1496 # -----------------------
1498 # -----------------------
1499 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1502 if len(mylist
) == 1:
1503 if exist_segment(mp
, mylist
[0], mylist
[0], 6) is False: # Both equal
1507 ms
.glpointa
= mylist
[0]
1508 ms
.glpointb
= mylist
[0]
1510 self
.report({'ERROR'},
1511 "MeasureIt: Enter in EDITMODE and select one vertex only for creating "
1512 "measure from vertex to origin")
1516 if exist_segment(mp
, 0, 0, 7) is False: # Both equal
1521 # ------------------
1523 # ------------------
1525 ms
.glarrow_a
= scene
.measureit_glarrow_a
1526 ms
.glarrow_b
= scene
.measureit_glarrow_b
1527 ms
.glarrow_s
= scene
.measureit_glarrow_s
1529 ms
.glcolor
= scene
.measureit_default_color
1531 ms
.glspace
= scene
.measureit_hint_space
1533 ms
.gltxt
= scene
.measureit_gl_txt
1534 ms
.glfont_size
= scene
.measureit_font_size
1535 ms
.glfont_align
= scene
.measureit_font_align
1536 ms
.glfont_rotat
= scene
.measureit_font_rotation
1538 mp
.measureit_num
+= 1
1541 context
.area
.tag_redraw()
1545 self
.report({'WARNING'},
1546 "View3D not found, cannot run operator")
1548 return {'CANCELLED'}
1551 # -------------------------------------------------------------
1552 # Defines button that deletes a measure segment
1554 # -------------------------------------------------------------
1555 class MEASUREIT_OT_DeleteSegment(Operator
):
1556 bl_idname
= "measureit.deletesegment"
1558 bl_description
= "Delete a measure"
1561 # ------------------------------
1562 # Execute button action
1563 # ------------------------------
1564 def execute(self
, context
):
1565 if context
.area
.type == 'VIEW_3D':
1567 mainobject
= context
.object
1568 mp
= mainobject
.MeasureGenerator
[0]
1569 ms
= mp
.measureit_segments
[self
.tag
]
1572 mp
.measureit_segments
.remove(self
.tag
)
1573 mp
.measureit_num
-= 1
1575 context
.area
.tag_redraw()
1578 self
.report({'WARNING'},
1579 "View3D not found, cannot run operator")
1581 return {'CANCELLED'}
1584 # -------------------------------------------------------------
1585 # Defines button that deletes all measure segments
1587 # -------------------------------------------------------------
1588 class MEASUREIT_OT_DeleteAllSegment(Operator
):
1589 bl_idname
= "measureit.deleteallsegment"
1591 bl_description
= "Delete all measures (it cannot be undone)"
1594 # ------------------------------
1595 # Execute button action
1596 # ------------------------------
1597 def execute(self
, context
):
1598 if context
.area
.type == 'VIEW_3D':
1600 mainobject
= context
.object
1601 mp
= mainobject
.MeasureGenerator
[0]
1603 while len(mp
.measureit_segments
) > 0:
1604 mp
.measureit_segments
.remove(0)
1607 mp
.measureit_num
= len(mp
.measureit_segments
)
1609 context
.area
.tag_redraw()
1612 self
.report({'WARNING'},
1613 "View3D not found, cannot run operator")
1615 return {'CANCELLED'}
1618 # -------------------------------------------------------------
1619 # Defines button that deletes all measure segment sums
1621 # -------------------------------------------------------------
1622 class MEASUREIT_OT_DeleteAllSum(Operator
):
1623 bl_idname
= "measureit.deleteallsum"
1625 bl_description
= "Delete all sum groups"
1628 # ------------------------------
1629 # Execute button action
1630 # ------------------------------
1631 # noinspection PyMethodMayBeStatic
1632 def execute(self
, context
):
1633 if context
.object is not None:
1634 if 'MeasureGenerator' in context
.object:
1635 mp
= context
.object.MeasureGenerator
[0]
1636 for idx
in range(mp
.measureit_num
):
1637 ms
= mp
.measureit_segments
[idx
]
1643 # -------------------------------------------------------------
1644 # Defines button that expands all measure segments
1646 # -------------------------------------------------------------
1647 class MEASUREIT_OT_ExpandAllSegment(Operator
):
1648 bl_idname
= "measureit.expandallsegment"
1650 bl_description
= "Expand all measure properties"
1653 # ------------------------------
1654 # Execute button action
1655 # ------------------------------
1656 def execute(self
, context
):
1657 if context
.area
.type == 'VIEW_3D':
1659 mainobject
= context
.object
1660 mp
= mainobject
.MeasureGenerator
[0]
1662 for i
in mp
.measureit_segments
:
1667 self
.report({'WARNING'},
1668 "View3D not found, cannot run operator")
1670 return {'CANCELLED'}
1673 # -------------------------------------------------------------
1674 # Defines button that collapses all measure segments
1676 # -------------------------------------------------------------
1677 class MEASUREIT_OT_CollapseAllSegment(Operator
):
1678 bl_idname
= "measureit.collapseallsegment"
1679 bl_label
= "Collapse"
1680 bl_description
= "Collapses all measure properties"
1683 # ------------------------------
1684 # Execute button action
1685 # ------------------------------
1686 def execute(self
, context
):
1687 if context
.area
.type == 'VIEW_3D':
1689 mainobject
= context
.object
1690 mp
= mainobject
.MeasureGenerator
[0]
1692 for i
in mp
.measureit_segments
:
1697 self
.report({'WARNING'},
1698 "View3D not found, cannot run operator")
1700 return {'CANCELLED'}
1703 # -------------------------------------------------------------
1704 # Defines button for render option
1706 # -------------------------------------------------------------
1707 class MEASUREIT_OT_RenderSegment(Operator
):
1708 bl_idname
= "measureit.rendersegment"
1710 bl_description
= "Create a render image with measures. Use UV/Image editor to view image generated"
1713 # ------------------------------
1714 # Execute button action
1715 # ------------------------------
1716 # noinspection PyMethodMayBeStatic,PyUnusedLocal
1717 def execute(self
, context
):
1718 scene
= context
.scene
1719 msg
= "New image created with measures. Open it in UV/image editor"
1720 camera_msg
= "Unable to render. No camera found"
1721 # -----------------------------
1723 # -----------------------------
1724 if scene
.camera
is None:
1725 self
.report({'ERROR'}, camera_msg
)
1727 # -----------------------------
1729 # -----------------------------
1730 if scene
.measureit_render_type
== "1":
1731 # noinspection PyBroadException
1732 if render_main(self
, context
) is True:
1733 self
.report({'INFO'}, msg
)
1734 # -----------------------------
1736 # -----------------------------
1737 if scene
.measureit_render_type
== "2":
1738 oldframe
= scene
.frame_current
1741 for frm
in range(scene
.frame_start
, scene
.frame_end
+ 1):
1742 scene
.frame_set(frm
)
1743 print("MeasureIt: Rendering frame %04d" % frm
)
1744 flag
= render_main(self
, context
, True)
1748 scene
.frame_current
= oldframe
1750 self
.report({'INFO'}, msg
)
1754 # ---------------------
1756 # ---------------------
1757 # noinspection PyMethodMayBeStatic
1758 def set_camera_view(self
):
1759 for area
in bpy
.context
.screen
.areas
:
1760 if area
.type == 'VIEW_3D':
1761 area
.spaces
[0].region_3d
.view_perspective
= 'CAMERA'
1763 # -------------------------------------
1764 # Set only render status
1765 # -------------------------------------
1766 # noinspection PyMethodMayBeStatic
1767 def set_only_render(self
, status
):
1768 screen
= bpy
.context
.screen
1772 # get spaceview_3d in current screen
1773 for a
in screen
.areas
:
1774 if a
.type == 'VIEW_3D':
1776 if s
.type == 'VIEW_3D':
1780 if v3d
is not False:
1781 s
.show_only_render
= status
1784 # -------------------------------------------------------------
1785 # Defines a new note
1787 # -------------------------------------------------------------
1788 class MEASUREIT_OT_AddNote(Operator
):
1789 bl_idname
= "measureit.addnote"
1791 bl_description
= "(OBJECT mode only) Add a new annotation"
1794 # ------------------------------
1796 # ------------------------------
1797 # noinspection PyUnusedLocal
1799 def poll(cls
, context
):
1800 if bpy
.context
.mode
== 'OBJECT':
1805 # ------------------------------
1806 # Execute button action
1807 # ------------------------------
1808 def execute(self
, context
):
1809 if context
.area
.type == 'VIEW_3D':
1810 bpy
.ops
.object.empty_add(type='PLAIN_AXES')
1811 myempty
= bpy
.data
.objects
[bpy
.context
.active_object
.name
]
1812 myempty
.location
= bpy
.context
.scene
.cursor
.location
1813 myempty
.empty_display_size
= 0.01
1814 myempty
.name
= "Annotation"
1816 scene
= context
.scene
1817 mainobject
= myempty
1818 if 'MeasureGenerator' not in mainobject
:
1819 mainobject
.MeasureGenerator
.add()
1821 mp
= mainobject
.MeasureGenerator
[0]
1822 # Create all array elements
1823 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1824 mp
.measureit_segments
.add()
1827 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1830 ms
.glpointb
= 0 # Equal
1832 ms
.glcolor
= scene
.measureit_default_color
1834 ms
.glspace
= scene
.measureit_hint_space
1836 ms
.gltxt
= scene
.measureit_gl_txt
1837 ms
.glfont_size
= scene
.measureit_font_size
1838 ms
.glfont_align
= scene
.measureit_font_align
1839 ms
.glfont_rotat
= scene
.measureit_font_rotation
1841 mp
.measureit_num
+= 1
1844 context
.area
.tag_redraw()
1847 self
.report({'WARNING'},
1848 "View3D not found, cannot run operator")
1850 return {'CANCELLED'}
1853 # -------------------------------------------------------------
1854 # Defines button that enables/disables the tip display
1856 # -------------------------------------------------------------
1857 class MEASUREIT_OT_RunHintDisplay(Operator
):
1858 bl_idname
= "measureit.runopengl"
1859 bl_label
= "Display hint data manager"
1860 bl_description
= "Main control for enabling or disabling the display of measurements in the viewport"
1862 _handle
= None # keep function handler
1864 # ----------------------------------
1865 # Enable gl drawing adding handler
1866 # ----------------------------------
1868 def handle_add(self
, context
):
1869 if MEASUREIT_OT_RunHintDisplay
._handle
is None:
1870 MEASUREIT_OT_RunHintDisplay
._handle
= SpaceView3D
.draw_handler_add(draw_callback_px
, (self
, context
),
1873 context
.window_manager
.measureit_run_opengl
= True
1875 # ------------------------------------
1876 # Disable gl drawing removing handler
1877 # ------------------------------------
1878 # noinspection PyUnusedLocal
1880 def handle_remove(self
, context
):
1881 if MEASUREIT_OT_RunHintDisplay
._handle
is not None:
1882 SpaceView3D
.draw_handler_remove(MEASUREIT_OT_RunHintDisplay
._handle
, 'WINDOW')
1883 MEASUREIT_OT_RunHintDisplay
._handle
= None
1884 context
.window_manager
.measureit_run_opengl
= False
1886 # ------------------------------
1887 # Execute button action
1888 # ------------------------------
1889 def execute(self
, context
):
1890 if context
.area
.type == 'VIEW_3D':
1891 if context
.window_manager
.measureit_run_opengl
is False:
1892 self
.handle_add(self
, context
)
1893 context
.area
.tag_redraw()
1895 self
.handle_remove(self
, context
)
1896 context
.area
.tag_redraw()
1900 self
.report({'WARNING'},
1901 "View3D not found, cannot run operator")
1903 return {'CANCELLED'}
1906 # -------------------------------------------------------------
1907 # Handle all draw routines (OpenGL main entry point)
1909 # -------------------------------------------------------------
1910 def draw_main(context
):
1911 region
= bpy
.context
.region
1912 # Detect if Quadview to get drawing area
1913 if not context
.space_data
.region_quadviews
:
1914 rv3d
= bpy
.context
.space_data
.region_3d
1917 if context
.area
.type != 'VIEW_3D' or context
.space_data
.type != 'VIEW_3D':
1920 for region
in context
.area
.regions
:
1921 if region
.type == 'WINDOW':
1923 if context
.region
.id == region
.id:
1928 rv3d
= context
.space_data
.region_quadviews
[i
]
1930 scene
= bpy
.context
.scene
1932 # Display selected or all
1933 if scene
.measureit_gl_ghost
is False:
1934 objlist
= context
.selected_objects
1936 objlist
= context
.view_layer
.objects
1939 bgl
.glEnable(bgl
.GL_BLEND
)
1940 # ---------------------------------------
1941 # Generate all OpenGL calls for measures
1942 # ---------------------------------------
1943 for myobj
in objlist
:
1944 if myobj
.visible_get() is True:
1945 if 'MeasureGenerator' in myobj
:
1946 op
= myobj
.MeasureGenerator
[0]
1947 draw_segments(context
, myobj
, op
, region
, rv3d
)
1949 # ---------------------------------------
1950 # Generate all OpenGL calls for debug
1951 # ---------------------------------------
1952 if scene
.measureit_debug
is True:
1953 selobj
= bpy
.context
.selected_objects
1954 for myobj
in selobj
:
1955 if scene
.measureit_debug_objects
is True:
1956 draw_object(context
, myobj
, region
, rv3d
)
1957 elif scene
.measureit_debug_object_loc
is True:
1958 draw_object(context
, myobj
, region
, rv3d
)
1959 if scene
.measureit_debug_vertices
is True:
1960 draw_vertices(context
, myobj
, region
, rv3d
)
1961 elif scene
.measureit_debug_vert_loc
is True:
1962 draw_vertices(context
, myobj
, region
, rv3d
)
1963 if scene
.measureit_debug_edges
is True:
1964 draw_edges(context
, myobj
, region
, rv3d
)
1965 if scene
.measureit_debug_faces
is True or scene
.measureit_debug_normals
is True:
1966 draw_faces(context
, myobj
, region
, rv3d
)
1968 # -----------------------
1969 # restore opengl defaults
1970 # -----------------------
1971 bgl
.glDisable(bgl
.GL_BLEND
)
1974 # -------------------------------------------------------------
1975 # Handler for drawing OpenGl
1976 # -------------------------------------------------------------
1977 # noinspection PyUnusedLocal
1978 def draw_callback_px(self
, context
):
1982 # -------------------------------------------------------------
1983 # Check if the segment already exist
1985 # -------------------------------------------------------------
1986 def exist_segment(mp
, pointa
, pointb
, typ
=1, pointc
=None):
1987 # for ms in mp.measureit_segments[mp.measureit_num]
1988 for ms
in mp
.measureit_segments
:
1989 if ms
.gltype
== typ
and ms
.glfree
is False:
1991 if ms
.glpointa
== pointa
and ms
.glpointb
== pointb
:
1993 if ms
.glpointa
== pointb
and ms
.glpointb
== pointa
:
1996 if ms
.glpointa
== pointa
and ms
.glpointb
== pointb
and ms
.glpointc
== pointc
:
2002 # -------------------------------------------------------------
2003 # Get vertex selected
2004 # -------------------------------------------------------------
2005 def get_selected_vertex(myobject
):
2007 # if not mesh, no vertex
2008 if myobject
.type != "MESH":
2010 # --------------------
2012 # --------------------
2013 oldobj
= bpy
.context
.object
2014 bpy
.context
.view_layer
.objects
.active
= myobject
2016 if myobject
.mode
!= 'EDIT':
2017 bpy
.ops
.object.mode_set(mode
='EDIT')
2020 bm
= from_edit_mesh(myobject
.data
)
2024 mylist
.append(v
.index
)
2027 bpy
.ops
.object.editmode_toggle()
2028 # Back context object
2029 bpy
.context
.view_layer
.objects
.active
= oldobj
2031 # if select all vertices, then use origin
2032 if tv
== len(mylist
):
2038 # -------------------------------------------------------------
2039 # Get vertex selected
2040 # -------------------------------------------------------------
2041 def get_selected_vertex_history(myobject
):
2043 # if not mesh, no vertex
2044 if myobject
.type != "MESH":
2046 # --------------------
2048 # --------------------
2049 oldobj
= bpy
.context
.object
2050 bpy
.context
.view_layer
.objects
.active
= myobject
2052 if myobject
.mode
!= 'EDIT':
2053 bpy
.ops
.object.mode_set(mode
='EDIT')
2056 bm
= from_edit_mesh(myobject
.data
)
2057 for v
in bm
.select_history
:
2058 mylist
.append(v
.index
)
2061 bpy
.ops
.object.editmode_toggle()
2062 # Back context object
2063 bpy
.context
.view_layer
.objects
.active
= oldobj
2068 # -------------------------------------------------------------
2069 # Get vertex selected segments
2070 # -------------------------------------------------------------
2071 def get_smart_selected(myobject
):
2073 # if not mesh, no vertex
2074 if myobject
.type != "MESH":
2076 # --------------------
2078 # --------------------
2079 oldobj
= bpy
.context
.object
2080 bpy
.context
.view_layer
.objects
.active
= myobject
2082 if myobject
.mode
!= 'EDIT':
2083 bpy
.ops
.object.mode_set(mode
='EDIT')
2086 bm
= from_edit_mesh(myobject
.data
)
2088 if e
.select
is True:
2089 mylist
.append(e
.verts
[0].index
)
2090 mylist
.append(e
.verts
[1].index
)
2093 bpy
.ops
.object.editmode_toggle()
2094 # Back context object
2095 bpy
.context
.view_layer
.objects
.active
= oldobj
2100 # -------------------------------------------------------------
2101 # Get vertex selected faces
2102 # -------------------------------------------------------------
2103 def get_selected_faces(myobject
):
2105 # if not mesh, no vertex
2106 if myobject
.type != "MESH":
2108 # --------------------
2110 # --------------------
2111 oldobj
= bpy
.context
.object
2112 bpy
.context
.view_layer
.objects
.active
= myobject
2114 if myobject
.mode
!= 'EDIT':
2115 bpy
.ops
.object.mode_set(mode
='EDIT')
2118 bm
= from_edit_mesh(myobject
.data
)
2121 if e
.select
is True:
2122 for i
in range(len(e
.verts
)):
2123 myfaces
.append(e
.verts
[i
].index
)
2125 mylist
.extend([myfaces
])
2128 bpy
.ops
.object.editmode_toggle()
2129 # Back context object
2130 bpy
.context
.view_layer
.objects
.active
= oldobj