1 # SPDX-FileCopyrightText: 2019-2022 Alan Odom (Clockmender)
2 # SPDX-FileCopyrightText: 2019-2022 Rune Morling (ermo)
4 # SPDX-License-Identifier: GPL-2.0-or-later
8 from math
import sin
, cos
, tan
, pi
9 from mathutils
import Vector
10 from .pdt_functions
import (
15 class PDT_OT_WaveGenerator(bpy
.types
.Operator
):
16 """Generate Trig Waves in Active Object"""
17 bl_idname
= "pdt.wave_generator"
18 bl_label
= "Generate Waves"
19 bl_options
= {"REGISTER", "UNDO"}
22 def poll(cls
, context
):
23 pg
= context
.scene
.pdt_pg
24 return pg
.trig_obj
is not None
26 def execute(self
, context
):
27 """Generate Trig Waves in Active Object.
30 Uses all the PDT trig_* variables.
32 This function will draw a trigonometrical wave based upon cycle length
33 One cycle is assumed to be 180 degrees, so half a revolution of an imaginary
34 rotating object. If a full cycle from 0 to 360 degrees is required, the cycles
35 number should be set to 2.
38 context: Blender bpy.context instance.
44 pg
= context
.scene
.pdt_pg
46 # Find the horizontal, vertical and depth axes in the view from working plane.
49 a1
, a2
, a3
= set_mode(plane
)
50 # Make sure object selected in the UI is the active object.
52 for obj
in bpy
.data
.objects
:
53 obj
.select_set(state
=False)
54 context
.view_layer
.objects
.active
= pg
.trig_obj
55 # x_inc is the increase in X (Horiz axis) per unit of resolution of the wave, so if
56 # resolution is 9, nine points will be drawn in each cycle representing increases of
57 # 20 degrees and 1/9th of the cycle length.
59 x_inc
= pg
.trig_len
/ pg
.trig_res
62 # Delete all existing vertices first.
64 bpy
.ops
.object.mode_set(mode
='EDIT')
65 for v
in pg
.trig_obj
.data
.vertices
:
67 bpy
.ops
.mesh
.delete(type='VERT')
68 bpy
.ops
.object.mode_set(mode
='OBJECT')
70 if pg
.trig_obj
.mode
!= "EDIT":
71 bpy
.ops
.object.mode_set(mode
='EDIT')
72 bm
= bmesh
.from_edit_mesh(pg
.trig_obj
.data
)
74 # Loop for each point in the number of cycles times the resolution value.
75 # Uses basic trigonomtry to calculate the wave locations.
76 # If Absolute has been set, all values are made positive.
77 # z_val is assumed to be the offset from the horizontal axis of the wave.
78 # These values will be offset by the Offset Vector given in the UI.
80 for i
in range((pg
.trig_res
* pg
.trig_cycles
) + 1):
81 # Uses a calculation of trig function angle of imaginary object times maximum amplitude
82 # of wave. So with reolution at 9, angular increments are 20 degrees.
83 # Angles must be in Radians for this calcultion.
85 if pg
.trig_type
== "sin":
87 z_val
= abs(sin((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
)
89 z_val
= sin((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
90 elif pg
.trig_type
== "cos":
92 z_val
= abs(cos((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
)
94 z_val
= cos((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
97 z_val
= abs(tan((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
)
99 z_val
= tan((i
/ pg
.trig_res
) * pi
) * pg
.trig_amp
101 if abs(z_val
) > pg
.trig_tanmax
:
103 z_val
= pg
.trig_tanmax
106 z_val
= pg
.trig_tanmax
108 z_val
= -pg
.trig_tanmax
110 # Start with Offset Vector from UI and add wave offsets to it.
111 # Axis a3 (depth) is never changed from offset vector in UI.
113 vert_loc
= Vector(pg
.trig_off
)
114 vert_loc
[a1
] = vert_loc
[a1
] + (i
* x_inc
)
115 vert_loc
[a2
] = vert_loc
[a2
] + z_val
117 # Translate view local coordinates (horiz, vert, depth) into World XYZ
119 vert_loc
= view_coords(vert_loc
[a1
], vert_loc
[a2
], vert_loc
[a3
])
120 vertex_new
= bm
.verts
.new(vert_loc
)
121 # Refresh Vertices list in object data.
123 bm
.verts
.ensure_lookup_table()
125 # Make an edge from last two vertices in object data.
127 bm
.edges
.new([bm
.verts
[-2], vertex_new
])
129 bmesh
.update_edit_mesh(pg
.trig_obj
.data
)
130 bpy
.ops
.object.mode_set(mode
='OBJECT')