Geometries Example

// Writes an OMF file containing one of each of the remaining element geometries.
// Surface and LineSet are covered in pyramid.c so won't be repeated here.

#include <assert.h>
#include <omf.h>
#include <stdio.h>
#include <stdlib.h>

// 2D Tensor data.
static const double TENSOR_U[] = { 2.0, 1.0 };
static const double TENSOR_V[] = { 1.0, 1.0 };
static const double TENSOR_W[] = { 0.5 };

// 2D grid heights.
static const float HEIGHTS[] = {
    -1.0, -1.0, -1.0,  -1.0, 1.0, -1.0,  -1.0, -1.0, -1.0,
};

// 2D vertices.
static const float VERTICES[][3] = {
    { 10.0, 0.0, -1.0 },
    { 12.0, 0.0, -1.0 },
    { 13.0, 0.0, -1.0 },
    { 10.0, 1.0, -1.0 },
    { 12.0, 1.0, 1.0 },
    { 13.0, 1.0, -1.0 },
    { 10.0, 2.0, -1.0 },
    { 12.0, 2.0, -1.0 },
    { 13.0, 2.0, -1.0 },
};

static const uint32_t REGULAR_SUBBLOCK_PARENTS[][3] = {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 1, 0, 0 },
};

static const uint32_t REGULAR_SUBBLOCK_CORNERS[][6] = {
    { 0, 1, 0, 1, 2, 1 },
    { 1, 0, 0, 2, 1, 1 },
    { 1, 1, 0, 2, 2, 2 },
    { 0, 0, 0, 2, 2, 2 },
};

static const uint32_t FREEFORM_SUBBLOCK_PARENTS[][3] = {
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 1, 0, 0 },
};

static const float FREEFORM_SUBBLOCK_CORNERS[][6] = {
    { 0.0, 0.0, 0.0, 0.5, 1.0, 0.17f },
    { 0.0, 0.0, 0.17f, 0.5, 1.0, 1.0 },
    { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0 },
};

typedef struct {
    const float (*vertices)[3];
    size_t length;
    size_t index;
} VertexIter;

static bool next_vertex(void *object, double out[3]) {
    VertexIter *iter = object;
    if (iter->index >= iter->length) {
        return false;
    } else {
        out[0] = iter->vertices[iter->index][0];
        out[1] = iter->vertices[iter->index][1];
        out[2] = iter->vertices[iter->index][2];
        ++iter->index;
        return true;
    }
}

