Skip to content

Convenience scripts and wrapper functions

Zoltan Derzsi edited this page Mar 10, 2019 · 37 revisions

There are certain features in the Optotrak system that can be automated, or in typical in typical usage cases requires no manual interaction. These 'convenience scripts', you to use your system quickly and painlessly with the use of the API functions in the toolbox.

Convenience scripts

make_mrproper.m

This script cleans the build and temporary directories. As git doesn't work conveniently with empty directories, this script adds placeholder files in the directories it just wiped. After the execution of this script, you have to re-compile everything.

add_toolbox_to_path.m

Sometimes I work on a shared computer, which means that I can't add the path permanently. You can run this script to add the relevant sub-directories to Matlab's path, allowing you to call these functions.

RUNME.m

Ideally, this is the first script you run, after setting up your environment in a few steps.

optotrak_align_my_system.m

Before using this function, please read about the calibration (alignment and registration) process first. Otherwise,

This function detects what hardware do you have,
%and it performs the necessary registration and alignment.
% Input arguments are:
%   -> config_file is the data acquisition settings .ini file.
%   -> rigid_body_file is the rigid body definition you are using to register and/or align with.
% total_rms_error is the error introduced by the coordinate system
% operations.

optotrak_load_lib.m

Once you compiled your files with RUNME.m, you won't have to do it again on the computer you are using. Execute this script to load the Optotrak library to Matlab, so you have access to all the API functions (with these limitations).

optotrak_<foobar>_decoder.m

These scripts decode the flags you recovered with the functions. Normally, in C, you have the #define <foobar> directives, but they get lost in the transition to Matlab. So, I made these functions, and they return a cell array with the names and meanings of the flags. Normally, during a simple experimental run, you won't need these.

optotrak_startup.m

This function does the optotrak reset dance, the following way:

  • Checking whether the compiled binaries exist
  • TransputerDetermineSystemCfg()
  • TransputerLoadSystem('system')
  • TransputerInitializeSystem(<log status and error messages>)

It is working as a function, so it returns a zero if completed successfully. It also has the necessary delays and error management, so if it fails for some reason, you'll hopefully have an idea why.

optotrak_set_up_system.m

This function loads the specified camera calibration file, loads the camera parameters, and then it sets up data acquisition from a specified ini file.
% Input argumens are:
%   -> camera_calibration_file is a file in your ndigital directory by default.
%   -> data_acquisition_config_file is the ini file you edited/generated.
% fail is 0 upon success, and the function terminates with an error message if something went wrong.

This function calls OptotrakLoadCameraParameters() and OptotrakSetupCollectionFromFile(), and it also turns on the markers, by calling OptotrakActivateMarkers().

optotrak_kill.m

Use this script to get rid of any running Optotrak software, and to unload the libraries from the memory. These are the steps it does:

  • OptotrakDeActivateMarkers()
  • OptotrakStopCollection()
  • TransputerShutDownSystem()

After all these are completed, it unloads the Optotrak library. Note: If you type clear all in Matlab after calling this script, you might need to power-cycle the Optotrak system to regain control over it.

optotrak_get_setup_info.m

% This function determines how the Optotrak system is configured. Essentially, it calls OptotrakGetStatus(), but it does all the variable declarations for you. You can get all the information with just a single line, which is extremely convenient. It also decodes the flags for you.
%   -> There are no input arguments.
% -Output argument is a structure, with all the parameters conveniently
%  named in the fields.

optotrak_are_two_markers_close.m

%This function tells you whether two markers are close to
%each other.
%   By default, the tolerance is 25mm. You can change this by tossing a third
%   argument, in millimetres.
% Input arguments are:
%   -> marker_number_1 is the NUMBER of the marker in the Optotrak system.
%   -> marker_number_2 is the NUMBER of the marker in the Optotrak system.
%   -> optionally, tolerance, which is a number is millimetres.
% You can specify any marker, and the function will fail if you are out of
% bounds.
% Output argument is:
% Output argument is:
%   1: if the coordinates are close to each other
%   0: if the coordinates are further away from each other

optotrak_are_two_points_close.m

