solstice

Compute collected power and efficiencies of a solar plant
git clone git://git.meso-star.com/solstice.git
Log | Files | Refs | README | LICENSE

commit a0910550a278832bbe9edc0f75c7fd7691732ff6
parent 3519ceab269d0cb68477b7cbda120100faf1394d
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  3 Apr 2017 18:57:46 +0200

First commit on hemispheres; just to save work.

Diffstat:
Mdoc/input | 13+++++++++++--
Msrc/parser/solparser.c | 12++++++++++++
Msrc/parser/solparser.h | 5+++++
Msrc/parser/solparser_c.h | 11+++++++++++
Msrc/parser/solparser_geometry.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/parser/solparser_pivot.c | 22+++-------------------
Msrc/parser/solparser_shape.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/test_solparser3.c | 30++++++++++++++++++++++++++++--
Msrc/parser/test_solparser6.c | 17++++++++++++++++-
Msrc/solstice_object.c | 31++++++++++++++++++++++++++++++-
10 files changed, 272 insertions(+), 39 deletions(-)

diff --git a/doc/input b/doc/input @@ -131,6 +131,7 @@ | <parabol> | <parabolic-cylinder> | <hyperbol> + | <hemisphere> | <plane> | <sphere> | <stl> @@ -154,7 +155,7 @@ parabol: focal: REAL # in ]0, INF) clip: <polyclip-list> - # By default slices is automatically compute with respect to the parabol + # By default slices is automatically computed with respect to the parabol # curvature [ slices: INTEGER ] # in [4, 4096) @@ -162,7 +163,7 @@ parabolic-cylinder: # y^2 - 4*focal*z = 0 focal: REAL # in ]0, INF) clip: <polyclip-list> - # By default slices is automatically compute with respect to the hyperbol + # By default slices is automatically computed with respect to the hyperbol # curvature [ slices: INTEGER ] # in [4, 4096) @@ -181,6 +182,14 @@ real: REAL # in ]0, INF) image: REAL # in ]0, INF) +# x^2 + y^2 + (z - radius)^2 - radius^2 = 0 +<hemisphere> ::= + hemisphere: + radius: REAL # in ]0, INF) + # By default slices is automatically compute with respect to the hemisphere + # extension +[ slices: INTEGER ] # in [4, 4096) + <plane> ::= plane: clip: <polyclip-list> diff --git a/src/parser/solparser.c b/src/parser/solparser.c @@ -205,6 +205,7 @@ parser_clear(struct solparser* parser) darray_paraboloid_clear(&parser->parabols); darray_paraboloid_clear(&parser->parabolic_cylinders); darray_hyperboloid_clear(&parser->hyperbols); + darray_hemisphere_clear(&parser->hemispheres); darray_plane_clear(&parser->planes); darray_sphere_clear(&parser->spheres); darray_impgeom_clear(&parser->stls); @@ -259,6 +260,7 @@ parser_release(ref_T* ref) darray_paraboloid_release(&parser->parabols); darray_paraboloid_release(&parser->parabolic_cylinders); darray_hyperboloid_release(&parser->hyperbols); + darray_hemisphere_release(&parser->hemispheres); darray_plane_release(&parser->planes); darray_sphere_release(&parser->spheres); darray_impgeom_release(&parser->stls); @@ -587,6 +589,7 @@ solparser_create darray_paraboloid_init(mem_allocator, &parser->parabols); darray_paraboloid_init(mem_allocator, &parser->parabolic_cylinders); darray_hyperboloid_init(mem_allocator, &parser->hyperbols); + darray_hemisphere_init(mem_allocator, &parser->hemispheres); darray_plane_init(mem_allocator, &parser->planes); darray_sphere_init(mem_allocator, &parser->spheres); darray_impgeom_init(mem_allocator, &parser->stls); @@ -1047,6 +1050,15 @@ solparser_get_shape_hyperbol return darray_hyperboloid_cdata_get(&parser->hyperbols) + hyperboloid.i; } +const struct solparser_shape_hemisphere* +solparser_get_shape_hemisphere + (const struct solparser* parser, + const struct solparser_shape_hemisphere_id hemisphere) +{ + ASSERT(parser && hemisphere.i < darray_hemisphere_size_get(&parser->hemispheres)); + return darray_hemisphere_cdata_get(&parser->hemispheres) + hemisphere.i; +} + const struct solparser_shape_plane* solparser_get_shape_plane (const struct solparser* parser, diff --git a/src/parser/solparser.h b/src/parser/solparser.h @@ -177,6 +177,11 @@ solparser_get_shape_hyperbol (const struct solparser* parser, const struct solparser_shape_hyperboloid_id hyperboloid); +extern LOCAL_SYM const struct solparser_shape_hemisphere* +solparser_get_shape_hemisphere + (const struct solparser* parser, + const struct solparser_shape_hemisphere_id hemisphere); + extern LOCAL_SYM const struct solparser_shape_plane* solparser_get_shape_plane (const struct solparser* parser, diff --git a/src/parser/solparser_c.h b/src/parser/solparser_c.h @@ -120,6 +120,16 @@ struct target_alias { solparser_shape_hyperboloid_copy_and_release #include <rsys/dynamic_array.h> +/* Declare the array of hemispheres */ +#define DARRAY_NAME hemisphere +#define DARRAY_DATA struct solparser_shape_hemisphere +#define DARRAY_FUNCTOR_INIT solparser_shape_hemisphere_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_hemisphere_release +#define DARRAY_FUNCTOR_COPY solparser_shape_hemisphere_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ + solparser_shape_hemisphere_copy_and_release +#include <rsys/dynamic_array.h> + /* Declare the array of planes */ #define DARRAY_NAME plane #define DARRAY_DATA struct solparser_shape_plane @@ -211,6 +221,7 @@ struct solparser { struct darray_paraboloid parabols; struct darray_paraboloid parabolic_cylinders; struct darray_hyperboloid hyperbols; + struct darray_hemisphere hemispheres; struct darray_plane planes; struct darray_sphere spheres; struct darray_impgeom stls; diff --git a/src/parser/solparser_geometry.c b/src/parser/solparser_geometry.c @@ -329,6 +329,7 @@ parse_cylinder shape = darray_cylinder_data_get(&parser->cylinders) + ishape; n = cylinder->data.mapping.pairs.top - cylinder->data.mapping.pairs.start; + shape->nslices = 16; /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -382,13 +383,6 @@ parse_cylinder CHECK_PARAM(RADIUS, "radius"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SLICES, &shape->nslices, 16); - #undef DEFAULT_PARAM - exit: out_ishape->i = ishape; return res; @@ -692,6 +686,102 @@ error: } static res_T +parse_hemisphere + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* hemisphere, + struct solparser_shape_hemisphere_id* out_ishape) +{ + enum { CLIP, RADIUS, SLICES }; + struct solparser_shape_hemisphere* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && hemisphere && out_ishape); + + if(hemisphere->type != YAML_MAPPING_NODE) { + log_err(parser, hemisphere, "expect a mapping of hemisphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a hemispheric shape */ + ishape = darray_hemisphere_size_get(&parser->hemispheres); + res = darray_hemisphere_resize(&parser->hemispheres, ishape + 1); + if(res != RES_OK) { + log_err(parser, hemisphere, "could not allocate the hemisphere shape.\n"); + goto error; + } + shape = darray_hemisphere_data_get(&parser->hemispheres) + ishape; + + n = hemisphere->data.mapping.pairs.top - hemisphere->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect hemisphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the hemisphere parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "clip")) { + SETUP_MASK(CLIP, "clip"); + res = parse_clip(parser, doc, val, &shape->polyclips); + } + else if(!strcmp((char*)key->data.scalar.value, "radius")) { + SETUP_MASK(RADIUS, "radius"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->radius); + } + else if(!strcmp((char*)key->data.scalar.value, "slices")) { + SETUP_MASK(SLICES, "slices"); + res = parse_integer(parser, val, 4, 4096, &shape->nslices); + } + else { + log_err(parser, key, "unknown hemisphere parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if (res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, hemisphere, \ + "the hemisphere parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(RADIUS, "radius"); + #undef CHECK_PARAM + +exit : + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_hemisphere_pop_back(&parser->hemispheres); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T parse_plane (struct solparser* parser, yaml_document_t* doc, @@ -722,6 +812,7 @@ parse_plane shape = darray_plane_data_get(&parser->planes) + ishape; n = plane->data.mapping.pairs.top - plane->data.mapping.pairs.start; + shape->nslices = 1; /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -809,6 +900,7 @@ parse_sphere shape = darray_sphere_data_get(&parser->spheres) + ishape; n = sphere->data.mapping.pairs.top - sphere->data.mapping.pairs.start; + shape->nslices = 16; /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -858,13 +950,6 @@ parse_sphere CHECK_PARAM(RADIUS, "radius"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SLICES, &shape->nslices, 16); - #undef DEFAULT_PARAM - exit: out_ishape->i = ishape; return res; @@ -975,6 +1060,11 @@ parse_object SETUP_MASK(SHAPE, "shape"); shape->type = SOLPARSER_SHAPE_HYPERBOL; res = parse_hyperboloid(parser, doc, val, &shape->data.hyperbol); + } + else if(!strcmp((char*)key->data.scalar.value, "hemisphere")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_HEMISPHERE; + res = parse_hemisphere(parser, doc, val, &shape->data.hemisphere); } else if(!strcmp((char*)key->data.scalar.value, "plane")) { SETUP_MASK(SHAPE, "shape"); shape->type = SOLPARSER_SHAPE_PLANE; diff --git a/src/parser/solparser_pivot.c b/src/parser/solparser_pivot.c @@ -191,6 +191,7 @@ parse_x_pivot solxpivot = darray_x_pivot_data_get(&parser->x_pivots) + isolpivot; n = x_pivot->data.mapping.pairs.top - x_pivot->data.mapping.pairs.start; + d3_splat(solxpivot->ref_point, 0); /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -240,15 +241,6 @@ parse_x_pivot CHECK_PARAM(TARGET, "target"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point, 0); - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+1, 0); - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+2, 0); - #undef DEFAULT_PARAM - exit: out_isolpivot->i = isolpivot; return res; @@ -292,6 +284,8 @@ parse_zx_pivot solxzpivot = darray_zx_pivot_data_get(&parser->zx_pivots) + isolpivot; n = zx_pivot->data.mapping.pairs.top - zx_pivot->data.mapping.pairs.start; + solxzpivot->spacing = 0; /* default value */ + d3_splat(solxzpivot->ref_point, 0); /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -348,16 +342,6 @@ parse_zx_pivot CHECK_PARAM(TARGET, "target"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SPACING, &solxzpivot->spacing, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+1, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+2, 0); - #undef DEFAULT_PARAM - exit: out_isolpivot->i = isolpivot; return res; diff --git a/src/parser/solparser_shape.h b/src/parser/solparser_shape.h @@ -33,6 +33,7 @@ enum solparser_shape_type { SOLPARSER_SHAPE_PARABOL, SOLPARSER_SHAPE_PARABOLIC_CYLINDER, SOLPARSER_SHAPE_HYPERBOL, + SOLPARSER_SHAPE_HEMISPHERE, SOLPARSER_SHAPE_PLANE, SOLPARSER_SHAPE_SPHERE, SOLPARSER_SHAPE_STL /* Imported STereo Lithography */ @@ -260,6 +261,55 @@ solparser_shape_hyperboloid_copy_and_release } /******************************************************************************* +* Hemisphere shape +******************************************************************************/ +struct solparser_shape_hemisphere { + double radius; + struct darray_polyclip polyclips; + long nslices; /* < 0 if not defined */ +}; + +static INLINE void +solparser_shape_hemisphere_init + (struct mem_allocator* allocator, + struct solparser_shape_hemisphere* hemisphere) +{ + ASSERT(hemisphere); + hemisphere->nslices = -1; + darray_polyclip_init(allocator, &hemisphere->polyclips); +} + +static INLINE void +solparser_shape_hemisphere_release + (struct solparser_shape_hemisphere* hemisphere) +{ + ASSERT(hemisphere); + darray_polyclip_release(&hemisphere->polyclips); +} + +static INLINE res_T +solparser_shape_hemisphere_copy + (struct solparser_shape_hemisphere* dst, + const struct solparser_shape_hemisphere* src) +{ + ASSERT(dst && src); + dst->radius = src->radius; + dst->nslices = src->nslices; + return darray_polyclip_copy(&dst->polyclips, &src->polyclips); +} + +static INLINE res_T +solparser_shape_hemisphere_copy_and_release + (struct solparser_shape_hemisphere* dst, + struct solparser_shape_hemisphere* src) +{ + ASSERT(dst && src); + dst->radius = src->radius; + dst->nslices = src->nslices; + return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); +} + +/******************************************************************************* * Plane shape ******************************************************************************/ struct solparser_shape_plane { @@ -327,6 +377,7 @@ struct solparser_shape_cylinder_id { size_t i; }; struct solparser_shape_imported_geometry_id { size_t i; }; struct solparser_shape_paraboloid_id { size_t i; }; struct solparser_shape_hyperboloid_id { size_t i; }; +struct solparser_shape_hemisphere_id { size_t i; }; struct solparser_shape_plane_id { size_t i; }; struct solparser_shape_sphere_id { size_t i; }; @@ -339,6 +390,7 @@ struct solparser_shape { struct solparser_shape_paraboloid_id parabol; struct solparser_shape_paraboloid_id parabolic_cylinder; struct solparser_shape_hyperboloid_id hyperbol; + struct solparser_shape_hemisphere_id hemisphere; struct solparser_shape_plane_id plane; struct solparser_shape_sphere_id sphere; struct solparser_shape_imported_geometry_id stl; diff --git a/src/parser/test_solparser3.c b/src/parser/test_solparser3.c @@ -32,6 +32,13 @@ static const char* input[] = { " - operation : AND\n", " vertices : [[1, 2],[3, 4],[6, 7]]\n", " material: *lambertian\n", + "- geometry: &hemisphere1\n", + " - hemisphere:\n", + " radius: 100\n", + " clip:\n", + " - operation : AND\n", + " vertices : [[1, 2],[3, 4],[6, 7]]\n", + " material: *lambertian\n", "- sun: \n", " dni: 1\n", " spectrum: [{wavelength: 1, data: 1}]\n", @@ -61,6 +68,9 @@ static const char* input[] = { " - name: entity0c\n", " primary: 0\n", " geometry: *hyperbol1\n", + " - name: entity0d\n", + " primary: 0\n", + " geometry: *hemisphere1\n", "- entity:\n", " name: entity1\n", " x_pivot:\n", @@ -95,7 +105,7 @@ check_entity0 struct solparser_anchor_id anchor_id; struct solparser_entity_id entity_id; struct solparser_object_id obj_id; - const struct solparser_entity *entity0a, *entity0b; + const struct solparser_entity *entity0a, *entity0b, *entity0c, *entity0d; const struct solparser_material_matte* matte; const struct solparser_material* mtl; const struct solparser_material_double_sided* mtl2; @@ -137,7 +147,7 @@ check_entity0 matte = solparser_get_material_matte(parser, mtl->data.matte); CHECK(matte->reflectivity, 0.5); - CHECK(solparser_entity_get_children_count(entity0), 3); + CHECK(solparser_entity_get_children_count(entity0), 4); CHECK(solparser_entity_get_anchors_count(entity0), 3); anchor_id = solparser_entity_get_anchor(entity0, 0); @@ -186,6 +196,22 @@ check_entity0 entity0_entity0b_entity0b = solparser_get_anchor(parser, anchor_id); CHECK(strcmp(str_cget(&entity0_entity0b_entity0b->name), "entity0b"), 0); CHECK(d3_eq(entity0_entity0b_entity0b->position, d3(tmp, 7, 8, 9)), 1); + + entity_id = solparser_entity_get_child(entity0, 2); + entity0c = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0c->name), "entity0c"), 0); + CHECK(entity0c->type, SOLPARSER_ENTITY_GEOMETRY); + NCHECK(entity0->data.geometry.i, entity0c->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0c), 0); + CHECK(solparser_entity_get_children_count(entity0c), 0); + + entity_id = solparser_entity_get_child(entity0, 3); + entity0d = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0d->name), "entity0d"), 0); + CHECK(entity0d->type, SOLPARSER_ENTITY_GEOMETRY); + NCHECK(entity0->data.geometry.i, entity0d->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0d), 0); + CHECK(solparser_entity_get_children_count(entity0d), 0); } static void diff --git a/src/parser/test_solparser6.c b/src/parser/test_solparser6.c @@ -35,6 +35,7 @@ main(int argc, char** argv) const struct solparser_shape_paraboloid* parabol; const struct solparser_shape_plane* plane; const struct solparser_shape_hyperboloid* hyperbol; + const struct solparser_shape_hemisphere* hemisphere; const struct solparser_polyclip* polyclip; double pos[2]; FILE* stream; @@ -72,6 +73,12 @@ main(int argc, char** argv) fprintf(stream, " - operation : AND\n"); fprintf(stream, " vertices : [[1, 2], [3, 4], [6, 7]]\n"); fprintf(stream, " material: { ?virtual }\n"); + fprintf(stream, " - hemisphere:\n"); + fprintf(stream, " radius: 100\n"); + fprintf(stream, " clip :\n"); + fprintf(stream, " - operation : AND\n"); + fprintf(stream, " vertices : [[1, 2], [3, 4], [6, 7]]\n"); + fprintf(stream, " material: { ?virtual }\n"); rewind(stream); CHECK(solparser_setup(parser, NULL, stream), RES_OK); @@ -88,7 +95,7 @@ main(int argc, char** argv) CHECK(solparser_entity_get_children_count(entity), 0); CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); geom = solparser_get_geometry(parser, entity->data.geometry); - CHECK(solparser_geometry_get_objects_count(geom), 4); + CHECK(solparser_geometry_get_objects_count(geom), 5); obj_id = solparser_geometry_get_object(geom, 0); obj = solparser_get_object(parser, obj_id); @@ -140,6 +147,14 @@ main(int argc, char** argv) plane = solparser_get_shape_plane(parser, shape->data.plane); CHECK(plane->nslices, 1); /* Default value */ + obj_id = solparser_geometry_get_object(geom, 4); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_HEMISPHERE); + hemisphere = solparser_get_shape_hemisphere(parser, shape->data.hemisphere);; + CHECK(hemisphere->radius, 100); + CHECK(hemisphere->nslices, -1); /* Default value: auto */ + solparser_entity_iterator_next(&it); CHECK(solparser_entity_iterator_eq(&it, &end), 1); diff --git a/src/solstice_object.c b/src/solstice_object.c @@ -458,7 +458,32 @@ create_hyperbol } return create_ssol_shape_punched_surface - (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); + (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); +} + +static res_T +create_hemisphere + (struct solstice* solstice, + const double transform[12], + const struct solparser_shape_hemisphere_id id, + struct ssol_shape** out_ssol_shape) +{ + const struct solparser_shape_hemisphere* hemisphere; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + ASSERT(solstice); + + hemisphere = solparser_get_shape_hemisphere(solstice->parser, id); + + quadric.type = SSOL_QUADRIC_HEMISPHERE; + quadric.data.hemisphere.radius = hemisphere->radius; + d33_set(quadric.transform, transform); + d3_set(quadric.transform + 9, transform + 9); + if(hemisphere->nslices > 0) { /* nslices is set */ + quadric.slices_count_hint = (size_t)hemisphere->nslices; + } + + return create_ssol_shape_punched_surface + (solstice, &hemisphere->polyclips, &quadric, out_ssol_shape); } static res_T @@ -536,6 +561,10 @@ create_shaded_shape case SOLPARSER_SHAPE_HYPERBOL: res = create_hyperbol(solstice, transform, shape->data.hyperbol, ssol_shape); break; + case SOLPARSER_SHAPE_HEMISPHERE: + res = + create_hemisphere(solstice, transform, shape->data.hemisphere, ssol_shape); + break; case SOLPARSER_SHAPE_PLANE: res = create_plane(solstice, transform, shape->data.plane, ssol_shape); break;