int define_Computed_field_type_connected_threshold_image_filter(struct Parse_state *state,
	void *field_modify_void, void *computed_field_simple_package_void)
/*******************************************************************************
LAST MODIFIED : 30 August 2006

DESCRIPTION :
Converts <field> into type COMPUTED_FIELD_CONNECTED_THRESHOLD_IMAGE_FILTER (if it is not
already) and allows its contents to be modified.
==============================================================================*/
{
	double lower_threshold, upper_threshold, replace_value;
	int num_seed_points;
	int seed_dimension;
  double *seed_points;
	int return_code;
	int seed_points_length;
	int previous_state_index, expected_parameters;

	struct Computed_field *source_field;
	Computed_field_modify_data *field_modify;
	struct Option_table *option_table;
	struct Set_Computed_field_conditional_data set_source_field_data;

	ENTER(define_Computed_field_type_connected_threshold_image_filter);
	USE_PARAMETER(computed_field_simple_package_void);
	if (state && (field_modify=(Computed_field_modify_data *)field_modify_void))
	{
		return_code = 1;

		source_field = (struct Computed_field *)NULL;
		lower_threshold = 0.0;
		upper_threshold = 1.0;
		replace_value = 1;
		num_seed_points = 0;
		seed_dimension  = 2;
		seed_points = (double *)NULL;

		// should probably default to having 1 seed point
		//		seed_points[0] = 0.5;  // pjb: is this ok?
		//		seed_points[1] = 0.5;
		seed_points_length = 0;

		/* get valid parameters for projection field */
		if ((NULL != field_modify->get_field()) &&
			(computed_field_connected_threshold_image_filter_type_string ==
				Computed_field_get_type_string(field_modify->get_field())))
		{
			return_code =
				Cmiss_field_get_type_connected_threshold_image_filter(field_modify->get_field(), &source_field,
				&lower_threshold, &upper_threshold, &replace_value,
		  &num_seed_points, &seed_dimension, &seed_points);
		}
		if (return_code)
		{

			if (source_field)
			{
				ACCESS(Computed_field)(source_field);
			}

			if (state->current_token &&
				(!(strcmp(PARSER_HELP_STRING, state->current_token)&&
					strcmp(PARSER_RECURSIVE_HELP_STRING, state->current_token))))
			{
				/* Handle help separately */
				option_table = CREATE(Option_table)();
			Option_table_add_help(option_table,
				"The connected_threshold_filter field uses the itk::ConnectedThresholdImageFilter code to segment a field. The <field> it operates on is usually a sample_texture field, based on a texture that has been created from image file(s).  The segmentation is based on a region growing algorithm which requires at least one seed point.  To specify the seed points first set the <num_seed_points> and the <dimension> of the image.  The <seed_points> are a list of the coordinates for the first and any subsequent seed points.  Starting from the seed points any neighbouring pixels with an intensity between <lower_threshold> and the <upper_threshold> are added to the region.  Pixels within the region have their pixel intensity set to <replace_value> while the remaining pixels are set to 0. See a/testing/image_processing_2D for an example of using this field.  For more information see the itk software guide.");

				/* field */
				set_source_field_data.computed_field_manager =
					field_modify->get_field_manager();
				set_source_field_data.conditional_function = Computed_field_is_scalar;
				set_source_field_data.conditional_function_user_data = (void *)NULL;
				Option_table_add_entry(option_table, "field", &source_field,
															 &set_source_field_data, set_Computed_field_conditional);
				/* lower_threshold */
				Option_table_add_double_entry(option_table, "lower_threshold",
																			&lower_threshold);
				/* upper_threshold */
				Option_table_add_double_entry(option_table, "upper_threshold",
																			&upper_threshold);
				/* replace_value */
				Option_table_add_double_entry(option_table, "replace_value",
																			&replace_value);
				/* num_seed_points */
				Option_table_add_int_positive_entry(option_table, "num_seed_points",
																						&num_seed_points);
				Option_table_add_int_positive_entry(option_table, "dimension",
																						&seed_dimension);
				Option_table_add_double_vector_entry(option_table, "seed_points",
																						 seed_points, &seed_points_length);
				return_code = Option_table_multi_parse(option_table, state);
				DESTROY(Option_table)(&option_table);
			}

			if (return_code)
			{

				// store previous state so that we can return to it
				previous_state_index = state->current_index;

				/* parse the two options which determine the number of seed values
					 and hence the size of the array that must be created to read in
					 the number of seed values. */

				option_table = CREATE(Option_table)();
				/* num_seed_points */
				Option_table_add_int_positive_entry(option_table, "num_seed_points",
																						&num_seed_points);
				/* dimension */
				Option_table_add_int_positive_entry(option_table, "dimension",
																						&seed_dimension);
				/* Ignore all the other entries */
				Option_table_ignore_all_unmatched_entries(option_table);
				return_code = Option_table_multi_parse(option_table, state);
				DESTROY(Option_table)(&option_table);
				/* Return back to where we were */
				shift_Parse_state(state, previous_state_index - state->current_index);

			}

			/* parse the rest of the table */
			if (return_code)
			{
				seed_points_length = num_seed_points * seed_dimension;

				REALLOCATE(seed_points, seed_points, double, seed_points_length);
				// pjb: should I populate array with dummy values?

				option_table = CREATE(Option_table)();
				/* field */
				set_source_field_data.computed_field_manager =
					field_modify->get_field_manager();
				set_source_field_data.conditional_function = Computed_field_is_scalar;
				set_source_field_data.conditional_function_user_data = (void *)NULL;
				Option_table_add_entry(option_table, "field", &source_field,
															 &set_source_field_data, set_Computed_field_conditional);
				/* lower_threshold */
				Option_table_add_double_entry(option_table, "lower_threshold",
																			&lower_threshold);
				/* upper_threshold */
				Option_table_add_double_entry(option_table, "upper_threshold",
																			&upper_threshold);
				/* replace_value */
				Option_table_add_double_entry(option_table, "replace_value",
																			&replace_value);
				expected_parameters = 1;
				Option_table_add_ignore_token_entry(option_table, "num_seed_points",
																						&expected_parameters);
				expected_parameters = 1;
				Option_table_add_ignore_token_entry(option_table, "dimension",
																						&expected_parameters);
				Option_table_add_double_vector_entry(option_table, "seed_points",
																						 seed_points, &seed_points_length);
				return_code=Option_table_multi_parse(option_table,state);
				DESTROY(Option_table)(&option_table);
			}

			/* no errors,not asking for help */
			if (return_code)
			{
				if (!source_field)
				{
					display_message(ERROR_MESSAGE,
						"define_Computed_field_type_connected_threshold_image_filter.  "
						"Missing source field");
					return_code = 0;
				}
			}
			if (return_code)
			{
				return_code = field_modify->update_field_and_deaccess(
					Cmiss_field_module_create_connected_threshold_image_filter(
						field_modify->get_field_module(),
						source_field, lower_threshold, upper_threshold, replace_value,
						num_seed_points, seed_dimension, seed_points));
			}

			if (!return_code)
			{
				if ((!state->current_token) ||
					(strcmp(PARSER_HELP_STRING, state->current_token)&&
						strcmp(PARSER_RECURSIVE_HELP_STRING, state->current_token)))
				{
					/* error */
					display_message(ERROR_MESSAGE,
						"define_Computed_field_type_connected_threshold_image_filter.  Failed");
				}
			}

			if (source_field)
			{
				DEACCESS(Computed_field)(&source_field);
			}

			if (seed_points) {
				DEALLOCATE(seed_points);
			}
		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"define_Computed_field_type_connected_threshold_image_filter.  Invalid argument(s)");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* define_Computed_field_type_connected_threshold_image_filter */
int define_Computed_field_type_fast_marching_image_filter(struct Parse_state *state,
	void *field_modify_void, void *computed_field_simple_package_void)
/*******************************************************************************
LAST MODIFIED : 30 August 2006

DESCRIPTION :
Converts <field> into type COMPUTED_FIELD_FAST_MARCHING_IMAGE_FILTER (if it is not
already) and allows its contents to be modified.
==============================================================================*/
{
	double stopping_value;
	int num_seed_points;
	int dimension;
	double *seed_points;
	double *seed_values;
	int *output_size;
	int length_seed_points;
	int return_code;
	int previous_state_index;
	int i;

	struct Computed_field *source_field;
	Computed_field_modify_data *field_modify;
	struct Option_table *option_table;
	struct Set_Computed_field_conditional_data set_source_field_data;

	ENTER(define_Computed_field_type_fast_marching_image_filter);
	USE_PARAMETER(computed_field_simple_package_void);
	if (state && (field_modify=(Computed_field_modify_data *)field_modify_void))
	{
		return_code = 1;

		source_field = (struct Computed_field *)NULL;
		stopping_value = 100;
		num_seed_points = 1;
		dimension  = 2;
		length_seed_points = num_seed_points * dimension;

		seed_points = (double *)NULL;
		seed_values = (double *)NULL;
		output_size = (int *)NULL;

		ALLOCATE(seed_points, double, length_seed_points);
		ALLOCATE(seed_values, double, num_seed_points);
		ALLOCATE(output_size, int, dimension);

		// should probably default to having 1 seed
		seed_points[0] = 0.5;  // pjb: is this ok?
		seed_points[1] = 0.5;
		seed_values[0] = 0.0;
		output_size[0] = 128;
		output_size[1] = 128;

		/* get valid parameters for projection field */
		if ((NULL != field_modify->get_field()) &&
			(computed_field_fast_marching_image_filter_type_string ==
				Computed_field_get_type_string(field_modify->get_field())))
		{
			return_code =
				cmzn_field_get_type_fast_marching_image_filter(field_modify->get_field(), &source_field,
				  &stopping_value, &num_seed_points, &dimension, &seed_points, &seed_values, &output_size);
		}
		if (return_code)
		{

			if (source_field)
			{
				ACCESS(Computed_field)(source_field);
			}

			if (state->current_token &&
				(!(strcmp(PARSER_HELP_STRING, state->current_token)&&
					strcmp(PARSER_RECURSIVE_HELP_STRING, state->current_token))))
			{
				/* Handle help separately */
				option_table = CREATE(Option_table)();
				Option_table_add_help(option_table,
					"The fast_marching_filter field uses the itk::FastMarchingImageFilter code to segment a field. The segmentation is based on a level set algorithm.  The <field> it operates on is used as a speed term, to govern where the level set curve grows quickly.  The speed term is usually some function (eg a sigmoid) of an image gradient field.  The output field is a time crossing map, where the value at is each pixel is the time take to reach that location from the specified seed points.  Values typically range from 0 through to extremely large (10 to the 38).  To convert the time cross map into a segmented region use a binary threshold filter. To specify the seed points first set the <num_seed_points> and the <dimension> of the image.  The <seed_points> are a list of the coordinates for the first and any subsequent seed points.   It is also possible to specify non-zero initial <seed_values> if desired and to set the <output_size> of the time crossing map. See a/segmentation for an example of using this field.  For more information see the itk software guide.");

				/* field */
				set_source_field_data.computed_field_manager =
					field_modify->get_field_manager();
				set_source_field_data.conditional_function = Computed_field_is_scalar;
				set_source_field_data.conditional_function_user_data = (void *)NULL;
				Option_table_add_entry(option_table, "field", &source_field,
					&set_source_field_data, set_Computed_field_conditional);
				/* stopping_value */
				Option_table_add_double_entry(option_table, "stopping_value",
																			&stopping_value);
				/* num_seed_points */
				Option_table_add_int_positive_entry(option_table, "num_seed_points",
																						&num_seed_points);
				/* dimension */
				Option_table_add_int_positive_entry(option_table, "dimension",
																						&dimension);
				/* seed_points */
				Option_table_add_double_vector_entry(option_table, "seed_points",
																						 seed_points, &length_seed_points);
				/* seed_values */
				Option_table_add_double_vector_entry(option_table, "seed_values",
																						 seed_values, &num_seed_points);
				/* output_size */
				Option_table_add_int_vector_entry(option_table, "output_size",
																						 output_size, &dimension);

				return_code = Option_table_multi_parse(option_table, state);
				DESTROY(Option_table)(&option_table);
			}

			if (return_code)
			{

				// store previous state so that we can return to it
				previous_state_index = state->current_index;

				/* parse the two options which determine the number of seed values
					 and hence the size of the array that must be created to read in
					 the number of seed values. */

				option_table = CREATE(Option_table)();
				/* num_seed_points */
				Option_table_add_int_positive_entry(option_table, "num_seed_points",
																						&num_seed_points);
				/* dimension */
				Option_table_add_int_positive_entry(option_table, "dimension",
																						&dimension);
				/* Ignore all the other entries */
				Option_table_ignore_all_unmatched_entries(option_table);
				return_code = Option_table_multi_parse(option_table, state);
				DESTROY(Option_table)(&option_table);

				/* Return back to where we were */
				shift_Parse_state(state, previous_state_index - state->current_index);

			}

			/* parse the rest of the table */
			if (return_code)
			{
				length_seed_points = num_seed_points * dimension;

				/* reallocate memory for arrays */
				REALLOCATE(seed_points, seed_points, double, length_seed_points);
				REALLOCATE(seed_values, seed_values, double, num_seed_points);
				REALLOCATE(output_size, output_size, int, dimension);

				/* set default values, in case options are not specified in field definition. */
				for (i=0; i < length_seed_points ;i++) {
					seed_points[i] = 0;
				}
				for (i=0; i < num_seed_points ;i++) {
					seed_values[i] = 0;
				}
				for (i=0; i < dimension ;i++) {
					output_size[i] = 128;
				}

				option_table = CREATE(Option_table)();
				/* field */
				set_source_field_data.computed_field_manager =
					field_modify->get_field_manager();
				set_source_field_data.conditional_function = Computed_field_is_scalar;
				set_source_field_data.conditional_function_user_data = (void *)NULL;
				Option_table_add_entry(option_table, "field", &source_field,
															 &set_source_field_data, set_Computed_field_conditional);
				/* stopping_value */
				Option_table_add_double_entry(option_table, "stopping_value",
					&stopping_value);
				int num_seed_points_expected_parameters = 1;
				Option_table_add_ignore_token_entry(option_table, "num_seed_points",
					&num_seed_points_expected_parameters);
				int dimension_expected_parameters = 1;
				Option_table_add_ignore_token_entry(option_table, "dimension",
					&dimension_expected_parameters);
				Option_table_add_double_vector_entry(option_table, "seed_points",
					seed_points, &length_seed_points);
				Option_table_add_double_vector_entry(option_table, "seed_values",
					seed_values, &num_seed_points);
				Option_table_add_int_vector_entry(option_table, "output_size",
					output_size, &dimension);

				return_code=Option_table_multi_parse(option_table,state);
				DESTROY(Option_table)(&option_table);

			}

			/* no errors,not asking for help */
			if (return_code)
			{
				if (!source_field)
				{
					display_message(ERROR_MESSAGE,
						"define_Computed_field_type_fast_marching_image_filter.  "
						"Missing source field");
					return_code = 0;
				}
			}
			if (return_code)
			{
				return_code = field_modify->update_field_and_deaccess(
					cmzn_fieldmodule_create_field_imagefilter_fast_marching(
						field_modify->get_field_module(),
						source_field, stopping_value, num_seed_points, dimension,
						seed_points, seed_values, output_size));
			}

			if (!return_code)
			{
				if ((!state->current_token) ||
					(strcmp(PARSER_HELP_STRING, state->current_token)&&
						strcmp(PARSER_RECURSIVE_HELP_STRING, state->current_token)))
				{
					/* error */
					display_message(ERROR_MESSAGE,
						"define_Computed_field_type_fast_marching_image_filter.  Failed");
				}
			}

			if (source_field)
			{
				DEACCESS(Computed_field)(&source_field);
			}

			if (seed_points) {
				DEALLOCATE(seed_points);
			}

			if (seed_values) {
				DEALLOCATE(seed_values);
			}

			if (output_size) {
				DEALLOCATE(output_size);
			}

		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"define_Computed_field_type_fast_marching_image_filter.  Invalid argument(s)");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* define_Computed_field_type_fast_marching_image_filter */