From 73bda89771d9c4bf57e5b1fbaa5e067f9ca00403 Mon Sep 17 00:00:00 2001 From: Ryan Inch Date: Sun, 10 May 2020 23:36:00 -0400 Subject: Collection Manager: QCD tooltip fixes. Task: T69577 Add LMB shortcut to the QCD header widget tooltip. Remove redundant references to QCD from this tooltip. --- object_collection_manager/__init__.py | 2 +- object_collection_manager/qcd_operators.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/object_collection_manager/__init__.py b/object_collection_manager/__init__.py index 65ebe49c..5c3edb7a 100644 --- a/object_collection_manager/__init__.py +++ b/object_collection_manager/__init__.py @@ -22,7 +22,7 @@ bl_info = { "name": "Collection Manager", "description": "Manage collections and their objects", "author": "Ryan Inch", - "version": (2, 7, 20), + "version": (2, 7, 21), "blender": (2, 80, 0), "location": "View3D - Object Mode (Shortcut - M)", "warning": '', # used for warning icon and text in addons panel diff --git a/object_collection_manager/qcd_operators.py b/object_collection_manager/qcd_operators.py index 9d5242e5..78d65643 100644 --- a/object_collection_manager/qcd_operators.py +++ b/object_collection_manager/qcd_operators.py @@ -140,8 +140,9 @@ class ViewMoveQCDSlot(Operator): slot_string = f"QCD Slot {properties.slot}: \"{slot_name}\"\n" hotkey_string = ( - " * Shift+LMB - Toggle QCD slot.\n" - " * Ctrl+LMB - Move objects to QCD slot.\n" + " * LMB - Isolate slot.\n" + " * Shift+LMB - Toggle slot.\n" + " * Ctrl+LMB - Move objects to slot.\n" " * Ctrl+Shift+LMB - Toggle objects' slot" ) -- cgit v1.2.3 From 1f161da140806c8ac441c7108973036307800d81 Mon Sep 17 00:00:00 2001 From: Ryan Inch Date: Mon, 11 May 2020 00:40:00 -0400 Subject: Collection Manager: Global Exclude RTO fix. Task: T69577 Fix the Global Exclude RTO unnecessarily resetting the active collection to the Scene Collection. --- object_collection_manager/__init__.py | 2 +- object_collection_manager/operators.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/object_collection_manager/__init__.py b/object_collection_manager/__init__.py index 5c3edb7a..dcb4daf0 100644 --- a/object_collection_manager/__init__.py +++ b/object_collection_manager/__init__.py @@ -22,7 +22,7 @@ bl_info = { "name": "Collection Manager", "description": "Manage collections and their objects", "author": "Ryan Inch", - "version": (2, 7, 21), + "version": (2, 7, 22), "blender": (2, 80, 0), "location": "View3D - Object Mode (Shortcut - M)", "warning": '', # used for warning icon and text in addons panel diff --git a/object_collection_manager/operators.py b/object_collection_manager/operators.py index ce39867e..4d028cf2 100644 --- a/object_collection_manager/operators.py +++ b/object_collection_manager/operators.py @@ -412,6 +412,7 @@ class CMUnExcludeAllOperator(Operator): def invoke(self, context, event): global rto_history + orig_active_collection = context.view_layer.active_layer_collection view_layer = context.view_layer.name modifiers = get_modifiers(event) @@ -436,6 +437,9 @@ class CMUnExcludeAllOperator(Operator): else: activate_all_rtos(view_layer, "exclude") + # reset active collection + context.view_layer.active_layer_collection = orig_active_collection + return {'FINISHED'} -- cgit v1.2.3 From 590710871b7b2e1f7f50bb622f1409b794ad38c2 Mon Sep 17 00:00:00 2001 From: Alan Odom Date: Mon, 11 May 2020 23:33:59 +0200 Subject: PDT: Fix Library path issue, Add Trig Waves Functions An issue occurred if you opened Blender with a new file where the Parts Library path pointed relative to the Blender App, not the working directory, so was not found. The Parts Library file is now moved to the Parts Library Menu, so must be set for new .blend files. Existing .blend files are not affected by this change. Error message altered to reflect the option of having this Parts Library live anywhere. New Feature: Add Trig Waves Functions Requires the user to select an existing object in the Trig menu. --- precision_drawing_tools/__init__.py | 146 +++++++++++++++++----------- precision_drawing_tools/pdt_library.py | 11 ++- precision_drawing_tools/pdt_menus.py | 41 +++++++- precision_drawing_tools/pdt_msg_strings.py | 4 +- precision_drawing_tools/pdt_tangent.py | 25 ++++- precision_drawing_tools/pdt_trig_waves.py | 150 +++++++++++++++++++++++++++++ 6 files changed, 313 insertions(+), 64 deletions(-) create mode 100644 precision_drawing_tools/pdt_trig_waves.py diff --git a/precision_drawing_tools/__init__.py b/precision_drawing_tools/__init__.py index c2fbf647..62de72b6 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 a0b1a6be..4850481b 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 c42d18c9..be452f01 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 8d01abb2..7d0cc2bc 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 d743d3eb..22b34c7a 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 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"} -- cgit v1.2.3