def execute(self, context): keywords = self.as_keywords(ignore=("axis_forward", "axis_up", "use_selection", "global_scale", "check_existing", "filter_glob", "use_scene_unit", "use_mesh_modifiers", "batch_mode" )) scene = context.scene Block = bpy.data.objects.get('Templates Base') if not Block: self.report({'ERROR'}, 'You have not created your block yet') return {'CANCEL'} #TODO, maybe give option to export the sweep surface or convex surface data_seq = [Block] # Take into account scene's unit scale, so that 1 inch in Blender gives 1 inch elsewhere! See T42000. global_scale = self.global_scale if scene.unit_settings.system != 'NONE' and self.use_scene_unit: global_scale *= scene.unit_settings.scale_length global_matrix = axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up, ).to_4x4() * Matrix.Scale(global_scale, 4) if self.batch_mode == 'OFF': faces = itertools.chain.from_iterable( blender_utils.faces_from_mesh(ob, global_matrix, self.use_mesh_modifiers) for ob in data_seq) stl_utils.write_stl(faces=faces, **keywords) elif self.batch_mode == 'OBJECT': prefix = os.path.splitext(self.filepath)[0] keywords_temp = keywords.copy() for ob in data_seq: faces = blender_utils.faces_from_mesh(ob, global_matrix, self.use_mesh_modifiers) keywords_temp["filepath"] = prefix + bpy.path.clean_name(ob.name) + ".stl" stl_utils.write_stl(faces=faces, **keywords_temp) filename = os.path.basename(self.filepath).split('.')[0] tracking.trackUsage("apgExportBlock", param = filename) return {'FINISHED'}
def execute(self, context): tracking.trackUsage("D3Splint:StopFunctionalSurface", None) print('removing the handler') handlers = [ hand.__name__ for hand in bpy.app.handlers.frame_change_pre ] if occlusal_surface_frame_change.__name__ in handlers: bpy.app.handlers.frame_change_pre.remove( occlusal_surface_frame_change) else: print('alrady removed') return {'FINISHED'}
def execute(self, context): n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] prefs = get_settings() start = time.time() Shell = bpy.data.objects.get('Final Splint') if Shell == None: self.report({'ERROR'}, 'Need to calculate the finalize the splint first') return {'CANCELLED'} bme = bmesh.new() bme.from_object(Shell, context.scene) bme.verts.ensure_lookup_table() bme.edges.ensure_lookup_table() bme.faces.ensure_lookup_table() islands = bmesh_loose_parts(bme, selected_faces = None, max_iters = 100) if len(islands) == 1: print('there is only one solid part') Shell.modifiers.clear() bme.to_mesh(Shell.data) bme.free() return {'FINISHED'} best_island = max(islands, key = len) to_keep = set(best_island) total_faces = set(bme.faces[:]) del_faces = total_faces - to_keep bmesh.ops.delete(bme, geom = list(del_faces), context = 3) del_verts = [] #There has GOT to be a smarter way. Maybe by iterating over del_faces? for v in bme.verts: if all([f in del_faces for f in v.link_faces]): del_verts += [v] bmesh.ops.delete(bme, geom = del_verts, context = 1) del_edges = [] for ed in bme.edges: if len(ed.link_faces) == 0: del_edges += [ed] bmesh.ops.delete(bme, geom = del_edges, context = 4) Shell.modifiers.clear() bme.to_mesh(Shell.data) bme.free() finish = time.time() print('took %f seconds to clean islands' % (finish - start)) completion_time = time.time() - start print('Applied all modifiers and removed islands in %f seconds' % completion_time) tracking.trackUsage("D3Splint:RemoveIslands",str(completion_time)[0:4]) return {'FINISHED'}
def execute(self, context): n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] prefs = get_settings() if not prefs.non_clinical_use: self.report({'ERROR'}, 'You must certify non-clinical use in your addon preferences or in the panel') return {'CANCELLED'} if splint.finalize_splint: self.report({'WARNING'}, 'You have already finalized, this will remove or alter existing modifiers and try again') if splint.workflow_type != 'BITE_POSITIONER': self.report({'ERROR'}, 'This splint is not a bite positioner workflow, change it to use this function') return {'CANCELLED'} Shell = bpy.data.objects.get('Splint Shell') Maxilla = bpy.data.objects.get(splint.get_maxilla()) Mandible = bpy.data.objects.get(splint.get_mandible()) if Shell == None: self.report({'ERROR'}, 'Need to calculate the bite wafer first') return {'CANCELLED'} if Maxilla == None: self.report({'ERROR'}, 'Need to mark the maxillary modelfirst') return {'CANCELLED'} if Mandible == None: self.report({'ERROR'}, 'Need to mark the mandible first') return {'CANCELLED'} if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode = 'OBJECT') start = time.time() #don't add multiple boolean modifiers if 'Final Splint' not in bpy.data.objects: me = Shell.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') ob = bpy.data.objects.new('Final Splint', me) context.scene.objects.link(ob) ob.matrix_world = Shell.matrix_world else: ob = bpy.data.objects.get('Final Splint') me = ob.data #Blockout Wax Needs a union modifier if 'Subtract Mandible' in ob.modifiers: mod = ob.modifiers.get('Subtract Mandible') mod.object = Mandible mod.operation = 'DIFFERENCE' mod.solver = self.solver else: mod = ob.modifiers.new('Subtract Mandible', type = 'BOOLEAN') mod.object = Mandible mod.operation = 'DIFFERENCE' mod.solver = self.solver if 'Subtract Maxilla' in ob.modifiers: mod = ob.modifiers.get('Subtract Maxilla') mod.object = Maxilla mod.operation = 'DIFFERENCE' mod.solver = self.solver else: mod = ob.modifiers.new('Subtract Maxilla', type = 'BOOLEAN') mod.object = Maxilla mod.operation = 'DIFFERENCE' mod.solver = self.solver for obj in context.scene.objects: obj.hide = True context.scene.objects.active = ob ob.select = True ob.hide = False completion_time = time.time() - start print('competed the boolean subtraction in %f seconds' % completion_time) splint.finalize_splint = True tracking.trackUsage("D3Splint:FinishBiteBoolean",(self.solver, str(completion_time)[0:4])) return {'FINISHED'}
def execute(self, context): n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] prefs = get_settings() if not prefs.non_clinical_use: self.report({'ERROR'}, 'You must certify non-clinical use in your addon preferences or in the panel') return {'CANCELLED'} if splint.finalize_splint: self.report({'WARNING'}, 'You have already finalized, this will remove or alter existing modifiers and try again') if self.solver == 'CORK': self.report({'ERROR'}, 'The Cork engine has not been set up with this new method') return {'CANCELLED'} Shell = bpy.data.objects.get('Splint Shell') Refractory = bpy.data.objects.get('Refractory Model') if Shell == None: self.report({'ERROR'}, 'Need to calculate splint shell first') return {'CANCELLED'} if Refractory == None: self.report({'ERROR'}, 'Need to make refractory model first') return {'CANCELLED'} if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode = 'OBJECT') start = time.time() #don't add multiple boolean modifiers if 'Final Splint' not in bpy.data.objects: me = Shell.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') ob = bpy.data.objects.new('Final Splint', me) context.scene.objects.link(ob) ob.matrix_world = Shell.matrix_world else: ob = bpy.data.objects.get('Final Splint') me = ob.data a_base = bpy.data.objects.get('Auto Base') if 'Trim Base' in ob.modifiers and a_base != None: mod = ob.modifiers.get('Trim Base') mod.object = a_base mod.operation = 'DIFFERENCE' mod.solver = self.solver else: mod = ob.modifiers.new('Trim Base', type = 'BOOLEAN') mod.object = a_base mod.operation = 'DIFFERENCE' mod.solver = self.solver #Final Spint need only 1 boolean operation if 'Refractory Model' in ob.modifiers: mod = ob.modifiers.get('Passive Spacer') else: mod = ob.modifiers.new('Refractory Model', type = 'BOOLEAN') mod.object = Refractory mod.operation = 'DIFFERENCE' mod.solver = self.solver for obj in context.scene.objects: obj.hide = True context.scene.objects.active = ob ob.select = True ob.hide = False ob.update_tag() context.scene.update() completion_time = time.time() - start print('competed the boolean subtraction in %f seconds' % completion_time) splint.finalize_splint = True splint.ops_string += 'Finalize Splint:' tracking.trackUsage("D3Splint:FinishBoolean3",(self.solver, str(completion_time)[0:4])) tmodel = bpy.data.objects.get('Trimmed_Model') #make sure user can verify no intersections if tmodel: tmodel.hide = False context.space_data.show_backface_culling = False return {'FINISHED'}
def execute(self, context): n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] prefs = get_settings() if not prefs.non_clinical_use: self.report({'ERROR'}, 'You must certify non-clinical use in your addon preferences or in the panel') return {'CANCELLED'} if splint.finalize_splint: self.report({'WARNING'}, 'You have already finalized, this will remove or alter existing modifiers and try again') Shell = bpy.data.objects.get('Splint Shell') Passive = bpy.data.objects.get('Passive Spacer') Blockout = bpy.data.objects.get('Blockout Wax') if Shell == None: self.report({'ERROR'}, 'Need to calculate splint shell first') return {'CANCELLED'} if Passive == None: self.report({'ERROR'}, 'Need to make passive spacer first') return {'CANCELLED'} if Blockout == None and self.use_blockout == True: self.report({'ERROR'}, 'Need to blockout trimmed model first') return {'CANCELLED'} if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode = 'OBJECT') start = time.time() #don't add multiple boolean modifiers if 'Final Splint' not in bpy.data.objects: me = Shell.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') ob = bpy.data.objects.new('Final Splint', me) context.scene.objects.link(ob) ob.matrix_world = Shell.matrix_world else: ob = bpy.data.objects.get('Final Splint') me = ob.data a_base = bpy.data.objects.get('Auto Base') if 'Trim Base' in ob.modifiers and a_base != None: mod = ob.modifiers.get('Trim Base') mod.object = a_base mod.operation = 'DIFFERENCE' mod.solver = self.solver1 else: mod = ob.modifiers.new('Trim Base', type = 'BOOLEAN') mod.object = a_base mod.operation = 'DIFFERENCE' mod.solver = self.solver1 if self.method_order == 'JOIN': #Structure is Shell - (Blockout + Passive) #Blockout Wax Needs a union modifier if 'Join Passive' in Blockout.modifiers: mod = Blockout.modifiers.get('Join Passive') mod.object = Passive mod.operation = 'UNION' mod.solver = self.solver1 else: mod = Blockout.modifiers.new('Join Passive', type = 'BOOLEAN') mod.object = Passive mod.operation = 'UNION' mod.solver = self.solver1 #Final Spint need only 1 boolean operation if 'Passive Spacer' in ob.modifiers: mod = ob.modifiers.get('Passive Spacer') ob.modifiers.remove(mod) if 'Subtract Blockout' in ob.modifiers: mod = ob.modifiers.get('Subtract Blockout') mod.object = Blockout mod.operation = 'DIFFERENCE' mod.solver = self.solver2 else: mod = ob.modifiers.new('Subtract Blockout', type = 'BOOLEAN') mod.object = Blockout mod.operation = 'DIFFERENCE' mod.solver = self.solver2 elif self.method_order == 'SUBTRACT': #Strucure is #Shell - Blockout - Passive #Blockout Wax MUST NOT have modifier if 'Join Passive' in Blockout.modifiers: mod = Blockout.modifiers.get('Join Passive') Blockout.modifiers.remove(mod) Blockout.update_tag() if 'Subtract Blockout' in ob.modifiers: mod = ob.modifiers.get('Subtract Blockout') mod.object = Blockout mod.operation = 'DIFFERENCE' mod.solver = self.solver1 else: mod = ob.modifiers.new('Subtract Blockout', type = 'BOOLEAN') mod.object = Blockout mod.operation = 'DIFFERENCE' mod.solver = self.solver1 if 'Passive Spacer' not in ob.modifiers: bool_mod = ob.modifiers.new('Passive Spacer', type = 'BOOLEAN') bool_mod.operation = 'DIFFERENCE' bool_mod.object = Passive bool_mod.solver = self.solver2 #Bmesh is too likely to create bad cuts else: bool_mod = ob.modifiers.get('Passive Spacer') bool_mod.operation = 'DIFFERENCE' bool_mod.object = Passive bool_mod.solver = self.solver2 ##Bmesh is too likely to create bad cuts for obj in context.scene.objects: obj.hide = True context.scene.objects.active = ob ob.select = True ob.hide = False ob.update_tag() context.scene.update() completion_time = time.time() - start print('competed the boolean subtraction in %f seconds' % completion_time) splint.finalize_splint = True tracking.trackUsage("D3Splint:FinishBoolean",(self.solver1,self.solver2, self.method_order, str(completion_time)[0:4])) tmodel = bpy.data.objects.get('Trimmed_Model') #make sure user can verify no intersections if tmodel: tmodel.hide = False return {'FINISHED'}
def exec(self, context): try: bme = cork_boolean(context, self._cork, "-diff", self._base, self._plane) except Exception as e: print('error in line 24') self.report({'ERROR'}, str(e)) tracking.trackUsage("D3Splint:FAILEDCorkBoolean") return {'CANCELLED'} bme.verts.ensure_lookup_table() bme.edges.ensure_lookup_table() bme.faces.ensure_lookup_table() #clean loose verts to_delete = [] for v in bme.verts: if len(v.link_edges) < 2: to_delete.append(v) print('deleting %i loose verts' % len(to_delete)) bmesh.ops.delete(bme, geom = to_delete, context = 1) bme.verts.ensure_lookup_table() bme.edges.ensure_lookup_table() bme.faces.ensure_lookup_table() #delete edges without faces to_delete = [] for ed in bme.edges: if len(ed.link_faces) == 0: for v in ed.verts: if len(v.link_faces) == 0: to_delete.append(v) to_delete = list(set(to_delete)) bmesh.ops.delete(bme, geom = to_delete, context = 1) bme.verts.ensure_lookup_table() bme.edges.ensure_lookup_table() bme.faces.ensure_lookup_table() total_faces = set(bme.faces[:]) islands = [] iters = 0 while len(total_faces) and iters < 100: iters += 1 seed = total_faces.pop() island = flood_selection_faces(bme, {}, seed, max_iters = 10000) islands += [island] total_faces.difference_update(island) best = max(islands, key = len) total_faces = set(bme.faces[:]) del_faces = total_faces - best bmesh.ops.delete(bme, geom = list(del_faces), context = 3) del_verts = [] for v in bme.verts: if all([f in del_faces for f in v.link_faces]): del_verts += [v] bmesh.ops.delete(bme, geom = del_verts, context = 1) del_edges = [] for ed in bme.edges: if len(ed.link_faces) == 0: del_edges += [ed] bmesh.ops.delete(bme, geom = del_edges, context = 4) if 'Final Splint' in bpy.data.objects: ob = bpy.data.objects.get('Final Splint') if len(ob.modifiers): ob.modifiers.clear() bme.to_mesh(ob.data) ob.data.update() else: me = bpy.data.meshes.new('Final Splint') ob = bpy.data.objects.new('Final Splint', me) context.scene.objects.link(ob) bme.free() for obj in context.scene.objects: obj.hide = True context.scene.objects.active = ob ob.select = True ob.hide = False tracking.trackUsage("D3Splint:SplintBooleanCORK") return {'FINISHED'}
def execute(self, context): n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] prefs = common_utilities.get_settings() if not prefs.non_clinical_use: self.report({'ERROR'}, 'You must certify non-clinical use in your addon preferences or in the panel') return {'CANCELLED'} if splint.finalize_splint: self.report({'WARNING'}, 'You have already finalized, this will remove or alter existing modifiers and try again') Shell = bpy.data.objects.get('Splint Shell') Passive = bpy.data.objects.get('Passive Spacer') if Shell == None: self.report({'ERROR'}, 'Need to calculate splint shell first') return {'CANCELLED'} if Passive == None: self.report({'ERROR'}, 'Need to make passive spacer first') return {'CANCELLED'} if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode = 'OBJECT') tracking.trackUsage("D3Splint:FinishBoolean",None) #don't add multiple boolean modifiers if 'Passive Fit' not in Shell.modifiers: bool_mod = Shell.modifiers.new('Passive Fit', type = 'BOOLEAN') bool_mod.operation = 'DIFFERENCE' bool_mod.solver = self.solver #update in case they changed the spacer bool_mod.object = Passive Passive.hide = True bme = bmesh.new() bme.from_object(Shell, context.scene) bme.faces.ensure_lookup_table() bme.verts.ensure_lookup_table() total_faces = set(bme.faces[:]) islands = [] iters = 0 while len(total_faces) and iters < 100: iters += 1 seed = total_faces.pop() island = flood_selection_faces(bme, {}, seed, max_iters = 10000) islands += [island] total_faces.difference_update(island) best = max(islands, key = len) total_faces = set(bme.faces[:]) del_faces = total_faces - best bmesh.ops.delete(bme, geom = list(del_faces), context = 3) del_verts = [] for v in bme.verts: if all([f in del_faces for f in v.link_faces]): del_verts += [v] bmesh.ops.delete(bme, geom = del_verts, context = 1) del_edges = [] for ed in bme.edges: if len(ed.link_faces) == 0: del_edges += [ed] bmesh.ops.delete(bme, geom = del_edges, context = 4) if 'Final Splint' not in bpy.data.objects: me = bpy.data.meshes.new('Final Splint') ob = bpy.data.objects.new('Final Splint', me) context.scene.objects.link(ob) ob.matrix_world = Shell.matrix_world else: ob = bpy.data.objects.get('Final Splint') me = ob.data bme.to_mesh(me) bme.free() for obj in context.scene.objects: obj.hide = True context.scene.objects.active = ob ob.select = True ob.hide = False tmodel = bpy.data.objects.get('Trimmed_Model') #make sure user can verify no intersections if tmodel: tmodel.hide = False splint.finalize_splint = True context.space_data.show_backface_culling = False return {'FINISHED'}
def finish(self, context): #settings = get_settings() #apply all modifiers context.window.cursor_modal_restore() tracking.trackUsage("D3Splint:PlaneCutRaw",None)
def execute(self, context): if not len(context.scene.odc_splints): self.report({'ERROR'}, 'Need to start a splint by setting model first') return {'CANCELLED'} n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] Model = bpy.data.objects.get(splint.model) Shell = bpy.data.objects.get('Splint Shell') Opposing = bpy.data.objects.get(splint.opposing) if Shell == None: self.report({'ERROR'}, 'Need to calculate splint shell first') return {'CANCELLED'} if Opposing == None: self.report({'ERROR'}, 'Need to indicate opposing model') return {'CANCELLED'} if len(Shell.modifiers): old_data = Shell.data new_data = Shell.to_mesh(context.scene, apply_modifiers = True, settings = 'PREVIEW') for mod in Shell.modifiers: Shell.modifiers.remove(mod) Shell.data = new_data bpy.data.meshes.remove(old_data) bme = bmesh.new() bme.from_mesh(Opposing.data) bme.verts.ensure_lookup_table() mx_p = Opposing.matrix_world imx_p = mx_p.inverted() mx_m = Model.matrix_world imx_m = mx_m.inverted() mx_s = Shell.matrix_world imx_s = mx_s.inverted() if splint.jaw_type == 'MAXILLA': Z = Vector((0,0,1)) else: Z = Vector((0,0,-1)) #Do a manual ray cast to the underlying data...use BVH in future? sbme = bmesh.new() sbme.from_mesh(Shell.data) sbme.verts.ensure_lookup_table() print('got the shell data') n_ray_casted = 0 for v in sbme.verts: ray_orig = mx_s * v.co ray_target = mx_s * ( v.co + 5 * Z ) ray_target2 = mx_s * (v.co - self.snap_limit * Z) ok, loc, no, face_ind = Opposing.ray_cast(imx_p * ray_orig, imx_p * ray_target - imx_p*ray_orig) if ok: v.co = imx_s * (mx_p * loc) n_ray_casted += 1 if self.sculpt_to: if abs(v.normal.dot(Z)) < .2: continue ok, loc, no, face_ind = Opposing.ray_cast(imx_p * ray_orig, imx_p * ray_target2 - imx_p*ray_orig, distance = self.snap_limit) if ok: v.co = imx_s * (mx_p * loc) n_ray_casted += 1 sbme.to_mesh(Shell.data) sbme.free() Shell.data.update() Opposing.hide = True Shell.hide = False Model.hide = False splint.ops_string += 'MIP_Bite:' tracking.trackUsage("D3Splint:MIPBite", param = None, background = True) return {'FINISHED'}
def finish(self, context): #settings = get_settings() context.window.cursor_modal_restore() tracking.trackUsage("D3Splint:StencilText",None)
def invoke(self, context, event): tracking.trackUsage("D3Splint:ChangePinSetting", None) return context.window_manager.invoke_props_dialog(self)
def execute(self, context): tracking.trackUsage( "D3Tool:GenArticulator", str((self.intra_condyle_width, self.intra_condyle_width, self.bennet_angle, self.canine_guidance, self.incisal_guidance))) context.scene.frame_start = 0 context.scene.frame_end = 3 * self.resolution context.scene.frame_set(0) #add 2 bezier paths named right and left condyle, move them to the condyle width if 'Articulator' in bpy.data.objects: #start fresh art_arm = bpy.data.objects.get('Articulator') n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] opposing = splint.get_mandible() Model = bpy.data.objects.get(opposing) if Model: for cons in Model.constraints: if cons.type == 'CHILD_OF' and cons.target == art_arm: Model.constraints.remove(cons) context.scene.objects.unlink(art_arm) art_data = art_arm.data bpy.data.objects.remove(art_arm) bpy.data.armatures.remove(art_data) if 'Right Condyle Path' in bpy.data.curves: rcp_obj = bpy.data.objects.get("RCP") lcp_obj = bpy.data.objects.get("LCP") rcp = bpy.data.curves.get('Right Condyle Path') lcp = bpy.data.curves.get('Left Condyle Path') else: rcp = bpy.data.curves.new('Right Condyle Path', type='CURVE') lcp = bpy.data.curves.new('Left Condyle Path', type='CURVE') rcp.splines.new('BEZIER') lcp.splines.new('BEZIER') rcp.splines[0].bezier_points.add(count=1) lcp.splines[0].bezier_points.add(count=1) rcp_obj = bpy.data.objects.new("RCP", rcp) lcp_obj = bpy.data.objects.new("LCP", lcp) context.scene.objects.link(rcp_obj) context.scene.objects.link(lcp_obj) rcp.splines[0].bezier_points[0].handle_left_type = 'AUTO' rcp.splines[0].bezier_points[0].handle_right_type = 'AUTO' lcp.splines[0].bezier_points[0].handle_left_type = 'AUTO' lcp.splines[0].bezier_points[0].handle_right_type = 'AUTO' rcp.splines[0].bezier_points[1].handle_left_type = 'AUTO' rcp.splines[0].bezier_points[1].handle_right_type = 'AUTO' lcp.splines[0].bezier_points[1].handle_left_type = 'AUTO' lcp.splines[0].bezier_points[1].handle_right_type = 'AUTO' #track lenght rcp.splines[0].bezier_points[0].co = Vector((-2, 0, 0)) lcp.splines[0].bezier_points[0].co = Vector((-2, 0, 0)) rcp.splines[0].bezier_points[1].co = Vector((8, 0, 0)) lcp.splines[0].bezier_points[1].co = Vector((8, 0, 0)) rcp.dimensions = '3D' lcp.dimensions = '3D' rcp_obj.location = Vector((0, -0.5 * self.intra_condyle_width, 0)) lcp_obj.location = Vector((0, 0.5 * self.intra_condyle_width, 0)) lcp_obj.rotation_euler[1] = self.condyle_angle / 180 * math.pi rcp_obj.rotation_euler[1] = self.condyle_angle / 180 * math.pi lcp_obj.rotation_euler[2] = -self.bennet_angle / 180 * math.pi rcp_obj.rotation_euler[2] = self.bennet_angle / 180 * math.pi ant_guidance = Vector( (math.cos(self.incisal_guidance * math.pi / 180), 0, -math.sin(self.incisal_guidance * math.pi / 180))) rcan_guidance = Vector( (0, math.cos(self.canine_guidance * math.pi / 180), -math.sin(self.canine_guidance * math.pi / 180))) lcan_guidance = Vector( (0, -math.cos(self.canine_guidance * math.pi / 180), -math.sin(self.canine_guidance * math.pi / 180))) ant_guidance.normalize() rcan_guidance.normalize() lcan_guidance.normalize() bme = bmesh.new() v0 = Vector((0, -.5 * self.guidance_delay_lat, 0)) v1 = v0 + Vector((self.guidance_delay_ant, 0, 0)) v2 = v1 + 15 * ant_guidance v3 = Vector((0, .5 * self.guidance_delay_lat, 0)) v4 = v3 + Vector((self.guidance_delay_ant, 0, 0)) v5 = v4 + 15 * ant_guidance v6 = v0 + 15 * lcan_guidance v7 = v1 + 15 * lcan_guidance v8 = v2 + 15 * lcan_guidance v9 = v3 + 15 * rcan_guidance v10 = v4 + 15 * rcan_guidance v11 = v5 + 15 * rcan_guidance vecs = [v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11] vs = [bme.verts.new(v) for v in vecs] bme.faces.new((vs[0], vs[3], vs[4], vs[1])) bme.faces.new((vs[1], vs[4], vs[5], vs[2])) bme.faces.new((vs[3], vs[9], vs[10], vs[4])) bme.faces.new((vs[6], vs[0], vs[1], vs[7])) bme.faces.new((vs[4], vs[10], vs[11], vs[5])) bme.faces.new((vs[7], vs[1], vs[2], vs[8])) if 'Guide Table' in bpy.data.objects: guide_object = bpy.data.objects.get('Guide Table') guide_data = guide_object.data else: guide_data = bpy.data.meshes.new('Guide Table') guide_object = bpy.data.objects.new('Guide Table', guide_data) context.scene.objects.link(guide_object) guide_object.location = Vector( (99.9, 0, -60)) #TODO, incisal edge location bme.to_mesh(guide_data) art_data = bpy.data.armatures.new('Articulator') art_data.draw_type = 'STICK' art_arm = bpy.data.objects.new('Articulator', art_data) context.scene.objects.link(art_arm) art_arm.select = True context.scene.objects.active = art_arm bpy.ops.object.mode_set(mode='EDIT') bpy.ops.armature.bone_primitive_add(name="Right Condyle") bpy.ops.armature.bone_primitive_add(name="Left Condyle") bpy.ops.armature.bone_primitive_add(name="Mand Bow Silent") bpy.ops.armature.bone_primitive_add(name="Mandibular Bow") bpy.ops.armature.bone_primitive_add(name="Guide Pin") bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') b = art_arm.data.edit_bones.get("Right Condyle") b.head.xyz = Vector((0, 0, 0)) b.tail.xyz = Vector((0, 0, 10)) b = art_arm.data.edit_bones.get("Left Condyle") b.head.xyz = Vector((0, 0, 0)) b.tail.xyz = Vector((0, 0, 10)) b = art_arm.data.edit_bones.get('Mand Bow Silent') b.head.xyz = Vector((0, 0, 0)) b.tail.xyz = Vector((100, 0, 0)) b = art_arm.data.edit_bones.get('Mandibular Bow') b.head.xyz = Vector((0, 0, 0)) b.tail.xyz = Vector((100, 0, 0)) #notice this bone points up, because the head will snap to guide plane b = art_arm.data.edit_bones.get('Guide Pin') b.head.xyz = Vector((100, 0, -60)) b.tail.xyz = Vector((100, 0, 0)) bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='POSE') #now set the pose constrints if 'threeway_envelope_r' not in bpy.app.driver_namespace: bpy.app.driver_namespace[ 'threeway_envelope_r'] = three_way_envelope_r if 'threeway_envelope_l' not in bpy.app.driver_namespace: bpy.app.driver_namespace[ 'threeway_envelope_l'] = three_way_envelope_l pboneR = art_arm.pose.bones.get('Right Condyle') cons = pboneR.constraints.new(type='FOLLOW_PATH') cons.target = rcp_obj cons.use_fixed_location = True d = cons.driver_add('offset_factor').driver v = d.variables.new() v.name = "frame" v.targets[0].id_type = 'SCENE' v.targets[0].id = context.scene v.targets[0].data_path = "frame_current" #d.expression = "threeway_envelope_r(frame) * " + str(self.range_of_motion)[0:3] cfactor = min(8.0, self.factor / 8.0) d.expression = 'threeway_envelope_r(frame,' + str( cfactor)[0:4] + ',' + str(self.resolution) + ')' pboneL = art_arm.pose.bones.get('Left Condyle') cons = pboneL.constraints.new(type='FOLLOW_PATH') cons.target = lcp_obj cons.use_fixed_location = True d = cons.driver_add('offset_factor').driver v = d.variables.new() v.name = "frame" v.targets[0].id_type = 'SCENE' v.targets[0].id = context.scene v.targets[0].data_path = "frame_current" #d.expression = "threeway_envelope_l(frame) * " + str(self.range_of_motion)[0:3] d.expression = 'threeway_envelope_l(frame,' + str( cfactor)[0:4] + ',' + str(self.resolution) + ')' cons = pboneR.constraints.new(type='LOCKED_TRACK') cons.target = art_arm cons.subtarget = "Left Condyle" cons.track_axis = "TRACK_NEGATIVE_Z" cons.lock_axis = "LOCK_Y" cons = pboneL.constraints.new(type='LOCKED_TRACK') cons.target = art_arm cons.subtarget = "Right Condyle" cons.track_axis = 'TRACK_NEGATIVE_Z' cons.lock_axis = "LOCK_Y" #update the pose posititions bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='POSE') pboneBow = art_arm.pose.bones.get('Mand Bow Silent') cons = pboneBow.constraints.new('CHILD_OF') cons.target = art_arm cons.subtarget = 'Left Condyle' cons.inverse_matrix = pboneL.matrix.inverted() bpy.ops.object.mode_set(mode='EDIT') cons.influence = .5 bpy.ops.object.mode_set(mode='POSE') cons = pboneBow.constraints.new('CHILD_OF') cons.target = art_arm cons.subtarget = 'Right Condyle' cons.inverse_matrix = pboneR.matrix.inverted() bpy.ops.object.mode_set(mode='EDIT') cons.influence = .5 bpy.ops.object.mode_set(mode='POSE') pbonePin = art_arm.pose.bones.get('Guide Pin') cons = pbonePin.constraints.new(type='CHILD_OF') cons.target = art_arm cons.use_rotation_x = False cons.use_rotation_y = False cons.subtarget = 'Mand Bow Silent' cons.inverse_matrix = pboneBow.matrix.inverted() bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='POSE') cons = pbonePin.constraints.new(type='SHRINKWRAP') cons.target = guide_object cons.shrinkwrap_type = 'PROJECT' cons.project_axis = "NEG_Y" bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='POSE') pboneBow2 = art_arm.pose.bones.get("Mandibular Bow") cons = pboneBow2.constraints.new(type='CHILD_OF') cons.target = art_arm cons.subtarget = 'Mand Bow Silent' cons = pboneBow2.constraints.new(type='LOCKED_TRACK') cons.target = art_arm cons.subtarget = 'Guide Pin' cons.head_tail = 1 cons.track_axis = 'TRACK_Y' cons.lock_axis = 'LOCK_Z' cons = pboneBow2.constraints.new(type='TRACK_TO') cons.target = art_arm cons.subtarget = 'Guide Pin' cons.head_tail = 1 cons.track_axis = 'TRACK_Y' cons.up_axis = 'UP_Z' #https://blender.stackexchange.com/questions/19602/child-of-constraint-set-inverse-with-python bpy.ops.object.mode_set(mode='OBJECT') n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] maxilla = splint.get_maxilla() Maxilla = bpy.data.objects.get(maxilla) if Maxilla: for ob in context.scene.objects: ob.select = False Maxilla.hide = False context.scene.objects.active = Maxilla Maxilla.select = True #bpy.ops.view3d.viewnumpad(type = 'RIGHT') bpy.ops.d3splint.enable_articulator_visualizations() #save settings to object art_arm['bennet_angle'] = self.bennet_angle art_arm['intra_condyle_width'] = self.intra_condyle_width art_arm['incisal_guidance'] = self.incisal_guidance art_arm['canine_guidance'] = self.canine_guidance art_arm['condyle_angle'] = self.condyle_angle art_arm['guidance_delay_ant'] = self.guidance_delay_ant art_arm['guidance_delay_lat'] = self.guidance_delay_ant splint.ops_string += 'GenArticulator:' if not self.auto_mount: return {'FINISHED'} n = context.scene.odc_splint_index splint = context.scene.odc_splints[n] splint.ops_string += 'Generate Articulator:' mandible = splint.get_mandible() Mandible = bpy.data.objects.get(mandible) if Mandible: Mandible.hide = False cons = Mandible.constraints.new(type='CHILD_OF') cons.target = art_arm cons.subtarget = 'Mandibular Bow' mx = art_arm.matrix_world * art_arm.pose.bones[ 'Mandibular Bow'].matrix cons.inverse_matrix = mx.inverted() #write the lower jaw BVH to cache for fast ray_casting OppModel = bpy.data.objects.get(splint.opposing) if OppModel != None: bme = bmesh.new() bme.from_mesh(OppModel.data) bvh = BVHTree.FromBMesh(bme) splint_cache.write_mesh_cache(OppModel, bme, bvh) return {'FINISHED'}
def execute(self, context): splint = context.scene.odc_splints[0] Model = bpy.data.objects.get(splint.opposing) Master = bpy.data.objects.get(splint.model) Art = bpy.data.objects.get('Articulator') if Model == None: self.report({'ERROR'}, 'No Opposing Model') return {'CANCELLED'} if Art == None: self.report({ 'ERROR' }, 'You need to Generate Articulator or set initial articulator values first' ) return {'CANCELLED'} if not splint_cache.is_object_valid(Model): splint_cache.clear_mesh_cache() bme = bmesh.new() bme.from_mesh(Model.data) bme.faces.ensure_lookup_table() bme.verts.ensure_lookup_table() bvh = BVHTree.FromBMesh(bme) splint_cache.write_mesh_cache(Model, bme, bvh) bpy.ops.d3splint.articulator_mode_set( mode=self.mode, resolution=self.resolution, range_of_motion=self.range_of_motion, use_relax=self.use_relax, relax_ramp_length=self.relax_ramp_length) #filter the occlusal surface verts Plane = bpy.data.objects.get('Dynamic Occlusal Surface') if Plane == None: self.report({ 'ERROR' }, 'Need to mark occlusal curve on opposing object to get reference plane' ) return {'CANCELLED'} Shell = bpy.data.objects.get('Splint Shell') if Shell == None: self.report({'WARNING'}, 'There is no splint shell, however this OK.') if Shell: if len(Shell.modifiers): Shell.select = True Shell.hide = False context.scene.objects.active = Shell for mod in Shell.modifiers: bpy.ops.object.modifier_apply(modifier=mod.name) bme = bmesh.new() bme.from_mesh(Plane.data) bme.verts.ensure_lookup_table() #reset occusal plane if animate articulator has happened already if "AnimateArticulator" in splint.ops_string: for v in bme.verts: v.co[2] = 0 mx_p = Plane.matrix_world imx_p = mx_p.inverted() mx_s = Shell.matrix_world imx_s = mx_s.inverted() keep_verts = set() if splint.jaw_type == 'MAXILLA': Z = Vector((0, 0, 1)) else: Z = Vector((0, 0, -1)) for v in bme.verts: ray_orig = mx_p * v.co ray_target = mx_p * v.co + 5 * Z ok, loc, no, face_ind = Shell.ray_cast( imx_s * ray_orig, imx_s * ray_target - imx_s * ray_orig) if ok: keep_verts.add(v) print('there are %i keep verts' % len(keep_verts)) front = set() for v in keep_verts: immediate_neighbors = [ ed.other_vert(v) for ed in v.link_edges if ed.other_vert(v) not in keep_verts ] front.update(immediate_neighbors) front.difference_update(keep_verts) keep_verts.update(front) for i in range(0, 10): new_neighbors = set() for v in front: immediate_neighbors = [ ed.other_vert(v) for ed in v.link_edges if ed.other_vert(v) not in front ] new_neighbors.update(immediate_neighbors) keep_verts.update(front) front = new_neighbors delete_verts = [v for v in bme.verts if v not in keep_verts] bmesh.ops.delete(bme, geom=delete_verts, context=1) bme.to_mesh(Plane.data) for ob in bpy.data.objects: if ob.type == 'MESH': ob.hide = True elif ob.type == 'CURVE': ob.hide = True Model.hide = False Master.hide = False Plane.hide = False tracking.trackUsage("D3Splint:CreateSurface", None) context.scene.frame_current = -1 context.scene.frame_current = 0 splint.ops_string += 'AnimateArticulator:' print('adding the handler!') handlers = [ hand.__name__ for hand in bpy.app.handlers.frame_change_pre ] if occlusal_surface_frame_change.__name__ not in handlers: bpy.app.handlers.frame_change_pre.append( occlusal_surface_frame_change) else: print('handler already in there') context.space_data.show_backface_culling = False bpy.ops.screen.animation_play() return {'FINISHED'}