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 0741cfe75dee1c716bfa9212825dd2fb52773b27
parent 860462a6161bb46fc256f6b40924a3bc69e08d90
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 24 Feb 2017 14:23:58 +0100

Drastically improved the dump geometry mode

Replace the -O dump option by the -g one. Add dump options like the output
geometry format and the possibility to split the output data by geometry
or by object.

Diffstat:
Mdoc/cli | 12+++++++++++-
Msrc/solstice.c | 20+++++++++++++-------
Msrc/solstice.h | 7+++++--
Msrc/solstice_args.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/solstice_args.h.in | 19+++++++++++++++++--
Msrc/solstice_c.h | 14+++++++++++++-
Msrc/solstice_dump_obj.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/solstice_entity.c | 6++++++
Msrc/solstice_node.c | 16++++++++++++++++
Msrc/test_solstice_args.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 327 insertions(+), 27 deletions(-)

diff --git a/doc/cli b/doc/cli @@ -4,7 +4,7 @@ solstice -D <sun-dir-list> -f # Force output overwrite -h # Short help and exit - -O # Switch in dump mode + -g <dump> # Switch in dump geometry -o OUTPUT # defaulting to stdout if not defined -q # don't print a message if no INPUT is submitted -n INTEGER # Realisations count @@ -14,6 +14,7 @@ solstice INPUT # Input scene in YAML solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 +solstice -g format=obj:split-group=1 -d and -D are exclusive @@ -38,6 +39,15 @@ solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 <rendering-option> ::= <fov> | <img> | <position> | <target> | <up> +<dump> ::= + format=<dump-format>[:split=<split-mode>] + +<dump-format> ::= + obj + +<split-mode> ::= + geometry | object | none + <fov> ::= fov=<real3> diff --git a/src/solstice.c b/src/solstice.c @@ -520,7 +520,8 @@ solstice_init solstice->nrealisations = args->nrealisations; solstice->output_hits = args->output_hits; - solstice->dump_obj = args->dump_obj; + solstice->dump_format = args->dump_format; + solstice->dump_split_mode = args->dump_split_mode; exit: return res; @@ -560,6 +561,8 @@ solstice_run(struct solstice* solstice) const double* sun_dirs = NULL; size_t nsun_dirs = 0; size_t i; + int dump; + int draw; res_T res = RES_OK; ASSERT(solstice); @@ -568,12 +571,15 @@ solstice_run(struct solstice* solstice) ASSERT(nsun_dirs%3 == 0); nsun_dirs /= 3/*#dims*/; + dump = solstice->dump_format != SOLSTICE_ARGS_DUMP_NONE; + draw = solstice->framebuffer != NULL; + if(!nsun_dirs) { - if(solstice->dump_obj) { - res = solstice_dump_obj(solstice); + if(dump) { + res = solstice_dump(solstice); if(res != RES_OK) goto error; } else { - ASSERT(solstice->framebuffer); + ASSERT(draw); res = solstice_draw(solstice); if(res != RES_OK) goto error; } @@ -584,11 +590,11 @@ solstice_run(struct solstice* solstice) res = solstice_update_entities(solstice, sun_dir); if(res != RES_OK) goto error; - if(solstice->framebuffer) { + if(draw) { res = solstice_draw(solstice); if(res != RES_OK) goto error; - } else if(solstice->dump_obj) { - res = solstice_dump_obj(solstice); + } else if(dump) { + res = solstice_dump(solstice); if(res != RES_OK) goto error; } else { res = ssol_sun_set_direction(solstice->sun, sun_dir); diff --git a/src/solstice.h b/src/solstice.h @@ -18,6 +18,7 @@ #include "parser/solparser_material.h" #include "receivers/srcvl.h" +#include "solstice_args.h" #include <rsys/dynamic_array_double.h> #include <rsys/hash_table.h> @@ -25,7 +26,6 @@ #include <rsys/str.h> struct solparser; -struct solstice_args; struct solstice_node; struct ssol_device; struct ssol_material; @@ -87,11 +87,14 @@ struct solstice { struct ssol_camera* camera; struct ssol_image* framebuffer; + /* Dump geometry */ + enum solstice_args_dump_format dump_format; + enum solstice_args_dump_split_mode dump_split_mode; + struct darray_double sun_dirs; /* List of double3 */ size_t nrealisations; /* # realisations */ FILE* output; /* Output stream */ - int dump_obj; /* Dump the geometry */ int output_hits; /* Output per receiver hits */ struct mem_allocator* allocator; diff --git a/src/solstice_args.c b/src/solstice_args.c @@ -54,7 +54,7 @@ print_help(const char* program) " -n REALISATIONS number of realisations. Default is %lu.\n", SOLSTICE_ARGS_DEFAULT.nrealisations); printf( -" -O switch in dump geometry mode.\n"); +" -g <dump> switch in dump geometry mode and configure it.\n"); printf( " -o OUTPUT write results to OUTPUT. If not defined, write results to\n" " standard output.\n"); @@ -298,6 +298,128 @@ error: goto exit; } +static res_T +parse_dump_format(const char* str, enum solstice_args_dump_format* fmt) +{ + res_T res = RES_OK; + ASSERT(str && fmt); + + if(!strcmp(str, "obj")) { + *fmt = SOLSTICE_ARGS_DUMP_OBJ; + } else { + fprintf(stderr, "Invalid dump format `%s'.\n", str); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_dump_split_mode(const char* str, enum solstice_args_dump_split_mode* mode) +{ + res_T res = RES_OK; + ASSERT(str && mode); + + if(!strcmp(str, "geometry")) { + *mode = SOLSTICE_ARGS_DUMP_SPLIT_GEOMETRY; + } else if(!strcmp(str, "none")) { + *mode = SOLSTICE_ARGS_DUMP_SPLIT_NONE; + } else if(!strcmp(str, "object")) { + *mode = SOLSTICE_ARGS_DUMP_SPLIT_OBJECT; + } else { + fprintf(stderr, "Invalid dump split mode `%s'.\n", str); + res = RES_BAD_ARG; + goto error; + } +exit: + return res; +error: + goto exit; +} + +static res_T +parse_dump_option(const char* str, struct solstice_args* args) +{ + char buf[128]; + char* key; + char* val; + char* ctx; + res_T res = RES_OK; + ASSERT(str && args); + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the dump geometry option string `%s'\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + key = strtok_r(buf, "=", &ctx); + val = strtok_r(NULL, "", &ctx); + + if(!val) { + fprintf(stderr, "Missing a value to the dump option `%s'.\n", key); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp(key, "format")) { + res = parse_dump_format(val, &args->dump_format); + } else if(!strcmp(key, "split")) { + res = parse_dump_split_mode(val, &args->dump_split_mode); + } else { + fprintf(stderr, "Invalid dump option `%s'.\n", val); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) goto error; + + if(args->dump_format == SOLSTICE_ARGS_DUMP_NONE) { + fprintf(stderr, "No dump format is defined.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_dump_options(const char* str, struct solstice_args* args) +{ + char buf[512]; + char* tk; + char* ctx; + res_T res = RES_OK; + ASSERT(args && str); + (void)str, (void)args; + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the dump geometry options string `%s'.\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + tk = strtok_r(buf, ":", &ctx); + do { + res = parse_dump_option(tk, args); + tk = strtok_r(NULL, ":", &ctx); + } while(tk); + +exit: + return res; +error: + goto exit; +} + /******************************************************************************* * Local function ******************************************************************************/ @@ -311,7 +433,7 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) *args = SOLSTICE_ARGS_DEFAULT; optind = 0; - while((opt = getopt(argc, argv, "D:fHhn:Oo:qR:r:t:")) != -1) { + while((opt = getopt(argc, argv, "D:fg:Hhn:o:qR:r:t:")) != -1) { switch(opt) { case 'D': res = parse_sun_dir_list(optarg, args); @@ -327,7 +449,7 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) res = cstr_to_ulong(optarg, &args->nrealisations); if(res == RES_OK && !args->nrealisations) res = RES_BAD_ARG; break; - case 'O': args->dump_obj = 1; break; + case 'g': res = parse_dump_options(optarg, args); break; case 'o': args->output_filename = optarg; break; case 'q': args->quiet = 1; break; case 'R': args->receivers_filename = optarg; break; @@ -347,14 +469,16 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) } } - if(!args->rendering && !args->dump_obj && !args->nsun_dirs) { + if(!args->rendering + && args->dump_format == SOLSTICE_ARGS_DUMP_NONE + && !args->nsun_dirs) { fprintf(stderr, "Missing sun direction.\n"); res = RES_BAD_ARG; goto error; } - if(args->dump_obj && args->rendering) { - fprintf(stderr, "The '-O' and '-r' options are exclusive\n"); + if(args->dump_format != SOLSTICE_ARGS_DUMP_NONE && args->rendering) { + fprintf(stderr, "The '-g' and '-r' options are exclusive\n"); res = RES_BAD_ARG; goto error; } diff --git a/src/solstice_args.h.in b/src/solstice_args.h.in @@ -24,6 +24,17 @@ struct solstice_args_spherical { double elevation; /* In radians */ }; +enum solstice_args_dump_format { + SOLSTICE_ARGS_DUMP_OBJ, + SOLSTICE_ARGS_DUMP_NONE +}; + +enum solstice_args_dump_split_mode { + SOLSTICE_ARGS_DUMP_SPLIT_GEOMETRY, + SOLSTICE_ARGS_DUMP_SPLIT_NONE, + SOLSTICE_ARGS_DUMP_SPLIT_OBJECT +}; + struct solstice_args { const char* output_filename; const char* input_filename; /* May be NULL <=> read data from stdin */ @@ -47,8 +58,10 @@ struct solstice_args { unsigned long height; } img; + enum solstice_args_dump_format dump_format; + enum solstice_args_dump_split_mode dump_split_mode; + int force_overwriting; - int dump_obj; int rendering; int output_hits; /* Output the per receiver hits */ int quiet; @@ -80,8 +93,10 @@ static const struct solstice_args SOLSTICE_ARGS_NULL = SOLSTICE_ARGS_NULL__; @SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT@ \ }, \ \ + SOLSTICE_ARGS_DUMP_NONE, /* Dump format */ \ + SOLSTICE_ARGS_DUMP_SPLIT_NONE, /* Dump split mode */ \ + \ 0, /* Force overwriting */ \ - 0, /* Dump */ \ 0, /* Rendering */ \ 0, /* Output hits */ \ 0, /* Quiet */ \ diff --git a/src/solstice_c.h b/src/solstice_c.h @@ -20,6 +20,8 @@ #include "parser/solparser.h" #include <rsys/ref_count.h> +#include <rsys/str.h> + #include <solstice/sanim.h> enum solstice_node_type { @@ -32,6 +34,7 @@ enum solstice_node_type { struct solstice_node { struct sanim_node anim; + struct str name; enum solstice_node_type type; struct ssol_instance* instance; /* Available for geometry nodes */ @@ -50,7 +53,7 @@ solstice_solve (struct solstice* solstice); extern LOCAL_SYM res_T -solstice_dump_obj +solstice_dump (struct solstice* solstice); extern LOCAL_SYM res_T @@ -110,6 +113,15 @@ solstice_node_ref_put (struct solstice_node* node); extern LOCAL_SYM res_T +solstice_node_set_name + (struct solstice_node* node, + const char* name); + +extern LOCAL_SYM const char* +solstice_node_get_name + (const struct solstice_node* node); + +extern LOCAL_SYM res_T solstice_node_geometry_set_primary (struct solstice_node* node, const int is_primary); diff --git a/src/solstice_dump_obj.c b/src/solstice_dump_obj.c @@ -19,6 +19,7 @@ struct dump_context { FILE* output; size_t ids_offset; + enum solstice_args_dump_split_mode split_mode; }; /******************************************************************************* @@ -29,8 +30,20 @@ dump_instantiated_shaded_shape (struct ssol_instantiated_shaded_shape* sshape, struct dump_context* ctx) { unsigned i, ntris, nverts; + enum ssol_material_type type; + const char* mtl; ASSERT(sshape && ctx); + SSOL(material_get_type(sshape->mtl_front, &type)); + switch(type) { + case SSOL_MATERIAL_MATTE: mtl = "matte"; break; + case SSOL_MATERIAL_MIRROR: mtl = "mirror"; break; + case SSOL_MATERIAL_VIRTUAL: mtl = "virtual"; break; + default: FATAL("Unexpected Solstice Solver material type.\n"); break; + } + + fprintf(ctx->output, "usemtl %s\n", mtl); + SSOL(shape_get_vertices_count(sshape->shape, &nverts)); FOR_EACH(i, 0, nverts) { double pos[3]; @@ -50,7 +63,12 @@ dump_instantiated_shaded_shape (unsigned long)(ids[2] + 1 + ctx->ids_offset)); } - ctx->ids_offset += nverts; + if(ctx->split_mode == SOLSTICE_ARGS_DUMP_SPLIT_OBJECT) { + fprintf(ctx->output, "---\n"); + ctx->ids_offset = 0; + } else { + ctx->ids_offset += nverts; + } } static res_T @@ -63,7 +81,6 @@ dump_instance(struct ssol_instance* instance, void* context) SSOL(instance_get_shaded_shapes_count(instance, &n)); FOR_EACH(i, 0, n) { struct ssol_instantiated_shaded_shape sshape; - SSOL(instance_get_shaded_shape(instance, i, &sshape)); dump_instantiated_shaded_shape(&sshape, ctx); } @@ -71,23 +88,55 @@ dump_instance(struct ssol_instance* instance, void* context) return RES_OK; } +static res_T +dump_geometry + (const struct sanim_node* n, const double transform[12], void* data) +{ + struct solstice_node* node; + struct dump_context* ctx = data; + res_T res = RES_OK; + ASSERT(n && data); + (void)transform; + + node = CONTAINER_OF(n, struct solstice_node, anim); + if(node->type != SOLSTICE_NODE_GEOMETRY) return RES_OK; + fprintf(ctx->output, "g %s\n", solstice_node_get_name(node)); + res = dump_instance(node->instance, data); + if(res != RES_OK) return res; + + if(ctx->split_mode == SOLSTICE_ARGS_DUMP_SPLIT_GEOMETRY) { + fprintf(ctx->output, "---\n"); + ctx->ids_offset = 0; + } + return RES_OK; +} + /******************************************************************************* * Local functions ******************************************************************************/ res_T -solstice_dump_obj(struct solstice* solstice) +solstice_dump(struct solstice* solstice) { struct dump_context ctx; + double dummy_dir[3] = {0, 0, 1}; + size_t i, n; res_T res = RES_OK; - ASSERT(solstice); + ASSERT(solstice && solstice->dump_format == SOLSTICE_ARGS_DUMP_OBJ); ctx.output = solstice->output; ctx.ids_offset = 0; + ctx.split_mode = solstice->dump_split_mode; + + n = darray_nodes_size_get(&solstice->roots); + FOR_EACH(i, 0, n) { + struct solstice_node* node = darray_nodes_data_get(&solstice->roots)[i]; - res = ssol_scene_for_each_instance(solstice->scene, dump_instance, &ctx); - if(res != RES_OK) { - fprintf(stderr, "Could not dump the solstice geometry.\n"); - goto error; + fprintf(solstice->output, "# %s\n", solstice_node_get_name(node)); + res = sanim_node_visit_tree(&node->anim, dummy_dir, &ctx, dump_geometry); + if(res != RES_OK) { + fprintf(stderr, "Could not dump the solstice geometry.\n"); + goto error; + } } exit: diff --git a/src/solstice_entity.c b/src/solstice_entity.c @@ -255,6 +255,12 @@ create_node goto error; } + res = solstice_node_set_name(node, str_cget(name)); + if(res != RES_OK) { + fprintf(stderr, "Could not setup the solstice node name.\n"); + goto error; + } + /* Setup the primary parameter for the geometry entity */ if(entity->type == SOLPARSER_ENTITY_GEOMETRY) { res = solstice_node_geometry_set_primary(node, entity->primary); diff --git a/src/solstice_node.c b/src/solstice_node.c @@ -37,6 +37,7 @@ node_create } ref_init(&node->ref); + str_init(allocator, &node->name); node->type = type; node->anim = SANIM_NODE_NULL; node->allocator = allocator; @@ -61,6 +62,7 @@ node_release(ref_T* ref) node = CONTAINER_OF(ref, struct solstice_node, ref); if(node->instance) SSOL(instance_ref_put(node->instance)); + str_release(&node->name); SANIM(node_is_initialized(&node->anim, &is_init)); if(is_init) { @@ -222,6 +224,20 @@ solstice_node_ref_put(struct solstice_node* node) } res_T +solstice_node_set_name(struct solstice_node* node, const char* name) +{ + ASSERT(node); + return str_set(&node->name, name); +} + +const char* +solstice_node_get_name(const struct solstice_node* node) +{ + ASSERT(node); + return str_cget(&node->name); +} + +res_T solstice_node_geometry_set_primary (struct solstice_node* node, const int is_primary) { diff --git a/src/test_solstice_args.c b/src/test_solstice_args.c @@ -459,6 +459,64 @@ test_input(void) cmd_delete(cmd); } +static void +test_dump(void) +{ + struct solstice_args args = SOLSTICE_ARGS_NULL; + char** cmd = NULL; + + cmd = cmd_create(0, "test", "-D", "0,90", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_format, SOLSTICE_ARGS_DUMP_NONE); + CHECK(args.dump_split_mode, SOLSTICE_ARGS_DUMP_SPLIT_NONE); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_format, SOLSTICE_ARGS_DUMP_OBJ); + CHECK(args.dump_split_mode, SOLSTICE_ARGS_DUMP_SPLIT_NONE); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "split=geometry:format=obj", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_format, SOLSTICE_ARGS_DUMP_OBJ); + CHECK(args.dump_split_mode, SOLSTICE_ARGS_DUMP_SPLIT_GEOMETRY); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj:split=object", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_format, SOLSTICE_ARGS_DUMP_OBJ); + CHECK(args.dump_split_mode, SOLSTICE_ARGS_DUMP_SPLIT_OBJECT); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj::::split=none", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_format, SOLSTICE_ARGS_DUMP_OBJ); + CHECK(args.dump_split_mode, SOLSTICE_ARGS_DUMP_SPLIT_NONE); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "split=object", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=stl", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj:dummy", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj:split", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); +} + int main(int argc, char** argv) { @@ -472,6 +530,7 @@ main(int argc, char** argv) test_quiet(); test_receivers(); test_input(); + test_dump(); CHECK(mem_allocated_size(), 0); return 0; }