1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # ----------------------------------------------------------
4 # File: measureit_main.py
5 # Main panel for different Measureit general actions
6 # Author: Antonio Vazquez (antonioya)
8 # ----------------------------------------------------------
9 # noinspection PyUnresolvedReferences
12 from bmesh
import from_edit_mesh
13 # noinspection PyUnresolvedReferences
14 from bpy
.types
import PropertyGroup
, Panel
, Object
, Operator
, SpaceView3D
15 from bpy
.props
import IntProperty
, CollectionProperty
, FloatVectorProperty
, BoolProperty
, StringProperty
, \
16 FloatProperty
, EnumProperty
17 from bpy
.app
.handlers
import persistent
18 # noinspection PyUnresolvedReferences
19 from .measureit_geometry
import *
20 from .measureit_render
import *
23 # ------------------------------------------------------
24 # Handler to detect new Blend load
26 # ------------------------------------------------------
27 # noinspection PyUnusedLocal
29 def load_handler(dummy
):
30 MEASUREIT_OT_RunHintDisplay
.handle_remove(None, bpy
.context
)
33 # ------------------------------------------------------
34 # Handler to detect save Blend
35 # Clear not used measured
37 # ------------------------------------------------------
38 # noinspection PyUnusedLocal
40 def save_handler(dummy
):
41 # noinspection PyBroadException
43 print("MeasureIt: Cleaning data")
44 objlist
= bpy
.context
.scene
.objects
46 if 'MeasureGenerator' in myobj
:
47 mp
= myobj
.MeasureGenerator
[0]
49 for ms
in mp
.measureit_segments
:
50 ms
.name
= "segment_" + str(x
)
53 idx
= mp
.measureit_segments
.find(ms
.name
)
55 print("MeasureIt: Removed segment not used")
56 mp
.measureit_segments
.remove(idx
)
59 mp
.measureit_num
= len(mp
.measureit_segments
)
64 bpy
.app
.handlers
.load_post
.append(load_handler
)
65 bpy
.app
.handlers
.save_pre
.append(save_handler
)
68 # ------------------------------------------------------------------
69 # Define property group class for measureit faces index
70 # ------------------------------------------------------------------
71 class MeasureitIndex(PropertyGroup
):
72 glidx
: IntProperty(name
="index", description
="vertex index")
76 bpy
.utils
.register_class(MeasureitIndex
)
79 # ------------------------------------------------------------------
80 # Define property group class for measureit faces
81 # ------------------------------------------------------------------
82 class MeasureitFaces(PropertyGroup
):
83 glface
: IntProperty(name
="glface", description
="Face number")
85 measureit_index
: CollectionProperty(type=MeasureitIndex
)
89 bpy
.utils
.register_class(MeasureitFaces
)
92 # ------------------------------------------------------------------
93 # Define property group class for measureit data
94 # ------------------------------------------------------------------
95 class MeasureitProperties(PropertyGroup
):
96 gltype
: IntProperty(name
="gltype",
97 description
="Measure type (1-Segment, 2-Label, etc..)", default
=1)
98 glpointa
: IntProperty(name
="glpointa",
99 description
="Hidden property for opengl")
100 glpointb
: IntProperty(name
="glpointb",
101 description
="Hidden property for opengl")
102 glpointc
: IntProperty(name
="glpointc",
103 description
="Hidden property for opengl")
104 glcolor
: FloatVectorProperty(name
="glcolor",
105 description
="Color for the measure",
106 default
=(0.173, 0.545, 1.0, 1.0),
111 glview
: BoolProperty(name
="glview",
112 description
="Measure visible/hide",
114 glspace
: FloatProperty(name
='glspace', min=-100, max=100, default
=0.1,
116 description
='Distance to display measure')
117 glwidth
: IntProperty(name
='glwidth', min=1, max=10, default
=1,
118 description
='line width')
119 glfree
: BoolProperty(name
="glfree",
120 description
="This measure is free and can be deleted",
122 gltxt
: StringProperty(name
="gltxt", maxlen
=256,
123 description
="Short description (use | for line break)")
124 gladvance
: BoolProperty(name
="gladvance",
125 description
="Advanced options as line width or position",
127 gldefault
: BoolProperty(name
="gldefault",
128 description
="Display measure in position calculated by default",
130 glnormalx
: FloatProperty(name
="glnormalx",
131 description
="Change orientation in X axis",
132 default
=1, min=-1, max=1, precision
=2)
133 glnormaly
: FloatProperty(name
="glnormaly",
134 description
="Change orientation in Y axis",
135 default
=0, min=-1, max=1, precision
=2)
136 glnormalz
: FloatProperty(name
="glnormalz",
137 description
="Change orientation in Z axis",
138 default
=0, min=-1, max=1, precision
=2)
139 glfont_size
: IntProperty(name
="Text Size",
140 description
="Text size",
141 default
=14, min=6, max=150)
142 glfont_align
: EnumProperty(items
=(('L', "Left Align", ""),
143 ('C', "Center Align", ""),
144 ('R', "Right Align", "")),
146 description
="Set Font Alignment")
147 glfont_rotat
: IntProperty(name
='Rotate', min=0, max=360, default
=0,
148 description
="Text rotation in degrees")
149 gllink
: StringProperty(name
="gllink",
150 description
="linked object for linked measures")
151 glocwarning
: BoolProperty(name
="glocwarning",
152 description
="Display a warning if some axis is not used in distance",
154 glocx
: BoolProperty(name
="glocx",
155 description
="Include changes in X axis for calculating the distance",
157 glocy
: BoolProperty(name
="glocy",
158 description
="Include changes in Y axis for calculating the distance",
160 glocz
: BoolProperty(name
="glocz",
161 description
="Include changes in Z axis for calculating the distance",
163 glfontx
: IntProperty(name
="glfontx",
164 description
="Change font position in X axis",
165 default
=0, min=-3000, max=3000)
166 glfonty
: IntProperty(name
="glfonty",
167 description
="Change font position in Y axis",
168 default
=0, min=-3000, max=3000)
169 gldist
: BoolProperty(name
="gldist",
170 description
="Display distance for this measure",
172 glnames
: BoolProperty(name
="glnames",
173 description
="Display text for this measure",
175 gltot
: EnumProperty(items
=(('99', "-", "Select a group for sum"),
203 description
="Add segment length in selected group")
204 glorto
: EnumProperty(items
=(('99', "None", ""),
205 ('0', "A", "Point A must use selected point B location"),
206 ('1', "B", "Point B must use selected point A location")),
208 description
="Display point selected as orthogonal (select axis to copy)")
209 glorto_x
: BoolProperty(name
="ox",
210 description
="Copy X location",
212 glorto_y
: BoolProperty(name
="oy",
213 description
="Copy Y location",
215 glorto_z
: BoolProperty(name
="oz",
216 description
="Copy Z location",
218 glarrow_a
: EnumProperty(items
=(('99', "--", "No arrow"),
219 ('1', "Line", "The point of the arrow are lines"),
220 ('2', "Triangle", "The point of the arrow is triangle"),
221 ('3', "TShape", "The point of the arrow is a T")),
223 description
="Add arrows to point A")
224 glarrow_b
: EnumProperty(items
=(('99', "--", "No arrow"),
225 ('1', "Line", "The point of the arrow are lines"),
226 ('2', "Triangle", "The point of the arrow is triangle"),
227 ('3', "TShape", "The point of the arrow is a T")),
229 description
="Add arrows to point B")
230 glarrow_s
: IntProperty(name
="Size",
231 description
="Arrow size",
232 default
=15, min=6, max=500)
234 glarc_full
: BoolProperty(name
="arcfull",
235 description
="Create full circumference",
237 glarc_extrad
: BoolProperty(name
="arcextrad",
238 description
="Adapt radio length to arc line",
240 glarc_rad
: BoolProperty(name
="arc rad",
241 description
="Show arc radius",
243 glarc_len
: BoolProperty(name
="arc len",
244 description
="Show arc length",
246 glarc_ang
: BoolProperty(name
="arc ang",
247 description
="Show arc angle",
250 glarc_a
: EnumProperty(items
=(('99', "--", "No arrow"),
251 ('1', "Line", "The point of the arrow are lines"),
252 ('2', "Triangle", "The point of the arrow is triangle"),
253 ('3', "TShape", "The point of the arrow is a T")),
255 description
="Add arrows to point A")
256 glarc_b
: EnumProperty(items
=(('99', "--", "No arrow"),
257 ('1', "Line", "The point of the arrow are lines"),
258 ('2', "Triangle", "The point of the arrow is triangle"),
259 ('3', "TShape", "The point of the arrow is a T")),
261 description
="Add arrows to point B")
262 glarc_s
: IntProperty(name
="Size",
263 description
="Arrow size",
264 default
=15, min=6, max=500)
265 glarc_txradio
: StringProperty(name
="txradio",
266 description
="Text for radius", default
="r=")
267 glarc_txlen
: StringProperty(name
="txlen",
268 description
="Text for length", default
="L=")
269 glarc_txang
: StringProperty(name
="txang",
270 description
="Text for angle", default
="A=")
271 glcolorarea
: FloatVectorProperty(name
="glcolorarea",
272 description
="Color for the measure of area",
273 default
=(0.1, 0.1, 0.1, 1.0),
280 measureit_faces
: CollectionProperty(type=MeasureitFaces
)
284 bpy
.utils
.register_class(MeasureitProperties
)
287 # ------------------------------------------------------------------
288 # Define object class (container of segments)
290 # ------------------------------------------------------------------
291 class MeasureContainer(PropertyGroup
):
292 measureit_num
: IntProperty(name
='Number of measures', min=0, max=1000, default
=0,
293 description
='Number total of measureit elements')
295 measureit_segments
: CollectionProperty(type=MeasureitProperties
)
298 bpy
.utils
.register_class(MeasureContainer
)
299 Object
.MeasureGenerator
= CollectionProperty(type=MeasureContainer
)
302 # ------------------------------------------------------------------
305 # ------------------------------------------------------------------
306 class MEASUREIT_PT_Edit(Panel
):
307 bl_idname
= "MEASUREIT_PT_Edit"
309 bl_space_type
= 'VIEW_3D'
310 bl_region_type
= 'UI'
312 bl_parent_id
= 'MEASUREIT_PT_Main'
314 # -----------------------------------------------------
316 # -----------------------------------------------------
318 def poll(cls
, context
):
322 if 'MeasureGenerator' not in o
:
325 mp
= context
.object.MeasureGenerator
[0]
326 if mp
.measureit_num
> 0:
331 # -----------------------------------------------------
332 # Draw (create UI interface)
333 # -----------------------------------------------------
334 # noinspection PyUnusedLocal
335 def draw(self
, context
):
337 scene
= context
.scene
338 if context
.object is not None:
339 if 'MeasureGenerator' in context
.object:
342 row
.label(text
=context
.object.name
)
344 row
.prop(scene
, 'measureit_gl_precision', text
="Precision")
345 row
.prop(scene
, 'measureit_units')
347 row
.prop(scene
, 'measureit_gl_show_d', text
="Distances", toggle
=True, icon
="ALIGN_CENTER")
348 row
.prop(scene
, 'measureit_gl_show_n', text
="Texts", toggle
=True, icon
="FONT_DATA")
350 row
.prop(scene
, 'measureit_hide_units', text
="Hide measurement unit")
353 row
.prop(scene
, 'measureit_scale', text
="Scale")
354 if scene
.measureit_scale
is True:
355 split
= row
.split(factor
=0.25, align
=False)
356 split
.prop(scene
, 'measureit_scale_color', text
="")
357 split
.prop(scene
, 'measureit_scale_factor', text
="1")
360 row
.prop(scene
, 'measureit_gl_scaletxt', text
="")
361 row
.prop(scene
, 'measureit_scale_font')
362 row
.prop(scene
, 'measureit_scale_precision', text
="")
365 row
.prop(scene
, 'measureit_scale_pos_x')
366 row
.prop(scene
, 'measureit_scale_pos_y')
370 row
.prop(scene
, 'measureit_ovr', text
="Override")
371 if scene
.measureit_ovr
is True:
372 split
= row
.split(factor
=0.25, align
=False)
373 split
.prop(scene
, 'measureit_ovr_color', text
="")
374 split
.prop(scene
, 'measureit_ovr_width', text
="Width")
377 row
.prop(scene
, 'measureit_ovr_font', text
="Font")
378 row
.prop(scene
, 'measureit_ovr_font_align', text
="")
379 if scene
.measureit_ovr_font_align
== 'L':
380 row
.prop(scene
, 'measureit_ovr_font_rotation', text
="Rotate")
382 mp
= context
.object.MeasureGenerator
[0]
386 if mp
.measureit_num
> 0:
388 row
= box
.row(align
=True)
389 row
.operator("measureit.expandallsegment", text
="Expand all", icon
="ZOOM_IN")
390 row
.operator("measureit.collapseallsegment", text
="Collapse all", icon
="ZOOM_OUT")
391 for idx
in range(mp
.measureit_num
):
392 if mp
.measureit_segments
[idx
].glfree
is False:
393 add_item(box
, idx
, mp
.measureit_segments
[idx
])
396 row
.operator("measureit.deleteallsegment", text
="Delete all", icon
="X")
400 if mp
.measureit_num
> 0:
401 scale
= bpy
.context
.scene
.unit_settings
.scale_length
402 tx
= ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
403 "T", "U", "V", "W", "X", "Y", "Z"]
404 tot
= [0.0] * len(tx
)
405 ac
= [False] * len(tx
)
406 myobj
= context
.object
407 obverts
= get_mesh_vertices(myobj
)
409 for idx
in range(mp
.measureit_num
):
410 ms
= mp
.measureit_segments
[idx
]
411 if (ms
.gltype
== 1 or ms
.gltype
== 12
412 or ms
.gltype
== 13 or ms
.gltype
== 14) and ms
.gltot
!= '99' \
413 and ms
.glfree
is False: # only segments
414 if bpy
.context
.mode
== "EDIT_MESH":
415 bm
= bmesh
.from_edit_mesh(bpy
.context
.edit_object
.data
)
416 if hasattr(bm
.verts
, "ensure_lookup_table"):
417 bm
.verts
.ensure_lookup_table()
418 if ms
.glpointa
<= len(obverts
) and ms
.glpointb
<= len(obverts
):
419 p1
= get_point(obverts
[ms
.glpointa
].co
, myobj
)
421 p2
= get_point(obverts
[ms
.glpointb
].co
, myobj
)
422 elif ms
.gltype
== 12:
424 obverts
[ms
.glpointa
].co
[1],
425 obverts
[ms
.glpointa
].co
[2]), myobj
)
426 elif ms
.gltype
== 13:
427 p2
= get_point((obverts
[ms
.glpointa
].co
[0],
429 obverts
[ms
.glpointa
].co
[2]), myobj
)
431 p2
= get_point((obverts
[ms
.glpointa
].co
[0],
432 obverts
[ms
.glpointa
].co
[1],
435 dist
, distloc
= distance(p1
, p2
, ms
.glocx
, ms
.glocy
, ms
.glocz
)
441 tot
[int(ms
.gltot
)] += usedist
442 ac
[int(ms
.gltot
)] = True
448 pr
= scene
.measureit_gl_precision
449 fmt
= "%1." + str(pr
) + "f"
450 units
= scene
.measureit_units
453 box
.label(text
="Totals", icon
='SOLO_ON')
455 for idx
in range(len(tot
)):
458 tx_dist
= format_distance(fmt
, units
, tot
[idx
])
459 row
= box
.row(align
=True)
460 row
.label(text
="Group " + tx
[idx
] + ":")
462 row
.label(text
=tx_dist
)
465 row
= box
.row(align
=True)
468 row
.label(text
="-" * 20)
469 tx_dist
= format_distance(fmt
, units
, final
)
471 row
= box
.row(align
=True)
474 row
.label(text
=tx_dist
)
477 row
.operator("measureit.deleteallsum", text
="Delete all", icon
="X")
480 # -----------------------------------------------------
481 # Add segment options to the panel.
482 # -----------------------------------------------------
483 def add_item(box
, idx
, segment
):
484 scene
= bpy
.context
.scene
485 row
= box
.row(align
=True)
486 if segment
.glview
is True:
491 row
.prop(segment
, 'glview', text
="", toggle
=True, icon
=icon
)
492 row
.prop(segment
, 'gladvance', text
="", toggle
=True, icon
="PREFERENCES")
493 if segment
.gltype
== 20: # Area special
494 split
= row
.split(factor
=0.15, align
=True)
495 split
.prop(segment
, 'glcolorarea', text
="")
496 split
= split
.split(factor
=0.20, align
=True)
497 split
.prop(segment
, 'glcolor', text
="")
499 split
= row
.split(factor
=0.25, align
=True)
500 split
.prop(segment
, 'glcolor', text
="")
501 split
.prop(segment
, 'gltxt', text
="")
502 op
= row
.operator("measureit.deletesegment", text
="", icon
="X")
503 op
.tag
= idx
# saves internal data
504 if segment
.gladvance
is True:
505 row
= box
.row(align
=True)
506 row
.prop(segment
, 'glfont_size', text
="Font")
507 row
.prop(segment
, 'glfont_align', text
="")
508 if segment
.glfont_align
== 'L':
509 row
.prop(segment
, 'glfont_rotat', text
="Rotate")
510 row
= box
.row(align
=True)
511 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
512 row
.prop(segment
, 'glspace', text
="Distance")
513 row
.prop(segment
, 'glfontx', text
="X")
514 row
.prop(segment
, 'glfonty', text
="Y")
517 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
518 row
= box
.row(align
=True)
519 row
.prop(segment
, 'glarrow_a', text
="")
520 row
.prop(segment
, 'glarrow_b', text
="")
521 if segment
.glarrow_a
!= '99' or segment
.glarrow_b
!= '99':
522 row
.prop(segment
, 'glarrow_s', text
="Size")
524 if segment
.gltype
!= 2 and segment
.gltype
!= 10:
525 row
= box
.row(align
=True)
526 if scene
.measureit_gl_show_d
is True and segment
.gltype
!= 9:
527 row
.prop(segment
, 'gldist', text
="Distance", toggle
=True, icon
="ALIGN_CENTER")
528 if scene
.measureit_gl_show_n
is True:
529 row
.prop(segment
, 'glnames', text
="Text", toggle
=True, icon
="FONT_DATA")
531 if segment
.gltype
== 1 or segment
.gltype
== 12 or segment
.gltype
== 13 or segment
.gltype
== 14:
532 row
.prop(segment
, 'gltot', text
="Sum")
534 if segment
.gltype
!= 9 and segment
.gltype
!= 10 and segment
.gltype
!= 20:
535 row
= box
.row(align
=True)
536 row
.prop(segment
, 'glwidth', text
="Line")
537 row
.prop(segment
, 'gldefault', text
="Automatic position")
538 if segment
.gldefault
is False:
539 row
= box
.row(align
=True)
540 row
.prop(segment
, 'glnormalx', text
="X")
541 row
.prop(segment
, 'glnormaly', text
="Y")
542 row
.prop(segment
, 'glnormalz', text
="Z")
545 if segment
.gltype
!= 2 and segment
.gltype
!= 9 and segment
.gltype
!= 10 \
546 and segment
.gltype
!= 11 and segment
.gltype
!= 12 and segment
.gltype
!= 13 \
547 and segment
.gltype
!= 14 and segment
.gltype
!= 20:
548 row
= box
.row(align
=True)
549 row
.prop(segment
, 'glocx', text
="X", toggle
=True)
550 row
.prop(segment
, 'glocy', text
="Y", toggle
=True)
551 row
.prop(segment
, 'glocz', text
="Z", toggle
=True)
552 if segment
.glocx
is False or segment
.glocy
is False or segment
.glocz
is False:
554 if segment
.gltype
== 1:
555 row
.prop(segment
, 'glorto', text
="Orthogonal")
556 row
.prop(segment
, 'glocwarning', text
="Warning")
557 # orthogonal (only segments)
558 if segment
.gltype
== 1:
559 if segment
.glorto
!= "99":
560 row
= box
.row(align
=True)
561 row
.prop(segment
, 'glorto_x', text
="X", toggle
=True)
562 row
.prop(segment
, 'glorto_y', text
="Y", toggle
=True)
563 row
.prop(segment
, 'glorto_z', text
="Z", toggle
=True)
566 if segment
.gltype
== 11:
567 row
= box
.row(align
=True)
568 row
.prop(segment
, 'glarc_rad', text
="Radius")
569 row
.prop(segment
, 'glarc_len', text
="Length")
570 row
.prop(segment
, 'glarc_ang', text
="Angle")
572 row
= box
.row(align
=True)
573 row
.prop(segment
, 'glarc_txradio', text
="")
574 row
.prop(segment
, 'glarc_txlen', text
="")
575 row
.prop(segment
, 'glarc_txang', text
="")
576 row
= box
.row(align
=True)
577 row
.prop(segment
, 'glarc_full', text
="Full Circle")
578 if segment
.glarc_rad
is True:
579 row
.prop(segment
, 'glarc_extrad', text
="Adapt radio")
581 row
= box
.row(align
=True)
582 row
.prop(segment
, 'glarc_a', text
="")
583 row
.prop(segment
, 'glarc_b', text
="")
584 if segment
.glarc_a
!= '99' or segment
.glarc_b
!= '99':
585 row
.prop(segment
, 'glarc_s', text
="Size")
588 # ------------------------------------------------------------------
589 # Define panel class for main functions.
590 # ------------------------------------------------------------------
591 class MEASUREIT_PT_Main(Panel
):
592 bl_idname
= "MEASUREIT_PT_Main"
593 bl_label
= "MeasureIt Tools"
594 bl_space_type
= 'VIEW_3D'
595 bl_region_type
= 'UI'
597 bl_options
= {'DEFAULT_CLOSED'}
599 # ------------------------------
601 # ------------------------------
602 def draw(self
, context
):
604 scene
= context
.scene
606 # ------------------------------
608 # ------------------------------
610 # ------------------------------
612 # ------------------------------
614 if context
.window_manager
.measureit_run_opengl
is False:
621 row
.operator("measureit.runopengl", text
=txt
, icon
=icon
)
622 row
.prop(scene
, "measureit_gl_ghost", text
="", icon
='GHOST_ENABLED')
626 box
.label(text
="Add Measures")
628 row
.operator("measureit.addsegment", text
="Segment")
629 row
.prop(scene
, "measureit_sum", text
="Sum")
633 op
= row
.operator("measureit.addsegmentorto", text
="X")
634 op
.tag
= 0 # saves internal data
635 op
= row
.operator("measureit.addsegmentorto", text
="Y")
636 op
.tag
= 1 # saves internal data
637 op
= row
.operator("measureit.addsegmentorto", text
="Z")
638 op
.tag
= 2 # saves internal data
641 row
.operator("measureit.addangle", text
="Angle", icon
="LINCURVE")
642 row
.operator("measureit.addarc", text
="Arc")
645 row
.operator("measureit.addlabel", text
="Label", icon
="FONT_DATA")
646 row
.operator("measureit.addnote", text
="Annotation")
649 row
.operator("measureit.addlink", text
="Link")
650 row
.operator("measureit.addorigin", text
="Origin")
653 row
.operator("measureit.addarea", text
="Area", icon
="MESH_GRID")
655 # ------------------------------
657 # ------------------------------
659 row
= box
.row(align
=False)
660 if scene
.measureit_debug
is False:
661 row
.prop(scene
, "measureit_debug", icon
="TRIA_RIGHT",
662 text
="Mesh Debug", emboss
=False)
664 row
.prop(scene
, "measureit_debug", icon
="TRIA_DOWN",
665 text
="Mesh Debug", emboss
=False)
668 split
= row
.split(factor
=0.10, align
=True)
669 split
.prop(scene
, 'measureit_debug_obj_color', text
="")
670 split
.prop(scene
, "measureit_debug_objects", icon
="OBJECT_DATA")
671 split
.prop(scene
, "measureit_debug_object_loc", icon
="EMPTY_DATA")
674 split
= row
.split(factor
=0.10, align
=True)
675 split
.prop(scene
, 'measureit_debug_vert_color', text
="")
676 split
.prop(scene
, "measureit_debug_vertices", icon
="VERTEXSEL")
677 split
.prop(scene
, "measureit_debug_vert_loc", icon
="EMPTY_DATA")
678 if scene
.measureit_debug_vert_loc
is True:
679 split
.prop(scene
, 'measureit_debug_vert_loc_toggle', text
="")
682 split
= row
.split(factor
=0.10, align
=True)
683 split
.prop(scene
, 'measureit_debug_edge_color', text
="")
684 split
= split
.split(factor
=0.5, align
=True)
685 split
.prop(scene
, "measureit_debug_edges", icon
="EDGESEL")
688 split
= row
.split(factor
=0.10, align
=True)
689 split
.prop(scene
, 'measureit_debug_face_color', text
="")
690 split
= split
.split(factor
=0.5, align
=True)
691 split
.prop(scene
, "measureit_debug_faces", icon
="FACESEL")
694 split
= row
.split(factor
=0.10, align
=True)
695 split
.prop(scene
, 'measureit_debug_norm_color', text
="")
696 if scene
.measureit_debug_normals
is False:
697 split
= split
.split(factor
=0.50, align
=True)
698 split
.prop(scene
, "measureit_debug_normals", icon
="OBJECT_ORIGIN")
700 split
= split
.split(factor
=0.5, align
=True)
701 split
.prop(scene
, "measureit_debug_normals", icon
="OBJECT_ORIGIN")
702 split
.prop(scene
, "measureit_debug_normal_size")
704 split
= row
.split(factor
=0.10, align
=True)
706 split
.prop(scene
, "measureit_debug_normal_details")
707 split
.prop(scene
, 'measureit_debug_width', text
="Thickness")
709 row
= box
.row(align
=True)
710 row
.prop(scene
, "measureit_debug_select", icon
="GHOST_ENABLED")
711 row
.prop(scene
, 'measureit_debug_font', text
="Font")
712 row
.prop(scene
, 'measureit_debug_precision', text
="Precision")
715 # ------------------------------------------------------------------
716 # Define panel class for conf functions.
717 # ------------------------------------------------------------------
718 class MEASUREIT_PT_Conf(Panel
):
719 bl_idname
= "MEASUREIT_PT_Conf"
720 bl_label
= "Configuration"
721 bl_space_type
= 'VIEW_3D'
722 bl_region_type
= 'UI'
724 bl_parent_id
= 'MEASUREIT_PT_Main'
725 bl_options
= {'DEFAULT_CLOSED'}
727 # ------------------------------
729 # ------------------------------
730 def draw(self
, context
):
732 scene
= context
.scene
737 split
= row
.split(factor
=0.2, align
=True)
738 split
.label(text
="Text")
739 split
= split
.split(factor
=0.2, align
=True)
740 split
.prop(scene
, "measureit_default_color", text
="")
741 split
.prop(scene
, "measureit_gl_txt", text
="")
742 row
= box
.row(align
=True)
743 row
.prop(scene
, "measureit_hint_space")
744 row
.prop(scene
, "measureit_font_align", text
="")
746 row
= box
.row(align
=True)
747 row
.prop(scene
, "measureit_glarrow_a", text
="")
748 row
.prop(scene
, "measureit_glarrow_b", text
="")
749 if scene
.measureit_glarrow_a
!= '99' or scene
.measureit_glarrow_b
!= '99':
750 row
.prop(scene
, "measureit_glarrow_s", text
="Size")
751 row
= box
.row(align
=True)
752 row
.prop(scene
, "measureit_font_size")
753 if scene
.measureit_font_align
== 'L':
754 row
.prop(scene
, "measureit_font_rotation", text
="Rotate")
757 # ------------------------------------------------------------------
758 # Define panel class for render functions.
759 # ------------------------------------------------------------------
760 class MEASUREIT_PT_Render(Panel
):
761 bl_idname
= "MEASUREIT_PT_Render"
763 bl_space_type
= 'VIEW_3D'
764 bl_region_type
= 'UI'
765 bl_category
= 'Display'
766 bl_parent_id
= 'MEASUREIT_PT_Main'
767 bl_options
= {'DEFAULT_CLOSED'}
769 # ------------------------------
771 # ------------------------------
772 def draw(self
, context
):
774 scene
= context
.scene
779 row
.prop(scene
, "measureit_render_type")
781 row
.operator("measureit.rendersegment", icon
='SCRIPT')
783 row
.prop(scene
, "measureit_render", text
="Save render image")
785 row
.prop(scene
, "measureit_rf", text
="Frame")
786 if scene
.measureit_rf
is True:
787 row
.prop(scene
, "measureit_rf_color", text
="Color")
789 row
.prop(scene
, "measureit_rf_border", text
="Space")
790 row
.prop(scene
, "measureit_rf_line", text
="Width")
793 # -------------------------------------------------------------
794 # Defines button that adds a measure segment
796 # -------------------------------------------------------------
797 class MEASUREIT_OT_AddSegment(Operator
):
798 bl_idname
= "measureit.addsegment"
800 bl_description
= "(EDITMODE only) Add a new measure segment between 2 vertices (select 2 vertices or more)"
802 # ------------------------------
804 # ------------------------------
806 def poll(cls
, context
):
812 if bpy
.context
.mode
== 'EDIT_MESH':
819 # ------------------------------
820 # Execute button action
821 # ------------------------------
822 def execute(self
, context
):
823 if context
.area
.type == 'VIEW_3D':
825 scene
= context
.scene
826 mainobject
= context
.object
827 mylist
= get_smart_selected(mainobject
)
828 if len(mylist
) < 2: # if not selected linked vertex
829 mylist
= get_selected_vertex(mainobject
)
832 if 'MeasureGenerator' not in mainobject
:
833 mainobject
.MeasureGenerator
.add()
835 mp
= mainobject
.MeasureGenerator
[0]
836 for x
in range(0, len(mylist
) - 1, 2):
837 # -----------------------
839 # -----------------------
840 if exist_segment(mp
, mylist
[x
], mylist
[x
+ 1]) is False:
841 # Create all array elements
842 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
843 mp
.measureit_segments
.add()
846 ms
= mp
.measureit_segments
[mp
.measureit_num
]
848 ms
.glpointa
= mylist
[x
]
849 ms
.glpointb
= mylist
[x
+ 1]
850 ms
.glarrow_a
= scene
.measureit_glarrow_a
851 ms
.glarrow_b
= scene
.measureit_glarrow_b
852 ms
.glarrow_s
= scene
.measureit_glarrow_s
854 ms
.glcolor
= scene
.measureit_default_color
856 ms
.glspace
= scene
.measureit_hint_space
858 ms
.gltxt
= scene
.measureit_gl_txt
859 ms
.glfont_size
= scene
.measureit_font_size
860 ms
.glfont_align
= scene
.measureit_font_align
861 ms
.glfont_rotat
= scene
.measureit_font_rotation
863 ms
.gltot
= scene
.measureit_sum
865 mp
.measureit_num
+= 1
868 context
.area
.tag_redraw()
871 self
.report({'ERROR'},
872 "MeasureIt: Select at least two vertices for creating measure segment.")
875 self
.report({'WARNING'},
876 "View3D not found, cannot run operator")
881 # -------------------------------------------------------------
882 # Defines button that adds an area measure
884 # -------------------------------------------------------------
885 class MEASUREIT_OT_AddArea(Operator
):
886 bl_idname
= "measureit.addarea"
888 bl_description
= "(EDITMODE only) Add a new measure for area (select 1 o more faces)"
890 # ------------------------------
892 # ------------------------------
894 def poll(cls
, context
):
900 if bpy
.context
.mode
== 'EDIT_MESH':
907 # ------------------------------
908 # Execute button action
909 # ------------------------------
910 def execute(self
, context
):
911 if context
.area
.type == 'VIEW_3D':
913 scene
= context
.scene
914 mainobject
= context
.object
915 mylist
= get_selected_faces(mainobject
)
917 if 'MeasureGenerator' not in mainobject
:
918 mainobject
.MeasureGenerator
.add()
920 mp
= mainobject
.MeasureGenerator
[0]
921 mp
.measureit_segments
.add()
922 ms
= mp
.measureit_segments
[mp
.measureit_num
]
927 # Create array elements
928 ms
.measureit_faces
.add()
931 mf
= ms
.measureit_faces
[f
]
935 mf
.measureit_index
.add()
936 mi
= mf
.measureit_index
[i
]
941 rgb
= scene
.measureit_default_color
942 ms
.glcolor
= (rgb
[0], rgb
[1], rgb
[2], 0.4)
944 ms
.glspace
= scene
.measureit_hint_space
946 ms
.gltxt
= scene
.measureit_gl_txt
947 ms
.glfont_size
= scene
.measureit_font_size
948 ms
.glfont_align
= scene
.measureit_font_align
949 ms
.glfont_rotat
= scene
.measureit_font_rotation
951 ms
.gltot
= scene
.measureit_sum
953 mp
.measureit_num
+= 1
955 context
.area
.tag_redraw()
958 self
.report({'ERROR'},
959 "MeasureIt: Select at least one face for creating area measure. ")
962 self
.report({'WARNING'},
963 "View3D not found, cannot run operator")
968 # -------------------------------------------------------------
969 # Defines button that adds a measure segment to x/y/z origin
971 # -------------------------------------------------------------
972 class MEASUREIT_OT_AddSegmentOrto(Operator
):
973 bl_idname
= "measureit.addsegmentorto"
975 bl_description
= "(EDITMODE only) Add a new measure segment from vertex to object origin for one " \
976 "axis (select 1 vertex)"
979 # ------------------------------
981 # ------------------------------
983 def poll(cls
, context
):
989 if bpy
.context
.mode
== 'EDIT_MESH':
996 # ------------------------------
997 # Execute button action
998 # ------------------------------
999 def execute(self
, context
):
1000 if context
.area
.type == 'VIEW_3D':
1002 scene
= context
.scene
1003 mainobject
= context
.object
1004 mylist
= get_smart_selected(mainobject
)
1005 if len(mylist
) < 1: # if not selected linked vertex
1006 mylist
= get_selected_vertex(mainobject
)
1008 if len(mylist
) >= 1:
1009 if 'MeasureGenerator' not in mainobject
:
1010 mainobject
.MeasureGenerator
.add()
1012 mp
= mainobject
.MeasureGenerator
[0]
1013 for x
in range(len(mylist
)):
1014 # -----------------------
1016 # -----------------------
1017 if exist_segment(mp
, mylist
[x
], mylist
[x
], 12 + int(self
.tag
)) is False:
1018 # Create all array elements
1019 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1020 mp
.measureit_segments
.add()
1023 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1024 ms
.gltype
= 12 + int(self
.tag
)
1025 ms
.glpointa
= mylist
[x
]
1026 ms
.glpointb
= mylist
[x
]
1027 ms
.glarrow_a
= scene
.measureit_glarrow_a
1028 ms
.glarrow_b
= scene
.measureit_glarrow_b
1029 ms
.glarrow_s
= scene
.measureit_glarrow_s
1031 ms
.glcolor
= scene
.measureit_default_color
1033 ms
.glspace
= scene
.measureit_hint_space
1035 ms
.gltxt
= scene
.measureit_gl_txt
1036 ms
.glfont_size
= scene
.measureit_font_size
1037 ms
.glfont_align
= scene
.measureit_font_align
1038 ms
.glfont_rotat
= scene
.measureit_font_rotation
1040 ms
.gltot
= scene
.measureit_sum
1042 mp
.measureit_num
+= 1
1045 context
.area
.tag_redraw()
1048 self
.report({'ERROR'},
1049 "MeasureIt: Select at least one vertex for creating measure segment.")
1052 self
.report({'WARNING'},
1053 "View3D not found, cannot run operator")
1055 return {'CANCELLED'}
1058 # -------------------------------------------------------------
1059 # Defines button that adds an angle measure
1061 # -------------------------------------------------------------
1062 class MEASUREIT_OT_AddAngle(Operator
):
1063 bl_idname
= "measureit.addangle"
1065 bl_description
= "(EDITMODE only) Add a new angle measure (select 3 vertices, 2nd is angle vertex)"
1067 # ------------------------------
1069 # ------------------------------
1071 def poll(cls
, context
):
1076 if o
.type == "MESH":
1077 if bpy
.context
.mode
== 'EDIT_MESH':
1084 # ------------------------------
1085 # Execute button action
1086 # ------------------------------
1087 def execute(self
, context
):
1088 if context
.area
.type == 'VIEW_3D':
1090 scene
= context
.scene
1091 mainobject
= context
.object
1092 mylist
= get_selected_vertex_history(mainobject
)
1093 if len(mylist
) == 3:
1094 if 'MeasureGenerator' not in mainobject
:
1095 mainobject
.MeasureGenerator
.add()
1097 mp
= mainobject
.MeasureGenerator
[0]
1098 # -----------------------
1100 # -----------------------
1101 if exist_segment(mp
, mylist
[0], mylist
[1], 9, mylist
[2]) is False:
1102 # Create all array elements
1103 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1104 mp
.measureit_segments
.add()
1107 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1109 ms
.glpointa
= mylist
[0]
1110 ms
.glpointb
= mylist
[1]
1111 ms
.glpointc
= mylist
[2]
1113 ms
.glcolor
= scene
.measureit_default_color
1115 ms
.glspace
= scene
.measureit_hint_space
1117 ms
.gltxt
= scene
.measureit_gl_txt
1118 ms
.glfont_size
= scene
.measureit_font_size
1119 ms
.glfont_align
= scene
.measureit_font_align
1120 ms
.glfont_rotat
= scene
.measureit_font_rotation
1122 mp
.measureit_num
+= 1
1125 context
.area
.tag_redraw()
1128 self
.report({'ERROR'},
1129 "MeasureIt: Select three vertices for creating angle measure")
1132 self
.report({'WARNING'},
1133 "View3D not found, cannot run operator")
1135 return {'CANCELLED'}
1138 # -------------------------------------------------------------
1139 # Defines button that adds an arc measure
1141 # -------------------------------------------------------------
1142 class MEASUREIT_OT_AddArc(Operator
):
1143 bl_idname
= "measureit.addarc"
1145 bl_description
= "(EDITMODE only) Add a new arc measure (select 3 vertices of the arc," \
1146 " vertices 1st and 3rd are arc extremes)"
1148 # ------------------------------
1150 # ------------------------------
1152 def poll(cls
, context
):
1157 if o
.type == "MESH":
1158 if bpy
.context
.mode
== 'EDIT_MESH':
1165 # ------------------------------
1166 # Execute button action
1167 # ------------------------------
1168 def execute(self
, context
):
1169 if context
.area
.type == 'VIEW_3D':
1171 scene
= context
.scene
1172 mainobject
= context
.object
1173 mylist
= get_selected_vertex_history(mainobject
)
1174 if len(mylist
) == 3:
1175 if 'MeasureGenerator' not in mainobject
:
1176 mainobject
.MeasureGenerator
.add()
1178 mp
= mainobject
.MeasureGenerator
[0]
1179 # -----------------------
1181 # -----------------------
1182 if exist_segment(mp
, mylist
[0], mylist
[1], 11, mylist
[2]) is False:
1183 # Create all array elements
1184 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1185 mp
.measureit_segments
.add()
1188 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1190 ms
.glpointa
= mylist
[0]
1191 ms
.glpointb
= mylist
[1]
1192 ms
.glpointc
= mylist
[2]
1193 ms
.glarrow_a
= scene
.measureit_glarrow_a
1194 ms
.glarrow_b
= scene
.measureit_glarrow_b
1195 ms
.glarrow_s
= scene
.measureit_glarrow_s
1197 ms
.glcolor
= scene
.measureit_default_color
1199 ms
.glspace
= scene
.measureit_hint_space
1201 ms
.gltxt
= scene
.measureit_gl_txt
1202 ms
.glfont_size
= scene
.measureit_font_size
1203 ms
.glfont_align
= scene
.measureit_font_align
1204 ms
.glfont_rotat
= scene
.measureit_font_rotation
1206 mp
.measureit_num
+= 1
1209 context
.area
.tag_redraw()
1212 self
.report({'ERROR'},
1213 "MeasureIt: Select three vertices for creating arc measure")
1216 self
.report({'WARNING'},
1217 "View3D not found, cannot run operator")
1219 return {'CANCELLED'}
1222 # -------------------------------------------------------------
1223 # Defines button that adds a label segment
1225 # -------------------------------------------------------------
1226 class MEASUREIT_OT_AddLabel(Operator
):
1227 bl_idname
= "measureit.addlabel"
1229 bl_description
= "(EDITMODE only) Add a new measure label (select 1 vertex)"
1231 # ------------------------------
1233 # ------------------------------
1235 def poll(cls
, context
):
1240 if o
.type == "MESH":
1241 if bpy
.context
.mode
== 'EDIT_MESH':
1248 # ------------------------------
1249 # Execute button action
1250 # ------------------------------
1251 def execute(self
, context
):
1252 if context
.area
.type == 'VIEW_3D':
1254 scene
= context
.scene
1255 mainobject
= context
.object
1256 mylist
= get_selected_vertex(mainobject
)
1257 if len(mylist
) == 1:
1258 if 'MeasureGenerator' not in mainobject
:
1259 mainobject
.MeasureGenerator
.add()
1261 mp
= mainobject
.MeasureGenerator
[0]
1262 # -----------------------
1264 # -----------------------
1265 if exist_segment(mp
, mylist
[0], mylist
[0], 2) is False: # Both equal
1266 # Create all array elements
1267 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1268 mp
.measureit_segments
.add()
1271 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1273 ms
.glpointa
= mylist
[0]
1274 ms
.glpointb
= mylist
[0] # Equal
1275 ms
.glarrow_a
= scene
.measureit_glarrow_a
1276 ms
.glarrow_b
= scene
.measureit_glarrow_b
1277 ms
.glarrow_s
= scene
.measureit_glarrow_s
1279 ms
.glcolor
= scene
.measureit_default_color
1281 ms
.glspace
= scene
.measureit_hint_space
1283 ms
.gltxt
= scene
.measureit_gl_txt
1284 ms
.glfont_size
= scene
.measureit_font_size
1285 ms
.glfont_align
= scene
.measureit_font_align
1286 ms
.glfont_rotat
= scene
.measureit_font_rotation
1288 mp
.measureit_num
+= 1
1291 context
.area
.tag_redraw()
1294 self
.report({'ERROR'},
1295 "MeasureIt: Select one vertex for creating measure label")
1298 self
.report({'WARNING'},
1299 "View3D not found, cannot run operator")
1301 return {'CANCELLED'}
1304 # -------------------------------------------------------------
1305 # Defines button that adds a link
1307 # -------------------------------------------------------------
1308 class MEASUREIT_OT_AddLink(Operator
):
1309 bl_idname
= "measureit.addlink"
1311 bl_description
= "(OBJECT mode only) Add a new measure between objects (select 2 " \
1312 "objects and optionally 1 or 2 vertices)"
1314 # ------------------------------
1316 # ------------------------------
1318 def poll(cls
, context
):
1323 if o
.type == "MESH" or o
.type == "EMPTY" or o
.type == "CAMERA" or o
.type == "LIGHT":
1324 if bpy
.context
.mode
== 'OBJECT':
1331 # ------------------------------
1332 # Execute button action
1333 # ------------------------------
1334 def execute(self
, context
):
1335 if context
.area
.type == 'VIEW_3D':
1336 scene
= context
.scene
1337 mainobject
= context
.object
1338 # -------------------------------
1339 # Verify number of objects
1340 # -------------------------------
1341 if len(context
.selected_objects
) != 2:
1342 self
.report({'ERROR'},
1343 "MeasureIt: Select two objects only, and optionally 1 vertex or 2 vertices "
1344 "(one of each object)")
1346 # Locate other object
1348 for o
in context
.selected_objects
:
1349 if o
.name
!= mainobject
.name
:
1351 # Verify destination vertex
1352 lkobj
= bpy
.data
.objects
[linkobject
]
1353 mylinkvertex
= get_selected_vertex(lkobj
)
1354 if len(mylinkvertex
) > 1:
1355 self
.report({'ERROR'},
1356 "MeasureIt: The destination object has more than one vertex selected. "
1357 "Select only 1 or none")
1359 # Verify origin vertex
1360 myobjvertex
= get_selected_vertex(mainobject
)
1361 if len(mylinkvertex
) > 1:
1362 self
.report({'ERROR'},
1363 "MeasureIt: The active object has more than one vertex selected. Select only 1 or none")
1366 # -------------------------------
1368 # -------------------------------
1370 if 'MeasureGenerator' not in mainobject
:
1371 mainobject
.MeasureGenerator
.add()
1373 mp
= mainobject
.MeasureGenerator
[0]
1375 # if exist_segment(mp, mylist[0], mylist[0], 3) is False:
1377 # Create all array elements
1378 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1379 mp
.measureit_segments
.add()
1382 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1383 # -----------------------
1385 # -----------------------
1386 if len(myobjvertex
) == 1 and len(mylinkvertex
) == 1:
1388 ms
.glpointa
= myobjvertex
[0]
1389 ms
.glpointb
= mylinkvertex
[0]
1391 # -----------------------
1393 # -----------------------
1394 if len(myobjvertex
) == 1 and len(mylinkvertex
) == 0:
1396 ms
.glpointa
= myobjvertex
[0]
1399 # -----------------------
1401 # -----------------------
1402 if len(myobjvertex
) == 0 and len(mylinkvertex
) == 1:
1405 ms
.glpointb
= mylinkvertex
[0]
1407 # -----------------------
1409 # -----------------------
1410 if len(myobjvertex
) == 0 and len(mylinkvertex
) == 0:
1413 ms
.glpointb
= 0 # Equal
1416 # ------------------
1418 # ------------------
1420 ms
.glarrow_a
= scene
.measureit_glarrow_a
1421 ms
.glarrow_b
= scene
.measureit_glarrow_b
1422 ms
.glarrow_s
= scene
.measureit_glarrow_s
1424 ms
.glcolor
= scene
.measureit_default_color
1426 ms
.glspace
= scene
.measureit_hint_space
1428 ms
.gltxt
= scene
.measureit_gl_txt
1429 ms
.glfont_size
= scene
.measureit_font_size
1430 ms
.glfont_align
= scene
.measureit_font_align
1431 ms
.glfont_rotat
= scene
.measureit_font_rotation
1433 ms
.gllink
= linkobject
1435 mp
.measureit_num
+= 1
1437 # -----------------------
1439 # -----------------------
1441 context
.area
.tag_redraw()
1444 self
.report({'WARNING'},
1445 "View3D not found, cannot run operator")
1447 return {'CANCELLED'}
1450 # -------------------------------------------------------------
1451 # Defines button that adds an origin segment
1453 # -------------------------------------------------------------
1454 class MEASUREIT_OT_AddOrigin(Operator
):
1455 bl_idname
= "measureit.addorigin"
1457 bl_description
= "(OBJECT mode only) Add a new measure to origin (select object and optionally 1 vertex)"
1459 # ------------------------------
1461 # ------------------------------
1463 def poll(cls
, context
):
1468 if o
.type == "MESH" or o
.type == "EMPTY" or o
.type == "CAMERA" or o
.type == "LIGHT":
1469 if bpy
.context
.mode
== 'OBJECT':
1476 # ------------------------------
1477 # Execute button action
1478 # ------------------------------
1479 def execute(self
, context
):
1480 if context
.area
.type == 'VIEW_3D':
1482 scene
= context
.scene
1483 mainobject
= context
.object
1484 mylist
= get_selected_vertex(mainobject
)
1485 if 'MeasureGenerator' not in mainobject
:
1486 mainobject
.MeasureGenerator
.add()
1488 mp
= mainobject
.MeasureGenerator
[0]
1489 # Create all array elements
1490 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1491 mp
.measureit_segments
.add()
1493 # -----------------------
1495 # -----------------------
1496 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1499 if len(mylist
) == 1:
1500 if exist_segment(mp
, mylist
[0], mylist
[0], 6) is False: # Both equal
1504 ms
.glpointa
= mylist
[0]
1505 ms
.glpointb
= mylist
[0]
1507 self
.report({'ERROR'},
1508 "MeasureIt: Enter in EDITMODE and select one vertex only for creating "
1509 "measure from vertex to origin")
1513 if exist_segment(mp
, 0, 0, 7) is False: # Both equal
1518 # ------------------
1520 # ------------------
1522 ms
.glarrow_a
= scene
.measureit_glarrow_a
1523 ms
.glarrow_b
= scene
.measureit_glarrow_b
1524 ms
.glarrow_s
= scene
.measureit_glarrow_s
1526 ms
.glcolor
= scene
.measureit_default_color
1528 ms
.glspace
= scene
.measureit_hint_space
1530 ms
.gltxt
= scene
.measureit_gl_txt
1531 ms
.glfont_size
= scene
.measureit_font_size
1532 ms
.glfont_align
= scene
.measureit_font_align
1533 ms
.glfont_rotat
= scene
.measureit_font_rotation
1535 mp
.measureit_num
+= 1
1538 context
.area
.tag_redraw()
1542 self
.report({'WARNING'},
1543 "View3D not found, cannot run operator")
1545 return {'CANCELLED'}
1548 # -------------------------------------------------------------
1549 # Defines button that deletes a measure segment
1551 # -------------------------------------------------------------
1552 class MEASUREIT_OT_DeleteSegment(Operator
):
1553 bl_idname
= "measureit.deletesegment"
1555 bl_description
= "Delete a measure"
1558 # ------------------------------
1559 # Execute button action
1560 # ------------------------------
1561 def execute(self
, context
):
1562 if context
.area
.type == 'VIEW_3D':
1564 mainobject
= context
.object
1565 mp
= mainobject
.MeasureGenerator
[0]
1566 ms
= mp
.measureit_segments
[self
.tag
]
1569 mp
.measureit_segments
.remove(self
.tag
)
1570 mp
.measureit_num
-= 1
1572 context
.area
.tag_redraw()
1575 self
.report({'WARNING'},
1576 "View3D not found, cannot run operator")
1578 return {'CANCELLED'}
1581 # -------------------------------------------------------------
1582 # Defines button that deletes all measure segments
1584 # -------------------------------------------------------------
1585 class MEASUREIT_OT_DeleteAllSegment(Operator
):
1586 bl_idname
= "measureit.deleteallsegment"
1588 bl_description
= "Delete all measures (it cannot be undone)"
1591 # ------------------------------
1592 # Execute button action
1593 # ------------------------------
1594 def execute(self
, context
):
1595 if context
.area
.type == 'VIEW_3D':
1597 mainobject
= context
.object
1598 mp
= mainobject
.MeasureGenerator
[0]
1600 while len(mp
.measureit_segments
) > 0:
1601 mp
.measureit_segments
.remove(0)
1604 mp
.measureit_num
= len(mp
.measureit_segments
)
1606 context
.area
.tag_redraw()
1609 self
.report({'WARNING'},
1610 "View3D not found, cannot run operator")
1612 return {'CANCELLED'}
1615 # -------------------------------------------------------------
1616 # Defines button that deletes all measure segment sums
1618 # -------------------------------------------------------------
1619 class MEASUREIT_OT_DeleteAllSum(Operator
):
1620 bl_idname
= "measureit.deleteallsum"
1622 bl_description
= "Delete all sum groups"
1625 # ------------------------------
1626 # Execute button action
1627 # ------------------------------
1628 # noinspection PyMethodMayBeStatic
1629 def execute(self
, context
):
1630 if context
.object is not None:
1631 if 'MeasureGenerator' in context
.object:
1632 mp
= context
.object.MeasureGenerator
[0]
1633 for idx
in range(mp
.measureit_num
):
1634 ms
= mp
.measureit_segments
[idx
]
1640 # -------------------------------------------------------------
1641 # Defines button that expands all measure segments
1643 # -------------------------------------------------------------
1644 class MEASUREIT_OT_ExpandAllSegment(Operator
):
1645 bl_idname
= "measureit.expandallsegment"
1647 bl_description
= "Expand all measure properties"
1650 # ------------------------------
1651 # Execute button action
1652 # ------------------------------
1653 def execute(self
, context
):
1654 if context
.area
.type == 'VIEW_3D':
1656 mainobject
= context
.object
1657 mp
= mainobject
.MeasureGenerator
[0]
1659 for i
in mp
.measureit_segments
:
1664 self
.report({'WARNING'},
1665 "View3D not found, cannot run operator")
1667 return {'CANCELLED'}
1670 # -------------------------------------------------------------
1671 # Defines button that collapses all measure segments
1673 # -------------------------------------------------------------
1674 class MEASUREIT_OT_CollapseAllSegment(Operator
):
1675 bl_idname
= "measureit.collapseallsegment"
1676 bl_label
= "Collapse"
1677 bl_description
= "Collapses all measure properties"
1680 # ------------------------------
1681 # Execute button action
1682 # ------------------------------
1683 def execute(self
, context
):
1684 if context
.area
.type == 'VIEW_3D':
1686 mainobject
= context
.object
1687 mp
= mainobject
.MeasureGenerator
[0]
1689 for i
in mp
.measureit_segments
:
1694 self
.report({'WARNING'},
1695 "View3D not found, cannot run operator")
1697 return {'CANCELLED'}
1700 # -------------------------------------------------------------
1701 # Defines button for render option
1703 # -------------------------------------------------------------
1704 class MEASUREIT_OT_RenderSegment(Operator
):
1705 bl_idname
= "measureit.rendersegment"
1707 bl_description
= "Create a render image with measures. Use UV/Image editor to view image generated"
1710 # ------------------------------
1711 # Execute button action
1712 # ------------------------------
1713 # noinspection PyMethodMayBeStatic,PyUnusedLocal
1714 def execute(self
, context
):
1715 scene
= context
.scene
1716 msg
= "New image created with measures. Open it in UV/image editor"
1717 camera_msg
= "Unable to render. No camera found"
1718 # -----------------------------
1720 # -----------------------------
1721 if scene
.camera
is None:
1722 self
.report({'ERROR'}, camera_msg
)
1724 # -----------------------------
1726 # -----------------------------
1727 if scene
.measureit_render_type
== "1":
1728 # noinspection PyBroadException
1729 if render_main(self
, context
) is True:
1730 self
.report({'INFO'}, msg
)
1731 # -----------------------------
1733 # -----------------------------
1734 if scene
.measureit_render_type
== "2":
1735 oldframe
= scene
.frame_current
1738 for frm
in range(scene
.frame_start
, scene
.frame_end
+ 1):
1739 scene
.frame_set(frm
)
1740 print("MeasureIt: Rendering frame %04d" % frm
)
1741 flag
= render_main(self
, context
, True)
1745 scene
.frame_current
= oldframe
1747 self
.report({'INFO'}, msg
)
1751 # ---------------------
1753 # ---------------------
1754 # noinspection PyMethodMayBeStatic
1755 def set_camera_view(self
):
1756 for area
in bpy
.context
.screen
.areas
:
1757 if area
.type == 'VIEW_3D':
1758 area
.spaces
[0].region_3d
.view_perspective
= 'CAMERA'
1760 # -------------------------------------
1761 # Set only render status
1762 # -------------------------------------
1763 # noinspection PyMethodMayBeStatic
1764 def set_only_render(self
, status
):
1765 screen
= bpy
.context
.screen
1769 # get spaceview_3d in current screen
1770 for a
in screen
.areas
:
1771 if a
.type == 'VIEW_3D':
1773 if s
.type == 'VIEW_3D':
1777 if v3d
is not False:
1778 s
.show_only_render
= status
1781 # -------------------------------------------------------------
1782 # Defines a new note
1784 # -------------------------------------------------------------
1785 class MEASUREIT_OT_AddNote(Operator
):
1786 bl_idname
= "measureit.addnote"
1788 bl_description
= "(OBJECT mode only) Add a new annotation"
1791 # ------------------------------
1793 # ------------------------------
1794 # noinspection PyUnusedLocal
1796 def poll(cls
, context
):
1797 if bpy
.context
.mode
== 'OBJECT':
1802 # ------------------------------
1803 # Execute button action
1804 # ------------------------------
1805 def execute(self
, context
):
1806 if context
.area
.type == 'VIEW_3D':
1807 bpy
.ops
.object.empty_add(type='PLAIN_AXES')
1808 myempty
= bpy
.data
.objects
[bpy
.context
.active_object
.name
]
1809 myempty
.location
= bpy
.context
.scene
.cursor
.location
1810 myempty
.empty_display_size
= 0.01
1811 myempty
.name
= "Annotation"
1813 scene
= context
.scene
1814 mainobject
= myempty
1815 if 'MeasureGenerator' not in mainobject
:
1816 mainobject
.MeasureGenerator
.add()
1818 mp
= mainobject
.MeasureGenerator
[0]
1819 # Create all array elements
1820 for cont
in range(len(mp
.measureit_segments
) - 1, mp
.measureit_num
):
1821 mp
.measureit_segments
.add()
1824 ms
= mp
.measureit_segments
[mp
.measureit_num
]
1827 ms
.glpointb
= 0 # Equal
1829 ms
.glcolor
= scene
.measureit_default_color
1831 ms
.glspace
= scene
.measureit_hint_space
1833 ms
.gltxt
= scene
.measureit_gl_txt
1834 ms
.glfont_size
= scene
.measureit_font_size
1835 ms
.glfont_align
= scene
.measureit_font_align
1836 ms
.glfont_rotat
= scene
.measureit_font_rotation
1838 mp
.measureit_num
+= 1
1841 context
.area
.tag_redraw()
1844 self
.report({'WARNING'},
1845 "View3D not found, cannot run operator")
1847 return {'CANCELLED'}
1850 # -------------------------------------------------------------
1851 # Defines button that enables/disables the tip display
1853 # -------------------------------------------------------------
1854 class MEASUREIT_OT_RunHintDisplay(Operator
):
1855 bl_idname
= "measureit.runopengl"
1856 bl_label
= "Display hint data manager"
1857 bl_description
= "Main control for enabling or disabling the display of measurements in the viewport"
1859 _handle
= None # keep function handler
1861 # ----------------------------------
1862 # Enable gl drawing adding handler
1863 # ----------------------------------
1865 def handle_add(self
, context
):
1866 if MEASUREIT_OT_RunHintDisplay
._handle
is None:
1867 MEASUREIT_OT_RunHintDisplay
._handle
= SpaceView3D
.draw_handler_add(draw_callback_px
, (self
, context
),
1870 context
.window_manager
.measureit_run_opengl
= True
1872 # ------------------------------------
1873 # Disable gl drawing removing handler
1874 # ------------------------------------
1875 # noinspection PyUnusedLocal
1877 def handle_remove(self
, context
):
1878 if MEASUREIT_OT_RunHintDisplay
._handle
is not None:
1879 SpaceView3D
.draw_handler_remove(MEASUREIT_OT_RunHintDisplay
._handle
, 'WINDOW')
1880 MEASUREIT_OT_RunHintDisplay
._handle
= None
1881 context
.window_manager
.measureit_run_opengl
= False
1883 # ------------------------------
1884 # Execute button action
1885 # ------------------------------
1886 def execute(self
, context
):
1887 if context
.area
.type == 'VIEW_3D':
1888 if context
.window_manager
.measureit_run_opengl
is False:
1889 self
.handle_add(self
, context
)
1890 context
.area
.tag_redraw()
1892 self
.handle_remove(self
, context
)
1893 context
.area
.tag_redraw()
1897 self
.report({'WARNING'},
1898 "View3D not found, cannot run operator")
1900 return {'CANCELLED'}
1903 # -------------------------------------------------------------
1904 # Handle all draw routines (OpenGL main entry point)
1906 # -------------------------------------------------------------
1907 def draw_main(context
):
1908 region
= bpy
.context
.region
1909 # Detect if Quadview to get drawing area
1910 if not context
.space_data
.region_quadviews
:
1911 rv3d
= bpy
.context
.space_data
.region_3d
1914 if context
.area
.type != 'VIEW_3D' or context
.space_data
.type != 'VIEW_3D':
1917 for region
in context
.area
.regions
:
1918 if region
.type == 'WINDOW':
1920 if context
.region
.id == region
.id:
1925 rv3d
= context
.space_data
.region_quadviews
[i
]
1927 scene
= bpy
.context
.scene
1929 # Display selected or all
1930 if scene
.measureit_gl_ghost
is False:
1931 objlist
= context
.selected_objects
1933 objlist
= context
.view_layer
.objects
1936 gpu
.state
.blend_set('ALPHA')
1937 # ---------------------------------------
1938 # Generate all OpenGL calls for measures
1939 # ---------------------------------------
1940 for myobj
in objlist
:
1941 if myobj
.visible_get() is True:
1942 if 'MeasureGenerator' in myobj
:
1943 op
= myobj
.MeasureGenerator
[0]
1944 draw_segments(context
, myobj
, op
, region
, rv3d
)
1946 # ---------------------------------------
1947 # Generate all OpenGL calls for debug
1948 # ---------------------------------------
1949 if scene
.measureit_debug
is True:
1950 selobj
= bpy
.context
.selected_objects
1951 for myobj
in selobj
:
1952 if scene
.measureit_debug_objects
is True:
1953 draw_object(context
, myobj
, region
, rv3d
)
1954 elif scene
.measureit_debug_object_loc
is True:
1955 draw_object(context
, myobj
, region
, rv3d
)
1956 if scene
.measureit_debug_vertices
is True:
1957 draw_vertices(context
, myobj
, region
, rv3d
)
1958 elif scene
.measureit_debug_vert_loc
is True:
1959 draw_vertices(context
, myobj
, region
, rv3d
)
1960 if scene
.measureit_debug_edges
is True:
1961 draw_edges(context
, myobj
, region
, rv3d
)
1962 if scene
.measureit_debug_faces
is True or scene
.measureit_debug_normals
is True:
1963 draw_faces(context
, myobj
, region
, rv3d
)
1965 # -----------------------
1967 # -----------------------
1968 gpu
.state
.blend_set('NONE')
1971 # -------------------------------------------------------------
1972 # Handler for drawing OpenGl
1973 # -------------------------------------------------------------
1974 # noinspection PyUnusedLocal
1975 def draw_callback_px(self
, context
):
1979 # -------------------------------------------------------------
1980 # Check if the segment already exist
1982 # -------------------------------------------------------------
1983 def exist_segment(mp
, pointa
, pointb
, typ
=1, pointc
=None):
1984 # for ms in mp.measureit_segments[mp.measureit_num]
1985 for ms
in mp
.measureit_segments
:
1986 if ms
.gltype
== typ
and ms
.glfree
is False:
1988 if ms
.glpointa
== pointa
and ms
.glpointb
== pointb
:
1990 if ms
.glpointa
== pointb
and ms
.glpointb
== pointa
:
1993 if ms
.glpointa
== pointa
and ms
.glpointb
== pointb
and ms
.glpointc
== pointc
:
1999 # -------------------------------------------------------------
2000 # Get vertex selected
2001 # -------------------------------------------------------------
2002 def get_selected_vertex(myobject
):
2004 # if not mesh, no vertex
2005 if myobject
.type != "MESH":
2007 # --------------------
2009 # --------------------
2010 oldobj
= bpy
.context
.object
2011 bpy
.context
.view_layer
.objects
.active
= myobject
2013 if myobject
.mode
!= 'EDIT':
2014 bpy
.ops
.object.mode_set(mode
='EDIT')
2017 bm
= from_edit_mesh(myobject
.data
)
2021 mylist
.append(v
.index
)
2024 bpy
.ops
.object.editmode_toggle()
2025 # Back context object
2026 bpy
.context
.view_layer
.objects
.active
= oldobj
2028 # if select all vertices, then use origin
2029 if tv
== len(mylist
):
2035 # -------------------------------------------------------------
2036 # Get vertex selected
2037 # -------------------------------------------------------------
2038 def get_selected_vertex_history(myobject
):
2040 # if not mesh, no vertex
2041 if myobject
.type != "MESH":
2043 # --------------------
2045 # --------------------
2046 oldobj
= bpy
.context
.object
2047 bpy
.context
.view_layer
.objects
.active
= myobject
2049 if myobject
.mode
!= 'EDIT':
2050 bpy
.ops
.object.mode_set(mode
='EDIT')
2053 bm
= from_edit_mesh(myobject
.data
)
2054 for v
in bm
.select_history
:
2055 mylist
.append(v
.index
)
2058 bpy
.ops
.object.editmode_toggle()
2059 # Back context object
2060 bpy
.context
.view_layer
.objects
.active
= oldobj
2065 # -------------------------------------------------------------
2066 # Get vertex selected segments
2067 # -------------------------------------------------------------
2068 def get_smart_selected(myobject
):
2070 # if not mesh, no vertex
2071 if myobject
.type != "MESH":
2073 # --------------------
2075 # --------------------
2076 oldobj
= bpy
.context
.object
2077 bpy
.context
.view_layer
.objects
.active
= myobject
2079 if myobject
.mode
!= 'EDIT':
2080 bpy
.ops
.object.mode_set(mode
='EDIT')
2083 bm
= from_edit_mesh(myobject
.data
)
2085 if e
.select
is True:
2086 mylist
.append(e
.verts
[0].index
)
2087 mylist
.append(e
.verts
[1].index
)
2090 bpy
.ops
.object.editmode_toggle()
2091 # Back context object
2092 bpy
.context
.view_layer
.objects
.active
= oldobj
2097 # -------------------------------------------------------------
2098 # Get vertex selected faces
2099 # -------------------------------------------------------------
2100 def get_selected_faces(myobject
):
2102 # if not mesh, no vertex
2103 if myobject
.type != "MESH":
2105 # --------------------
2107 # --------------------
2108 oldobj
= bpy
.context
.object
2109 bpy
.context
.view_layer
.objects
.active
= myobject
2111 if myobject
.mode
!= 'EDIT':
2112 bpy
.ops
.object.mode_set(mode
='EDIT')
2115 bm
= from_edit_mesh(myobject
.data
)
2118 if e
.select
is True:
2119 for i
in range(len(e
.verts
)):
2120 myfaces
.append(e
.verts
[i
].index
)
2122 mylist
.extend([myfaces
])
2125 bpy
.ops
.object.editmode_toggle()
2126 # Back context object
2127 bpy
.context
.view_layer
.objects
.active
= oldobj