diff options
Diffstat (limited to 'precision_drawing_tools/pdt_trig_waves.py')
-rw-r--r-- | precision_drawing_tools/pdt_trig_waves.py | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/precision_drawing_tools/pdt_trig_waves.py b/precision_drawing_tools/pdt_trig_waves.py new file mode 100644 index 00000000..535ac85a --- /dev/null +++ b/precision_drawing_tools/pdt_trig_waves.py @@ -0,0 +1,150 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENCE BLOCK ***** +# +# ----------------------------------------------------------------------- +# Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019 +# ----------------------------------------------------------------------- +# +import bpy +import bmesh +from math import sin, cos, tan, pi +from mathutils import Vector +from .pdt_functions import ( + set_mode, + view_coords, +) + +class PDT_OT_WaveGenerator(bpy.types.Operator): + """Generate Trig Waves in Active Object""" + bl_idname = "pdt.wave_generator" + bl_label = "Generate Waves" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + pg = context.scene.pdt_pg + return pg.trig_obj is not None + + def execute(self, context): + """Generate Trig Waves in Active Object. + + Note: + Uses all the PDT trig_* variables. + + This function will draw a trigonometrical wave based upon cycle length + One cycle is assumed to be 180 degrees, so half a revolution of an imaginary + rotating object. If a full cycle from 0 to 360 degrees is required, the cycles + number should be set to 2. + + Args: + context: Blender bpy.context instance. + + Returns: + Nothing. + """ + + pg = context.scene.pdt_pg + plane = pg.plane + # Find the horizontal, vertical and depth axes in the view from working plane. + # Order is: H, V, D. + # + a1, a2, a3 = set_mode(plane) + # Make sure object selected in the UI is the active object. + # + for obj in bpy.data.objects: + obj.select_set(state=False) + context.view_layer.objects.active = pg.trig_obj + # x_inc is the increase in X (Horiz axis) per unit of resolution of the wave, so if + # resolution is 9, nine points will be drawn in each cycle representing increases of + # 20 degrees and 1/9th of the cycle length. + # + x_inc = pg.trig_len / pg.trig_res + + if pg.trig_del: + # Delete all existing vertices first. + # + bpy.ops.object.mode_set(mode='EDIT') + for v in pg.trig_obj.data.vertices: + v.select = True + bpy.ops.mesh.delete(type='VERT') + bpy.ops.object.mode_set(mode='OBJECT') + + if pg.trig_obj.mode != "EDIT": + bpy.ops.object.mode_set(mode='EDIT') + bm = bmesh.from_edit_mesh(pg.trig_obj.data) + + # Loop for each point in the number of cycles times the resolution value. + # Uses basic trigonomtry to calculate the wave locations. + # If Absolute has been set, all values are made positive. + # z_val is assumed to be the offset from the horizontal axis of the wave. + # These values will be offset by the Offset Vector given in the UI. + # + for i in range((pg.trig_res * pg.trig_cycles) + 1): + # Uses a calculation of trig function angle of imaginary object times maximum amplitude + # of wave. So with reolution at 9, angular increments are 20 degrees. + # Angles must be in Radians for this calcultion. + # + if pg.trig_type == "sin": + if pg.trig_abs: + z_val = abs(sin((i / pg.trig_res) * pi) * pg.trig_amp) + else: + z_val = sin((i / pg.trig_res) * pi) * pg.trig_amp + elif pg.trig_type == "cos": + if pg.trig_abs: + z_val = abs(cos((i / pg.trig_res) * pi) * pg.trig_amp) + else: + z_val = cos((i / pg.trig_res) * pi) * pg.trig_amp + else: + if pg.trig_abs: + z_val = abs(tan((i / pg.trig_res) * pi) * pg.trig_amp) + else: + z_val = tan((i / pg.trig_res) * pi) * pg.trig_amp + + if abs(z_val) > pg.trig_tanmax: + if z_val >= 0: + z_val = pg.trig_tanmax + else: + if pg.trig_abs: + z_val = pg.trig_tanmax + else: + z_val = -pg.trig_tanmax + + # Start with Offset Vector from UI and add wave offsets to it. + # Axis a3 (depth) is never changed from offset vector in UI. + # + vert_loc = Vector(pg.trig_off) + vert_loc[a1] = vert_loc[a1] + (i * x_inc) + vert_loc[a2] = vert_loc[a2] + z_val + if plane == "LO": + # Translate view local coordinates (horiz, vert, depth) into World XYZ + # + vert_loc = view_coords(vert_loc[a1], vert_loc[a2], vert_loc[a3]) + vertex_new = bm.verts.new(vert_loc) + # Refresh Vertices list in object data. + # + bm.verts.ensure_lookup_table() + if i > 0: + # Make an edge from last two vertices in object data. + # + bm.edges.new([bm.verts[-2], vertex_new]) + + bmesh.update_edit_mesh(pg.trig_obj.data) + bpy.ops.object.mode_set(mode='OBJECT') + + return {"FINISHED"} |