/* * Copyright (C) 2011-2014 Karlsruhe Institute of Technology * * This file is part of Ufo. * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include #include #ifdef __APPLE__ #include #else #include #endif #include "ufo-anka-backproject-task.h" #include "lamino-roi.h" /* Copy only neccessary projection region */ /* TODO: make this a parameter? */ /* Wait with enabling this until sync issues in ufo-core have been solved */ #define COPY_PROJECTION_REGION 0 #define EXTRACT_FLOAT(region, index) g_value_get_float (g_value_array_get_nth ((region), (index))) #define REGION_SIZE(region) ((EXTRACT_INT ((region), 2)) == 0) ? 0 : \ ((EXTRACT_INT ((region), 1) - EXTRACT_INT ((region), 0) - 1) /\ EXTRACT_INT ((region), 2) + 1) #define PAD_TO_DIVIDE(dividend, divisor) ((dividend) + (divisor) - (dividend) % (divisor)) /** * SECTION:ufo-anka-backproject-task * @Short_description: Backproject projection by projection * @Title: anka_backproject * */ typedef enum { PARAM_Z, PARAM_CENTER, PARAM_LAMINO, PARAM_ROLL } Param; struct _UfoAnkaBackprojectTaskPrivate { /* private */ gboolean generated; guint count; /* sine and cosine table size based on BURST */ gsize table_size; /* OpenCL */ cl_context context; cl_kernel vector_kernel; cl_kernel scalar_kernel; cl_sampler sampler; /* Buffered images for invoking backprojection on BURST projections at once. * We potentially don't need to copy the last image and can use the one from * framework directly but it seems to have no performance effects. */ cl_mem images[BURST]; /* properties */ GValueArray *x_region; GValueArray *y_region; GValueArray *region; GValueArray *center; GValueArray *projection_offset; float sines[BURST], cosines[BURST]; guint num_projections; gfloat overall_angle; gfloat tomo_angle; gfloat lamino_angle; gfloat z; gfloat roll_angle; Param parameter; }; static void ufo_task_interface_init (UfoTaskIface *iface); G_DEFINE_TYPE_WITH_CODE (UfoAnkaBackprojectTask, ufo_anka_backproject_task, UFO_TYPE_TASK_NODE, G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK, ufo_task_interface_init)) #define UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ANKA_BACKPROJECT_TASK, UfoAnkaBackprojectTaskPrivate)) enum { PROP_0, PROP_X_REGION, PROP_Y_REGION, PROP_Z, PROP_REGION, PROP_PROJECTION_OFFSET, PROP_CENTER, PROP_NUM_PROJECTIONS, PROP_OVERALL_ANGLE, PROP_TOMO_ANGLE, PROP_LAMINO_ANGLE, PROP_PARAMETER, PROP_ROLL_ANGLE, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES] = { NULL, }; static void set_region (GValueArray *src, GValueArray **dst) { if (EXTRACT_INT (src, 0) > EXTRACT_INT (src, 1)) { g_log ("Ufo", G_LOG_LEVEL_CRITICAL, "Error <%s:%i>: Invalid region [\"from\", \"to\", \"step\"]: [%d, %d, %d], "\ "\"from\" has to be less than or equal to \"to\"", __FILE__, __LINE__, EXTRACT_INT (src, 0), EXTRACT_INT (src, 1), EXTRACT_INT (src, 2)); } else { g_value_array_free (*dst); *dst = g_value_array_copy (src); } } static void copy_to_image (UfoBuffer *input, cl_mem output_image, cl_command_queue cmd_queue, size_t origin[3], size_t region[3], gint in_width) { const UfoBufferLocation location = ufo_buffer_get_location (input); cl_mem input_data; cl_event event; gfloat *input_data_host; size_t src_offset; input_data = ufo_buffer_get_device_image (input, cmd_queue); UFO_RESOURCES_CHECK_CLERR (clEnqueueCopyImage (cmd_queue, input_data, output_image, origin, origin, region, 0, NULL, &event)); UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event)); UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event)); } UfoNode * ufo_anka_backproject_task_new (void) { return UFO_NODE (g_object_new (UFO_TYPE_ANKA_BACKPROJECT_TASK, NULL)); } static void ufo_anka_backproject_task_setup (UfoTask *task, UfoResources *resources, GError **error) { UfoAnkaBackprojectTaskPrivate *priv; cl_int cl_error; gint i; gchar *vector_kernel_name, *kernel_filename; vector_kernel_name = g_strdup_printf ("backproject_burst_%d", BURST); if (!vector_kernel_name) { g_warning ("Error making burst kernel name"); } priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); priv->context = ufo_resources_get_context (resources); switch (priv->parameter) { case PARAM_Z: kernel_filename = g_strdup ("z_kernel.cl"); break; case PARAM_CENTER: kernel_filename = g_strdup ("center_kernel.cl"); break; case PARAM_LAMINO: kernel_filename = g_strdup ("lamino_kernel.cl"); break; case PARAM_ROLL: kernel_filename = g_strdup ("roll_kernel.cl"); break; default: g_warning ("Unkown varying parameter"); break; } priv->vector_kernel = ufo_resources_get_kernel (resources, kernel_filename, vector_kernel_name, error); priv->scalar_kernel = ufo_resources_get_kernel (resources, kernel_filename, "backproject_burst_1", error); priv->sampler = clCreateSampler (priv->context, (cl_bool) FALSE, CL_ADDRESS_CLAMP, CL_FILTER_LINEAR, &cl_error); UFO_RESOURCES_CHECK_CLERR (clRetainContext (priv->context)); UFO_RESOURCES_CHECK_CLERR (cl_error); if (priv->vector_kernel) { UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->vector_kernel)); } if (priv->scalar_kernel) { UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->scalar_kernel)); } for (i = 0; i < BURST; i++) { priv->images[i] = NULL; } switch (BURST) { case 1: priv->table_size = sizeof (cl_float); break; case 2: priv->table_size = sizeof (cl_float2); break; case 4: priv->table_size = sizeof (cl_float4); break; case 8: priv->table_size = sizeof (cl_float8); break; case 16: priv->table_size = sizeof (cl_float16); break; default: g_warning ("Unsupported vector size"); break; } g_free (vector_kernel_name); g_free (kernel_filename); } static void ufo_anka_backproject_task_get_requisition (UfoTask *task, UfoBuffer **inputs, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; gfloat start, stop, step; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); start = EXTRACT_FLOAT (priv->region, 0); stop = EXTRACT_FLOAT (priv->region, 1); step = EXTRACT_FLOAT (priv->region, 2); if (!priv->num_projections) { g_warning ("Number of projections has not been set"); } if (step == 0.0f) { g_warning ("Step in region is 0"); } requisition->n_dims = 3; requisition->dims[0] = REGION_SIZE (priv->x_region); requisition->dims[1] = REGION_SIZE (priv->y_region); requisition->dims[2] = (gint) ceil ((stop - start) / step); } static guint ufo_anka_backproject_task_get_num_inputs (UfoTask *task) { return 1; } static guint ufo_anka_backproject_task_get_num_dimensions (UfoTask *task, guint input) { g_return_val_if_fail (input == 0, 0); return 3; } static gboolean ufo_anka_backproject_task_equal_real (UfoNode *n1, UfoNode *n2) { g_return_val_if_fail (UFO_IS_ANKA_BACKPROJECT_TASK (n1) && UFO_IS_ANKA_BACKPROJECT_TASK (n2), FALSE); return UFO_ANKA_BACKPROJECT_TASK (n1)->priv->vector_kernel == UFO_ANKA_BACKPROJECT_TASK (n2)->priv->vector_kernel; } static UfoTaskMode ufo_anka_backproject_task_get_mode (UfoTask *task) { return UFO_TASK_MODE_REDUCTOR | UFO_TASK_MODE_GPU; } static gboolean ufo_anka_backproject_task_process (UfoTask *task, UfoBuffer **inputs, UfoBuffer *output, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; UfoRequisition in_req; UfoGpuNode *node; UfoProfiler *profiler; gfloat tomo_angle, *sines, *cosines; gint i, index; gint cumulate; gsize table_size; gboolean scalar; /* regions stripped off the "to" value */ gfloat x_region[2], y_region[2], z_region[2], x_center[2], z_ends[2], lamino_angles[2], roll_angles[2], y_center, sin_lamino, cos_lamino, norm_factor, sin_roll, cos_roll; gint x_copy_region[2], y_copy_region[2]; cl_kernel kernel; cl_command_queue cmd_queue; cl_mem out_mem; cl_int cl_error; /* image creation and copying */ cl_image_format image_fmt; size_t origin[3]; size_t region[3]; /* keep the warp size satisfied but make sure the local grid is localized * around a point in 3D for efficient caching */ const gint real_size[4] = {requisition->dims[0], requisition->dims[1], requisition->dims[2], 0}; const gsize local_work_size[] = {16, 8, 8}; gsize global_work_size[3]; global_work_size[0] = requisition->dims[0] % local_work_size[0] ? PAD_TO_DIVIDE (requisition->dims[0], local_work_size[0]) : requisition->dims[0]; global_work_size[1] = requisition->dims[1] % local_work_size[1] ? PAD_TO_DIVIDE (requisition->dims[1], local_work_size[1]) : requisition->dims[1]; global_work_size[2] = requisition->dims[2] % local_work_size[2] ? PAD_TO_DIVIDE (requisition->dims[2], local_work_size[2]) : requisition->dims[2]; priv = UFO_ANKA_BACKPROJECT_TASK (task)->priv; node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task))); cmd_queue = ufo_gpu_node_get_cmd_queue (node); out_mem = ufo_buffer_get_device_array (output, cmd_queue); ufo_buffer_get_requisition (inputs[0], &in_req); index = priv->count % BURST; tomo_angle = priv->tomo_angle > -G_MAXFLOAT ? priv->tomo_angle : priv->overall_angle * priv->count / priv->num_projections; norm_factor = fabs (priv->overall_angle) / priv->num_projections; priv->sines[index] = sin (tomo_angle); priv->cosines[index] = cos (tomo_angle); x_region[0] = (gfloat) EXTRACT_INT (priv->x_region, 0); x_region[1] = (gfloat) EXTRACT_INT (priv->x_region, 2); y_region[0] = (gfloat) EXTRACT_INT (priv->y_region, 0); y_region[1] = (gfloat) EXTRACT_INT (priv->y_region, 2); if (priv->parameter == PARAM_Z) { z_ends[0] = z_region[0] = EXTRACT_FLOAT (priv->region, 0); z_region[1] = EXTRACT_FLOAT (priv->region, 2); z_ends[1] = EXTRACT_FLOAT (priv->region, 1); } else { z_ends[0] = z_region[0] = priv->z; z_ends[1] = priv->z + 1.0f; } if (priv->parameter == PARAM_CENTER) { x_center[0] = EXTRACT_FLOAT (priv->region, 0) - EXTRACT_INT (priv->projection_offset, 0); x_center[1] = EXTRACT_FLOAT (priv->region, 2); } else { x_center[0] = x_center[1] = EXTRACT_FLOAT (priv->center, 0) - EXTRACT_INT (priv->projection_offset, 0); } if (priv->parameter == PARAM_LAMINO) { lamino_angles[0] = EXTRACT_FLOAT (priv->region, 0); lamino_angles[1] = EXTRACT_FLOAT (priv->region, 2); } else { lamino_angles[0] = lamino_angles[1] = priv->lamino_angle; } if (priv->parameter == PARAM_ROLL) { roll_angles[0] = EXTRACT_FLOAT (priv->region, 0); roll_angles[1] = EXTRACT_FLOAT (priv->region, 2); } else { roll_angles[0] = roll_angles[1] = priv->roll_angle; } y_center = EXTRACT_FLOAT (priv->center, 1) - EXTRACT_INT (priv->projection_offset, 1); sin_lamino = sinf (priv->lamino_angle); cos_lamino = cosf (priv->lamino_angle); /* Minus the value because we are rotating back */ sin_roll = sinf (-priv->roll_angle); cos_roll = cosf (-priv->roll_angle); scalar = priv->count >= priv->num_projections / BURST * BURST ? 1 : 0; /* If COPY_PROJECTION_REGION is True we copy only the part necessary */ /* for a given tomographic and laminographic angle */ /* TODO: Extend the region determination to be able to handle PARAM_LAMINO */ if (COPY_PROJECTION_REGION && priv->parameter != PARAM_LAMINO) { determine_x_region (x_copy_region, priv->x_region, priv->y_region, tomo_angle, EXTRACT_FLOAT (priv->center, 0), in_req.dims[0]); determine_y_region (y_copy_region, priv->x_region, priv->y_region, z_ends, tomo_angle, priv->lamino_angle, EXTRACT_FLOAT (priv->center, 1), in_req.dims[1]); origin[0] = x_copy_region[0]; origin[1] = y_copy_region[0]; origin[2] = 0; region[0] = x_copy_region[1] - x_copy_region[0]; region[1] = y_copy_region[1] - y_copy_region[0]; } else { origin[0] = origin[1] = origin[2] = 0; region[0] = in_req.dims[0]; region[1] = in_req.dims[1]; } region[2] = 1; if (priv->images[index] == NULL) { /* TODO: dangerous, don't rely on the ufo-buffer */ image_fmt.image_channel_order = CL_INTENSITY; image_fmt.image_channel_data_type = CL_FLOAT; /* TODO: what with the "other" API? */ priv->images[index] = clCreateImage2D (priv->context, CL_MEM_READ_ONLY, &image_fmt, in_req.dims[0], in_req.dims[1], 0, NULL, &cl_error); UFO_RESOURCES_CHECK_CLERR (cl_error); } copy_to_image (inputs[0], priv->images[index], cmd_queue, origin, region, in_req.dims[0]); if (scalar) { kernel = priv->scalar_kernel; cumulate = priv->count; table_size = sizeof (cl_float); sines = &priv->sines[index]; cosines = &priv->cosines[index]; i = 1; UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof (cl_mem), &priv->images[index])); } else { kernel = priv->vector_kernel; cumulate = priv->count + 1 == BURST ? 0 : 1; table_size = priv->table_size; sines = priv->sines; cosines = priv->cosines; i = BURST; UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, index, sizeof (cl_mem), &priv->images[index])); } if (scalar || index == BURST - 1) { /* Execute the kernel after BURST images have arrived, i.e. we use more * projections at one invocation, so the number of read/writes to the * result is reduced by a factor of BURST. If there are not enough * projecttions left, execute the scalar kernel */ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_mem), &out_mem)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_sampler), &priv->sampler)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_int3), real_size)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), x_center)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), (cl_float *) &y_center)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), x_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), y_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), z_region)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), lamino_angles)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float2), roll_angles)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &sin_lamino)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &cos_lamino)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, table_size, sines)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, table_size, cosines)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &norm_factor)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &sin_roll)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i++, sizeof (cl_float), &cos_roll)); UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, i, sizeof (cl_int), (cl_int *) &cumulate)); profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (task)); ufo_profiler_call (profiler, cmd_queue, kernel, 3, global_work_size, local_work_size); } priv->count++; return TRUE; } static gboolean ufo_anka_backproject_task_generate (UfoTask *task, UfoBuffer *output, UfoRequisition *requisition) { UfoAnkaBackprojectTaskPrivate *priv; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (task); if (priv->generated) { return FALSE; } priv->generated = TRUE; return TRUE; } static void ufo_anka_backproject_task_finalize (GObject *object) { UfoAnkaBackprojectTaskPrivate *priv; gint i; priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); g_value_array_free (priv->x_region); g_value_array_free (priv->y_region); g_value_array_free (priv->region); g_value_array_free (priv->projection_offset); g_value_array_free (priv->center); if (priv->vector_kernel) { UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->vector_kernel)); priv->vector_kernel = NULL; } if (priv->scalar_kernel) { UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (priv->scalar_kernel)); priv->scalar_kernel = NULL; } if (priv->context) { UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context)); priv->context = NULL; } if (priv->sampler) { UFO_RESOURCES_CHECK_CLERR (clReleaseSampler (priv->sampler)); priv->sampler = NULL; } for (i = 0; i < BURST; i++) { if (priv->images[i] != NULL) { UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->images[i])); priv->images[i] = NULL; } } G_OBJECT_CLASS (ufo_anka_backproject_task_parent_class)->finalize (object); } static void ufo_task_interface_init (UfoTaskIface *iface) { iface->setup = ufo_anka_backproject_task_setup; iface->get_requisition = ufo_anka_backproject_task_get_requisition; iface->get_num_inputs = ufo_anka_backproject_task_get_num_inputs; iface->get_num_dimensions = ufo_anka_backproject_task_get_num_dimensions; iface->get_mode = ufo_anka_backproject_task_get_mode; iface->process = ufo_anka_backproject_task_process; iface->generate = ufo_anka_backproject_task_generate; } static void ufo_anka_backproject_task_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); GValueArray *array; switch (property_id) { case PROP_X_REGION: array = (GValueArray *) g_value_get_boxed (value); set_region (array, &priv->x_region); break; case PROP_Y_REGION: array = (GValueArray *) g_value_get_boxed (value); set_region (array, &priv->y_region); break; case PROP_Z: priv->z = g_value_get_float (value); break; case PROP_REGION: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->region); priv->region = g_value_array_copy (array); break; case PROP_PROJECTION_OFFSET: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->projection_offset); priv->projection_offset = g_value_array_copy (array); break; case PROP_CENTER: array = (GValueArray *) g_value_get_boxed (value); g_value_array_free (priv->center); priv->center = g_value_array_copy (array); break; case PROP_NUM_PROJECTIONS: priv->num_projections = g_value_get_uint (value); break; case PROP_OVERALL_ANGLE: priv->overall_angle = g_value_get_float (value); break; case PROP_TOMO_ANGLE: priv->tomo_angle = g_value_get_float (value); break; case PROP_LAMINO_ANGLE: priv->lamino_angle = g_value_get_float (value); break; case PROP_ROLL_ANGLE: priv->roll_angle = g_value_get_float (value); break; case PROP_PARAMETER: if (!g_strcmp0 (g_value_get_string (value), "z")) { priv->parameter = PARAM_Z; } else if (!g_strcmp0 (g_value_get_string (value), "x-center")) { priv->parameter = PARAM_CENTER; } else if (!g_strcmp0 (g_value_get_string (value), "lamino-angle")) { priv->parameter = PARAM_LAMINO; } else if (!g_strcmp0 (g_value_get_string (value), "roll-angle")) { priv->parameter = PARAM_ROLL; } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ufo_anka_backproject_task_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { UfoAnkaBackprojectTaskPrivate *priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE (object); switch (property_id) { case PROP_X_REGION: g_value_set_boxed (value, priv->x_region); break; case PROP_Y_REGION: g_value_set_boxed (value, priv->y_region); break; case PROP_Z: g_value_set_float (value, priv->z); break; case PROP_REGION: g_value_set_boxed (value, priv->region); break; case PROP_PROJECTION_OFFSET: g_value_set_boxed (value, priv->projection_offset); break; case PROP_CENTER: g_value_set_boxed (value, priv->center); break; case PROP_NUM_PROJECTIONS: g_value_set_uint (value, priv->num_projections); break; case PROP_OVERALL_ANGLE: g_value_set_float (value, priv->overall_angle); break; case PROP_TOMO_ANGLE: g_value_set_float (value, priv->tomo_angle); break; case PROP_LAMINO_ANGLE: g_value_set_float (value, priv->lamino_angle); break; case PROP_ROLL_ANGLE: g_value_set_float (value, priv->roll_angle); break; case PROP_PARAMETER: switch (priv->parameter) { case PARAM_Z: g_value_set_string (value, "z"); break; case PARAM_CENTER: g_value_set_string (value, "x-center"); break; case PARAM_LAMINO: g_value_set_string (value, "lamino-angle"); break; case PARAM_ROLL: g_value_set_string (value, "roll-angle"); break; } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ufo_anka_backproject_task_class_init (UfoAnkaBackprojectTaskClass *klass) { GObjectClass *oclass; UfoNodeClass *node_class; oclass = G_OBJECT_CLASS (klass); node_class = UFO_NODE_CLASS (klass); oclass->finalize = ufo_anka_backproject_task_finalize; oclass->set_property = ufo_anka_backproject_task_set_property; oclass->get_property = ufo_anka_backproject_task_get_property; GParamSpec *region_vals = g_param_spec_int ("region_values", "Region values", "Elements in regions", G_MININT, G_MAXINT, (gint) 0, G_PARAM_READWRITE); GParamSpec *float_region_vals = g_param_spec_float ("float_region_values", "Float Region values", "Elements in float regions", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_X_REGION] = g_param_spec_value_array ("x-region", "X region for reconstruction as (from, to, step)", "X region for reconstruction as (from, to, step)", region_vals, G_PARAM_READWRITE); properties[PROP_Y_REGION] = g_param_spec_value_array ("y-region", "Y region for reconstruction as (from, to, step)", "Y region for reconstruction as (from, to, step)", region_vals, G_PARAM_READWRITE); properties[PROP_Z] = g_param_spec_float ("z", "Z coordinate of the reconstructed slice", "Z coordinate of the reconstructed slice", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_REGION] = g_param_spec_value_array ("region", "Region for the parameter along z-axis as (from, to, step)", "Region for the parameter along z-axis as (from, to, step)", float_region_vals, G_PARAM_READWRITE); properties[PROP_PROJECTION_OFFSET] = g_param_spec_value_array ("projection-offset", "Offset to projection data as (x, y)", "Offset to projection data as (x, y) for the case input data \ is cropped to the necessary range of interest", region_vals, G_PARAM_READWRITE); properties[PROP_CENTER] = g_param_spec_value_array ("center", "Center of the volume with respect to projections (x, y)", "Center of the volume with respect to projections (x, y), (rotation axes)", float_region_vals, G_PARAM_READWRITE); properties[PROP_OVERALL_ANGLE] = g_param_spec_float ("overall-angle", "Angle covered by all projections", "Angle covered by all projections (can be negative for negative steps " "in case only num-projections is specified", -G_MAXFLOAT, G_MAXFLOAT, G_PI, G_PARAM_READWRITE); properties[PROP_NUM_PROJECTIONS] = g_param_spec_uint ("num-projections", "Number of projections", "Number of projections", 0, 16384, 0, G_PARAM_READWRITE); properties[PROP_TOMO_ANGLE] = g_param_spec_float ("tomo-angle", "Tomographic rotation angle in radians", "Tomographic rotation angle in radians (used for acquiring projections)", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_LAMINO_ANGLE] = g_param_spec_float ("lamino-angle", "Absolute laminogrpahic angle in radians", "Absolute laminogrpahic angle in radians determining the sample tilt", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_ROLL_ANGLE] = g_param_spec_float ("roll-angle", "Sample angular misalignment to the side (roll) in radians", "Sample angular misalignment to the side (roll) in radians (CW is positive)", -G_MAXFLOAT, G_MAXFLOAT, 0.0f, G_PARAM_READWRITE); properties[PROP_PARAMETER] = g_param_spec_string ("parameter", "Which paramter will be varied along the z-axis", "Which paramter will be varied along the z-axis, from \"z\", \"x-center\", \"lamino-angle\",\ \"roll-angle\"", "z", G_PARAM_READWRITE); for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++) g_object_class_install_property (oclass, i, properties[i]); node_class->equal = ufo_anka_backproject_task_equal_real; g_type_class_add_private (klass, sizeof(UfoAnkaBackprojectTaskPrivate)); } static void ufo_anka_backproject_task_init(UfoAnkaBackprojectTask *self) { UfoAnkaBackprojectTaskPrivate *priv; self->priv = priv = UFO_ANKA_BACKPROJECT_TASK_GET_PRIVATE(self); guint i; GValue int_zero = G_VALUE_INIT; GValue float_zero = G_VALUE_INIT; g_value_init (&int_zero, G_TYPE_INT); g_value_init (&float_zero, G_TYPE_FLOAT); g_value_set_int (&int_zero, 0); g_value_set_float (&float_zero, 0.0f); self->priv->x_region = g_value_array_new (3); self->priv->y_region = g_value_array_new (3); self->priv->region = g_value_array_new (3); self->priv->z = 0.0f; self->priv->projection_offset = g_value_array_new (2); self->priv->center = g_value_array_new (2); for (i = 0; i < 3; i++) { g_value_array_insert (self->priv->x_region, i, &int_zero); g_value_array_insert (self->priv->y_region, i, &int_zero); g_value_array_insert (self->priv->region, i, &float_zero); if (i < 2) { g_value_array_insert (self->priv->projection_offset, i, &int_zero); g_value_array_insert (self->priv->center, i, &float_zero); } } self->priv->num_projections = 0; self->priv->overall_angle = G_PI; self->priv->tomo_angle = -G_MAXFLOAT; self->priv->lamino_angle = 0.0f; self->priv->roll_angle = 0.0f; self->priv->parameter = PARAM_Z; self->priv->count = 0; self->priv->generated = FALSE; }