Changeset View
Changeset View
Standalone View
Standalone View
object_print3d_utils/mesh_helpers.py
| Show All 26 Lines | 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' | assert obj.type == 'MESH' | ||||
| if apply_modifiers and obj.modifiers: | if apply_modifiers and obj.modifiers: | ||||
| import bpy | import bpy | ||||
| me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False) | me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_loop_triangles=False) | ||||
| bm = bmesh.new() | bm = bmesh.new() | ||||
| bm.from_mesh(me) | bm.from_mesh(me) | ||||
| bpy.data.meshes.remove(me) | bpy.data.meshes.remove(me) | ||||
| del bpy | del bpy | ||||
| else: | else: | ||||
| me = obj.data | me = obj.data | ||||
| if obj.mode == 'EDIT': | if obj.mode == 'EDIT': | ||||
| bm_orig = bmesh.from_edit_mesh(me) | bm_orig = bmesh.from_edit_mesh(me) | ||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | def bmesh_check_thick_object(obj, thickness): | ||||
| del ret | del ret | ||||
| # old edge -> new mapping | # old edge -> new mapping | ||||
| # Convert new/old map to index dict. | # Convert new/old map to index dict. | ||||
| # Create a real mesh (lame!) | # Create a real mesh (lame!) | ||||
| context = bpy.context | context = bpy.context | ||||
| scene = context.scene | scene = context.scene | ||||
| layer = context.view_layer | |||||
| layer_collection = context.layer_collection | |||||
| if layer_collection is None: | |||||
| scene_collection = scene.master_collection.collections.new("") | |||||
| layer_collection = layer.collections.link(scene_collection) | |||||
| else: | |||||
| scene_collection = layer_collection.collection | |||||
| me_tmp = bpy.data.meshes.new(name="~temp~") | me_tmp = bpy.data.meshes.new(name="~temp~") | ||||
| bm.to_mesh(me_tmp) | bm.to_mesh(me_tmp) | ||||
| # bm.free() # delay free | # bm.free() # delay free | ||||
| obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp) | obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp) | ||||
| base = scene.objects.link(obj_tmp) | # base = scene.objects.link(obj_tmp) | ||||
| scene_collection.objects.link(obj_tmp) | |||||
| # Add new object to local view layer | # Add new object to local view layer | ||||
| # XXX28 | |||||
| ''' | |||||
| v3d = None | v3d = None | ||||
| if context.space_data and context.space_data.type == 'VIEW_3D': | if context.space_data and context.space_data.type == 'VIEW_3D': | ||||
| v3d = context.space_data | v3d = context.space_data | ||||
| if v3d and v3d.local_view: | if v3d and v3d.local_view: | ||||
| base.layers_from_view(context.space_data) | base.layers_from_view(context.space_data) | ||||
| ''' | |||||
| scene.update() | scene.update() | ||||
| ray_cast = obj_tmp.ray_cast | ray_cast = obj_tmp.ray_cast | ||||
| EPS_BIAS = 0.0001 | EPS_BIAS = 0.0001 | ||||
| faces_error = set() | faces_error = set() | ||||
| bm_faces_new = bm.faces[:] | bm_faces_new = bm.faces[:] | ||||
| for f in bm_faces_new: | for f in bm_faces_new: | ||||
| no = f.normal | no = f.normal | ||||
| no_sta = no * EPS_BIAS | no_sta = no * EPS_BIAS | ||||
| no_end = no * thickness | no_end = no * thickness | ||||
| for p in bmesh_face_points_random(f, num_points=6): | for p in bmesh_face_points_random(f, num_points=6): | ||||
| # Cast the ray backwards | # Cast the ray backwards | ||||
| p_a = p - no_sta | p_a = p - no_sta | ||||
| p_b = p - no_end | p_b = p - no_end | ||||
| p_dir = p_b - p_a | p_dir = p_b - p_a | ||||
| ok, co, no, index = ray_cast(p_a, p_dir, p_dir.length) | ok, co, no, index = ray_cast(p_a, p_dir, distance=p_dir.length) | ||||
| if ok: | if ok: | ||||
| # Add the face we hit | # Add the face we hit | ||||
| for f_iter in (f, bm_faces_new[index]): | for f_iter in (f, bm_faces_new[index]): | ||||
| # if the face wasn't triangulated, just use existing | # if the face wasn't triangulated, just use existing | ||||
| f_org = face_map.get(f_iter, f_iter) | f_org = face_map.get(f_iter, f_iter) | ||||
| f_org_index = face_index_map_org[f_org] | f_org_index = face_index_map_org[f_org] | ||||
| faces_error.add(f_org_index) | faces_error.add(f_org_index) | ||||
| # finished with bm | # finished with bm | ||||
| bm.free() | bm.free() | ||||
| scene.objects.unlink(obj_tmp) | scene_collection.objects.unlink(obj_tmp) | ||||
| bpy.data.objects.remove(obj_tmp) | bpy.data.objects.remove(obj_tmp) | ||||
| bpy.data.meshes.remove(me_tmp) | bpy.data.meshes.remove(me_tmp) | ||||
| scene.update() | scene.update() | ||||
| return array.array('i', faces_error) | return array.array('i', faces_error) | ||||
| def object_merge(context, objects): | def object_merge(context, objects): | ||||
| """ | """ | ||||
| Caller must remove. | Caller must remove. | ||||
| """ | """ | ||||
| import bpy | import bpy | ||||
| def cd_remove_all_but_active(seq): | def cd_remove_all_but_active(seq): | ||||
| tot = len(seq) | tot = len(seq) | ||||
| if tot > 1: | if tot > 1: | ||||
| act = seq.active_index | act = seq.active_index | ||||
| for i in range(tot - 1, -1, -1): | for i in range(tot - 1, -1, -1): | ||||
| if i != act: | if i != act: | ||||
| seq.remove(seq[i]) | seq.remove(seq[i]) | ||||
| scene = context.scene | scene = context.scene | ||||
| layer = context.view_layer | |||||
| layer_collection = context.layer_collection | |||||
| if layer_collection is None: | |||||
| scene_collection = scene.master_collection.collections.new("") | |||||
| layer_collection = layer.collections.link(scene_collection) | |||||
| else: | |||||
| scene_collection = layer_collection.collection | |||||
| # deselect all | # deselect all | ||||
| for obj in scene.objects: | for obj in scene.objects: | ||||
| obj.select = False | obj.select_set('DESELECT') | ||||
| # add empty object | # add empty object | ||||
| mesh_base = bpy.data.meshes.new(name="~tmp~") | mesh_base = bpy.data.meshes.new(name="~tmp~") | ||||
| obj_base = bpy.data.objects.new(name="~tmp~", object_data=mesh_base) | obj_base = bpy.data.objects.new(name="~tmp~", object_data=mesh_base) | ||||
| base_base = scene.objects.link(obj_base) | scene_collection.objects.link(obj_base) | ||||
| scene.objects.active = obj_base | layer.objects.active = obj_base | ||||
| obj_base.select = True | obj_base.select_set('SELECT') | ||||
| # loop over all meshes | # loop over all meshes | ||||
| for obj in objects: | for obj in objects: | ||||
| if obj.type != 'MESH': | if obj.type != 'MESH': | ||||
| continue | continue | ||||
| # convert each to a mesh | # convert each to a mesh | ||||
| mesh_new = obj.to_mesh(scene=scene, | mesh_new = obj.to_mesh( | ||||
| depsgraph=context.depsgraph, | |||||
| apply_modifiers=True, | apply_modifiers=True, | ||||
| settings='PREVIEW', | calc_loop_triangles=False, | ||||
| calc_tessface=False) | ) | ||||
| # remove non-active uvs/vcols | # remove non-active uvs/vcols | ||||
| cd_remove_all_but_active(mesh_new.vertex_colors) | cd_remove_all_but_active(mesh_new.vertex_colors) | ||||
| cd_remove_all_but_active(mesh_new.uv_textures) | cd_remove_all_but_active(mesh_new.uv_layers) | ||||
| # join into base mesh | # join into base mesh | ||||
| obj_new = bpy.data.objects.new(name="~tmp-new~", object_data=mesh_new) | obj_new = bpy.data.objects.new(name="~tmp-new~", object_data=mesh_new) | ||||
| base_new = scene.objects.link(obj_new) | base_new = scene_collection.objects.link(obj_new) | ||||
| obj_new.matrix_world = obj.matrix_world | obj_new.matrix_world = obj.matrix_world | ||||
| fake_context = context.copy() | fake_context = context.copy() | ||||
| fake_context["active_object"] = obj_base | fake_context["active_object"] = obj_base | ||||
| fake_context["selected_editable_bases"] = [base_base, base_new] | fake_context["selected_editable_objects"] = [obj_base, obj_new] | ||||
| bpy.ops.object.join(fake_context) | bpy.ops.object.join(fake_context) | ||||
| del base_new, obj_new | del base_new, obj_new | ||||
| # remove object and its mesh, join does this | # remove object and its mesh, join does this | ||||
| # scene.objects.unlink(obj_new) | # scene_collection.objects.unlink(obj_new) | ||||
| # bpy.data.objects.remove(obj_new) | # bpy.data.objects.remove(obj_new) | ||||
| bpy.data.meshes.remove(mesh_new) | bpy.data.meshes.remove(mesh_new) | ||||
| scene.update() | scene.update() | ||||
| # return new object | # return new object | ||||
| return base_base | return obj_base | ||||
| def face_is_distorted(ele, angle_distort): | def face_is_distorted(ele, angle_distort): | ||||
| no = ele.normal | no = ele.normal | ||||
| angle_fn = no.angle | angle_fn = no.angle | ||||
| for loop in ele.loops: | for loop in ele.loops: | ||||
| loopno = loop.calc_normal() | loopno = loop.calc_normal() | ||||
| if loopno.dot(no) < 0.0: | if loopno.dot(no) < 0.0: | ||||
| loopno.negate() | loopno.negate() | ||||
| if angle_fn(loopno, 1000.0) > angle_distort: | if angle_fn(loopno, 1000.0) > angle_distort: | ||||
| return True | return True | ||||
| return False | return False | ||||