Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef GRID_H
- #define GRID_H
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- /*
- * This file is in public domain.
- */
- typedef struct {
- double minimum;
- double maximum;
- } span;
- struct grid {
- /* Grid size */
- int xsize;
- int ysize;
- int zsize;
- /* Total number of grid points */
- size_t size; /* xsize * ysize * zsize */
- /* Strides, allowing any major */
- size_t xstride; /* 1 */
- size_t ystride; /* xsize */
- size_t zstride; /* xsize * ysize */
- /* Cell containing minimum/maximum samples */
- size_t minimum_cell;
- size_t maximum_cell;
- double minimum_sample;
- double maximum_sample;
- /* Location of the (0,0,0) grid point */
- double xorigin;
- double yorigin;
- double zorigin;
- /* Grid unit distances along each axis */
- double xunit;
- double yunit;
- double zunit;
- /* Scalar field sampling function */
- void *field_data;
- double (*field)(void *field_data, double x, double y, double z);
- /* Location stack */
- size_t stack_size;
- size_t stack_used;
- size_t *stack;
- /* Grid cells */
- unsigned char *cell;
- /* Sample cache */
- double sample[];
- };
- #define CELL_UNKNOWN 0U
- #define CELL_SAMPLED 1U
- #define CELL_PUSHED 2U
- #define CELL_WALKED 4U
- #define GRID_X(grid, index) (((index) / (grid)->xstride) % (grid)->xsize)
- #define GRID_Y(grid, index) (((index) / (grid)->ystride) % (grid)->ysize)
- #define GRID_Z(grid, index) (((index) / (grid)->zstride) % (grid)->zsize)
- #define GRID_I(grid, x, y, z) ((size_t)(x) * (grid)->xstride + (size_t)(y) * (grid)->ystride + (size_t)(z) * (grid)->zstride)
- static inline void grid_clear(struct grid *const g)
- {
- unsigned char *p = g->cell;
- unsigned char *const q = g->cell + g->size;
- /* Retain only CELL_SAMPLED flag. */
- while (p < q)
- *(p++) &= CELL_SAMPLED;
- /* Clear the stack, too. */
- g->stack_used = 0;
- }
- static inline size_t grid_pop(struct grid *const g)
- {
- /* Skip already walked indices. */
- while (g->stack_used > 0 && (g->cell[g->stack[g->stack_used - 1]] & CELL_WALKED) != 0)
- g->stack_used--;
- if (g->stack_used > 0) {
- const size_t i = g->stack[--g->stack_used];
- /* Mark popped index walked, and return it. */
- g->cell[i] |= CELL_WALKED;
- return i;
- } else
- return g->size; /* Stack empty. */
- }
- static inline int grid_push(struct grid *const g, const size_t i)
- {
- /* Do not push already pushed or walked cells. */
- if (g->cell[i] & (CELL_PUSHED | CELL_WALKED))
- return 0;
- /* Grow stack if necessary. */
- if (g->stack_used >= g->stack_size) {
- const size_t new_size = (g->stack_used | 1023) + 1025;
- size_t *new_stack;
- new_stack = realloc(g->stack, new_size * sizeof g->stack[0]);
- if (new_stack == NULL)
- return errno = ENOMEM;
- g->stack = new_stack;
- g->stack_size = new_size;
- }
- /* Mark cell pushed, */
- g->cell[i] |= CELL_PUSHED;
- /* and append it to the stack. */
- g->stack[g->stack_used++] = i;
- return 0;
- }
- static inline double grid_sample(struct grid *const g, const size_t x, const size_t y, const size_t z)
- {
- const size_t i = x * g->xstride + y * g->ystride + z * g->zstride;
- if (!(g->cell[i] & CELL_SAMPLED)) {
- g->sample[i] = g->field(g->field_data, g->xorigin + (double)x * g->xunit,
- g->yorigin + (double)y * g->yunit,
- g->zorigin + (double)z * g->zunit);
- g->cell[i] |= CELL_SAMPLED;
- }
- return g->sample[i];
- }
- static span grid_cell(struct grid *const g, const size_t x, const size_t y, const size_t z, double corner[2][2][2])
- {
- const size_t xstride = g->xstride,
- ystride = g->ystride,
- zstride = g->zstride;
- const double field_x = g->xorigin + (double)x * g->xunit,
- field_y = g->yorigin + (double)y * g->yunit,
- field_z = g->zorigin + (double)z * g->zunit,
- unit_x = g->xunit,
- unit_y = g->yunit,
- unit_z = g->zunit;
- unsigned char *const cell = g->cell + x * xstride + y * ystride + z * zstride;
- double *const sample = g->sample + x * xstride + y * ystride + z * zstride;
- span result;
- if (!(cell[0] & CELL_SAMPLED)) {
- sample[0] = g->field(g->field_data, field_x, field_y, field_z);
- cell[0] |= CELL_SAMPLED;
- }
- corner[0][0][0] = sample[0];
- { const size_t i = xstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[1][0][0] = sample[i];
- }
- { const size_t i = ystride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y + unit_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[0][1][0] = sample[i];
- }
- { const size_t i = xstride + ystride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y + unit_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[1][1][0] = sample[i];
- }
- { const size_t i = zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[0][0][1] = sample[i];
- }
- { const size_t i = xstride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[1][0][1] = sample[i];
- }
- { const size_t i = ystride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y + unit_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[0][1][1] = sample[i];
- }
- { const size_t i = xstride + ystride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y + unit_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- corner[1][1][1] = sample[i];
- }
- result.minimum = corner[0][0][0];
- if (result.minimum > corner[0][0][1])
- result.minimum = corner[0][0][1];
- if (result.minimum > corner[0][1][0])
- result.minimum = corner[0][1][0];
- if (result.minimum > corner[0][1][1])
- result.minimum = corner[0][1][1];
- if (result.minimum > corner[1][0][0])
- result.minimum = corner[1][0][0];
- if (result.minimum > corner[1][0][1])
- result.minimum = corner[1][0][1];
- if (result.minimum > corner[1][1][0])
- result.minimum = corner[1][1][0];
- if (result.minimum > corner[1][1][1])
- result.minimum = corner[1][1][1];
- result.maximum = corner[0][0][0];
- if (result.maximum < corner[0][0][1])
- result.maximum = corner[0][0][1];
- if (result.maximum < corner[0][1][0])
- result.maximum = corner[0][1][0];
- if (result.maximum < corner[0][1][1])
- result.maximum = corner[0][1][1];
- if (result.maximum < corner[1][0][0])
- result.maximum = corner[1][0][0];
- if (result.maximum < corner[1][0][1])
- result.maximum = corner[1][0][1];
- if (result.maximum < corner[1][1][0])
- result.maximum = corner[1][1][0];
- if (result.maximum < corner[1][1][1])
- result.maximum = corner[1][1][1];
- return result;
- }
- static inline span grid_cell_span(struct grid *const g, const size_t x, const size_t y, const size_t z)
- {
- const size_t xstride = g->xstride,
- ystride = g->ystride,
- zstride = g->zstride;
- const double field_x = g->xorigin + (double)x * g->xunit,
- field_y = g->yorigin + (double)y * g->yunit,
- field_z = g->zorigin + (double)z * g->zunit,
- unit_x = g->xunit,
- unit_y = g->yunit,
- unit_z = g->zunit;
- unsigned char *const cell = g->cell + x * xstride + y * ystride + z * zstride;
- double *const sample = g->sample + x * xstride + y * ystride + z * zstride;
- span result;
- if (!(cell[0] & CELL_SAMPLED)) {
- sample[0] = g->field(g->field_data, field_x, field_y, field_z);
- cell[0] |= CELL_SAMPLED;
- }
- result.minimum = sample[0];
- result.maximum = sample[0];
- { const size_t i = xstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = ystride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y + unit_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = xstride + ystride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y + unit_y, field_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = xstride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = ystride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x, field_y + unit_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- { const size_t i = xstride + ystride + zstride;
- if (!(cell[i] & CELL_SAMPLED)) {
- sample[i] = g->field(g->field_data, field_x + unit_x, field_y + unit_y, field_z + unit_z);
- cell[i] |= CELL_SAMPLED;
- }
- { const double s = sample[i];
- if (result.minimum > s)
- result.minimum = s;
- if (result.maximum < s)
- result.maximum = s;
- }
- }
- return result;
- }
- static int grid_minimum_cell(struct grid *const g)
- {
- unsigned char *const cell = g->cell;
- const size_t xstride = g->xstride,
- ystride = g->ystride,
- zstride = g->zstride,
- xsize = g->xsize,
- ysize = g->ysize,
- zsize = g->zsize,
- end = g->size;
- size_t x, y, z;
- size_t i, best_i;
- double s, best_s;
- grid_clear(g);
- best_s = grid_sample(g, 0, 0, 0);
- best_i = 0;
- s = grid_sample(g, xsize-1, 0, 0);
- if (s < best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride;
- }
- s = grid_sample(g, 0, ysize-1, 0);
- if (s < best_s) {
- best_s = s;
- best_i = (ysize-1) * ystride;
- }
- s = grid_sample(g, xsize-1, ysize-1, 0);
- if (s < best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (ysize-1) * ystride;
- }
- s = grid_sample(g, 0, 0, zsize-1);
- if (s < best_s) {
- best_s = s;
- best_i = (zsize-1) * zstride;
- }
- s = grid_sample(g, xsize-1, 0, zsize-1);
- if (s < best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (zsize-1) * zstride;
- }
- s = grid_sample(g, 0, ysize-1, zsize - 1);
- if (s < best_s) {
- best_s = s;
- best_i = (ysize-1) * ystride + (zsize-1) * zstride;
- }
- s = grid_sample(g, xsize-1, ysize-1, zsize-1);
- if (s < best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (ysize-1) * ystride + (zsize-1) * zstride;
- }
- if (grid_push(g, best_i))
- return errno;
- while (1) {
- i = grid_pop(g);
- if (i >= end)
- break;
- x = (i / xstride) % xsize;
- y = (i / ystride) % ysize;
- z = (i / zstride) % zsize;
- s = grid_sample(g, x, y, z);
- if (s < best_s || (s == best_s && i < best_i)) {
- best_i = i;
- best_s = s;
- }
- if (x > 0 && grid_sample(g, x-1, y, z) <= best_s)
- if (grid_push(g, i - xstride))
- return errno;
- if (y > 0 && grid_sample(g, x, y-1, z) <= best_s)
- if (grid_push(g, i - ystride))
- return errno;
- if (z > 0 && grid_sample(g, x, y, z-1) <= best_s)
- if (grid_push(g, i - zstride))
- return errno;
- if (x+1 < xsize && grid_sample(g, x+1, y, z) <= best_s)
- if (grid_push(g, i + xstride))
- return errno;
- if (y+1 < ysize && grid_sample(g, x, y+1, z) <= best_s)
- if (grid_push(g, i + ystride))
- return errno;
- if (z+1 < zsize && grid_sample(g, x, y, z+1) <= best_s)
- if (grid_push(g, i + zstride))
- return errno;
- }
- x = (best_i / xstride) % xsize;
- if (x+1 >= xsize)
- x = xsize - 2;
- y = (best_i / ystride) % ysize;
- if (y+1 >= ysize)
- y = ysize - 2;
- z = (best_i / zstride) % zsize;
- if (z+1 >= zsize)
- z = zsize - 2;
- g->minimum_cell = x*xstride + y*ystride + z*zstride;
- g->minimum_sample = best_s;
- return 0;
- }
- static int grid_maximum_cell(struct grid *const g)
- {
- unsigned char *const cell = g->cell;
- const size_t xstride = g->xstride,
- ystride = g->ystride,
- zstride = g->zstride,
- xsize = g->xsize,
- ysize = g->ysize,
- zsize = g->zsize,
- end = g->size;
- size_t x, y, z;
- size_t i, best_i;
- double s, best_s;
- grid_clear(g);
- best_s = grid_sample(g, 0, 0, 0);
- best_i = 0;
- s = grid_sample(g, xsize-1, 0, 0);
- if (s >= best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride;
- }
- s = grid_sample(g, 0, ysize-1, 0);
- if (s >= best_s) {
- best_s = s;
- best_i = (ysize-1) * ystride;
- }
- s = grid_sample(g, xsize-1, ysize-1, 0);
- if (s >= best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (ysize-1) * ystride;
- }
- s = grid_sample(g, 0, 0, zsize-1);
- if (s >= best_s) {
- best_s = s;
- best_i = (zsize-1) * zstride;
- }
- s = grid_sample(g, xsize-1, 0, zsize-1);
- if (s >= best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (zsize-1) * zstride;
- }
- s = grid_sample(g, 0, ysize-1, zsize - 1);
- if (s >= best_s) {
- best_s = s;
- best_i = (ysize-1) * ystride + (zsize-1) * zstride;
- }
- s = grid_sample(g, xsize-1, ysize-1, zsize-1);
- if (s >= best_s) {
- best_s = s;
- best_i = (xsize-1) * xstride + (ysize-1) * ystride + (zsize-1) * zstride;
- }
- if (grid_push(g, best_i))
- return errno;
- while (1) {
- i = grid_pop(g);
- if (i >= end)
- break;
- x = (i / xstride) % xsize;
- y = (i / ystride) % ysize;
- z = (i / zstride) % zsize;
- s = grid_sample(g, x, y, z);
- if (s > best_s || (s == best_s && i > best_i)) {
- best_i = i;
- best_s = s;
- }
- if (x > 0 && grid_sample(g, x-1, y, z) >= best_s)
- if (grid_push(g, i - xstride))
- return errno;
- if (y > 0 && grid_sample(g, x, y-1, z) >= best_s)
- if (grid_push(g, i - ystride))
- return errno;
- if (z > 0 && grid_sample(g, x, y, z-1) >= best_s)
- if (grid_push(g, i - zstride))
- return errno;
- if (x+1 < xsize && grid_sample(g, x+1, y, z) >= best_s)
- if (grid_push(g, i + xstride))
- return errno;
- if (y+1 < ysize && grid_sample(g, x, y+1, z) >= best_s)
- if (grid_push(g, i + ystride))
- return errno;
- if (z+1 < zsize && grid_sample(g, x, y, z+1) >= best_s)
- if (grid_push(g, i + zstride))
- return errno;
- }
- x = (best_i / xstride) % xsize;
- if (x > 0)
- x--;
- y = (best_i / ystride) % ysize;
- if (y > 0)
- y--;
- z = (best_i / zstride) % zsize;
- if (z > 0)
- z--;
- g->maximum_cell = x*xstride + y*ystride + z*zstride;
- g->maximum_sample = best_s;
- return 0;
- }
- static size_t grid_find_cell(struct grid *const g, const double c)
- {
- const size_t xsize = g->xsize,
- ysize = g->ysize,
- zsize = g->zsize,
- xstride = g->xstride,
- ystride = g->ystride,
- zstride = g->zstride;
- size_t xmin = (g->minimum_cell / xstride) % xsize,
- ymin = (g->minimum_cell / ystride) % ysize,
- zmin = (g->minimum_cell / zstride) % zsize;
- size_t xmax = (g->maximum_cell / xstride) % xsize,
- ymax = (g->maximum_cell / ystride) % ysize,
- zmax = (g->maximum_cell / zstride) % zsize;
- span s, smin, smax;
- smin = grid_cell_span(g, xmin, ymin, zmin);
- smax = grid_cell_span(g, xmax, ymax, zmax);
- /* c outside the sample range? */
- if (c < smin.minimum || c > smax.maximum)
- return g->size; /* Not found */
- /* c within the minimum cell? */
- if (smin.minimum <= c && c <= smin.maximum)
- return g->minimum_cell;
- /* c within the maximum cell? */
- if (smax.maximum <= c && c <= smax.maximum)
- return g->maximum_cell;
- /* Do a binary search to locate a cell spanning c. */
- while (1) {
- const size_t x = (xmin + xmax) / 2;
- const size_t y = (ymin + ymax) / 2;
- const size_t z = (zmin + zmax) / 2;
- s = grid_cell_span(g, x, y, z);
- if (s.minimum <= c && c <= s.maximum)
- return x * xstride + y * ystride + z * zstride;
- if (x == xmin && y == ymin && z == zmin)
- return xmax * xstride + ymax * ystride + zmax * zstride;
- if (s.minimum > c) {
- smax = s;
- xmax = x;
- ymax = y;
- zmax = z;
- continue;
- }
- if (s.maximum < c) {
- smin = s;
- xmin = x;
- ymin = y;
- zmin = z;
- continue;
- }
- if (s.maximum > c) {
- smax = s;
- xmax = x;
- ymax = y;
- zmax = z;
- continue;
- }
- if (s.minimum < c) {
- smin = s;
- xmin = x;
- ymin = y;
- zmin = z;
- continue;
- }
- }
- /* Only possibility! */
- return xmax * xstride + ymax * ystride + zmax * zstride;
- }
- static int grid_isosurface(struct grid *const g, const double value, void *custom,
- int (*callback)(void *custom, struct grid *g, int x, int y, int z, double value, double sample[2][2][2]))
- {
- double corner[2][2][2];
- size_t i, x, y, z;
- span s;
- int err;
- if (g == NULL || callback == NULL)
- return errno = EINVAL;
- /* Use a binary search from minimum to maximum cells,
- * to find a suitable starting cell. */
- i = grid_find_cell(g, value);
- if (i >= g->size)
- return errno = ENOENT;
- grid_clear(g);
- err = grid_push(g, i);
- if (err)
- return errno = err;
- while (1) {
- i = grid_pop(g);
- if (i >= g->size)
- break;
- x = (i / g->xstride) % g->xsize;
- y = (i / g->ystride) % g->ysize;
- z = (i / g->zstride) % g->zsize;
- s = grid_cell(g, x, y, z, corner);
- if (s.minimum <= value && s.maximum >= value) {
- err = callback(custom, g, x, y, z, value, corner);
- if (err) {
- errno = 0;
- return err;
- }
- }
- /* Neighboring cells sharing a face */
- if (x > 0 && !(g->cell[i - g->xstride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x-1, y, z);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i - g->xstride))
- return errno;
- }
- if (y > 0 && !(g->cell[i - g->ystride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x, y-1, z);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i - g->ystride))
- return errno;
- }
- if (z > 0 && !(g->cell[i - g->zstride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x, y, z-1);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i - g->zstride))
- return errno;
- }
- if (x < g->xsize-2 && !(g->cell[i + g->xstride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x+1, y, z);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i + g->xstride))
- return errno;
- }
- if (y < g->ysize-2 && !(g->cell[i + g->ystride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x, y+1, z);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i + g->ystride))
- return errno;
- }
- if (z < g->zsize-2 && !(g->cell[i + g->zstride] & CELL_PUSHED)) {
- s = grid_cell_span(g, x, y, z+1);
- if (s.minimum <= value && s.maximum >= value)
- if (grid_push(g, i + g->zstride))
- return errno;
- }
- }
- /* Success. */
- return errno = 0;
- }
- static struct grid *grid_free(struct grid *const g)
- {
- if (g != NULL) {
- free(g->stack);
- g->xsize = 0;
- g->ysize = 0;
- g->zsize = 0;
- g->size = 0;
- g->xstride = 0;
- g->ystride = 0;
- g->zstride = 0;
- g->minimum_cell = 0;
- g->maximum_cell = 0;
- g->minimum_sample = 0.0;
- g->maximum_sample = 0.0;
- g->xorigin = 0.0;
- g->yorigin = 0.0;
- g->zorigin = 0.0;
- g->xunit = 0.0;
- g->yunit = 0.0;
- g->zunit = 0.0;
- g->field_data = NULL;
- g->field = NULL;
- g->stack_size = 0;
- g->stack_used = 0;
- g->stack = NULL;
- g->cell = NULL;
- free(g);
- }
- return NULL;
- }
- static struct grid *grid_new(const int xsize, const int ysize, const int zsize,
- const double xmin, const double ymin, const double zmin,
- const double xmax, const double ymax, const double zmax,
- void *field_data,
- double (*field)(void *data, double x, double y, double z))
- {
- const size_t size = (size_t)xsize * (size_t)ysize * (size_t)zsize;
- const size_t base = sizeof (struct grid) + size * sizeof (double);
- const size_t bytes = base + size;
- struct grid *g;
- size_t i;
- int err;
- /* Make sure parameters make sense. */
- if (xsize < 2 || ysize < 2 || zsize < 2 || field == NULL) {
- errno = EINVAL;
- return NULL;
- }
- /* Try to detect size overflow. */
- if (bytes <= base || bytes <= size ||
- (size_t)((base - sizeof (struct grid)) / sizeof (double)) != size ||
- (size_t)(size / (size_t)xsize) != (size_t)ysize * (size_t)zsize ||
- (size_t)(size / (size_t)ysize / (size_t)zsize) != (size_t)xsize) {
- errno = ENOMEM;
- return NULL;
- }
- /* Allocate; both cell and sample arrays are part of the structure allocation. */
- g = malloc(bytes);
- if (g == NULL) {
- errno = ENOMEM;
- return NULL;
- }
- /* Initialize the fields. */
- g->xsize = xsize;
- g->ysize = ysize;
- g->zsize = zsize;
- g->size = size;
- g->xstride = 1;
- g->ystride = (size_t)xsize;
- g->zstride = (size_t)xsize * (size_t)ysize;
- g->xorigin = xmin;
- g->yorigin = ymin;
- g->zorigin = zmin;
- g->xunit = (xmax - xmin) / (double)(xsize - 1);
- g->yunit = (ymax - ymin) / (double)(ysize - 1);
- g->zunit = (zmax - zmin) / (double)(zsize - 1);
- g->field_data = field_data;
- g->field = field;
- g->stack_size = 0;
- g->stack_used = 0;
- g->stack = NULL;
- /* Cells are allocated as part of the structure, following the last cached sample. */
- g->cell = (unsigned char *)&(g->sample[size]);
- /* Clear sample cache. This is actually not really necessary, just "nice". */
- g->sample[0] = 0.0;
- for (i = 1; i < size; i++)
- memcpy(g->sample + i, g->sample, sizeof g->sample[0]);
- /* Clear cells to initial state. This is actually necessary. */
- memset(g->cell, CELL_UNKNOWN, size);
- /* Locate the cell containing the minimum sample. */
- err = grid_minimum_cell(g);
- if (err) {
- free(g);
- errno = err;
- return NULL;
- }
- /* Locate the cell containing the maximum sample. */
- err = grid_maximum_cell(g);
- if (err) {
- free(g);
- errno = err;
- return NULL;
- }
- /* All done successfully. */
- errno = 0;
- return g;
- }
- #endif /* GRID_H */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement