1 # SPDX-FileCopyrightText: 2017-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 "name": "Simple Curve",
7 "author": "Vladimir Spivak (cwolf3d)",
10 "location": "View3D > Add > Curve",
11 "description": "Adds Simple Curve",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
14 "category": "Add Curve",
18 # ------------------------------------------------------------
21 from bpy_extras
import object_utils
22 from bpy
.types
import (
28 from bpy
.props
import (
37 from mathutils
import (
47 # from bpy_extras.object_utils import *
50 # ------------------------------------------------------------
56 newpoints
.append([0.0, 0.0, 0.0])
61 # ------------------------------------------------------------
64 def SimpleLine(c1
=[0.0, 0.0, 0.0], c2
=[2.0, 2.0, 2.0]):
67 c3
= Vector(c2
) - Vector(c1
)
68 newpoints
.append([0.0, 0.0, 0.0])
69 newpoints
.append([c3
[0], c3
[1], c3
[2]])
74 # ------------------------------------------------------------
77 def SimpleAngle(length
=1.0, angle
=45.0):
80 angle
= radians(angle
)
81 newpoints
.append([length
, 0.0, 0.0])
82 newpoints
.append([0.0, 0.0, 0.0])
83 newpoints
.append([length
* cos(angle
), length
* sin(angle
), 0.0])
88 # ------------------------------------------------------------
91 def SimpleDistance(length
=1.0, center
=True):
95 newpoints
.append([-length
/ 2, 0.0, 0.0])
96 newpoints
.append([length
/ 2, 0.0, 0.0])
98 newpoints
.append([0.0, 0.0, 0.0])
99 newpoints
.append([length
, 0.0, 0.0])
104 # ------------------------------------------------------------
107 def SimpleCircle(sides
=4, radius
=1.0):
110 angle
= radians(360) / sides
111 newpoints
.append([radius
, 0, 0])
118 newpoints
.append([x
, y
, 0])
124 # ------------------------------------------------------------
127 def SimpleEllipse(a
=2.0, b
=1.0):
130 newpoints
.append([a
, 0.0, 0.0])
131 newpoints
.append([0.0, b
, 0.0])
132 newpoints
.append([-a
, 0.0, 0.0])
133 newpoints
.append([0.0, -b
, 0.0])
138 # ------------------------------------------------------------
141 def SimpleArc(sides
=0, radius
=1.0, startangle
=0.0, endangle
=45.0):
144 startangle
= radians(startangle
)
145 endangle
= radians(endangle
)
148 angle
= (endangle
- startangle
) / sides
149 x
= cos(startangle
) * radius
150 y
= sin(startangle
) * radius
151 newpoints
.append([x
, y
, 0])
155 x
= cos(t
+ startangle
) * radius
156 y
= sin(t
+ startangle
) * radius
157 newpoints
.append([x
, y
, 0])
159 x
= cos(endangle
) * radius
160 y
= sin(endangle
) * radius
161 newpoints
.append([x
, y
, 0])
166 # ------------------------------------------------------------
169 def SimpleSector(sides
=0, radius
=1.0, startangle
=0.0, endangle
=45.0):
172 startangle
= radians(startangle
)
173 endangle
= radians(endangle
)
176 newpoints
.append([0, 0, 0])
177 angle
= (endangle
- startangle
) / sides
178 x
= cos(startangle
) * radius
179 y
= sin(startangle
) * radius
180 newpoints
.append([x
, y
, 0])
184 x
= cos(t
+ startangle
) * radius
185 y
= sin(t
+ startangle
) * radius
186 newpoints
.append([x
, y
, 0])
188 x
= cos(endangle
) * radius
189 y
= sin(endangle
) * radius
190 newpoints
.append([x
, y
, 0])
195 # ------------------------------------------------------------
198 def SimpleSegment(sides
=0, a
=2.0, b
=1.0, startangle
=0.0, endangle
=45.0):
201 startangle
= radians(startangle
)
202 endangle
= radians(endangle
)
205 angle
= (endangle
- startangle
) / sides
206 x
= cos(startangle
) * a
207 y
= sin(startangle
) * a
208 newpoints
.append([x
, y
, 0])
212 x
= cos(t
+ startangle
) * a
213 y
= sin(t
+ startangle
) * a
214 newpoints
.append([x
, y
, 0])
216 x
= cos(endangle
) * a
217 y
= sin(endangle
) * a
218 newpoints
.append([x
, y
, 0])
220 x
= cos(endangle
) * b
221 y
= sin(endangle
) * b
222 newpoints
.append([x
, y
, 0])
226 x
= cos(t
+ startangle
) * b
227 y
= sin(t
+ startangle
) * b
228 newpoints
.append([x
, y
, 0])
230 x
= cos(startangle
) * b
231 y
= sin(startangle
) * b
232 newpoints
.append([x
, y
, 0])
237 # ------------------------------------------------------------
240 def SimpleRectangle(width
=2.0, length
=2.0, rounded
=0.0, center
=True):
249 newpoints
.append([-x
+ r
, y
, 0.0])
250 newpoints
.append([x
- r
, y
, 0.0])
251 newpoints
.append([x
, y
- r
, 0.0])
252 newpoints
.append([x
, -y
+ r
, 0.0])
253 newpoints
.append([x
- r
, -y
, 0.0])
254 newpoints
.append([-x
+ r
, -y
, 0.0])
255 newpoints
.append([-x
, -y
+ r
, 0.0])
256 newpoints
.append([-x
, y
- r
, 0.0])
258 newpoints
.append([-x
, y
, 0.0])
259 newpoints
.append([x
, y
, 0.0])
260 newpoints
.append([x
, -y
, 0.0])
261 newpoints
.append([-x
, -y
, 0.0])
267 newpoints
.append([r
, y
, 0.0])
268 newpoints
.append([x
- r
, y
, 0.0])
269 newpoints
.append([x
, y
- r
, 0.0])
270 newpoints
.append([x
, r
, 0.0])
271 newpoints
.append([x
- r
, 0.0, 0.0])
272 newpoints
.append([r
, 0.0, 0.0])
273 newpoints
.append([0.0, r
, 0.0])
274 newpoints
.append([0.0, y
- r
, 0.0])
276 newpoints
.append([0.0, 0.0, 0.0])
277 newpoints
.append([0.0, y
, 0.0])
278 newpoints
.append([x
, y
, 0.0])
279 newpoints
.append([x
, 0.0, 0.0])
284 # ------------------------------------------------------------
287 def SimpleRhomb(width
=2.0, length
=2.0, center
=True):
293 newpoints
.append([-x
, 0.0, 0.0])
294 newpoints
.append([0.0, y
, 0.0])
295 newpoints
.append([x
, 0.0, 0.0])
296 newpoints
.append([0.0, -y
, 0.0])
298 newpoints
.append([x
, 0.0, 0.0])
299 newpoints
.append([0.0, y
, 0.0])
300 newpoints
.append([x
, length
, 0.0])
301 newpoints
.append([width
, y
, 0.0])
306 # ------------------------------------------------------------
309 def SimplePolygon(sides
=3, radius
=1.0):
311 angle
= radians(360.0) / sides
318 newpoints
.append([x
, y
, 0.0])
324 # ------------------------------------------------------------
327 def SimplePolygon_ab(sides
=3, a
=2.0, b
=1.0):
329 angle
= radians(360.0) / sides
336 newpoints
.append([x
, y
, 0.0])
342 # ------------------------------------------------------------
345 def SimpleTrapezoid(a
=2.0, b
=1.0, h
=1.0, center
=True):
352 newpoints
.append([-x
, -r
, 0.0])
353 newpoints
.append([-y
, r
, 0.0])
354 newpoints
.append([y
, r
, 0.0])
355 newpoints
.append([x
, -r
, 0.0])
358 newpoints
.append([0.0, 0.0, 0.0])
359 newpoints
.append([x
- y
, h
, 0.0])
360 newpoints
.append([x
+ y
, h
, 0.0])
361 newpoints
.append([a
, 0.0, 0.0])
366 # ------------------------------------------------------------
367 # get array of vertcoordinates according to splinetype
368 def vertsToPoints(Verts
, splineType
):
373 # array for BEZIER spline output (V3)
374 if splineType
== 'BEZIER':
378 # array for nonBEZIER output (V4)
382 if splineType
== 'NURBS':
391 # ------------------------------------------------------------
394 def main(context
, self
, use_enter_edit_mode
):
395 # output splineType 'POLY' 'NURBS' 'BEZIER'
396 splineType
= self
.outputType
398 sides
= abs(int((self
.Simple_endangle
- self
.Simple_startangle
) / 90))
401 if self
.Simple_Type
== 'Point':
402 verts
= SimplePoint()
404 if self
.Simple_Type
== 'Line':
405 verts
= SimpleLine(self
.location
, self
.Simple_endlocation
)
407 if self
.Simple_Type
== 'Distance':
408 verts
= SimpleDistance(self
.Simple_length
, self
.Simple_center
)
410 if self
.Simple_Type
== 'Angle':
411 verts
= SimpleAngle(self
.Simple_length
, self
.Simple_angle
)
413 if self
.Simple_Type
== 'Circle':
414 if self
.Simple_sides
< 4:
415 self
.Simple_sides
= 4
416 if self
.Simple_radius
== 0:
418 verts
= SimpleCircle(self
.Simple_sides
, self
.Simple_radius
)
420 if self
.Simple_Type
== 'Ellipse':
421 verts
= SimpleEllipse(self
.Simple_a
, self
.Simple_b
)
423 if self
.Simple_Type
== 'Arc':
424 if self
.Simple_sides
< sides
:
425 self
.Simple_sides
= sides
426 if self
.Simple_radius
== 0:
429 self
.Simple_sides
, self
.Simple_radius
,
430 self
.Simple_startangle
, self
.Simple_endangle
433 if self
.Simple_Type
== 'Sector':
434 if self
.Simple_sides
< sides
:
435 self
.Simple_sides
= sides
436 if self
.Simple_radius
== 0:
438 verts
= SimpleSector(
439 self
.Simple_sides
, self
.Simple_radius
,
440 self
.Simple_startangle
, self
.Simple_endangle
443 if self
.Simple_Type
== 'Segment':
444 if self
.Simple_sides
< sides
:
445 self
.Simple_sides
= sides
446 if self
.Simple_a
== 0 or self
.Simple_b
== 0 or self
.Simple_a
== self
.Simple_b
:
448 if self
.Simple_a
> self
.Simple_b
:
449 verts
= SimpleSegment(
450 self
.Simple_sides
, self
.Simple_a
, self
.Simple_b
,
451 self
.Simple_startangle
, self
.Simple_endangle
453 if self
.Simple_a
< self
.Simple_b
:
454 verts
= SimpleSegment(
455 self
.Simple_sides
, self
.Simple_b
, self
.Simple_a
,
456 self
.Simple_startangle
, self
.Simple_endangle
459 if self
.Simple_Type
== 'Rectangle':
460 verts
= SimpleRectangle(
461 self
.Simple_width
, self
.Simple_length
,
462 self
.Simple_rounded
, self
.Simple_center
465 if self
.Simple_Type
== 'Rhomb':
467 self
.Simple_width
, self
.Simple_length
, self
.Simple_center
470 if self
.Simple_Type
== 'Polygon':
471 if self
.Simple_sides
< 3:
472 self
.Simple_sides
= 3
473 verts
= SimplePolygon(
474 self
.Simple_sides
, self
.Simple_radius
477 if self
.Simple_Type
== 'Polygon_ab':
478 if self
.Simple_sides
< 3:
479 self
.Simple_sides
= 3
480 verts
= SimplePolygon_ab(
481 self
.Simple_sides
, self
.Simple_a
, self
.Simple_b
484 if self
.Simple_Type
== 'Trapezoid':
485 verts
= SimpleTrapezoid(
486 self
.Simple_a
, self
.Simple_b
, self
.Simple_h
, self
.Simple_center
489 # turn verts into array
490 vertArray
= vertsToPoints(verts
, splineType
)
493 if bpy
.context
.mode
== 'EDIT_CURVE':
495 Curve
= context
.active_object
496 newSpline
= Curve
.data
.splines
.new(type=splineType
) # spline
498 name
= self
.Simple_Type
# Type as name
500 dataCurve
= bpy
.data
.curves
.new(name
, type='CURVE') # curve data block
501 newSpline
= dataCurve
.splines
.new(type=splineType
) # spline
503 # create object with new Curve
504 Curve
= object_utils
.object_data_add(context
, dataCurve
, operator
=self
) # place in active scene
505 Curve
.select_set(True)
507 for spline
in Curve
.data
.splines
:
508 if spline
.type == 'BEZIER':
509 for point
in spline
.bezier_points
:
510 point
.select_control_point
= False
511 point
.select_left_handle
= False
512 point
.select_right_handle
= False
514 for point
in spline
.points
:
517 # create spline from vertarray
519 if splineType
== 'BEZIER':
520 newSpline
.bezier_points
.add(int(len(vertArray
) * 0.33))
521 newSpline
.bezier_points
.foreach_set('co', vertArray
)
522 for point
in newSpline
.bezier_points
:
523 point
.handle_right_type
= self
.handleType
524 point
.handle_left_type
= self
.handleType
525 point
.select_control_point
= True
526 point
.select_left_handle
= True
527 point
.select_right_handle
= True
528 all_points
.append(point
)
530 newSpline
.points
.add(int(len(vertArray
) * 0.25 - 1))
531 newSpline
.points
.foreach_set('co', vertArray
)
532 newSpline
.use_endpoint_u
= True
533 for point
in newSpline
.points
:
534 all_points
.append(point
)
541 if splineType
== 'BEZIER':
542 if self
.Simple_Type
== 'Circle' or self
.Simple_Type
== 'Arc' or \
543 self
.Simple_Type
== 'Sector' or self
.Simple_Type
== 'Segment' or \
544 self
.Simple_Type
== 'Ellipse':
547 p
.handle_right_type
= 'FREE'
548 p
.handle_left_type
= 'FREE'
550 if self
.Simple_Type
== 'Circle':
552 for p1
in all_points
:
554 p2
= all_points
[i
+ 1]
555 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
556 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
557 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
558 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
559 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
560 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
561 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
562 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
566 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
567 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
569 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
573 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
574 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
579 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
580 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
581 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
582 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
583 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
584 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
585 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
586 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
590 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
591 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
593 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
597 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
598 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
603 if self
.Simple_Type
== 'Ellipse':
604 all_points
[0].handle_right
= Vector((self
.Simple_a
, self
.Simple_b
* d
, 0))
605 all_points
[0].handle_left
= Vector((self
.Simple_a
, -self
.Simple_b
* d
, 0))
606 all_points
[1].handle_right
= Vector((-self
.Simple_a
* d
, self
.Simple_b
, 0))
607 all_points
[1].handle_left
= Vector((self
.Simple_a
* d
, self
.Simple_b
, 0))
608 all_points
[2].handle_right
= Vector((-self
.Simple_a
, -self
.Simple_b
* d
, 0))
609 all_points
[2].handle_left
= Vector((-self
.Simple_a
, self
.Simple_b
* d
, 0))
610 all_points
[3].handle_right
= Vector((self
.Simple_a
* d
, -self
.Simple_b
, 0))
611 all_points
[3].handle_left
= Vector((-self
.Simple_a
* d
, -self
.Simple_b
, 0))
613 if self
.Simple_Type
== 'Arc':
615 for p1
in all_points
:
617 p2
= all_points
[i
+ 1]
618 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
619 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
620 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
621 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
622 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
623 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
624 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
625 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
629 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
630 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
632 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
636 if self
.Simple_startangle
< self
.Simple_endangle
:
637 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
638 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
642 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
643 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
647 all_points
[0].handle_left_type
= 'VECTOR'
648 all_points
[-1].handle_right_type
= 'VECTOR'
650 if self
.Simple_Type
== 'Sector':
652 for p1
in all_points
:
654 p1
.handle_right_type
= 'VECTOR'
655 p1
.handle_left_type
= 'VECTOR'
657 p2
= all_points
[i
+ 1]
658 u1
= asin(p1
.co
.y
/ self
.Simple_radius
)
659 u2
= asin(p2
.co
.y
/ self
.Simple_radius
)
660 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
661 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
662 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
663 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
664 u1
= acos(p1
.co
.x
/ self
.Simple_radius
)
665 u2
= acos(p2
.co
.x
/ self
.Simple_radius
)
669 l
= 4 / 3 * tan(1 / 4 * u
) * self
.Simple_radius
670 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
672 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
676 if self
.Simple_startangle
< self
.Simple_endangle
:
677 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
678 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
682 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
683 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
687 all_points
[0].handle_left_type
= 'VECTOR'
688 all_points
[0].handle_right_type
= 'VECTOR'
689 all_points
[1].handle_left_type
= 'VECTOR'
690 all_points
[-1].handle_right_type
= 'VECTOR'
692 if self
.Simple_Type
== 'Segment':
694 if self
.Simple_a
> self
.Simple_b
:
695 Segment_a
= self
.Simple_a
696 Segment_b
= self
.Simple_b
697 if self
.Simple_a
< self
.Simple_b
:
698 Segment_b
= self
.Simple_a
699 Segment_a
= self
.Simple_b
700 for p1
in all_points
:
702 p2
= all_points
[i
+ 1]
703 u1
= asin(p1
.co
.y
/ Segment_a
)
704 u2
= asin(p2
.co
.y
/ Segment_a
)
705 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
706 u1
= acos(p1
.co
.x
/ Segment_a
)
707 u2
= acos(p2
.co
.x
/ Segment_a
)
708 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
709 u1
= acos(p1
.co
.x
/ Segment_a
)
710 u2
= acos(p2
.co
.x
/ Segment_a
)
714 l
= 4 / 3 * tan(1 / 4 * u
) * Segment_a
715 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
717 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
721 if self
.Simple_startangle
< self
.Simple_endangle
:
722 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
723 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
727 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
728 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
731 elif i
!= (n
/ 2 - 1) and i
!= (n
- 1):
732 p2
= all_points
[i
+ 1]
733 u1
= asin(p1
.co
.y
/ Segment_b
)
734 u2
= asin(p2
.co
.y
/ Segment_b
)
735 if p1
.co
.x
> 0 and p2
.co
.x
< 0:
736 u1
= acos(p1
.co
.x
/ Segment_b
)
737 u2
= acos(p2
.co
.x
/ Segment_b
)
738 elif p1
.co
.x
< 0 and p2
.co
.x
> 0:
739 u1
= acos(p1
.co
.x
/ Segment_b
)
740 u2
= acos(p2
.co
.x
/ Segment_b
)
744 l
= 4 / 3 * tan(1 / 4 * u
) * Segment_b
745 v1
= Vector((-p1
.co
.y
, p1
.co
.x
, 0))
747 v2
= Vector((-p2
.co
.y
, p2
.co
.x
, 0))
751 if self
.Simple_startangle
< self
.Simple_endangle
:
752 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) - vh1
753 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) + vh2
757 v1
= Vector((p1
.co
.x
, p1
.co
.y
, 0)) + vh1
758 v2
= Vector((p2
.co
.x
, p2
.co
.y
, 0)) - vh2
763 all_points
[0].handle_left_type
= 'VECTOR'
764 all_points
[n
- 1].handle_right_type
= 'VECTOR'
765 all_points
[int(n
/ 2) - 1].handle_right_type
= 'VECTOR'
766 all_points
[int(n
/ 2)].handle_left_type
= 'VECTOR'
768 # set newSpline Options
769 newSpline
.use_cyclic_u
= self
.use_cyclic_u
770 newSpline
.use_endpoint_u
= self
.endp_u
771 newSpline
.order_u
= self
.order_u
774 Curve
.data
.dimensions
= self
.shape
775 Curve
.data
.use_path
= True
776 if self
.shape
== '3D':
777 Curve
.data
.fill_mode
= 'FULL'
779 Curve
.data
.fill_mode
= 'BOTH'
781 # move and rotate spline in edit mode
782 if bpy
.context
.mode
== 'EDIT_CURVE':
783 if self
.align
== "WORLD":
784 location
= self
.location
- context
.active_object
.location
785 bpy
.ops
.transform
.translate(value
= location
, orient_type
='GLOBAL')
786 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X', orient_type
='GLOBAL')
787 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y', orient_type
='GLOBAL')
788 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z', orient_type
='GLOBAL')
790 elif self
.align
== "VIEW":
791 bpy
.ops
.transform
.translate(value
= self
.location
)
792 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
793 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
794 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
796 elif self
.align
== "CURSOR":
797 location
= context
.active_object
.location
798 self
.location
= bpy
.context
.scene
.cursor
.location
- location
799 self
.rotation
= bpy
.context
.scene
.cursor
.rotation_euler
801 bpy
.ops
.transform
.translate(value
= self
.location
)
802 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
803 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
804 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
807 def menu(self
, context
):
808 oper1
= self
.layout
.operator(Simple
.bl_idname
, text
="Angle", icon
="DRIVER_ROTATIONAL_DIFFERENCE")
809 oper1
.Simple_Type
= "Angle"
810 oper1
.use_cyclic_u
= False
812 oper2
= self
.layout
.operator(Simple
.bl_idname
, text
="Arc", icon
="MOD_THICKNESS")
813 oper2
.Simple_Type
= "Arc"
814 oper2
.use_cyclic_u
= False
816 oper3
= self
.layout
.operator(Simple
.bl_idname
, text
="Circle", icon
="ANTIALIASED")
817 oper3
.Simple_Type
= "Circle"
818 oper3
.use_cyclic_u
= True
820 oper4
= self
.layout
.operator(Simple
.bl_idname
, text
="Distance", icon
="DRIVER_DISTANCE")
821 oper4
.Simple_Type
= "Distance"
822 oper4
.use_cyclic_u
= False
824 oper5
= self
.layout
.operator(Simple
.bl_idname
, text
="Ellipse", icon
="MESH_TORUS")
825 oper5
.Simple_Type
= "Ellipse"
826 oper5
.use_cyclic_u
= True
828 oper6
= self
.layout
.operator(Simple
.bl_idname
, text
="Line", icon
="MOD_SIMPLIFY")
829 oper6
.Simple_Type
= "Line"
830 oper6
.use_cyclic_u
= False
833 oper7
= self
.layout
.operator(Simple
.bl_idname
, text
="Point", icon
="LAYER_ACTIVE")
834 oper7
.Simple_Type
= "Point"
835 oper7
.use_cyclic_u
= False
837 oper8
= self
.layout
.operator(Simple
.bl_idname
, text
="Polygon", icon
="SEQ_CHROMA_SCOPE")
838 oper8
.Simple_Type
= "Polygon"
839 oper8
.use_cyclic_u
= True
841 oper9
= self
.layout
.operator(Simple
.bl_idname
, text
="Polygon ab", icon
="SEQ_CHROMA_SCOPE")
842 oper9
.Simple_Type
= "Polygon_ab"
843 oper9
.use_cyclic_u
= True
845 oper10
= self
.layout
.operator(Simple
.bl_idname
, text
="Rectangle", icon
="MESH_PLANE")
846 oper10
.Simple_Type
= "Rectangle"
847 oper10
.use_cyclic_u
= True
849 oper11
= self
.layout
.operator(Simple
.bl_idname
, text
="Rhomb", icon
="DECORATE_ANIMATE")
850 oper11
.Simple_Type
= "Rhomb"
851 oper11
.use_cyclic_u
= True
853 oper12
= self
.layout
.operator(Simple
.bl_idname
, text
="Sector", icon
="CON_SHRINKWRAP")
854 oper12
.Simple_Type
= "Sector"
855 oper12
.use_cyclic_u
= True
857 oper13
= self
.layout
.operator(Simple
.bl_idname
, text
="Segment", icon
="MOD_SIMPLEDEFORM")
858 oper13
.Simple_Type
= "Segment"
859 oper13
.use_cyclic_u
= True
861 oper14
= self
.layout
.operator(Simple
.bl_idname
, text
="Trapezoid", icon
="MOD_EDGESPLIT")
862 oper14
.Simple_Type
= "Trapezoid"
863 oper14
.use_cyclic_u
= True
865 # ------------------------------------------------------------
868 class Simple(Operator
, object_utils
.AddObjectHelper
):
869 bl_idname
= "curve.simple"
870 bl_label
= "Simple Curve"
871 bl_description
= "Construct a Simple Curve"
872 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
875 Simple
: BoolProperty(
878 description
="Simple Curve"
880 Simple_Change
: BoolProperty(
883 description
="Change Simple Curve"
885 Simple_Delete
: StringProperty(
887 description
="Delete Simple Curve"
890 Types
= [('Point', "Point", "Construct a Point"),
891 ('Line', "Line", "Construct a Line"),
892 ('Distance', "Distance", "Construct a two point Distance"),
893 ('Angle', "Angle", "Construct an Angle"),
894 ('Circle', "Circle", "Construct a Circle"),
895 ('Ellipse', "Ellipse", "Construct an Ellipse"),
896 ('Arc', "Arc", "Construct an Arc"),
897 ('Sector', "Sector", "Construct a Sector"),
898 ('Segment', "Segment", "Construct a Segment"),
899 ('Rectangle', "Rectangle", "Construct a Rectangle"),
900 ('Rhomb', "Rhomb", "Construct a Rhomb"),
901 ('Polygon', "Polygon", "Construct a Polygon"),
902 ('Polygon_ab', "Polygon ab", "Construct a Polygon ab"),
903 ('Trapezoid', "Trapezoid", "Construct a Trapezoid")
905 Simple_Type
: EnumProperty(
907 description
="Form of Curve to create",
911 Simple_endlocation
: FloatVectorProperty(
913 description
="End location",
914 default
=(2.0, 2.0, 2.0),
915 subtype
='TRANSLATION'
917 # Trapezoid properties
918 Simple_a
: FloatProperty(
921 min=0.0, soft_min
=0.0,
923 description
="a side Value"
925 Simple_b
: FloatProperty(
928 min=0.0, soft_min
=0.0,
930 description
="b side Value"
932 Simple_h
: FloatProperty(
936 description
="Height of the Trapezoid - distance between a and b"
938 Simple_angle
: FloatProperty(
943 Simple_startangle
: FloatProperty(
946 min=-360.0, soft_min
=-360.0,
947 max=360.0, soft_max
=360.0,
948 description
="Start angle"
950 Simple_endangle
: FloatProperty(
953 min=-360.0, soft_min
=-360.0,
954 max=360.0, soft_max
=360.0,
955 description
="End angle"
957 Simple_sides
: IntProperty(
963 Simple_radius
: FloatProperty(
966 min=0.0, soft_min
=0.0,
970 Simple_center
: BoolProperty(
971 name
="Length center",
973 description
="Length center"
976 Angle_types
= [('Degrees', "Degrees", "Use Degrees"),
977 ('Radians', "Radians", "Use Radians")]
978 Simple_degrees_or_radians
: EnumProperty(
979 name
="Degrees or radians",
980 description
="Degrees or radians",
983 # Rectangle properties
984 Simple_width
: FloatProperty(
991 Simple_length
: FloatProperty(
994 min=0.0, soft_min
=0.0,
998 Simple_rounded
: FloatProperty(
1001 min=0.0, soft_min
=0.0,
1003 description
="Rounded corners"
1007 ('2D', "2D", "2D shape Curve"),
1008 ('3D', "3D", "3D shape Curve")]
1009 shape
: EnumProperty(
1012 description
="2D or 3D Curve"
1014 outputType
: EnumProperty(
1015 name
="Output splines",
1016 description
="Type of splines to output",
1018 ('POLY', "Poly", "Poly Spline type"),
1019 ('NURBS', "Nurbs", "Nurbs Spline type"),
1020 ('BEZIER', "Bezier", "Bezier Spline type")],
1023 use_cyclic_u
: BoolProperty(
1026 description
="make curve closed"
1028 endp_u
: BoolProperty(
1029 name
="Use endpoint u",
1031 description
="stretch to endpoints"
1033 order_u
: IntProperty(
1038 description
="Order of nurbs spline"
1040 handleType
: EnumProperty(
1043 description
="Bezier handles type",
1045 ('VECTOR', "Vector", "Vector type Bezier handles"),
1046 ('AUTO', "Auto", "Automatic type Bezier handles")]
1048 edit_mode
: BoolProperty(
1049 name
="Show in edit mode",
1051 description
="Show in edit mode"
1054 def draw(self
, context
):
1055 layout
= self
.layout
1058 col
= layout
.column()
1059 col
.prop(self
, "Simple_Type")
1064 if self
.Simple_Type
== 'Line':
1066 col
= box
.column(align
=True)
1067 col
.label(text
=self
.Simple_Type
+ " Options:")
1068 col
.prop(self
, "Simple_endlocation")
1069 v
= Vector(self
.Simple_endlocation
) - Vector(self
.location
)
1072 if self
.Simple_Type
== 'Distance':
1074 col
= box
.column(align
=True)
1075 col
.label(text
=self
.Simple_Type
+ " Options:")
1076 col
.prop(self
, "Simple_length")
1077 col
.prop(self
, "Simple_center")
1078 l
= self
.Simple_length
1080 if self
.Simple_Type
== 'Angle':
1082 col
= box
.column(align
=True)
1083 col
.label(text
=self
.Simple_Type
+ " Options:")
1084 col
.prop(self
, "Simple_length")
1085 col
.prop(self
, "Simple_angle")
1087 if self
.Simple_Type
== 'Circle':
1089 col
= box
.column(align
=True)
1090 col
.label(text
=self
.Simple_Type
+ " Options:")
1091 col
.prop(self
, "Simple_sides")
1092 col
.prop(self
, "Simple_radius")
1094 l
= 2 * pi
* abs(self
.Simple_radius
)
1095 s
= pi
* self
.Simple_radius
* self
.Simple_radius
1097 if self
.Simple_Type
== 'Ellipse':
1099 col
= box
.column(align
=True)
1100 col
.label(text
=self
.Simple_Type
+ " Options:")
1101 col
.prop(self
, "Simple_a", text
="Radius a")
1102 col
.prop(self
, "Simple_b", text
="Radius b")
1104 l
= pi
* (3 * (self
.Simple_a
+ self
.Simple_b
) -
1105 sqrt((3 * self
.Simple_a
+ self
.Simple_b
) *
1106 (self
.Simple_a
+ 3 * self
.Simple_b
)))
1108 s
= pi
* abs(self
.Simple_b
) * abs(self
.Simple_a
)
1110 if self
.Simple_Type
== 'Arc':
1112 col
= box
.column(align
=True)
1113 col
.label(text
=self
.Simple_Type
+ " Options:")
1114 col
.prop(self
, "Simple_sides")
1115 col
.prop(self
, "Simple_radius")
1117 col
= box
.column(align
=True)
1118 col
.prop(self
, "Simple_startangle")
1119 col
.prop(self
, "Simple_endangle")
1121 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1123 l
= abs(pi
* self
.Simple_radius
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1125 if self
.Simple_Type
== 'Sector':
1127 col
= box
.column(align
=True)
1128 col
.label(text
=self
.Simple_Type
+ " Options:")
1129 col
.prop(self
, "Simple_sides")
1130 col
.prop(self
, "Simple_radius")
1132 col
= box
.column(align
=True)
1133 col
.prop(self
, "Simple_startangle")
1134 col
.prop(self
, "Simple_endangle")
1136 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1138 l
= abs(pi
* self
.Simple_radius
*
1139 (self
.Simple_endangle
- self
.Simple_startangle
) / 180) + self
.Simple_radius
* 2
1141 s
= pi
* self
.Simple_radius
* self
.Simple_radius
* \
1142 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1144 if self
.Simple_Type
== 'Segment':
1146 col
= box
.column(align
=True)
1147 col
.label(text
=self
.Simple_Type
+ " Options:")
1148 col
.prop(self
, "Simple_sides")
1149 col
.prop(self
, "Simple_a", text
="Radius a")
1150 col
.prop(self
, "Simple_b", text
="Radius b")
1152 col
= box
.column(align
=True)
1153 col
.prop(self
, "Simple_startangle")
1154 col
.prop(self
, "Simple_endangle")
1157 #row.prop(self, "Simple_degrees_or_radians", expand=True)
1159 la
= abs(pi
* self
.Simple_a
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1160 lb
= abs(pi
* self
.Simple_b
* (self
.Simple_endangle
- self
.Simple_startangle
) / 180)
1161 l
= abs(self
.Simple_a
- self
.Simple_b
) * 2 + la
+ lb
1163 sa
= pi
* self
.Simple_a
* self
.Simple_a
* \
1164 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1166 sb
= pi
* self
.Simple_b
* self
.Simple_b
* \
1167 abs(self
.Simple_endangle
- self
.Simple_startangle
) / 360
1171 if self
.Simple_Type
== 'Rectangle':
1173 col
= box
.column(align
=True)
1174 col
.label(text
=self
.Simple_Type
+ " Options:")
1175 col
.prop(self
, "Simple_width")
1176 col
.prop(self
, "Simple_length")
1177 col
.prop(self
, "Simple_rounded")
1179 box
.prop(self
, "Simple_center")
1180 l
= 2 * abs(self
.Simple_width
) + 2 * abs(self
.Simple_length
)
1181 s
= abs(self
.Simple_width
) * abs(self
.Simple_length
)
1183 if self
.Simple_Type
== 'Rhomb':
1185 col
= box
.column(align
=True)
1186 col
.label(text
=self
.Simple_Type
+ " Options:")
1187 col
.prop(self
, "Simple_width")
1188 col
.prop(self
, "Simple_length")
1189 col
.prop(self
, "Simple_center")
1191 g
= hypot(self
.Simple_width
/ 2, self
.Simple_length
/ 2)
1193 s
= self
.Simple_width
* self
.Simple_length
/ 2
1195 if self
.Simple_Type
== 'Polygon':
1197 col
= box
.column(align
=True)
1198 col
.label(text
=self
.Simple_Type
+ " Options:")
1199 col
.prop(self
, "Simple_sides")
1200 col
.prop(self
, "Simple_radius")
1202 if self
.Simple_Type
== 'Polygon_ab':
1204 col
= box
.column(align
=True)
1205 col
.label(text
="Polygon ab Options:")
1206 col
.prop(self
, "Simple_sides")
1207 col
.prop(self
, "Simple_a")
1208 col
.prop(self
, "Simple_b")
1210 if self
.Simple_Type
== 'Trapezoid':
1212 col
= box
.column(align
=True)
1213 col
.label(text
=self
.Simple_Type
+ " Options:")
1214 col
.prop(self
, "Simple_a")
1215 col
.prop(self
, "Simple_b")
1216 col
.prop(self
, "Simple_h")
1218 box
.prop(self
, "Simple_center")
1219 g
= hypot(self
.Simple_h
, (self
.Simple_a
- self
.Simple_b
) / 2)
1220 l
= self
.Simple_a
+ self
.Simple_b
+ g
* 2
1221 s
= (abs(self
.Simple_a
) + abs(self
.Simple_b
)) / 2 * self
.Simple_h
1224 row
.prop(self
, "shape", expand
=True)
1227 col
= layout
.column()
1228 col
.label(text
="Output Curve Type:")
1229 col
.row().prop(self
, "outputType", expand
=True)
1231 if self
.outputType
== 'NURBS':
1232 col
.prop(self
, "order_u")
1233 elif self
.outputType
== 'BEZIER':
1234 col
.row().prop(self
, 'handleType', expand
=True)
1236 col
= layout
.column()
1237 col
.row().prop(self
, "use_cyclic_u", expand
=True)
1239 col
= layout
.column()
1240 col
.row().prop(self
, "edit_mode", expand
=True)
1242 col
= layout
.column()
1243 # AddObjectHelper props
1244 col
.prop(self
, "align")
1245 col
.prop(self
, "location")
1246 col
.prop(self
, "rotation")
1248 if l
!= 0 or s
!= 0:
1250 box
.label(text
="Statistics:", icon
="INFO")
1252 l_str
= str(round(l
, 4))
1253 box
.label(text
="Length: " + l_str
)
1255 s_str
= str(round(s
, 4))
1256 box
.label(text
="Area: " + s_str
)
1259 def poll(cls
, context
):
1260 return context
.scene
is not None
1262 def execute(self
, context
):
1264 # turn off 'Enter Edit Mode'
1265 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
1266 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
1269 main(context
, self
, use_enter_edit_mode
)
1271 if use_enter_edit_mode
:
1272 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1274 # restore pre operator state
1275 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
1278 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1280 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
1284 def invoke(self
, context
, event
):
1286 self
.execute(context
)
1296 from bpy
.utils
import register_class
1300 bpy
.types
.VIEW3D_MT_curve_add
.append(menu
)
1303 from bpy
.utils
import unregister_class
1304 for cls
in reversed(classes
):
1305 unregister_class(cls
)
1307 bpy
.types
.VIEW3D_MT_curve_add
.remove(menu
)
1309 if __name__
== "__main__":