Software

The software is essentially an application of 3D computational geometry. It is implemented here as a Web application with 7 forms. The web document is generated from xml source by tools from the LME Practical XML project. Each form is associated with a Perl CGI script which is executed when it is submitted. The scripts acquire and validate the form data, reporting errors, and call C++ programs when coordinate transformations and graphic generation are required. The form data is stored in xml files for later reference.

Conventions

Frame coordinates are defined in a local coordinate system for each component, and in a single global coordinate system. Local coordinates are independent of transformations. Global coordinates result from applying transformations to local coordinates. The relationship between the assembled frame, the x-ray source, and the x-ray sensor is defined in the global coordinate system. The x-ray sensor lies on the global y=0 plane, with the frame and the x-ray source at -ve y.

In each ring local coordinate system:

  • The ring reference face lies on the z=0 plane with the centre at the origin and the z axis upwards.
  • The first fixing hole lies on the x axis.
  • Looking in the -ve z direction, other holes are laid out anticlockwise on the z=0 plane from the first hole. Positive angles are anticlockwise in this view.

In each strut local coordinate system:

  • The strut is aligned along the z axis.
  • Element positions depend on strut length.

Strut elements rigidly connected to a ring (joint supports and joint centres) are defined in the ring local coordinate system.

In the assembled frame, the ring reference faces are the inner faces, adjacent to the struts. The local z axes of the rings point in the same general direction, from ring 0 to ring 1. This is required so hole numbering runs the same way round both rings. Ring 1 is an approximate z mirror of ring 0 in the local coordinate system:

  • The other ring face is at -ve z for ring 0 and +ve z for ring 1.
  • The strut joint offset is at +ve z for ring 0 and -ve z for ring 1.
  • The ring normal points in the +ve z direction for ring 0 and the -ve z direction for ring 1.

Fixator frame geometry and frame transformations are realised by ring transformations. Given transformations for ring 0 and ring 1, frame geometry and transformations are fully defined. Ring transformations determine strut lengths and transformations. When strut lengths are defined in the user interface, ring 0 is positioned at the global coordinate system origin, with the same local and global coordinates, and ring 1 is transformed to give the required strut lengths. Subsequently, when the frame is transformed to generate different views with fixed strut lengths, frame transformations are applied to both rings.

For the convenience of both users and programmers, numeric item ids (ring, ring hole, strut, etc) are 1-based (eg 1..6) in the user interface, but 0-based (eg 0..5) in the C++ code. The mapping is done in the cgi scripts which pass parameters to the C++ code, with the (temporary) exception of ring hole ids as noted in the code.

Algorithms

First the fixator rings and struts, and the assembled frame, are defined. The initial frame geometry is computed from strut lengths by a least-squares search of inverse kinematic space. When the initial x-rays are taken to establish the deformity parameters, the frame orientation is recorded. The software then generates projected views of the frame, with a coordinate grid, which match the x-ray images. The x-rays and the generated images are overlaid, allowing the bone reference point coordinates to be read from the grid in the coordinate systems of the views. Rays passing through these points are transformed to the frame reference coordinate system, and their intersection found. Then the full geometry is known and the deformity correction schedule can be computed.

The method presented here will be most effective with digital x-rays, when the overlaying can be done by software. As it will be some time before digital x-rays are the norm, later discussion assumes that the x-ray film will be used, and that the generated matching images will be printed.

Inverse Kinematics

If we know the relative position and orientation of the two rings, computing the strut lengths is simple. We can easily calculate the end coordinates, and given those, Pythagorus tells us the strut lengths. This is the easy inverse kinematics problem. However, in this case it appears that the easy solution is not much use, because the position and orientation of the rings are not being controlled - the strut lengths are.

Forward Kinematics

If we know the strut lengths, how do we find the relative position and orientation of the rings? This is the hard forward kinematics problem, not easy to solve analytically, so we won't even try. Instead we use the inverse kinematics approach, setting up a simple computer model of the rings, and stepping through relative positions and orientations, looking for a set of strut lengths which most closely matches the given set. The search space is very large though, so we use a binary search to minimise the time taken to find a solution.

