PDT: Refactor per Pylint suggestions + readability

- Remove unused imports
- Add comments where appropriate
- Improve readability of variable names
- Re-implement a couple of functions using dictionaries instead of if-statements
- Results of Pylint & Black operations, plus some fixes to code.
This commit is contained in:
Alan Odom 2020-01-29 17:48:38 +00:00 committed by Rune Morling
parent 7805692b57
commit 877308f917
14 changed files with 808 additions and 718 deletions

View File

@ -21,11 +21,9 @@
# Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
# -----------------------------------------------------------------------
#
import bpy
import bmesh
import math
from math import sqrt, tan, pi
import numpy as np
from math import sqrt, tan, pi
from mathutils import Vector
from mathutils.geometry import intersect_point_line
from .pdt_functions import (
@ -45,7 +43,7 @@ from .pdt_functions import (
from . import pdt_exception
PDT_SelectionError = pdt_exception.SelectionError
PDT_InvalidVector = pdt_exception.InvalidVector
PDT_ObjectMode = pdt_exception.ObjectMode
PDT_ObjectModeError = pdt_exception.ObjectModeError
PDT_InfRadius = pdt_exception.InfRadius
PDT_NoObjectError = pdt_exception.NoObjectError
PDT_IntersectionError = pdt_exception.IntersectionError
@ -101,10 +99,13 @@ def vector_build(context, pg, obj, operation, values, num_values):
flip_a = pg.flip_angle
flip_p = pg.flip_percent
# Cartesian 3D coordinates
if num_values == 3 and len(values) == 3:
output_vector = Vector((float(values[0]), float(values[1]), float(values[2])))
# Polar 2D coordinates
elif num_values == 2 and len(values) == 2:
output_vector = dis_ang(values, flip_a, plane, scene)
# Percentage of imaginary line between two 3D coordinates
elif num_values == 1 and len(values) == 1:
output_vector = get_percent(obj, flip_p, float(values[0]), operation, scene)
else:
@ -115,7 +116,7 @@ def vector_build(context, pg, obj, operation, values, num_values):
else:
pg.error = PDT_ERR_BAD1VALS
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise pdt_InvalidVector
raise PDT_InvalidVector
return output_vector
@ -149,7 +150,7 @@ def placement_normal(context, operation):
if obj is None:
pg.error = PDT_ERR_NO_ACT_OBJ
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
raise PDT_ObjectModeError
obj_loc = obj.matrix_world.decompose()[0]
bm = bmesh.from_edit_mesh(obj.data)
if len(bm.select_history) == 3:
@ -224,10 +225,9 @@ def placement_normal(context, operation):
else:
pg.error = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_NOR}"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
def placement_centre(context, operation):
def placement_arc_centre(context, operation):
"""Manipulates Geometry, or Objects to an Arc Centre defined by 3 points on an Imaginary Arc.
-- set position of CUrsor (CU)
@ -256,7 +256,7 @@ def placement_centre(context, operation):
if obj is None:
pg.error = PDT_ERR_NO_ACT_OBJ
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
raise PDT_ObjectModeError
obj = context.view_layer.objects.active
obj_loc = obj.matrix_world.decompose()[0]
bm = bmesh.from_edit_mesh(obj.data)
@ -333,7 +333,6 @@ def placement_centre(context, operation):
else:
pg.error = f"{operation} {PDT_ERR_NON_VALID} {PDT_LAB_ARCCENTRE}"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
def placement_intersect(context, operation):
@ -556,7 +555,7 @@ def join_two_vertices(context):
else:
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
raise PDT_ObjectModeError
def set_angle_distance_two(context):
@ -631,15 +630,12 @@ def set_angle_distance_two(context):
if plane == "LO":
pg.distance = round(sqrt(
(vector_a.x - vector_b.x) ** 2 +
(vector_a.y - vector_b.y) ** 2), val_round
)
(vector_a.y - vector_b.y) ** 2), val_round)
else:
pg.distance = round(sqrt(
(vector_a[a1] - vector_b[a1]) ** 2 +
(vector_a[a2] - vector_b[a2]) ** 2), val_round
)
pg.cartesian_coords = Vector(([round(i, val_round) for i in (vector_b - vector_a)]))
return
(vector_a[a2] - vector_b[a2]) ** 2), val_round)
pg.cartesian_coords = Vector(([round(i, val_round) for i in vector_b - vector_a]))
def set_angle_distance_three(context):
@ -672,7 +668,7 @@ def set_angle_distance_three(context):
if vector_a is None:
pg.error = PDT_ERR_VERT_MODE
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise pdt_InvalidVector
raise PDT_InvalidVector
else:
pg.error = f"{PDT_ERR_SEL_3_VERTIO} {len(bm.select_history)})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -708,8 +704,7 @@ def set_angle_distance_three(context):
else:
pg.angle = round(ang, val_round)
pg.distance = round((vector_a - vector_b).length, val_round)
pg.cartesian_coords = Vector(([round(i, val_round) for i in (vector_b - vector_a)]))
return
pg.cartesian_coords = Vector(([round(i, val_round) for i in vector_b - vector_a]))
def origin_to_cursor(context):
@ -750,8 +745,7 @@ def origin_to_cursor(context):
else:
pg.error = f"{PDT_ERR_EDOB_MODE} {obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
return
raise PDT_ObjectModeError
def taper(context):
@ -809,7 +803,7 @@ def taper(context):
v.co[a2] = v.co[a2] - (dis_v * tan(ang_v * pi / 180))
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
else:
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectModeError

View File

@ -21,7 +21,7 @@
# Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
# -----------------------------------------------------------------------
#
# Exception Routines
# Exceptions are used in the absence of nullable types in python
class SelectionError(Exception):
@ -36,7 +36,7 @@ class CommandFailure(Exception):
pass
class ObjectMode(Exception):
class ObjectModeError(Exception):
pass
@ -66,3 +66,6 @@ class VerticesConnected(Exception):
class InvalidAngle(Exception):
pass
class ShaderError(Exception):
pass

View File

@ -107,7 +107,7 @@ from .pdt_msg_strings import (
PDT_DES_ROTMOVAX,
PDT_DES_TRIM,
PDT_DES_VALIDLET,
PDT_DES_WORPLANE
PDT_DES_WORPLANE,
)
from .pdt_command import command_run
from .pdt_functions import scale_set
@ -176,7 +176,9 @@ def enumlist_collections(self, context):
if len(pg.collection_search_string) == 0:
object_names = [ob for ob in data_from.collections]
else:
object_names = [ob for ob in data_from.collections if pg.collection_search_string in ob]
object_names = [
ob for ob in data_from.collections if pg.collection_search_string in ob
]
for object_name in object_names:
_pdt_col_items.append((object_name, object_name, ""))
else:
@ -219,32 +221,21 @@ def enumlist_materials(self, context):
class PDTSceneProperties(PropertyGroup):
"""Contains all PDT related properties."""
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
)
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)
cartesian_coords : FloatVectorProperty(
name="Coords",
default=(0.0, 0.0, 0.0),
subtype="XYZ",
description=PDT_DES_COORDS
cartesian_coords: FloatVectorProperty(
name="Coords", default=(0.0, 0.0, 0.0), subtype="XYZ", description=PDT_DES_COORDS
)
distance : FloatProperty(
distance: FloatProperty(
name="Distance", default=0.0, precision=5, description=PDT_DES_OFFDIS, unit="LENGTH"
)
angle : FloatProperty(
angle: FloatProperty(
name="Angle", min=-180, max=180, default=0.0, precision=5, description=PDT_DES_OFFANG
)
percent : FloatProperty(
name="Percent", default=0.0, precision=5, description=PDT_DES_OFFPER
)
plane : EnumProperty(
percent: FloatProperty(name="Percent", default=0.0, precision=5, description=PDT_DES_OFFPER)
plane: EnumProperty(
items=(
("XZ", "Front(X-Z)", "Use X-Z Plane"),
("XY", "Top(X-Y)", "Use X-Y Plane"),
@ -255,7 +246,7 @@ class PDTSceneProperties(PropertyGroup):
default="XZ",
description=PDT_DES_WORPLANE,
)
select : EnumProperty(
select: EnumProperty(
items=(
("REL", "Current Pos.", "Move Relative to Current Position"),
(
@ -268,13 +259,17 @@ class PDTSceneProperties(PropertyGroup):
default="SEL",
description=PDT_DES_MOVESEL,
)
operation : EnumProperty(
operation: EnumProperty(
items=(
("CU", "Move Cursor", "This function will Move the Cursor"),
("PP", "Move Pivot Point", "This function will Move the Pivot Point"),
("MV", "Move Entities", "This function will Move selected Vertices or Objects"),
("NV", "Add New Vertex", "This function will Add a New Vertex"),
("EV", "Extrude Vertex/Vertices", "This function will Extrude Vertex/Vertices Only in EDIT Mode"),
(
"EV",
"Extrude Vertex/Vertices",
"This function will Extrude Vertex/Vertices Only in EDIT Mode",
),
("SE", "Split Edges", "This function will Split Edges Only in EDIT Mode"),
(
"DG",
@ -291,7 +286,7 @@ class PDTSceneProperties(PropertyGroup):
default="CU",
description=PDT_DES_OPMODE,
)
taper : EnumProperty(
taper: EnumProperty(
items=(
("RX-MY", "RotX-MovY", "Rotate X - Move Y"),
("RX-MZ", "RotX-MovZ", "Rotate X - Move Z"),
@ -305,27 +300,19 @@ class PDTSceneProperties(PropertyGroup):
description=PDT_DES_ROTMOVAX,
)
flip_angle : BoolProperty(
name="Flip Angle", default=False, description=PDT_DES_FLIPANG
)
flip_percent : BoolProperty(
name="Flip %", default=False, description=PDT_DES_FLIPPER
)
flip_angle: BoolProperty(name="Flip Angle", default=False, description=PDT_DES_FLIPANG)
flip_percent: BoolProperty(name="Flip %", default=False, description=PDT_DES_FLIPPER)
extend : BoolProperty(
name="Trim/Extend All", default=False, description=PDT_DES_TRIM
)
extend: BoolProperty(name="Trim/Extend All", default=False, description=PDT_DES_TRIM)
lib_objects : EnumProperty(
items=enumlist_objects, name="Objects", description=PDT_DES_LIBOBS
)
lib_collections : EnumProperty(
lib_objects: EnumProperty(items=enumlist_objects, name="Objects", description=PDT_DES_LIBOBS)
lib_collections: EnumProperty(
items=enumlist_collections, name="Collections", description=PDT_DES_LIBCOLS
)
lib_materials : EnumProperty(
lib_materials: EnumProperty(
items=enumlist_materials, name="Materials", description=PDT_DES_LIBMATS
)
lib_mode : EnumProperty(
lib_mode: EnumProperty(
items=(
("OBJECTS", "Objects", "Use Objects"),
("COLLECTIONS", "Collections", "Use Collections"),
@ -336,14 +323,11 @@ class PDTSceneProperties(PropertyGroup):
description=PDT_DES_LIBMODE,
)
rotation_coords : FloatVectorProperty(
name="Rotation",
default=(0.0, 0.0, 0.0),
subtype="XYZ",
description="Rotation Coordinates"
rotation_coords: FloatVectorProperty(
name="Rotation", default=(0.0, 0.0, 0.0), subtype="XYZ", description="Rotation Coordinates"
)
object_order : EnumProperty(
object_order: EnumProperty(
items=(
("1,2,3,4", "1,2,3,4", "Objects 1 & 2 are First Line"),
("1,3,2,4", "1,3,2,4", "Objects 1 & 3 are First Line"),
@ -353,105 +337,86 @@ class PDTSceneProperties(PropertyGroup):
default="1,2,3,4",
description=PDT_DES_OBORDER,
)
vrotangle : FloatProperty(name="View Rotate Angle", default=10, max=180, min=-180)
command : StringProperty(
name="Command",
default="CA0,0,0",
update=command_run,
description=PDT_DES_VALIDLET,
vrotangle: FloatProperty(name="View Rotate Angle", default=10, max=180, min=-180)
command: StringProperty(
name="Command", default="CA0,0,0", update=command_run, description=PDT_DES_VALIDLET,
)
maths_output : FloatProperty(
name="Maths output",
default=0,
description=PDT_DES_OUTPUT,
maths_output: FloatProperty(
name="Maths output", default=0, description=PDT_DES_OUTPUT,
)
error : StringProperty(name="Error", default="")
error: StringProperty(name="Error", default="")
# Was pivot* -- is now pivot_*
pivot_loc : FloatVectorProperty(
name="Pivot Location",
default=(0.0, 0.0, 0.0),
subtype="XYZ",
description=PDT_DES_PPLOC,
pivot_loc: FloatVectorProperty(
name="Pivot Location", default=(0.0, 0.0, 0.0), subtype="XYZ", description=PDT_DES_PPLOC,
)
pivot_scale : FloatVectorProperty(
pivot_scale: FloatVectorProperty(
name="Pivot Scale", default=(1.0, 1.0, 1.0), subtype="XYZ", description=PDT_DES_PPSCALEFAC
)
pivot_size : FloatProperty(
pivot_size: FloatProperty(
name="Pivot Factor", min=0.4, max=10, default=2, precision=1, description=PDT_DES_PPSIZE
)
pivot_width : IntProperty(
name="Width", min=1, max=5, default=2, description=PDT_DES_PPWIDTH
)
pivot_width: IntProperty(name="Width", min=1, max=5, default=2, description=PDT_DES_PPWIDTH)
# FIXME: might as well become pivot_angle
pivot_ang : FloatProperty(name="Pivot Angle", min=-180, max=180, default=0.0)
pivot_ang: FloatProperty(name="Pivot Angle", min=-180, max=180, default=0.0)
# FIXME: pivot_dist for consistency?
pivot_dis : FloatProperty(name="Pivot Dist",
default=0.0,
min = 0,
update=scale_set,
description=PDT_DES_PIVOTDIS,
pivot_dis: FloatProperty(
name="Pivot Dist", default=0.0, min=0, update=scale_set, description=PDT_DES_PIVOTDIS,
)
pivot_alpha : FloatProperty(
name="Alpha",
min=0.2,
max=1,
default=0.6,
precision=1,
description=PDT_DES_PPTRANS,
pivot_alpha: FloatProperty(
name="Alpha", min=0.2, max=1, default=0.6, precision=1, description=PDT_DES_PPTRANS,
)
pivot_show : BoolProperty()
pivot_show: BoolProperty()
# Was filletrad
fillet_radius : FloatProperty(
fillet_radius: FloatProperty(
name="Fillet Radius", min=0.0, default=1.0, description=PDT_DES_FILLETRAD
)
# Was filletnum
fillet_segments : IntProperty(
fillet_segments: IntProperty(
name="Fillet Segments", min=1, default=4, description=PDT_DES_FILLETSEG
)
# Was filletpro
fillet_profile : FloatProperty(
fillet_profile: FloatProperty(
name="Fillet Profile", min=0.0, max=1.0, default=0.5, description=PDT_DES_FILLETPROF
)
# Was filletbool
fillet_vertices_only : BoolProperty(
name="Fillet Vertices Only",
default=True,
description=PDT_DES_FILLETVERTS,
fillet_vertices_only: BoolProperty(
name="Fillet Vertices Only", default=True, description=PDT_DES_FILLETVERTS,
)
fillet_intersect : BoolProperty(
name="Intersect",
default=False,
description=PDT_DES_FILLINT,
fillet_intersect: BoolProperty(
name="Intersect", default=False, description=PDT_DES_FILLINT,
)
class PDTPreferences(AddonPreferences):
# This must match the addon name, use '__package__' when defining this in a submodule of a python package.
# 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'
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)"
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',
pdt_ui_width: IntProperty(
name="UI Width Cut-off",
default=350,
description="Cutoff width for shrinking items per line in menus"
description="Cutoff width for shrinking items per line in menus",
)
pdt_input_round : IntProperty(
name='Input Rounding',
default=5,
description='Rounding Factor for Inputs'
pdt_input_round: IntProperty(
name="Input Rounding", default=5, description="Rounding Factor for Inputs"
)
def draw(self, context):
@ -510,12 +475,12 @@ classes = (
pdt_pivot_point.PDT_OT_PivotWrite,
pdt_pivot_point.PDT_OT_PivotRead,
pdt_view.PDT_OT_ViewRot,
pdt_view.PDT_OT_vRotL,
pdt_view.PDT_OT_vRotR,
pdt_view.PDT_OT_vRotU,
pdt_view.PDT_OT_vRotD,
pdt_view.PDT_OT_vRoll,
pdt_view.PDT_OT_viso,
pdt_view.PDT_OT_ViewRotL,
pdt_view.PDT_OT_ViewRotR,
pdt_view.PDT_OT_ViewRotU,
pdt_view.PDT_OT_ViewRotD,
pdt_view.PDT_OT_ViewRoll,
pdt_view.PDT_OT_ViewIso,
pdt_view.PDT_OT_Reset3DView,
pdt_xall.PDT_OT_IntersectAllEdges,
)
@ -534,10 +499,10 @@ def register():
# OpenGL flag
#
wm = WindowManager
window_manager = WindowManager
# Register Internal OpenGL Property
#
wm.pdt_run_opengl = BoolProperty(default=False)
window_manager.pdt_run_opengl = BoolProperty(default=False)
Scene.pdt_pg = PointerProperty(type=PDTSceneProperties)
@ -554,10 +519,10 @@ def unregister():
pdt_pivot_point.PDT_OT_ModalDrawOperator.handle_remove(
pdt_pivot_point.PDT_OT_ModalDrawOperator, bpy.context
)
wm = bpy.context.window_manager
p = "pdt_run_opengl"
if p in wm:
del wm[p]
window_manager = bpy.context.window_manager
pdt_wm = "pdt_run_opengl"
if pdt_wm in window_manager:
del window_manager[pdt_wm]
for cls in reversed(classes):
unregister_class(cls)

View File

@ -34,6 +34,7 @@ from .pdt_msg_strings import (
)
from .pdt_functions import debug, oops
def add_line_to_bisection(context):
"""Computes Bisector of 2 Co-Planar Edges.
@ -47,8 +48,8 @@ def add_line_to_bisection(context):
obj = context.object
if all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"]):
pg = context.scene.pdt_pg
me = obj.data
bm = bmesh.from_edit_mesh(me)
obj_data = obj.data
bm = bmesh.from_edit_mesh(obj_data)
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
@ -60,39 +61,47 @@ def add_line_to_bisection(context):
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
[[v1, v2], [v3, v4]] = [[v.co for v in e.verts] for e in edges]
debug(f"vectors found:\n {v1}\n {v2}\n {v3}\n {v4}")
[[vector_a, vector_b], [vector_c, vector_d]] = [[v.co for v in e.verts] for e in edges]
debug(f"vectors found:\n {vector_a}\n {vector_b}\n {vector_c}\n {vector_d}")
dist1 = (v1 - v2).length
dist2 = (v3 - v4).length
dist1 = (vector_a - vector_b).length
dist2 = (vector_c - vector_d).length
bdist = min([dist1, dist2])
edge1 = (v1, v2)
edge2 = (v3, v4)
edge1 = (vector_a, vector_b)
edge2 = (vector_c, vector_d)
if not cm.test_coplanar(edge1, edge2):
pg.error = PDT_ERR_NCEDGES
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
# get pt and pick farthest vertex from (projected) intersections
pt = cm.get_intersection(edge1, edge2)
far1 = v2 if (v1 - pt).length < (v2 - pt).length else v1
far2 = v4 if (v3 - pt).length < (v4 - pt).length else v3
# get intersect_point and pick farthest vertex from (projected) intersections
intersect_point = cm.get_intersection(edge1, edge2)
far1 = (
vector_b
if (vector_a - intersect_point).length < (vector_b - intersect_point).length
else vector_a
)
far2 = (
vector_d
if (vector_c - intersect_point).length < (vector_d - intersect_point).length
else vector_c
)
dex1 = far1 - pt
dex2 = far2 - pt
dex1 = far1 - intersect_point
dex2 = far2 - intersect_point
dex1 = dex1 * (bdist / dex1.length)
dex2 = dex2 * (bdist / dex2.length)
pt2 = pt + (dex1).lerp(dex2, 0.5)
pt3 = pt2.lerp(pt, 2.0)
intersect_point2 = intersect_point + (dex1).lerp(dex2, 0.5)
intersect_point3 = intersect_point2.lerp(intersect_point, 2.0)
vec1 = bm.verts.new(pt2)
vec2 = bm.verts.new(pt)
vec3 = bm.verts.new(pt3)
vec1 = bm.verts.new(intersect_point2)
vec2 = bm.verts.new(intersect_point)
vec3 = bm.verts.new(intersect_point3)
bm.edges.new((vec1, vec2))
bm.edges.new((vec2, vec3))
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
bmesh.update_edit_mesh(me)
bmesh.update_edit_mesh(obj_data)
else:
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -109,10 +118,10 @@ class PDT_OT_LineOnBisection(bpy.types.Operator):
@classmethod
def poll(cls, context):
"""Only allow operation on a mesh object in EDIT mode."""
ob = context.active_object
if ob is None:
obj = context.active_object
if obj is None:
return False
return all([ob is not None, ob.type == "MESH", ob.mode == "EDIT"])
return all([obj is not None, obj.type == "MESH", obj.mode == "EDIT"])
def execute(self, context):
"""Computes Bisector of 2 Co-Planar Edges.

View File

@ -3,7 +3,7 @@
# 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.
# of the License, or (at your ointersect_pointion) 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
@ -28,19 +28,20 @@ from mathutils import Vector
from mathutils.geometry import intersect_line_line, intersect_point_line
from .pdt_functions import debug
def point_on_edge(p, edge):
def point_on_edge(point, edge):
"""Find Point on Edge.
Args:
p: vector
point: vector
edge: tuple containing 2 vectors.
Returns:
True if point p happens to lie on the edge, False otherwise.
"""
pt, _percent = intersect_point_line(p, *edge)
on_line = (pt - p).length < 1.0e-5
intersect_point, _percent = intersect_point_line(point, *edge)
on_line = (intersect_point - point).length < 1.0e-5
return on_line and (0.0 <= _percent <= 1.0)
@ -56,8 +57,10 @@ def line_from_edge_intersect(edge1, edge2):
Output of intersect_line_line.
"""
[p1, p2], [p3, p4] = edge1, edge2
return intersect_line_line(p1, p2, p3, p4)
[intersect_point1, intersect_point2], [intersect_point3, intersect_point4] = edge1, edge2
return intersect_line_line(
intersect_point1, intersect_point2, intersect_point3, intersect_point4
)
def get_intersection(edge1, edge2):
@ -73,6 +76,7 @@ def get_intersection(edge1, edge2):
line = line_from_edge_intersect(edge1, edge2)
if line:
return (line[0] + line[1]) / 2
return None
def test_coplanar(edge1, edge2):
@ -92,50 +96,53 @@ def test_coplanar(edge1, edge2):
line = line_from_edge_intersect(edge1, edge2)
if line:
return (line[0] - line[1]).length < 1.0e-5
return None
def closest_idx(pt, e):
def closest_idx(intersect_point, edge):
"""Get Closest Vertex to input point.
If both points in e are equally far from pt, then v1 is returned.
If both points in e are equally far from intersect_point, then v1 is returned.
Args:
pt: vector
e: bmesh edge
intersect_point: vector
edge: bmesh edge
Returns:
Index of vertex closest to pt.
Index of vertex closest to intersect_point.
"""
if isinstance(e, bmesh.types.BMEdge):
ev = e.verts
v1 = ev[0].co
v2 = ev[1].co
distance_test = (v1 - pt).length <= (v2 - pt).length
return ev[0].index if distance_test else ev[1].index
if isinstance(edge, bmesh.types.BMEdge):
edge_verts = edge.verts
vector_a = edge_verts[0].co
vector_b = edge_verts[1].co
distance_test = (vector_a - intersect_point).length <= (vector_b - intersect_point).length
return edge_verts[0].index if distance_test else edge_verts[1].index
debug(f"Received {e}, check expected input in docstring ")
debug(f"Received {edge}, check expected input in docstring ")
return None
def closest_vector(pt, e):
def closest_vector(intersect_point, edge):
"""Return Closest Vector to input Point.
If both points in e are equally far from pt, then v1 is returned.
If both points in e are equally far from intersect_point, then v1 is returned.
Args:
pt: vector
e: tuple containing 2 vectors
intersect_point: vector
edge: tuple containing 2 vectors
Returns:
Vector closest to pt.
Vector closest to intersect_point.
"""
if isinstance(e, tuple) and all([isinstance(co, Vector) for co in e]):
v1, v2 = e
distance_test = (v1 - pt).length <= (v2 - pt).length
return v1 if distance_test else v2
if isinstance(edge, tuple) and all([isinstance(co, Vector) for co in edge]):
vector_a, vector_b = edge
distance_test = (vector_a - intersect_point).length <= (vector_b - intersect_point).length
return vector_a if distance_test else vector_b
debug(f"Received {e}, check expected input in docstring ")
debug(f"Received {edge}, check expected input in docstring ")
return None
def coords_tuple_from_edge_idx(bm, idx):
@ -159,8 +166,8 @@ def vertex_indices_from_edges_tuple(bm, edge_tuple):
The vertex indices of edge_tuple.
"""
def k(v, w):
return bm.edges[edge_tuple[v]].verts[w].index
def k(ind_v, ind_w):
return bm.edges[edge_tuple[ind_v]].verts[ind_w].index
return [k(i >> 1, i % 2) for i in range(4)]
@ -182,29 +189,38 @@ def get_vert_indices_from_bmedges(edges):
return temp_edges
def num_edges_point_lies_on(pt, edges):
def num_edges_point_lies_on(intersect_point, edges):
"""Returns the number of edges that a point lies on."""
res = [point_on_edge(pt, edge) for edge in [edges[:2], edges[2:]]]
res = [point_on_edge(intersect_point, edge) for edge in [edges[:2], edges[2:]]]
return len([i for i in res if i])
def find_intersecting_edges(bm, pt, idx1, idx2):
def find_intersecting_edges(bm, intersect_point, idx1, idx2):
"""Find Intercecting Edges.
Args:
pt: Vector
intersect_point: Vector
idx1, ix2: edge indices
Returns:
The list of edge indices where pt is on those edges.
The list of edge indices where intersect_point is on those edges.
"""
if not pt:
if not intersect_point:
return []
idxs = [idx1, idx2]
edges = [coords_tuple_from_edge_idx(bm, idx) for idx in idxs]
return [idx for edge, idx in zip(edges, idxs) if point_on_edge(pt, edge)]
return [idx for edge, idx in zip(edges, idxs) if point_on_edge(intersect_point, edge)]
def vert_idxs_from_edge_idx(bm, idx):
"""Find Vertex Indices form Edge Indices.
Args:
Object Bmesh as bm
Selection Index as idx
Returns:
Vertex Indices of Edge.
"""
edge = bm.edges[idx]
return edge.verts[0].index, edge.verts[1].index

View File

@ -40,7 +40,7 @@ from .pdt_command_functions import (
origin_to_cursor,
taper,
placement_normal,
placement_centre,
placement_arc_centre,
placement_intersect,
)
from .pdt_msg_strings import (
@ -59,6 +59,8 @@ from .pdt_msg_strings import (
PDT_ERR_BADMATHS,
PDT_OBJ_MODE_ERROR,
PDT_ERR_SEL_4_VERTS,
PDT_ERR_INT_LINES,
PDT_LAB_PLANE,
)
from .pdt_bix import add_line_to_bisection
from .pdt_etof import extend_vertex
@ -68,8 +70,9 @@ from . import pdt_exception
PDT_SelectionError = pdt_exception.SelectionError
PDT_InvalidVector = pdt_exception.InvalidVector
PDT_CommandFailure = pdt_exception.CommandFailure
PDT_ObjectMode = pdt_exception.ObjectMode
PDT_MathError = pdt_exception.MathsError
PDT_ObjectModeError = pdt_exception.ObjectModeError
PDT_MathsError = pdt_exception.MathsError
PDT_IntersectionError = pdt_exception.IntersectionError
class PDT_OT_CommandReRun(Operator):
@ -149,7 +152,7 @@ def command_run(self, context):
if obj.mode not in {"OBJECT", "EDIT"} or obj.type != "MESH":
pg.error = PDT_OBJ_MODE_ERROR
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_ObjectMode
raise PDT_ObjectModeError
# Special Cases of Command.
if command == "?" or command.lower() == "help":
@ -157,52 +160,47 @@ def command_run(self, context):
context.window_manager.popup_menu(pdt_help, title="PDT Command Line Help", icon="INFO")
# fmt: on
return
elif command == "":
if command == "":
return
elif command.upper() == "J2V":
if command.upper() == "J2V":
join_two_vertices(context)
return
elif command.upper() == "AD2":
if command.upper() == "AD2":
set_angle_distance_two(context)
return
elif command.upper() == "AD3":
if command.upper() == "AD3":
set_angle_distance_three(context)
return
elif command.upper() == "OTC":
if command.upper() == "OTC":
origin_to_cursor(context)
return
elif command.upper() == "TAP":
if command.upper() == "TAP":
taper(context)
return
elif command.upper() == "BIS":
if command.upper() == "BIS":
add_line_to_bisection(context)
return
elif command.upper() == "ETF":
if command.upper() == "ETF":
extend_vertex(context)
return
elif command.upper() == "INTALL":
if command.upper() == "INTALL":
intersect_all(context)
return
elif command.upper()[1:] == "NML":
if command.upper()[1:] == "NML":
placement_normal(context, command.upper()[0])
return
elif command.upper()[1:] == "CEN":
placement_centre(context, command.upper()[0])
if command.upper()[1:] == "CEN":
placement_arc_centre(context, command.upper()[0])
return
elif command.upper()[1:] == "INT":
if command.upper()[1:] == "INT":
placement_intersect(context, command.upper()[0])
return
# Check First Letter
# Check Command Length
if len(command) < 3:
pg.error = PDT_ERR_CHARS_NUM
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
operation = command[0].upper()
if operation not in {"C", "D", "E", "F", "G", "N", "M", "P", "V", "S"}:
pg.error = PDT_ERR_BADFLETTER
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
# Check First Letter
operation = command[0].upper()
@ -214,11 +212,11 @@ def command_run(self, context):
# Check Second Letter.
mode = command[1].lower()
if (
(operation == "F" and mode not in {"v", "e", "i"})
or (operation in {"D", "E"} and mode not in {"d", "i"})
or (operation == "M" and mode not in {"a", "d", "i", "p", "o", "x", "y", "z"})
or (operation not in {"D", "E", "F", "M"} and mode not in {"a", "d", "i", "p"})
):
(operation == "F" and mode not in {"v", "e", "i"})
or (operation in {"D", "E"} and mode not in {"d", "i"})
or (operation == "M" and mode not in {"a", "d", "i", "p", "o", "x", "y", "z"})
or (operation not in {"D", "E", "F", "M"} and mode not in {"a", "d", "i", "p"})
):
pg.error = f"'{mode}' {PDT_ERR_NON_VALID} '{operation}'"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
@ -249,7 +247,7 @@ def command_run(self, context):
# ------------------------
# Move Vertices or Objects
elif operation == "G":
if operation == "G":
try:
move_entities(context, pg, operation, mode, obj, bm, verts, values)
except PDT_CommandFailure:
@ -257,7 +255,7 @@ def command_run(self, context):
# --------------
# Add New Vertex
elif operation == "N":
if operation == "N":
try:
add_new_vertex(context, pg, operation, mode, obj, bm, verts, values)
except PDT_CommandFailure:
@ -265,7 +263,7 @@ def command_run(self, context):
# -----------
# Split Edges
elif operation == "S":
if operation == "S":
try:
split_edges(context, pg, operation, mode, obj, obj_loc, bm, values)
except PDT_CommandFailure:
@ -274,7 +272,7 @@ def command_run(self, context):
# ----------------
# Extrude Vertices
elif operation == "V":
if operation == "V":
try:
extrude_vertices(context, pg, operation, mode, obj, obj_loc, bm, verts, values)
except PDT_CommandFailure:
@ -282,7 +280,7 @@ def command_run(self, context):
# ----------------
# Extrude Geometry
elif operation == "E":
if operation == "E":
try:
extrude_geometry(context, pg, operation, mode, obj, bm, values)
except PDT_CommandFailure:
@ -290,7 +288,7 @@ def command_run(self, context):
# ------------------
# Duplicate Geometry
elif operation == "D":
if operation == "D":
try:
duplicate_geometry(context, pg, operation, mode, obj, bm, values)
except PDT_CommandFailure:
@ -298,18 +296,12 @@ def command_run(self, context):
# ---------------
# Fillet Geometry
elif operation == "F":
if operation == "F":
try:
fillet_geometry(context, pg, mode, obj, bm, verts, values)
except PDT_CommandFailure:
return
# -------------
# Anything else
else:
# Trap all other value and allow for more options
return
def pdt_help(self, context):
"""Display PDT Command Line help in a pop-up."""
@ -392,12 +384,19 @@ def command_maths(context, mode, pg, expression, output_target):
elif output_target == "p":
pg.percent = round(maths_result, val_round)
else:
# Mst be "o"
# Must be "o"
pg.maths_output = round(maths_result, val_round)
return
def command_parse(context):
"""Parse Command Input.
Args:
context: Blender bpy.context instance.
Returns:
pg, values_out, obj, obj_loc, bm, verts.
"""
scene = context.scene
pg = scene.pdt_pg
command = pg.command.strip()
@ -418,7 +417,7 @@ def command_parse(context):
val_round = context.preferences.addons[__package__].preferences.pdt_input_round
values_out = [str(round(float(v), val_round)) for v in values]
bm, good = obj_check(context, obj, scene, operation)
bm, good = obj_check(obj, scene, operation)
if good:
obj_loc = obj.matrix_world.decompose()[0]
else:
@ -426,12 +425,11 @@ def command_parse(context):
if mode_s == 'SEL' and bm is not None and mode not in {"a"}:
if len(bm.select_history) == 0:
if len([v for v in bm.verts if v.select]) == 0:
verts = [v for v in bm.verts if v.select]
if len(verts) == 0:
pg.error = PDT_ERR_NO_SEL_GEOM
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_SelectionError
else:
verts = [v for v in bm.verts if v.select]
else:
verts = bm.select_history
elif operation == "G" and mode == "a":
@ -446,6 +444,16 @@ def command_parse(context):
def move_cursor_pivot(context, pg, operation, mode, obj, verts, values):
"""Moves Cursor & Pivot Point.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, verts, values
Returns:
Nothing.
"""
# Absolute/Global Coordinates, or Delta/Relative Coordinates
if mode in {"a", "d"}:
try:
@ -466,7 +474,7 @@ def move_cursor_pivot(context, pg, operation, mode, obj, verts, values):
except:
raise PDT_InvalidVector
if vector_delta == None:
if vector_delta is None:
raise PDT_InvalidVector
scene = context.scene
@ -507,10 +515,19 @@ def move_cursor_pivot(context, pg, operation, mode, obj, verts, values):
scene.cursor.location = vector_delta
else:
pg.pivot_loc = vector_delta
return
def move_entities(context, pg, operation, mode, obj, bm, verts, values):
"""Moves Entities.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, bm, verts, values
Returns:
Nothing.
"""
obj_loc = obj.matrix_world.decompose()[0]
# Absolute/Global Coordinates
@ -562,10 +579,19 @@ def move_entities(context, pg, operation, mode, obj, bm, verts, values):
if obj.mode == 'EDIT':
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def add_new_vertex(context, pg, operation, mode, obj, bm, verts, values):
"""Add New Vertex.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, bm, verts, values
Returns:
Nothing.
"""
obj_loc = obj.matrix_world.decompose()[0]
if not obj.mode == "EDIT":
@ -606,10 +632,19 @@ def add_new_vertex(context, pg, operation, mode, obj, bm, verts, values):
new_vertex.select_set(True)
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def split_edges(context, pg, operation, mode, obj, obj_loc, bm, values):
"""Split Edges.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, obj_loc, bm, verts, values
Returns:
Nothing.
"""
if not obj.mode == "EDIT":
pg.error = PDT_ERR_SPLITEDIT
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -694,10 +729,19 @@ def split_edges(context, pg, operation, mode, obj, obj_loc, bm, values):
v.select_set(False)
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def extrude_vertices(context, pg, operation, mode, obj, obj_loc, bm, verts, values):
"""Extrude Vertices.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, onj_loc, bm, verts, values
Returns:
Nothing.
"""
if not obj.mode == "EDIT":
pg.error = PDT_ERR_EXTEDIT
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -760,10 +804,19 @@ def extrude_vertices(context, pg, operation, mode, obj, obj_loc, bm, verts, valu
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def extrude_geometry(context, pg, operation, mode, obj, bm, values):
"""Extrude Geometry.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, bm, verts, values
Returns:
Nothing.
"""
if not obj.mode == "EDIT":
pg.error = PDT_ERR_EXTEDIT
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -799,9 +852,19 @@ def extrude_geometry(context, pg, operation, mode, obj, bm, values):
update_sel(bm, verts_extr, edges_extr, faces_extr)
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def duplicate_geometry(context, pg, operation, mode, obj, bm, values):
"""Duplicate Geometry.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, bm, verts, values
Returns:
Nothing.
"""
if not obj.mode == "EDIT":
pg.error = PDT_ERR_DUPEDIT
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -837,10 +900,19 @@ def duplicate_geometry(context, pg, operation, mode, obj, bm, values):
update_sel(bm, verts_dupe, edges_dupe, faces_dupe)
bmesh.update_edit_mesh(obj.data)
bm.select_history.clear()
return
def fillet_geometry(context, pg, mode, obj, bm, verts, values):
"""Fillet Geometry.
Args:
context: Blender bpy.context instance.
pg, operation, mode, obj, bm, verts, values
Returns:
Nothing.
"""
if not obj.mode == "EDIT":
pg.error = PDT_ERR_FILEDIT
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -870,14 +942,14 @@ def fillet_geometry(context, pg, mode, obj, bm, verts, values):
v_last = edges[1].verts[0]
v_first = edges[1].verts[1]
vector_delta, done = intersection(v_active.co,
v_other.co,
v_last.co,
v_first.co,
plane
)
v_other.co,
v_last.co,
v_first.co,
plane
)
if not done:
errmsg = f"{PDT_ERR_INT_LINES} {plane} {PDT_LAB_PLANE}"
self.report({"ERROR"}, errmsg)
pg.error = f"{PDT_ERR_INT_LINES} {plane} {PDT_LAB_PLANE}"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
raise PDT_IntersectionError
if (v_active.co - vector_delta).length < (v_other.co - vector_delta).length:
v_active.co = vector_delta
@ -904,4 +976,3 @@ def fillet_geometry(context, pg, mode, obj, bm, verts, values):
profile=_profile,
vertex_only=vert_bool
)
return

View File

@ -21,42 +21,14 @@
# Author: Alan Odom (Clockmender), Rune Morling (ermo) Copyright (c) 2019
# -----------------------------------------------------------------------
#
import bmesh
import bpy
import numpy as np
from bpy.types import Operator
from mathutils import Vector
from mathutils.geometry import intersect_point_line
from math import sin, cos, tan, pi, sqrt
from .pdt_functions import (
check_selection,
set_axis,
view_coords,
view_coords_i,
intersection,
)
from .pdt_msg_strings import (
PDT_ERR_EDOB_MODE,
PDT_ERR_INT_LINES,
PDT_ERR_INT_NO_ALL,
PDT_ERR_NON_VALID,
PDT_ERR_NO_ACT_OBJ,
PDT_ERR_SEL_2_OBJS,
PDT_ERR_SEL_2_VERTIO,
PDT_ERR_SEL_3_OBJS,
PDT_ERR_SEL_3_VERTIO,
PDT_ERR_SEL_4_OBJS,
PDT_ERR_SEL_4_VERTS,
PDT_ERR_TAPER_ANG,
PDT_ERR_TAPER_SEL,
PDT_ERR_VERT_MODE,
PDT_INF_OBJ_MOVED,
PDT_LAB_ABS,
PDT_LAB_DEL,
PDT_LAB_DIR,
PDT_LAB_INTERSECT,
PDT_LAB_PERCENT,
PDT_LAB_PLANE,
)
@ -587,21 +559,21 @@ class PDT_OT_Fillet(Operator):
val_round = context.preferences.addons[__package__].preferences.pdt_input_round
if pg.fillet_intersect:
pg.command = (
f"fi{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
f"fi{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
)
elif pg.fillet_vertices_only:
pg.command = (
f"fv{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
f"fv{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
)
else:
pg.command = (
f"fe{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
f"fe{str(round(pg.fillet_radius, val_round))}"
f",{str(round(pg.fillet_segments, val_round))}"
f",{str(round(pg.fillet_profile, val_round))}"
)
return {"FINISHED"}

View File

@ -29,25 +29,23 @@ import bmesh
from mathutils.geometry import intersect_line_plane
from .pdt_msg_strings import (
PDT_ERR_NOINT,
PDT_ERR_SEL_1_E_1_F
PDT_ERR_EDOB_MODE,
)
from .pdt_functions import oops
def failure_message(self, context):
def failure_message(context):
"""Warn to the user to select 1 edge and 1 face."""
pg = context.scene.pdt_pg
pg.error = f"Select One Face and One Edge"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
def failure_message_on_plane(self, context):
def failure_message_on_plane(context):
"""Report an informative error message in a popup."""
pg = context.scene.pdt_pg
pg.error = f"{PDT_ERR_NOINT}"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
def extend_vertex(context):
"""Computes Edge Extension to Face.
@ -59,31 +57,33 @@ def extend_vertex(context):
Nothing."""
obj = bpy.context.edit_object
pg = context.scene.pdt_pg
if all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"]):
me = obj.data
bm = bmesh.from_edit_mesh(me)
object_data = obj.data
bm = bmesh.from_edit_mesh(object_data)
verts = bm.verts
faces = bm.faces
planes = [f for f in faces if f.select]
if not len(planes) == 1:
failure_message(self, context)
failure_message(context)
return
plane = planes[0]
plane_vert_indices = plane.verts[:]
all_selected_vert_indices = [v for v in verts if v.select]
M = set(plane_vert_indices)
N = set(all_selected_vert_indices)
O = N.difference(M)
O = list(O)
plane_verts = set(plane_vert_indices)
all_verts = set(all_selected_vert_indices)
diff_verts = all_verts.difference(plane_verts)
diff_verts = list(diff_verts)
if not len(O) == 2:
failure_message(self, context)
if not len(diff_verts) == 2:
failure_message(context)
return
(v1_ref, v1), (v2_ref, v2) = [(i, i.co) for i in O]
(v1_ref, v1), (v2_ref, v2) = [(i, i.co) for i in diff_verts]
plane_co = plane.calc_center_median()
plane_no = plane.normal
@ -92,15 +92,15 @@ def extend_vertex(context):
if new_co:
new_vertex = verts.new(new_co)
A_len = (v1 - new_co).length
B_len = (v2 - new_co).length
a_len = (v1 - new_co).length
b_len = (v2 - new_co).length
vertex_reference = v1_ref if (A_len < B_len) else v2_ref
vertex_reference = v1_ref if (a_len < b_len) else v2_ref
bm.edges.new([vertex_reference, new_vertex])
bmesh.update_edit_mesh(me, True)
bmesh.update_edit_mesh(object_data, True)
else:
failure_message_on_plane(self, context)
failure_message_on_plane(context)
else:
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
@ -117,10 +117,10 @@ class PDT_OT_EdgeToFace(bpy.types.Operator):
@classmethod
def poll(cls, context):
"""Only allow this to work if a mesh is selected in EDIT mode."""
ob = context.object
if ob is None:
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
return all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"])
def execute(self, context):
"""Extends Disconnected Edge to Intersect with Face.

View File

@ -37,12 +37,9 @@ from .pdt_msg_strings import (
PDT_ERR_SEL_2_OBJS,
PDT_ERR_NO_ACT_OBJ,
PDT_ERR_SEL_1_EDGEM,
PDT_ERR_BAD1VALS,
PDT_ERR_BAD2VALS,
PDT_ERR_BAD3VALS,
PDT_ERR_SEL_2_VERTS,
PDT_ERR_CONNECTED,
)
from . import pdt_exception
PDT_ShaderError = pdt_exception.ShaderError
def debug(msg, prefix=""):
@ -96,7 +93,10 @@ def oops(self, context):
def set_mode(mode_pl):
"""Sets Active Axes for View Orientation.
Sets indices of axes for locational vectors
Sets indices of axes for locational vectors:
"XY": a1 = x, a2 = y, a3 = z
"XZ": a1 = x, a2 = z, a3 = y
"YZ": a1 = y, a2 = z, a3 = x
Args:
mode_pl: Plane Selector variable as input
@ -105,16 +105,12 @@ def set_mode(mode_pl):
3 Integer indices.
"""
if mode_pl == "XY":
# a1 = x a2 = y a3 = z
return 0, 1, 2
if mode_pl == "XZ":
# a1 = x a2 = z a3 = y
return 0, 2, 1
if mode_pl == "YZ":
# a1 = y a2 = z a3 = x
return 1, 2, 0
#FIXME: This needs a proper specification and a default
order = {
"XY": (0, 1, 2),
"XZ": (0, 2, 1),
"YZ": (1, 2, 0),
}
return order[mode_pl]
def set_axis(mode_pl):
@ -132,19 +128,15 @@ def set_axis(mode_pl):
3 Integer Indicies.
"""
if mode_pl == "RX-MY":
return 0, 1, 2
if mode_pl == "RX-MZ":
return 0, 2, 1
if mode_pl == "RY-MX":
return 1, 0, 2
if mode_pl == "RY-MZ":
return 1, 2, 0
if mode_pl == "RZ-MX":
return 2, 0, 1
if mode_pl == "RZ-MY":
return 2, 1, 0
#FIXME: This needs a proper specification and a default
order = {
"RX-MY": (0, 1, 2),
"RX-MZ": (0, 2, 1),
"RY-MX": (1, 0, 2),
"RY-MZ": (1, 2, 0),
"RZ-MX": (2, 0, 1),
"RZ-MY": (2, 1, 0),
}
return order[mode_pl]
def check_selection(num, bm, obj):
@ -163,20 +155,19 @@ def check_selection(num, bm, obj):
if len(bm.select_history) < num:
return None
else:
actE = bm.select_history[-1]
if isinstance(actE, bmesh.types.BMVert):
vector_a = actE.co
active_vertex = bm.select_history[-1]
if isinstance(active_vertex, bmesh.types.BMVert):
vector_a = active_vertex.co
if num == 1:
return vector_a
elif num == 2:
if num == 2:
vector_b = bm.select_history[-2].co
return vector_a, vector_b
elif num == 3:
if num == 3:
vector_b = bm.select_history[-2].co
vector_c = bm.select_history[-3].co
return vector_a, vector_b, vector_c
elif num == 4:
if num == 4:
vector_b = bm.select_history[-2].co
vector_c = bm.select_history[-3].co
vector_d = bm.select_history[-4].co
@ -233,13 +224,13 @@ def view_coords(x_loc, y_loc, z_loc):
areas = [a for a in bpy.context.screen.areas if a.type == "VIEW_3D"]
if len(areas) > 0:
vm = areas[0].spaces.active.region_3d.view_matrix
vm = vm.to_3x3().normalized().inverted()
vl = Vector((x_loc, y_loc, z_loc))
vw = vm @ vl
return vw
else:
return Vector((0, 0, 0))
view_matrix = areas[0].spaces.active.region_3d.view_matrix
view_matrix = view_matrix.to_3x3().normalized().inverted()
view_location = Vector((x_loc, y_loc, z_loc))
new_view_location = view_matrix @ view_location
return new_view_location
return Vector((0, 0, 0))
def view_coords_i(x_loc, y_loc, z_loc):
@ -258,13 +249,13 @@ def view_coords_i(x_loc, y_loc, z_loc):
areas = [a for a in bpy.context.screen.areas if a.type == "VIEW_3D"]
if len(areas) > 0:
vm = areas[0].spaces.active.region_3d.view_matrix
vm = vm.to_3x3().normalized()
vl = Vector((x_loc, y_loc, z_loc))
vw = vm @ vl
return vw
else:
return Vector((0, 0, 0))
view_matrix = areas[0].spaces.active.region_3d.view_matrix
view_matrix = view_matrix.to_3x3().normalized()
view_location = Vector((x_loc, y_loc, z_loc))
new_view_location = view_matrix @ view_location
return new_view_location
return Vector((0, 0, 0))
def view_dir(dis_v, ang_v):
@ -283,15 +274,15 @@ def view_dir(dis_v, ang_v):
areas = [a for a in bpy.context.screen.areas if a.type == "VIEW_3D"]
if len(areas) > 0:
vm = areas[0].spaces.active.region_3d.view_matrix
vm = vm.to_3x3().normalized().inverted()
vl = Vector((0, 0, 0))
vl.x = dis_v * cos(ang_v * pi / 180)
vl.y = dis_v * sin(ang_v * pi / 180)
vw = vm @ vl
return vw
else:
return Vector((0, 0, 0))
view_matrix = areas[0].spaces.active.region_3d.view_matrix
view_matrix = view_matrix.to_3x3().normalized().inverted()
view_location = Vector((0, 0, 0))
view_location.x = dis_v * cos(ang_v * pi / 180)
view_location.y = dis_v * sin(ang_v * pi / 180)
new_view_location = view_matrix @ view_location
return new_view_location
return Vector((0, 0, 0))
def euler_to_quaternion(roll, pitch, yaw):
@ -307,16 +298,16 @@ def euler_to_quaternion(roll, pitch, yaw):
"""
# fmt: off
qx = (np.sin(roll/2) * np.cos(pitch/2) * np.cos(yaw/2)
- np.cos(roll/2) * np.sin(pitch/2) * np.sin(yaw/2))
qy = (np.cos(roll/2) * np.sin(pitch/2) * np.cos(yaw/2)
+ np.sin(roll/2) * np.cos(pitch/2) * np.sin(yaw/2))
qz = (np.cos(roll/2) * np.cos(pitch/2) * np.sin(yaw/2)
- np.sin(roll/2) * np.sin(pitch/2) * np.cos(yaw/2))
qw = (np.cos(roll/2) * np.cos(pitch/2) * np.cos(yaw/2)
+ np.sin(roll/2) * np.sin(pitch/2) * np.sin(yaw/2))
quat_x = (np.sin(roll/2) * np.cos(pitch/2) * np.cos(yaw/2)
- np.cos(roll/2) * np.sin(pitch/2) * np.sin(yaw/2))
quat_y = (np.cos(roll/2) * np.sin(pitch/2) * np.cos(yaw/2)
+ np.sin(roll/2) * np.cos(pitch/2) * np.sin(yaw/2))
quat_z = (np.cos(roll/2) * np.cos(pitch/2) * np.sin(yaw/2)
- np.sin(roll/2) * np.sin(pitch/2) * np.cos(yaw/2))
quat_w = (np.cos(roll/2) * np.cos(pitch/2) * np.cos(yaw/2)
+ np.sin(roll/2) * np.sin(pitch/2) * np.sin(yaw/2))
# fmt: on
return Quaternion((qw, qx, qy, qz))
return Quaternion((quat_w, quat_x, quat_y, quat_z))
def arc_centre(vector_a, vector_b, vector_c):
@ -331,22 +322,29 @@ def arc_centre(vector_a, vector_b, vector_c):
Vector representing Arc Centre and Float representing Arc Radius.
"""
A = np.array([vector_a.x, vector_a.y, vector_a.z])
B = np.array([vector_b.x, vector_b.y, vector_b.z])
C = np.array([vector_c.x, vector_c.y, vector_c.z])
a = np.linalg.norm(C - B)
b = np.linalg.norm(C - A)
c = np.linalg.norm(B - A)
coord_a = np.array([vector_a.x, vector_a.y, vector_a.z])
coord_b = np.array([vector_b.x, vector_b.y, vector_b.z])
coord_c = np.array([vector_c.x, vector_c.y, vector_c.z])
line_a = np.linalg.norm(coord_c - coord_b)
line_b = np.linalg.norm(coord_c - coord_a)
line_c = np.linalg.norm(coord_b - coord_a)
# fmt: off
s = (a+b+c) / 2
R = a*b*c/4 / np.sqrt(s * (s-a) * (s-b) * (s-c))
b1 = a*a * (b*b + c*c - a*a)
b2 = b*b * (a*a + c*c - b*b)
b3 = c*c * (a*a + b*b - c*c)
line_s = (line_a+line_b+line_c) / 2
radius = (
line_a*line_b*line_c/4
/ np.sqrt(line_s
* (line_s-line_a)
* (line_s-line_b)
* (line_s-line_c))
)
base_1 = line_a*line_a * (line_b*line_b + line_c*line_c - line_a*line_a)
base_2 = line_b*line_b * (line_a*line_a + line_c*line_c - line_b*line_b)
base_3 = line_c*line_c * (line_a*line_a + line_b*line_b - line_c*line_c)
# fmt: on
P = np.column_stack((A, B, C)).dot(np.hstack((b1, b2, b3)))
P /= b1 + b2 + b3
return Vector((P[0], P[1], P[2])), R
intersect_coord = np.column_stack((coord_a, coord_b, coord_c))
intersect_coord = intersect_coord.dot(np.hstack((base_1, base_2, base_3)))
intersect_coord /= base_1 + base_2 + base_3
return Vector((intersect_coord[0], intersect_coord[1], intersect_coord[2])), radius
def intersection(vertex_a, vertex_b, vertex_c, vertex_d, plane):
@ -371,38 +369,39 @@ def intersection(vertex_a, vertex_b, vertex_c, vertex_d, plane):
vertex_offset = vertex_c - vertex_a
vertex_c = view_coords_i(vertex_offset.x, vertex_offset.y, vertex_offset.z)
vector_ref = Vector((0, 0, 0))
ap1 = (vertex_c.x, vertex_c.y)
ap2 = (vertex_d.x, vertex_d.y)
bp1 = (vertex_b.x, vertex_b.y)
bp2 = (vector_ref.x, vector_ref.y)
coord_a = (vertex_c.x, vertex_c.y)
coord_b = (vertex_d.x, vertex_d.y)
coord_c = (vertex_b.x, vertex_b.y)
coord_d = (vector_ref.x, vector_ref.y)
else:
a1, a2, a3 = set_mode(plane)
ap1 = (vertex_c[a1], vertex_c[a2])
ap2 = (vertex_d[a1], vertex_d[a2])
bp1 = (vertex_a[a1], vertex_a[a2])
bp2 = (vertex_b[a1], vertex_b[a2])
s = np.vstack([ap1, ap2, bp1, bp2])
h = np.hstack((s, np.ones((4, 1))))
l1 = np.cross(h[0], h[1])
l2 = np.cross(h[2], h[3])
x, y, z = np.cross(l1, l2)
if z == 0:
coord_a = (vertex_c[a1], vertex_c[a2])
coord_b = (vertex_d[a1], vertex_d[a2])
coord_c = (vertex_a[a1], vertex_a[a2])
coord_d = (vertex_b[a1], vertex_b[a2])
v_stack = np.vstack([coord_a, coord_b, coord_c, coord_d])
h_stack = np.hstack((v_stack, np.ones((4, 1))))
line_a = np.cross(h_stack[0], h_stack[1])
line_b = np.cross(h_stack[2], h_stack[3])
x_loc, y_loc, z_loc = np.cross(line_a, line_b)
if z_loc == 0:
return Vector((0, 0, 0)), False
nx = x / z
nz = y / z
new_x_loc = x_loc / z_loc
new_z_loc = y_loc / z_loc
if plane == "LO":
ly = 0
new_y_loc = 0
else:
ly = vertex_a[a3]
new_y_loc = vertex_a[a3]
# Order Vector Delta
if plane == "XZ":
vector_delta = Vector((nx, ly, nz))
vector_delta = Vector((new_x_loc, new_y_loc, new_z_loc))
elif plane == "XY":
vector_delta = Vector((nx, nz, ly))
vector_delta = Vector((new_x_loc, new_z_loc, new_y_loc))
elif plane == "YZ":
vector_delta = Vector((ly, nx, nz))
elif plane == "LO":
vector_delta = view_coords(nx, nz, ly) + vertex_a
vector_delta = Vector((new_y_loc, new_x_loc, new_z_loc))
else:
# Must be Local View Plane
vector_delta = view_coords(new_x_loc, new_z_loc, new_y_loc) + vertex_a
return vector_delta, True
@ -442,38 +441,38 @@ def get_percent(obj, flip_p, per_v, data, scene):
pg.error = PDT_ERR_SEL_2_V_1_E + str(len(verts)) + " Vertices"
bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return None
p1 = np.array([vector_a.x, vector_a.y, vector_a.z])
p2 = np.array([vector_b.x, vector_b.y, vector_b.z])
coord_a = np.array([vector_a.x, vector_a.y, vector_a.z])
coord_b = np.array([vector_b.x, vector_b.y, vector_b.z])
if obj.mode == "OBJECT":
objs = bpy.context.view_layer.objects.selected
if len(objs) != 2:
pg.error = PDT_ERR_SEL_2_OBJS + str(len(objs)) + ")"
bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return None
p1 = np.array(
coord_a = np.array(
[
objs[-1].matrix_world.decompose()[0].x,
objs[-1].matrix_world.decompose()[0].y,
objs[-1].matrix_world.decompose()[0].z,
]
)
p2 = np.array(
coord_b = np.array(
[
objs[-2].matrix_world.decompose()[0].x,
objs[-2].matrix_world.decompose()[0].y,
objs[-2].matrix_world.decompose()[0].z,
]
)
p4 = np.array([0, 0, 0])
p3 = p2 - p1
coord_c = coord_b - coord_a
coord_d = np.array([0, 0, 0])
_per_v = per_v
if (flip_p and data != "MV") or data == "MV":
_per_v = 100 - per_v
V = (p4+p3) * (_per_v / 100) + p1
return Vector((V[0], V[1], V[2]))
coord_out = (coord_d+coord_c) * (_per_v / 100) + coord_a
return Vector((coord_out[0], coord_out[1], coord_out[2]))
def obj_check(context, obj, scene, operator):
def obj_check(obj, scene, operator):
"""Check Object & Selection Validity.
Args:
@ -499,32 +498,29 @@ def obj_check(context, obj, scene, operator):
pg.error = f"{PDT_ERR_SEL_1_EDGEM} {len(bm.edges)})"
bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return None, False
else:
return bm, True
return bm, True
if len(bm.select_history) >= 1:
vector_a = None
if _operator not in {"D", "E", "F", "G", "N", "S"}:
vector_a = check_selection(1, bm, obj)
else:
verts = [v for v in bm.verts if v.select]
if len(verts) > 0:
vector_a = verts[0]
else:
vector_a = None
if vector_a is None:
pg.error = PDT_ERR_VERT_MODE
bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return None, False
return bm, True
else:
return None, True
return None, True
def dis_ang(vals, flip_a, plane, scene):
def dis_ang(values, flip_angle, plane, scene):
"""Set Working Axes when using Direction command.
Args:
vals: Input Arguments (Values)
flip_a: Whether to flip the angle
values: Input Arguments
flip_angle: Whether to flip the angle
plane: Working Plane
scene: Current Scene
@ -533,9 +529,9 @@ def dis_ang(vals, flip_a, plane, scene):
"""
pg = scene.pdt_pg
dis_v = float(vals[0])
ang_v = float(vals[1])
if flip_a:
dis_v = float(values[0])
ang_v = float(values[1])
if flip_angle:
if ang_v > 0:
ang_v = ang_v - 180
else:
@ -555,10 +551,10 @@ def dis_ang(vals, flip_a, plane, scene):
# Shader for displaying the Pivot Point as Graphics.
#
shader = gpu.shader.from_builtin("3D_UNIFORM_COLOR") if not bpy.app.background else None
SHADER = gpu.shader.from_builtin("3D_UNIFORM_COLOR") if not bpy.app.background else None
def draw3D(coords, gtype, rgba, context):
def draw_3d(coords, gtype, rgba, context):
"""Draw Pivot Point Graphics.
Draws either Lines Points, or Tris using defined shader
@ -573,19 +569,19 @@ def draw3D(coords, gtype, rgba, context):
Nothing.
"""
batch = batch_for_shader(shader, gtype, {"pos": coords})
batch = batch_for_shader(SHADER, gtype, {"pos": coords})
try:
if coords is not None:
bgl.glEnable(bgl.GL_BLEND)
shader.bind()
shader.uniform_float("color", rgba)
batch.draw(shader)
SHADER.bind()
SHADER.uniform_float("color", rgba)
batch.draw(SHADER)
except:
pass
raise PDT_ShaderError
def drawCallback3D(self, context):
def draw_callback_3d(self, context):
"""Create Coordinate List for Pivot Point Graphic.
Creates coordinates for Pivot Point Graphic consisting of 6 Tris
@ -601,73 +597,73 @@ def drawCallback3D(self, context):
scene = context.scene
pg = scene.pdt_pg
w = context.region.width
x = pg.pivot_loc.x
y = pg.pivot_loc.y
z = pg.pivot_loc.z
region_width = context.region.width
x_loc = pg.pivot_loc.x
y_loc = pg.pivot_loc.y
z_loc = pg.pivot_loc.z
# Scale it from view
areas = [a for a in context.screen.areas if a.type == "VIEW_3D"]
if len(areas) > 0:
sf = abs(areas[0].spaces.active.region_3d.window_matrix.decompose()[2][1])
scale_factor = abs(areas[0].spaces.active.region_3d.window_matrix.decompose()[2][1])
# Check for orhtographic view and resize
#if areas[0].spaces.active.region_3d.is_orthographic_side_view:
# a = w / sf / 60000 * pg.pivot_size
# dim_a = region_width / sf / 60000 * pg.pivot_size
#else:
# a = w / sf / 5000 * pg.pivot_size
a = w / sf / 50000 * pg.pivot_size
b = a * 0.65
c = a * 0.05 + (pg.pivot_width * a * 0.02)
o = c / 3
# dim_a = region_width / sf / 5000 * pg.pivot_size
dim_a = region_width / scale_factor / 50000 * pg.pivot_size
dim_b = dim_a * 0.65
dim_c = dim_a * 0.05 + (pg.pivot_width * dim_a * 0.02)
dim_o = dim_c / 3
# fmt: off
# X Axis
coords = [
(x, y, z),
(x+b, y-o, z),
(x+b, y+o, z),
(x+a, y, z),
(x+b, y+c, z),
(x+b, y-c, z),
(x_loc, y_loc, z_loc),
(x_loc+dim_b, y_loc-dim_o, z_loc),
(x_loc+dim_b, y_loc+dim_o, z_loc),
(x_loc+dim_a, y_loc, z_loc),
(x_loc+dim_b, y_loc+dim_c, z_loc),
(x_loc+dim_b, y_loc-dim_c, z_loc),
]
# fmt: on
colour = (1.0, 0.0, 0.0, pg.pivot_alpha)
draw3D(coords, "TRIS", colour, context)
coords = [(x, y, z), (x+a, y, z)]
draw3D(coords, "LINES", colour, context)
draw_3d(coords, "TRIS", colour, context)
coords = [(x_loc, y_loc, z_loc), (x_loc+dim_a, y_loc, z_loc)]
draw_3d(coords, "LINES", colour, context)
# fmt: off
# Y Axis
coords = [
(x, y, z),
(x-o, y+b, z),
(x+o, y+b, z),
(x, y+a, z),
(x+c, y+b, z),
(x-c, y+b, z),
(x_loc, y_loc, z_loc),
(x_loc-dim_o, y_loc+dim_b, z_loc),
(x_loc+dim_o, y_loc+dim_b, z_loc),
(x_loc, y_loc+dim_a, z_loc),
(x_loc+dim_c, y_loc+dim_b, z_loc),
(x_loc-dim_c, y_loc+dim_b, z_loc),
]
# fmt: on
colour = (0.0, 1.0, 0.0, pg.pivot_alpha)
draw3D(coords, "TRIS", colour, context)
coords = [(x, y, z), (x, y + a, z)]
draw3D(coords, "LINES", colour, context)
draw_3d(coords, "TRIS", colour, context)
coords = [(x_loc, y_loc, z_loc), (x_loc, y_loc + dim_a, z_loc)]
draw_3d(coords, "LINES", colour, context)
# fmt: off
# Z Axis
coords = [
(x, y, z),
(x-o, y, z+b),
(x+o, y, z+b),
(x, y, z+a),
(x+c, y, z+b),
(x-c, y, z+b),
(x_loc, y_loc, z_loc),
(x_loc-dim_o, y_loc, z_loc+dim_b),
(x_loc+dim_o, y_loc, z_loc+dim_b),
(x_loc, y_loc, z_loc+dim_a),
(x_loc+dim_c, y_loc, z_loc+dim_b),
(x_loc-dim_c, y_loc, z_loc+dim_b),
]
# fmt: on
colour = (0.2, 0.5, 1.0, pg.pivot_alpha)
draw3D(coords, "TRIS", colour, context)
coords = [(x, y, z), (x, y, z + a)]
draw3D(coords, "LINES", colour, context)
draw_3d(coords, "TRIS", colour, context)
coords = [(x_loc, y_loc, z_loc), (x_loc, y_loc, z_loc + dim_a)]
draw_3d(coords, "LINES", colour, context)
# Centre
coords = [(x, y, z)]
coords = [(x_loc, y_loc, z_loc)]
colour = (1.0, 1.0, 0.0, pg.pivot_alpha)
draw3D(coords, "POINTS", colour, context)
draw_3d(coords, "POINTS", colour, context)
def scale_set(self, context):

View File

@ -31,6 +31,7 @@ from .pdt_msg_strings import PDT_ERR_NO_LIBRARY
class PDT_OT_LibShow(Operator):
"""Show Library File Details."""
bl_idname = "pdt.lib_show"
bl_label = "Show Library Details"
bl_options = {"REGISTER", "UNDO"}
@ -51,7 +52,9 @@ class PDT_OT_LibShow(Operator):
pg.error = str(Path(file_path))
debug("PDT Parts Library:")
debug(f"{pg.error}")
bpy.context.window_manager.popup_menu(oops, title="Information - Parts Library File", icon="INFO")
bpy.context.window_manager.popup_menu(
oops, title="Information - Parts Library File", icon="INFO"
)
return {"FINISHED"}
@ -86,37 +89,51 @@ class PDT_OT_Append(Operator):
if path.is_file() and ".blend" in str(path):
if pg.lib_mode == "OBJECTS":
# Force object Mode
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.wm.append(
filepath=str(path), directory=str(path) + "/Object", filename=pg.lib_objects
filepath=str(path),
directory=str(path) + "/Object",
filename=pg.lib_objects,
)
for obj in context.view_layer.objects:
if obj.name not in obj_names:
obj.select_set(False)
obj.location = Vector(
(scene.cursor.location.x, scene.cursor.location.y, scene.cursor.location.z)
(
scene.cursor.location.x,
scene.cursor.location.y,
scene.cursor.location.z,
)
)
return {"FINISHED"}
elif pg.lib_mode == "COLLECTIONS":
if pg.lib_mode == "COLLECTIONS":
bpy.ops.wm.append(
filepath=str(path), directory=str(path) + "/Collection", filename=pg.lib_collections
filepath=str(path),
directory=str(path) + "/Collection",
filename=pg.lib_collections,
)
for obj in context.view_layer.objects:
if obj.name not in obj_names:
obj.select_set(False)
obj.location = Vector(
(scene.cursor.location.x, scene.cursor.location.y, scene.cursor.location.z)
(
scene.cursor.location.x,
scene.cursor.location.y,
scene.cursor.location.z,
)
)
return {"FINISHED"}
elif pg.lib_mode == "MATERIALS":
if pg.lib_mode == "MATERIALS":
bpy.ops.wm.append(
filepath=str(path), directory=str(path) + "/Material", filename=pg.lib_materials
filepath=str(path),
directory=str(path) + "/Material",
filename=pg.lib_materials,
)
return {"FINISHED"}
else:
errmsg = PDT_ERR_NO_LIBRARY
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
errmsg = PDT_ERR_NO_LIBRARY
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
class PDT_OT_Link(Operator):
@ -148,26 +165,32 @@ class PDT_OT_Link(Operator):
if path.is_file() and ".blend" in str(path):
if pg.lib_mode == "OBJECTS":
# Force object Mode
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.wm.link(
filepath=str(path), directory=str(path) + "/Object", filename=pg.lib_objects
filepath=str(path),
directory=str(path) + "/Object",
filename=pg.lib_objects,
)
for obj in context.view_layer.objects:
obj.select_set(False)
return {"FINISHED"}
elif pg.lib_mode == "COLLECTIONS":
if pg.lib_mode == "COLLECTIONS":
bpy.ops.wm.link(
filepath=str(path), directory=str(path) + "/Collection", filename=pg.lib_collections
filepath=str(path),
directory=str(path) + "/Collection",
filename=pg.lib_collections,
)
for obj in context.view_layer.objects:
obj.select_set(False)
return {"FINISHED"}
elif pg.lib_mode == "MATERIALS":
if pg.lib_mode == "MATERIALS":
bpy.ops.wm.link(
filepath=str(path), directory=str(path) + "/Material", filename=pg.lib_materials
filepath=str(path),
directory=str(path) + "/Material",
filename=pg.lib_materials,
)
return {"FINISHED"}
else:
errmsg = PDT_ERR_NO_LIBRARY
self.report({"ERROR"}, errmsg)
return {"FINISHED"}
errmsg = PDT_ERR_NO_LIBRARY
self.report({"ERROR"}, errmsg)
return {"FINISHED"}

View File

@ -28,147 +28,153 @@
#
# Menu Labels
#
PDT_LAB_ABS = "Absolute" # "Global"
PDT_LAB_DEL = "Delta" # "Relative"
PDT_LAB_DIR = "Direction" # "Polar"
PDT_LAB_NOR = "Normal" # "Perpendicular"
PDT_LAB_ARCCENTRE = "Arc Centre"
PDT_LAB_PLANE = "Plane"
PDT_LAB_MODE = "Mode"
PDT_LAB_OPERATION = "Operation"
PDT_LAB_PERCENT = "Percent"
PDT_LAB_INTERSECT = "Intersect" # "Convergance"
PDT_LAB_ORDER = "Order"
PDT_LAB_FLIPANGLE = "Flip Angle"
PDT_LAB_FLIPPERCENT = "Flip %"
PDT_LAB_ALLACTIVE = "All/Active"
PDT_LAB_VARIABLES = "Coordinates/Delta Offsets & Other Variables"
PDT_LAB_CVALUE = "Coordinates"
PDT_LAB_DISVALUE = "Distance"
PDT_LAB_ANGLEVALUE = "Angle"
PDT_LAB_PERCENTS = "%"
PDT_LAB_TOOLS = "Tools"
PDT_LAB_JOIN2VERTS = "Join 2 Verts"
PDT_LAB_ORIGINCURSOR = "Origin To Cursor"
PDT_LAB_AD2D = "Set A/D 2D"
PDT_LAB_AD3D = "Set A/D 3D"
PDT_LAB_TAPERAXES = "" # Intentionally left blank
PDT_LAB_TAPER = "Taper"
PDT_LAB_INTERSETALL = "Intersect All"
PDT_LAB_BISECT = "Bisect"
PDT_LAB_EDGETOEFACE = "Edge-To-Face"
PDT_LAB_FILLET = "Fillet"
PDT_LAB_SEGMENTS = "Segments"
PDT_LAB_USEVERTS = "Use Vertices"
PDT_LAB_RADIUS = "Radius"
PDT_LAB_PROFILE = "Profile"
PDT_LAB_PIVOTSIZE = "" # Intentionally left blank
PDT_LAB_PIVOTWIDTH = "" # Intentionally left blank
PDT_LAB_PIVOTALPHA = "" # Intentionally left blank
PDT_LAB_PIVOTLOC = "" # Intentionally left blank
PDT_LAB_PIVOTLOCH = "Location"
PDT_LAB_ABS = "Absolute" # "Global"
PDT_LAB_DEL = "Delta" # "Relative"
PDT_LAB_DIR = "Direction" # "Polar"
PDT_LAB_NOR = "Normal" # "Perpendicular"
PDT_LAB_ARCCENTRE = "Arc Centre"
PDT_LAB_PLANE = "Plane"
PDT_LAB_MODE = "Mode"
PDT_LAB_OPERATION = "Operation"
PDT_LAB_PERCENT = "Percent"
PDT_LAB_INTERSECT = "Intersect" # "Convergance"
PDT_LAB_ORDER = "Order"
PDT_LAB_FLIPANGLE = "Flip Angle"
PDT_LAB_FLIPPERCENT = "Flip %"
PDT_LAB_ALLACTIVE = "All/Active"
PDT_LAB_VARIABLES = "Coordinates/Delta Offsets & Other Variables"
PDT_LAB_CVALUE = "Coordinates"
PDT_LAB_DISVALUE = "Distance"
PDT_LAB_ANGLEVALUE = "Angle"
PDT_LAB_PERCENTS = "%"
PDT_LAB_TOOLS = "Tools"
PDT_LAB_JOIN2VERTS = "Join 2 Verts"
PDT_LAB_ORIGINCURSOR = "Origin To Cursor"
PDT_LAB_AD2D = "Set A/D 2D"
PDT_LAB_AD3D = "Set A/D 3D"
PDT_LAB_TAPERAXES = "" # Intentionally left blank
PDT_LAB_TAPER = "Taper"
PDT_LAB_INTERSETALL = "Intersect All"
PDT_LAB_BISECT = "Bisect"
PDT_LAB_EDGETOEFACE = "Edge-To-Face"
PDT_LAB_FILLET = "Fillet"
PDT_LAB_SEGMENTS = "Segments"
PDT_LAB_USEVERTS = "Use Vertices"
PDT_LAB_RADIUS = "Radius"
PDT_LAB_PROFILE = "Profile"
PDT_LAB_PIVOTSIZE = "" # Intentionally left blank
PDT_LAB_PIVOTWIDTH = "" # Intentionally left blank
PDT_LAB_PIVOTALPHA = "" # Intentionally left blank
PDT_LAB_PIVOTLOC = "" # Intentionally left blank
PDT_LAB_PIVOTLOCH = "Location"
#
# Error Message
#
PDT_ERR_NO_ACT_OBJ = "No Active Object - Please Select an Object"
PDT_OBJ_MODE_ERROR = "Only Mesh Object in Edit or Object Mode Supported"
PDT_ERR_NO_ACT_VERT = "No Active Vertex - Select One Vertex Individually"
PDT_ERR_NO_SEL_GEOM = "No Geometry/Objects Selected"
PDT_ERR_NO_ACT_VERTS = "No Selected Geometry - Please Select some Geometry"
PDT_ERR_NON_VALID = "is Not a Valid Option in Selected Object's Mode for Command:"
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_ACT_OBJ = "No Active Object - Please Select an Object"
PDT_OBJ_MODE_ERROR = "Only Mesh Object in Edit or Object Mode Supported"
PDT_ERR_NO_ACT_VERT = "No Active Vertex - Select One Vertex Individually"
PDT_ERR_NO_SEL_GEOM = "No Geometry/Objects Selected"
PDT_ERR_NO_ACT_VERTS = "No Selected Geometry - Please Select some Geometry"
PDT_ERR_NON_VALID = "is Not a Valid Option in Selected Object's Mode for Command:"
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_SEL_1_VERTI = "Select at least 1 Vertex Individually (Currently selected:"
PDT_ERR_SEL_1_VERT = "Select at least 1 Vertex (Currently selected:"
PDT_ERR_SEL_2_VERTI = "Select at least 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTIO = "Select Exactly 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTS = "Select Exactly 2 Vertices (Currently selected:"
PDT_ERR_SEL_2_EDGES = "Select Only 2 Non-Intersecting Edges (Currently selected:"
PDT_ERR_SEL_3_VERTS = "Select Exactly 3 Vertices (Currently selected:"
PDT_ERR_SEL_3_VERTIO = "Select Exactly 3 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_V_1_E = "Select 2 Vertices Individually, or 1 Edge (Currently selected:"
PDT_ERR_SEL_4_VERTS = "Select 4 Vertices Individually, or 2 Edges (Currently selected:"
PDT_ERR_SEL_1_E_1_F = "Select 1 Face and 1 Detached Edge"
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:"
PDT_ERR_SEL_2_VERTI = "Select at least 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTIO = "Select Exactly 2 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_VERTS = "Select Exactly 2 Vertices (Currently selected:"
PDT_ERR_SEL_2_EDGES = "Select Only 2 Non-Intersecting Edges (Currently selected:"
PDT_ERR_SEL_3_VERTS = "Select Exactly 3 Vertices (Currently selected:"
PDT_ERR_SEL_3_VERTIO = "Select Exactly 3 Vertices Individually (Currently selected:"
PDT_ERR_SEL_2_V_1_E = "Select 2 Vertices Individually, or 1 Edge (Currently selected:"
PDT_ERR_SEL_4_VERTS = "Select 4 Vertices Individually, or 2 Edges (Currently selected:"
PDT_ERR_SEL_1_E_1_F = "Select 1 Face and 1 Detached Edge"
PDT_ERR_SEL_1_EDGE = "Select Exactly 1 Edge (Currently selected:"
PDT_ERR_SEL_1_EDGEM = "Select at least 1 Edge (Currently selected:"
PDT_ERR_SEL_1_EDGE = "Select Exactly 1 Edge (Currently selected:"
PDT_ERR_SEL_1_EDGEM = "Select at least 1 Edge (Currently selected:"
PDT_ERR_SEL_1_OBJ = "Select Exactly 1 Object (Currently selected:"
PDT_ERR_SEL_2_OBJS = "Select Exactly 2 Objects (Currently selected:"
PDT_ERR_SEL_3_OBJS = "Select Exactly 3 Objects (Currently selected:"
PDT_ERR_SEL_4_OBJS = "Select Exactly 4 Objects (Currently selected:"
PDT_ERR_SEL_1_OBJ = "Select Exactly 1 Object (Currently selected:"
PDT_ERR_SEL_2_OBJS = "Select Exactly 2 Objects (Currently selected:"
PDT_ERR_SEL_3_OBJS = "Select Exactly 3 Objects (Currently selected:"
PDT_ERR_SEL_4_OBJS = "Select Exactly 4 Objects (Currently selected:"
PDT_ERR_FACE_SEL = "You have a Face Selected, this would have ruined the Topology"
PDT_ERR_FACE_SEL = "You have a Face Selected, this would have ruined the Topology"
PDT_ERR_INT_LINES = "Implied Lines Do Not Intersect in"
PDT_ERR_INT_NO_ALL = "Active Vertex was not Closest to Intersection and All/Act was not Selected"
PDT_ERR_STRIGHT_LINE = "Selected Points all lie in a Straight Line"
PDT_ERR_CONNECTED = "Vertices are already Connected"
PDT_ERR_EDIT_MODE = "Only Works in EDIT Mode (Current mode:"
PDT_ERR_EDOB_MODE = "Only Works in EDIT, or OBJECT Modes (Current mode:"
PDT_ERR_TAPER_ANG = "Angle must be in Range -80 to +80 (Currently set to:"
PDT_ERR_TAPER_SEL = "Select at Least 2 Vertices Individually - Active is Rotation Point (Currently selected:"
PDT_ERR_NO3DVIEW = "View3D not found, cannot run operator"
PDT_ERR_SCALEZERO = "Scale Distance is 0"
PDT_ERR_INT_LINES = "Implied Lines Do Not Intersect in"
PDT_ERR_INT_NO_ALL = (
"Active Vertex was not Closest to Intersection and All/Act was not Selected"
)
PDT_ERR_STRIGHT_LINE = "Selected Points all lie in a Straight Line"
PDT_ERR_CONNECTED = "Vertices are already Connected"
PDT_ERR_EDIT_MODE = "Only Works in EDIT Mode (Current mode:"
PDT_ERR_EDOB_MODE = "Only Works in EDIT, or OBJECT Modes (Current mode:"
PDT_ERR_TAPER_ANG = "Angle must be in Range -80 to +80 (Currently set to:"
PDT_ERR_TAPER_SEL = ("Select at Least 2 Vertices Individually - Active is Rotation Point "
+ "(Currently selected:")
PDT_ERR_NO3DVIEW = "View3D not found, cannot run operator"
PDT_ERR_SCALEZERO = "Scale Distance is 0"
PDT_ERR_CHARS_NUM = "Bad Command Format, not enough Characters"
PDT_ERR_BADFLETTER = "Bad Operator (1st Letter); C D E F G N M P S V or ? only"
PDT_ERR_BADMATHS = "Not a Valid Mathematical Expression!"
PDT_ERR_BADCOORDL = "X Y & Z Not permitted in anything other than Maths Operations"
PDT_ERR_BAD1VALS = "Bad Command - 1 Value needed"
PDT_ERR_BAD2VALS = "Bad Command - 2 Values needed"
PDT_ERR_BAD3VALS = "Bad Command - 3 Coords needed"
PDT_ERR_ADDVEDIT = "Only Add New Vertices in Edit Mode"
PDT_ERR_SPLITEDIT = "Only Split Edges in Edit Mode"
PDT_ERR_EXTEDIT = "Only Extrude Vertices in Edit Mode"
PDT_ERR_DUPEDIT = "Only Duplicate Geometry in Edit Mode"
PDT_ERR_FILEDIT = "Only Fillet Geometry in Edit Mode"
PDT_ERR_NOCOMMAS = "No commas allowed in Maths Command"
PDT_ERR_CHARS_NUM = "Bad Command Format, not enough Characters"
PDT_ERR_BADFLETTER = "Bad Operator (1st Letter); C D E F G N M P S V or ? only"
PDT_ERR_BADMATHS = "Not a Valid Mathematical Expression!"
PDT_ERR_BADCOORDL = "X Y & Z Not permitted in anything other than Maths Operations"
PDT_ERR_BAD1VALS = "Bad Command - 1 Value needed"
PDT_ERR_BAD2VALS = "Bad Command - 2 Values needed"
PDT_ERR_BAD3VALS = "Bad Command - 3 Coords needed"
PDT_ERR_ADDVEDIT = "Only Add New Vertices in Edit Mode"
PDT_ERR_SPLITEDIT = "Only Split Edges in Edit Mode"
PDT_ERR_EXTEDIT = "Only Extrude Vertices in Edit Mode"
PDT_ERR_DUPEDIT = "Only Duplicate Geometry in Edit Mode"
PDT_ERR_FILEDIT = "Only Fillet Geometry in Edit Mode"
PDT_ERR_NOCOMMAS = "No commas allowed in Maths Command"
PDT_ERR_2CPNPE = "Select 2 Co-Planar Non-Parallel Edges"
PDT_ERR_NCEDGES = "Edges must be Co-Planar Non-Parallel Edges, Selected Edges aren't"
PDT_ERR_1EDGE1FACE = "Select 1 face and 1 Detached Edge"
PDT_ERR_NOINT = "No Intersection Found"
PDT_ERR_2CPNPE = "Select 2 Co-Planar Non-Parallel Edges"
PDT_ERR_NCEDGES = "Edges must be Co-Planar Non-Parallel Edges, Selected Edges aren't"
PDT_ERR_1EDGE1FACE = "Select 1 face and 1 Detached Edge"
PDT_ERR_NOINT = "No Intersection Found"
# Info messages
#
PDT_INF_OBJ_MOVED = "Active Object Moved to Intersection, "
PDT_INF_OBJ_MOVED = "Active Object Moved to Intersection, "
# Confirm Messages
#
PDT_CON_AREYOURSURE = "Are You Sure About This?"
PDT_CON_AREYOURSURE = "Are You Sure About This?"
# Descriptions
#
PDT_DES_COORDS = "Cartesian Inputs"
PDT_DES_OFFDIS = "Offset Distance"
PDT_DES_OFFANG = "Offset Angle"
PDT_DES_OFFPER = "Offset Percentage"
PDT_DES_WORPLANE = "Choose Working Plane"
PDT_DES_MOVESEL = "Select Move Mode"
PDT_DES_OPMODE = "Select Operation Mode"
PDT_DES_ROTMOVAX = "Rotational Axis - Movement Axis"
PDT_DES_FLIPANG = "Flip Angle 180 degrees"
PDT_DES_FLIPPER = "Flip Percent to 100 - %"
PDT_DES_TRIM = "Trim/Extend only Active Vertex, or All"
PDT_DES_LIBOBS = "Objects in Library"
PDT_DES_LIBCOLS = "Collections in Library"
PDT_DES_LIBMATS = "Materials in Library"
PDT_DES_LIBMODE = "Library Mode"
PDT_DES_LIBSER = "Enter A Search String (Contained)"
PDT_DES_OBORDER = "Object Order to Lines"
PDT_DES_VALIDLET = "Valid 1st letters; C D E G N P S V, Valid 2nd letters: A D I O P"
PDT_DES_OUTPUT = "Output for Maths Operations"
PDT_DES_PPLOC = "Location of PivotPoint"
PDT_DES_PPSCALEFAC = "Scale Factors"
PDT_DES_PPSIZE = "Pivot Size Factor"
PDT_DES_PPWIDTH = "Pivot Line Width in Pixels"
PDT_DES_PPTRANS = "Pivot Point Transparency"
PDT_DES_PIVOTDIS = "Input Distance to Compare with Sytem Distance to set Scales"
PDT_DES_FILLETRAD = "Fillet Radius"
PDT_DES_FILLETSEG = "Number of Fillet Segments"
PDT_DES_FILLETPROF = "Fillet Profile"
PDT_DES_FILLETVERTS = "Use Vertices, or Edges, Set to False for Extruded Geometry"
PDT_DES_FILLINT = "Intersect & Fillet Two Selected Edges"
PDT_DES_COORDS = "Cartesian Inputs"
PDT_DES_OFFDIS = "Offset Distance"
PDT_DES_OFFANG = "Offset Angle"
PDT_DES_OFFPER = "Offset Percentage"
PDT_DES_WORPLANE = "Choose Working Plane"
PDT_DES_MOVESEL = "Select Move Mode"
PDT_DES_OPMODE = "Select Operation Mode"
PDT_DES_ROTMOVAX = "Rotational Axis - Movement Axis"
PDT_DES_FLIPANG = "Flip Angle 180 degrees"
PDT_DES_FLIPPER = "Flip Percent to 100 - %"
PDT_DES_TRIM = "Trim/Extend only Active Vertex, or All"
PDT_DES_LIBOBS = "Objects in Library"
PDT_DES_LIBCOLS = "Collections in Library"
PDT_DES_LIBMATS = "Materials in Library"
PDT_DES_LIBMODE = "Library Mode"
PDT_DES_LIBSER = "Enter A Search String (Contained)"
PDT_DES_OBORDER = "Object Order to Lines"
PDT_DES_VALIDLET = "Valid 1st letters; C D E G N P S V, Valid 2nd letters: A D I O P"
PDT_DES_OUTPUT = "Output for Maths Operations"
PDT_DES_PPLOC = "Location of PivotPoint"
PDT_DES_PPSCALEFAC = "Scale Factors"
PDT_DES_PPSIZE = "Pivot Size Factor"
PDT_DES_PPWIDTH = "Pivot Line Width in Pixels"
PDT_DES_PPTRANS = "Pivot Point Transparency"
PDT_DES_PIVOTDIS = "Input Distance to Compare with Sytem Distance to set Scales"
PDT_DES_FILLETRAD = "Fillet Radius"
PDT_DES_FILLETSEG = "Number of Fillet Segments"
PDT_DES_FILLETPROF = "Fillet Profile"
PDT_DES_FILLETVERTS = "Use Vertices, or Edges, Set to False for Extruded Geometry"
PDT_DES_FILLINT = "Intersect & Fillet Two Selected Edges"

View File

@ -26,7 +26,7 @@ import bmesh
from bpy.types import Operator, SpaceView3D
from mathutils import Vector, Matrix
from math import pi
from .pdt_functions import view_coords, drawCallback3D
from .pdt_functions import view_coords, draw_callback_3d
from .pdt_msg_strings import (
PDT_CON_AREYOURSURE,
PDT_ERR_EDIT_MODE,
@ -60,7 +60,7 @@ class PDT_OT_ModalDrawOperator(bpy.types.Operator):
if PDT_OT_ModalDrawOperator._handle is None:
PDT_OT_ModalDrawOperator._handle = SpaceView3D.draw_handler_add(
drawCallback3D, (self, context), "WINDOW", "POST_VIEW"
draw_callback_3d, (self, context), "WINDOW", "POST_VIEW"
)
context.window_manager.pdt_run_opengl = True
@ -103,9 +103,8 @@ class PDT_OT_ModalDrawOperator(bpy.types.Operator):
context.area.tag_redraw()
return {"FINISHED"}
else:
self.report({"ERROR"}, PDT_ERR_NO3DVIEW)
self.report({"ERROR"}, PDT_ERR_NO3DVIEW)
return {"CANCELLED"}
@ -117,10 +116,11 @@ class PDT_OT_ViewPlaneRotate(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
return all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"])
def execute(self, context):
@ -170,10 +170,11 @@ class PDT_OT_ViewPlaneScale(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
return all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"])
def execute(self, context):
@ -205,17 +206,17 @@ class PDT_OT_ViewPlaneScale(Operator):
bm = bmesh.from_edit_mesh(obj.data)
verts = verts = [v for v in bm.verts if v.select]
for v in verts:
dx = (pg.pivot_loc.x - obj.matrix_world.decompose()[0].x - v.co.x) * (
delta_x = (pg.pivot_loc.x - obj.matrix_world.decompose()[0].x - v.co.x) * (
1 - pg.pivot_scale.x
)
dy = (pg.pivot_loc.y - obj.matrix_world.decompose()[0].y - v.co.y) * (
delta_y = (pg.pivot_loc.y - obj.matrix_world.decompose()[0].y - v.co.y) * (
1 - pg.pivot_scale.y
)
dz = (pg.pivot_loc.z - obj.matrix_world.decompose()[0].z - v.co.z) * (
delta_z = (pg.pivot_loc.z - obj.matrix_world.decompose()[0].z - v.co.z) * (
1 - pg.pivot_scale.z
)
dv = Vector((dx, dy, dz))
v.co = v.co + dv
delta_v = Vector((delta_x, delta_y, delta_z))
v.co = v.co + delta_v
bmesh.update_edit_mesh(obj.data)
return {"FINISHED"}
@ -276,10 +277,11 @@ class PDT_OT_PivotSelected(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH", ob.mode == "EDIT"])
return all([bool(obj), obj.type == "MESH", obj.mode == "EDIT"])
def execute(self, context):
@ -313,9 +315,9 @@ class PDT_OT_PivotSelected(Operator):
pg.pivot_loc = scene.cursor.location
scene.cursor.location = old_cursor_loc
return {"FINISHED"}
else:
self.report({"ERROR"}, PDT_ERR_NO_SEL_GEOM)
return {"FINISHED"}
self.report({"ERROR"}, PDT_ERR_NO_SEL_GEOM)
return {"FINISHED"}
class PDT_OT_PivotOrigin(Operator):
@ -326,10 +328,11 @@ class PDT_OT_PivotOrigin(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH"])
return all([bool(obj), obj.type == "MESH"])
def execute(self, context):
"""Moves Pivot Point to Object Origin.
@ -362,10 +365,11 @@ class PDT_OT_PivotWrite(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH"])
return all([bool(obj), obj.type == "MESH"])
def execute(self, context):
"""Writes Pivot Point Location to Object's Custom Properties.
@ -408,10 +412,11 @@ class PDT_OT_PivotRead(Operator):
@classmethod
def poll(cls, context):
ob = context.object
if ob is None:
"""Check Onject Status."""
obj = context.object
if obj is None:
return False
return all([bool(ob), ob.type == "MESH"])
return all([bool(obj), obj.type == "MESH"])
def execute(self, context):
"""Reads Pivot Point Location from Object's Custom Properties.
@ -438,6 +443,6 @@ class PDT_OT_PivotRead(Operator):
if "PDT_PP_LOC" in obj:
pg.pivot_loc = obj["PDT_PP_LOC"]
return {"FINISHED"}
else:
self.report({"ERROR"}, PDT_ERR_NOPPLOC)
return {"FINISHED"}
self.report({"ERROR"}, PDT_ERR_NOPPLOC)
return {"FINISHED"}

View File

@ -32,6 +32,8 @@ from .pdt_functions import debug, euler_to_quaternion
class PDT_OT_ViewRot(Operator):
"""Rotate View by Absolute Coordinates."""
bl_idname = "pdt.viewrot"
bl_label = "Rotate View"
bl_options = {"REGISTER", "UNDO"}
@ -58,13 +60,15 @@ class PDT_OT_ViewRot(Operator):
roll_value = euler_to_quaternion(
pg.rotation_coords.x * pi / 180,
pg.rotation_coords.y * pi / 180,
pg.rotation_coords.z * pi / 180
pg.rotation_coords.z * pi / 180,
)
context.region_data.view_rotation = roll_value
return {"FINISHED"}
class PDT_OT_vRotL(Operator):
class PDT_OT_ViewRotL(Operator):
"""Rotate View Left."""
bl_idname = "pdt.viewleft"
bl_label = "Rotate Left"
bl_options = {"REGISTER", "UNDO"}
@ -90,7 +94,9 @@ class PDT_OT_vRotL(Operator):
return {"FINISHED"}
class PDT_OT_vRotR(Operator):
class PDT_OT_ViewRotR(Operator):
"""Rotate View Right."""
bl_idname = "pdt.viewright"
bl_label = "Rotate Right"
bl_options = {"REGISTER", "UNDO"}
@ -117,7 +123,9 @@ class PDT_OT_vRotR(Operator):
return {"FINISHED"}
class PDT_OT_vRotU(Operator):
class PDT_OT_ViewRotU(Operator):
"""Rotate View Up."""
bl_idname = "pdt.viewup"
bl_label = "Rotate Up"
bl_options = {"REGISTER", "UNDO"}
@ -144,7 +152,9 @@ class PDT_OT_vRotU(Operator):
return {"FINISHED"}
class PDT_OT_vRotD(Operator):
class PDT_OT_ViewRotD(Operator):
"""Rotate View Down."""
bl_idname = "pdt.viewdown"
bl_label = "Rotate Down"
bl_options = {"REGISTER", "UNDO"}
@ -171,7 +181,9 @@ class PDT_OT_vRotD(Operator):
return {"FINISHED"}
class PDT_OT_vRoll(Operator):
class PDT_OT_ViewRoll(Operator):
"""Roll View."""
bl_idname = "pdt.viewroll"
bl_label = "Roll View"
bl_options = {"REGISTER", "UNDO"}
@ -198,7 +210,9 @@ class PDT_OT_vRoll(Operator):
return {"FINISHED"}
class PDT_OT_viso(Operator):
class PDT_OT_ViewIso(Operator):
"""Set View Isometric."""
bl_idname = "pdt.viewiso"
bl_label = "Isometric View"
bl_options = {"REGISTER", "UNDO"}
@ -216,17 +230,17 @@ class PDT_OT_viso(Operator):
Status Set.
"""
# Try working this out in your head!
context.region_data.view_rotation = Quaternion(
(0.8205, 0.4247, -0.1759, -0.3399)
)
context.region_data.view_perspective = 'ORTHO'
context.region_data.view_rotation = Quaternion((0.8205, 0.4247, -0.1759, -0.3399))
context.region_data.view_perspective = "ORTHO"
return {"FINISHED"}
class PDT_OT_Reset3DView(Operator):
"""Reset Views to Factory Default."""
bl_idname = "pdt.reset_3d_view"
bl_label = "Reset 3D View"
bl_options = {'REGISTER', 'UNDO'}
bl_options = {"REGISTER", "UNDO"}
bl_description = "Reset 3D View to Blender Defaults."
def execute(self, context):
@ -241,13 +255,15 @@ class PDT_OT_Reset3DView(Operator):
# The default view_distance to the origin when starting up Blender
default_view_distance = 17.986562728881836
default_view_distance = bpy.data.screens['Layout'].areas[-1].spaces[0].region_3d.view_distance
default_view_distance = (
bpy.data.screens["Layout"].areas[-1].spaces[0].region_3d.view_distance
)
# The default view_matrix when starting up Blender
default_view_matrix = (
(0.41, -0.4017, 0.8188, 0.0),
(0.912, 0.1936, -0.3617, 0.0),
(-0.0133, 0.8950, 0.4458, 0.0),
(0.0, 0.0, -17.9866, 1.0)
(0.0, 0.0, -17.9866, 1.0),
)
view = context.region_data
@ -270,4 +286,4 @@ class PDT_OT_Reset3DView(Operator):
view.update()
debug(f"view_matrix AFTER reset:\n{view.view_matrix}")
return {'FINISHED'}
return {"FINISHED"}

View File

@ -29,14 +29,18 @@ from mathutils.geometry import intersect_line_line as LineIntersect
import itertools
from collections import defaultdict
from . import pdt_cad_module as cm
from .pdt_functions import oops
from .pdt_msg_strings import (
PDT_ERR_EDOB_MODE
)
def order_points(edge, point_list):
"""Order these edges from distance to v1, then sandwich the sorted list with v1, v2."""
v1, v2 = edge
def dist(co):
return (v1 - co).length
def dist(coord):
return (v1 - coord).length
point_list = sorted(point_list, key=dist)
return [v1] + point_list + [v2]
@ -89,8 +93,8 @@ def get_intersection_dictionary(bm, edge_indices):
permutations = get_valid_permutations(bm, edge_indices)
k = defaultdict(list)
d = defaultdict(list)
list_k = defaultdict(list)
list_d = defaultdict(list)
for edges in permutations:
raw_vert_indices = cm.vertex_indices_from_edges_tuple(bm, edges)
@ -103,35 +107,35 @@ def get_intersection_dictionary(bm, edge_indices):
continue
# reaches this point only when an intersection happens on both edges.
[k[edge].append(points[0]) for edge in edges]
[list_k[edge].append(points[0]) for edge in edges]
# k will contain a dict of edge indices and points found on those edges.
for edge_idx, unordered_points in k.items():
for edge_idx, unordered_points in list_k.items():
tv1, tv2 = bm.edges[edge_idx].verts
v1 = bm.verts[tv1.index].co
v2 = bm.verts[tv2.index].co
ordered_points = order_points((v1, v2), unordered_points)
d[edge_idx].extend(ordered_points)
list_d[edge_idx].extend(ordered_points)
return d
return list_d
def update_mesh(bm, int_dict):
"""Make new geometry (delete old first)."""
oe = bm.edges
ov = bm.verts
orig_e = bm.edges
orig_v = bm.verts
new_verts = []
collect = new_verts.extend
for _, point_list in int_dict.items():
num_edges_to_add = len(point_list) - 1
for i in range(num_edges_to_add):
a = ov.new(point_list[i])
b = ov.new(point_list[i + 1])
oe.new((a, b))
coord_a = orig_v.new(point_list[i])
coord_b = orig_v.new(point_list[i + 1])
orig_e.new((coord_a, coord_b))
bm.normal_update()
collect([a, b])
collect([coord_a, coord_b])
bmesh.ops.delete(bm, geom=[edge for edge in bm.edges if edge.select], context="EDGES")
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.0001)
@ -178,6 +182,7 @@ def intersect_all(context):
bmesh.update_edit_mesh(obj.data)
else:
pg.error = f"{PDT_ERR_EDOB_MODE},{obj.mode})"
context.window_manager.popup_menu(oops, title="Error", icon="ERROR")
return
@ -196,10 +201,19 @@ class PDT_OT_IntersectAllEdges(bpy.types.Operator):
@classmethod
def poll(cls, context):
ob = context.active_object
if ob is None:
"""Check to see object is in correct condidtion.
Args:
Class,
context: Blender bpy.context instance.
Returns:
Boolean
"""
obj = context.active_object
if obj is None:
return False
return ob is not None and ob.type == "MESH" and ob.mode == "EDIT"
return obj is not None and obj.type == "MESH" and obj.mode == "EDIT"
def execute(self, context):
"""Computes All intersections with Crossing Geometry.