Skip to content
Snippets Groups Projects
pdt_design.py 23.4 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
    # -----------------------------------------------------------------------
    #
    from bpy.types import Operator
    from .pdt_msg_strings import (
        PDT_ERR_NON_VALID,
        PDT_LAB_ABS,
        PDT_LAB_DEL,
        PDT_LAB_DIR,
        PDT_LAB_INTERSECT,
        PDT_LAB_PERCENT,
    )
    
    
    class PDT_OT_PlacementAbs(Operator):
        """Use Absolute, or Global Placement."""
    
        bl_idname = "pdt.absolute"
        bl_label = "Absolute Mode"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Manipulates Geometry, or Objects by Absolute (World) Coordinates.
    
    
            Note:
                - Reads pg.operate from Operation Mode Selector as 'operation'
                - Reads pg.cartesian_coords scene variables to:
                -- set position of CUrsor      (CU)
                -- set postion of Pivot Point  (PP)
                -- MoVe geometry/objects       (MV)
                -- Extrude Vertices            (EV)
                -- Split Edges                 (SE)
                -- add a New Vertex            (NV)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
    
            decimal_places = context.preferences.addons[__package__].preferences.pdt_input_round
    
    
            if operation == "CU":
                # Cursor
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ca{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
    Alan Odom's avatar
    Alan Odom committed
                )
    
            elif operation == "PP":
                # Pivot Point
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"pa{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
    Alan Odom's avatar
    Alan Odom committed
                )
    
            elif operation == "MV":
                # Move Entities
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ga{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
    Alan Odom's avatar
    Alan Odom committed
                )
    
            elif operation == "SE":
                # Split Edges
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"sa{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
    Alan Odom's avatar
    Alan Odom committed
                )
    
            elif operation == "NV":
                # New Vertex
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"na{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "EV":
                # Extrude Vertices
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"va{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_ABS}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    
    class PDT_OT_PlacementDelta(Operator):
        """Use Delta, or Incremental Placement."""
    
        bl_idname = "pdt.delta"
        bl_label = "Delta Mode"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Manipulates Geometry, or Objects by Delta Offset (Increment).
    
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                - Reads pg.select, pg.plane, pg.cartesian_coords scene variables to:
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- Split Edges                  (SE)
                -- add a New Vertex             (NV)
                -- Duplicate Geometry           (DG)
                -- Extrude Geometry             (EG)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
    
            decimal_places = context.preferences.addons[__package__].preferences.pdt_input_round
    
    
            if operation == "CU":
                # Cursor
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"cd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "PP":
                # Pivot Point
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"pd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "MV":
                # Move Entities
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"gd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "SE":
                # Split Edges
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"sd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "NV":
                # New Vertex
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"nd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "EV":
                # Extrue Vertices
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"vd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "DG":
                # Duplicate Entities
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"dd{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
            elif operation == "EG":
                # Extrue Geometry
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ed{str(round(pg.cartesian_coords.x, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.y, decimal_places))}"
                    f",{str(round(pg.cartesian_coords.z, decimal_places))}"
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DEL}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    
    class PDT_OT_PlacementDis(Operator):
        """Use Directional, or Distance @ Angle Placement."""
    
        bl_idname = "pdt.distance"
        bl_label = "Distance@Angle Mode"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Manipulates Geometry, or Objects by Distance at Angle (Direction).
    
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                - Reads pg.select, pg.distance, pg.angle, pg.plane & pg.flip_angle scene variables to:
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- Split Edges                  (SE)
                -- add a New Vertex             (NV)
                -- Duplicate Geometry           (DG)
                -- Extrude Geometry             (EG)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
    
            decimal_places = context.preferences.addons[__package__].preferences.pdt_input_round
    
            if operation == "CU":
                # Cursor
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ci{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "PP":
                # Pivot Point
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"pi{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "MV":
                # Move Entities
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"gi{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "SE":
                # Split Edges
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"si{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "NV":
                # New Vertex
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ni{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "EV":
                # Extrude Vertices
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"vi{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "DG":
                # Duplicate Geometry
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"di{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
            elif operation == "EG":
                # Extrude Geometry
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"ei{str(round(pg.distance, decimal_places))}"
                    f",{str(round(pg.angle, decimal_places))}"
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_DIR}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    
    class PDT_OT_PlacementPer(Operator):
        """Use Percentage Placement."""
    
        bl_idname = "pdt.percent"
        bl_label = "Percentage Mode"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Manipulates Geometry, or Objects by Percentage between 2 points.
    
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                - Reads pg.percent, pg.extend & pg.flip_percent scene variables to:
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- Split Edges                  (SE)
                -- add a New Vertex             (NV)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
    
            decimal_places = context.preferences.addons[__package__].preferences.pdt_input_round
    
    
            if operation == "CU":
                # Cursor
    
                pg.command = f"cp{str(round(pg.percent, decimal_places))}"
    
            elif operation == "PP":
                # Pivot Point
    
                pg.command = f"pp{str(round(pg.percent, decimal_places))}"
    
            elif operation == "MV":
                # Move Entities
    
                pg.command = f"gp{str(round(pg.percent, decimal_places))}"
    
            elif operation == "SE":
                # Split Edges
    
                pg.command = f"sp{str(round(pg.percent, decimal_places))}"
    
            elif operation == "NV":
                # New Vertex
    
                pg.command = f"np{str(round(pg.percent, decimal_places))}"
    
            elif operation == "EV":
                # Extrude Vertices
    
                pg.command = f"vp{str(round(pg.percent, decimal_places))}"
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_PERCENT}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    
    class PDT_OT_PlacementNormal(Operator):
        """Use Normal, or Perpendicular Placement."""
    
        bl_idname = "pdt.normal"
        bl_label = "Normal Mode"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Manipulates Geometry, or Objects by Normal Intersection between 3 points.
    
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                - Reads pg.extend scene variable to:
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- Split Edges                  (SE)
                -- add a New Vertex             (NV)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
            if operation == "CU":
                pg.command = f"cnml"
            elif operation == "PP":
                pg.command = f"pnml"
            elif operation == "MV":
                pg.command = f"gnml"
            elif operation == "EV":
                pg.command = f"vnml"
            elif operation == "SE":
                pg.command = f"snml"
            elif operation == "NV":
                pg.command = f"nnml"
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
                self.report({"ERROR"}, error_message)
    
    class PDT_OT_PlacementCen(Operator):
        """Use Placement at Arc Centre."""
    
        bl_idname = "pdt.centre"
        bl_label = "Centre Mode"
    
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
    
            """Manipulates Geometry, or Objects to an Arc Centre defined by 3 points on an Imaginary Arc.
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- add a New vertex             (NV)
    
                Invalid Options result in self.report Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
            if operation == "CU":
                pg.command = f"ccen"
            elif operation == "PP":
                pg.command = f"pcen"
            elif operation == "MV":
                pg.command = f"gcen"
            elif operation == "EV":
                pg.command = f"vcen"
            elif operation == "NV":
                pg.command = f"ncen"
            else:
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    class PDT_OT_PlacementInt(Operator):
        """Use Intersection, or Convergence Placement."""
    
        bl_idname = "pdt.intersect"
        bl_label = "Intersect Mode"
    
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
    
            """Manipulates Geometry, or Objects by Convergance Intersection between 4 points, or 2 Edges.
    
            Note:
                - Reads pg.operation from Operation Mode Selector as 'operation'
                - Reads pg.plane scene variable and operates in Working Plane to:
                -- set position of CUrsor       (CU)
                -- set position of Pivot Point  (PP)
                -- MoVe geometry/objects        (MV)
                -- Extrude Vertices             (EV)
                -- add a New vertex             (NV)
    
                Invalid Options result in "self.report" Error.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            operation = pg.operation
            if operation == "CU":
                pg.command = f"cint"
            elif operation == "PP":
                pg.command = f"pint"
            elif operation == "MV":
                pg.command = f"gint"
            elif operation == "EV":
                pg.command = f"vint"
            elif operation == "NV":
                pg.command = f"nint"
            else:
    
                error_message = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_INTERSECT}"
                self.report({"ERROR"}, error_message)
    
            return {"FINISHED"}
    
    
    
    class PDT_OT_JoinVerts(Operator):
        """Join 2 Free Vertices into an Edge."""
    
        bl_idname = "pdt.join"
        bl_label = "Join 2 Vertices"
        bl_options = {"REGISTER", "UNDO"}
    
        @classmethod
        def poll(cls, context):
            ob = context.object
            if ob is None:
                return False
            return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
    
        def execute(self, context):
            """Joins 2 Free Vertices that do not form part of a Face.
    
    
            Note:
                Joins two vertices that do not form part of a single face
                It is designed to close open Edge Loops, where a face is not required
                or to join two disconnected Edges.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            pg.command = f"j2v"
            return {"FINISHED"}
    
    
    
    class PDT_OT_Fillet(Operator):
        """Fillet Edges by Vertex, Set Use Verts to False for Extruded Structure."""
    
        bl_idname = "pdt.fillet"
        bl_label = "Fillet"
        bl_options = {"REGISTER", "UNDO"}
    
        @classmethod
        def poll(cls, context):
            ob = context.object
            if ob is None:
                return False
            return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
    
        def execute(self, context):
            """Create Fillets by Vertex or by Geometry.
    
    
            Note:
                Fillets connected edges, or connected faces
    
                - pg.fillet_radius  ; Radius of fillet
                - pg.fillet_segments  ; Number of segments
                - pg.fillet_profile  ; Profile, values 0 to 1
                - pg.fillet_vertices_only ; Vertices (True), or Face/Edges
                - pg.fillet_intersect ; Intersect dges first (True), or not
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
    
            decimal_places = context.preferences.addons[__package__].preferences.pdt_input_round
    
            if pg.fillet_intersect:
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"fi{str(round(pg.fillet_radius, decimal_places))}"
                    f",{str(round(pg.fillet_segments, decimal_places))}"
                    f",{str(round(pg.fillet_profile, decimal_places))}"
    
            elif pg.fillet_vertices_only:
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"fv{str(round(pg.fillet_radius, decimal_places))}"
                    f",{str(round(pg.fillet_segments, decimal_places))}"
                    f",{str(round(pg.fillet_profile, decimal_places))}"
    
    Alan Odom's avatar
    Alan Odom committed
                pg.command = (
    
                    f"fe{str(round(pg.fillet_radius, decimal_places))}"
                    f",{str(round(pg.fillet_segments, decimal_places))}"
                    f",{str(round(pg.fillet_profile, decimal_places))}"
    
            return {"FINISHED"}
    
    
    
    class PDT_OT_Angle2(Operator):
        """Measure Distance and Angle in Working Plane, Also sets Deltas."""
    
        bl_idname = "pdt.angle2"
        bl_label = "Measure 2D"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Measures Angle and Offsets between 2 Points in View Plane.
    
    
            Note:
                Uses 2 Selected Vertices to set pg.angle and pg.distance scene variables
                also sets delta offset from these 2 points using standard Numpy Routines
                Works in Edit and Oject Modes.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            pg.command = f"ad2"
    
            return {"FINISHED"}
    
    
    class PDT_OT_Angle3(Operator):
        """Measure Distance and Angle in 3D Space."""
    
        bl_idname = "pdt.angle3"
        bl_label = "Measure 3D"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Measures Angle and Offsets between 3 Points in World Space, Also sets Deltas.
    
    
            Note:
                Uses 3 Selected Vertices to set pg.angle and pg.distance scene variables
                also sets delta offset from these 3 points using standard Numpy Routines
                Works in Edit and Oject Modes.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
            pg = context.scene.pdt_pg
    
            pg.command = f"ad3"
    
            return {"FINISHED"}
    
    
    class PDT_OT_Origin(Operator):
        """Move Object Origin to Cursor Location."""
    
        bl_idname = "pdt.origin"
        bl_label = "Move Origin"
        bl_options = {"REGISTER", "UNDO"}
    
        def execute(self, context):
            """Sets Object Origin in Edit Mode to Cursor Location.
    
    
            Note:
                Keeps geometry static in World Space whilst moving Object Origin
                Requires cursor location
                Works in Edit and Object Modes.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            pg.command = f"otc"
    
            return {"FINISHED"}
    
    
    class PDT_OT_Taper(Operator):
        """Taper Vertices at Angle in Chosen Axis Mode."""
    
        bl_idname = "pdt.taper"
        bl_label = "Taper"
        bl_options = {"REGISTER", "UNDO"}
    
        @classmethod
        def poll(cls, context):
            ob = context.object
            if ob is None:
                return False
            return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
    
        def execute(self, context):
            """Taper Geometry along World Axes.
    
    
            Note:
                Similar to Blender Shear command except that it shears by angle rather than displacement.
                Rotates about World Axes and displaces along World Axes, angle must not exceed +-80 degrees.
                Rotation axis is centred on Active Vertex.
                Works only in Edit mode.
    
    
            Args:
                context: Blender bpy.context instance.
    
            Note:
                Uses pg.taper & pg.angle scene variables
    
            Returns:
                Status Set.
            """
    
    
            pg = context.scene.pdt_pg
            pg.command = f"tap"
    
            return {"FINISHED"}