1 # SPDX-License-Identifier: GPL-2.0-or-later
4 "name": "Simple Curve",
5 "author": "Vladimir Spivak (cwolf3d)",
8 "location": "View3D > Add > Curve",
9 "description": "Adds Simple Curve",
11 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
12 "category": "Add Curve",
16 # ------------------------------------------------------------
19 from bpy_extras
import object_utils
20 from bpy
.types
import (
26 from bpy
.props
import (
35 from mathutils
import (
45 # from bpy_extras.object_utils import *
48 # ------------------------------------------------------------
54 newpoints
.append([0.0, 0.0, 0.0])
59 # ------------------------------------------------------------
62 def SimpleLine(c1
=[0.0, 0.0, 0.0], c2
=[2.0, 2.0, 2.0]):
65 c3
= Vector(c2
) - Vector(c1
)
66 newpoints
.append([0.0, 0.0, 0.0])
67 newpoints
.append([c3
[0], c3
[1], c3
[2]])
72 # ------------------------------------------------------------
75 def SimpleAngle(length
=1.0, angle
=45.0):
78 angle
= radians(angle
)
79 newpoints
.append([length
, 0.0, 0.0])
80 newpoints
.append([0.0, 0.0, 0.0])
81 newpoints
.append([length
* cos(angle
), length
* sin(angle
), 0.0])
86 # ------------------------------------------------------------
89 def SimpleDistance(length
=1.0, center
=True):
93 newpoints
.append([-length
/ 2, 0.0, 0.0])
94 newpoints
.append([length
/ 2, 0.0, 0.0])
96 newpoints
.append([0.0, 0.0, 0.0])
97 newpoints
.append([length
, 0.0, 0.0])
102 # ------------------------------------------------------------
105 def SimpleCircle(sides
=4, radius
=1.0):
108 angle
= radians(360) / sides
109 newpoints
.append([radius
, 0, 0])
116 newpoints
.append([x
, y
, 0])
122 # ------------------------------------------------------------
125 def SimpleEllipse(a
=2.0, b
=1.0):
128 newpoints
.append([a
, 0.0, 0.0])
129 newpoints
.append([0.0, b
, 0.0])
130 newpoints
.append([-a
, 0.0, 0.0])
131 newpoints
.append([0.0, -b
, 0.0])
136 # ------------------------------------------------------------
139 def SimpleArc(sides
=0, radius
=1.0, startangle
=0.0, endangle
=45.0):
142 startangle
= radians(startangle
)
143 endangle
= radians(endangle
)
146 angle
= (endangle
- startangle
) / sides
147 x
= cos(startangle
) * radius
148 y
= sin(startangle
) * radius
149 newpoints
.append([x
, y
, 0])
153 x
= cos(t
+ startangle
) * radius
154 y
= sin(t
+ startangle
) * radius
155 newpoints
.append([x
, y
, 0])
157 x
= cos(endangle
) * radius
158 y
= sin(endangle
) * radius
159 newpoints
.append([x
, y
, 0])
164 # ------------------------------------------------------------
167 def SimpleSector(sides
=0, radius
=1.0, startangle
=0.0, endangle
=45.0):
170 startangle
= radians(startangle
)
171 endangle
= radians(endangle
)
174 newpoints
.append([0, 0, 0])
175 angle
= (endangle
- startangle
) / sides
176 x
= cos(startangle
) * radius
177 y
= sin(startangle
) * radius
178 newpoints
.append([x
, y
, 0])
182 x
= cos(t
+ startangle
) * radius
183 y
= sin(t
+ startangle
) * radius
184 newpoints
.append([x
, y
, 0])
186 x
= cos(endangle
) * radius
187 y
= sin(endangle
) * radius
188 newpoints
.append([x
, y
, 0])
193 # ------------------------------------------------------------
196 def SimpleSegment(sides
=0, a
=2.0, b
=1.0, startangle
=0.0, endangle
=45.0):
199 startangle
= radians(startangle
)
200 endangle
= radians(endangle
)
203 angle
= (endangle
- startangle
) / sides
204 x
= cos(startangle
) * a
205 y
= sin(startangle
) * a
206 newpoints
.append([x
, y
, 0])
210 x
= cos(t
+ startangle
) * a
211 y
= sin(t
+ startangle
) * a
212 newpoints
.append([x
, y
, 0])
214 x
= cos(endangle
) * a
215 y
= sin(endangle
) * a
216 newpoints
.append([x
, y
, 0])
218 x
= cos(endangle
) * b
219 y
= sin(endangle
) * b
220 newpoints
.append([x
, y
, 0])
224 x
= cos(t
+ startangle
) * b
225 y
= sin(t
+ startangle
) * b
226 newpoints
.append([x
, y
, 0])
228 x
= cos(startangle
) * b
229 y
= sin(startangle
) * b
230 newpoints
.append([x
, y
, 0])
235 # ------------------------------------------------------------
238 def SimpleRectangle(width
=2.0, length
=2.0, rounded
=0.0, center
=True):
247 newpoints
.append([-x
+ r
, y
, 0.0])
248 newpoints
.append([x
- r
, y
, 0.0])
249 newpoints
.append([x
, y
- r
, 0.0])
250 newpoints
.append([x
, -y
+ r
, 0.0])
251 newpoints
.append([x
- r
, -y
, 0.0])
252 newpoints
.append([-x
+ r
, -y
, 0.0])
253 newpoints
.append([-x
, -y
+ r
, 0.0])
254 newpoints
.append([-x
, y
- r
, 0.0])
256 newpoints
.append([-x
, y
, 0.0])
257 newpoints
.append([x
, y
, 0.0])
258 newpoints
.append([x
, -y
, 0.0])
259 newpoints
.append([-x
, -y
, 0.0])
265 newpoints
.append([r
, y
, 0.0])
266 newpoints
.append([x
- r
, y
, 0.0])
267 newpoints
.append([x
, y
- r
, 0.0])
268 newpoints
.append([x
, r
, 0.0])
269 newpoints
.append([x
- r
, 0.0, 0.0])
270 newpoints
.append([r
, 0.0, 0.0])
271 newpoints
.append([0.0, r
, 0.0])
272 newpoints
.append([0.0, y
- r
, 0.0])
274 newpoints
.append([0.0, 0.0, 0.0])
275 newpoints
.append([0.0, y
, 0.0])
276 newpoints
.append([x
, y
, 0.0])
277 newpoints
.append([x
, 0.0, 0.0])
282 # ------------------------------------------------------------
285 def SimpleRhomb(width
=2.0, length
=2.0, center
=True):
291 newpoints
.append([-x
, 0.0, 0.0])
292 newpoints
.append([0.0, y
, 0.0])
293 newpoints
.append([x
, 0.0, 0.0])
294 newpoints
.append([0.0, -y
, 0.0])
296 newpoints
.append([x
, 0.0, 0.0])
297 newpoints
.append([0.0, y
, 0.0])
298 newpoints
.append([x
, length
, 0.0])
299 newpoints
.append([width
, y
, 0.0])
304 # ------------------------------------------------------------
307 def SimplePolygon(sides
=3, radius
=1.0):
309 angle
= radians(360.0) / sides
316 newpoints
.append([x
, y
, 0.0])
322 # ------------------------------------------------------------
325 def SimplePolygon_ab(sides
=3, a
=2.0, b
=1.0):
327 angle
= radians(360.0) / sides
334 newpoints
.append([x
, y
, 0.0])
340 # ------------------------------------------------------------
343 def SimpleTrapezoid(a
=2.0, b
=1.0, h
=1.0, center
=True):
350 newpoints
.append([-x
, -r
, 0.0])
351 newpoints
.append([-y
, r
, 0.0])
352 newpoints
.append([y
, r
, 0.0])
353 newpoints
.append([x
, -r
, 0.0])
356 newpoints
.append([0.0, 0.0, 0.0])
357 newpoints
.append([x
- y
, h
, 0.0])
358 newpoints
.append([x
+ y
, h
, 0.0])
359 newpoints
.append([a
, 0.0, 0.0])
364 # ------------------------------------------------------------
365 # get array of vertcoordinates according to splinetype
366 def vertsToPoints(Verts
, splineType
):
371 # array for BEZIER spline output (V3)
372 if splineType
== 'BEZIER':
376 # array for nonBEZIER output (V4)
380 if splineType
== 'NURBS':
389 # ------------------------------------------------------------
392 def main(context
, self
, use_enter_edit_mode
):
393 # output splineType 'POLY' 'NURBS' 'BEZIER'
394 splineType
= self
.outputType
396 sides
= abs(int((self
.Simple_endangle
- self
.Simple_startangle
) / 90))
399 if self
.Simple_Type
== 'Point':
400 verts
= SimplePoint()
402 if self
.Simple_Type
== 'Line':
403 verts
= SimpleLine(self
.location
, self
.Simple_endlocation
)
405 if self
.Simple_Type
== 'Distance':
406 verts
= SimpleDistance(self
.Simple_length
, self
.Simple_center
)
408 if self
.Simple_Type
== 'Angle':
409 verts
= SimpleAngle(self
.Simple_length
, self
.Simple_angle
)
411 if self
.Simple_Type
== 'Circle':
412 if self
.Simple_sides
< 4:
413 self
.Simple_sides
= 4
414 if self
.Simple_radius
== 0:
416 verts
= SimpleCircle(self
.Simple_sides
, self
.Simple_radius
)
418 if self
.Simple_Type
== 'Ellipse':
419 verts
= SimpleEllipse(self
.Simple_a
, self
.Simple_b
)
421 if self
.Simple_Type
== 'Arc':
422 if self
.Simple_sides
< sides
:
423 self
.Simple_sides
= sides
424 if self
.Simple_radius
== 0:
427 self
.Simple_sides
, self
.Simple_radius
,
428 self
.Simple_startangle
, self
.Simple_endangle
431 if self
.Simple_Type
== 'Sector':
432 if self
.Simple_sides
< sides
:
433 self
.Simple_sides
= sides
434 if self
.Simple_radius
== 0:
436 verts
= SimpleSector(
437 self
.Simple_sides
, self
.Simple_radius
,
438 self
.Simple_startangle
, self
.Simple_endangle
441 if self
.Simple_Type
== 'Segment':
442 if self
.Simple_sides
< sides
:
443 self
.Simple_sides
= sides
444 if self
.Simple_a
== 0 or self
.Simple_b
== 0 or self
.Simple_a
== self
.Simple_b
:
446 if self
.Simple_a
> self
.Simple_b
:
447 verts
= SimpleSegment(
448 self
.Simple_sides
, self
.Simple_a
, self
.Simple_b
,
449 self
.Simple_startangle
, self
.Simple_endangle
451 if self
.Simple_a
< self
.Simple_b
:
452 verts
= SimpleSegment(
453 self
.Simple_sides
, self
.Simple_b
, self
.Simple_a
,
454 self
.Simple_startangle
, self
.Simple_endangle
457 if self
.Simple_Type
== 'Rectangle':
458 verts
= SimpleRectangle(
459 self
.Simple_width
, self
.Simple_length
,
460 self
.Simple_rounded
, self
.Simple_center
463 if self
.Simple_Type
== 'Rhomb':
465 self
.Simple_width
, self
.Simple_length
, self
.Simple_center
468 if self
.Simple_Type
== 'Polygon':
469 if self
.Simple_sides
< 3:
470 self
.Simple_sides
= 3
471 verts
= SimplePolygon(
472 self
.Simple_sides
, self
.Simple_radius
475 if self
.Simple_Type
== 'Polygon_ab':
476 if self
.Simple_sides
< 3:
477 self
.Simple_sides
= 3
478 verts
= SimplePolygon_ab(
479 self
.Simple_sides
, self
.Simple_a
, self
.Simple_b
482 if self
.Simple_Type
== 'Trapezoid':
483 verts
= SimpleTrapezoid(
484 self
.Simple_a
, self
.Simple_b
, self
.Simple_h
, self
.Simple_center
487 # turn verts into array
488 vertArray
= vertsToPoints(verts
, splineType
)
491 if bpy
.context
.mode
== 'EDIT_CURVE':
493 Curve
= context
.active_object
494 newSpline
= Curve
.data
.splines
.new(type=splineType
) # spline
496 name
= self
.Simple_Type
# Type as name
498 dataCurve
= bpy
.data
.curves
.new(name
, type='CURVE') # curve data block
499 newSpline
= dataCurve
.splines
.new(type=splineType
) # spline
501 # create object with new Curve
502 Curve
= object_utils
.object_data_add(context
, dataCurve
, operator
=self
) # place in active scene
503 Curve
.select_set(True)
505 for spline
in Curve
.data
.splines
:
506 if spline
.type == 'BEZIER':
507 for point
in spline
.bezier_points
:
508 point
.select_control_point
= False
509 point
.select_left_handle
= False
510 point
.select_right_handle
= False
512 for point
in spline
.points
:
515 # create spline from vertarray
517 if splineType
== 'BEZIER':
518 newSpline
.bezier_points
.add(int(len(vertArray
) * 0.33))
519 newSpline
.bezier_points
.foreach_set('co', vertArray
)
520 for point
in newSpline
.bezier_points
:
521 point
.handle_right_type
= self
.handleType
522 point
.handle_left_type
= self
.handleType
523 point
.select_control_point
= True
524 point
.select_left_handle
= True
525 point
.select_right_handle
= True
526 all_points
.append(point
)
528 newSpline
.points
.add(int(len(vertArray
) * 0.25 - 1))
529 newSpline
.points
.foreach_set('co', vertArray
)
530 newSpline
.use_endpoint_u
= True
531 for point
in newSpline
.points
:
532 all_points
.append(point
)
539 if splineType
== 'BEZIER':
540 if self
.Simple_Type
== 'Circle' or self
.Simple_Type
== 'Arc' or \
541 self
.Simple_Type
== 'Sector' or self
.Simple_Type
== 'Segment' or \
542 self
.Simple_Type
== 'Ellipse':
545 p
.handle_right_type
= 'FREE'
546 p
.handle_left_type
= 'FREE'
548 if self
.Simple_Type
== 'Circle':
550 for p1
in all_points
:
552 p2
= all_points
[i
+ 1]
553 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
554 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
555 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
556 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
557 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
558 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
559 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
560 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
564 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
565 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
567 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
571 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
572 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
577 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
578 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
579 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
580 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
581 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
582 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
583 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
584 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
588 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
589 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
591 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
595 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
596 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
601 if self
.Simple_Type
== 'Ellipse':
602 all_points
[0].handle_right
= Vector((self
.Simple_a
, self
.Simple_b
* d
, 0))
603 all_points
[0].handle_left
= Vector((self
.Simple_a
, -self
.Simple_b
* d
, 0))
604 all_points
[1].handle_right
= Vector((-self
.Simple_a
* d
, self
.Simple_b
, 0))
605 all_points
[1].handle_left
= Vector((self
.Simple_a
* d
, self
.Simple_b
, 0))
606 all_points
[2].handle_right
= Vector((-self
.Simple_a
, -self
.Simple_b
* d
, 0))
607 all_points
[2].handle_left
= Vector((-self
.Simple_a
, self
.Simple_b
* d
, 0))
608 all_points
[3].handle_right
= Vector((self
.Simple_a
* d
, -self
.Simple_b
, 0))
609 all_points
[3].handle_left
= Vector((-self
.Simple_a
* d
, -self
.Simple_b
, 0))
611 if self
.Simple_Type
== 'Arc':
613 for p1
in all_points
:
615 p2
= all_points
[i
+ 1]
616 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
617 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
618 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
619 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
620 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
621 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
622 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
623 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
627 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
628 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
630 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
634 if self
.Simple_startangle
< self
.Simple_endangle
:
635 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
636 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
640 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
641 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
645 all_points
[0].handle_left_type
= 'VECTOR'
646 all_points
[-1].handle_right_type
= 'VECTOR'
648 if self
.Simple_Type
== 'Sector':
650 for p1
in all_points
:
652 p1
.handle_right_type
= 'VECTOR'
653 p1
.handle_left_type
= 'VECTOR'
655 p2
= all_points
[i
+ 1]
656 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
657 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
658 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
659 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
660 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
661 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
662 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
663 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
667 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
668 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
670 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
674 if self
.Simple_startangle
< self
.Simple_endangle
:
675 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
676 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
680 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
681 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
685 all_points
[0].handle_left_type
= 'VECTOR'
686 all_points
[0].handle_right_type
= 'VECTOR'
687 all_points
[1].handle_left_type
= 'VECTOR'
688 all_points
[-1].handle_right_type
= 'VECTOR'
690 if self
.Simple_Type
== 'Segment':
692 if self
.Simple_a
> self
.Simple_b
:
693 Segment_a
= self
.Simple_a
694 Segment_b
= self
.Simple_b
695 if self
.Simple_a
< self
.Simple_b
:
696 Segment_b
= self
.Simple_a
697 Segment_a
= self
.Simple_b
698 for p1
in all_points
:
700 p2
= all_points
[i
+ 1]
701 u1
= asin(p1
.co
.y
/ Segment_a
)
702 u2
= asin(p2
.co
.y
/ Segment_a
)
703 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
704 u1
= acos(p1
.co
.x
/ Segment_a
)
705 u2
= acos(p2
.co
.x
/ Segment_a
)
706 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
707 u1
= acos(p1
.co
.x
/ Segment_a
)
708 u2
= acos(p2
.co
.x
/ Segment_a
)
712 l
= 4 / 3 * tan(1 / 4 * u
) * Segment_a
713 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
715 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
719 if self
.Simple_startangle
< self
.Simple_endangle
:
720 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
721 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
725 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
726 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
729 elif i
!= (n
/ 2 - 1) and i
!= (n
- 1):
730 p2
= all_points
[i
+ 1]
731 u1
= asin(p1
.co
.y
/ Segment_b
)
732 u2
= asin(p2
.co
.y
/ Segment_b
)
733 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
734 u1
= acos(p1
.co
.x
/ Segment_b
)
735 u2
= acos(p2
.co
.x
/ Segment_b
)
736 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
737 u1
= acos(p1
.co
.x
/ Segment_b
)
738 u2
= acos(p2
.co
.x
/ Segment_b
)
742 l
= 4 / 3 * tan(1 / 4 * u
) * Segment_b
743 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
745 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
749 if self
.Simple_startangle
< self
.Simple_endangle
:
750 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
751 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
755 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
756 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
761 all_points
[0].handle_left_type
= 'VECTOR'
762 all_points
[n
- 1].handle_right_type
= 'VECTOR'
763 all_points
[int(n
/ 2) - 1].handle_right_type
= 'VECTOR'
764 all_points
[int(n
/ 2)].handle_left_type
= 'VECTOR'
766 # set newSpline Options
767 newSpline
.use_cyclic_u
= self
.use_cyclic_u
768 newSpline
.use_endpoint_u
= self
.endp_u
769 newSpline
.order_u
= self
.order_u
772 Curve
.data
.dimensions
= self
.shape
773 Curve
.data
.use_path
= True
774 if self
.shape
== '3D':
775 Curve
.data
.fill_mode
= 'FULL'
777 Curve
.data
.fill_mode
= 'BOTH'
779 # move and rotate spline in edit mode
780 if bpy
.context
.mode
== 'EDIT_CURVE':
781 if self
.align
== "WORLD":
782 location
= self
.location
- context
.active_object
.location
783 bpy
.ops
.transform
.translate(value
= location
, orient_type
='GLOBAL')
784 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X', orient_type
='GLOBAL')
785 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y', orient_type
='GLOBAL')
786 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z', orient_type
='GLOBAL')
788 elif self
.align
== "VIEW":
789 bpy
.ops
.transform
.translate(value
= self
.location
)
790 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
791 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
792 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
794 elif self
.align
== "CURSOR":
795 location
= context
.active_object
.location
796 self
.location
= bpy
.context
.scene
.cursor
.location
- location
797 self
.rotation
= bpy
.context
.scene
.cursor
.rotation_euler
799 bpy
.ops
.transform
.translate(value
= self
.location
)
800 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
801 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
802 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
805 def menu(self
, context
):
806 oper1
= self
.layout
.operator(Simple
.bl_idname
, text
="Angle", icon
="DRIVER_ROTATIONAL_DIFFERENCE")
807 oper1
.Simple_Type
= "Angle"
808 oper1
.use_cyclic_u
= False
810 oper2
= self
.layout
.operator(Simple
.bl_idname
, text
="Arc", icon
="MOD_THICKNESS")
811 oper2
.Simple_Type
= "Arc"
812 oper2
.use_cyclic_u
= False
814 oper3
= self
.layout
.operator(Simple
.bl_idname
, text
="Circle", icon
="ANTIALIASED")
815 oper3
.Simple_Type
= "Circle"
816 oper3
.use_cyclic_u
= True
818 oper4
= self
.layout
.operator(Simple
.bl_idname
, text
="Distance", icon
="DRIVER_DISTANCE")
819 oper4
.Simple_Type
= "Distance"
820 oper4
.use_cyclic_u
= False
822 oper5
= self
.layout
.operator(Simple
.bl_idname
, text
="Ellipse", icon
="MESH_TORUS")
823 oper5
.Simple_Type
= "Ellipse"
824 oper5
.use_cyclic_u
= True
826 oper6
= self
.layout
.operator(Simple
.bl_idname
, text
="Line", icon
="MOD_SIMPLIFY")
827 oper6
.Simple_Type
= "Line"
828 oper6
.use_cyclic_u
= False
831 oper7
= self
.layout
.operator(Simple
.bl_idname
, text
="Point", icon
="LAYER_ACTIVE")
832 oper7
.Simple_Type
= "Point"
833 oper7
.use_cyclic_u
= False
835 oper8
= self
.layout
.operator(Simple
.bl_idname
, text
="Polygon", icon
="SEQ_CHROMA_SCOPE")
836 oper8
.Simple_Type
= "Polygon"
837 oper8
.use_cyclic_u
= True
839 oper9
= self
.layout
.operator(Simple
.bl_idname
, text
="Polygon ab", icon
="SEQ_CHROMA_SCOPE")
840 oper9
.Simple_Type
= "Polygon_ab"
841 oper9
.use_cyclic_u
= True
843 oper10
= self
.layout
.operator(Simple
.bl_idname
, text
="Rectangle", icon
="MESH_PLANE")
844 oper10
.Simple_Type
= "Rectangle"
845 oper10
.use_cyclic_u
= True
847 oper11
= self
.layout
.operator(Simple
.bl_idname
, text
="Rhomb", icon
="DECORATE_ANIMATE")
848 oper11
.Simple_Type
= "Rhomb"
849 oper11
.use_cyclic_u
= True
851 oper12
= self
.layout
.operator(Simple
.bl_idname
, text
="Sector", icon
="CON_SHRINKWRAP")
852 oper12
.Simple_Type
= "Sector"
853 oper12
.use_cyclic_u
= True
855 oper13
= self
.layout
.operator(Simple
.bl_idname
, text
="Segment", icon
="MOD_SIMPLEDEFORM")
856 oper13
.Simple_Type
= "Segment"
857 oper13
.use_cyclic_u
= True
859 oper14
= self
.layout
.operator(Simple
.bl_idname
, text
="Trapezoid", icon
="MOD_EDGESPLIT")
860 oper14
.Simple_Type
= "Trapezoid"
861 oper14
.use_cyclic_u
= True
863 # ------------------------------------------------------------
866 class Simple(Operator
, object_utils
.AddObjectHelper
):
867 bl_idname
= "curve.simple"
868 bl_label
= "Simple Curve"
869 bl_description
= "Construct a Simple Curve"
870 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
873 Simple
: BoolProperty(
876 description
="Simple Curve"
878 Simple_Change
: BoolProperty(
881 description
="Change Simple Curve"
883 Simple_Delete
: StringProperty(
885 description
="Delete Simple Curve"
888 Types
= [('Point', "Point", "Construct a Point"),
889 ('Line', "Line", "Construct a Line"),
890 ('Distance', "Distance", "Construct a two point Distance"),
891 ('Angle', "Angle", "Construct an Angle"),
892 ('Circle', "Circle", "Construct a Circle"),
893 ('Ellipse', "Ellipse", "Construct an Ellipse"),
894 ('Arc', "Arc", "Construct an Arc"),
895 ('Sector', "Sector", "Construct a Sector"),
896 ('Segment', "Segment", "Construct a Segment"),
897 ('Rectangle', "Rectangle", "Construct a Rectangle"),
898 ('Rhomb', "Rhomb", "Construct a Rhomb"),
899 ('Polygon', "Polygon", "Construct a Polygon"),
900 ('Polygon_ab', "Polygon ab", "Construct a Polygon ab"),
901 ('Trapezoid', "Trapezoid", "Construct a Trapezoid")
903 Simple_Type
: EnumProperty(
905 description
="Form of Curve to create",
909 Simple_endlocation
: FloatVectorProperty(
911 description
="End location",
912 default
=(2.0, 2.0, 2.0),
913 subtype
='TRANSLATION'
915 # Trapezoid properties
916 Simple_a
: FloatProperty(
919 min=0.0, soft_min
=0.0,
921 description
="a side Value"
923 Simple_b
: FloatProperty(
926 min=0.0, soft_min
=0.0,
928 description
="b side Value"
930 Simple_h
: FloatProperty(
934 description
="Height of the Trapezoid - distance between a and b"
936 Simple_angle
: FloatProperty(
941 Simple_startangle
: FloatProperty(
944 min=-360.0, soft_min
=-360.0,
945 max=360.0, soft_max
=360.0,
946 description
="Start angle"
948 Simple_endangle
: FloatProperty(
951 min=-360.0, soft_min
=-360.0,
952 max=360.0, soft_max
=360.0,
953 description
="End angle"
955 Simple_sides
: IntProperty(
961 Simple_radius
: FloatProperty(
964 min=0.0, soft_min
=0.0,
968 Simple_center
: BoolProperty(
969 name
="Length center",
971 description
="Length center"
974 Angle_types
= [('Degrees', "Degrees", "Use Degrees"),
975 ('Radians', "Radians", "Use Radians")]
976 Simple_degrees_or_radians
: EnumProperty(
977 name
="Degrees or radians",
978 description
="Degrees or radians",
981 # Rectangle properties
982 Simple_width
: FloatProperty(
989 Simple_length
: FloatProperty(
992 min=0.0, soft_min
=0.0,
996 Simple_rounded
: FloatProperty(
999 min=0.0, soft_min
=0.0,
1001 description
="Rounded corners"
1005 ('2D', "2D", "2D shape Curve"),
1006 ('3D', "3D", "3D shape Curve")]
1007 shape
: EnumProperty(
1010 description
="2D or 3D Curve"
1012 outputType
: EnumProperty(
1013 name
="Output splines",
1014 description
="Type of splines to output",
1016 ('POLY', "Poly", "Poly Spline type"),
1017 ('NURBS', "Nurbs", "Nurbs Spline type"),
1018 ('BEZIER', "Bezier", "Bezier Spline type")],
1021 use_cyclic_u
: BoolProperty(
1024 description
="make curve closed"
1026 endp_u
: BoolProperty(
1027 name
="Use endpoint u",
1029 description
="stretch to endpoints"
1031 order_u
: IntProperty(
1036 description
="Order of nurbs spline"
1038 handleType
: EnumProperty(
1041 description
="Bezier handles type",
1043 ('VECTOR', "Vector", "Vector type Bezier handles"),
1044 ('AUTO', "Auto", "Automatic type Bezier handles")]
1046 edit_mode
: BoolProperty(
1047 name
="Show in edit mode",
1049 description
="Show in edit mode"
1052 def draw(self
, context
):
1053 layout
= self
.layout
1056 col
= layout
.column()
1057 col
.prop(self
, "Simple_Type")
1062 if self
.Simple_Type
== 'Line':
1064 col
= box
.column(align
=True)
1065 col
.label(text
=self
.Simple_Type
+ " Options:")
1066 col
.prop(self
, "Simple_endlocation")
1067 v
= Vector(self
.Simple_endlocation
) - Vector(self
.location
)
1070 if self
.Simple_Type
== 'Distance':
1072 col
= box
.column(align
=True)
1073 col
.label(text
=self
.Simple_Type
+ " Options:")
1074 col
.prop(self
, "Simple_length")
1075 col
.prop(self
, "Simple_center")
1076 l
= self
.Simple_length
1078 if self
.Simple_Type
== 'Angle':
1080 col
= box
.column(align
=True)
1081 col
.label(text
=self
.Simple_Type
+ " Options:")
1082 col
.prop(self
, "Simple_length")
1083 col
.prop(self
, "Simple_angle")
1085 if self
.Simple_Type
== 'Circle':
1087 col
= box
.column(align
=True)
1088 col
.label(text
=self
.Simple_Type
+ " Options:")
1089 col
.prop(self
, "Simple_sides")
1090 col
.prop(self
, "Simple_radius")
1092 l
= 2 * pi
* abs(self
.Simple_radius
)
1093 s
= pi
* self
.Simple_radius
* self
.Simple_radius
1095 if self
.Simple_Type
== 'Ellipse':
1097 col
= box
.column(align
=True)
1098 col
.label(text
=self
.Simple_Type
+ " Options:")
1099 col
.prop(self
, "Simple_a", text
="Radius a")
1100 col
.prop(self
, "Simple_b", text
="Radius b")
1102 l
= pi
* (3 * (self
.Simple_a
+ self
.Simple_b
) -
1103 sqrt((3 * self
.Simple_a
+ self
.Simple_b
) *
1104 (self
.Simple_a
+ 3 * self
.Simple_b
)))
1106 s
= pi
* abs(self
.Simple_b
) * abs(self
.Simple_a
)
1108 if self
.Simple_Type
== 'Arc':
1110 col
= box
.column(align
=True)
1111 col
.label(text
=self
.Simple_Type
+ " Options:")
1112 col
.prop(self
, "Simple_sides")
1113 col
.prop(self
, "Simple_radius")
1115 col
= box
.column(align
=True)
1116 col
.prop(self
, "Simple_startangle")
1117 col
.prop(self
, "Simple_endangle")
1119 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1121 l
= abs(pi
* self
.Simple_radius
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1123 if self
.Simple_Type
== 'Sector':
1125 col
= box
.column(align
=True)
1126 col
.label(text
=self
.Simple_Type
+ " Options:")
1127 col
.prop(self
, "Simple_sides")
1128 col
.prop(self
, "Simple_radius")
1130 col
= box
.column(align
=True)
1131 col
.prop(self
, "Simple_startangle")
1132 col
.prop(self
, "Simple_endangle")
1134 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1136 l
= abs(pi
* self
.Simple_radius
*
1137 (self
.Simple_endangle
- self
.Simple_startangle
) / 180) + self
.Simple_radius
* 2
1139 s
= pi
* self
.Simple_radius
* self
.Simple_radius
* \
1140 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1142 if self
.Simple_Type
== 'Segment':
1144 col
= box
.column(align
=True)
1145 col
.label(text
=self
.Simple_Type
+ " Options:")
1146 col
.prop(self
, "Simple_sides")
1147 col
.prop(self
, "Simple_a", text
="Radius a")
1148 col
.prop(self
, "Simple_b", text
="Radius b")
1150 col
= box
.column(align
=True)
1151 col
.prop(self
, "Simple_startangle")
1152 col
.prop(self
, "Simple_endangle")
1155 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1157 la
= abs(pi
* self
.Simple_a
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1158 lb
= abs(pi
* self
.Simple_b
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1159 l
= abs(self
.Simple_a
- self
.Simple_b
) * 2 + la
+ lb
1161 sa
= pi
* self
.Simple_a
* self
.Simple_a
* \
1162 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1164 sb
= pi
* self
.Simple_b
* self
.Simple_b
* \
1165 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1169 if self
.Simple_Type
== 'Rectangle':
1171 col
= box
.column(align
=True)
1172 col
.label(text
=self
.Simple_Type
+ " Options:")
1173 col
.prop(self
, "Simple_width")
1174 col
.prop(self
, "Simple_length")
1175 col
.prop(self
, "Simple_rounded")
1177 box
.prop(self
, "Simple_center")
1178 l
= 2 * abs(self
.Simple_width
) + 2 * abs(self
.Simple_length
)
1179 s
= abs(self
.Simple_width
) * abs(self
.Simple_length
)
1181 if self
.Simple_Type
== 'Rhomb':
1183 col
= box
.column(align
=True)
1184 col
.label(text
=self
.Simple_Type
+ " Options:")
1185 col
.prop(self
, "Simple_width")
1186 col
.prop(self
, "Simple_length")
1187 col
.prop(self
, "Simple_center")
1189 g
= hypot(self
.Simple_width
/ 2, self
.Simple_length
/ 2)
1191 s
= self
.Simple_width
* self
.Simple_length
/ 2
1193 if self
.Simple_Type
== 'Polygon':
1195 col
= box
.column(align
=True)
1196 col
.label(text
=self
.Simple_Type
+ " Options:")
1197 col
.prop(self
, "Simple_sides")
1198 col
.prop(self
, "Simple_radius")
1200 if self
.Simple_Type
== 'Polygon_ab':
1202 col
= box
.column(align
=True)
1203 col
.label(text
="Polygon ab Options:")
1204 col
.prop(self
, "Simple_sides")
1205 col
.prop(self
, "Simple_a")
1206 col
.prop(self
, "Simple_b")
1208 if self
.Simple_Type
== 'Trapezoid':
1210 col
= box
.column(align
=True)
1211 col
.label(text
=self
.Simple_Type
+ " Options:")
1212 col
.prop(self
, "Simple_a")
1213 col
.prop(self
, "Simple_b")
1214 col
.prop(self
, "Simple_h")
1216 box
.prop(self
, "Simple_center")
1217 g
= hypot(self
.Simple_h
, (self
.Simple_a
- self
.Simple_b
) / 2)
1218 l
= self
.Simple_a
+ self
.Simple_b
+ g
* 2
1219 s
= (abs(self
.Simple_a
) + abs(self
.Simple_b
)) / 2 * self
.Simple_h
1222 row
.prop(self
, "shape", expand
=True)
1225 col
= layout
.column()
1226 col
.label(text
="Output Curve Type:")
1227 col
.row().prop(self
, "outputType", expand
=True)
1229 if self
.outputType
== 'NURBS':
1230 col
.prop(self
, "order_u")
1231 elif self
.outputType
== 'BEZIER':
1232 col
.row().prop(self
, 'handleType', expand
=True)
1234 col
= layout
.column()
1235 col
.row().prop(self
, "use_cyclic_u", expand
=True)
1237 col
= layout
.column()
1238 col
.row().prop(self
, "edit_mode", expand
=True)
1240 col
= layout
.column()
1241 # AddObjectHelper props
1242 col
.prop(self
, "align")
1243 col
.prop(self
, "location")
1244 col
.prop(self
, "rotation")
1246 if l
!= 0 or s
!= 0:
1248 box
.label(text
="Statistics:", icon
="INFO")
1250 l_str
= str(round(l
, 4))
1251 box
.label(text
="Length: " + l_str
)
1253 s_str
= str(round(s
, 4))
1254 box
.label(text
="Area: " + s_str
)
1257 def poll(cls
, context
):
1258 return context
.scene
is not None
1260 def execute(self
, context
):
1262 # turn off 'Enter Edit Mode'
1263 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
1264 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
1267 main(context
, self
, use_enter_edit_mode
)
1269 if use_enter_edit_mode
:
1270 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1272 # restore pre operator state
1273 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
1276 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1278 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
1282 def invoke(self
, context
, event
):
1284 self
.execute(context
)
1294 from bpy
.utils
import register_class
1298 bpy
.types
.VIEW3D_MT_curve_add
.append(menu
)
1301 from bpy
.utils
import unregister_class
1302 for cls
in reversed(classes
):
1303 unregister_class(cls
)
1305 bpy
.types
.VIEW3D_MT_curve_add
.remove(menu
)
1307 if __name__
== "__main__":