Least Squares Method

When solving the forward kinematics problem through a binary search of the inverse kinematics solution space, we need a way of deciding if one candidate set of strut lengths is closer than another to the given lengths. For this we use the well-known least squares method. For each strut, we compute the difference between the computed and the given lengths (the error). Then we sum the squares of the errors, and seek to minimise this sum. Using squares improves the computation two ways: first, the signs of the errors can be ignored; and second, squares heavily penalise large errors.

Ray Intersection

The coordinates of the bone reference points (the deformity parameters) are entered approximately in the local coordinate systems of the frontal and lateral x-ray views, which are themselves only approximately orthogonal. We can determine definite bone reference coordinates in a global coordinate system by finding the 'intersection' of a pair of rays (line segments) through each point. We define the intersection here to be the midpoint of the common normal to the rays. The length of this normal is expected to be small.

Forms and CGI Scripts

Ring Parameters

The user enters a ring identifier and optionally defines new ring parameters. Script ringparameters.cgi reads old ring data or writes new data, and redisplays the form.

Strut Parameters

The user enters a strut identifier and optionally defines new strut parameters. Script strutparameters.cgi reads old strut data or writes new data, and redisplays the form.

Frame Parameters

The user enters a frame identifier and optionally defines new frame parameters. Script frameparameters.cgi reads old frame data or writes new data, and redisplays the form.

Strut Lengths

The user enters a frame identifier and optionally defines new strut lengths. Script strutlengths.cgi reads old strut length data or writes new data. It then calls C++ program setstrutlengths to compute the frame geometry, and redisplays the form with generated graphics.

X-Ray Parameters

The user enters a frame identifier and optionally defines new x-ray parameters. Script xrayparameters.cgi reads old x-ray data or writes new data. It then calls C++ program transformviews to transform the frame to match the frontal and lateral x-ray views, and redisplays the form with generated graphics.

Deformity Parameters

The user enters a frame identifier and optionally defines new deformity parameters. Script deformityparameters.cgi reads old deformity data or writes new data. It then calls C++ program computebonecoords to compute the bone reference point coordinates, and redisplays the form with generated graphics.

Deformity Correction

The user enters a frame identifier and optionally defines new deformity correction parameters. Script deformitycorrection.cgi reads old deformity correction data or writes new data. It then calls C++ program computecorrections, and redisplays the form with the generated deformity correction schedule and graphics.

C++ Classes and Programs

Maths Classes

The vector and matrix classes we use come from Graphics Gems IV. We found them in 1993 and have used them ever since. They were written by Jean-Francois Doue, to whom many thanks.

Artifact Classes

The artifact classes deal with the definition, transformation and visualisation of solid geometry primitives.

Fixator Classes

The fixator classes encapsulate knowledge about fixator rings, struts, and frames, and how to transform and visualise them. They provide functions implementing the algorithms described above.

Programs

Given appropriate ring, strut and frame definitions, setstrutlengths computes frame geometry from strut lengths, by a least squares search of inverse kinematic space.

transformviews transforms the computed frame geometry so that projected frontal and lateral views match the corresponding x-ray images. The generated graphics include coordinate grids for deformity parameter capture by overlaying graphics and x-rays.

computebonecoords computes the bone reference point coordinates implied by the deformity parameters. This is done by ray intersection as described above. A second set of frontal and lateral graphics is generated, with bone reference points marked for checking.

computecorrections generates a schedule of strut length adjustments which will correct the given deformity in a given number of steps.

External Programs

POV-Ray Renderer

All the graphics are generated by POV-Ray, an excellent open source ray tracing program. As you can see on POV-Ray's website, it is capable of much more than we do with it here. Its scripting interface makes it easy to interface to other software. We generate scripts in the C++ code and get POV-Ray to generate the graphics files from them.

Apache Configuration

There is an example Apache configuration file in the distribution, in misc. Refer to this if you want to set up your own server for the software.