Fracture plate (3-matic 14.0)

This tutorial shows how to semi-automatically design a patient specific finger plate. The workflow focuses on designing a plate based on the position of screws in 3D. This tutorial will help in understanding workflows that are part of a design process. The project hand_plate.mxp that is located in the 3-matic installation folder …\DemoFiles.

import os
import trimatic
from tkinter import *
import numpy

# Constants used for the script
ORIGINAL_FILES = ["screw","fingerbone"]
TEMP = "temp"
WRAPPED_TEMP = "wrapped_temp"
PLATE = "Hand plate"
FINAL_PLATE = "Final Hand plate"
SCREWS = ["Screw 1", "Screw 2", "Screw 3", "Screw 4"]
MESSAGE_1 = "Create the profile of the fracture plate and click OK. The script will continue..."
MESSAGE_2  = "Position the 4 screws of the plate. Click OK and start indicating the desired locations..."

# Open project and select the best view.
application_exe = trimatic.get_application_path()
application_path = os.path.dirname(application_exe)
project_filename = application_path + "/DemoFiles/hand_plate.mxp"
trimatic.open_project(project_filename)
trimatic.view_default(trimatic.DefaultViews.Back)
finger_bone = trimatic.find_part(ORIGINAL_FILES[1])
assert finger_bone
trimatic.zoom(finger_bone)

# Calculate the center of  gravity and inertia axes to ensure that create a plane.
finger_bone = trimatic.find_part(ORIGINAL_FILES[1])
inertia = trimatic.compute_inertia_axes(finger_bone)
finger_bone_zx_pl = trimatic.create_plane_normal_origin(normal=inertia[1],origin=inertia[0])
finger_bone_zx_pl.visible = False
sketch = trimatic.create_sketch(planes=finger_bone_zx_pl)

# Move the plane and the sketch above the bone
assembly = [finger_bone_zx_pl,sketch]
translation_vector = (0,inertia[2][1]+10,0)
trimatic.translate(assembly,translation_vector)

# Importing the references of the surfaces onto the sketch.
for surf in finger_bone.get_surfaces():
	trimatic.import_outline(sketch,surf, construction=True)

# UI for the creation of the curve profile. 

trimatic.message_box(MESSAGE_1,'Sketch profile',False )

# Create a temporary part and hide the sketch
finger_bone.visible = False
temp_part = trimatic.copy_to_part(finger_bone.get_surfaces())
temp_part.name = TEMP
temp_part.visible = False
sketch.visible = False

# Wrap the temporary part
wrapped_temp = trimatic.wrap(entities=temp_part,gap_closing_distance=0.4,smallest_detail=0.2)
wrapped_temp.name = WRAPPED_TEMP


#project curve to part and split to surfaces
direc = (0,-translation_vector[1],0)
trimatic.project_curve(entities=sketch,direction=direc,target_entities=wrapped_temp)
trimatic.attach_curve(wrapped_temp.get_curve_sets()[0],wrapped_temp)
trimatic.split_surfaces_by_curves(wrapped_temp,wrapped_temp.get_curve_sets()[0])

# Find and pick the smallest surface which is the plate
surfs = wrapped_temp.get_surfaces()
plate_surf = surfs[0]
if plate_surf.area > surfs[1].area:
	plate_surf = surfs[1]

#From surface to Part for the plate
plate_part = trimatic.copy_to_part(plate_surf)
plate_surf = plate_part.get_surfaces()[0]
trimatic.move_surface(plate_surf,direction=None,distance=0.5)
plate_part.name = PLATE

#Delete temp parts
trimatic.delete(temp_part)
finger_bone.visible = True

# UI for the indicating scews
trimatic.message_box(MESSAGE_2,'Indicate screws',False )

points = [trimatic.indicate_coordinate() for i in range(len(SCREWS))]
planes = [0 for i in range(len(points))]
po = 0
for p in points:
	duplicatebone = trimatic.duplicate(plate_part)
	spherepoint = trimatic.create_sphere_part(p,1)
	inters = trimatic.boolean_intersection((duplicatebone,spherepoint))
	allsurfaces = inters.find_surfaces('Surface')
	areas = [0 for i in range(len(allsurfaces))]
	a = 0
	for s in allsurfaces:
		areas[a] = s.area
		a = a+1
	ms = numpy.argmax(areas)
	planes[po] = trimatic.create_plane_fit(allsurfaces[ms])
	# Check necessary whether Z-axis of plane points in right direction
	# by comparing direction from point to center of gravity with Z-axis direction
	gr = trimatic.compute_center_of_gravity(inters)
	sp = numpy.inner(numpy.subtract(p,gr),planes[po].object_coordinate_system.z_axis)
	if sp < 0:
		trimatic.rotate(planes[po],180,planes[po].object_coordinate_system.origin,planes[po].object_coordinate_system.x_axis)
	po = po + 1
	trimatic.delete(inters)
	
# Place screws with plane to plane align
screws = [0 for i in range(len(points))]
screws2 = [0 for i in range(len(points))]
sc = 0
screw = trimatic.find_part(ORIGINAL_FILES[0])
screw.visible = False

for p in points:
	xyplanescrew = trimatic.create_plane_normal_origin(screw.object_coordinate_system.z_axis,screw.object_coordinate_system.origin)
	duplicatescrew = trimatic.duplicate(screw)
	trimatic.plane_to_plane_align(planes[sc],xyplanescrew,duplicatescrew)
	screws[sc] = duplicatescrew
	screws2[sc] = trimatic.duplicate(screws[sc])
	planes[sc].visible = False
	screws[sc].visible = False
	sc = sc + 1
	trimatic.delete(xyplanescrew)

#Move a bit the screws to appear better
for sc in screws:
	trvector = sc.object_coordinate_system.z_axis #only 1 mm required
	trimatic.translate(sc,trvector)
	
allscrews = trimatic.boolean_union(screws)
screws_4_subtraction = trimatic.boolean_union(screws2)


#create holes in the plate
final_plate = trimatic.boolean_subtraction(plate_part,screws_4_subtraction)
final_plate.name  = FINAL_PLATE
wrapped_temp.visible = False
trimatic.resume_progress()