static bool write(const char *path) {
    OmfError *error;
    OmfWriter *writer;
    OmfHandle *proj_handle, *comp_handle;
    OmfProject project;
    OmfElement element;
    OmfPointSet point_set;
    OmfComposite composite;
    OmfGridSurface grid_surface;
    OmfTensorGrid2 tensor_grid2;
    OmfTensorGrid3 tensor_grid3;
    OmfRegularGrid3 regular_grid3;
    OmfBlockModel block_model;
    OmfRegularSubblocks subblocks;
    OmfFreeformSubblocks freeform_subblocks;
    VertexIter iter;

    // Open the file and create a project.
    writer = omf_writer_open(path);
    project = omf_project_init("geometries.omf");
    proj_handle = omf_writer_project(writer, &project);

    // Composite element, sub-elements added below.
    composite = omf_composite_init();
    element = omf_element_init("Container");
    element.composite = &composite;
    element.description = "Contains a grid surface, plus a point set of the vertices of that grid.";
    comp_handle = omf_writer_element(writer, proj_handle, &element);

    // GridSurface.
    tensor_grid2 = omf_tensor_grid2_init(
        omf_writer_array_scalars64(writer, TENSOR_U, 2),
        omf_writer_array_scalars64(writer, TENSOR_V, 2)
    );
    grid_surface = omf_grid_surface_init();
    grid_surface.orient.origin[0] = 10.0;
    grid_surface.tensor_grid = &tensor_grid2;
    grid_surface.heights = omf_writer_array_scalars32(writer, HEIGHTS, 9);
    element = omf_element_init("GridSurface");
    element.description = "An example 2D grid surface.";
    element.grid_surface = &grid_surface;
    omf_writer_element(writer, comp_handle, &element);

    // PointSet.
    // Write the vertices using the iterator API.
    iter.vertices = VERTICES;
    iter.index = 0;
    iter.length = 9;
    point_set = omf_point_set_init(omf_writer_array_vertices64_iter(writer, &next_vertex, &iter));
    element = omf_element_init("PointSet");
    element.description = "Points that should be in the same places as the grid vertices.";
    element.point_set = &point_set;
    omf_writer_element(writer, comp_handle, &element);

    // BlockModel with tensor grid and no sub-blocks.
    tensor_grid3 = omf_tensor_grid3_init(
        omf_writer_array_scalars64(writer, TENSOR_U, 2),
        omf_writer_array_scalars64(writer, TENSOR_V, 2),
        omf_writer_array_scalars64(writer, TENSOR_W, 1)
    );
    block_model = omf_block_model_init();
    block_model.tensor_grid = &tensor_grid3;
    element = omf_element_init("Tensor block model");
    element.block_model = &block_model;
    omf_writer_element(writer, proj_handle, &element);

    // BlockModel with regular sub-blocks.
    regular_grid3 = omf_regular_grid3_init(1.0, 1.0, 1.0, 2, 1, 1);
    subblocks = omf_regular_subblocks_init(
        2, 2, 2,
        omf_writer_array_regular_subblocks(writer, REGULAR_SUBBLOCK_PARENTS, REGULAR_SUBBLOCK_CORNERS, 4)
    );
    block_model = omf_block_model_init();
    block_model.regular_grid = &regular_grid3;
    block_model.regular_subblocks = &subblocks;
    element = omf_element_init("Regular block model with regular sub-blocks");
    element.block_model = &block_model;
    omf_writer_element(writer, proj_handle, &element);

    // BlockModel with free-form sub-blocks.
    regular_grid3 = omf_regular_grid3_init(1.0, 1.0, 1.0, 2, 1, 1);
    freeform_subblocks = omf_freeform_subblocks_init(
        omf_writer_array_freeform_subblocks32(writer, FREEFORM_SUBBLOCK_PARENTS, FREEFORM_SUBBLOCK_CORNERS, 3)
    );
    block_model = omf_block_model_init();
    block_model.regular_grid = &regular_grid3;
    block_model.freeform_subblocks = &freeform_subblocks;
    element = omf_element_init("Regular block model with free-form sub-blocks");
    element.block_model = &block_model;
    omf_writer_element(writer, proj_handle, &element);

    // Finish writing and close the file.
    omf_writer_finish(writer, NULL);

    // Check for errors.
    if ((error = omf_error()) != NULL) {
        fprintf(stderr, "[write failed] %s (%d)\n", error->message, error->code);
        omf_error_free(error);
        return false;
    }
    return true;
}

static bool read(const char *path) {
    OmfReader *reader;
    const OmfProject *project;
    const OmfElement *element;
    OmfError *error;
    double u[2], v[2], heights[9], x, y, z;
    size_t i, j;
    double vertices[9][3];

    // Open the file and read the project.
    reader = omf_reader_open(path);
    project = omf_reader_project(reader, NULL);
    if (!project) {
        error = omf_error();
        fprintf(stderr, "[read failed] %s (%d)\n", error->message, error->code);
        omf_error_free(error);
        return false;
    }
    printf("name: %s\n", project->name);

    // Read and print the grid surface.
    element = &project->elements[0].composite->elements[0];
    printf("element: %s\n", element->name);
    omf_reader_array_scalars64(reader, element->grid_surface->tensor_grid->u, u, 2);
    omf_reader_array_scalars64(reader, element->grid_surface->tensor_grid->v, v, 2);
    // The heights were written as 'float' but can be read back as 'double'. Casting to larger
    // types within the same category (floating point, unsigned int, and signed int) is allowed.
    omf_reader_array_scalars64(reader, element->grid_surface->heights, heights, 9);
    y = element->grid_surface->orient.origin[1];
    for (j = 0; j <= 2; j++) {
        x = element->grid_surface->orient.origin[0];
        for (i = 0; i <= 2; i++) {
            z = heights[j * 3 + i] + element->grid_surface->orient.origin[2];
            printf("    %g %g %g\n", x, y, z);
            if (i < 2) {
                x += u[i];
            }
        }
        if (j < 2) {
            y += v[j];
        }
    }

    // Read and print the points.
    element = &project->elements[0].composite->elements[1];
    printf("element: %s\n", element->name);
    omf_reader_array_vertices64(reader, element->point_set->vertices, vertices, 9);
    for (i = 0; i < 9; i++) {
        printf("    %g %g %g\n", vertices[i][0], vertices[i][1], vertices[i][2]);
    }

    // Close the reader only once we're done with `project`.
    omf_reader_close(reader);

    // Check for errors.
    if ((error = omf_error()) != NULL) {
        fprintf(stderr, "[read failed] %s (%d)\n", error->message,
                error->code);
        omf_error_free(error);
        return false;
    }
    return true;
}

int main() {
    if (!write("geometries.omf")) return 1;
    if (!read("geometries.omf")) return 1;
    return 0;
}