%This function tells you whether two points are close in a form of a boolean.
%   By default, the tolerance is 25mm. You can change this by tossing a third
%   argument, in millimetres.
% Input arguments are:
%   -> coord_triplet_1 is the X-Y-Z coordinate triplet of the first point
%   -> coord_triplet_2 is the X-Y-Z coordinate triplet of the second point
%   -> optionally, tolerance which is in millimetres
% Output argument is:
%   1: if the coordinates are close to each other
%   0: if the coordinates are further away from each other

optotrak_assign_virtual_marker.m

%This function generates the association parameters of a given virtual marker and a known rigid body.
% Ideally, only a single set of coordinates are required. You can use the output of this function to determine where the virtual marker is once the rigid body has moved away.
% WARNING: If you calculate the centroid and orientation without defining a rigid body in the system, it's your responsibility to make sure that the markers you used in the calculation are at a fixed distance from each other.
% Input parameters are:
%   -> virtual_marker_coords is an X-Y-Z triplet, and is the known location of the virtual marker you want to assign to
%   -> centroid_coordinates is an X-Y-Z triplet which contains the location of the rigid body
%   -> rotation is the roll-pitch-yaw triplet that determines the orientation of the rigid body.
% virtual marker definition is a vector, which contains the following:
%   x_offset, which is the coordinate difference between the centroid and the virtual marker coordinates
%   y_offset, which is the coordinate difference between the centroid and the virtual marker coordinates
%   z_offset, which is the coordinate difference between the centroid and the virtual marker coordinates
%   roll, which is the rotation along the X axis in radians of the rigid body at the time of declaration
%   pitch, which is the rotation along the X axis in radians of the rigid body at the time of declaration
%   yaw, which is the rotation along the X axis in radians of the rigid body at the time of declaration

optotrak_calculate_centroid_and_orientation.m

%This function calculates the centroid of a bunch of markers. The orientation is calculated using a single marker.
% PLEASE NOTE: There is no sanity check on the marker locations. This script works for basic stuff, but if you want to have something fancier, I suggest the use of rigid bodies.
% To avoid confusion and disappointment, use as many markers as possible
% Input arugments are:
%   -> marker_coordinates is an N*3 array, where the X-Y-Z coordinates are stored as triplets
%   -> reference marker is an optional argument. If specified, the orientation will be calculated using a specified marker. Otherwise, the orientation is calculated using the first marker.
% translation_array is an X-Y-Z array of the centroid location. Every row is a different frame.
% rotation_array is the roll-pitch-yaw rotation angle triplet IN RADIANS for each frame.

optotrak_calculate_centroid_marker_distance.m

% [centroid_marker_differences] = optotrak_calculate_centroid_marker_distance(position3d_array)
% This function calculated the centroid of a bunch of markers, and returns the distances between the centroid and each marker.
% You can give this function multiple frames of data.
%Input arguments are:
%   -> position3d_array, which is a f-by-(N*3) array, for f frames and N markers.
%Returns:
% centroid_marker_differences, which is an f-by-N array, for f frames and N markers.

optotrak_calculate_body_warp.m

% [mean_distance_difference] = optotrak_calculate_body_warp( body_position3d_array1, body_position3d_array2 )
% This function useful when you use rigid bodies with markers attached to them, but you don't want to use the rigid body functionality of the Optotrak system.
% When the rigid body 'warps', its makers change position with respect to each other. The Optotrak system's rigid body facility takes care of detecting this and fails the rigid body transform, but if you are 'blindly' tracking the centroids, you will have issues with tracking without knowing it.
% This function compares the distances betwenn the markers and the centroid of a body, and will output the maximum difference between the mean value distances for each marker. You can use this function to ckeck whether your tracking is working.
% Input arguments are:
%   -body_position3d_array1, is an f-by(N*3) array, with f frames and N markers
%   -body_position3d_array2, is an f-by(N*3) array, with f frames and N markers
% Returns:
% mean_distance_difference, between the two centroids and markers, in millimetres.

optotrak_get_distance.m

%This function calculates the distance between two x-y-z
%coordinates. Dimension 1 is the number of frames, and dimension 2 is X-Y-Z.
% Input arguments are:
%   -> coord_triplet_1 is the X-Y-Z coordinate triplet of the first point
%   -> coord_triplet_2 is the X-Y-Z coordinate triplet of the second
% Output arguments are:
% -distance is the distance between the two points.

optotrak_get_marker_coords.m

