Print3D: PEP8 cleanup

This commit is contained in:
Mikhail Rachinskiy
2019-09-18 17:14:08 +04:00
parent 11fdc251a1
commit 9f7b301a9b
5 changed files with 135 additions and 172 deletions

View File

@ -22,13 +22,13 @@ bl_info = {
"name": "3D Print Toolbox",
"author": "Campbell Barton",
"blender": (2, 80, 0),
"location": "3D View > Toolbox",
"location": "3D View > Sidebar",
"description": "Utilities for 3D printing",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Modeling/PrintToolbox",
# TODO
# "wiki_url": "",
"support": 'OFFICIAL',
"category": "Mesh",
}
}
if "bpy" in locals():
@ -40,22 +40,19 @@ else:
import math
import bpy
from bpy.types import PropertyGroup
from bpy.props import (
StringProperty,
BoolProperty,
FloatProperty,
EnumProperty,
PointerProperty,
)
from bpy.types import (
AddonPreferences,
PropertyGroup,
)
StringProperty,
BoolProperty,
FloatProperty,
EnumProperty,
PointerProperty,
)
from . import (
ui,
operators,
)
ui,
operators,
)
class Print3D_Scene_Props(PropertyGroup):
@ -122,12 +119,13 @@ class Print3D_Scene_Props(PropertyGroup):
classes = (
Print3D_Scene_Props,
ui.VIEW3D_PT_Print3D_Object,
ui.VIEW3D_PT_Print3D_Mesh,
operators.MESH_OT_Print3D_Info_Volume,
operators.MESH_OT_Print3D_Info_Area,
operators.MESH_OT_Print3D_Check_Degenerate,
operators.MESH_OT_Print3D_Check_Distorted,
operators.MESH_OT_Print3D_Check_Solid,
@ -136,20 +134,14 @@ classes = (
operators.MESH_OT_Print3D_Check_Sharp,
operators.MESH_OT_Print3D_Check_Overhang,
operators.MESH_OT_Print3D_Check_All,
operators.MESH_OT_Print3D_Clean_Isolated,
operators.MESH_OT_Print3D_Clean_Distorted,
# operators.MESH_OT_Print3D_Clean_Thin,
operators.MESH_OT_Print3D_Clean_Non_Manifold,
operators.MESH_OT_Print3D_Select_Report,
operators.MESH_OT_Print3D_Scale_To_Volume,
operators.MESH_OT_Print3D_Scale_To_Bounds,
operators.MESH_OT_Print3D_Export,
Print3D_Scene_Props,
)

View File

@ -65,7 +65,6 @@ def write_mesh(context, info, report_cb):
path_mode = 'COPY' if print_3d.use_export_texture else 'AUTO'
context_override = context.copy()
obj_tmp = None
# PLY can only export single mesh objects!
@ -90,6 +89,7 @@ def write_mesh(context, info, report_cb):
name = os.path.splitext(name)[0]
else:
name = "untitled"
# add object name
name += "-%s" % bpy.path.clean_name(obj.name)
@ -118,55 +118,55 @@ def write_mesh(context, info, report_cb):
addon_ensure("io_mesh_stl")
filepath = bpy.path.ensure_ext(filepath, ".stl")
ret = bpy.ops.export_mesh.stl(
context_override,
filepath=filepath,
ascii=False,
use_mesh_modifiers=True,
use_selection=True,
global_scale=global_scale,
)
context_override,
filepath=filepath,
ascii=False,
use_mesh_modifiers=True,
use_selection=True,
global_scale=global_scale,
)
elif export_format == 'PLY':
addon_ensure("io_mesh_ply")
filepath = bpy.path.ensure_ext(filepath, ".ply")
ret = bpy.ops.export_mesh.ply(
context_override,
filepath=filepath,
use_mesh_modifiers=True,
global_scale=global_scale,
)
context_override,
filepath=filepath,
use_mesh_modifiers=True,
global_scale=global_scale,
)
elif export_format == 'X3D':
addon_ensure("io_scene_x3d")
filepath = bpy.path.ensure_ext(filepath, ".x3d")
ret = bpy.ops.export_scene.x3d(
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
elif export_format == 'WRL':
addon_ensure("io_scene_vrml2")
filepath = bpy.path.ensure_ext(filepath, ".wrl")
ret = bpy.ops.export_scene.vrml2(
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
elif export_format == 'OBJ':
addon_ensure("io_scene_obj")
filepath = bpy.path.ensure_ext(filepath, ".obj")
ret = bpy.ops.export_scene.obj(
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
context_override,
filepath=filepath,
use_mesh_modifiers=True,
use_selection=True,
path_mode=path_mode,
global_scale=global_scale,
)
else:
assert 0
@ -186,6 +186,7 @@ def write_mesh(context, info, report_cb):
# restore context
for ob in context_backup["selected_objects"]:
ob.select_set(True)
layer.objects.active = context_backup["active_object"]
if 'FINISHED' in ret:

View File

@ -24,9 +24,7 @@ import bmesh
def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
"""
Returns a transformed, triangulated copy of the mesh
"""
"""Returns a transformed, triangulated copy of the mesh"""
assert obj.type == 'MESH'
@ -61,47 +59,39 @@ def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifier
def bmesh_from_object(obj):
"""
Object/Edit Mode get mesh, use bmesh_to_object() to write back.
"""
"""Object/Edit Mode get mesh, use bmesh_to_object() to write back."""
me = obj.data
is_editmode = (obj.mode == 'EDIT')
if is_editmode:
if obj.mode == 'EDIT':
bm = bmesh.from_edit_mesh(me)
else:
bm = bmesh.new()
bm.from_mesh(me)
return bm
def bmesh_to_object(obj, bm):
"""
Object/Edit Mode update the object.
"""
"""Object/Edit Mode update the object."""
me = obj.data
is_editmode = (obj.mode == 'EDIT')
if is_editmode:
if obj.mode == 'EDIT':
bmesh.update_edit_mesh(me, True)
else:
bm.to_mesh(me)
# grr... cause an update
if me.vertices:
me.vertices[0].co[0] = me.vertices[0].co[0]
def bmesh_calc_area(bm):
"""
Calculate the surface area.
"""
"""Calculate the surface area."""
return sum(f.calc_area() for f in bm.faces)
def bmesh_check_self_intersect_object(obj):
"""
Check if any faces self intersect
returns an array of edge index values.
"""
"""Check if any faces self intersect returns an array of edge index values."""
import array
import mathutils
@ -147,6 +137,7 @@ def bmesh_check_thick_object(obj, thickness):
# Triangulate
bm = bmesh_copy_from_object(obj, transform=True, triangulate=False)
# map original faces to their index.
face_index_map_org = {f: i for i, f in enumerate(bm.faces)}
ret = bmesh.ops.triangulate(bm, faces=bm.faces)
@ -166,27 +157,14 @@ def bmesh_check_thick_object(obj, thickness):
bm.to_mesh(me_tmp)
# bm.free() # delay free
obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp)
# base = scene.objects.link(obj_tmp)
scene_collection.objects.link(obj_tmp)
# Add new object to local view layer
# XXX28
'''
v3d = None
if context.space_data and context.space_data.type == 'VIEW_3D':
v3d = context.space_data
if v3d and v3d.local_view:
base.layers_from_view(context.space_data)
'''
layer.update()
ray_cast = obj_tmp.ray_cast
EPS_BIAS = 0.0001
faces_error = set()
bm_faces_new = bm.faces[:]
for f in bm_faces_new:
@ -209,8 +187,7 @@ def bmesh_check_thick_object(obj, thickness):
f_org_index = face_index_map_org[f_org]
faces_error.add(f_org_index)
# finished with bm
bm.free()
bm.free() # finished with bm
scene_collection.objects.unlink(obj_tmp)
bpy.data.objects.remove(obj_tmp)
@ -222,9 +199,7 @@ def bmesh_check_thick_object(obj, thickness):
def object_merge(context, objects):
"""
Caller must remove.
"""
"""Caller must remove."""
import bpy
@ -279,10 +254,6 @@ def object_merge(context, objects):
bpy.ops.object.join(fake_context)
del base_new, obj_new
# remove object and its mesh, join does this
# scene_collection.objects.unlink(obj_new)
# bpy.data.objects.remove(obj_new)
obj_eval.to_mesh_clear()
layer.update()
@ -291,7 +262,6 @@ def object_merge(context, objects):
return obj_base
def face_is_distorted(ele, angle_distort):
no = ele.normal
angle_fn = no.angle

View File

@ -213,12 +213,11 @@ class MESH_OT_Print3D_Check_Distorted(Operator):
bm.normal_update()
faces_distort = array.array(
'i',
(i for i, ele in enumerate(bm.faces) if mesh_helpers.face_is_distorted(ele, angle_distort))
)
'i',
(i for i, ele in enumerate(bm.faces) if mesh_helpers.face_is_distorted(ele, angle_distort))
)
info.append(("Non-Flat Faces: %d" % len(faces_distort),
(bmesh.types.BMFace, faces_distort)))
info.append(("Non-Flat Faces: %d" % len(faces_distort), (bmesh.types.BMFace, faces_distort)))
bm.free()
@ -238,9 +237,7 @@ class MESH_OT_Print3D_Check_Thick(Operator):
print_3d = scene.print_3d
faces_error = mesh_helpers.bmesh_check_thick_object(obj, print_3d.thickness_min)
info.append(("Thin Faces: %d" % len(faces_error),
(bmesh.types.BMFace, faces_error)))
info.append(("Thin Faces: %d" % len(faces_error), (bmesh.types.BMFace, faces_error)))
def execute(self, context):
return execute_check(self, context)
@ -260,11 +257,12 @@ class MESH_OT_Print3D_Check_Sharp(Operator):
bm = mesh_helpers.bmesh_copy_from_object(obj, transform=True, triangulate=False)
bm.normal_update()
edges_sharp = [ele.index for ele in bm.edges
if ele.is_manifold and ele.calc_face_angle_signed() > angle_sharp]
edges_sharp = [
ele.index for ele in bm.edges
if ele.is_manifold and ele.calc_face_angle_signed() > angle_sharp
]
info.append(("Sharp Edge: %d" % len(edges_sharp),
(bmesh.types.BMEdge, edges_sharp)))
info.append(("Sharp Edge: %d" % len(edges_sharp), (bmesh.types.BMEdge, edges_sharp)))
bm.free()
def execute(self, context):
@ -296,11 +294,12 @@ class MESH_OT_Print3D_Check_Overhang(Operator):
z_down_angle = z_down.angle
# 4.0 ignores zero area faces
faces_overhang = [ele.index for ele in bm.faces
if z_down_angle(ele.normal, 4.0) < angle_overhang]
faces_overhang = [
ele.index for ele in bm.faces
if z_down_angle(ele.normal, 4.0) < angle_overhang
]
info.append(("Overhang Face: %d" % len(faces_overhang),
(bmesh.types.BMFace, faces_overhang)))
info.append(("Overhang Face: %d" % len(faces_overhang), (bmesh.types.BMFace, faces_overhang)))
bm.free()
def execute(self, context):
@ -320,7 +319,7 @@ class MESH_OT_Print3D_Check_All(Operator):
MESH_OT_Print3D_Check_Thick,
MESH_OT_Print3D_Check_Sharp,
MESH_OT_Print3D_Check_Overhang,
)
)
def execute(self, context):
obj = context.active_object
@ -368,8 +367,7 @@ class MESH_OT_Print3D_Clean_Isolated(Operator):
for ele in elems_remove:
remove(ele)
change |= bool(elems_remove)
info.append(("Faces Removed: %d" % len(elems_remove),
None))
info.append(("Faces Removed: %d" % len(elems_remove), None))
del elems_remove
# --- edge
elems_remove = [ele for ele in bm.edges if edge_is_isolated(ele)]
@ -377,8 +375,7 @@ class MESH_OT_Print3D_Clean_Isolated(Operator):
for ele in elems_remove:
remove(ele)
change |= bool(elems_remove)
info.append(("Edge Removed: %d" % len(elems_remove),
None))
info.append(("Edge Removed: %d" % len(elems_remove), None))
del elems_remove
# --- vert
elems_remove = [ele for ele in bm.verts if vert_is_isolated(ele)]
@ -386,8 +383,7 @@ class MESH_OT_Print3D_Clean_Isolated(Operator):
for ele in elems_remove:
remove(ele)
change |= bool(elems_remove)
info.append(("Verts Removed: %d" % len(elems_remove),
None))
info.append(("Verts Removed: %d" % len(elems_remove), None))
del elems_remove
# ---
@ -463,12 +459,14 @@ class MESH_OT_Print3D_Clean_Non_Manifold(Operator):
bpy.ops.object.mode_set(mode='OBJECT')
self.report(
{'INFO'},
"Modified Verts:%+d, Edges:%+d, Faces:%+d" %
(bm_key[0] - bm_key_orig[0],
bm_key[1] - bm_key_orig[1],
bm_key[2] - bm_key_orig[2],
))
{'INFO'},
"Modified Verts:%+d, Edges:%+d, Faces:%+d" %
(
bm_key[0] - bm_key_orig[0],
bm_key[1] - bm_key_orig[1],
bm_key[2] - bm_key_orig[2],
)
)
return {'FINISHED'}
@ -522,7 +520,6 @@ class MESH_OT_Print3D_Clean_Non_Manifold(Operator):
while True:
cls.fill_non_manifold(sides)
cls.delete_newly_generated_non_manifold_verts()
bm_key = cls.elem_count(context)
@ -533,30 +530,26 @@ class MESH_OT_Print3D_Clean_Non_Manifold(Operator):
@staticmethod
def select_non_manifold_verts(
use_wire=False,
use_boundary=False,
use_multi_face=False,
use_non_contiguous=False,
use_verts=False,
):
use_wire=False,
use_boundary=False,
use_multi_face=False,
use_non_contiguous=False,
use_verts=False
):
"""select non-manifold vertices"""
bpy.ops.mesh.select_non_manifold(
extend=False,
use_wire=use_wire,
use_boundary=use_boundary,
use_multi_face=use_multi_face,
use_non_contiguous=use_non_contiguous,
use_verts=use_verts,
)
extend=False,
use_wire=use_wire,
use_boundary=use_boundary,
use_multi_face=use_multi_face,
use_non_contiguous=use_non_contiguous,
use_verts=use_verts,
)
@classmethod
def count_non_manifold_verts(cls, context):
"""return a set of coordinates of non-manifold vertices"""
cls.select_non_manifold_verts(
use_wire=True,
use_boundary=True,
use_verts=True,
)
cls.select_non_manifold_verts(use_wire=True, use_boundary=True, use_verts=True)
bm = bmesh.from_edit_mesh(context.edit_object.data)
return sum((1 for v in bm.verts if v.select))
@ -606,13 +599,13 @@ class MESH_OT_Print3D_Select_Report(Operator):
bmesh.types.BMVert: 'VERT',
bmesh.types.BMEdge: 'EDGE',
bmesh.types.BMFace: 'FACE',
}
}
_type_to_attr = {
bmesh.types.BMVert: "verts",
bmesh.types.BMEdge: "edges",
bmesh.types.BMFace: "faces",
}
}
def execute(self, context):
obj = context.edit_object
@ -689,8 +682,7 @@ class MESH_OT_Print3D_Scale_To_Volume(Operator):
if context.mode == 'EDIT_MESH':
volume = calc_volume(context.edit_object)
else:
volume = sum(calc_volume(obj) for obj in context.selected_editable_objects
if obj.type == 'MESH')
volume = sum(calc_volume(obj) for obj in context.selected_editable_objects if obj.type == 'MESH')
if volume == 0.0:
self.report({'WARNING'}, "Object has zero volume")
@ -717,14 +709,17 @@ class MESH_OT_Print3D_Scale_To_Bounds(Operator):
length: FloatProperty(
name="Length Limit",
unit='LENGTH',
min=0.0, max=100000.0,
min=0.0,
max=100000.0,
)
def execute(self, context):
scale = self.length / self.length_init
_scale(scale,
report=self.report,
report_suffix=", Clamping %s-Axis" % "XYZ"[self.axis_init])
_scale(
scale,
report=self.report,
report_suffix=", Clamping %s-Axis" % "XYZ"[self.axis_init]
)
return {'FINISHED'}
def invoke(self, context, event):
@ -734,13 +729,17 @@ class MESH_OT_Print3D_Scale_To_Bounds(Operator):
return max(((max(v[i] for v in vecs) - min(v[i] for v in vecs)), i) for i in range(3))
if context.mode == 'EDIT_MESH':
length, axis = calc_length([Vector(v) @ obj.matrix_world
for obj in [context.edit_object]
for v in obj.bound_box])
length, axis = calc_length(
[Vector(v) @ obj.matrix_world for obj in [context.edit_object] for v in obj.bound_box]
)
else:
length, axis = calc_length([Vector(v) @ obj.matrix_world
for obj in context.selected_editable_objects
if obj.type == 'MESH' for v in obj.bound_box])
length, axis = calc_length(
[
Vector(v) @ obj.matrix_world for obj in context.selected_editable_objects
if obj.type == 'MESH'
for v in obj.bound_box
]
)
if length == 0.0:
self.report({'WARNING'}, "Object has zero bounds")
@ -770,5 +769,5 @@ class MESH_OT_Print3D_Export(Operator):
if ret:
return {'FINISHED'}
else:
return {'CANCELLED'}
return {'CANCELLED'}

View File

@ -35,7 +35,7 @@ class Print3D_ToolBar:
bmesh.types.BMVert: 'VERTEXSEL',
bmesh.types.BMEdge: 'EDGESEL',
bmesh.types.BMFace: 'FACESEL',
}
}
@classmethod
def poll(cls, context):
@ -52,18 +52,19 @@ class Print3D_ToolBar:
layout.label(text="Output:")
box = layout.box()
col = box.column(align=False)
# box.alert = True
for i, (text, data) in enumerate(info):
if obj and data and data[1]:
bm_type, bm_array = data
col.operator("mesh.print3d_select_report",
text=text,
icon=Print3D_ToolBar._type_to_icon[bm_type]).index = i
col.operator(
"mesh.print3d_select_report",
text=text,
icon=Print3D_ToolBar._type_to_icon[bm_type],
).index = i
layout.operator("mesh.select_non_manifold", text='Non Manifold Extended')
else:
col.label(text=text)
def draw(self, context):
layout = self.layout