diff --git a/precision_drawing_tools/__init__.py b/precision_drawing_tools/__init__.py
index c2fbf64766db0bddf3d44d91325afc698a6e069e..62de72b67f8f782779e549d5ca27b0cda49958d9 100644
--- a/precision_drawing_tools/__init__.py
+++ b/precision_drawing_tools/__init__.py
@@ -29,8 +29,8 @@
 bl_info = {
     "name": "Precision Drawing Tools (PDT)",
     "author": "Alan Odom (Clockmender), Rune Morling (ermo)",
-    "version": (1, 3, 0),
-    "blender": (2, 82, 0),
+    "version": (1, 4, 0),
+    "blender": (2, 83, 0),
     "location": "View3D > UI > PDT",
     "description": "Precision Drawing Tools for Acccurate Modelling",
     "warning": "",
@@ -54,6 +54,7 @@ if "bpy" in locals():
     importlib.reload(pdt_bix)
     importlib.reload(pdt_etof)
     importlib.reload(pdt_tangent)
+    importlib.reload(pdt_trig_waves)
 else:
     from . import pdt_design
     from . import pdt_pivot_point
@@ -64,11 +65,17 @@ else:
     from . import pdt_bix
     from . import pdt_etof
     from . import pdt_tangent
+    from . import pdt_trig_waves
 
 import bpy
 import os
 from pathlib import Path
-from bpy.types import AddonPreferences, PropertyGroup, Scene, WindowManager
+from bpy.types import (
+    AddonPreferences,
+    PropertyGroup, Scene,
+    WindowManager,
+    Object,
+)
 from bpy.props import (
     BoolProperty,
     CollectionProperty,
@@ -130,6 +137,39 @@ _pdt_col_items = []
 _pdt_mat_items = []
 
 
+class PDTPreferences(AddonPreferences):
+    # This must match the addon name, use '__package__'
+    # when defining this in a submodule of a python package.
+
+    bl_idname = __name__
+
+    debug: BoolProperty(
+        name="Enable console debug output from PDT scripts",
+        default=False,
+        description="NOTE: Does not enable debugging globally in Blender (only in PDT scripts)",
+    )
+
+    pdt_ui_width: IntProperty(
+        name="UI Width Cut-off",
+        default=350,
+        description="Cutoff width for shrinking items per line in menus",
+    )
+
+    pdt_input_round: IntProperty(
+        name="Input Rounding", default=5, description="Rounding Factor for Inputs"
+    )
+
+    def draw(self, context):
+        layout = self.layout
+
+        box = layout.box()
+        row1 = box.row()
+        row2 = box.row()
+        row1.prop(self, "debug")
+        row2.prop(self, "pdt_ui_width")
+        row2.prop(self, "pdt_input_round")
+
+
 def enumlist_objects(self, context):
     """Populate Objects List from Parts Library.
 
@@ -145,8 +185,8 @@ def enumlist_objects(self, context):
 
     scene = context.scene
     pg = scene.pdt_pg
-    file_path = context.preferences.addons[__package__].preferences.pdt_library_path
-    path = Path(file_path)
+    file_path = pg.pdt_library_path
+    path = Path(bpy.path.abspath(file_path))
     _pdt_obj_items.clear()
 
     if path.is_file() and ".blend" in str(path):
@@ -158,7 +198,7 @@ def enumlist_objects(self, context):
         for object_name in object_names:
             _pdt_obj_items.append((object_name, object_name, ""))
     else:
-        _pdt_obj_items.append(("MISSING", "Library is Missing", ""))
+        _pdt_obj_items.append(("MISSING", "Library Not Set", ""))
     return _pdt_obj_items
 
 
@@ -177,8 +217,8 @@ def enumlist_collections(self, context):
 
     scene = context.scene
     pg = scene.pdt_pg
-    file_path = context.preferences.addons[__package__].preferences.pdt_library_path
-    path = Path(file_path)
+    file_path = pg.pdt_library_path
+    path = Path(bpy.path.abspath(file_path))
     _pdt_col_items.clear()
 
     if path.is_file() and ".blend" in str(path):
@@ -192,7 +232,7 @@ def enumlist_collections(self, context):
         for object_name in object_names:
             _pdt_col_items.append((object_name, object_name, ""))
     else:
-        _pdt_col_items.append(("MISSING", "Library is Missing", ""))
+        _pdt_col_items.append(("MISSING", "Library Not Set", ""))
     return _pdt_col_items
 
 
@@ -211,8 +251,8 @@ def enumlist_materials(self, context):
 
     scene = context.scene
     pg = scene.pdt_pg
-    file_path = context.preferences.addons[__package__].preferences.pdt_library_path
-    path = Path(file_path)
+    file_path = pg.pdt_library_path
+    path = Path(bpy.path.abspath(file_path))
     _pdt_mat_items.clear()
 
     if path.is_file() and ".blend" in str(path):
@@ -226,13 +266,21 @@ def enumlist_materials(self, context):
         for object_name in object_names:
             _pdt_mat_items.append((object_name, object_name, ""))
     else:
-        _pdt_mat_items.append(("MISSING", "Library is Missing", ""))
+        _pdt_mat_items.append(("MISSING", "Library Not Set", ""))
     return _pdt_mat_items
 
 
 class PDTSceneProperties(PropertyGroup):
     """Contains all PDT related properties."""
 
+    pdt_library_path: StringProperty(
+        name="Library",
+        default="",
+        description="Parts Library File",
+        maxlen=1024,
+        subtype="FILE_PATH",
+    )
+
     object_search_string: StringProperty(name="Search", default="", description=PDT_DES_LIBSER)
     collection_search_string: StringProperty(name="Search", default="", description=PDT_DES_LIBSER)
     material_search_string: StringProperty(name="Search", default="", description=PDT_DES_LIBSER)
@@ -429,48 +477,34 @@ class PDTSceneProperties(PropertyGroup):
         description=PDT_DES_TANMODE,
     )
 
-
-class PDTPreferences(AddonPreferences):
-    # This must match the addon name, use '__package__'
-    # when defining this in a submodule of a python package.
-
-    bl_idname = __name__
-
-    pdt_library_path: StringProperty(
-        name="Parts Library",
-        default="",
-        description="Parts Library File",
-        maxlen=1024,
-        subtype="FILE_PATH",
-    )
-
-    debug: BoolProperty(
-        name="Enable console debug output from PDT scripts",
-        default=False,
-        description="NOTE: Does not enable debugging globally in Blender (only in PDT scripts)",
-    )
-
-    pdt_ui_width: IntProperty(
-        name="UI Width Cut-off",
-        default=350,
-        description="Cutoff width for shrinking items per line in menus",
-    )
-
-    pdt_input_round: IntProperty(
-        name="Input Rounding", default=5, description="Rounding Factor for Inputs"
-    )
-
-    def draw(self, context):
-        layout = self.layout
-
-        box = layout.box()
-        row1 = box.row()
-        row2 = box.row()
-        row3 = box.row()
-        row1.prop(self, "debug")
-        row2.prop(self, "pdt_ui_width")
-        row2.prop(self, "pdt_input_round")
-        row3.prop(self, "pdt_library_path")
+    # For Trig Waves
+    trig_type : EnumProperty(
+        items=(
+            ("sin", "Sine", "Sine Wave"),
+            ("cos", "Cosine", "Cosine Wave"),
+            ("tan", "Tangent", "Tangent Wave"),
+        ),
+        name="Wave Form",
+        default="sin",
+        description="Trig. Wave Form",
+    )
+    trig_cycles : IntProperty(name="Cycles #", default=1, min=1,
+        description="1 Cycle = 180 Degrees")
+    trig_amp : FloatProperty(name="Amplitude", default=1, min=0.01,
+        description="Maximum Height of 1 Cycle (forms Basis for Tangents)")
+    trig_len : FloatProperty(name="Cycle Length", default=2, min=0.02,
+        description="Length in Blender Units of 1 Cycle")
+    trig_obj : PointerProperty(name="Object", type=Object)
+    trig_del : BoolProperty(name="Empty Object", default=False,
+        description="Delete ALL Vertices in Object First")
+    trig_res : IntProperty(name="Resolution", default=18, min=4, max=72,
+        description="Number of Vertices per Cycle (180 Degrees)")
+    trig_tanmax : FloatProperty(name="Tangent Max", default=10, min=0.1,
+        description="Maximum Permitted Tangent Value")
+    trig_off : FloatVectorProperty(name="Start Loc", default=(0,0,0),
+        description="Location in World Space for Origin of Wave")
+    trig_abs : BoolProperty(name="Absolute", default=False,
+        description="Use Absolute Values Only")
 
 
 # List of All Classes in the Add-on to register
@@ -479,8 +513,8 @@ class PDTPreferences(AddonPreferences):
 # (and unloaded last)
 #
 classes = (
-    PDTSceneProperties,
     PDTPreferences,
+    PDTSceneProperties,
     pdt_bix.PDT_OT_LineOnBisection,
     pdt_command.PDT_OT_CommandReRun,
     pdt_design.PDT_OT_PlacementAbs,
@@ -507,6 +541,7 @@ classes = (
     pdt_menus.PDT_PT_PanelViewControl,
     pdt_menus.PDT_PT_PanelPivotPoint,
     pdt_menus.PDT_PT_PanelPartsLibrary,
+    pdt_menus.PDT_PT_PanelTrig,
     pdt_pivot_point.PDT_OT_ModalDrawOperator,
     pdt_pivot_point.PDT_OT_ViewPlaneRotate,
     pdt_pivot_point.PDT_OT_ViewPlaneScale,
@@ -523,6 +558,7 @@ classes = (
     pdt_tangent.PDT_OT_TangentSet3,
     pdt_tangent.PDT_OT_TangentSet4,
     pdt_tangent.PDT_OT_TangentExpandMenu,
+    pdt_trig_waves.PDT_OT_WaveGenerator,
     pdt_view.PDT_OT_ViewRot,
     pdt_view.PDT_OT_ViewRotL,
     pdt_view.PDT_OT_ViewRotR,
diff --git a/precision_drawing_tools/pdt_library.py b/precision_drawing_tools/pdt_library.py
index a0b1a6be96b03e99a6c6a69604cd20ccf1a4c26b..4850481b01d21ffe0f059d148b10a54262e8f9ab 100644
--- a/precision_drawing_tools/pdt_library.py
+++ b/precision_drawing_tools/pdt_library.py
@@ -48,7 +48,7 @@ class PDT_OT_LibShow(Operator):
 
         scene = context.scene
         pg = scene.pdt_pg
-        file_path = context.preferences.addons[__package__].preferences.pdt_library_path
+        file_path = pg.pdt_library_path
         pg.error = str(Path(file_path))
         debug("PDT Parts Library:")
         debug(f"{pg.error}")
@@ -89,10 +89,10 @@ class PDT_OT_Append(Operator):
                 return {"FINISHED"}
 
         obj_names = [o.name for o in context.view_layer.objects].copy()
-        file_path = context.preferences.addons[__package__].preferences.pdt_library_path
+        file_path = pg.pdt_library_path
         path = Path(file_path)
 
-        if path.is_file() and ".blend" in str(path):
+        if path.is_file() and str(path).endswith(".blend"):
             if pg.lib_mode == "OBJECTS":
                 bpy.ops.wm.append(
                     filepath=str(path),
@@ -170,9 +170,10 @@ class PDT_OT_Link(Operator):
                 self.report({"ERROR"}, error_message)
                 return {"FINISHED"}
 
-        file_path = context.preferences.addons[__package__].preferences.pdt_library_path
+        file_path = pg.pdt_library_path
         path = Path(file_path)
-        if path.is_file() and ".blend" in str(path):
+
+        if path.is_file() and str(path).endswith(".blend"):
             if pg.lib_mode == "OBJECTS":
                 bpy.ops.wm.link(
                     filepath=str(path),
diff --git a/precision_drawing_tools/pdt_menus.py b/precision_drawing_tools/pdt_menus.py
index c42d18c9e67acb52ffb556ef1338a8d6c21cefd4..be452f018038ba1f3158c44fcdb81281a22340b9 100644
--- a/precision_drawing_tools/pdt_menus.py
+++ b/precision_drawing_tools/pdt_menus.py
@@ -306,6 +306,8 @@ class PDT_PT_PanelPartsLibrary(Panel):
         layout = self.layout
         pdt_pg = context.scene.pdt_pg
         row = layout.row()
+        row.prop(pdt_pg, "pdt_library_path")
+        row = layout.row()
         col = row.column()
         col.operator("pdt.append", text="Append")
         col = row.column()
@@ -339,7 +341,7 @@ class PDT_PT_PanelPartsLibrary(Panel):
         row = box.row()
         row.prop(pdt_pg, "lib_materials", text="")
         row = box.row()
-        row.operator("pdt.lib_show", text="Show Library File", icon='INFO')
+        #row.operator("pdt.lib_show", text="Load Library File", icon='INFO')
 
 
 class PDT_PT_PanelViewControl(Panel):
@@ -474,3 +476,40 @@ class PDT_PT_PanelTangent(Panel):
             split.prop(pdt_pg, "tangent_radius1", text="")
             row = box.row()
             row.operator("pdt.tangentoperate", text="Tangents From Inputs", icon="NONE")
+
+class PDT_PT_PanelTrig(Panel):
+    bl_idname = "PDT_PT_PanelTrig"
+    bl_label = "PDT Trigonometrical Waves"
+    bl_space_type = "VIEW_3D"
+    bl_region_type = "UI"
+    bl_category = "PDT"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self,context):
+        layout = self.layout
+        pdt_pg = context.scene.pdt_pg
+        row = layout.row()
+        row.label(text=f"Working {PDT_LAB_PLANE}:")
+        row.prop(pdt_pg, "plane", text="")
+
+        row = layout.row()
+        split = row.split(factor=0.5, align=True)
+        split.prop(pdt_pg, "trig_type")
+        split.prop(pdt_pg, "trig_cycles")
+        row = layout.row()
+        split = row.split(factor=0.5, align=True)
+        split.prop(pdt_pg, "trig_amp")
+        split.prop(pdt_pg, "trig_len")
+        row = layout.row()
+        split = row.split(factor=0.5, align=True)
+        split.prop(pdt_pg, "trig_obj", text="")
+        split.prop(pdt_pg, "trig_del")
+        row = layout.row()
+        split = row.split(factor=0.5, align=True)
+        split.prop(pdt_pg, "trig_res")
+        split.prop(pdt_pg, "trig_tanmax")
+        row = layout.row()
+        row.prop(pdt_pg, "trig_off")
+        row = layout.row()
+        row.operator("pdt.wave_generator", icon="SEQ_LUMA_WAVEFORM")
+        row.prop(pdt_pg, "trig_abs")
diff --git a/precision_drawing_tools/pdt_msg_strings.py b/precision_drawing_tools/pdt_msg_strings.py
index 8d01abb206cf38f092f744f31cdb3a549f9e7c25..7d0cc2bc6604519472795f4c64bfccd29f07c415 100644
--- a/precision_drawing_tools/pdt_msg_strings.py
+++ b/precision_drawing_tools/pdt_msg_strings.py
@@ -94,8 +94,8 @@ PDT_ERR_VERT_MODE = "Work in Vertex Mode for this Function"
 PDT_ERR_NOPPLOC = (
     "Custom Property PDT_PP_LOC for this object not found, have you Written it yet?"
 )
-PDT_ERR_NO_LIBRARY = ("PDT Library Blend File (parts_library.blend) is Missing "
-                      + "from Addons/clockworxpdt Folder")
+PDT_ERR_NO_LIBRARY = ("PDT Library Blend File is Missing "
+                      + "or not Correctly Set to a Blend File")
 
 PDT_ERR_SEL_1_VERTI = "Select at least 1 Vertex Individually (Currently selected:"
 PDT_ERR_SEL_1_VERT = "Select at least 1 Vertex (Currently selected:"
diff --git a/precision_drawing_tools/pdt_tangent.py b/precision_drawing_tools/pdt_tangent.py
index d743d3ebd104783b39f0b1e9f35ae52629aaf078..22b34c7a2a3efddf11766543f7c29c55773e6bd7 100644
--- a/precision_drawing_tools/pdt_tangent.py
+++ b/precision_drawing_tools/pdt_tangent.py
@@ -114,6 +114,8 @@ def get_tangent_points(context, hloc_0, vloc_0, radius_0, hloc_p, vloc_p):
         vloc_t2: Vertical Location of Second Tangent Point
     """
 
+    # Uses basic Pythagorus' theorem to compute locations
+    #
     numerator = (radius_0 ** 2 * (hloc_p - hloc_0)) + (
         radius_0
         * (vloc_p - vloc_0)
@@ -186,6 +188,8 @@ def make_vectors(coords, a1, a2, a3, pg):
     tangent_vector_o4[a3] = coords[8]
 
     if pg.plane == "LO":
+        # Reset coordinates from view local (Horiz, Vert, depth) to World XYZ.
+        #
         tangent_vector_o1 = view_coords(
             tangent_vector_o1[a1], tangent_vector_o1[a2], tangent_vector_o1[a3]
         )
@@ -223,6 +227,8 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
     a1, a2, a3 = set_mode(plane)
     mode = pg.tangent_mode
     if plane == "LO":
+        # Translate world cordinates into view local (horiz, vert, depth)
+        #
         centre_0 = view_coords_i(centre_0[a1], centre_0[a2], centre_0[a3])
         centre_1 = view_coords_i(centre_1[a1], centre_1[a2], centre_1[a3])
         centre_2 = view_coords_i(centre_2[a1], centre_2[a2], centre_2[a3])
@@ -239,6 +245,7 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
         (distance <= radius_0 or distance <= radius_1 and mode in {"outer", "both"})
         ):
         # Cannot execute, centres are too close.
+        #
         pg.error = f"{PDT_ERR_BADDISTANCE}"
         context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
         return {"FINISHED"}
@@ -260,6 +267,7 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
             context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
             return {"FINISHED"}
         # Point Tangents
+        #
         tangent_vector_o1 = Vector((0, 0, 0))
         tangent_vector_o1[a1] = hloc_to1
         tangent_vector_o1[a2] = vloc_to1
@@ -269,6 +277,8 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
         tangent_vector_o2[a2] = vloc_to2
         tangent_vector_o2[a3] = centre_2[a3]
         if pg.plane == "LO":
+            # Translate view local coordinates (horiz, vert, depth) into World XYZ
+            #
             centre_2 = view_coords(centre_2[a1], centre_2[a2], centre_2[a3])
             tangent_vector_o1 = view_coords(
                 tangent_vector_o1[a1], tangent_vector_o1[a2], tangent_vector_o1[a3]
@@ -287,8 +297,11 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
     """
 
     if mode in {"outer", "both"}:
+        # Uses basic trigonometry and Pythagorus' theorem to compute locations
+        #
         if radius_0 == radius_1:
             # No intersection point for outer tangents
+            #
             sin_angle = (centre_1[a2] - centre_0[a2]) / distance
             cos_angle = (centre_1[a1] - centre_0[a1]) / distance
             hloc_to1 = centre_0[a1] + (radius_0 * sin_angle)
@@ -342,6 +355,8 @@ def tangent_setup(context, pg, plane, obj_data, centre_0, centre_1, centre_2, ra
     """
 
     if mode in {"inner", "both"}:
+        # Uses basic trigonometry and Pythagorus' theorem to compute locations
+        #
         hloc_pi, vloc_pi = get_tangent_intersect_inner(
             centre_0[a1], centre_0[a2], centre_1[a1], centre_1[a2], radius_0, radius_1
         )
@@ -442,6 +457,8 @@ def analyse_arc(context, pg):
             context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
             raise PDT_SelectionError
         vector_a = verts[0].co
+        # Get the nearest to middle vertex of the arc
+        #
         vector_b = verts[int(floor(len(verts) / 2))].co
         vector_c = verts[-1].co
         vector_delta, radius = arc_centre(vector_a, vector_b, vector_c)
@@ -484,6 +501,7 @@ class PDT_OT_TangentOperate(Operator):
         Returns:
             Nothing.
         """
+
         scene = context.scene
         pg = scene.pdt_pg
         plane = pg.plane
@@ -521,7 +539,7 @@ class PDT_OT_TangentOperateSel(Operator):
     bl_idname = "pdt.tangentoperatesel"
     bl_label = "Calculate Tangents"
     bl_options = {"REGISTER", "UNDO"}
-    bl_description = "Calculate Tangents to Arcs from 2 Selected Vertices, or 1 & Point"
+    bl_description = "Calculate Tangents to Arcs from 2 Selected Vertices, or 1 & Point in Menu"
 
     @classmethod
     def poll(cls, context):
@@ -601,6 +619,8 @@ class PDT_OT_TangentOperateSel(Operator):
             e.select_set(False)
         bmesh.update_edit_mesh(obj.data)
         bm.select_history.clear()
+        # Select the nearest to middle vertex in the arc
+        #
         verts1 = [verts1[0].co, verts1[int(floor(len(verts1) / 2))].co, verts1[-1].co]
         vertsn = [vertsn[0].co, vertsn[int(floor(len(vertsn) / 2))].co, vertsn[-1].co]
         centre_0, radius_0 = arc_centre(verts1[0], verts1[1], verts1[2])
@@ -756,6 +776,9 @@ class PDT_OT_TangentExpandMenu(Operator):
     def execute(self, context):
         """Expand/Collapse Tangent Menu.
 
+        Note:
+            This is used to add further options to the menu.
+
         Args:
             context: Blender bpy.context instance.
 
diff --git a/precision_drawing_tools/pdt_trig_waves.py b/precision_drawing_tools/pdt_trig_waves.py
new file mode 100644
index 0000000000000000000000000000000000000000..535ac85a9a55fc535cdf89d43df609d492ab8f4a
--- /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"}