%This function returns the coordinates of a single marker.
% Note that this script calls DataGetLatest3D_as_array, to minimise execution time.
%Input arguments are:
%   -> marker_number is the marker that you are querying
%Output arguments are:
% -fail is 0 when the operation was successful.
%  If the marker is not visible, fail will be -1.
%  If the marker is outside the detected number of markers, fail will be 1000
% marker_coords is a 1-by-3 array, which contains the selected marker coordinates.

optotrak_get_virtual_marker_coords.m

%This is function that calculates the X-Y-Z coordinates of a virtual marker, using the given virtual marker definition and the translation and rotation matrices.
% WARNING: Nothing checks whether the rigid body the virtual marker definition was created with is actually the same as the input of this function.
% This function is designed to get a single virtual marker's coordinates on a rigid body transform that can be many frames. So if you want many virtual markers for the same rigid body, simply execute this funciton with different virtual marker definitions.
% Input arguments are:
%   -> virtual marker definition is a 1-by-6 vector, containing the following:
%       -X-offset, which is the difference between the virtual marker and centroid X coordinates
%       -Y-offset, which is the difference between the virtual marker and centroid Y coordinates
%       -Z-offset, which is the difference between the virtual marker and centroid Z coordinates
%       -roll, wich is the rotation along the X axis in radians of the rigid body at the time of declaration
%       -pitch, wich is the rotation along the X axis in radians of the rigid body at the time of declaration
%       -yaw, wich is the rotation along the X axis in radians of the rigid body at the time of declaration
%   -> translation is the X-Y-Z triplet of the current location of the rigid body
%   -> rotation is the current roll-pitch-yaw orientation of the rigid body, in radians
% virtual_marker_coords contains the calculated virtual marker coordinates, as an X-Y-Z triplet. Each row is a separate frame.

optotrak_stop_buffering_and_write_out.m

This script executes DataBufferStop() and DataBufferWriteData(). However, if you initialised the buffer with DataBufferInitializeFile(), then the raw data file you generated still stays open, even after you finished data collection. This can potentially corrupt your data, and this function calls FileClose(0) to prevent it from happening. Ideally this script hangs until the buffer has fully been written out to disk. Use additional checks and safeguards. Ideally, this should only be called once the data collection time specified in the config file has elapsed since DataBufferStart() was called.

optotrak_generate_rigid_body_file()

This function generates a rigid body file with the specified marker positions. You can use this script to make the rigid body file to calibrate your system, or to create a rigid body programmatically. The topic of rigid bodies is huge, so I made a separate page: read more about rigid bodies here.

%OPTOTRAK_GENERATE_RIGID_BODY_FILE
% [fail] = optotrak_generate_rigid_body_file(coordinates, origin_marker, filename, coordinate_tolerance, normal_vector_coordinates, varargin)
% This function creates a rigid body file, so you can use it with RigidBodyAddFromFile().
% NOTE: IF you use this for calibration, please Please PLEASE make sure you use millimetres! The toolbox relies on the metric system.
% The function has two uses:
%   -For calibrating a system, you can specify a marker which will be the origin.
%    This means that the selected marker's coordinates will be [0, 0, 0]. All other coordinates will be translated.
%   -You can also use the coordinates as they come from the system, for instance for creating virtual markers.
% Input arguments are:
%   -> coordinates is a 1-by-N*3 array, containing the X-Y-Z position triplets for each marker.
%   -> origin_marker is the marker to be used as the origin. This is good for calibration
%       Set this to the appropriate number of marker to use that marker as origin. The manual calls this a 'local' coordinate system
%       If you don't want this feature, set it to 0, and the rigid body will be in the 'default' coordinate system.
%   -> filename is the path to where the rigid body file will be created.
%       If you want, you can set this to C:\ndigital\rigid\<your_rigid_body>.RIG
%       Make sure you have permission though.
%   -> coordinate_tolerance is the marker position tolerance in millimetres
%       It specifies how much the rigid body conversion error can be before the system decides that it wouldn't return a transformation.
%       Valid range is 0.05...10mm
%   -> normal_vector_coordinates is a 1-by-N array. The normal vectors are perpendicular to the marker's plane.
%       If unsure, just give it a bunch of zeros.
%       For simple rigid bodies, all normal vectors can point to the same direction
% Optional input argument is:
%   -> minimum_visible_markers is a number that tells the Optotrak system to give up transforming rigid bodies 
% Output argument is:
%   -fail, which is zero when everything worked out. There are built-in sanity checks and error messages in this script.

