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 e6728748b90a6da11dba299c18f0b24dec3a55bc
parent 00622de9cfa91fd88b811687f77afb5158adda67
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  6 Mar 2017 09:49:30 +0100

Merge branch 'develop' into feature_hyperbols

Diffstat:
Msrc/parser/solparser.c | 19-------------------
Msrc/parser/solparser_pivot.h | 40+++++++++++++++++++++++++++-------------
Msrc/solstice.c | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/solstice_args.c | 2++
Msrc/solstice_args.h.in | 4+++-
Msrc/solstice_entity.c | 143++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
6 files changed, 222 insertions(+), 102 deletions(-)

diff --git a/src/parser/solparser.c b/src/parser/solparser.c @@ -217,7 +217,6 @@ struct solparser { struct solparser_sun sun; /* The loaded sun */ /* Entity */ - struct htable_yaml2sols yaml2entities; /* Cache of entities */ struct htable_str2sols str2entities; struct darray_entity entities; @@ -416,7 +415,6 @@ parser_clear(struct solparser* parser) parser->sun_key = 0; /* Entities */ - htable_yaml2sols_clear(&parser->yaml2entities); htable_str2sols_clear(&parser->str2entities); darray_entity_clear(&parser->entities); @@ -468,7 +466,6 @@ parser_release(ref_T* ref) solparser_sun_release(&parser->sun); /* Entities */ - htable_yaml2sols_release(&parser->yaml2entities); htable_str2sols_release(&parser->str2entities); darray_entity_release(&parser->entities); @@ -2790,7 +2787,6 @@ parse_entity enum { ANCHORS, CHILDREN, DATA, NAME, TRANSFORM, PRIMARY }; struct solparser_entity solent; struct solparser_entity* psolent; - const size_t *pisolent; size_t isolent = SIZE_MAX; intptr_t i, n; int mask = 0; /* Register the parsed attributes */ @@ -2799,14 +2795,6 @@ parse_entity solparser_entity_init(parser->allocator, &solent); - pisolent = htable_yaml2sols_find(&parser->yaml2entities, &entity); - if(pisolent) { - isolent = *pisolent; - res = entity_register_name(parser, entity, htable, *pisolent); - if(res != RES_OK) goto error; - goto exit; - } - if(entity->type != YAML_MAPPING_NODE) { log_err(parser, entity, "expect an entity definition.\n"); res = RES_BAD_ARG; @@ -2928,12 +2916,6 @@ parse_entity res = entity_register_name(parser, entity, htable, isolent); if(res != RES_OK) goto error; - res = htable_yaml2sols_set(&parser->yaml2entities, &entity, &isolent); - if(res != RES_OK) { - log_err(parser, entity, "could not register the entity.\n"); - goto error; - } - exit: solparser_entity_release(&solent); out_isolent->i = isolent; @@ -3664,7 +3646,6 @@ solparser_create solparser_sun_init(mem_allocator, &parser->sun); /* Entities */ - htable_yaml2sols_init(mem_allocator, &parser->yaml2entities); htable_str2sols_init(mem_allocator, &parser->str2entities); darray_entity_init(mem_allocator, &parser->entities); diff --git a/src/parser/solparser_pivot.h b/src/parser/solparser_pivot.h @@ -18,15 +18,9 @@ #include <rsys/double3.h> -enum solparser_target_type { - SOLPARSER_TARGET_ANCHOR, - SOLPARSER_TARGET_DIRECTION, - SOLPARSER_TARGET_POSITION, - SOLPARSER_TARGET_SUN, - - SOLPARSER_TARGET_TYPES_COUNT__ -}; - +/******************************************************************************* + * Anchor + ******************************************************************************/ struct solparser_anchor_id { size_t i; }; struct solparser_anchor { @@ -67,6 +61,18 @@ solparser_anchor_copy_and_release return str_copy_and_release(&dst->name, &src->name); } +/******************************************************************************* + * Target + ******************************************************************************/ +enum solparser_target_type { + SOLPARSER_TARGET_ANCHOR, + SOLPARSER_TARGET_DIRECTION, + SOLPARSER_TARGET_POSITION, + SOLPARSER_TARGET_SUN, + + SOLPARSER_TARGET_TYPES_COUNT__ +}; + struct solparser_target { enum solparser_target_type type; union { @@ -75,10 +81,14 @@ struct solparser_target { struct solparser_anchor_id anchor; } data; }; -#define SOLPARSER_TARGET_NULL__ { SOLPARSER_TARGET_TYPES_COUNT__, {{0,0,0}} } +#define SOLPARSER_TARGET_NULL__ { 0 } static const struct solparser_target SOLPARSER_TARGET_NULL = SOLPARSER_TARGET_NULL__; + +/******************************************************************************* + * X pivot + ******************************************************************************/ struct solparser_pivot_id { size_t i; }; struct solparser_x_pivot { @@ -92,12 +102,16 @@ static const struct solparser_x_pivot SOLPARSER_X_PIVOT_NULL = static INLINE void solparser_x_pivot_init -(struct mem_allocator* allocator, struct solparser_x_pivot* x_pivot) + (struct mem_allocator* allocator, struct solparser_x_pivot* x_pivot) { - (void) allocator; + (void)allocator; ASSERT(x_pivot); *x_pivot = SOLPARSER_X_PIVOT_NULL; } + +/******************************************************************************* + * ZX pivot + ******************************************************************************/ struct solparser_zx_pivot { double spacing; double ref_point[3]; @@ -112,7 +126,7 @@ static INLINE void solparser_zx_pivot_init (struct mem_allocator* allocator, struct solparser_zx_pivot* zx_pivot) { - (void) allocator; + (void)allocator; ASSERT(zx_pivot); *zx_pivot = SOLPARSER_ZX_PIVOT_NULL; } diff --git a/src/solstice.c b/src/solstice.c @@ -44,7 +44,6 @@ #include <unistd.h> #endif - #include <solstice/ssol.h> /******************************************************************************* @@ -95,10 +94,99 @@ clear_nodes(struct darray_nodes* nodes) } static res_T +auto_look_at + (struct ssol_scene* scn, + const double fov_x, /* Horizontal field of view in radian */ + const double proj_ratio, /* Width / height */ + const double up[3], /* Up vector */ + double position[3], + double target[3]) +{ + float flower[3], fupper[3]; + double lower[3], upper[3]; + double up_abs[3]; + double axis_min[3]; + double axis_x[3]; + double axis_z[3]; + double tmp[3]; + double radius; + double depth; + res_T res; + ASSERT(scn && fov_x && proj_ratio && up); + + res = ssol_scene_compute_aabb(scn, flower, fupper); + if(res != RES_OK) { + fprintf(stderr, "Couldn't compute the scene bounding box.\n"); + goto error; + } + + if(flower[0] > fupper[0] + || flower[1] > fupper[1] + || flower[2] > fupper[2]) { /* Empty scene */ + d3_set(position, SOLSTICE_ARGS_DEFAULT.camera.pos); + d3_set(target, SOLSTICE_ARGS_DEFAULT.camera.tgt); + goto exit; + } + + d3_set_f3(upper, fupper); + d3_set_f3(lower, flower); + + /* The target is the scene centroid */ + d3_muld(target, d3_add(target, lower, upper), 0.5); + + /* Define which up dimension is minimal and use its unit vector to compute a + * vector orthogonal to `up'. This ensures that the unit vector and `up' are + * not collinear and thus that their cross product is not a zero vector. */ + up_abs[0] = fabs(up[0]); + up_abs[1] = fabs(up[1]); + up_abs[2] = fabs(up[2]); + if(up_abs[0] < up_abs[1]) { + if(up_abs[0] < up_abs[2]) d3(axis_min, 1, 0, 0); + else d3(axis_min, 0, 0, 1); + } else { + if(up_abs[1] < up_abs[2]) d3(axis_min, 0, 1, 0); + else d3(axis_min, 0, 0, 1); + } + d3_normalize(axis_x, d3_cross(axis_x, up, axis_min)); + d3_normalize(axis_z, d3_cross(axis_z, up, axis_x)); + + /* Approximate whether on the XYZ or the ZYX basis the visible part of the + * model is maximise */ + if(fabs(d3_dot(axis_x, upper)) < fabs(d3_dot(axis_z, upper))) { + SWAP(double, axis_x[0], axis_z[0]); + SWAP(double, axis_x[1], axis_z[1]); + SWAP(double, axis_x[2], axis_z[2]); + } + + /* Ensure that the whole model is visible */ + radius = d3_len(d3_sub(tmp, upper, lower)) * 0.5; + if(proj_ratio < 1) { + depth = radius / sin(fov_x/2.0); + } else { + depth = radius / sin(fov_x/(2.0*proj_ratio)); + } + + /* Define the camera position */ + d3_sub(position, target, d3_muld(tmp, axis_z, depth)); + + /* Empirically move the position to find a better point of view */ + d3_add(position, position, d3_muld(tmp, up, radius)); /*Empirical offset*/ + d3_add(position, position, d3_muld(tmp, axis_x, radius)); /*Empirical offset*/ + d3_normalize(tmp, d3_sub(tmp, target, position)); + d3_sub(position, target, d3_muld(tmp, tmp, depth)); + +exit: + return res; +error: + goto exit; +} + +static res_T setup_camera(struct solstice* solstice, const struct solstice_args* args) { struct ssol_camera* cam = NULL; double proj_ratio = 0; + double pos[3], tgt[3]; res_T res = RES_OK; ASSERT(solstice && args); @@ -122,8 +210,16 @@ setup_camera(struct solstice* solstice, const struct solstice_args* args) goto error; } - res = ssol_camera_look_at - (cam, args->camera.pos, args->camera.tgt, args->camera.up); + if(!args->camera.auto_look_at) { + d3_set(pos, args->camera.pos); + d3_set(tgt, args->camera.tgt); + } else { + res = auto_look_at(solstice->scene, MDEG2RAD(args->camera.fov_x), + proj_ratio, args->camera.up, pos, tgt); + if(res != RES_OK) goto error; + } + + res = ssol_camera_look_at(cam, pos, tgt, args->camera.up); if(res != RES_OK) { fprintf(stderr, "Invalid camera point of view:\n" @@ -462,13 +558,6 @@ solstice_init goto error; } - if(args->rendering) { - res = setup_camera(solstice, args); - if(res != RES_OK) goto error; - res = setup_framebuffer(solstice, args); - if(res != RES_OK) goto error; - } - res = setup_sun_dirs(solstice, args); if(res != RES_OK) goto error; @@ -505,6 +594,13 @@ solstice_init solstice->dump_format = args->dump_format; solstice->dump_split_mode = args->dump_split_mode; + if(args->rendering) { + res = setup_camera(solstice, args); + if(res != RES_OK) goto error; + res = setup_framebuffer(solstice, args); + if(res != RES_OK) goto error; + } + exit: return res; error: diff --git a/src/solstice_args.c b/src/solstice_args.c @@ -238,6 +238,7 @@ parse_rendering_option(const char* str, struct solstice_args* args) fprintf(stderr, "Invalid camera position `%s'.\n", val); goto error; } + args->camera.auto_look_at = 0; /* Disable auto look at */ } else if(!strcmp(key, "tgt")) { res = cstr_to_list_double(val, ',', args->camera.tgt, &len, 3); if(res == RES_OK && len != 3) res = RES_BAD_ARG; @@ -245,6 +246,7 @@ parse_rendering_option(const char* str, struct solstice_args* args) fprintf(stderr, "Invalid camera target `%s'.\n", val); goto error; } + args->camera.auto_look_at = 0; /* Disable auto look at */ } else if(!strcmp(key, "up")) { res = cstr_to_list_double(val, ',', args->camera.up, &len, 3); if(res == RES_OK && len != 3) res = RES_BAD_ARG; diff --git a/src/solstice_args.h.in b/src/solstice_args.h.in @@ -51,6 +51,7 @@ struct solstice_args { double tgt[3]; double up[3]; double fov_x; /* In radians */ + int auto_look_at; } camera; struct { @@ -85,7 +86,8 @@ static const struct solstice_args SOLSTICE_ARGS_NULL = SOLSTICE_ARGS_NULL__; { @SOLSTICE_ARGS_DEFAULT_CAMERA_POS@ }, \ { @SOLSTICE_ARGS_DEFAULT_CAMERA_TGT@ }, \ { @SOLSTICE_ARGS_DEFAULT_CAMERA_UP@ }, \ - @SOLSTICE_ARGS_DEFAULT_CAMERA_FOV@ \ + @SOLSTICE_ARGS_DEFAULT_CAMERA_FOV@, \ + 1, \ }, \ \ { /* Image */ \ diff --git a/src/solstice_entity.c b/src/solstice_entity.c @@ -35,6 +35,33 @@ update_instance_transform return ssol_instance_set_transform(node->instance, transform); } +static res_T +merge_name + (struct str* RESTRICT output, + const struct str* name0, + const struct str* name1) +{ + res_T res = RES_OK; + ASSERT(output && name0 && name1); + ASSERT(output != name0 && output != name1); + + res = str_copy(output, name0); + if(res != RES_OK) goto error; + + res = str_append_char(output, '.'); + if(res != RES_OK) goto error; + + res = str_append(output, str_cget(name1)); + if(res != RES_OK) goto error; + +exit: + return res; +error: + fprintf(stderr, "Could not build the name from `%s' and `%s'.\n", + str_cget(name0), str_cget(name1)); + goto exit; +} + static INLINE int srcvl_side_to_ssol_mask(const enum srcvl_side side) { @@ -100,7 +127,7 @@ error: static res_T get_anchor_node (struct solstice* solstice, - struct solparser_anchor_id anchor_id, + const struct solparser_anchor_id anchor_id, struct solstice_node** out_node) { struct solstice_node* node = NULL; @@ -114,7 +141,6 @@ get_anchor_node } else { res = solstice_node_target_create(solstice->allocator, &node); if(res != RES_OK) goto error; - res = htable_anchor_set(&solstice->anchors, &anchor_id.i, &node); if(res != RES_OK) goto error; } @@ -127,6 +153,48 @@ error: goto exit; } +static res_T +setup_tracking + (struct solstice* solstice, + struct sanim_tracking* tracking, + const struct solparser_target* target) +{ + struct solstice_node* anchor_node = NULL; + struct str anchor_name; + res_T res = RES_OK; + ASSERT(solstice && tracking && target); + + str_init(solstice->allocator, &anchor_name); + + switch(target->type) { + case SOLPARSER_TARGET_ANCHOR: + tracking->policy = TRACKING_NODE_TARGET; + res = get_anchor_node(solstice, target->data.anchor, &anchor_node); + if(res != RES_OK) goto error; + solstice_node_target_get_tracking(anchor_node, tracking); + break; + case SOLPARSER_TARGET_DIRECTION: + tracking->policy = TRACKING_OUT_DIR; + d3_set(tracking->data.out_dir.u, target->data.direction); + break; + case SOLPARSER_TARGET_POSITION: + tracking->policy = TRACKING_POINT; + d3_set(tracking->data.point.target, target->data.position); + tracking->data.point.target_is_local = 0; /* TODO */ + break; + case SOLPARSER_TARGET_SUN: + tracking->policy = TRACKING_SUN; + break; + default: FATAL("Unreachable code.\n"); break; + } + +exit: + str_release(&anchor_name); + return res; +error: + goto exit; +} + static struct solstice_node* create_x_pivot_node @@ -135,7 +203,6 @@ create_x_pivot_node { double n[3]; struct solstice_node* node = NULL; - struct solstice_node* target = NULL; const struct solparser_x_pivot* parser_x_pivot = NULL; struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL; struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL; @@ -148,28 +215,8 @@ create_x_pivot_node d3_set(anim_pivot.data.pivot1.ref_normal, d3(n, 0, 0, 1)); d3_set(anim_pivot.data.pivot1.ref_point, parser_x_pivot->ref_point); - /* Setup the tracking descriptor */ - switch (parser_x_pivot->target.type) { - case SOLPARSER_TARGET_ANCHOR: - anim_tracking.policy = TRACKING_NODE_TARGET; - target = *htable_anchor_find - (&solstice->anchors, &parser_x_pivot->target.data.anchor.i); - solstice_node_target_get_tracking(target, &anim_tracking); - break; - case SOLPARSER_TARGET_DIRECTION: - anim_tracking.policy = TRACKING_OUT_DIR; - d3_set(anim_tracking.data.out_dir.u, parser_x_pivot->target.data.direction); - break; - case SOLPARSER_TARGET_POSITION: - anim_tracking.policy = TRACKING_POINT; - d3_set(anim_tracking.data.point.target, parser_x_pivot->target.data.position); - anim_tracking.data.point.target_is_local = 0; /* TODO */ - break; - case SOLPARSER_TARGET_SUN: - anim_tracking.policy = TRACKING_SUN; - break; - default: FATAL("Unreachable code.\n"); break; - } + res = setup_tracking(solstice, &anim_tracking, &parser_x_pivot->target); + if(res != RES_OK) goto error; res = solstice_node_pivot_create (solstice->allocator, &anim_pivot, &anim_tracking, &node); @@ -194,7 +241,6 @@ create_zx_pivot_node const struct solparser_entity* entity) { struct solstice_node* node = NULL; - struct solstice_node* target = NULL; const struct solparser_zx_pivot* parser_zx_pivot = NULL; struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL; struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL; @@ -207,35 +253,15 @@ create_zx_pivot_node anim_pivot.data.pivot2.spacing = parser_zx_pivot->spacing; d3_set(anim_pivot.data.pivot2.ref_point, parser_zx_pivot->ref_point); - /* Setup the tracking descriptor */ - switch (parser_zx_pivot->target.type) { - case SOLPARSER_TARGET_ANCHOR: - anim_tracking.policy = TRACKING_NODE_TARGET; - CHECK(RES_OK, - get_anchor_node(solstice, parser_zx_pivot->target.data.anchor, &target)); - solstice_node_target_get_tracking(target, &anim_tracking); - break; - case SOLPARSER_TARGET_DIRECTION: - anim_tracking.policy = TRACKING_OUT_DIR; - d3_set(anim_tracking.data.out_dir.u, parser_zx_pivot->target.data.direction); - break; - case SOLPARSER_TARGET_POSITION: - anim_tracking.policy = TRACKING_POINT; - d3_set(anim_tracking.data.point.target, parser_zx_pivot->target.data.position); - anim_tracking.data.point.target_is_local = 0; /* TODO */ - break; - case SOLPARSER_TARGET_SUN: - anim_tracking.policy = TRACKING_SUN; - break; - default: FATAL("Unreachable code.\n"); break; - } + res = setup_tracking(solstice, &anim_tracking, &parser_zx_pivot->target); + if(res != RES_OK) goto error; res = solstice_node_pivot_create (solstice->allocator, &anim_pivot, &anim_tracking, &node); - if (res != RES_OK) goto error; + if(res != RES_OK) goto error; res = darray_nodes_push_back(&solstice->pivots, &node); - if (res != RES_OK) goto error; + if(res != RES_OK) goto error; exit: return node; @@ -257,12 +283,14 @@ create_node struct solstice_node* child = NULL; struct solstice_receiver* rcv = NULL; struct str child_name; + struct str anchor_name; double rotation[3]; size_t i; res_T res = RES_OK; ASSERT(solstice && entity && name); str_init(solstice->allocator, &child_name); + str_init(solstice->allocator, &anchor_name); /* Create the entity node */ switch(entity->type) { @@ -333,6 +361,9 @@ create_node id = solparser_entity_get_anchor(entity, i); anchor = solparser_get_anchor(solstice->parser, id); + res = merge_name(&anchor_name, name, &anchor->name); + if(res != RES_OK) goto error; + res = get_anchor_node(solstice, id, &tgt); if(res != RES_OK) goto error; @@ -353,15 +384,8 @@ create_node id = solparser_entity_get_child(entity, i); child_entity = solparser_get_entity(solstice->parser, id); - #define CALL(Func) \ - if(RES_OK != (res = Func)) { \ - fprintf(stderr, "Could not build the absolute entity name.\n"); \ - goto error; \ - } (void)0 - CALL(str_copy(&child_name, name)); - CALL(str_append_char(&child_name, '.')); - CALL(str_append(&child_name, str_cget(&child_entity->name))); - #undef CALL + res = merge_name(&child_name, name, &child_entity->name); + if(res != RES_OK) goto error; child = create_node(solstice, child_entity, &child_name); if(!child) goto error; @@ -375,6 +399,7 @@ create_node exit: str_release(&child_name); + str_release(&anchor_name); return node; error: if(child) solstice_node_ref_put(child);