Skip to content
Snippets Groups Projects
pdt_trig_waves.py 5.78 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ***** 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"}