Cleanup: strip trailing space, remove BOM
[blender-addons.git] / precision_drawing_tools / pdt_trig_waves.py
blob535ac85a9a55fc535cdf89d43df609d492ab8f4a
1 # ***** BEGIN GPL LICENSE BLOCK *****
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # ***** END GPL LICENCE BLOCK *****
20 # -----------------------------------------------------------------------
21 # Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
22 # -----------------------------------------------------------------------
24 import bpy
25 import bmesh
26 from math import sin, cos, tan, pi
27 from mathutils import Vector
28 from .pdt_functions import (
29 set_mode,
30 view_coords,
33 class PDT_OT_WaveGenerator(bpy.types.Operator):
34 """Generate Trig Waves in Active Object"""
35 bl_idname = "pdt.wave_generator"
36 bl_label = "Generate Waves"
37 bl_options = {"REGISTER", "UNDO"}
39 @classmethod
40 def poll(cls, context):
41 pg = context.scene.pdt_pg
42 return pg.trig_obj is not None
44 def execute(self, context):
45 """Generate Trig Waves in Active Object.
47 Note:
48 Uses all the PDT trig_* variables.
50 This function will draw a trigonometrical wave based upon cycle length
51 One cycle is assumed to be 180 degrees, so half a revolution of an imaginary
52 rotating object. If a full cycle from 0 to 360 degrees is required, the cycles
53 number should be set to 2.
55 Args:
56 context: Blender bpy.context instance.
58 Returns:
59 Nothing.
60 """
62 pg = context.scene.pdt_pg
63 plane = pg.plane
64 # Find the horizontal, vertical and depth axes in the view from working plane.
65 # Order is: H, V, D.
67 a1, a2, a3 = set_mode(plane)
68 # Make sure object selected in the UI is the active object.
70 for obj in bpy.data.objects:
71 obj.select_set(state=False)
72 context.view_layer.objects.active = pg.trig_obj
73 # x_inc is the increase in X (Horiz axis) per unit of resolution of the wave, so if
74 # resolution is 9, nine points will be drawn in each cycle representing increases of
75 # 20 degrees and 1/9th of the cycle length.
77 x_inc = pg.trig_len / pg.trig_res
79 if pg.trig_del:
80 # Delete all existing vertices first.
82 bpy.ops.object.mode_set(mode='EDIT')
83 for v in pg.trig_obj.data.vertices:
84 v.select = True
85 bpy.ops.mesh.delete(type='VERT')
86 bpy.ops.object.mode_set(mode='OBJECT')
88 if pg.trig_obj.mode != "EDIT":
89 bpy.ops.object.mode_set(mode='EDIT')
90 bm = bmesh.from_edit_mesh(pg.trig_obj.data)
92 # Loop for each point in the number of cycles times the resolution value.
93 # Uses basic trigonomtry to calculate the wave locations.
94 # If Absolute has been set, all values are made positive.
95 # z_val is assumed to be the offset from the horizontal axis of the wave.
96 # These values will be offset by the Offset Vector given in the UI.
98 for i in range((pg.trig_res * pg.trig_cycles) + 1):
99 # Uses a calculation of trig function angle of imaginary object times maximum amplitude
100 # of wave. So with reolution at 9, angular increments are 20 degrees.
101 # Angles must be in Radians for this calcultion.
103 if pg.trig_type == "sin":
104 if pg.trig_abs:
105 z_val = abs(sin((i / pg.trig_res) * pi) * pg.trig_amp)
106 else:
107 z_val = sin((i / pg.trig_res) * pi) * pg.trig_amp
108 elif pg.trig_type == "cos":
109 if pg.trig_abs:
110 z_val = abs(cos((i / pg.trig_res) * pi) * pg.trig_amp)
111 else:
112 z_val = cos((i / pg.trig_res) * pi) * pg.trig_amp
113 else:
114 if pg.trig_abs:
115 z_val = abs(tan((i / pg.trig_res) * pi) * pg.trig_amp)
116 else:
117 z_val = tan((i / pg.trig_res) * pi) * pg.trig_amp
119 if abs(z_val) > pg.trig_tanmax:
120 if z_val >= 0:
121 z_val = pg.trig_tanmax
122 else:
123 if pg.trig_abs:
124 z_val = pg.trig_tanmax
125 else:
126 z_val = -pg.trig_tanmax
128 # Start with Offset Vector from UI and add wave offsets to it.
129 # Axis a3 (depth) is never changed from offset vector in UI.
131 vert_loc = Vector(pg.trig_off)
132 vert_loc[a1] = vert_loc[a1] + (i * x_inc)
133 vert_loc[a2] = vert_loc[a2] + z_val
134 if plane == "LO":
135 # Translate view local coordinates (horiz, vert, depth) into World XYZ
137 vert_loc = view_coords(vert_loc[a1], vert_loc[a2], vert_loc[a3])
138 vertex_new = bm.verts.new(vert_loc)
139 # Refresh Vertices list in object data.
141 bm.verts.ensure_lookup_table()
142 if i > 0:
143 # Make an edge from last two vertices in object data.
145 bm.edges.new([bm.verts[-2], vertex_new])
147 bmesh.update_edit_mesh(pg.trig_obj.data)
148 bpy.ops.object.mode_set(mode='OBJECT')
150 return {"FINISHED"}