Align long bones (3-matic 13)

This script aligns a long bone to the world coordinate system based on 5 landmark points: an origin, proximal, distal, left and right point.

#This script aligns a long bone to the world coordinate system based on 5 landmark points: an origin, proximal, distal, left and right point. The distal-proximal direction defines the Z direction. The X direction is defined based on the right-left direction ( lateral-medial or medial-lateral, depending on whether it's the right or the left side).

#Input: bone_name: string with name of bone part
	# orig_name: string with  name of origin point
	# pt_prox_name: string with name of proximal point
	# pt_dist_name: string with name of distal point
	# pt_right_name: string with name of right point
	# pt_left_name: string with name of left point    

# Output: repositioned long bone along with input landmarks and calculated landmarks (x axis, 
# z axis, projected point, etc). 

# Author: Julien Deckx (Materialise)
# Version: 1.0. (June 21 2018)


import trimatic

def AlignLongBone(bone_name, orig_name, pt_prox_name, pt_dist_name, pt_right_name, pt_left_name):

	# find all entities
	bone = trimatic.find_part(bone_name)
	orig = trimatic.find_point(orig_name)
	pt_prox = trimatic.find_point(pt_prox_name)
	pt_dist = trimatic.find_point(pt_dist_name)
	pt_left = trimatic.find_point(pt_left_name)
	pt_right = trimatic.find_point(pt_right_name)


	# the z direction is defined as distal to proximal
	z_line = trimatic.create_line(pt_dist, pt_prox)
	z_line.name = "z_line"

	# create a plane perpendicular to z, with pt_right as origin
	z_plane = trimatic.analyze.create_plane_normal_origin(origin=pt_right, normal=z_line.direction)
	z_plane.name = "z_plane"

	# extend z_plane and convert to part to allow projection of pt_left 
	lr_distance = trimatic.measure.create_distance_measurement(pt_left, pt_right)

	z_plane.delta_x = lr_distance.value+1
	z_plane.delta_y = lr_distance.value+1

	z_plane_part = trimatic.convert_analytical_primitive_to_part(z_plane)

	# project pt_left in z_plane (try both +z and -z direction)
	plusZ_direction  = z_line.direction
	minZ_direction  = tuple([-x for x in plusZ_direction])
	try: 
		pt_left_proj = trimatic.project_point(direction = plusZ_direction, parts = z_plane_part, point_to_project = pt_left)
	except:
		pt_left_proj = trimatic.project_point(direction = minZ_direction, parts = z_plane_part, point_to_project = pt_left)

	pt_left_proj = trimatic.create_point(pt_left_proj[0])
	pt_left_proj.name = "pt_left_proj"

	# the direction is defined as the projection of the line from right to left
	x_line  = trimatic.create_line(pt_right, pt_left_proj)

	# create planes for plane-to-plane align 
	orig_x = trimatic.translate(entities = orig, translation_vector = x_line.direction, number_of_copies = 1)
	orig_z = trimatic.translate(entities = orig, translation_vector = z_line.direction, number_of_copies = 1)

	plane_moving = trimatic.create_plane_3_points(orig, orig_x, orig_z)
	plane_fixed = trimatic.create_plane_3_points((0,0,0), (1,0,0), (0,0,1))

	trimatic.delete(orig_x)
	trimatic.delete(orig_z)

	# plane-to-plane align
	trimatic.plane_to_plane_align(plane_on_fixed_entity=plane_fixed,plane_on_moving_entity=plane_moving,move_along_entities=(bone, pt_prox, pt_dist, pt_left, pt_right, orig, z_line,z_plane,lr_distance, pt_left_proj, x_line),coincident=True)