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 693d9c633d293a63756924b03f4fade44de94925
parent 2226e05667eb32b0b117bc15216ea7952dcc0a25
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu,  2 Mar 2017 16:32:19 +0100

Add an "auto look at" in rendering mode

If no position and no target is explicitly defined through the -r
option, automatically compute the rendering point of view to ensure that
the whole scene is visible.

Diffstat:
Msrc/solstice.c | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/solstice_args.c | 2++
Msrc/solstice_args.h.in | 4+++-
3 files changed, 111 insertions(+), 11 deletions(-)

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 */ \