def execute(self, context): settings = get_settings() dbg = settings.debug #if bpy.context.mode != 'OBJECT': # bpy.ops.object.mode_set(mode = 'OBJECT') sce = context.scene n = sce.odc_implant_index implant_space = sce.odc_implants[n] implants = odcutils.implant_selection(context) layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] if implants != []: for implant_space in implants: #check if space already has an implant object. #if so, delete, replace, print warning if implant_space.implant and implant_space.implant in bpy.data.objects: self.report({ 'WARNING' }, "replacing the existing implant with the one you chose") Implant = bpy.data.objects[implant_space.implant] #the origin/location of the implant is it's apex L = Implant.location.copy() world_mx = Implant.matrix_world.copy() #the platorm is the length of the implant above the apex, in the local Z direction #local Z positive is out the apex, soit's negative. #Put the cursor there sce.cursor_location = L - Implant.dimensions[ 2] * world_mx.to_3x3() * Vector((0, 0, 1)) #first get rid of children...so we can use the #parent to find out who the children are if Implant.children: for child in Implant.children: sce.objects.unlink(child) child.user_clear() bpy.data.objects.remove(child) #unlink it from the scene, clear it's users, remove it. sce.objects.unlink(Implant) Implant.user_clear() #remove the object bpy.data.objects.remove(Implant) #TDOD what about the children/hardwares? else: world_mx = Matrix.Identity(4) world_mx[0][3] = sce.cursor_location[0] world_mx[1][3] = sce.cursor_location[1] world_mx[2][3] = sce.cursor_location[2] #is this more memory friendly than listing all objects? current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library odcutils.obj_from_lib(settings.imp_lib, self.imp) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Implant = ob sce.objects.link(Implant) #this relies on the associated hardware objects having the parent implant #name inside them if self.hardware: current_obs = [ob.name for ob in bpy.data.objects] inc = self.imp + '_' hardware_list = odcutils.obj_list_from_lib( settings.imp_lib, include=inc) print(hardware_list) for ob in hardware_list: odcutils.obj_from_lib(settings.imp_lib, ob) for ob in bpy.data.objects: if ob.name not in current_obs: sce.objects.link(ob) ob.parent = Implant ob.layers[11] = True delta = Implant.dimensions[2] * world_mx.to_3x3() * Vector( (0, 0, 1)) print(delta.length) world_mx[0][3] += delta[0] world_mx[1][3] += delta[1] world_mx[2][3] += delta[2] Implant.matrix_world = world_mx if sce.odc_props.master: Master = bpy.data.objects[sce.odc_props.master] odcutils.parent_in_place(Implant, Master) else: self.report({ 'WARNING' }, 'No Master Model, placing implant anyway, moving objects may not preserve spatial relationships' ) #looks a little redundant, but it ensure if any #duplicates exist our referencing stays accurate Implant.name = implant_space.name + '_' + Implant.name implant_space.implant = Implant.name odcutils.layer_management(sce.odc_implants, debug=dbg) for i, layer in enumerate(layers_copy): context.scene.layers[i] = layer context.scene.layers[11] = True return {'FINISHED'}
def execute(self, context): settings = get_settings() dbg = settings.debug #if bpy.context.mode != 'OBJECT': # bpy.ops.object.mode_set(mode = 'OBJECT') sce = context.scene implants = odcutils.implant_selection(context) layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] = True if implants != []: for implant_space in implants: #check if space already has an implant object. #if so, delete, replace, print warning Implant = bpy.data.objects[implant_space.implant] if Implant.rotation_mode != 'QUATERNION': Implant.rotation_mode = 'QUATERNION' Implant.update_tag() sce.update() if bpy.data.objects.get(implant_space.drill): self.report( {'WARNING'}, "replacing the existing drill with the one you chose") Sleeve = bpy.data.objects[implant_space.drill] #unlink it from the scene, clear it's users, remove it. sce.objects.unlink(Sleeve) Implant.user_clear() #remove the object bpy.data.objects.remove(Sleeve) current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library settings = get_settings() odcutils.obj_from_lib(settings.drill_lib, self.drill) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Sleeve = ob sce.objects.link(Sleeve) Sleeve.layers[19] = True mx_w = Implant.matrix_world.copy() #point the right direction Sleeve.rotation_mode = 'QUATERNION' Sleeve.rotation_quaternion = mx_w.to_quaternion() Sleeve.update_tag() context.scene.update() Trans = Sleeve.rotation_quaternion * Vector( (0, 0, -self.depth)) Sleeve.matrix_world[0][3] = mx_w[0][3] + Trans[0] Sleeve.matrix_world[1][3] = mx_w[1][3] + Trans[1] Sleeve.matrix_world[2][3] = mx_w[2][3] + Trans[2] Sleeve.name = implant_space.name + '_' + Sleeve.name implant_space.drill = Sleeve.name Sleeve.update_tag() context.scene.update() odcutils.parent_in_place(Sleeve, Implant) odcutils.layer_management(sce.odc_implants, debug=dbg) for i, layer in enumerate(layers_copy): context.scene.layers[i] = layer context.scene.layers[19] = True return {'FINISHED'}
def cloth_fill_main(context, loop_obj, oct, smooth, debug = False): ''' notes: make sure the user view is such that you can see the entire ring with out any corosses (knots) if calling from script not in 3dview, you can override the view args: context - blender context loop_obj: blender curve object or mesh object representing just a loop oct - octree depth for the grid to fill. smooth - iteartions to smooth the surface (soap bubble effect) return: CurveMesh : The filled looop object type Blender Object (Mesh) ''' #selection mode = verts sce = context.scene context.tool_settings.mesh_select_mode = [True,False,False] #get the space data v3d = bpy.context.space_data v3d.transform_orientation = 'GLOBAL' v3d.pivot_point = 'MEDIAN_POINT' region = v3d.region_3d vrot = region.view_rotation #this is a quat #set object mode...force selection if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = loop_obj loop_obj.select = True #change the mesh orientation to align with view..for blockout odcutils.reorient_object(loop_obj, vrot) #TODO test this sce.update() if loop_obj.type in {'CURVE','MESH'}: if loop_obj.type == 'CURVE': #check if cyclic if not loop_obj.data.splines[0].use_cyclic_u: loop_obj.data.splines[0].use_cyclic_u = True #TODO: add this over to margin #convert the curve to a mesh...so we can use it. bpy.ops.object.duplicate() bpy.ops.object.convert(target='MESH', keep_original = False) #active object is now the mesh version of the curve else: #make sure it's a loop if len(loop_obj.data.vertices) != len(loop_obj.data.edges): print('this is not a loop') return else: bpy.ops.object.duplicate() #active object is now the mesh duplicate #this will become our final cloth filled objec CurveMesh = context.object CurveMesh.name = "Cloth Tray Mesh" #do some size estimation size = max(list(CurveMesh.dimensions)) grid_predict = size * 0.9 / pow(oct,2) print("grid prediction is: " + str(grid_predict)) #make a duplicate... current_objects = list(bpy.data.objects) #remember current objects to ID new ones later bpy.ops.object.duplicate() for obj in sce.objects: if obj not in current_objects: obj.name = "cloth_temp" Temp = obj #fill the the surface of the temp bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.fill() #stretch it out a little bpy.ops.mesh.select_all(action = 'DESELECT') bpy.context.tool_settings.mesh_select_mode = [False,True,False] bpy.ops.mesh.select_non_manifold() bpy.ops.object.editmode_toggle() eds = [ed for ed in Temp.data.edges if ed.select] barrier = .05 * min(Temp.dimensions) odcutils.extrude_edges_out_view(Temp.data, eds, Temp.matrix_world, barrier/5, debug = debug) bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = [False,True,False] bpy.ops.mesh.select_non_manifold() bpy.ops.mesh.extrude_edges_move() bpy.ops.object.editmode_toggle() eds = [ed for ed in Temp.data.edges if ed.select] odcutils.extrude_edges_out_view(Temp.data, eds, Temp.matrix_world, barrier, debug = debug) bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = [True,False,False] bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') CurveMesh.select = True sce.objects.active = CurveMesh CurveMesh.rotation_mode = 'QUATERNION' #make the origin the same as the bez curve? sce.cursor_location = loop_obj.location bpy.ops.object.origin_set(type = 'ORIGIN_CURSOR') if CurveMesh.parent: Parent = CurveMesh.parent reparent = True wmx = CurveMesh.matrix_world.copy() CurveMesh.parent = None CurveMesh.matrix_world = wmx else: wmx = Matrix.Identity(4) reparent = False #unrotate it so we can make a nice remesh surface #although why this doesn't work with local coords I dunno bpy.ops.object.rotation_clear() #flatten to view...fill in the loop bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') #get the space data v3d = bpy.context.space_data v3d.transform_orientation = 'LOCAL' v3d.pivot_point = 'MEDIAN_POINT' bpy.ops.transform.resize(value=(1, 1, 0), constraint_orientation='LOCAL') bpy.ops.mesh.looptools_space() bpy.ops.mesh.fill() #add modifiers bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SOLIDIFY') bpy.ops.object.modifier_add(type='REMESH') solmod = CurveMesh.modifiers["Solidify"] solmod.thickness = grid_predict * .75 remod = CurveMesh.modifiers["Remesh"] remod.octree_depth = oct remod.scale = .9 #for some reason the modifier weren't updating bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() #problem with applying modifiers...new method. mesh = CurveMesh.to_mesh(bpy.context.scene, True, 'RENDER') new_obj = bpy.data.objects.new(CurveMesh.name, mesh) bpy.context.scene.objects.link(new_obj) new_obj.matrix_world = wmx bpy.context.scene.objects.active = new_obj CurveMesh.select = True bpy.context.scene.objects.active = CurveMesh bpy.ops.object.delete() new_obj.select = True CurveMesh = new_obj bpy.context.scene.objects.active = CurveMesh ''' bpy.ops.object.modifier_apply(modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_apply(modifier="Remesh") ''' bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action = 'DESELECT') bpy.ops.object.mode_set(mode = 'OBJECT') #make it a 2d obejct bpy.context.tool_settings.mesh_select_mode = [False,False,True] flat = False n = 0 while not flat: #hope to select a polygon not on the border CurveMesh.data.polygons[n].select = True bpy.ops.object.mode_set(mode = 'EDIT') bpy.ops.mesh.faces_select_linked_flat() bpy.ops.object.mode_set(mode = 'OBJECT') sel_faces = [poly for poly in CurveMesh.data.polygons if poly.select] if len(sel_faces) > len(CurveMesh.data.polygons)/3: flat = True if n > 100: break n+= 1 bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.delete() bpy.context.tool_settings.mesh_select_mode = [False,True,False] bpy.ops.mesh.select_loose() bpy.ops.mesh.delete(type='EDGE') bpy.ops.mesh.select_non_manifold() bpy.context.tool_settings.mesh_select_mode = [True,False,False] bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.vertices_smooth(repeat = smooth) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SHRINKWRAP') swrap = CurveMesh.modifiers["Shrinkwrap"] swrap.wrap_method = 'PROJECT' swrap.use_project_z = True swrap.use_negative_direction = True swrap.use_positive_direction = True swrap.target = Temp CurveMesh.rotation_quaternion = vrot bpy.ops.object.modifier_apply(modifier="Shrinkwrap") if reparent: CurveMesh.update_tag() sce.update() odcutils.parent_in_place(CurveMesh, Parent) bpy.ops.object.select_all(action='DESELECT') if debug < 3: Temp.select = True sce.objects.active=Temp bpy.ops.object.delete() CurveMesh.select = True sce.objects.active = CurveMesh bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') bpy.context.tool_settings.mesh_select_mode = [False,True,False] bpy.ops.mesh.select_loose() bpy.ops.mesh.delete(type='EDGE') bpy.context.tool_settings.mesh_select_mode = [True,False,False] bpy.ops.object.mode_set(mode='OBJECT') mx = CurveMesh.matrix_world sum_edges = 0 if len(CurveMesh.data.edges) != 0: for ed in CurveMesh.data.edges: v0 = CurveMesh.data.vertices[ed.vertices[0]] v1 = CurveMesh.data.vertices[ed.vertices[1]] V = mx*v1.co - mx*v0.co sum_edges += V.length avg_edge = sum_edges/len(CurveMesh.data.edges) if debug: print("average grid size: " + str(avg_edge)) return CurveMesh
def cloth_fill_main2(context, loop_obj, oct, smooth, debug = False): ''' notes: make sure the user view is such that you can see the entire ring with out any corosses (knots) if calling from script not in 3dview, you can override the view args: context - blender context loop_obj: blender curve object or mesh object representing just a loop oct - octree depth for the grid to fill. smooth - iteartions to smooth the surface (soap bubble effect) return: CurveMesh : The filled looop object type Blender Object (Mesh) ''' #selection mode = verts sce = context.scene if context.area.type != 'VIEW_3D': # Py cant access notifers for area in context.window.screen.areas: if area.type == 'VIEW_3D': # for reg in area.regions: # if reg.type == 'WINDOW': # region = reg for spc in area.spaces: if spc.type == 'VIEW_3D': v3d = spc region = spc.region_3d else: #get the space data v3d = bpy.context.space_data #v3d.transform_orientation = 'GLOBAL' #v3d.pivot_point = 'MEDIAN_POINT' region = v3d.region_3d vrot = region.view_rotation #this is a quat Z = vrot * Vector((0,0,1)) #change the mesh orientation to align with view..for blockout odcutils.reorient_object(loop_obj, vrot) #TODO test this sce.update() if loop_obj.parent: reparent = True else: reparent = False if loop_obj.type not in {'CURVE', 'MESH'}: return me = loop_obj.to_mesh(context.scene, True, 'PREVIEW') tray_bme = bmesh.new() tray_bme.from_mesh(me) tray_me = bpy.data.meshes.new('cloth tray') TrayOb = bpy.data.objects.new('Cloth Tray', tray_me) TrayOb.matrix_world = loop_obj.matrix_world #do some size estimation min_size = min(loop_obj.dimensions) size = max(list(loop_obj.dimensions)) grid_predict = size * 0.9 / pow(oct,2) print("grid prediction is: " + str(grid_predict)) #make a 2nd object to project down on... tmp_bme = bmesh.new() tmp_bme.from_mesh(me) temp_me = bpy.data.meshes.new('cloth temp') TempOb = bpy.data.objects.new('Cloth Temp', temp_me) TempOb.matrix_world = loop_obj.matrix_world context.scene.objects.link(TempOb) #fill the the surface of the temp geom = bmesh.ops.triangle_fill(tmp_bme, use_beauty = True, edges = tmp_bme.edges) tmp_bme.edges.ensure_lookup_table() tmp_bme.verts.ensure_lookup_table() #move edges outward a little perim_eds = [ed for ed in tmp_bme.edges if not ed.is_manifold] odcutils.extrude_bmesh_loop(tmp_bme, perim_eds, loop_obj.matrix_world, Z, -.001 * min_size, move_only = True) #This time add an extrusion odcutils.extrude_bmesh_loop(tmp_bme, perim_eds, loop_obj.matrix_world, Z, -.05 * min_size, move_only = False) #put the data in tmp_bme.to_mesh(TempOb.data) tmp_bme.free() #Now deal with the tray which is to be remeshed. #first, solidify all of their #flatten. Since oriented into view, this flattens it for v in tray_bme.verts: v.co[2] = 0.00 #triangle fill geom = bmesh.ops.triangle_fill(tray_bme, use_beauty = True, edges = tray_bme.edges) solid_geom = [f for f in tray_bme.faces] + [v for v in tray_bme.verts] + [ed for ed in tray_bme.edges] new_geom = bmesh.ops.solidify(tray_bme, geom = solid_geom, thickness = grid_predict * 0.75) tray_bme.to_mesh(tray_me) tray_bme.free() context.scene.objects.link(TrayOb) mod = TrayOb.modifiers.new('Remesh', type = 'REMESH') mod.octree_depth = oct mod.scale = .9 tray_bme = bmesh.new() final_me = TrayOb.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') tray_bme.from_mesh(final_me) tray_bme.verts.ensure_lookup_table() to_delete = [] for v in tray_bme.verts: if v.co[2] > .0001 or v.co[2] < -.0001: to_delete.append(v) bmesh.ops.delete(tray_bme, geom = to_delete, context = 1) TrayOb.modifiers.remove(modifier = mod) tray_bme.to_mesh(TrayOb.data) tray_bme.free() #TODOD, manually with ray cast swrap = TrayOb.modifiers.new('Shrinkwrap', type = 'SHRINKWRAP') swrap.wrap_method = 'PROJECT' swrap.use_project_z = True swrap.use_negative_direction = True swrap.use_positive_direction = True swrap.target = TempOb #tray_me = TrayOb.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') #TrayOb.data = tray_me #TrayOb.modifiers.remove(modifier = swrap) if reparent: TrayOb.update_tag() sce.update() odcutils.parent_in_place(TrayOb, loop_obj.parent) return TrayOb
def place_implant(context, implant_space, location,orientation,imp, hardware = True): ''' args: context implant_space - ODC Implant Space type location - Vector orientation - Matrix or Quaternion lib_implants - imp - string representing implant object name in link library ''' #check if space already has an implant object. #if so, delete, replace, print warning sce = context.scene if implant_space.implant and implant_space.implant in bpy.data.objects: print("replacing the existing implant with the one you chose") Implant = bpy.data.objects[implant_space.implant] #unlink it from the scene, clear it's useres, remove it. if Implant.children: for child in Implant.children: sce.objects.unlink(child) child.user_clear bpy.data.objects.remove(child) sce.objects.unlink(Implant) implant_mesh = Implant.data Implant.user_clear() #remove the object bpy.data.objects.remove(Implant) implant_mesh.user_clear() bpy.data.meshes.remove(implant_mesh) sce.update() #TDOD what about the children/hardwares? world_mx = Matrix.Identity(4) world_mx[0][3]=location[0] world_mx[1][3]=location[1] world_mx[2][3]=location[2] #mx_b = Matrix.Identity(4) #mx_l = Matrix.Identity(4) #is this more memory friendly than listing all objects? current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library settings = get_settings() odcutils.obj_from_lib(settings.imp_lib, imp) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Implant = ob sce.objects.link(Implant) #Implant.matrix_basis = mx_b Implant.matrix_world = world_mx Implant.update_tag() sce.update() Implant.rotation_mode = 'QUATERNION' Implant.rotation_quaternion = orientation sce.update() #Implant.matrix_local = mx_l #Implant.location = L if sce.odc_props.master: Master = bpy.data.objects[sce.odc_props.master] odcutils.parent_in_place(Implant, Master) else: print('No Master Model, placing implant anyway, moving objects may not preserve spatial relationships') #looks a little redundant, but it ensure if any #duplicates exist our referencing stays accurate Implant.name = implant_space.name + "_" + Implant.name implant_space.implant = Implant.name if hardware: current_obs = [ob.name for ob in bpy.data.objects] inc = imp + '_' settings = get_settings() hardware_list = odcutils.obj_list_from_lib(settings.imp_lib, include = inc) print(hardware_list) for ob in hardware_list: odcutils.obj_from_lib(settings.imp_lib,ob) for ob in bpy.data.objects: if ob.name not in current_obs: sce.objects.link(ob) ob.parent = Implant ob.layers[11] = True #TODO: put this in layer management. return Implant
def implant_inner_cylinder(context, space, thickness = None, debug = False): if debug: start_time = time.time() sce = context.scene Implant = sce.objects[space.implant] mx_w = Implant.matrix_world.copy() if thickness: D = thickness else: D = Implant.dimensions[0] #create a bmesh cylinder R = D/2 bm = odcutils.primitive_flattened_cylinder(R, R, 64, 30) if Implant.rotation_mode != 'QUATERNION': Implant.rotation_mode = 'QUATERNION' Implant.update_tag() context.scene.update() if space.inner and space.inner in bpy.data.objects: Cylinder = bpy.data.objects[space.inner] me = Cylinder.data else: me = bpy.data.meshes.new(Implant.name + '_GC') Cylinder = bpy.data.objects.new(Implant.name + '_IC', me) # Add the mesh to the scene scene = bpy.context.scene scene.objects.link(Cylinder) #point the right direction Cylinder.rotation_mode = 'QUATERNION' Cylinder.rotation_quaternion = mx_w.to_quaternion() #now we must update to propagate changes to the #world matrix. Otherwise, when we access matrix_world #it will not have the new information about scale and #rotation...and they changes will be lost when we access #the matrix to assign different values to other elements Cylinder.update_tag() context.scene.update() Trans = Implant.rotation_quaternion * Vector((0,0,- (30 + Implant.dimensions[2]))) Cylinder.matrix_world[0][3] = mx_w[0][3] + Trans[0] Cylinder.matrix_world[1][3] = mx_w[1][3] + Trans[1] Cylinder.matrix_world[2][3] = mx_w[2][3] + Trans[2] #Write the bmesh into a new mesh or replace the old mesh? bm.to_mesh(me) bm.free() Cylinder.vertex_groups.clear() Cylinder.vertex_groups.new("Project") #rodd verts added to the "Project Group" vert_inds = [v.index for v in Cylinder.data.vertices if v.index%2] Cylinder.vertex_groups["Project"].add(vert_inds, 1,'REPLACE') Cylinder.update_tag() context.scene.update() space.inner = Cylinder.name odcutils.parent_in_place(Cylinder, Implant) if debug: print('finished inner cylinder for %s in %f seconds' % (space.name, time.time() - start_time))
def implant_outer_cylinder(context, space, width, depth, trim = 0, wedge = False, wedge_pct = .7, debug = False): if debug: start_time = time.time() scene = bpy.context.scene Implant = scene.objects[space.implant] mx_w = Implant.matrix_world.copy() if Implant.rotation_mode != 'QUATERNION': Implant.rotation_mode = 'QUATERNION' Implant.update_tag() context.scene.update() R = width/2 H = .1 if wedge: bm = odcutils.primitive_wedge_cylinder(R, wedge_pct, 64, H) else: bm = odcutils.primitive_flattened_cylinder(R, R-trim, 64, H) if space.outer and space.outer in bpy.data.objects: Cylinder = bpy.data.objects[space.outer] me = Cylinder.data if len(Cylinder.modifiers): for mod in Cylinder.modifiers: Cylinder.modifiers.remove(mod) else: me = bpy.data.meshes.new(Implant.name + '_GC') Cylinder = bpy.data.objects.new(Implant.name + '_GC', me) scene.objects.link(Cylinder) name = Implant.name + '_GC' Cylinder.name = name #point the right direction Cylinder.rotation_mode = 'QUATERNION' Cylinder.rotation_quaternion = mx_w.to_quaternion() Cylinder.update_tag() context.scene.update() Trans = Implant.rotation_quaternion * Vector((0,0,-depth)) Cylinder.matrix_world[0][3] = mx_w[0][3] + Trans[0] Cylinder.matrix_world[1][3] = mx_w[1][3] + Trans[1] Cylinder.matrix_world[2][3] = mx_w[2][3] + Trans[2] bm.to_mesh(me) bm.free() #vert group Cylinder.vertex_groups.clear() Cylinder.vertex_groups.new("Project") vert_inds = [v.index for v in Cylinder.data.vertices if v.index%2] Cylinder.vertex_groups["Project"].add(vert_inds, 1,'REPLACE') Cylinder.update_tag() context.scene.update() if len(scene.odc_splints): splint = scene.odc_splints[scene.odc_splint_index] if splint.splint in bpy.data.objects: Splint = bpy.data.objects[splint.splint] mod = Cylinder.modifiers.new('Project','SHRINKWRAP') mod.wrap_method = 'PROJECT' mod.use_project_z = True mod.use_project_y = False mod.use_project_x = False mod.offset = .5 mod.target = Splint mod.vertex_group = 'Project' space.outer = Cylinder.name odcutils.parent_in_place(Cylinder, Implant) if debug: print('finished outer cylinder for %s in %f seconds' % (space.name, time.time() - start_time))
def execute(self, context): settings = get_settings() dbg = settings.debug #if bpy.context.mode != 'OBJECT': # bpy.ops.object.mode_set(mode = 'OBJECT') sce = context.scene implants = odcutils.implant_selection(context) layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] = True if implants != []: for implant_space in implants: #check if space already has an implant object. #if so, delete, replace, print warning Implant = bpy.data.objects[implant_space.implant] if Implant.rotation_mode != 'QUATERNION': Implant.rotation_mode = 'QUATERNION' Implant.update_tag() sce.update() if bpy.data.objects.get(implant_space.drill): self.report({'WARNING'}, "replacing the existing drill with the one you chose") Sleeve = bpy.data.objects[implant_space.drill] #unlink it from the scene, clear it's users, remove it. sce.objects.unlink(Sleeve) Implant.user_clear() #remove the object bpy.data.objects.remove(Sleeve) current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library settings = get_settings() odcutils.obj_from_lib(settings.drill_lib,self.drill) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Sleeve = ob sce.objects.link(Sleeve) Sleeve.layers[19] = True mx_w = Implant.matrix_world.copy() #point the right direction Sleeve.rotation_mode = 'QUATERNION' Sleeve.rotation_quaternion = mx_w.to_quaternion() Sleeve.update_tag() context.scene.update() Trans = Sleeve.rotation_quaternion * Vector((0,0,-self.depth)) Sleeve.matrix_world[0][3] = mx_w[0][3] + Trans[0] Sleeve.matrix_world[1][3] = mx_w[1][3] + Trans[1] Sleeve.matrix_world[2][3] = mx_w[2][3] + Trans[2] Sleeve.name = implant_space.name + '_' + Sleeve.name implant_space.drill = Sleeve.name Sleeve.update_tag() context.scene.update() odcutils.parent_in_place(Sleeve, Implant) odcutils.layer_management(sce.odc_implants, debug = dbg) for i, layer in enumerate(layers_copy): context.scene.layers[i] = layer context.scene.layers[19] = True return {'FINISHED'}
def execute(self, context): settings = get_settings() dbg = settings.debug #if bpy.context.mode != 'OBJECT': # bpy.ops.object.mode_set(mode = 'OBJECT') sce = context.scene n = sce.odc_implant_index implant_space = sce.odc_implants[n] implants = odcutils.implant_selection(context) layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] if implants != []: for implant_space in implants: #check if space already has an implant object. #if so, delete, replace, print warning if implant_space.implant and implant_space.implant in bpy.data.objects: self.report({'WARNING'}, "replacing the existing implant with the one you chose") Implant = bpy.data.objects[implant_space.implant] #the origin/location of the implant is it's apex L = Implant.location.copy() world_mx = Implant.matrix_world.copy() #the platorm is the length of the implant above the apex, in the local Z direction #local Z positive is out the apex, soit's negative. #Put the cursor there sce.cursor_location = L - Implant.dimensions[2] * world_mx.to_3x3() * Vector((0,0,1)) #first get rid of children...so we can use the #parent to find out who the children are if Implant.children: for child in Implant.children: sce.objects.unlink(child) child.user_clear() bpy.data.objects.remove(child) #unlink it from the scene, clear it's users, remove it. sce.objects.unlink(Implant) Implant.user_clear() #remove the object bpy.data.objects.remove(Implant) #TDOD what about the children/hardwares? else: world_mx = Matrix.Identity(4) world_mx[0][3]=sce.cursor_location[0] world_mx[1][3]=sce.cursor_location[1] world_mx[2][3]=sce.cursor_location[2] #is this more memory friendly than listing all objects? current_obs = [ob.name for ob in bpy.data.objects] #link the new implant from the library odcutils.obj_from_lib(settings.imp_lib,self.imp) #this is slightly more robust than trusting we don't have duplicate names. for ob in bpy.data.objects: if ob.name not in current_obs: Implant = ob sce.objects.link(Implant) #this relies on the associated hardware objects having the parent implant #name inside them if self.hardware: current_obs = [ob.name for ob in bpy.data.objects] inc = self.imp + '_' hardware_list = odcutils.obj_list_from_lib(settings.imp_lib, include = inc) print(hardware_list) for ob in hardware_list: odcutils.obj_from_lib(settings.imp_lib,ob) for ob in bpy.data.objects: if ob.name not in current_obs: sce.objects.link(ob) ob.parent = Implant ob.layers[11] = True delta = Implant.dimensions[2] * world_mx.to_3x3() * Vector((0,0,1)) print(delta.length) world_mx[0][3] += delta[0] world_mx[1][3] += delta[1] world_mx[2][3] += delta[2] Implant.matrix_world = world_mx if sce.odc_props.master: Master = bpy.data.objects[sce.odc_props.master] odcutils.parent_in_place(Implant, Master) else: self.report({'WARNING'}, 'No Master Model, placing implant anyway, moving objects may not preserve spatial relationships') #looks a little redundant, but it ensure if any #duplicates exist our referencing stays accurate Implant.name = implant_space.name + '_' + Implant.name implant_space.implant = Implant.name odcutils.layer_management(sce.odc_implants, debug = dbg) for i, layer in enumerate(layers_copy): context.scene.layers[i] = layer context.scene.layers[11] = True return {'FINISHED'}
def cloth_fill_main2(context, loop_obj, oct, smooth, debug=False): ''' notes: make sure the user view is such that you can see the entire ring with out any corosses (knots) if calling from script not in 3dview, you can override the view args: context - blender context loop_obj: blender curve object or mesh object representing just a loop oct - octree depth for the grid to fill. smooth - iteartions to smooth the surface (soap bubble effect) return: CurveMesh : The filled looop object type Blender Object (Mesh) ''' #selection mode = verts sce = context.scene if context.area.type != 'VIEW_3D': # Py cant access notifers for area in context.window.screen.areas: if area.type == 'VIEW_3D': # for reg in area.regions: # if reg.type == 'WINDOW': # region = reg for spc in area.spaces: if spc.type == 'VIEW_3D': v3d = spc region = spc.region_3d else: #get the space data v3d = bpy.context.space_data #v3d.transform_orientation = 'GLOBAL' #v3d.pivot_point = 'MEDIAN_POINT' region = v3d.region_3d vrot = region.view_rotation #this is a quat Z = vrot * Vector((0, 0, 1)) #change the mesh orientation to align with view..for blockout odcutils.reorient_object(loop_obj, vrot) #TODO test this sce.update() if loop_obj.parent: reparent = True else: reparent = False if loop_obj.type not in {'CURVE', 'MESH'}: return me = loop_obj.to_mesh(context.scene, True, 'PREVIEW') tray_bme = bmesh.new() tray_bme.from_mesh(me) tray_me = bpy.data.meshes.new('cloth tray') TrayOb = bpy.data.objects.new('Cloth Tray', tray_me) TrayOb.matrix_world = loop_obj.matrix_world #do some size estimation min_size = min(loop_obj.dimensions) size = max(list(loop_obj.dimensions)) grid_predict = size * 0.9 / pow(oct, 2) print("grid prediction is: " + str(grid_predict)) #make a 2nd object to project down on... tmp_bme = bmesh.new() tmp_bme.from_mesh(me) temp_me = bpy.data.meshes.new('cloth temp') TempOb = bpy.data.objects.new('Cloth Temp', temp_me) TempOb.matrix_world = loop_obj.matrix_world context.scene.objects.link(TempOb) #fill the the surface of the temp geom = bmesh.ops.triangle_fill(tmp_bme, use_beauty=True, edges=tmp_bme.edges) tmp_bme.edges.ensure_lookup_table() tmp_bme.verts.ensure_lookup_table() #move edges outward a little perim_eds = [ed for ed in tmp_bme.edges if not ed.is_manifold] odcutils.extrude_bmesh_loop(tmp_bme, perim_eds, loop_obj.matrix_world, Z, -.001 * min_size, move_only=True) #This time add an extrusion odcutils.extrude_bmesh_loop(tmp_bme, perim_eds, loop_obj.matrix_world, Z, -.05 * min_size, move_only=False) #put the data in tmp_bme.to_mesh(TempOb.data) tmp_bme.free() #Now deal with the tray which is to be remeshed. #first, solidify all of their #flatten. Since oriented into view, this flattens it for v in tray_bme.verts: v.co[2] = 0.00 #triangle fill geom = bmesh.ops.triangle_fill(tray_bme, use_beauty=True, edges=tray_bme.edges) solid_geom = [f for f in tray_bme.faces] + [v for v in tray_bme.verts] + [ ed for ed in tray_bme.edges ] new_geom = bmesh.ops.solidify(tray_bme, geom=solid_geom, thickness=grid_predict * 0.75) tray_bme.to_mesh(tray_me) tray_bme.free() context.scene.objects.link(TrayOb) mod = TrayOb.modifiers.new('Remesh', type='REMESH') mod.octree_depth = oct mod.scale = .9 tray_bme = bmesh.new() final_me = TrayOb.to_mesh(context.scene, apply_modifiers=True, settings='PREVIEW') tray_bme.from_mesh(final_me) tray_bme.verts.ensure_lookup_table() to_delete = [] for v in tray_bme.verts: if v.co[2] > .0001 or v.co[2] < -.0001: to_delete.append(v) bmesh.ops.delete(tray_bme, geom=to_delete, context=1) TrayOb.modifiers.remove(modifier=mod) tray_bme.to_mesh(TrayOb.data) tray_bme.free() #TODOD, manually with ray cast swrap = TrayOb.modifiers.new('Shrinkwrap', type='SHRINKWRAP') swrap.wrap_method = 'PROJECT' swrap.use_project_z = True swrap.use_negative_direction = True swrap.use_positive_direction = True swrap.target = TempOb #tray_me = TrayOb.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') #TrayOb.data = tray_me #TrayOb.modifiers.remove(modifier = swrap) if reparent: TrayOb.update_tag() sce.update() odcutils.parent_in_place(TrayOb, loop_obj.parent) return TrayOb
def cloth_fill_main(context, loop_obj, oct, smooth, debug=False): ''' notes: make sure the user view is such that you can see the entire ring with out any corosses (knots) if calling from script not in 3dview, you can override the view args: context - blender context loop_obj: blender curve object or mesh object representing just a loop oct - octree depth for the grid to fill. smooth - iteartions to smooth the surface (soap bubble effect) return: CurveMesh : The filled looop object type Blender Object (Mesh) ''' #selection mode = verts sce = context.scene context.tool_settings.mesh_select_mode = [True, False, False] #get the space data v3d = bpy.context.space_data v3d.transform_orientation = 'GLOBAL' v3d.pivot_point = 'MEDIAN_POINT' region = v3d.region_3d vrot = region.view_rotation #this is a quat #set object mode...force selection if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = loop_obj loop_obj.select = True #change the mesh orientation to align with view..for blockout odcutils.reorient_object(loop_obj, vrot) #TODO test this sce.update() if loop_obj.type in {'CURVE', 'MESH'}: if loop_obj.type == 'CURVE': #check if cyclic if not loop_obj.data.splines[0].use_cyclic_u: loop_obj.data.splines[ 0].use_cyclic_u = True #TODO: add this over to margin #convert the curve to a mesh...so we can use it. bpy.ops.object.duplicate() bpy.ops.object.convert(target='MESH', keep_original=False) #active object is now the mesh version of the curve else: #make sure it's a loop if len(loop_obj.data.vertices) != len(loop_obj.data.edges): print('this is not a loop') return else: bpy.ops.object.duplicate() #active object is now the mesh duplicate #this will become our final cloth filled objec CurveMesh = context.object CurveMesh.name = "Cloth Tray Mesh" #do some size estimation size = max(list(CurveMesh.dimensions)) grid_predict = size * 0.9 / pow(oct, 2) print("grid prediction is: " + str(grid_predict)) #make a duplicate... current_objects = list( bpy.data.objects) #remember current objects to ID new ones later bpy.ops.object.duplicate() for obj in sce.objects: if obj not in current_objects: obj.name = "cloth_temp" Temp = obj #fill the the surface of the temp bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.fill() #stretch it out a little bpy.ops.mesh.select_all(action='DESELECT') bpy.context.tool_settings.mesh_select_mode = [False, True, False] bpy.ops.mesh.select_non_manifold() bpy.ops.object.editmode_toggle() eds = [ed for ed in Temp.data.edges if ed.select] barrier = .05 * min(Temp.dimensions) odcutils.extrude_edges_out_view(Temp.data, eds, Temp.matrix_world, barrier / 5, debug=debug) bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = [False, True, False] bpy.ops.mesh.select_non_manifold() bpy.ops.mesh.extrude_edges_move() bpy.ops.object.editmode_toggle() eds = [ed for ed in Temp.data.edges if ed.select] odcutils.extrude_edges_out_view(Temp.data, eds, Temp.matrix_world, barrier, debug=debug) bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = [True, False, False] bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') CurveMesh.select = True sce.objects.active = CurveMesh CurveMesh.rotation_mode = 'QUATERNION' #make the origin the same as the bez curve? sce.cursor_location = loop_obj.location bpy.ops.object.origin_set(type='ORIGIN_CURSOR') if CurveMesh.parent: Parent = CurveMesh.parent reparent = True wmx = CurveMesh.matrix_world.copy() CurveMesh.parent = None CurveMesh.matrix_world = wmx else: wmx = Matrix.Identity(4) reparent = False #unrotate it so we can make a nice remesh surface #although why this doesn't work with local coords I dunno bpy.ops.object.rotation_clear() #flatten to view...fill in the loop bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') #get the space data v3d = bpy.context.space_data v3d.transform_orientation = 'LOCAL' v3d.pivot_point = 'MEDIAN_POINT' bpy.ops.transform.resize(value=(1, 1, 0), constraint_orientation='LOCAL') bpy.ops.mesh.looptools_space() bpy.ops.mesh.fill() #add modifiers bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SOLIDIFY') bpy.ops.object.modifier_add(type='REMESH') solmod = CurveMesh.modifiers["Solidify"] solmod.thickness = grid_predict * .75 remod = CurveMesh.modifiers["Remesh"] remod.octree_depth = oct remod.scale = .9 #for some reason the modifier weren't updating bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() #problem with applying modifiers...new method. mesh = CurveMesh.to_mesh(bpy.context.scene, True, 'RENDER') new_obj = bpy.data.objects.new(CurveMesh.name, mesh) bpy.context.scene.objects.link(new_obj) new_obj.matrix_world = wmx bpy.context.scene.objects.active = new_obj CurveMesh.select = True bpy.context.scene.objects.active = CurveMesh bpy.ops.object.delete() new_obj.select = True CurveMesh = new_obj bpy.context.scene.objects.active = CurveMesh ''' bpy.ops.object.modifier_apply(modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_apply(modifier="Remesh") ''' bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT') #make it a 2d obejct bpy.context.tool_settings.mesh_select_mode = [False, False, True] flat = False n = 0 while not flat: #hope to select a polygon not on the border CurveMesh.data.polygons[n].select = True bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.faces_select_linked_flat() bpy.ops.object.mode_set(mode='OBJECT') sel_faces = [poly for poly in CurveMesh.data.polygons if poly.select] if len(sel_faces) > len(CurveMesh.data.polygons) / 3: flat = True if n > 100: break n += 1 bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.delete() bpy.context.tool_settings.mesh_select_mode = [False, True, False] bpy.ops.mesh.select_loose() bpy.ops.mesh.delete(type='EDGE') bpy.ops.mesh.select_non_manifold() bpy.context.tool_settings.mesh_select_mode = [True, False, False] bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.vertices_smooth(repeat=smooth) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SHRINKWRAP') swrap = CurveMesh.modifiers["Shrinkwrap"] swrap.wrap_method = 'PROJECT' swrap.use_project_z = True swrap.use_negative_direction = True swrap.use_positive_direction = True swrap.target = Temp CurveMesh.rotation_quaternion = vrot bpy.ops.object.modifier_apply(modifier="Shrinkwrap") if reparent: CurveMesh.update_tag() sce.update() odcutils.parent_in_place(CurveMesh, Parent) bpy.ops.object.select_all(action='DESELECT') if debug < 3: Temp.select = True sce.objects.active = Temp bpy.ops.object.delete() CurveMesh.select = True sce.objects.active = CurveMesh bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') bpy.context.tool_settings.mesh_select_mode = [False, True, False] bpy.ops.mesh.select_loose() bpy.ops.mesh.delete(type='EDGE') bpy.context.tool_settings.mesh_select_mode = [True, False, False] bpy.ops.object.mode_set(mode='OBJECT') mx = CurveMesh.matrix_world sum_edges = 0 if len(CurveMesh.data.edges) != 0: for ed in CurveMesh.data.edges: v0 = CurveMesh.data.vertices[ed.vertices[0]] v1 = CurveMesh.data.vertices[ed.vertices[1]] V = mx * v1.co - mx * v0.co sum_edges += V.length avg_edge = sum_edges / len(CurveMesh.data.edges) if debug: print("average grid size: " + str(avg_edge)) return CurveMesh