optotrak_is_a_coord_close_to_a_plane()

Sometimes you need to check if a coordinate is in the close vicinity of a virtual wall along a specific X, Y, or Z coordinate. This function allows you to check this with a single line of code.

%OPTOTRAK_IS_A_COORD_CLOSE_TO_A_PLANE This function returns 1 if a
%coordinate is close to a selected plane, and 0 if it isn't.
% Input arguments are:
%   -> coord_triplet is a 1-by-3 array, with the X-Y-Z coordinates 
%   -> plane is the X, Y, or Z plane you want to test for.
%      Give this arguments as a string, i.e. 'X', or 'z'
%   -> threshold is the distance in millimetres. If not specified, it
%      defaults to 5 mm.

optotrak_is_a_marker_close_to_a_plane()

Sometimes you need to check if a properly initialised and visible Optotrak marker is in the close vicinity of a virtual wall along a specific X, Y, or Z coordinate. This function allows you to check this with a single line of code.

%OPTOTRAK_IS_A_COORD_CLOSE_TO_A_PLANE This function returns 1 if a
%coordinate is close to a selected plane, and 0 if it isn't.
% Input arguments are:
%   -> coord_triplet is a 1-by-3 array, with the X-Y-Z coordinates 
%   -> plane is the X, Y, or Z plane you want to test for.
%      Give this arguments as a string, i.e. 'X', or 'z'
%   -> threshold is the distance in millimetres. If not specified, it
%      defaults to 5 mm.

optotrak_get_selected_triplet()

This function was written to extract a triplet (of marker coordinates, rigid body rotations and centroids) from a set of collected data. This can be a single frame (row), or in a matrix. You can specify a single entry as a number, or a bunch of entries in an array. The return values containing the selected coordinates are always concatenated together.

[ selected_triplet ] = optotrak_get_selected_triplet( triplet_number, data_array )
This is ideal for selecting the appropriate data for a single marker, or rigid body transforms
Input arguments are:
  -> triplet_number is the appropriate triplet in the marker array.
      for example:
          3 returns entries 7, 8, and 9
          [1, 3] returns the concatenation of 1, 2, 3 and 7, 8, 9
  -> data_array is the array the appropriate triplets are selected from.
Returns:
The selected triplet. If multiple tripets are selected, the triplets are concatenated.

NOTE: this function works on matrices too.

This is useful when you just want to extract a single or a handful of markers to work with, or you just want to quickly extract some marker data for some other function without having to worry about calculating the proper array index. For example:

my_favourite_centroid = optotrak_get_selected_triplet(7, rigid_body_translations);

This extracts the translation coordinates (as a single X-Y-Z triplet) from rigid_body_translations, which corresponds to entries 19, 20 and 21. If rigid_body_centroids contains say 500 frames, my_favourite_centroid will be a 500-by-1x3 matrix. If rigid_body_centroids is a vector indicating that only a single frame of coordinates are to be worked with, my_favourite_centroid will be a 1-by-1x3 vector as well.

teddy_markers = optotrak_get_selected_triplet([1, 8:10, 32], marker_data);

this selects 5 markers (1, 8, 9, 10, 32), and returns their X-Y-Z triplets. If marker_data contains a single frame (row), teddy_markers will be a 1-by-5x3 vector. If marker_data is a matrix of 1000 frames, teddy_markers will be a 1000-by-5x3 matrix. Note that the order of markers in the output will be exactly the same as you specify: Marker 8's X-Y-Z triplet will correspond to indices 4, 5 and 6 in teddy_markers.


Wrapper functions in C

Due to some limitations, some functions are implemented in C, and been made available as a .mex* file. these are listed below:

optotrak_tell_me_what_went_wrong()

This is a wrapper for OptotrakGetErrorString(), and it prints the output to Matlab's command window. This function is used quite frequently when generating error messages. I found that even though this function is working correctly, it doesn't fetch all the information. I regularly check opto.err, which is, in Windows, is located at C:\ndigital\logs\opto.err

RigidBodyAddFromFile_euler()

 * [fail] = RigidBodyAddFromFile_euler(rigid_body_id, start_marker, rigid_body_file);
 *
 * This is a wrapper for RigidBodyAddFromFile(), and it locks the user to use Euler (pitch, roll, yaw) angles with translation
 * Input arguments are:
 * -> rigid_body_id is the ID you want to assign
 * -> start_marker is the first marker of the rigid body. Start from 0.
 * -> no_of_markers is the number of markers on the rigid body. At least 3 are needed. The max is 512.
 * -> rigid_body_file is the file, which is by default in C:\ndigital/rigid/*.rig. Do not use the extension.

DataGetNext3D_as_array()

 * [fail, frame_counter, position3d_array, flags] = DataGetNext3D_as_array();
 *
 * This is a wrapper for DataGetNext3D(), but it returns the Position3D data as an array, as opposed to structure array.

This function returns real-time data as a 1-by-N array, where the position coordinates are stored in X-Y-Z triplets. Also, invisible markers are returned as NaNs. Otherwise, the function is identical to DataGetNext3D().

DataGetLatest3d_as_array()

 * [fail, frame_counter, position3d_array, flags] = DataGetLatest3D_as_array();
 *
 * This is a wrapper for DataGetLatest3D(), but it returns the Position3D data as an array, as opposed to structure array.

This function returns real-time data as a 1-by-n array, where the position coordinates are stored in X-Y-Z triplets. Also, invisible markers are returned as NaNs. Otherwise, the function is identical to DataGetLatest3D().

DataGetLatestTransforms2_as_array()

 * [fail, frame_counter, translation, rotation, positions, flags] = DataGetLatestTransforms2_as_array(number_of_markers);
 *
 * This is a wrapper for DataGetLatestTransforms2()
 * hint: if there are no rigid bodies defined, this function will fail.
 * note: The position 3D only gets returned to the number of markers you specify as the input argument.
 * -frame_counter is the number of frames since initialisation
 * -translation is a 1-by-n matrix in X-Y-Z triplets holding the rigid body translation data
 * -rotation is a 1-by-n matrix in roll-pitch-yaw radians.
 * -positions is the 1-by-n matrix of X-Y-Z marker positions

This function returns real-time data as two or three arrays: The translation and rotation of the defined rigid body, and the positions of a specified number of markers. If you don't want any marker positions, just set the input argument to be 0.

DataGetNextTransforms2_as_array()

 * [fail, frame_counter, translation, rotation, positions, flags] = DataGetNextTransforms2_as_array(number_of_markers);
 *
 * This is a wrapper for DataGetNextTransforms2()
 * hint: if there are no rigid bodies defined, this function will fail.
 * note: The position 3D only gets returned to the number of markers you specify as the input argument.
 * -frame_counter is the number of frames since initialisation
 * -translation is a 1-by-n matrix in X-Y-Z triplets holding the rigid body translation data
 * -rotation is a 1-by-n matrix in roll-pitch-yaw radians.
 * -positions is the 1-by-n matrix of X-Y-Z marker positions

This function returns real-time data as two or three arrays: The translation and rotation of the defined rigid body, and the positions of a specified number of markers. If you don't want any marker positions, just set the input argument to be 0.

optotrak_convert_raw_file_to_position3d_array

[fail, position3d_array] = convert_raw_file_to_position3d_array(input_file_name)
%This function reads a raw data file, and it converts the raw (or centroid) data to X-Y-Z triplets for each marker.
% Note that the system must be properly initialised first, as the number of markers and the camera file has to be loaded to the system
% Input arguments are:
%   -> input_file_name is the file name with path, to the raw data file you want to process.
% return values are:
% -fail is 0 when everything went well. You will get error messages if something failed during the conversion process
% -position3d_array is an array where each row is one frame, and each three columns are X-Y-Z triplets for a marker. i.e marker 1's Z coordinate is column 3, etc.

optotrak_convert_raw_file_to_rigid_euler_array

[fail, position3d_array, translation_array, rotation_array] = convert_raw_file_to_rigid_euler_array(input_file_name)
% This function reads the raw data, and executes rigid body transforms.
% Note that you must have the system properly initialised and your rigid bodies loaded/defined if you want this function to work.
% Input arguments are:
%   -> input_file_name is the name and path to the raw data you want to process.
% Returns:
% -fail is 0 when everything went well. You will get error messages if something failed during the conversion process
% -position3d_array is an array where each row is one frame, and each three columns are X-Y-Z triplets for a marker. i.e marker 1's Z coordinate is column 3, etc.
% -translation_array is the X-Y-Z coordinates of the rigid body. Each row is a frame, and each triplet belongs to a rigid body.
% -rotation array is the roll-pitch-yaw rotation angles IN RADIANS. Each row is a frame, and each triplet belongs to a rigid body.

optotrak_align_coordinate_system()

Please read about Calibration first to avoid confusion, frustration and disappointment.

This is a wrapper function for nOptotrakAlignSystem(), The problem is that the AlignParametersStruct typedef is incorrectly read into Matlab.
% So, I made this file, which accepts the structure fields as command-line arguments. Also I hard-coded verbosity.
% Matlab declaration is:
% [fail, tolerance] = optotrak_align_system(old_camera_file_name, path_to_recording, path_to_rigid_body, new_camera_file_name, logfile_name)
% Input arguments are:
%   -> old_camera_file_name is the camera parameter file the raw data was recorded with. Usually, it's 'standard'.
%   -> path_to_recording is where the raw data file is
%   -> path_to_rigid_body is either the name of the rigid body file in the rigid body directory, or the full path to the .rig file itself. Must be the same one the recording was made with.
%   -> new_camera_file is the name of the camera file the alignment function is going to generate. You will need to use this in your experiments later-on.
%   -> logfile_ane, is the path or name of the log file the alignment algorithm will generate.
% fail is a failure indicator. A nnonzero value of fail tells you something went wrong.
% tolerance is the introduced error is millimetres. Re-aligning the coordinate system usually results in some interpolation errors. Typically it's a fraction of a millimetre.

optotrak_register_system_static()

Please read about Calibration first to avoid confusion, frustration and disappointment.

This is a C wrapper function for nOptotrakCalibrigSystem(). It alllows the registration of many cameras together into a common coordinate system.
% This function supposed to handle static rigid bodies in the recordings.
% The problem is that the RegisterParametersStruct typedef is incorrectly read into Matlab.
% So, I made this file, which accepts the structure fields as command-line arguments. Also I hard-coded verbosity.
% Matlab declaration is:
% [fail, tolerance] = optotrak_align_system(old_camera_file_name, path_to_recording, path_to_rigid_body, new_camera_file_name, logfile_name)
% Input arguments are:
%   -> old_camera_file_name is the camera parameter file the raw data was recorded with. Usually, it's 'standard'.
%   -> path_to_recording is where the raw data file is
%   -> path_to_rigid_body is either the name of the rigid body file in the rigid body directory, or the full path to the .rig file itself. Must be the same one the recording was made with.
%   -> new_camera_file is the name of the camera file the registration function is going to generate. You most probably will need to process it further, so it will align to your coordinate system.
%   -> logfile_ane, is the path or name of the log file the registration algorithm will generate.
% fail is a failure indicator. A nnonzero value of fail tells you something went wrong.
% tolerance is the introduced error is millimetres. Re-aligning the coordinate system usually results in some interpolation errors. Typically it's a fraction of a millimetre.

optotrak_register_system_dynamic()

Please read about Calibration first to avoid confusion, frustration and disappointment.

This is a C wrapper function for nOptotrakRegistergSystem(). It alllows the registration of many cameras together into a common coordinate system.
% This function supposed to handle rigid bodies that move about in the recordings.
% The problem is that the RegisterParametersStruct typedef is incorrectly read into Matlab.
% So, I made this file, which accepts the structure fields as command-line arguments. Also I hard-coded verbosity.
% Matlab declaration is:
% [fail, tolerance] = optotrak_align_system(old_camera_file_name, path_to_recording, path_to_rigid_body, new_camera_file_name, logfile_name)
% Input arguments are:
%   -> old_camera_file_name is the camera parameter file the raw data was recorded with. Usually, it's 'standard'.
%   -> path_to_recording is where the raw data file is
%   -> path_to_rigid_body is either the name of the rigid body file in the rigid body directory, or the full path to the .rig file itself. Must be the same one the recording was made with.
%   -> new_camera_file is the name of the camera file the registration function is going to generate. You most probably will need to process it further, so it will align to your coordinate system.
%   -> logfile_ane, is the path or name of the log file the registration algorithm will generate.
% fail is a failure indicator. A nnonzero value of fail tells you something went wrong.
% tolerance is the introduced error is millimetres. Re-aligning the coordinate system usually results in some interpolation errors. Typically it's a fraction of a millimetre.
Clone this wiki locally