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 25c08ed6760fe359f2482dc5e7cccd92f8544a41
parent 36c5dd6f23e96e2e95daced71fe97e776c3f4bf7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 27 Mar 2017 15:52:47 +0200

Merge branch 'release_0.1'

Diffstat:
Mcmake/CMakeLists.txt | 18++++++++++++++++++
Mcmake/parser/CMakeLists.txt | 12+++++++++---
Mcmake/receivers/CMakeLists.txt | 1+
Mdoc/cli | 38+++++++++++++++++++++++++++++++++++---
Mdoc/input | 487+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mdoc/output | 26++++++++++++++++++++++----
Mdoc/receiver | 1+
Msrc/parser/solparser.c | 613++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/parser/solparser.h | 20++++++++++++++++++++
Msrc/parser/solparser_material.h | 26++++++++++++++++++++++++++
Msrc/parser/solparser_pivot.h | 40+++++++++++++++++++++++++++-------------
Msrc/parser/solparser_shape.h | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/parser/test_solparser2.c | 1-
Msrc/parser/test_solparser3.c | 48+++++++++++++++++++++++++++++++++++++++++++++---
Msrc/parser/test_solparser6.c | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Asrc/parser/test_solparser7.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/test_solparser8.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/yaml/test_ko_0.yaml | 482+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Asrc/parser/yaml/test_ok_5.yaml | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/yaml/test_ok_6.yaml | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/yaml/test_ok_7.yaml | 40++++++++++++++++++++++++++++++++++++++++
Msrc/receivers/srcvl.c | 41++++++++++++++++++++++++++++++++++++++---
Msrc/receivers/srcvl.h | 1+
Msrc/receivers/test_srcvl2.c | 19++++++++++++++++++-
Msrc/receivers/yaml/test_ko.yaml | 8++++++++
Msrc/receivers/yaml/test_ok.yaml | 2++
Msrc/solstice.c | 275+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/solstice.h | 16++++++++++++++--
Msrc/solstice_args.c | 285+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/solstice_args.h.in | 48+++++++++++++++++++++++++++++++++++++++++++-----
Msrc/solstice_c.h | 19++++++++++++++++++-
Msrc/solstice_draw.c | 13+++++++++++--
Asrc/solstice_dump.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/solstice_entity.c | 188++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/solstice_material.c | 113++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/solstice_node.c | 21+++++++++++++++++++--
Msrc/solstice_object.c | 59++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/solstice_solve.c | 390++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/test_solstice_args.c | 243++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Asrc/test_solstice_simulation.c | 434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/beam_down.ref | 12++++++++++++
Ayaml/beam_down.yaml | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/beam_down_receiver.yaml | 3+++
Ayaml/test01.ref | 5+++++
Ayaml/test01.yaml | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test01_receiver.yaml | 1+
Ayaml/test02.ref | 5+++++
Ayaml/test02.yaml | 47+++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test02_receiver.yaml | 1+
Ayaml/test03.ref | 5+++++
Ayaml/test03.yaml | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test03_receiver.yaml | 1+
Ayaml/test04.ref | 4++++
Ayaml/test04.yaml | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test04_receiver.yaml | 1+
Ayaml/test05.ref | 5+++++
Ayaml/test05.yaml | 44++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test05_receiver.yaml | 1+
58 files changed, 4409 insertions(+), 681 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -70,6 +70,7 @@ set(SOLSTICE_ARGS_DEFAULT_CAMERA_UP "0,1,0") set(SOLSTICE_ARGS_DEFAULT_CAMERA_FOV "70") # In degrees set(SOLSTICE_ARGS_DEFAULT_IMG_WIDTH "800") set(SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT "600") +set(SOLSTICE_ARGS_DEFAULT_IMG_SPP "1") configure_file(${SOLSTICE_SOURCE_DIR}/solstice_args.h.in ${CMAKE_CURRENT_BINARY_DIR}/solstice_args.h @ONLY) @@ -86,6 +87,7 @@ set(SOLSTICE_FILES_SRC solstice.c solstice_args.c solstice_draw.c + solstice_dump.c solstice_entity.c solstice_material.c solstice_node.c @@ -138,6 +140,22 @@ if(NOT NO_TEST) new_test(test_solstice_args) + build_test(test_solstice_simulation) + function(add_test_simulation _name) + add_test(NAME test_solstice_simulation_${_name} + COMMAND test_solstice_simulation + $<TARGET_FILE:solstice> + ${SOLSTICE_SOURCE_DIR}/../yaml/ + ${_name}) + endfunction() + + add_test_simulation(beam_down) + add_test_simulation(test01) + add_test_simulation(test02) + add_test_simulation(test03) + add_test_simulation(test04) + add_test_simulation(test05) + endif() ################################################################################ diff --git a/cmake/parser/CMakeLists.txt b/cmake/parser/CMakeLists.txt @@ -39,7 +39,7 @@ set(SOLPARSER_FILES_INC solparser_shape.h solparser_sun.h) -# Prepend each file in the `SOLSTICE_FILES_<SRC|INC>' list by `SOLSTICE_SOURCE_DIR' +# Prepend each file in the `SOLPARSER_FILES_<SRC|INC>' list by `SOLPARSER_SOURCE_DIR' rcmake_prepend_path(SOLPARSER_FILES_SRC ${SOLPARSER_SOURCE_DIR}) rcmake_prepend_path(SOLPARSER_FILES_INC ${SOLPARSER_SOURCE_DIR}) rcmake_prepend_path(SOLPARSER_FILES_DOC ${PROJECT_SOURCE_DIR}/../) @@ -68,8 +68,6 @@ if(NOT NO_TEST) endfunction() build_test(test_solparser) - add_test(test_grammar_example test_solparser - ${PROJECT_SOURCE_DIR}/../../doc/input) add_test(test_solparser_ok_0 test_solparser ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_0.yaml) add_test(test_solparser_ok_1 test_solparser @@ -80,6 +78,12 @@ if(NOT NO_TEST) ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_3.yaml) add_test(test_solparser_ok_4 test_solparser ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_4.yaml) + add_test(test_solparser_ok_5 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_5.yaml) + add_test(test_solparser_ok_6 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_6.yaml) + add_test(test_solparser_ok_7 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_7.yaml) add_test(test_solparser_ko test_solparser -e ${SOLPARSER_SOURCE_DIR}/yaml/test_ko_0.yaml) @@ -88,6 +92,8 @@ if(NOT NO_TEST) new_test(test_solparser4) new_test(test_solparser5) new_test(test_solparser6) + new_test(test_solparser7) + new_test(test_solparser8) rcmake_copy_runtime_libraries(test_solparser) endif() diff --git a/cmake/receivers/CMakeLists.txt b/cmake/receivers/CMakeLists.txt @@ -65,6 +65,7 @@ if(NOT NO_TEST) ${SRCVL_SOURCE_DIR}/yaml/test_ko.yaml) new_test(test_srcvl2) + rcmake_copy_runtime_libraries(test_srcvl) endif() diff --git a/doc/cli b/doc/cli @@ -4,8 +4,9 @@ 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 + -p <dump-radiative-path> # Switch in dump radiative paths mode -q # don't print a message if no INPUT is submitted -n INTEGER # Realisations count -r <rendering> # Switch in rendering mode @@ -13,7 +14,8 @@ solstice -t INTEGER # Threads count INPUT # Input scene in YAML -solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 +solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70:spp=1 +solstice -g format=obj:split-group=1 -d and -D are exclusive @@ -36,7 +38,28 @@ solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 <rendering-option>[:<rendering-option> ... ] <rendering-option> ::= - <fov> | <img> | <position> | <target> | <up> + <fov> | <img> | <position> | <render-mode> | <samples-per-pixel> | <target> | <up> + +<dump> ::= + format=<dump-format>[:split=<split-mode>] + +<dump-radiative-path> ::= + <dump-path-option>[:<dump-path-option> ... ] + +<dump-path-option> ::= + <sun-ray-len> | <inf-ray-len> | default + +<sun-ray-len> ::= + srlen=REAL + +<inf-ray-len> ::= # Length of the rays going to infinite + irlen=REAL + +<dump-format> ::= + obj + +<split-mode> ::= + geometry | object | none <fov> ::= fov=<real3> @@ -47,6 +70,15 @@ solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 <position> ::= pos=<real3> +<render-mode> ::= + rmode=<render-algorithm> + +<render-algorithm> ::= + draft | pt # path tracing + +<samples-per-pixel> ::= + spp=<INTEGER> + <target> ::= tgt=<real3> diff --git a/doc/input b/doc/input @@ -1,6 +1,6 @@ -# -------------------------------------------------------------------------------- -# 1/ Exemple -# -------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------- +# 1/ Example +#-------------------------------------------------------------------------------- # Declare materials - material: &lambertian matte: @@ -77,223 +77,265 @@ transform: { translation: [10, 11, 12] } children: [ *composition ] -# -------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------- # 2/ Grammar -# -------------------------------------------------------------------------------- -# <solar-factory> ::= -# <sun> -# <items> -# -# <items> ::= -# - <item> -# [ - <item> ... ] -# -# <item> ::= -# <geometry> -# | <material> -# | <entity> -# | <template> -# -# ---------------------------------------- -# <geometry> ::= -# geometry: -# - <object> -# [ - <object> ... ] -# -# <object> ::= -# <shape> -# <material> -# [ <transform> ] -# -# <x_pivot> ::= -# x_pivot: -# [ ref_point: <real3>. Default 0,0,0 ] -# <target> -# -# <zx_pivot> ::= -# zx_pivot: -# [ spacing: REAL # in [0, INF). Default 0 ] -# [ ref_point: <real3>. Default 0,0,0 ] -# <target> -# -# <target> ::= -# target: -# anchor: <anchor-identifier> -# | direction: <real3> -# | position: <real3> -# | <sun> -# -# ---------------------------------------- -# <shape> ::= -# <cuboid> -# | <cylinder> -# | <obj> -# | <parabol> -# | <parabolic-cylinder> -# | <plane> -# | <sphere> -# | <stl> -# -# <cuboid> ::= -# cuboid: -# size: <real3*+> -# -# <cylinder> ::= -# cylinder: -# height: REAL # in ]0, INF) -# radius: REAL # in ]0, INF) -# [ slices: INTEGER ] # in [4, 4096]. Default 16 -# -# <obj> ::= -# obj: -# path: PATH -# -# <parabol> ::= -# parabol: # x^2 + y^2 - 4*focal*z = 0 -# focal: REAL # in ]0, INF) -# clip: <polyclip-list> -# -# <parabolic-cylinder> ::= -# parabolic-cylinder: # y^2 - 4*focal*z = 0 -# focal: REAL # in ]0, INF) -# clip: <polyclip-list> -# -# <plane> ::= -# plane: -# clip: <polyclip-list> -# -# <sphere> ::= -# sphere: -# radius: REAL # in ]0, INF) -# [ slices: INTEGER ] # in [4, 4096]. Default 16 -# -# <stl> ::= -# stl: -# path: PATH -# -# ---------------------------------------- -# <polyclip-list> ::= -# - <polyclip> -# [ - <polyclip> ... ] -# -# <polyclip> ::= -# operation: <AND|SUB> -# vertices: <vertices-list> -# -# <vertices-list> ::= -# - <real2> -# - <real2> -# - <real2> -# [ - <real2> ... ] -# -# ---------------------------------------- -# <material> ::= -# <material-descriptor> | <double-sided-material> -# -# <double-sided-material> ::= -# front: <material-descriptor> -# back: <material-descriptor> -# -# <material-descriptor> ::= -# <mirror> | <matte> | <virtual> -# -# <mirror> ::= -# mirror: -# reflectivity: REAL # in [0, 1] -# roughness: REAL # in [0, 1] -# -# <matte> ::= -# matte: -# reflectivity: REAL # in [0, 1] -# -# <virtual> ::= -# virtual: EMPTY-STRING -# -# ---------------------------------------- -# <entity> ::= -# entity: -# <entity-data> -# -# <template> ::= -# template: -# <entity-data> -# -# <entity-data> ::= -# name: STRING -# [ <geometry-data> | <x_pivot> | <zx_pivot> ] -# [ <anchors> ] -# [ <transform> ] -# [ <children> ] -# -# <geometry-data> ::= -# primary: INTEGER # in [0, 1] -# <geometry> -# -# <children> ::= -# children: -# - <entity-data> -# [ - <entity-data> ... ] -# -# <anchors> ::= -# anchors: -# - <anchor-data> -# [ - <anchor-data> ... ] -# -# <anchor-data> ::= -# name: STRING -# position: <real3> -# -# # "self" references the first level entity -# <entity-identifier> ::= -# <self|STRING>[.STRING ... ] -# -# <anchor-identifier> ::= -# <entity-identifier>.STRING -# -# ---------------------------------------- -# <sun> ::= -# sun: -# dni: REAL # Direct Normal Irradiance in ]0, INF) -# <spectrum> -# [ <radial-angular-distribution> ] -# -# <radial-angular-distribution> ::= -# <pillbox> | <buie> -# -# <buie> ::= -# buie: -# csr: REAL # in [1e-6, 0.849] -# -# <pillbox> ::= -# pillbox: -# aperture: REAL # in ]0, 90] -# -# ---------------------------------------- -# <transform> ::= -# transform: -# translation: <real3> -# rotation: <real3> -# -# <real2> ::= -# - REAL -# - REAL -# -# <real3> ::= -# - REAL -# - REAL -# - REAL -# -# <real3*+> ::= -# - REAL # in ]0, inf) -# - REAL # in ]0, inf) -# - REAL # in ]0, inf) -# -# <spectrum> ::= -# spectrum: -# - <spectrum-data> -# [ - <spectrum-data> ... ] -# -# <spectrum-data> ::= -# wavelength: REAL # in [0, INF) -# data: REAL # in [0, INF) -# -\ No newline at end of file +#-------------------------------------------------------------------------------- +<solar-factory> ::= + <sun> + <items> + +<items> ::= + - <item> +[ - <item> ... ] + +<item> ::= + <geometry> + | <material> + | <entity> + | <template> + +#---------------------------------------- +<geometry> ::= + geometry: + - <object> +[ - <object> ... ] + +<object> ::= + <shape> + <material> +[ <transform> ] + +<x_pivot> ::= + x_pivot: +[ ref_point: <real3>. Default 0,0,0 ] + <target> + +<zx_pivot> ::= + zx_pivot: +[ spacing: REAL # in [0, INF). Default 0 ] +[ ref_point: <real3>. Default 0,0,0 ] + <target> + +<target> ::= + target: + anchor: <anchor-identifier> + | direction: <real3> + | position: <real3> + | <sun> + +#---------------------------------------- +<shape> ::= + <cuboid> + | <cylinder> + | <obj> + | <parabol> + | <parabolic-cylinder> + | <hyperbol> + | <plane> + | <sphere> + | <stl> + +<cuboid> ::= + cuboid: + size: <real3*+> + +<cylinder> ::= + cylinder: + height: REAL # in ]0, INF) + radius: REAL # in ]0, INF) +[ slices: INTEGER ] # in [4, 4096]. Default 16 + +<obj> ::= + obj: + path: PATH + +# x^2 + y^2 - 4*focal*z = 0 +<parabol> ::= + parabol: + focal: REAL # in ]0, INF) + clip: <polyclip-list> + # By default slices is automatically compute with respect to the parabol + # curvature +[ slices: INTEGER ] # in [4, 4096) + +<parabolic-cylinder> ::= + 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 + # curvature +[ slices: INTEGER ] # in [4, 4096) + +# (x^2 + y^2) / a^2 - (z + z0 - g/2)^2 / b^2 + 1 = 0 +# with g = img_focal + real_focal; f = real_focal / g; +# a^2 = g^2(f - f^2); b = g(f - 1/2); z0 = |b| + g/2 +<hyperbol> ::= + hyperbol: + focals: <hyperboloid_focals> + clip: <polyclip-list> + # By default slices is automatically compute with respect to the hyperbol + # curvature +[ slices: INTEGER ] # in [4, 4096) + +<hyperboloid_focals> ::= + real: REAL # in ]0, INF) + image: REAL # in ]0, INF) + +<plane> ::= + plane: + clip: <polyclip-list> +[ slices: INTEGER ] # in [1, 4096). Default 1 + +<sphere> ::= + sphere: + radius: REAL # in ]0, INF) +[ slices: INTEGER ] # in [4, 4096]. Default 16 + +<stl> ::= + stl: + path: PATH + +#---------------------------------------- +<polyclip-list> ::= + - <polyclip> +[ - <polyclip> ... ] + +<polyclip> ::= + operation: <AND|SUB> + vertices: <vertices-list> + +<vertices-list> ::= + - <real2> + - <real2> + - <real2> +[ - <real2> ... ] + +#---------------------------------------- +<material> ::= + <material-descriptor> | <double-sided-material> + +<double-sided-material> ::= + front: <material-descriptor> + back: <material-descriptor> + +<material-descriptor> ::= + <dielectric> | <matte> | <mirror> | thin-dielectric> | <virtual> + +<dielectric> ::= + dielectric: + medium_i: <dielectric-medium> + medium_t: <dielectric-medium> + +<matte> ::= + matte: + reflectivity: REAL # in [0, 1] + +<mirror> ::= + mirror: + reflectivity: REAL # in [0, 1] + roughness: REAL # in [0, 1] + +<virtual> ::= + virtual: EMPTY-STRING + +<thin-dielectric> ::= + thin_dielectric: + thickness: REAL # in [0, INF) + medium_i: <dielectric-medium> + medium_t: <dielectric-medium> + +<dielectric-medium> ::= + refractive_index: REAL # in ]0, INF) + absorptivity: REAL # in [0, INF) + +#---------------------------------------- +<entity> ::= + entity: + <entity-data> + +<template> ::= + template: + <entity-data> + +<entity-data> ::= + name: STRING # except "self" +[ <geometry-data> | <x_pivot> | <zx_pivot> ] +[ <anchors> ] +[ <transform> ] +[ <children> ] + +<geometry-data> ::= + primary: INTEGER # in [0, 1] + <geometry> + +<children> ::= + children: + - <entity-data> +[ - <entity-data> ... ] + +<anchors> ::= + anchors: + - <anchor-data> +[ - <anchor-data> ... ] + +<anchor-data> ::= + name: STRING + <position-description> + +<position-description> ::= + position: <real3> | hyperboloid_image_focals: <hyperboloid_focals> + +# "self" references the first level entity +<entity-identifier> ::= + <self|STRING>[.STRING ... ] + +<anchor-identifier> ::= + <entity-identifier>.STRING + +#---------------------------------------- +<sun> ::= + sun: + dni: REAL # Direct Normal Irradiance in ]0, INF) + <spectrum> +[ <radial-angular-distribution> ] + +<radial-angular-distribution> ::= + <pillbox> | <buie> + +<buie> ::= + buie: + csr: REAL # in [1e-6, 0.849] + +<pillbox> ::= + pillbox: + aperture: REAL # in ]0, 90] + +#---------------------------------------- +<transform> ::= + transform: + translation: <real3> + rotation: <real3> + +<real2> ::= + - REAL + - REAL + +<real3> ::= + - REAL + - REAL + - REAL + +<real3*+> ::= + - REAL # in ]0, inf) + - REAL # in ]0, inf) + - REAL # in ]0, inf) + +<spectrum> ::= + spectrum: + - <spectrum-data> +[ - <spectrum-data> ... ] + +<spectrum-data> ::= + wavelength: REAL # in [0, INF) + data: REAL # in [0, INF) + diff --git a/doc/output b/doc/output @@ -1,15 +1,15 @@ <output> ::= - <receivers-count> + <count> [ <mc-receiver> ... ] <mc-shadow> <mc-missing> [ <receiver-hit> ... ] -<receivers-count> ::= - INTEGER +<count> ::= + INTEGER INTEGER # receivers-count experiments-count <mc-receiver> ::= - <receiver-name> <receiver-id> <estimation> + <receiver-name> <receiver-id> <integrated-irradiance> <reflectivity-loss> <absorptivity-loss> <cos-loss> <efficiency> <receiver-id> ::= INTEGER @@ -17,6 +17,24 @@ <receiver-name> ::= STRING +<intregrated-irradiance> ::= + <mc-double-sided> + +<reflectivity-loss> ::= + <mc-double-sided> + +<absorptivity-loss> ::= + <mc-double-sided> + +<coss-loss> ::= + <mc-double-sided> + +<efficiency> ::= + <mc-double-sided> + +<mc-double-sided> ::= + <estimation> <estimation> # front-estimation back-estimation + <mc-shadow> ::= <estimation> diff --git a/doc/receiver b/doc/receiver @@ -12,6 +12,7 @@ <receiver> ::= name: <entity-identifier> side: <BACK|FRONT|FRONT_AND_BACK> +[ per_primitive: INTEGER ] # in [0, 1] <entity-identifier> STRING[.STRING ... ] diff --git a/src/parser/solparser.c b/src/parser/solparser.c @@ -44,6 +44,16 @@ struct target_alias { #define DARRAY_DATA struct target_alias #include <rsys/dynamic_array.h> +/* Declare the array of mediums */ +#define DARRAY_NAME medium +#define DARRAY_DATA struct solparser_medium +#include <rsys/dynamic_array.h> + +/* Declare the array of dielectric materials */ +#define DARRAY_NAME dielectric +#define DARRAY_DATA struct solparser_material_dielectric +#include <rsys/dynamic_array.h> + /* Declare the array of matte materials */ #define DARRAY_NAME matte #define DARRAY_DATA struct solparser_material_matte @@ -54,6 +64,11 @@ struct target_alias { #define DARRAY_DATA struct solparser_material_mirror #include <rsys/dynamic_array.h> +/* Declare the array of thin_dielectric materials */ +#define DARRAY_NAME thin_dielectric +#define DARRAY_DATA struct solparser_material_thin_dielectric +#include <rsys/dynamic_array.h> + /* Declare the array of materials */ #define DARRAY_NAME material #define DARRAY_DATA struct solparser_material @@ -99,6 +114,16 @@ struct target_alias { solparser_shape_paraboloid_copy_and_release #include <rsys/dynamic_array.h> +/* Declare the array of hyperboloids */ +#define DARRAY_NAME hyperboloid +#define DARRAY_DATA struct solparser_shape_hyperboloid +#define DARRAY_FUNCTOR_INIT solparser_shape_hyperboloid_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_hyperboloid_release +#define DARRAY_FUNCTOR_COPY solparser_shape_hyperboloid_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ + solparser_shape_hyperboloid_copy_and_release +#include <rsys/dynamic_array.h> + /* Declare the array of planes */ #define DARRAY_NAME plane #define DARRAY_DATA struct solparser_shape_plane @@ -173,8 +198,11 @@ struct solparser { struct htable_yaml2sols yaml2mtls; /* Cache of materials */ struct darray_material mtls; struct darray_material2 mtls2; /* Double sided materials */ + struct darray_medium mediums; + struct darray_dielectric dielectrics; struct darray_matte mattes; struct darray_mirror mirrors; + struct darray_thin_dielectric thin_dielectrics; /* Use to deferred the setup of the anchor targeted by a pivot */ struct darray_tgtalias tgtaliases; @@ -186,6 +214,7 @@ struct solparser { struct darray_impgeom objs; struct darray_paraboloid parabols; struct darray_paraboloid parabolic_cylinders; + struct darray_hyperboloid hyperbols; struct darray_plane planes; struct darray_sphere spheres; struct darray_impgeom stls; @@ -200,7 +229,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; @@ -370,8 +398,11 @@ parser_clear(struct solparser* parser) htable_yaml2sols_clear(&parser->yaml2mtls); darray_material_clear(&parser->mtls); darray_material2_clear(&parser->mtls2); + darray_medium_clear(&parser->mediums); + darray_dielectric_clear(&parser->dielectrics); darray_matte_clear(&parser->mattes); darray_mirror_clear(&parser->mirrors); + darray_thin_dielectric_clear(&parser->thin_dielectrics); /* Deferred targeted anchors */ darray_tgtalias_clear(&parser->tgtaliases); @@ -383,6 +414,7 @@ parser_clear(struct solparser* parser) darray_impgeom_clear(&parser->objs); darray_paraboloid_clear(&parser->parabols); darray_paraboloid_clear(&parser->parabolic_cylinders); + darray_hyperboloid_clear(&parser->hyperbols); darray_plane_clear(&parser->planes); darray_sphere_clear(&parser->spheres); darray_impgeom_clear(&parser->stls); @@ -397,7 +429,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); @@ -421,8 +452,11 @@ parser_release(ref_T* ref) htable_yaml2sols_release(&parser->yaml2mtls); darray_material_release(&parser->mtls); darray_material2_release(&parser->mtls2); + darray_medium_release(&parser->mediums); + darray_dielectric_release(&parser->dielectrics); darray_matte_release(&parser->mattes); darray_mirror_release(&parser->mirrors); + darray_thin_dielectric_release(&parser->thin_dielectrics); /* Deferred targeted anchors */ darray_tgtalias_release(&parser->tgtaliases); @@ -434,6 +468,7 @@ parser_release(ref_T* ref) darray_impgeom_release(&parser->objs); darray_paraboloid_release(&parser->parabols); darray_paraboloid_release(&parser->parabolic_cylinders); + darray_hyperboloid_release(&parser->hyperbols); darray_plane_release(&parser->planes); darray_sphere_release(&parser->spheres); darray_impgeom_release(&parser->stls); @@ -447,7 +482,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); @@ -841,6 +875,192 @@ error: * Material ******************************************************************************/ static res_T +parse_medium + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* medium, + struct solparser_medium_id* out_imedium) +{ + enum { ABSORPTIVITY, REFRACTIVE_INDEX }; + struct solparser_medium* mdm = NULL; + size_t imedium = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && medium && out_imedium); + + if(medium->type != YAML_MAPPING_NODE) { + log_err(parser, medium, "expect a mapping of medium attributes.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the medium */ + imedium = darray_medium_size_get(&parser->mediums); + res = darray_medium_resize(&parser->mediums, imedium + 1); + if(res != RES_OK) { + log_err(parser, medium, "could not allocate the medium.\n"); + res = RES_BAD_ARG; + goto error; + } + mdm = darray_medium_data_get(&parser->mediums) + imedium; + + n = medium->data.mapping.pairs.top - medium->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a medium parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key,"the "Name" of the medium is already defined.\n");\ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "absorptivity")) { + SETUP_MASK(ABSORPTIVITY, "absorptivity"); + res = parse_real(parser, val, 0, DBL_MAX, &mdm->absorptivity); + } else if(!strcmp((char*)key->data.scalar.value, "refractive_index")) { + SETUP_MASK(REFRACTIVE_INDEX, "refractive_index"); + res = parse_real + (parser, val, nextafter(0, 1), DBL_MAX, &mdm->refractive_index); + } else { + log_err(parser, key, "unknown medium 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, medium, "the "Name" of the medium is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(ABSORPTIVITY, "absorptivity"); + CHECK_PARAM(REFRACTIVE_INDEX, "refractive_index"); + #undef CHECK_PARAM + +exit: + out_imedium->i = imedium; + return res; +error: + if(imedium) { + darray_medium_pop_back(&parser->mediums); + imedium = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_material_dielectric + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* dielec, + struct solparser_material_dielectric_id* out_imtl) +{ + enum { MEDIUM_I, MEDIUM_T }; + struct solparser_material_dielectric* mtl = NULL; + size_t imtl = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && dielec && out_imtl); + + if(dielec->type != YAML_MAPPING_NODE) { + log_err(parser, dielec, + "expect a mapping of dielec material attributes.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the dielec material */ + imtl = darray_dielectric_size_get(&parser->dielectrics); + res = darray_dielectric_resize(&parser->dielectrics, imtl + 1); + if(res != RES_OK) { + log_err(parser, dielec, + "could not allocate the dielec material.\n"); + goto error; + } + mtl = darray_dielectric_data_get(&parser->dielectrics) + imtl; + + n = dielec->data.mapping.pairs.top - dielec->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a dielec material parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" of the dielectric material is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "medium_i")) { + SETUP_MASK(MEDIUM_I, "medium_i"); + res = parse_medium(parser, doc, val, &mtl->medium_i); + } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) { + SETUP_MASK(MEDIUM_T, "medium_t"); + res = parse_medium(parser, doc, val, &mtl->medium_t); + } else { + log_err(parser, key, "unknown dielectric 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, dielec, \ + "the "Name" of the dielectric material is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(MEDIUM_I, "medium_i"); + CHECK_PARAM(MEDIUM_T, "medium_t"); + #undef CHECK_PARAM + +exit: + out_imtl->i = imtl; + return res; +error: + if(imtl) { + darray_dielectric_pop_back(&parser->dielectrics); + imtl = SIZE_MAX; + } + goto exit; +} + +static res_T parse_material_matte (struct solparser* parser, yaml_document_t* doc, @@ -1014,6 +1234,105 @@ error: } static res_T +parse_material_thin_dielectric + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* thin, + struct solparser_material_thin_dielectric_id* out_imtl) +{ + enum { MEDIUM_I, MEDIUM_T, THICKNESS }; + struct solparser_material_thin_dielectric* mtl = NULL; + size_t imtl = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && thin && out_imtl); + + if(thin->type != YAML_MAPPING_NODE) { + log_err(parser, thin, + "expect a mapping of thin dielectric material attributes.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the thin dielectric material */ + imtl = darray_thin_dielectric_size_get(&parser->thin_dielectrics); + res = darray_thin_dielectric_resize(&parser->thin_dielectrics, imtl + 1); + if(res != RES_OK) { + log_err(parser, thin, + "could not allocate the thin dielectric material.\n"); + goto error; + } + mtl = darray_thin_dielectric_data_get(&parser->thin_dielectrics) + imtl; + + n = thin->data.mapping.pairs.top - thin->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a thin dielectric material parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" of the thin dielectric material is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "medium_i")) { + SETUP_MASK(MEDIUM_I, "medium_i"); + res = parse_medium(parser, doc, val, &mtl->medium_i); + } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) { + SETUP_MASK(MEDIUM_T, "medium_t"); + res = parse_medium(parser, doc, val, &mtl->medium_t); + } else if(!strcmp((char*)key->data.scalar.value, "thickness")) { + SETUP_MASK(THICKNESS, "thickness"); + res = parse_real(parser, val, 0, DBL_MAX, &mtl->thickness); + } else { + log_err(parser, key, "unknown thin dielectric 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, thin, \ + "the "Name" of the thin dielectric material is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(MEDIUM_I, "medium_i"); + CHECK_PARAM(MEDIUM_T, "medium_t"); + CHECK_PARAM(THICKNESS, "thickness"); + #undef CHECK_PARAM + +exit: + out_imtl->i = imtl; + return res; +error: + if(mtl) { + darray_thin_dielectric_pop_back(&parser->thin_dielectrics); + imtl = SIZE_MAX; + } + goto exit; +} + +static res_T parse_material_virtual(struct solparser* parser, yaml_node_t* virtual) { res_T res = RES_OK; @@ -1093,7 +1412,11 @@ parse_material_descriptor } \ mask |= BIT(Flag); \ } (void)0 - if(!strcmp((char*)key->data.scalar.value, "matte")) { + if(!strcmp((char*)key->data.scalar.value, "dielectric")) { + SETUP_MASK(DESCRIPTOR, "descriptor"); + mtl->type = SOLPARSER_MATERIAL_DIELECTRIC; + res = parse_material_dielectric(parser, doc, val, &mtl->data.dielectric); + } else if(!strcmp((char*)key->data.scalar.value, "matte")) { SETUP_MASK(DESCRIPTOR, "descriptor"); mtl->type = SOLPARSER_MATERIAL_MATTE; res = parse_material_matte(parser, doc, val, &mtl->data.matte); @@ -1101,8 +1424,13 @@ parse_material_descriptor SETUP_MASK(DESCRIPTOR, "descriptor"); mtl->type = SOLPARSER_MATERIAL_MIRROR; res = parse_material_mirror(parser, doc, val, &mtl->data.mirror); + } else if(!strcmp((char*)key->data.scalar.value, "thin_dielectric")) { + SETUP_MASK(DESCRIPTOR, "descriptor"); + mtl->type = SOLPARSER_MATERIAL_THIN_DIELECTRIC; + res = parse_material_thin_dielectric + (parser, doc, val, &mtl->data.thin_dielectric); } else if(!strcmp((char*)key->data.scalar.value, "virtual")) { - SETUP_MASK(DESCRIPTOR, "virtual"); + SETUP_MASK(DESCRIPTOR, "descriptor"); mtl->type = SOLPARSER_MATERIAL_VIRTUAL; res = parse_material_virtual(parser, val); } else { @@ -1607,7 +1935,7 @@ parse_cylinder *(Ptr) = Value; \ } (void)0 DEFAULT_PARAM(SLICES, &shape->nslices, 16); - #undef DEFAULT_PARAM + #undef DEFAULT_PARAM exit: out_ishape->i = ishape; @@ -1716,7 +2044,7 @@ parse_paraboloid const enum solparser_shape_type type, struct solparser_shape_paraboloid_id* out_ishape) { - enum { CLIP, FOCAL }; + enum { CLIP, FOCAL, SLICES }; struct solparser_shape_paraboloid* shape = NULL; struct darray_paraboloid* paraboloids; const char* name; @@ -1780,6 +2108,9 @@ parse_paraboloid } else if(!strcmp((char*)key->data.scalar.value, "focal")) { SETUP_MASK(FOCAL, "focal"); res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->focal); + } 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 %s parameter `%s'.\n", name, key->data.scalar.value); @@ -1815,13 +2146,177 @@ error: } static res_T +parse_focals_description + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* desc, + struct solparser_hyperboloid_focals* focals) +{ + enum { REAL, IMAGE }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && desc && focals); + + if(desc->type != YAML_MAPPING_NODE) { + log_err(parser, desc, "expect a mapping of focal parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = desc->data.mapping.pairs.top - desc->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect focal parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the focal parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*) key->data.scalar.value, "real")) { + SETUP_MASK(REAL, "real"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->real); + } else if(!strcmp((char*) key->data.scalar.value, "image")) { + SETUP_MASK(IMAGE, "image"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->image); + } + 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, desc, \ + "the focal parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(REAL, "real"); + CHECK_PARAM(IMAGE, "image"); + #undef CHECK_PARAM + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_hyperboloid + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* hyperboloid, + struct solparser_shape_hyperboloid_id* out_ishape) +{ + enum { CLIP, FOCAL, SLICES }; + struct solparser_shape_hyperboloid* 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 && hyperboloid && out_ishape); + + if(hyperboloid->type != YAML_MAPPING_NODE) { + log_err(parser, hyperboloid, "expect a mapping of hyperbol parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a hyperboloid shape */ + ishape = darray_hyperboloid_size_get(&parser->hyperbols); + res = darray_hyperboloid_resize(&parser->hyperbols, ishape + 1); + if(res != RES_OK) { + log_err(parser, hyperboloid, "could not allocate the hyperbol shape.\n"); + goto error; + } + shape = darray_hyperboloid_data_get(&parser->hyperbols) + ishape; + + n = hyperboloid->data.mapping.pairs.top - hyperboloid->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect hyperbol parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the hyperbol 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, "focals")) { + SETUP_MASK(FOCAL, "focals"); + res = parse_focals_description(parser, doc, val, &shape->focals); + } 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 hyperbol 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, hyperboloid, \ + "the hyperbol parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(CLIP, "clip"); + CHECK_PARAM(FOCAL, "focals"); + #undef CHECK_PARAM + +exit : + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_hyperboloid_pop_back(&parser->hyperbols); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T parse_plane (struct solparser* parser, yaml_document_t* doc, const yaml_node_t* plane, struct solparser_shape_plane_id* out_ishape) { - enum { CLIP }; + enum { CLIP, SLICES }; struct solparser_shape_plane* shape = NULL; size_t ishape = SIZE_MAX; intptr_t i, n; @@ -1856,14 +2351,22 @@ parse_plane res = RES_BAD_ARG; goto error; } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the plane 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")) { - if(mask & BIT(CLIP)) { - log_err(parser, key, "the plane clipping is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(CLIP); + SETUP_MASK(CLIP, "clip"); res = parse_clip(parser, doc, val, &shape->polyclips); + } else if(!strcmp((char*)key->data.scalar.value, "slices")) { + SETUP_MASK(SLICES, "slices"); + res = parse_integer(parser, val, 1, 4096, &shape->nslices); } else { log_err(parser, key, "unknown plane parameter `%s'.\n", key->data.scalar.value); @@ -1874,6 +2377,7 @@ parse_plane log_node(parser, key); goto error; } + #undef SETUP_MASK } if(!(mask & BIT(CLIP))) { log_err(parser, plane, "the plane parameter `clip' is missing.\n"); @@ -2087,6 +2591,10 @@ parse_object shape->type = SOLPARSER_SHAPE_PARABOLIC_CYLINDER; res = parse_paraboloid (parser, doc, val, shape->type, &shape->data.parabolic_cylinder); + } else if(!strcmp((char*) key->data.scalar.value, "hyperbol")) { + 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, "plane")) { SETUP_MASK(SHAPE, "shape"); shape->type = SOLPARSER_SHAPE_PLANE; @@ -2356,8 +2864,14 @@ parse_anchor SETUP_MASK(NAME, "name"); res = parse_identifier_string(parser, val, &solanchor->name); } else if(!strcmp((char*)key->data.scalar.value, "position")) { - SETUP_MASK(POSITION, "position"); + SETUP_MASK(POSITION, "position description"); res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solanchor->position); + } else if(!strcmp((char*) key->data.scalar.value, "hyperboloid_image_focals")) { + struct solparser_hyperboloid_focals focals; + SETUP_MASK(POSITION, "position description"); + res = parse_focals_description(parser, doc, val, &focals); + if(res != RES_OK) goto error; + d3(solanchor->position, 0, 0, focals.image); } else { log_err(parser, key, "unknown anchor parameter `%s'.\n", key->data.scalar.value); @@ -2378,7 +2892,7 @@ parse_anchor goto error; \ } (void)0 CHECK_PARAM(NAME, "name"); - CHECK_PARAM(POSITION, "position"); + CHECK_PARAM(POSITION, "position description"); #undef CHECK_PARAM res = anchor_register_name(parser, anchor, htable, isolanchor); @@ -2487,7 +3001,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 */ @@ -2496,14 +3009,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; @@ -2557,6 +3062,13 @@ parse_entity } else if(!strcmp((char*)key->data.scalar.value, "name")) { SETUP_MASK(NAME, "name"); res = parse_identifier_string(parser, val, &solent.name); + if(!strcmp(str_get(&solent.name), "self")) { + /* self is a reserved keyword */ + log_err(parser, key, "Reserved keywords cannot be used as names: %s.\n", + str_get(&solent.name)); + res = RES_BAD_ARG; + goto error; + } } else if(!strcmp((char*)key->data.scalar.value, "x_pivot")) { SETUP_MASK(DATA, "data"); solent.type = SOLPARSER_ENTITY_X_PIVOT; @@ -2618,12 +3130,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; @@ -2941,7 +3447,7 @@ parse_zx_pivot parser, doc, val, -DBL_MAX, DBL_MAX, solxzpivot->ref_point); } else if(!strcmp((char*) key->data.scalar.value, "target")) { struct solparser_pivot_id pivot_id; - pivot_id.i = + pivot_id.i = (size_t) (solxzpivot - darray_zx_pivot_cdata_get(&parser->zx_pivots)); SETUP_MASK(TARGET, "target"); res = parse_target(parser, doc, val, &solxzpivot->target, pivot_id); @@ -3326,8 +3832,11 @@ solparser_create htable_yaml2sols_init(mem_allocator, &parser->yaml2mtls); darray_material_init(mem_allocator, &parser->mtls); darray_material2_init(mem_allocator, &parser->mtls2); + darray_medium_init(mem_allocator, &parser->mediums); + darray_dielectric_init(mem_allocator, &parser->dielectrics); darray_matte_init(mem_allocator, &parser->mattes); darray_mirror_init(mem_allocator, &parser->mirrors); + darray_thin_dielectric_init(mem_allocator, &parser->thin_dielectrics); /* Deferred targeted anchors */ darray_tgtalias_init(mem_allocator, &parser->tgtaliases); @@ -3339,6 +3848,7 @@ solparser_create darray_impgeom_init(mem_allocator, &parser->objs); darray_paraboloid_init(mem_allocator, &parser->parabols); darray_paraboloid_init(mem_allocator, &parser->parabolic_cylinders); + darray_hyperboloid_init(mem_allocator, &parser->hyperbols); darray_plane_init(mem_allocator, &parser->planes); darray_sphere_init(mem_allocator, &parser->spheres); darray_impgeom_init(mem_allocator, &parser->stls); @@ -3352,7 +3862,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); @@ -3644,6 +4153,15 @@ solparser_get_geometry return darray_geometry_cdata_get(&parser->geometries) + geom.i; } +const struct solparser_medium* +solparser_get_medium + (const struct solparser* parser, + const struct solparser_medium_id medium) +{ + ASSERT(parser && medium.i < darray_medium_size_get(&parser->mediums)); + return darray_medium_cdata_get(&parser->mediums) + medium.i; +} + const struct solparser_material* solparser_get_material (const struct solparser* parser, @@ -3662,6 +4180,16 @@ solparser_get_material_double_sided return darray_material2_cdata_get(&parser->mtls2) + mtl2.i; } +const struct solparser_material_dielectric* +solparser_get_material_dielectric + (const struct solparser* parser, + const struct solparser_material_dielectric_id dielectric) +{ + ASSERT(parser); + ASSERT(dielectric.i < darray_dielectric_size_get(&parser->dielectrics)); + return darray_dielectric_cdata_get(&parser->dielectrics) + dielectric.i; +} + const struct solparser_material_matte* solparser_get_material_matte (const struct solparser* parser, @@ -3680,6 +4208,16 @@ solparser_get_material_mirror return darray_mirror_cdata_get(&parser->mirrors) + mirror.i; } +const struct solparser_material_thin_dielectric* +solparser_get_material_thin_dielectric + (const struct solparser* parser, + const struct solparser_material_thin_dielectric_id thin) +{ + ASSERT(parser); + ASSERT(thin.i < darray_thin_dielectric_size_get(&parser->thin_dielectrics)); + return darray_thin_dielectric_cdata_get(&parser->thin_dielectrics) + thin.i; +} + const struct solparser_object* solparser_get_object (const struct solparser* parser, @@ -3762,6 +4300,15 @@ solparser_get_shape_parabolic_cylinder return darray_paraboloid_cdata_get(&parser->parabolic_cylinders)+paraboloid.i; } +const struct solparser_shape_hyperboloid* +solparser_get_shape_hyperbol + (const struct solparser* parser, + const struct solparser_shape_hyperboloid_id hyperboloid) +{ + ASSERT(parser && hyperboloid.i < darray_hyperboloid_size_get(&parser->hyperbols)); + return darray_hyperboloid_cdata_get(&parser->hyperbols) + hyperboloid.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 @@ -92,6 +92,11 @@ solparser_get_geometry (const struct solparser* parser, const struct solparser_geometry_id geom); +extern LOCAL_SYM const struct solparser_medium* +solparser_get_medium + (const struct solparser* parser, + const struct solparser_medium_id medium); + extern LOCAL_SYM const struct solparser_material* solparser_get_material (const struct solparser* parser, @@ -102,6 +107,11 @@ solparser_get_material_double_sided (const struct solparser* parser, const struct solparser_material_double_sided_id mtl2); +extern LOCAL_SYM const struct solparser_material_dielectric* +solparser_get_material_dielectric + (const struct solparser* parser, + const struct solparser_material_dielectric_id dielectric); + extern LOCAL_SYM const struct solparser_material_matte* solparser_get_material_matte (const struct solparser* parser, @@ -112,6 +122,11 @@ solparser_get_material_mirror (const struct solparser* parser, const struct solparser_material_mirror_id mirror); +extern LOCAL_SYM const struct solparser_material_thin_dielectric* +solparser_get_material_thin_dielectric + (const struct solparser* parser, + const struct solparser_material_thin_dielectric_id thin_dielectric); + extern LOCAL_SYM const struct solparser_object* solparser_get_object (const struct solparser* parser, @@ -157,6 +172,11 @@ solparser_get_shape_parabolic_cylinder (const struct solparser* parser, const struct solparser_shape_paraboloid_id paraboloid); +extern LOCAL_SYM const struct solparser_shape_hyperboloid* +solparser_get_shape_hyperbol + (const struct solparser* parser, + const struct solparser_shape_hyperboloid_id hyperboloid); + extern LOCAL_SYM const struct solparser_shape_plane* solparser_get_shape_plane (const struct solparser* parser, diff --git a/src/parser/solparser_material.h b/src/parser/solparser_material.h @@ -19,11 +19,27 @@ #include <stddef.h> enum solparser_material_type { + SOLPARSER_MATERIAL_DIELECTRIC, SOLPARSER_MATERIAL_MATTE, SOLPARSER_MATERIAL_MIRROR, + SOLPARSER_MATERIAL_THIN_DIELECTRIC, SOLPARSER_MATERIAL_VIRTUAL }; +struct solparser_medium { + double refractive_index; + double absorptivity; +}; + +struct solparser_medium_id { size_t i; }; + +struct solparser_material_dielectric { + struct solparser_medium_id medium_i; /* Medium the material "looks at" */ + struct solparser_medium_id medium_t; /* Opposite medium */ +}; + +struct solparser_material_dielectric_id { size_t i; }; + struct solparser_material_matte { double reflectivity; /* In [0, 1] */ }; @@ -37,11 +53,21 @@ struct solparser_material_mirror { struct solparser_material_mirror_id { size_t i; }; +struct solparser_material_thin_dielectric { + struct solparser_medium_id medium_i; /* Outside medium */ + struct solparser_medium_id medium_t; /* Medium of the slab */ + double thickness; +}; + +struct solparser_material_thin_dielectric_id { size_t i; }; + struct solparser_material { enum solparser_material_type type; union { + struct solparser_material_dielectric_id dielectric; struct solparser_material_matte_id matte; struct solparser_material_mirror_id mirror; + struct solparser_material_thin_dielectric_id thin_dielectric; } data; }; 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/parser/solparser_shape.h b/src/parser/solparser_shape.h @@ -32,6 +32,7 @@ enum solparser_shape_type { SOLPARSER_SHAPE_OBJ, /* Imported Alias Wavefront obj */ SOLPARSER_SHAPE_PARABOL, SOLPARSER_SHAPE_PARABOLIC_CYLINDER, + SOLPARSER_SHAPE_HYPERBOL, SOLPARSER_SHAPE_PLANE, SOLPARSER_SHAPE_SPHERE, SOLPARSER_SHAPE_STL /* Imported STereo Lithography */ @@ -158,7 +159,8 @@ solparser_shape_imported_geometry_copy_and_release ******************************************************************************/ struct solparser_shape_paraboloid { double focal; - struct darray_polyclip polyclips; + long nslices; /* < 0 if not defined */ + struct darray_polyclip polyclips; }; static INLINE void @@ -167,6 +169,7 @@ solparser_shape_paraboloid_init struct solparser_shape_paraboloid* paraboloid) { ASSERT(paraboloid); + paraboloid->nslices = -1; darray_polyclip_init(allocator, &paraboloid->polyclips); } @@ -184,6 +187,7 @@ solparser_shape_paraboloid_copy { ASSERT(dst && src); dst->focal = src->focal; + dst->nslices = src->nslices; return darray_polyclip_copy(&dst->polyclips, &src->polyclips); } @@ -194,6 +198,64 @@ solparser_shape_paraboloid_copy_and_release { ASSERT(dst && src); dst->focal = src->focal; + dst->nslices = src->nslices; + return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); +} + +/******************************************************************************* +* Hyperboloid shape +******************************************************************************/ +struct solparser_hyperboloid_focals { + double real; + double image; +}; + +#define SOLPARSER_HYPERBOLOID_FOCALS_NULL__ { 0, 0 } +static const struct solparser_hyperboloid_focals +SOLPARSER_HYPERBOLOID_FOCALS_NULL = SOLPARSER_HYPERBOLOID_FOCALS_NULL__; + +struct solparser_shape_hyperboloid { + struct solparser_hyperboloid_focals focals; + struct darray_polyclip polyclips; + long nslices; /* < 0 if not defined */ +}; + +static INLINE void +solparser_shape_hyperboloid_init + (struct mem_allocator* allocator, + struct solparser_shape_hyperboloid* hyperboloid) +{ + ASSERT(hyperboloid); + hyperboloid->nslices = -1; + darray_polyclip_init(allocator, &hyperboloid->polyclips); +} + +static INLINE void +solparser_shape_hyperboloid_release(struct solparser_shape_hyperboloid* hyperboloid) +{ + ASSERT(hyperboloid); + darray_polyclip_release(&hyperboloid->polyclips); +} + +static INLINE res_T +solparser_shape_hyperboloid_copy + (struct solparser_shape_hyperboloid* dst, + const struct solparser_shape_hyperboloid* src) +{ + ASSERT(dst && src); + dst->focals = src->focals; + dst->nslices = src->nslices; + return darray_polyclip_copy(&dst->polyclips, &src->polyclips); +} + +static INLINE res_T +solparser_shape_hyperboloid_copy_and_release + (struct solparser_shape_hyperboloid* dst, + struct solparser_shape_hyperboloid* src) +{ + ASSERT(dst && src); + dst->focals = src->focals; + dst->nslices = src->nslices; return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); } @@ -202,6 +264,7 @@ solparser_shape_paraboloid_copy_and_release ******************************************************************************/ struct solparser_shape_plane { struct darray_polyclip polyclips; + long nslices; }; static INLINE void @@ -210,6 +273,7 @@ solparser_shape_plane_init struct solparser_shape_plane* plane) { ASSERT(plane); + plane->nslices = 1; darray_polyclip_init(allocator, &plane->polyclips); } @@ -226,6 +290,7 @@ solparser_shape_plane_copy const struct solparser_shape_plane* src) { ASSERT(dst && src); + dst->nslices = src->nslices; return darray_polyclip_copy(&dst->polyclips, &src->polyclips); } @@ -235,6 +300,7 @@ solparser_shape_plane_copy_and_release struct solparser_shape_plane* src) { ASSERT(dst && src); + dst->nslices = src->nslices; return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); } @@ -260,6 +326,7 @@ struct solparser_shape_cuboid_id { size_t i; }; 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_plane_id { size_t i; }; struct solparser_shape_sphere_id { size_t i; }; @@ -271,6 +338,7 @@ struct solparser_shape { struct solparser_shape_imported_geometry_id obj; struct solparser_shape_paraboloid_id parabol; struct solparser_shape_paraboloid_id parabolic_cylinder; + struct solparser_shape_hyperboloid_id hyperbol; 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_solparser2.c b/src/parser/test_solparser2.c @@ -114,7 +114,6 @@ main(int argc, char** argv) entity_id = solparser_entity_iterator_get(&it); entity = solparser_get_entity(parser, entity_id); - CHECK(strcmp("lvl 0", str_cget(&entity->name)), 0); CHECK(solparser_entity_get_children_count(entity), 2); diff --git a/src/parser/test_solparser3.c b/src/parser/test_solparser3.c @@ -25,6 +25,13 @@ static const char* input[] = { "- geometry: &cylinder2\n", " - cylinder: { radius: 1, height: 10 }\n", " material: *lambertian\n", + "- geometry: &hyperbol1\n", + " - hyperbol:\n", + " focals: &hyp1_focals { real: 4, image: 1 }\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", @@ -37,6 +44,8 @@ static const char* input[] = { " position: [1, 2, 3]\n", " - name: anchor1\n", " position: [4, 5, 6]\n", + " - name: anchor2\n", + " hyperboloid_image_focals: *hyp1_focals\n", " children:\n", " - name: entity0a\n", " primary: 1\n", @@ -49,6 +58,9 @@ static const char* input[] = { " position: [4, 5, 6]\n", " - name: entity0b\n", " position: [7, 8, 9]\n", + " - name: entity0c\n", + " primary: 0\n", + " geometry: *hyperbol1\n", "- entity:\n", " name: entity1\n", " x_pivot:\n", @@ -60,6 +72,11 @@ static const char* input[] = { " spacing: 1\n", " ref_point: [1, 2, 3]\n", " target: { anchor: \"entity0.entity0b.anchor0\" }\n", + "- entity:\n", + " name: entity3\n", + " x_pivot:\n", + " ref_point: [4, 2, 3]\n", + " target: { anchor: \"entity0.anchor2\" }\n", NULL }; @@ -120,8 +137,8 @@ check_entity0 matte = solparser_get_material_matte(parser, mtl->data.matte); CHECK(matte->reflectivity, 0.5); - CHECK(solparser_entity_get_children_count(entity0), 2); - CHECK(solparser_entity_get_anchors_count(entity0), 2); + CHECK(solparser_entity_get_children_count(entity0), 3); + CHECK(solparser_entity_get_anchors_count(entity0), 3); anchor_id = solparser_entity_get_anchor(entity0, 0); entity0_anchor0 = solparser_get_anchor(parser, anchor_id); @@ -186,13 +203,14 @@ check_entity1 CHECK(solparser_entity_get_children_count(entity1), 0); x_pivot = solparser_get_x_pivot(parser, entity1->data.x_pivot); + NCHECK(x_pivot, NULL); CHECK(d3_eq(x_pivot->ref_point, d3(tmp, 1, 2, 3)), 1); CHECK(x_pivot->target.type, SOLPARSER_TARGET_ANCHOR); } static void check_entity2 -(struct solparser* parser, const struct solparser_entity* entity2) + (struct solparser* parser, const struct solparser_entity* entity2) { double tmp[3]; @@ -205,11 +223,32 @@ check_entity2 CHECK(solparser_entity_get_children_count(entity2), 0); zx_pivot = solparser_get_zx_pivot(parser, entity2->data.zx_pivot); + NCHECK(zx_pivot, NULL); CHECK(zx_pivot->spacing, 1); CHECK(d3_eq(zx_pivot->ref_point, d3(tmp, 1, 2, 3)), 1); CHECK(zx_pivot->target.type, SOLPARSER_TARGET_ANCHOR); } +static void +check_entity3 + (struct solparser* parser, const struct solparser_entity* entity3) +{ + double tmp[3]; + + NCHECK(parser, NULL); + NCHECK(entity3, NULL); + + CHECK(strcmp(str_cget(&entity3->name), "entity3"), 0); + CHECK(entity3->type, SOLPARSER_ENTITY_X_PIVOT); + CHECK(solparser_entity_get_anchors_count(entity3), 0); + CHECK(solparser_entity_get_children_count(entity3), 0); + + x_pivot = solparser_get_x_pivot(parser, entity3->data.x_pivot); + NCHECK(x_pivot, NULL); + CHECK(d3_eq(x_pivot->ref_point, d3(tmp, 4, 2, 3)), 1); + CHECK(x_pivot->target.type, SOLPARSER_TARGET_ANCHOR); +} + int main(int argc, char** argv) { @@ -256,6 +295,9 @@ main(int argc, char** argv) } else if(!strcmp(str_cget(&entity->name), "entity2")) { check_entity2(parser, entity); + } + else if (!strcmp(str_cget(&entity->name), "entity3")) { + check_entity3(parser, entity); } else { FATAL("Unexpected entity name.\n"); } diff --git a/src/parser/test_solparser6.c b/src/parser/test_solparser6.c @@ -31,6 +31,12 @@ main(int argc, char** argv) const struct solparser_material* mtl; const struct solparser_object* obj; const struct solparser_shape* shape; + const struct solparser_shape_sphere* sphere; + const struct solparser_shape_paraboloid* parabol; + const struct solparser_shape_plane* plane; + const struct solparser_shape_hyperboloid* hyperbol; + const struct solparser_polyclip* polyclip; + double pos[2]; FILE* stream; (void)argc, (void)argv; @@ -45,8 +51,27 @@ main(int argc, char** argv) fprintf(stream, " name: test\n"); fprintf(stream, " primary: 0\n"); fprintf(stream, " geometry:\n"); - fprintf(stream, " - sphere: { radius: 1 }\n"); - fprintf(stream, " material: { ?virtual }\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material: { ?virtual }\n"); + fprintf(stream, " - parabol:\n"); + fprintf(stream, " focal: 10\n"); + fprintf(stream, " slices : 10\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"); + fprintf(stream, " - hyperbol:\n"); + fprintf(stream, " focals: { real: 10, image: 2 }\n"); + fprintf(stream, " slices : 20\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"); + fprintf(stream, " - plane:\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); @@ -63,16 +88,58 @@ 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), 1); + CHECK(solparser_geometry_get_objects_count(geom), 4); + obj_id = solparser_geometry_get_object(geom, 0); obj = solparser_get_object(parser, obj_id); shape = solparser_get_shape(parser, obj->shape); CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + sphere = solparser_get_shape_sphere(parser, shape->data.sphere); + CHECK(sphere->radius, 1); + CHECK(sphere->nslices, 16); + + obj_id = solparser_geometry_get_object(geom, 1); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_PARABOL); + parabol = solparser_get_shape_parabol(parser, shape->data.parabol); + CHECK(parabol->focal, 10); + CHECK(parabol->nslices, 10); + CHECK(darray_polyclip_size_get(&parabol->polyclips), 1); + polyclip = darray_polyclip_cdata_get(&parabol->polyclips); + CHECK(polyclip->op, SOLPARSER_CLIP_OP_AND); + CHECK(solparser_polyclip_get_vertices_count(polyclip), 3); + solparser_polyclip_get_vertex(polyclip, 0, pos); + CHECK(pos[0], 1); + CHECK(pos[1], 2); + solparser_polyclip_get_vertex(polyclip, 1, pos); + CHECK(pos[0], 3); + CHECK(pos[1], 4); + solparser_polyclip_get_vertex(polyclip, 2, pos); + CHECK(pos[0], 6); + CHECK(pos[1], 7); + + obj_id = solparser_geometry_get_object(geom, 2); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_HYPERBOL); + hyperbol = solparser_get_shape_hyperbol(parser, shape->data.hyperbol); + CHECK(hyperbol->focals.real, 10); + CHECK(hyperbol->focals.image, 2); + CHECK(hyperbol->nslices, 20); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); CHECK(mtl2->front.i, mtl2->back.i); mtl = solparser_get_material(parser, mtl2->front); CHECK(mtl->type, SOLPARSER_MATERIAL_VIRTUAL); + obj_id = solparser_geometry_get_object(geom, 3); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_PLANE); + plane = solparser_get_shape_plane(parser, shape->data.plane); + CHECK(plane->nslices, 1); /* Default value */ + solparser_entity_iterator_next(&it); CHECK(solparser_entity_iterator_eq(&it, &end), 1); diff --git a/src/parser/test_solparser7.c b/src/parser/test_solparser7.c @@ -0,0 +1,105 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser.h" +#include "solparser_sun.h" +#include "test_solstice_utils.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_geometry* geom; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_thin_dielectric* thin; + const struct solparser_medium* medium; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1 }] }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: test\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry:\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material:\n"); + fprintf(stream, " thin_dielectric:\n"); + fprintf(stream, " thickness: 0.123\n"); + fprintf(stream, " medium_i: &outside\n"); + fprintf(stream, " refractive_index: 1\n"); + fprintf(stream, " absorptivity: 0\n"); + fprintf(stream, " medium_t: &inside\n"); + fprintf(stream, " refractive_index: 1.5\n"); + fprintf(stream, " absorptivity: 20\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("test", str_cget(&entity->name)), 0); + 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), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_THIN_DIELECTRIC); + thin = solparser_get_material_thin_dielectric + (parser, mtl->data.thin_dielectric); + CHECK(thin->thickness, 0.123); + + medium = solparser_get_medium(parser, thin->medium_i); + CHECK(medium->refractive_index, 1); + CHECK(medium->absorptivity, 0); + medium = solparser_get_medium(parser, thin->medium_t); + CHECK(medium->refractive_index, 1.5); + CHECK(medium->absorptivity, 20); + + CHECK(solparser_load(parser), RES_BAD_OP); + solparser_ref_put(parser); + + fclose(stream); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/parser/test_solparser8.c b/src/parser/test_solparser8.c @@ -0,0 +1,118 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser.h" +#include "solparser_sun.h" +#include "test_solstice_utils.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_geometry* geom; + const struct solparser_medium* medium; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_dielectric* dielec; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1 }] }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: test\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry:\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material:\n"); + fprintf(stream, " front:\n"); + fprintf(stream, " dielectric:\n"); + fprintf(stream, " medium_i: &outside\n"); + fprintf(stream, " refractive_index: 1\n"); + fprintf(stream, " absorptivity: 0\n"); + fprintf(stream, " medium_t: &inside\n"); + fprintf(stream, " refractive_index: 1.5\n"); + fprintf(stream, " absorptivity: 20\n"); + fprintf(stream, " back:\n"); + fprintf(stream, " dielectric:\n"); + fprintf(stream, " medium_i: *inside\n"); + fprintf(stream, " medium_t: *outside\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("test", str_cget(&entity->name)), 0); + 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), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + NCHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); + dielec = solparser_get_material_dielectric(parser, mtl->data.dielectric); + medium = solparser_get_medium(parser, dielec->medium_i); + CHECK(medium->refractive_index, 1); + CHECK(medium->absorptivity, 0); + medium = solparser_get_medium(parser, dielec->medium_t); + CHECK(medium->refractive_index, 1.5); + CHECK(medium->absorptivity, 20); + + mtl = solparser_get_material(parser, mtl2->back); + CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); + dielec = solparser_get_material_dielectric(parser, mtl->data.dielectric); + medium = solparser_get_medium(parser, dielec->medium_i); + CHECK(medium->refractive_index, 1.5); + CHECK(medium->absorptivity, 20); + medium = solparser_get_medium(parser, dielec->medium_t); + CHECK(medium->refractive_index, 1); + CHECK(medium->absorptivity, 0); + + CHECK(solparser_load(parser), RES_BAD_OP); + solparser_ref_put(parser); + + fclose(stream); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} + diff --git a/src/parser/yaml/test_ko_0.yaml b/src/parser/yaml/test_ko_0.yaml @@ -16,7 +16,7 @@ - sun: { spectrum: [{data: 1}] } --- # missing data -- sun: { spectrum: [{wavelength: 1}] } +- sun: { spectrum: [{wavelength: 1}] } --- # 2x wavelength - sun: { spectrum: [{wavelength: 1, wavelength: 1}] } @@ -143,7 +143,7 @@ - sun: { dni: 1, dni: 1 } --- # 2x spectrum -- sun: +- sun: spectrum: [{wavelength: 1, data: 1}] spectrum: [{wavelength: 1, data: 1}] --- @@ -223,6 +223,84 @@ --- # +# <thin-dielectric> ::= +# thin_dielectric: +# thickness: REAL # in [0, INF) +# medium_i: <dielectric-medium> +# medium_t: <dielectric-medium> +# + +# invalid absorptivity +- material: + thin_dielectric: + thickness: 0 + medium_i: &m { refractive_index: 1, absorptivity: -1 } + medium_t: *m +--- +# invalid thickness +- material: + thin_dielectric: + thickness: -0.01 + medium_i: &m { refractive_index: 1, absorptivity: 0 } + medium_t: *m +--- +# invalid refractive index +- material: + thin_dielectric: + thickness: 0 + medium_i: &m { refractive_index: 0, absorptivity: 0 } + medium_t: *m +--- +# missing thickness +- material: + thin_dielectric: + medium_i: &m { refractive_index: 1, absorptivity: 0 } + medium_t: *m +--- + +# +# <dielectric> ::= +# dielectric: +# medium_i: <dielectric-medium> +# medium_t: <dielectric-medium> +# + +# invalid refractive_index +- material: + dielectric: + medium_i: &m { refractive_index: 0, absorptivity: 0 } + medium_t: *m +--- +# invalid absorptivity +- material: + dielectric: + medium_i: &m { refractive_index: 1, absorptivity: -1 } + medium_t: *m +--- +# missing refractive_index +- material: + dielectric: + medium_i: &m { absorptivity: 0 } + medium_t: *m +--- +# missing absorptivity +- material: + dielectric: + medium_i: &m { refractive_index: 1 } + medium_t: *m +--- +# missing medium_i +- material: + dielectric: + medium_t: { refractive_index: 1, absorptivity: 0 } +--- +# missing medium_t +- material: + dielectric: + medium_i: { refractive_index: 1, absorptivity: 0 } +--- + +# # front: <material-descriptor> # @@ -254,7 +332,7 @@ # # missing material definition -- material: +- material: --- # unknown dummy parameter - material: { dummy: 123 } @@ -545,6 +623,33 @@ - operation: AND vertices: [ [1, 2], [3, 4], [6, 7] ] --- +# invalid slices +- geometry: + - parabol: + slices: 1 + focal: 1 + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- +# invalid slices +- geometry: + - parabol: + slices: 0 + focal: 1 + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- +# invalid slices +- geometry: + - parabol: + slices: 4097 + focal: 1 + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- # # <parabolic-cylinder> ::= @@ -599,6 +704,96 @@ --- # +# <hyperbol> ::= +# hyperbol: # (x^2 + y^2) / a^2 - (z + z0 - 1/2)^2 / b^2 + 1 = 0 +# # with g = img_focal + real_focal; f = real_focal / g; +# # a^2 = g^2(f - f^2); b = g(f - 1/2); z0 = |b| + g/2 +# focals: <hyperboloid_focals> +# clip: <polyclip-list> +# +# <hyperboloid_focals> ::= +# real: REAL # in ]0, INF) +# image: REAL # in ]0, INF) +# +# missing hyperbol definition +- geometry: [ { hyperbol: } ] +--- +# unknown dummy parameter +- geometry: [ { hyperbol: { dummy: 1 } } ] +--- +# missing focals definition +- geometry: [ { hyperbol: { focals: } } ] +--- +# missing real value +- geometry: [ { hyperbol: { focals: { real: } } } ] +--- +# missing image value +- geometry: [ { hyperbol: { focals: { image: } } } ] +--- +# missing clip value +- geometry: [ { hyperbol: { clip: } } ] +--- +# real should be a number +- geometry: [ { hyperbol: { focals: { real: "dummy" } } } ] +--- +# -1 invalid +- geometry: [ { hyperbol: { focals: { real: -1 } } } ] +--- +# 0 invalid +- geometry: [ { hyperbol: { focals: { real: 0 } } } ] +--- +# image should be a number +- geometry: [ { hyperbol: { focals: { image: "dummy" } } } ] +--- +# -1 invalid +- geometry: [ { hyperbol: { focals: { image: -1 } } } ] +--- +# 0 invalid +- geometry: [ { hyperbol: { focals: { image: 0 } } } ] +--- +# missing clip parameter +- geometry: [ { hyperbol: { focals: { real: 1, image: 1 } } } ] +--- +# missing real parameter +- geometry: + - hyperbol: + focals: { image: 1 } + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- +# missing image parameter +- geometry: + - hyperbol: + focals: { real: 10 } + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- +# 2x focals +- geometry: + - hyperbol: + focals: { real: 1, image: 1 } + focals: { real: 1, image: 1 } +--- +# 2x real +- geometry: [ { hyperbol: { focals: { real: 1, real: 1 } } } ] +--- +# 2x image +- geometry: [ { hyperbol: { focals: { image: 1, image: 1 } } } ] +--- +# 2x clip +- geometry: + - hyperbol: + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] + clip: + - operation: AND + vertices: [ [1, 2], [3, 4], [6, 7] ] +--- + +# # <plane> ::= # plane: # clip: <polyclip-list> @@ -620,7 +815,31 @@ - operation: AND vertices: [ [1, 2], [3, 4], [6, 7] ] --- +# invalid slices +- geometry: &target + - plane: + slices: 0 + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] +--- +# invalid slices +- geometry: &target + - plane: + slices: 4097 + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] +--- # # <sphere> ::= # sphere: @@ -682,8 +901,8 @@ --- # -# <pivot> ::= -# pivot: +# <x_pivot> ::= +# x_pivot: # point: <real3> # normal: <real3> # <target> @@ -696,339 +915,339 @@ # | <sun> # -# missing pivot definition +# missing x_pivot definition - entity: - pivot: + x_pivot: --- # unknown dummy parameter - entity: - pivot: + x_pivot: dummy: 1 --- # missing point definition - entity: - pivot: + x_pivot: point: --- # missing normal definition - entity: - pivot: + x_pivot: normal: --- # missing target definition - entity: - pivot: + x_pivot: target: --- # point should be a number - entity: - pivot: + x_pivot: point: "dummy" --- # point should have 3 values - entity: - pivot: + x_pivot: point: [ -4, 5.2 ] --- # point should have 3 values - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0, 1 ] --- # normal should be a number - entity: - pivot: + x_pivot: normal: "dummy" --- # normal should have 3 values - entity: - pivot: + x_pivot: normal: [ -4, 5.2 ] --- # normal should have 3 values - entity: - pivot: + x_pivot: normal: [ -4, 5.2, 0, 1 ] --- # target should be a <target> - entity: - pivot: + x_pivot: target: "dummy" --- # missing anchor definition - entity: - pivot: + x_pivot: target: anchor: --- # missing direction definition - entity: - pivot: + x_pivot: target: direction: --- # missing position definition - entity: - pivot: + x_pivot: target: position: --- # undefined anchor - entity: - pivot: + x_pivot: target: anchor: dummy --- # direction should be a number - entity: - pivot: + x_pivot: target: direction: "dummy" --- # direction should have 3 values - entity: - pivot: + x_pivot: target: direction: [ -4, 5.2 ] --- # direction should have 3 values - entity: - pivot: + x_pivot: target: direction: [ -4, 5.2, 0, 1 ] --- # position should be a number - entity: - pivot: + x_pivot: target: position: "dummy" --- # position should have 3 values - entity: - pivot: + x_pivot: target: position: [ -4, 5.2 ] --- # position should have 3 values - entity: - pivot: + x_pivot: target: position: [ -4, 5.2, 0, 1 ] --- # sun should be a <sun> - entity: - pivot: + x_pivot: target: { sun: "dummy" } --- # missing point - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot: + x_pivot: normal: [ -4, 5.2, 0 ] target: { sun: *sun } --- # missing normal - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0 ] target: { sun: *sun } --- # missing target - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] --- # 2x point - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0 ] point: [ -4, 5.2, 0 ] --- # 2x normal - entity: - pivot: + x_pivot: normal: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] --- # 2x target - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot: + x_pivot: target: { sun: *sun } target: { sun: *sun } --- -# <pivot2> ::= -# pivot2: +# <zx_pivot> ::= +# zx_pivot: # spacing: REAL # in [0, INF) # ref_point: <real3> # <target> -# +# # <target> ::= # target: # anchor: <anchor-identifier> # | direction: <real3> # | position: <real3> # | <sun> -# +# -# missing pivot2 definition +# missing zx_pivot definition - entity: - pivot2: + zx_pivot: --- # unknown dummy parameter - entity: - pivot2: + zx_pivot: dummy: 1 --- # missing spacing definition - entity: - pivot2: + zx_pivot: spacing: --- # missing ref_point definition - entity: - pivot2: + zx_pivot: ref_point: --- # missing target definition - entity: - pivot2: + zx_pivot: target: --- # spacing should be a number - entity: - pivot2: + zx_pivot: spacing: "dummy" --- # -1 invalid - entity: - pivot2: + zx_pivot: spacing: -1 --- # spacing should be a number - entity: - pivot2: + zx_pivot: ref_point: "dummy" --- # ref_point should have 3 values - entity: - pivot2: + zx_pivot: ref_point: [ -4, 5.2 ] --- # ref_point should have 3 values - entity: - pivot2: + zx_pivot: ref_point: [ -4, 5.2, 0, 1 ] --- # target should be a <target> - entity: - pivot2: + zx_pivot: target: "dummy" --- # missing anchor definition - entity: - pivot2: + zx_pivot: target: anchor: --- # missing direction definition - entity: - pivot2: + zx_pivot: target: direction: --- # missing position definition - entity: - pivot2: + zx_pivot: target: position: --- # undefined anchor - entity: - pivot2: + zx_pivot: target: anchor: dummy --- # direction should be a number - entity: - pivot2: + zx_pivot: target: direction: "dummy" --- # direction should have 3 values - entity: - pivot2: + zx_pivot: target: direction: [ -4, 5.2 ] --- # direction should have 3 values - entity: - pivot2: + zx_pivot: target: direction: [ -4, 5.2, 0, 1 ] --- # position should be a number - entity: - pivot2: + zx_pivot: target: position: "dummy" --- # position should have 3 values - entity: - pivot2: + zx_pivot: target: position: [ -4, 5.2 ] --- # position should have 3 values - entity: - pivot2: + zx_pivot: target: position: [ -4, 5.2, 0, 1 ] --- # sun should be a <sun> - entity: - pivot2: + zx_pivot: target: { sun: "dummy" } --- # missing point - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot2: + zx_pivot: normal: [ -4, 5.2, 0 ] target: { sun: *sun } --- # missing normal - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot2: + zx_pivot: point: [ -4, 5.2, 0 ] target: { sun: *sun } --- # missing target - entity: - pivot2: + zx_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] --- # 2x spacing - entity: - pivot2: + zx_pivot: spacing: 1 spacing: 1 --- # 2x ref_point - entity: - pivot2: + zx_pivot: ref_point: [ 0, 5.2, 0 ] ref_point: [ 0, 5.2, 0 ] --- # 2x target - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot2: + zx_pivot: target: { sun: *sun } target: { sun: *sun } --- @@ -1041,30 +1260,71 @@ # # <anchor-data> ::= # name: STRING -# position: <real3> +# <position-description> +# +# <position-description> ::= +# position: <real3> | hyperboloid_image_focals: <hyperboloid_focals> # # missing anchors definition - entity: anchors: --- -# missing position +# missing name definition - entity: - anchors: - - name: "anchor" + anchors: [ name: ] +--- +# missing position definition +- entity: + anchors: [ position: ] +--- +# missing hyperboloid_image_focals definition +- entity: + anchors: [ { hyperboloid_image_focals: } ] +--- +# missing position-description +- entity: + anchors: [ { name: "anchor" } ] +--- +# position should have 3 values +- entity: + anchors: [ { name: "anchor", position: [ -4, 5.2 ] } ] +--- +# position should have 3 values +- entity: + anchors: [ { name: "anchor", position: [ -4, 5.2, 0, 5 ] } ] --- # missing name - entity: + anchors: [ { position: [ -4, 5.2, 0 ] } ] +--- +# 2x name +- entity: + anchors: [ { name: "anchor", name: "anchor" } ] +--- +# 2x position-description +- entity: + anchors: [ { position: [ -4, 5.2, 0 ], position: [ -4, 5.2, 0 ] } ] +--- +# 2x position-description +- entity: anchors: - - position: [ -4, 5.2, 0 ] + - hyperboloid_image_focals: { real: 1, image: 1 } + hyperboloid_image_focals: { real: 1, image: 1 } +--- +# 2x position-description +- entity: + anchors: + - hyperboloid_image_focals: { real: 1, image: 1 } + position: [ -4, 5.2, 0 ] --- # 2 anchors with same name - entity: anchors: - - name: "anchor" - position: [ -4, 5.2, 0 ] - - name: "anchor" - position: [ -4, 5.2, 0 ] + - name: "anchor" + position: [ -4, 5.2, 0 ] + - name: "anchor" + position: [ -4, 5.2, 0 ] --- # @@ -1074,14 +1334,14 @@ # # <entity-data> ::= # name: STRING -# [ <geometry-data> | <pivot> | <pivot2> ] +# [ <geometry-data> | <x_pivot> | <zx_pivot> ] # [ <anchors> ] # [ <transform> ] # [ <children> ] # # <geometry-data> ::= # primary: INTEGER # in [0, 1] -# <geometry> +# <geometry> # # missing entity definition @@ -1093,17 +1353,20 @@ # missing name value - entity: { name: } --- +# reserved word used as name +- entity: { name: "self" } +--- # missing primary value - entity: { primary: } --- # missing geometry value - entity: { geometry: } --- -# missing pivot value -- entity: { pivot: } +# missing x_pivot value +- entity: { x_pivot: } --- -# missing pivot2 value -- entity: { pivot2: } +# missing zx_pivot value +- entity: { zx_pivot: } --- # missing anchors value - entity: { anchors: } @@ -1148,32 +1411,32 @@ # 2x primary - entity: { primary: 1, primary: 1 } --- -# cannot define both geometry and pivot +# cannot define both geometry and x_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] target: { sun: *sun } geometry: [ { stl: { path: "file" } } ] --- -# cannot define both geometry and pivot2 +# cannot define both geometry and zx_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot2: + zx_pivot: spacing: 1 ref_point: [ 0, 5.2, 0 ] target: { sun: *sun } geometry: [ { stl: { path: "file" } } ] --- -# cannot define both pivot and pivot2 +# cannot define both x_pivot and zx_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - entity: - pivot: + x_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] target: { sun: *sun } - pivot2: + zx_pivot: spacing: 1 ref_point: [ 0, 5.2, 0 ] target: { sun: *sun } @@ -1194,9 +1457,9 @@ --- # 2x children - entity: - children: + children: - name: "child1" - children: + children: - name: "child2" --- # 2 entities with the same name @@ -1220,14 +1483,14 @@ # # <entity-data> ::= # name: STRING -# [ <geometry-data> | <pivot> | <pivot2> ] +# [ <geometry-data> | <x_pivot> | <zx_pivot> ] # [ <anchors> ] # [ <transform> ] # [ <children> ] # # <geometry-data> ::= # primary: INTEGER # in [0, 1] -# <geometry> +# <geometry> # # missing template definition @@ -1250,12 +1513,12 @@ - template: &temp { geometry: } - entity: *temp --- -# missing pivot value -- template: &temp { pivot: } +# missing x_pivot value +- template: &temp { x_pivot: } - entity: *temp --- -# missing pivot2 value -- template: &temp { pivot2: } +# missing zx_pivot value +- template: &temp { zx_pivot: } - entity: *temp --- # missing anchors value @@ -1310,34 +1573,34 @@ - template: &temp { primary: 1, primary: 1 } - entity: *temp --- -# cannot define both geometry and pivot +# cannot define both geometry and x_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - template: &temp - pivot: + x_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] target: { sun: *sun } geometry: [ { stl: { path: "file" } } ] - entity: *temp --- -# cannot define both geometry and pivot2 +# cannot define both geometry and zx_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - template: &temp - pivot2: + zx_pivot: spacing: 1 ref_point: [ 0, 5.2, 0 ] target: { sun: *sun } geometry: [ { stl: { path: "file" } } ] - entity: *temp --- -# cannot define both pivot and pivot2 +# cannot define both x_pivot and zx_pivot - sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } - template: &temp - pivot: + x_pivot: point: [ -4, 5.2, 0 ] normal: [ -4, 5.2, 0 ] target: { sun: *sun } - pivot2: + zx_pivot: spacing: 1 ref_point: [ 0, 5.2, 0 ] target: { sun: *sun } @@ -1361,9 +1624,9 @@ --- # 2x children - template: &temp - children: + children: - name: "child1" - children: + children: - name: "child2" - entity: *temp --- @@ -1438,7 +1701,7 @@ - geometry: --- # unknown dummy parameter -- geometry: +- geometry: - dummy: 1 --- # missing material definition @@ -1491,4 +1754,4 @@ geometry: - cuboid: { size: [1, 2, 3] } material: { matte: { reflectivity: 1 } } - -\ No newline at end of file + diff --git a/src/parser/yaml/test_ok_5.yaml b/src/parser/yaml/test_ok_5.yaml @@ -0,0 +1,43 @@ +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } + +- material: &thin_dielectric + thin_dielectric: + thickness: 1 + medium_i: { absorptivity: 0, refractive_index: 1.00027 } + medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + +- entity: + name: "entity" + primary: 0 + geometry: + - material: *thin_dielectric + cylinder: { height: 1, radius: 1 } +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } + +- material: &thin_dielectric + thin_dielectric: + thickness: 0 + medium_i: { absorptivity: 0, refractive_index: 0.00027 } + medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + +- entity: + name: "entity" + primary: 0 + geometry: + - material: *thin_dielectric + cylinder: { height: 1, radius: 1 } + +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: "entity" + primary: 0 + geometry: + - cylinder: { height: 1, radius: 1 } + material: + thin_dielectric: + thickness: 10 + medium_i: { absorptivity: 0, refractive_index: 1 } + medium_t: { absorptivity: 20, refractive_index: 1.5 } + diff --git a/src/parser/yaml/test_ok_6.yaml b/src/parser/yaml/test_ok_6.yaml @@ -0,0 +1,108 @@ +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + plane: + slices: 4 + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + parabol: + slices: 40 + focal: 18 + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + parabol: + focal: 18 + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + parabolic-cylinder: + slices: 40 + focal: 18 + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + parabolic-cylinder: + focal: 18 + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] + +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + hyperbol: + slices: 40 + focals: { real: 1, image: 1 } + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + hyperbol: + focals: { real: 1, image: 1 } + clip: + - operation: AND + vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] + + diff --git a/src/parser/yaml/test_ok_7.yaml b/src/parser/yaml/test_ok_7.yaml @@ -0,0 +1,40 @@ +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } + +- material: &dielectric + dielectric: + medium_i: { absorptivity: 0, refractive_index: 1.00027 } + medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + +- entity: + name: "entity" + primary: 0 + geometry: + - material: *dielectric + cylinder: { height: 1, radius: 1 } +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } + +- material: &dielectric + dielectric: + medium_i: { absorptivity: 0, refractive_index: 0.00027 } + medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + +- entity: + name: "entity" + primary: 0 + geometry: + - material: *dielectric + cylinder: { height: 1, radius: 1 } + +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: "entity" + primary: 0 + geometry: + - cylinder: { height: 1, radius: 1 } + material: + dielectric: + medium_i: { absorptivity: 0, refractive_index: 1 } + medium_t: { absorptivity: 20, refractive_index: 1.5 } + diff --git a/src/receivers/srcvl.c b/src/receivers/srcvl.c @@ -15,6 +15,7 @@ #include "srcvl.h" +#include <rsys/cstr.h> #include <rsys/dynamic_array.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> @@ -27,6 +28,7 @@ struct receiver { struct str name; enum srcvl_side side; + int per_primitive; }; static INLINE void @@ -35,6 +37,7 @@ receiver_init(struct mem_allocator* allocator, struct receiver* receiver) ASSERT(receiver); str_init(allocator, &receiver->name); receiver->side = SRCVL_FRONT_AND_BACK; + receiver->per_primitive = 0; } static INLINE void @@ -49,15 +52,16 @@ receiver_copy(struct receiver* dst, const struct receiver* src) { ASSERT(dst && src); dst->side = src->side; + dst->per_primitive = src->per_primitive; return str_copy(&dst->name, &src->name); } - static INLINE res_T receiver_copy_and_release(struct receiver* dst, struct receiver* src) { ASSERT(dst && src); dst->side = src->side; + dst->per_primitive = src->per_primitive; return str_copy_and_release(&dst->name, &src->name); } @@ -152,7 +156,7 @@ parse_side } else if(!strcmp((char*)side->data.scalar.value, "FRONT_AND_BACK")) { *out_side = SRCVL_FRONT_AND_BACK; } else { - log_err(srcvl, side, "unknown side valie `%s'.\n", + log_err(srcvl, side, "unknown side value `%s'.\n", side->data.scalar.value); res = RES_BAD_ARG; goto error; @@ -164,12 +168,39 @@ error: } static res_T +parse_integer(struct srcvl* srcvl, yaml_node_t* integer, int* dst) +{ + res_T res = RES_OK; + ASSERT(integer && dst); + + if(integer->type != YAML_SCALAR_NODE + || !strlen((char*)integer->data.scalar.value)) { + log_err(srcvl, integer, "expect an integer.\n"); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_int((char*)integer->data.scalar.value, dst); + if(res != RES_OK) { + log_err(srcvl, integer, "invalid integer `%s'.\n", + integer->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T parse_receiver (struct srcvl* srcvl, yaml_document_t* doc, const yaml_node_t* receiver) { - enum { NAME, SIDE }; + enum { NAME, PER_PRIMITIVE, SIDE }; struct receiver* solreceiver = NULL; size_t isolreceiver; intptr_t i, n; @@ -218,6 +249,9 @@ parse_receiver } else if(!strcmp((char*)key->data.scalar.value, "side")) { SETUP_MASK(SIDE, "side"); res = parse_side(srcvl, val, &solreceiver->side); + } else if(!strcmp((char*)key->data.scalar.value, "per_primitive")) { + SETUP_MASK(PER_PRIMITIVE, "per_primitive"); + res = parse_integer(srcvl, val, &solreceiver->per_primitive); } else { log_err(srcvl, key, "unknown receiver parameter `%s'.\n", key->data.scalar.value); @@ -427,5 +461,6 @@ srcvl_get r = darray_receiver_cdata_get(&srcvl->receivers) + i; receiver->name = str_cget(&r->name); receiver->side = r->side; + receiver->per_primitive = r->per_primitive; } diff --git a/src/receivers/srcvl.h b/src/receivers/srcvl.h @@ -27,6 +27,7 @@ enum srcvl_side { struct srcvl_receiver { const char* name; enum srcvl_side side; + int per_primitive; /* Define if per primitive receiver is enabled */ }; struct mem_allocator; diff --git a/src/receivers/test_srcvl2.c b/src/receivers/test_srcvl2.c @@ -39,31 +39,48 @@ main(int argc, char** argv) fprintf(stream, "- { name: entity3, side: BACK }\n"); fprintf(stream, "- name: entity4\n"); fprintf(stream, " side: FRONT_AND_BACK\n"); + fprintf(stream, "- { name: entity5, side: BACK, per_primitive: 1 }\n"); + fprintf(stream, "- { name: entity6, per_primitive: 0, side: FRONT }\n"); rewind(stream); CHECK(srcvl_setup_stream(srcvl, NULL, stream), RES_OK); CHECK(srcvl_load(srcvl), RES_OK); - CHECK(srcvl_count(srcvl), 5); + CHECK(srcvl_count(srcvl), 7); srcvl_get(srcvl, 0, &receiver); CHECK(strcmp(receiver.name, "entity0"), 0); CHECK(receiver.side, SRCVL_FRONT_AND_BACK); + CHECK(receiver.per_primitive, 0); srcvl_get(srcvl, 1, &receiver); CHECK(strcmp(receiver.name, "entity1"), 0); CHECK(receiver.side, SRCVL_FRONT_AND_BACK); + CHECK(receiver.per_primitive, 0); srcvl_get(srcvl, 2, &receiver); CHECK(strcmp(receiver.name, "entity2"), 0); CHECK(receiver.side, SRCVL_FRONT); + CHECK(receiver.per_primitive, 0); srcvl_get(srcvl, 3, &receiver); CHECK(strcmp(receiver.name, "entity3"), 0); CHECK(receiver.side, SRCVL_BACK); + CHECK(receiver.per_primitive, 0); srcvl_get(srcvl, 4, &receiver); CHECK(strcmp(receiver.name, "entity4"), 0); CHECK(receiver.side, SRCVL_FRONT_AND_BACK); + CHECK(receiver.per_primitive, 0); + + srcvl_get(srcvl, 5, &receiver); + CHECK(strcmp(receiver.name, "entity5"), 0); + CHECK(receiver.side, SRCVL_BACK); + CHECK(receiver.per_primitive, 1); + + srcvl_get(srcvl, 6, &receiver); + CHECK(strcmp(receiver.name, "entity6"), 0); + CHECK(receiver.side, SRCVL_FRONT); + CHECK(receiver.per_primitive, 0); CHECK(srcvl_load(srcvl), RES_BAD_OP); diff --git a/src/receivers/yaml/test_ko.yaml b/src/receivers/yaml/test_ko.yaml @@ -18,3 +18,11 @@ --- - name: test - +--- +- name: test + per_primitive: hop +--- +- name: test + per_primitive: +--- +- per_primitive: 1 diff --git a/src/receivers/yaml/test_ok.yaml b/src/receivers/yaml/test_ok.yaml @@ -13,4 +13,6 @@ {name: test}, {side: FRONT_AND_BACK, name: "Hello world"}, {name: Hello world, side: BACK} + {name: hop, per_primitive: 1} + {per_primitive: 0, name: test} ] diff --git a/src/solstice.c b/src/solstice.c @@ -20,6 +20,8 @@ #include "solstice_args.h" #include "parser/solparser.h" +#include <rsys/double2.h> + #include <sys/stat.h> #include <sys/types.h> @@ -33,18 +35,13 @@ #define open _open #define close _close #define fdopen _fdopen - #define O_CREAT _O_CREAT - #define O_WRONLY _O_WRONLY - #define O_EXCL _O_EXCL - #define O_TRUNC _O_TRUNC - #define S_IRUSR _S_IREAD - #define S_IWUSR _S_IWRITE + #define S_IRUSR S_IREAD + #define S_IWUSR S_IWRITE #else /* open/close functions */ #include <unistd.h> #endif - #include <solstice/ssol.h> /******************************************************************************* @@ -95,10 +92,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 +208,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" @@ -210,6 +304,7 @@ static res_T setup_sun_dirs(struct solstice* solstice, const struct solstice_args* args) { double* sun_dirs = NULL; + double* sun_angles = NULL; size_t i; res_T res = RES_OK; ASSERT(solstice && args); @@ -220,18 +315,26 @@ setup_sun_dirs(struct solstice* solstice, const struct solstice_args* args) "Could not reserve the list of %lu sun directions.\n", (unsigned long)args->nsun_dirs); goto error; - } - + res = darray_double_resize(&solstice->sun_angles, args->nsun_dirs*2/*#dims*/); + if (res != RES_OK) { + fprintf(stderr, + "Could not reserve the list of %lu sun angles.\n", + (unsigned long)args->nsun_dirs); + goto error; + } sun_dirs = darray_double_data_get(&solstice->sun_dirs); + sun_angles = darray_double_data_get(&solstice->sun_angles); FOR_EACH(i, 0, args->nsun_dirs) { spherical_to_cartesian_sun_dir(args->sun_dirs + i, sun_dirs + i*3/*#dims*/); + d2(sun_angles + i*2, args->sun_dirs[i].azimuth, args->sun_dirs[i].elevation); } exit: return res; error: darray_double_clear(&solstice->sun_dirs); + darray_double_clear(&solstice->sun_angles); goto exit; } @@ -314,6 +417,7 @@ setup_receivers(struct solstice* solstice, struct srcvl* srcvl) receiver.node = NULL; receiver.side = rcv.side; + receiver.per_primitive = rcv.per_primitive; res = htable_receiver_set(&solstice->receivers, &name, &receiver); if(res != RES_OK) { @@ -368,56 +472,44 @@ error: goto exit; } -static int -prompt_yes_no(void) -{ - int val[2]; - - do { - fprintf(stderr, "(y/n) "); - - val[0] = getc(stdin); - if(val[0] != '\n' && val[0] != '\r') { - val[1] = getc(stdin); - } - if(val[1] != '\n' && val[1] != '\r') { - while(getc(stdin) != '\n'); /* Flush stdin */ - } - } while((val[1] != '\n' && val[1] != '\r') || (val[0] != 'y' && val[0] != 'n')); - - return val[0] == 'y'; -} - -static FILE* -open_output_stream(const char* name, const int force_overwriting) +static res_T +open_output_stream(const char* name, const int force_overwriting, FILE** stream) { + res_T res = RES_OK; int fd = -1; FILE* fp = NULL; ASSERT(name); if(force_overwriting) { fp = fopen(name, "w"); - if(!fp) goto error; + if(!fp) { + fprintf(stderr, "Could not open the output file `%s'.\n", name); + goto error; + } } else { fd = open(name, O_CREAT|O_WRONLY|O_EXCL|O_TRUNC, S_IRUSR|S_IWUSR); if(fd >= 0) { fp = fdopen(fd, "w"); - if(fp == NULL) goto error; - } else if(errno == EEXIST) { - fprintf(stderr, "The output file `%s' already exist. Overwrite it? ", name); - if(!prompt_yes_no()) return NULL; - - fd = open(name, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IRUSR); - if(fd >= 0) { - fp = fdopen(fd, "w"); - if(!fp) goto error; + if(fp == NULL) { + fprintf(stderr, "Could not open the output file `%s'.\n", name); + goto error; } + } else if(errno == EEXIST) { + fprintf(stderr, + "The output file `%s' already exists. Use -f to overwrite it.\n", name); + goto error; + } else { + fprintf(stderr, + "Unexpected error while opening the output file `%s'.\n", name); + goto error; } } exit: - return fp; + *stream = fp; + return res; error: + res = RES_IO_ERR; if(fp) { CHECK(fclose(fp), 0); fp = NULL; @@ -447,6 +539,7 @@ solstice_init darray_nodes_init(allocator, &solstice->roots); darray_nodes_init(allocator, &solstice->pivots); darray_double_init(allocator, &solstice->sun_dirs); + darray_double_init(allocator, &solstice->sun_angles); solstice->allocator = allocator ? allocator : &mem_default_allocator; @@ -474,27 +567,15 @@ 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; if(!args->output_filename) { solstice->output = stdout; } else { - solstice->output = open_output_stream - (args->output_filename, args->force_overwriting); - if(!solstice->output) { - fprintf(stderr, "Could not open the output file `%s'.\n", - args->output_filename); - res = RES_IO_ERR; - goto error; - } + res = open_output_stream(args->output_filename, args->force_overwriting, + &solstice->output); + if(res != RES_OK) goto error; } res = load_data(solstice, args); @@ -517,8 +598,24 @@ solstice_init goto error; } - solstice->nrealisations = args->nrealisations; + solstice->nexperiments = args->nexperiments; solstice->output_hits = args->output_hits; + solstice->dump_format = args->dump_format; + solstice->dump_split_mode = args->dump_split_mode; + solstice->dump_paths = args->dump_paths; + + solstice->path_tracker = SSOL_PATH_TRACKER_DEFAULT; + solstice->path_tracker.infinite_ray_length = args->infinite_ray_length; + solstice->path_tracker.sun_ray_length = args->sun_ray_length; + + 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; + solstice->render_mode = args->render_mode; + solstice->spp = args->img.spp; + } exit: return res; @@ -550,50 +647,74 @@ solstice_release(struct solstice* solstice) darray_nodes_release(&solstice->roots); darray_nodes_release(&solstice->pivots); darray_double_release(&solstice->sun_dirs); + darray_double_release(&solstice->sun_angles); } res_T solstice_run(struct solstice* solstice) { const double* sun_dirs = NULL; + const double* sun_angles = NULL; size_t nsun_dirs = 0; size_t i; + int dump; + int draw; res_T res = RES_OK; ASSERT(solstice); sun_dirs = darray_double_cdata_get(&solstice->sun_dirs); + sun_angles = darray_double_cdata_get(&solstice->sun_angles); nsun_dirs = darray_double_size_get(&solstice->sun_dirs); ASSERT(nsun_dirs%3 == 0); nsun_dirs /= 3/*#dims*/; - if(!solstice->framebuffer) { /* Solstice integration */ - FOR_EACH(i, 0, nsun_dirs) { - const double* sun_dir = sun_dirs + i*3/*#dims*/; - res = ssol_sun_set_direction(solstice->sun, sun_dir); - if(res != RES_OK) { - fprintf(stderr, "Could not update the sun direction.\n"); - goto error; - } - res = solstice_update_entities(solstice, sun_dir); + dump = solstice->dump_format != SOLSTICE_ARGS_DUMP_NONE; + draw = solstice->framebuffer != NULL; + + if(!nsun_dirs) { + const double sun_dir[3] = {0, 0, -1}; + + res = ssol_sun_set_direction(solstice->sun, sun_dir); + if(res != RES_OK) { + fprintf(stderr, "Could not update the sun direction.\n"); + goto error; + } + + fprintf(solstice->output, "#--- No Sun direction\n"); + + if(dump) { + res = solstice_dump(solstice); if(res != RES_OK) goto error; - res = solstice_solve(solstice); + } else { + ASSERT(draw); + res = solstice_draw(solstice); if(res != RES_OK) goto error; } - } else if(!nsun_dirs) { - res = solstice_draw(solstice); - if(res != RES_OK) goto error; } else { FOR_EACH(i, 0, nsun_dirs) { const double* sun_dir = sun_dirs + i*3/*#dims*/; + fprintf(solstice->output, "#--- Sun direction: %g %g (%g %g %g)\n", + SPLIT2(sun_angles), SPLIT3(sun_dir)); res = solstice_update_entities(solstice, sun_dir); if(res != RES_OK) goto error; - res = solstice_draw(solstice); - if(res != RES_OK) goto error; + res = ssol_sun_set_direction(solstice->sun, sun_dir); + if(res != RES_OK) { + fprintf(stderr, "Could not update the sun direction.\n"); + goto error; + } - fprintf(solstice->output, - "# Sun direction: %g %g %g\n", SPLIT3(sun_dir)); + if(draw) { + res = solstice_draw(solstice); + if(res != RES_OK) goto error; + } else if(dump) { + res = solstice_dump(solstice); + if(res != RES_OK) goto error; + } else { + res = solstice_solve(solstice); + if(res != RES_OK) goto error; + } } } 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; @@ -35,6 +35,7 @@ struct sanim_node; struct solstice_receiver { struct solstice_node* node; enum srcvl_side side; + int per_primitive; }; #define DARRAY_NAME nodes @@ -86,12 +87,23 @@ struct solstice { /* Rendering */ struct ssol_camera* camera; struct ssol_image* framebuffer; + enum solstice_args_render_mode render_mode; + unsigned spp; /* #Samples per pixel */ + + /* Dump geometry */ + enum solstice_args_dump_format dump_format; + enum solstice_args_dump_split_mode dump_split_mode; + + /* Dump radiative paths mode */ + struct ssol_path_tracker path_tracker; struct darray_double sun_dirs; /* List of double3 */ + struct darray_double sun_angles; - size_t nrealisations; /* # realisations */ + size_t nexperiments; /* # MC experiments */ FILE* output; /* Output stream */ int output_hits; /* Output per receiver hits */ + int dump_paths; struct mem_allocator* allocator; }; diff --git a/src/solstice_args.c b/src/solstice_args.c @@ -51,12 +51,16 @@ print_help(const char* program) printf( " -h display this help and exit.\n"); printf( -" -n REALISATIONS number of realisations. Default is %lu.\n", - SOLSTICE_ARGS_DEFAULT.nrealisations); +" -n EXPERIMENTS number of Monte Carlo experiments. Default is %lu.\n", + SOLSTICE_ARGS_DEFAULT.nexperiments); + printf( +" -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"); printf( +" -p <dump-paths> switch in dump radiative paths mode and configure it.\n"); + printf( " -q do not print the helper message when no FILE is submitted.\n"); printf( " -R RECEIVERS define the file from which the list of receivers are read.\n"); @@ -93,6 +97,37 @@ parse_fov(const char* str, double* out_fov) return RES_OK; } +static res_T +parse_multiple_options + (const char* str, + struct solstice_args* args, + res_T (*parse_option)(const char* str, struct solstice_args* args)) +{ + char buf[512]; + char* tk; + char* ctx; + res_T res = RES_OK; + ASSERT(args && str); + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, "Could not duplicate the option string `%s'.\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + tk = strtok_r(buf, ":", &ctx); + do { + res = parse_option(tk, args); + if(res != RES_OK) goto error; + tk = strtok_r(NULL, ":", &ctx); + } while(tk); + +exit: + return res; +error: + goto exit; +} static res_T parse_sun_dir_list(const char* str, struct solstice_args* args) @@ -180,6 +215,7 @@ parse_image_definition tk = strtok_r(buf, "x", &ctx); res = cstr_to_ulong(tk, width); + if(res == RES_OK && !*width) res = RES_BAD_ARG; if(res != RES_OK) { fprintf(stderr, "Invalid image width `%s'\n", tk); return res; @@ -187,6 +223,7 @@ parse_image_definition tk = strtok_r(NULL, "", &ctx); res = cstr_to_ulong(tk, height); + if(res == RES_OK && !*height) res = RES_BAD_ARG; if(res != RES_OK) { fprintf(stderr, "Invalid image height `%s'\n", tk); return res; @@ -196,6 +233,27 @@ parse_image_definition } static res_T +parse_render_mode(const char* str, enum solstice_args_render_mode* mode) +{ + res_T res = RES_OK; + ASSERT(str && mode); + + if(!strcmp(str, "draft")) { + *mode = SOLSTICE_ARGS_RENDER_DRAFT; + } else if(!strcmp(str, "pt")) { + *mode = SOLSTICE_ARGS_RENDER_PATH_TRACING; + } else { + fprintf(stderr, "Invalid render mode `%s'.\n", str); + res = RES_BAD_ARG; + goto error; + } +exit: + return res; +error: + goto exit; +} + +static res_T parse_rendering_option(const char* str, struct solstice_args* args) { char buf[128]; @@ -217,27 +275,45 @@ parse_rendering_option(const char* str, struct solstice_args* args) key = strtok_r(buf, "=", &ctx); val = strtok_r(NULL, "", &ctx); - if(!strcmp(key, "fov")) { + if(!val) { + fprintf(stderr, "Missing a value to the rendering option `%s'.\n", key); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp(key, "fov")) { /* Camera horizontal field of view in degrees */ res = parse_fov(val, &args->camera.fov_x); if(res != RES_OK) goto error; - } else if(!strcmp(key, "img")) { + } else if(!strcmp(key, "img")) { /* Image definition */ res = parse_image_definition(val, &args->img.width, &args->img.height); if(res != RES_OK) goto error; - } else if(!strcmp(key, "pos")) { + } else if(!strcmp(key, "pos")) { /* Camera position */ res = cstr_to_list_double(val, ',', args->camera.pos, &len, 3); if(res == RES_OK && len != 3) res = RES_BAD_ARG; if(res != RES_OK ) { fprintf(stderr, "Invalid camera position `%s'.\n", val); goto error; } - } else if(!strcmp(key, "tgt")) { + args->camera.auto_look_at = 0; /* Disable auto look at */ + } else if(!strcmp(key, "rmode")) { /* Render mode */ + res = parse_render_mode(val, &args->render_mode); + if(res != RES_OK) goto error; + } else if(!strcmp(key, "spp")) { /*# Samples per pixel */ + res = cstr_to_uint(val, &args->img.spp); + if(res == RES_OK && !args->img.spp) res = RES_BAD_ARG; + if(res != RES_OK) { + fprintf(stderr, "Invalid number of samples per pixel `%s'.\n", val); + goto error; + } + } else if(!strcmp(key, "tgt")) { /* Camera target */ res = cstr_to_list_double(val, ',', args->camera.tgt, &len, 3); if(res == RES_OK && len != 3) res = RES_BAD_ARG; if(res != RES_OK) { fprintf(stderr, "Invalid camera target `%s'.\n", val); goto error; } - } else if(!strcmp(key, "up")) { + args->camera.auto_look_at = 0; /* Disable auto look at */ + } else if(!strcmp(key, "up")) { /* Camera up vector */ res = cstr_to_list_double(val, ',', args->camera.up, &len, 3); if(res == RES_OK && len != 3) res = RES_BAD_ARG; if(res != RES_OK) { @@ -249,7 +325,6 @@ parse_rendering_option(const char* str, struct solstice_args* args) res = RES_BAD_ARG; goto error; } - args->rendering = 1; exit: return res; @@ -258,34 +333,145 @@ error: } static res_T -parse_rendering_options(const char* str, struct solstice_args* args) +parse_dump_format(const char* str, enum solstice_args_dump_format* fmt) { - char buf[512]; - char* tk; + 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(args); - (void)str, (void)args; + 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; - /* Setup default values of the rendering parameters */ - args->camera = SOLSTICE_ARGS_DEFAULT.camera; - args->img = SOLSTICE_ARGS_DEFAULT.img; +exit: + return res; +error: + goto exit; +} + +static res_T +parse_dump_paths_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(!str) goto exit; + if(!strcmp(str, "default")) { + args->infinite_ray_length = SOLSTICE_ARGS_DEFAULT.infinite_ray_length; + args->sun_ray_length = SOLSTICE_ARGS_DEFAULT.sun_ray_length; + goto exit; + } if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { fprintf(stderr, - "Could not duplicate the rendering options string `%s'.\n", str); +"Could not duplicate the dump radiative paths option string `%s'.\n", str); res = RES_MEM_ERR; goto error; } + strncpy(buf, str, sizeof(buf)); - tk = strtok_r(buf, ":", &ctx); - do { - res = parse_rendering_option(tk, args); - tk = strtok_r(NULL, ":", &ctx); - } while(tk); + key = strtok_r(buf, "=", &ctx); + val = strtok_r(NULL, "", &ctx); + + if(!val) { + fprintf(stderr, + "Missing a value to the dump radiative paths option `%s'.\n", key); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp(key, "irlen")) { + res = cstr_to_double(val, &args->infinite_ray_length); + if(res != RES_OK) { + fprintf(stderr, "Invalid infinite ray length `%s'.\n", val); + goto error; + } + } else if(!strcmp(key, "srlen")) { + res = cstr_to_double(val, &args->sun_ray_length); + if(res != RES_OK) { + fprintf(stderr, "Invalid sun ray length `%s'.\n", val); + goto error; + } + } else { + fprintf(stderr, "Invalid dump radiative paths option `%s'.\n", val); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) goto error; exit: return res; @@ -306,28 +492,42 @@ 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:O:o:qR:r:t:")) != -1) { + while((opt = getopt(argc, argv, "D:fg:Hhn:o:p:qR:r:t:")) != -1) { switch(opt) { - case 'D': + case 'D': /* Sun directions */ res = parse_sun_dir_list(optarg, args); break; case 'f': args->force_overwriting = 1; break; case 'H': args->output_hits = 1; break; - case 'h': + case 'h': /* Print short help and exit */ print_help(argv[0]); solstice_args_release(args); args->quit = 1; goto exit; - case 'n': - res = cstr_to_ulong(optarg, &args->nrealisations); - if(res == RES_OK && !args->nrealisations) res = RES_BAD_ARG; + case 'n': /* Define the number of experiments */ + res = cstr_to_ulong(optarg, &args->nexperiments); + if(res == RES_OK && !args->nexperiments) res = RES_BAD_ARG; + break; + case 'g': /* Switch in dump geometry mode and configure it */ + res = parse_multiple_options(optarg, args, parse_dump_option); + if(res == RES_OK && args->dump_format == SOLSTICE_ARGS_DUMP_NONE) { + fprintf(stderr, "%s: missing a dump format -- `%s'.\n", + argv[0], optarg); + res = RES_BAD_ARG; + } break; - case 'O': args->dump_obj = 1; break; case 'o': args->output_filename = optarg; break; + case 'p': /* Switch in dump radiative paths mode and configure it */ + args->dump_paths = 1; + res = parse_multiple_options(optarg, args, parse_dump_paths_option); + break; case 'q': args->quiet = 1; break; case 'R': args->receivers_filename = optarg; break; - case 'r': res = parse_rendering_options(optarg, args); break; - case 't': + case 'r': /* Switch in rendering mode and configure it */ + args->rendering = 1; + res = parse_multiple_options(optarg, args, parse_rendering_option); + break; + case 't': /* Submit an hint on the number of threads to use */ res = cstr_to_uint(optarg, &args->nthreads); if(res == RES_OK && !args->nthreads) res = RES_BAD_ARG; break; @@ -342,15 +542,28 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) } } - if(!args->rendering && !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 cannot be defined simultaneously.\n"); + if(args->dump_format != SOLSTICE_ARGS_DUMP_NONE && args->rendering) { + fprintf(stderr, "The '-g' and '-r' options are exclusives.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(args->dump_format != SOLSTICE_ARGS_DUMP_NONE && args->dump_paths) { + fprintf(stderr, "The '-g' and '-p' options are exclusives.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(args->dump_paths && args->rendering) { + fprintf(stderr, "The '-p' and '-r' options are exclusives.\n"); res = RES_BAD_ARG; goto error; } diff --git a/src/solstice_args.h.in b/src/solstice_args.h.in @@ -24,11 +24,27 @@ 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 +}; + +enum solstice_args_render_mode { + SOLSTICE_ARGS_RENDER_DRAFT, + SOLSTICE_ARGS_RENDER_PATH_TRACING +}; + struct solstice_args { const char* output_filename; const char* input_filename; /* May be NULL <=> read data from stdin */ const char* receivers_filename; - unsigned long nrealisations; /* #realisations */ + unsigned long nexperiments; /* #experiments */ unsigned nthreads; /* #threads */ /* List of sun directions */ @@ -40,15 +56,27 @@ struct solstice_args { double tgt[3]; double up[3]; double fov_x; /* In radians */ + int auto_look_at; } camera; struct { unsigned long width; unsigned long height; + unsigned spp; /* Samples per pixel */ } img; + enum solstice_args_render_mode render_mode; + + /* Dump geometry mode */ + enum solstice_args_dump_format dump_format; + enum solstice_args_dump_split_mode dump_split_mode; + + /* Dump radiative paths options. */ + double sun_ray_length; /* Length of the sun rays. */ + double infinite_ray_length; /* Length of the rays going to infinity. */ + int force_overwriting; - int dump_obj; + int dump_paths; /* Dump radiative paths */ int rendering; int output_hits; /* Output the per receiver hits */ int quiet; @@ -72,16 +100,26 @@ 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 */ \ @SOLSTICE_ARGS_DEFAULT_IMG_WIDTH@, \ - @SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT@ \ + @SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT@, \ + @SOLSTICE_ARGS_DEFAULT_IMG_SPP@ \ }, \ \ + SOLSTICE_ARGS_RENDER_DRAFT, /* Render mode */ \ + \ + SOLSTICE_ARGS_DUMP_NONE, /* Dump format */ \ + SOLSTICE_ARGS_DUMP_SPLIT_NONE, /* Dump split mode */ \ + \ + -1, /* Sun ray length */ \ + -1, /* Infinite ray length */ \ + \ 0, /* Force overwriting */ \ - 0, /* Dump */ \ + 0, /* Dump radiative paths */ \ 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,6 +53,10 @@ solstice_solve (struct solstice* solstice); extern LOCAL_SYM res_T +solstice_dump + (struct solstice* solstice); + +extern LOCAL_SYM res_T solstice_create_sun (struct solstice* solstice); @@ -106,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); @@ -113,7 +129,8 @@ solstice_node_geometry_set_primary extern LOCAL_SYM res_T solstice_node_geometry_set_receiver (struct solstice_node* node, - const int mask); /* Combination of ssol_side_flag */ + const int mask, /* Combination of ssol_side_flag */ + const int per_primitive); /* Enable the per primitive integration */ extern LOCAL_SYM void solstice_node_target_get_tracking diff --git a/src/solstice_draw.c b/src/solstice_draw.c @@ -76,8 +76,17 @@ solstice_draw(struct solstice* solstice) goto error; } - res = ssol_draw(solstice->scene, solstice->camera, layout.width, - layout.height, ssol_image_write, solstice->framebuffer); + switch(solstice->render_mode) { + case SOLSTICE_ARGS_RENDER_DRAFT: + res = ssol_draw_draft(solstice->scene, solstice->camera, layout.width, + layout.height, solstice->spp, ssol_image_write, solstice->framebuffer); + break; + case SOLSTICE_ARGS_RENDER_PATH_TRACING: + res = ssol_draw_pt(solstice->scene, solstice->camera, layout.width, + layout.height, solstice->spp, ssol_image_write, solstice->framebuffer); + break; + default: FATAL("Unreachable code.\n"); + } if(res != RES_OK) { fprintf(stderr, "Rendering error\n"); goto error; diff --git a/src/solstice_dump.c b/src/solstice_dump.c @@ -0,0 +1,150 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solstice_c.h" +#include <solstice/ssol.h> + +struct dump_context { + FILE* output; + size_t ids_offset; + enum solstice_args_dump_split_mode split_mode; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +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]; + SSOL(instantiated_shaded_shape_get_vertex_attrib + (sshape, i, SSOL_POSITION, pos)); + fprintf(ctx->output, "v %g %g %g\n", SPLIT3(pos)); + } + + SSOL(shape_get_triangles_count(sshape->shape, &ntris)); + FOR_EACH(i, 0, ntris) { + unsigned ids[3]; + SSOL(shape_get_triangle_indices(sshape->shape, i, ids)); + /* Note that in the obj fileformat the first index is 1 rather than 0 */ + fprintf(ctx->output, "f %lu %lu %lu\n", + (unsigned long)(ids[0] + 1 + ctx->ids_offset), + (unsigned long)(ids[1] + 1 + ctx->ids_offset), + (unsigned long)(ids[2] + 1 + ctx->ids_offset)); + } + + 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 +dump_instance(struct ssol_instance* instance, void* context) +{ + struct dump_context* ctx = context; + size_t i, n; + ASSERT(instance && ctx); + + 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); + } + + 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(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 && 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]; + + fprintf(solstice->output, "# %s\n", solstice_node_get_name(node)); + + /* TODO use a anim tree visitor that neither resolve the pivot + * transformations nor compute the node transforms */ + 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: + return res; +error: + goto exit; +} + 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* 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) { @@ -97,6 +124,78 @@ error: goto exit; } +static res_T +get_anchor_node + (struct solstice* solstice, + const struct solparser_anchor_id anchor_id, + struct solstice_node** out_node) +{ + struct solstice_node* node = NULL; + struct solstice_node** pnode = NULL; + res_T res = RES_OK; + ASSERT(solstice && out_node); + + pnode = htable_anchor_find(&solstice->anchors, &anchor_id.i); + if(pnode) { + node = *pnode; + } 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; + } + +exit: + *out_node = node; + return res; +error: + if(node) solstice_node_ref_put(node); + 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 (struct solstice* solstice, @@ -104,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; @@ -117,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); @@ -163,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; @@ -176,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; - target = *htable_anchor_find - (&solstice->anchors, &parser_zx_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_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; @@ -223,16 +280,17 @@ create_node const struct str* name) { struct solstice_node* node = NULL; - struct solstice_node* tgt = NULL; 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) { @@ -255,6 +313,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); @@ -272,7 +336,7 @@ create_node const int mask = srcvl_side_to_ssol_mask(rcv->side); ASSERT(rcv->node == NULL); /* Receiver is not attached to a node */ - res = solstice_node_geometry_set_receiver(node, mask); + res = solstice_node_geometry_set_receiver(node, mask, rcv->per_primitive); if(res != RES_OK) { fprintf(stderr, "Could not define the entity `%s' as a receiver.\n", str_cget(&entity->name)); @@ -290,16 +354,17 @@ create_node /* Register entity anchors */ FOR_EACH(i, 0, solparser_entity_get_anchors_count(entity)) { + struct solstice_node* tgt = NULL; struct solparser_anchor_id id; - const struct solparser_anchor* anchor = NULL; - - res = solstice_node_target_create(solstice->allocator, &tgt); - if(res != RES_OK) goto error; + const struct solparser_anchor* anchor; id = solparser_entity_get_anchor(entity, i); anchor = solparser_get_anchor(solstice->parser, id); - res = htable_anchor_set(&solstice->anchors, &id.i, &tgt); + 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; solstice_node_set_translation(tgt, anchor->position); @@ -319,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; @@ -341,9 +399,9 @@ create_node exit: str_release(&child_name); + str_release(&anchor_name); return node; error: - if(tgt) solstice_node_ref_put(tgt); if(child) solstice_node_ref_put(child); if(node) solstice_node_ref_put(node); node = NULL; diff --git a/src/solstice_material.c b/src/solstice_material.c @@ -18,13 +18,13 @@ #include <solstice/ssol.h> -struct mirror_param { +struct matte_param { double reflectivity; - double roughness; }; -struct matte_param { +struct mirror_param { double reflectivity; + double roughness; }; /******************************************************************************* @@ -100,6 +100,45 @@ mirror_get_roughness } static res_T +create_material_dielectric + (struct solstice* solstice, + const struct solparser_material_dielectric* dielectric, + struct ssol_material** out_mtl) +{ + const struct solparser_medium* medium_i; + const struct solparser_medium* medium_t; + struct ssol_medium ssol_medium_i; + struct ssol_medium ssol_medium_t; + struct ssol_dielectric_shader shader = SSOL_DIELECTRIC_SHADER_NULL; + struct ssol_material* mtl = NULL; + res_T res = RES_OK; + ASSERT(solstice && dielectric && out_mtl); + + res = ssol_material_create_dielectric(solstice->ssol, &mtl); + if(res != RES_OK) { + fprintf(stderr, + "Could not allocate the Solstice Solver dielectric material.\n"); + goto error; + } + + medium_i = solparser_get_medium(solstice->parser, dielectric->medium_i); + medium_t = solparser_get_medium(solstice->parser, dielectric->medium_t); + shader.normal = mtl_get_normal; + ssol_medium_i.refractive_index = medium_i->refractive_index; + ssol_medium_i.absorptivity = medium_i->absorptivity; + ssol_medium_t.refractive_index = medium_t->refractive_index; + ssol_medium_t.absorptivity = medium_t->absorptivity; + SSOL(dielectric_setup(mtl, &shader, &ssol_medium_i, &ssol_medium_t)); + +exit: + *out_mtl = mtl; + return res; +error: + if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + goto exit; +} + +static res_T create_material_matte (struct solstice* solstice, const struct solparser_material_matte* matte, @@ -136,7 +175,7 @@ create_material_matte shader.normal = mtl_get_normal; shader.reflectivity = matte_get_reflectivity; - SSOL(matte_set_shader(mtl, &shader)); + SSOL(matte_setup(mtl, &shader)); SSOL(material_set_param_buffer(mtl, pbuf)); exit: @@ -187,7 +226,7 @@ create_material_mirror shader.normal = mtl_get_normal; shader.reflectivity = mirror_get_reflectivity; shader.roughness = mirror_get_roughness; - SSOL(mirror_set_shader(mtl, &shader)); + SSOL(mirror_setup(mtl, &shader)); SSOL(material_set_param_buffer(mtl, pbuf)); exit: @@ -199,6 +238,47 @@ error: goto exit; } +static res_T +create_material_thin_dielectric + (struct solstice* solstice, + const struct solparser_material_thin_dielectric* thin, + struct ssol_material** out_mtl) +{ + struct ssol_thin_dielectric_shader shader = SSOL_THIN_DIELECTRIC_SHADER_NULL; + const struct solparser_medium* medium_i; + const struct solparser_medium* medium_t; + struct ssol_medium ssol_medium_i; + struct ssol_medium ssol_medium_t; + struct ssol_material* mtl = NULL; + res_T res = RES_OK; + ASSERT(solstice && thin && out_mtl); + + res = ssol_material_create_thin_dielectric(solstice->ssol, &mtl); + if(res != RES_OK) { + fprintf(stderr, + "Could not allocate the Solstice Solver thin dielectric material.\n"); + goto error; + } + + shader.normal = mtl_get_normal; + medium_i = solparser_get_medium(solstice->parser, thin->medium_i); + medium_t = solparser_get_medium(solstice->parser, thin->medium_t); + ssol_medium_i.refractive_index = medium_i->refractive_index; + ssol_medium_t.refractive_index = medium_t->refractive_index; + ssol_medium_i.absorptivity = medium_i->absorptivity; + ssol_medium_t.absorptivity = medium_t->absorptivity; + SSOL(thin_dielectric_setup + (mtl, &shader, &ssol_medium_i, &ssol_medium_t, thin->thickness)); + +exit: + *out_mtl = mtl; + return res; +error: + if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + goto exit; +} + + /******************************************************************************* * Local functions ******************************************************************************/ @@ -225,18 +305,33 @@ solstice_create_ssol_material if(pssol_mtl) { ssol_mtl = *pssol_mtl; } else { + const struct solparser_material_dielectric* dielectric; const struct solparser_material_matte* matte; const struct solparser_material_mirror* mirror; + const struct solparser_material_thin_dielectric* thin_dielectric; switch(mtl->type) { - case SOLPARSER_MATERIAL_MIRROR: - mirror = solparser_get_material_mirror(solstice->parser, mtl->data.mirror); - res = create_material_mirror(solstice, mirror, &ssol_mtl); + case SOLPARSER_MATERIAL_DIELECTRIC: + dielectric = solparser_get_material_dielectric + (solstice->parser, mtl->data.dielectric); + res = create_material_dielectric(solstice, dielectric, &ssol_mtl); break; case SOLPARSER_MATERIAL_MATTE: - matte = solparser_get_material_matte(solstice->parser, mtl->data.matte); + matte = solparser_get_material_matte + (solstice->parser, mtl->data.matte); res = create_material_matte(solstice, matte, &ssol_mtl); break; + case SOLPARSER_MATERIAL_MIRROR: + mirror = solparser_get_material_mirror + (solstice->parser, mtl->data.mirror); + res = create_material_mirror(solstice, mirror, &ssol_mtl); + break; + case SOLPARSER_MATERIAL_THIN_DIELECTRIC: + thin_dielectric = solparser_get_material_thin_dielectric + (solstice->parser, mtl->data.thin_dielectric); + res = create_material_thin_dielectric + (solstice, thin_dielectric, &ssol_mtl); + break; default: FATAL("Unreachable code.\n"); break; } if(res != RES_OK) goto error; 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) { @@ -230,10 +246,11 @@ solstice_node_geometry_set_primary } res_T -solstice_node_geometry_set_receiver(struct solstice_node* node, const int mask) +solstice_node_geometry_set_receiver + (struct solstice_node* node, const int mask, const int per_primitive) { ASSERT(node && node->type == SOLSTICE_NODE_GEOMETRY); - return ssol_instance_set_receiver(node->instance, mask); + return ssol_instance_set_receiver(node->instance, mask, per_primitive); } void diff --git a/src/solstice_object.c b/src/solstice_object.c @@ -284,21 +284,21 @@ create_stl ASSERT(str_cget(&stl->filename)); res = sstl_create(NULL, solstice->allocator, 0, &tmp_stl); - if (res != RES_OK) { + if(res != RES_OK) { fprintf(stderr, "Could not create a Solstice Solver STL shape.\n"); goto error; } res = sstl_load(tmp_stl, str_cget(&stl->filename)); - if (res != RES_OK) goto error; + if(res != RES_OK) goto error; res = sstl_get_desc(tmp_stl, &tmp_desc); - if (res != RES_OK) goto error; + if(res != RES_OK) goto error; ASSERT(tmp_desc.triangles_count <= UINT_MAX); ASSERT(tmp_desc.vertices_count <= UINT_MAX); mesh_ctx.transform = transform; mesh_ctx.desc = tmp_desc; res = ssol_shape_create_mesh(solstice->ssol, &ssol_shape); - if (res != RES_OK) { + if(res != RES_OK) { fprintf(stderr, "Could not create the STL mesh shape.\n"); goto error; } @@ -308,20 +308,17 @@ create_stl res = ssol_mesh_setup(ssol_shape, (unsigned)tmp_desc.triangles_count, mesh_ctx_sstl_get_ids, (unsigned)tmp_desc.vertices_count, &vertex_data, 1, &mesh_ctx); - if (res != RES_OK) { + if(res != RES_OK) { fprintf(stderr, "Could not setup STL mesh.\n"); goto error; } exit: - if (tmp_stl) { - SSTL(ref_put(tmp_stl)); - tmp_stl = NULL; - } + if(tmp_stl) SSTL(ref_put(tmp_stl)); *out_stl = ssol_shape; return res; error: - if (ssol_shape) { + if(ssol_shape) { SSOL(shape_ref_put(ssol_shape)); ssol_shape = NULL; } @@ -405,7 +402,9 @@ create_parabol quadric.data.parabol.focal = paraboloid->focal; d33_set(quadric.transform, transform); d3_set(quadric.transform+9, transform+9); - + if(paraboloid->nslices > 0) { /* nslices is set */ + quadric.slices_count_hint = (size_t)paraboloid->nslices; + } return create_ssol_shape_punched_surface (solstice, &paraboloid->polyclips, &quadric, out_ssol_shape); } @@ -424,9 +423,12 @@ create_parabolic_cylinder paraboloid = solparser_get_shape_parabolic_cylinder(solstice->parser, id); quadric.type = SSOL_QUADRIC_PARABOLIC_CYLINDER; - quadric.data.parabol.focal = paraboloid->focal; + quadric.data.parabolic_cylinder.focal = paraboloid->focal; d33_set(quadric.transform, transform); d3_set(quadric.transform+9, transform+9); + if(paraboloid->nslices > 0) { /* nslices is set */ + quadric.slices_count_hint = (size_t)paraboloid->nslices; + } return create_ssol_shape_punched_surface (solstice, &paraboloid->polyclips, &quadric, out_ssol_shape); @@ -434,6 +436,32 @@ create_parabolic_cylinder } static res_T +create_hyperbol + (struct solstice* solstice, + const double transform[12], + const struct solparser_shape_hyperboloid_id id, + struct ssol_shape** out_ssol_shape) +{ + const struct solparser_shape_hyperboloid* hyperboloid; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + ASSERT(solstice); + + hyperboloid = solparser_get_shape_hyperbol(solstice->parser, id); + + quadric.type = SSOL_QUADRIC_HYPERBOL; + quadric.data.hyperbol.real_focal = hyperboloid->focals.real; + quadric.data.hyperbol.img_focal = hyperboloid->focals.image; + d33_set(quadric.transform, transform); + d3_set(quadric.transform + 9, transform + 9); + if(hyperboloid->nslices > 0) { /* nslices is set */ + quadric.slices_count_hint = (size_t)hyperboloid->nslices; + } + + return create_ssol_shape_punched_surface + (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); +} + +static res_T create_plane (struct solstice* solstice, const double transform[12], @@ -441,12 +469,14 @@ create_plane struct ssol_shape** out_ssol_shape) { const struct solparser_shape_plane* plane; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; ASSERT(solstice); plane = solparser_get_shape_plane(solstice->parser, id); + ASSERT(plane->nslices > 0); quadric.type = SSOL_QUADRIC_PLANE; + quadric.slices_count_hint = (size_t)plane->nslices; d33_set(quadric.transform, transform); d3_set(quadric.transform+9, transform+9); @@ -503,6 +533,9 @@ create_shaded_shape res = create_parabolic_cylinder (solstice, transform, shape->data.parabol, ssol_shape); break; + case SOLPARSER_SHAPE_HYPERBOL: + res = create_hyperbol(solstice, transform, shape->data.hyperbol, ssol_shape); + break; case SOLPARSER_SHAPE_PLANE: res = create_plane(solstice, transform, shape->data.plane, ssol_shape); break; diff --git a/src/solstice_solve.c b/src/solstice_solve.c @@ -23,24 +23,33 @@ * Helper function ******************************************************************************/ static void -write_global_mc(struct solstice* solstice, struct ssol_estimator* estimator) +write_mc_global(struct solstice* solstice, struct ssol_estimator* estimator) { - struct ssol_estimator_status status; + struct ssol_mc_global mc_global; struct htable_receiver_iterator it, end; const struct solparser_sun* solparser_sun = NULL; + size_t nexperiments; double irradiance_factor; ASSERT(solstice && estimator); + #define MC_RCV_NONE { \ + { -1, -1, -1 }, /* Integrated irradiance */ \ + { -1, -1, -1 }, /* Absorptivity loss */ \ + { -1, -1, -1 }, /* Reflectivity loss */ \ + { -1, -1, -1 }, /* Cos loss */ \ + 0, NULL, NULL \ + } + /* get global information */ - SSOL(estimator_get_status(estimator, SSOL_STATUS_SHADOW, &status)); - SSOL(estimator_get_primary_area(estimator, &irradiance_factor)); + SSOL(estimator_get_mc_global(estimator, &mc_global)); + SSOL(estimator_get_count(estimator, &nexperiments)); + SSOL(estimator_get_sampled_area(estimator, &irradiance_factor)); solparser_sun = solparser_get_sun(solstice->parser); - irradiance_factor = 1 / (solparser_sun->dni * irradiance_factor); + irradiance_factor = 1.0 / (solparser_sun->dni * irradiance_factor); - fprintf(solstice->output, "%lu %lu %lu\n", + fprintf(solstice->output, "%lu %lu\n", (unsigned long)htable_receiver_size_get(&solstice->receivers), - (unsigned long)status.N, - (unsigned long)status.Nf); + (unsigned long)nexperiments); htable_receiver_begin(&solstice->receivers, &it); htable_receiver_end(&solstice->receivers, &end); @@ -48,63 +57,316 @@ write_global_mc(struct solstice* solstice, struct ssol_estimator* estimator) const struct str* name = htable_receiver_iterator_key_get(&it); struct solstice_receiver* rcv = htable_receiver_iterator_data_get(&it); struct ssol_instance* inst = rcv->node->instance; - struct ssol_estimator_status front; - struct ssol_estimator_status back; + struct ssol_mc_receiver front = MC_RCV_NONE; + struct ssol_mc_receiver back = MC_RCV_NONE; + double f_eff_E = -1, f_eff_SE = -1; /* Front efficiency */ + double b_eff_E = -1, b_eff_SE = -1; /* Back efficiency */ uint32_t id; - double f_eff_E, f_eff_SE, b_eff_E, b_eff_SE; htable_receiver_iterator_next(&it); switch(rcv->side) { case SRCVL_FRONT: - SSOL(estimator_get_receiver_status(estimator, inst, SSOL_FRONT, &front)); - back.irradiance.E = back.irradiance.SE = -1; - back.reflectivity_loss.E = back.reflectivity_loss.SE = -1; - back.absorptivity_loss.E = back.absorptivity_loss.SE = -1; - back.cos_loss.E = back.cos_loss.SE = -1; - f_eff_E = front.irradiance.E * irradiance_factor; - f_eff_SE = front.irradiance.SE * irradiance_factor; - b_eff_E = b_eff_SE = -1; + SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_FRONT, &front)); + f_eff_E = front.integrated_irradiance.E * irradiance_factor; + f_eff_SE = front.integrated_irradiance.SE * irradiance_factor; break; case SRCVL_BACK: - SSOL(estimator_get_receiver_status(estimator, inst, SSOL_BACK, &back)); - front.irradiance.E = front.irradiance.SE = -1; - front.reflectivity_loss.E = front.reflectivity_loss.SE = -1; - front.absorptivity_loss.E = front.absorptivity_loss.SE = -1; - front.cos_loss.E = front.cos_loss.SE = -1; - f_eff_E = f_eff_SE = -1; - b_eff_E = back.irradiance.E * irradiance_factor; - b_eff_SE = back.irradiance.SE * irradiance_factor; + SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_BACK, &back)); + b_eff_E = back.integrated_irradiance.E * irradiance_factor; + b_eff_SE = back.integrated_irradiance.SE * irradiance_factor; break; case SRCVL_FRONT_AND_BACK: - SSOL(estimator_get_receiver_status(estimator, inst, SSOL_FRONT, &front)); - SSOL(estimator_get_receiver_status(estimator, inst, SSOL_BACK, &back)); - f_eff_E = front.irradiance.E * irradiance_factor; - f_eff_SE = front.irradiance.SE * irradiance_factor; - b_eff_E = back.irradiance.E * irradiance_factor; - b_eff_SE = back.irradiance.SE * irradiance_factor; + SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_FRONT, &front)); + SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_BACK, &back)); + f_eff_E = front.integrated_irradiance.E * irradiance_factor; + f_eff_SE = front.integrated_irradiance.SE * irradiance_factor; + b_eff_E = back.integrated_irradiance.E * irradiance_factor; + b_eff_SE = back.integrated_irradiance.SE * irradiance_factor; break; default: FATAL("Unreachable code.\n"); break; } SSOL(instance_get_id(inst, &id)); - fprintf(solstice->output, + fprintf(solstice->output, "%s %u %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n", - str_cget(name), (unsigned) id, - front.irradiance.E, front.irradiance.SE, - back.irradiance.E, back.irradiance.SE, + str_cget(name), (unsigned)id, + front.integrated_irradiance.E, front.integrated_irradiance.SE, + back.integrated_irradiance.E, back.integrated_irradiance.SE, front.reflectivity_loss.E, front.reflectivity_loss.SE, back.reflectivity_loss.E, back.reflectivity_loss.SE, front.absorptivity_loss.E, front.absorptivity_loss.SE, back.absorptivity_loss.E, back.absorptivity_loss.SE, front.cos_loss.E, front.cos_loss.SE, back.cos_loss.E, back.cos_loss.SE, - /* global efficiency */ f_eff_E, f_eff_SE, b_eff_E, b_eff_SE); } - SSOL(estimator_get_status(estimator, SSOL_STATUS_SHADOW, &status)); - fprintf(solstice->output, "%g %g\n", status.irradiance.E, status.irradiance.SE); - SSOL(estimator_get_status(estimator, SSOL_STATUS_MISSING, &status)); - fprintf(solstice->output, "%g %g\n", status.irradiance.E, status.irradiance.SE); + fprintf(solstice->output, "%g %g\n", + mc_global.shadowed.E, mc_global.shadowed.SE); + fprintf(solstice->output, "%g %g\n", + mc_global.missing.E, mc_global.missing.SE); +} + +static void +dump_instantiated_shaded_shape_vertices + (struct solstice* solstice, + const struct ssol_instantiated_shaded_shape* inst_sshape) +{ + unsigned ivert, nverts; + ASSERT(solstice && inst_sshape); + + SSOL(shape_get_vertices_count(inst_sshape->shape, &nverts)); + FOR_EACH(ivert, 0, nverts) { + double pos[3]; + SSOL(instantiated_shaded_shape_get_vertex_attrib + (inst_sshape, ivert, SSOL_POSITION, pos)); + fprintf(solstice->output, "%f %f %f\n", SPLIT3(pos)); + } +} + +static void +dump_shape_triangle_indices + (struct solstice* solstice, + const struct ssol_shape* shape, + const size_t offset) +{ + unsigned itri, ntris; + ASSERT(solstice && shape); + + SSOL(shape_get_triangles_count(shape, &ntris)); + FOR_EACH(itri, 0, ntris) { + unsigned ids[3]; + SSOL(shape_get_triangle_indices(shape, itri, ids)); + fprintf(solstice->output, "3 %lu %lu %lu\n", + (unsigned long)(ids[0] + offset), + (unsigned long)(ids[1] + offset), + (unsigned long)(ids[2] + offset)); + } +} + +static void +dump_mc_shape + (struct solstice* solstice, + struct ssol_shape* shape, + struct ssol_mc_shape* mc_shape) +{ + unsigned itri, ntris; + ASSERT(solstice && shape && mc_shape); + + SSOL(shape_get_triangles_count(shape, &ntris)); + FOR_EACH(itri, 0, ntris) { + struct ssol_mc_primitive mc_prim; + SSOL(mc_shape_get_mc_primitive(mc_shape, itri, &mc_prim)); + fprintf(solstice->output, "%g %g\n", + mc_prim.integrated_irradiance.E, + mc_prim.integrated_irradiance.SE); + } +} + +static void +dump_per_primitive_mc_estimations + (struct solstice* solstice, + struct ssol_estimator* estimator, + struct ssol_instance* inst, + const enum ssol_side_flag side) +{ + size_t ishape, nshapes; + struct ssol_mc_receiver mc_rcv; + const char* name; + ASSERT(solstice && estimator && inst); + + SSOL(estimator_get_mc_receiver(estimator, inst, side, &mc_rcv)); + + switch(side) { + case SSOL_FRONT: name = "Front_faces"; break; + case SSOL_BACK: name = "Back_faces"; break; + default: FATAL("Unreachable code.\n"); break; + } + + fprintf(solstice->output, "SCALARS %s float 2\n", name); + fprintf(solstice->output, "LOOKUP_TABLE default\n"); + + SSOL(instance_get_shaded_shapes_count(inst, &nshapes)); + FOR_EACH(ishape, 0, nshapes) { + struct ssol_instantiated_shaded_shape inst_sshape; + struct ssol_mc_shape mc_shape; + SSOL(instance_get_shaded_shape(inst, ishape, &inst_sshape)); + SSOL(mc_receiver_get_mc_shape(&mc_rcv, inst_sshape.shape, &mc_shape)); + dump_mc_shape(solstice, inst_sshape.shape, &mc_shape); + } +} + +static void +write_per_receiver_mc_primitive + (struct solstice* solstice, struct ssol_estimator* estimator) +{ + struct htable_receiver_iterator it, end; + ASSERT(solstice && estimator); + + htable_receiver_begin(&solstice->receivers, &it); + htable_receiver_end(&solstice->receivers, &end); + while(!htable_receiver_iterator_eq(&it, &end)) { + struct ssol_instantiated_shaded_shape inst_sshape; + const struct str* name = htable_receiver_iterator_key_get(&it); + struct solstice_receiver* rcv = htable_receiver_iterator_data_get(&it); + struct ssol_instance* inst = rcv->node->instance; + size_t ishape, nshapes; + size_t nverts, ntris; + size_t offset; + + htable_receiver_iterator_next(&it); + SSOL(instance_get_shaded_shapes_count(inst, &nshapes)); + + /* Write the header */ + fprintf(solstice->output, "# vtk DataFile Version 2.0\n"); + fprintf(solstice->output, "%s\n", str_cget(name)); + fprintf(solstice->output, "ASCII\n"); + fprintf(solstice->output, "DATASET POLYDATA\n"); + + /* Compute the overall number of vertices & triangles of the receiver */ + nverts = ntris = 0; + FOR_EACH(ishape, 0, nshapes) { + unsigned shape_nverts, shape_ntris; + SSOL(instance_get_shaded_shape(inst, ishape, &inst_sshape)); + SSOL(shape_get_vertices_count(inst_sshape.shape, &shape_nverts)); + SSOL(shape_get_triangles_count(inst_sshape.shape, &shape_ntris)); + nverts += shape_nverts; + ntris += shape_ntris; + } + + /* Write the positions of the receiver shaded shapes */ + fprintf(solstice->output, "POINTS %lu float\n", (unsigned long)nverts); + FOR_EACH(ishape, 0, nshapes) { + SSOL(instance_get_shaded_shape(inst, ishape, &inst_sshape)); + dump_instantiated_shaded_shape_vertices(solstice, &inst_sshape); + } + + /* Write the triangles of the receiver shade shapes */ + offset = 0; + fprintf(solstice->output, "POLYGONS %lu %lu\n", + (unsigned long)ntris, (unsigned long)ntris*4); + FOR_EACH(ishape, 0, nshapes) { + unsigned shape_nverts; + SSOL(instance_get_shaded_shape(inst, ishape, &inst_sshape)); + SSOL(shape_get_vertices_count(inst_sshape.shape, &shape_nverts)); + dump_shape_triangle_indices(solstice, inst_sshape.shape, offset); + offset += shape_nverts; + } + + /* Write front faces MC estimations */ + fprintf(solstice->output, "CELL_DATA %lu\n", (unsigned long)ntris); + switch(rcv->side) { + case SRCVL_FRONT: + dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_FRONT); + break; + case SRCVL_BACK: + dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_BACK); + break; + case SRCVL_FRONT_AND_BACK: + dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_FRONT); + dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_BACK); + break; + default: FATAL("Unreachable code.\n"); break; + } + } +} + +static void +dump_path_positions(struct solstice* solstice, const struct ssol_path* path) +{ + size_t ivert, nverts; + ASSERT(solstice && path); + + SSOL(path_get_vertices_count(path, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct ssol_path_vertex vertex; + SSOL(path_get_vertex(path, ivert, &vertex)); + fprintf(solstice->output, "%f %f %f\n", SPLIT3(vertex.pos)); + } +} + +static void +dump_path_segments + (struct solstice* solstice, + const struct ssol_path* path, + const size_t offset) +{ + size_t i, nverts; + ASSERT(solstice && path); + + SSOL(path_get_vertices_count(path, &nverts)); + ASSERT(nverts); + + fprintf(solstice->output, "%lu", (unsigned long)nverts); + FOR_EACH(i, 0, nverts) { + fprintf(solstice->output, " %lu", (unsigned long)i + offset); + } + fprintf(solstice->output, "\n"); +} + +static void +write_paths(struct solstice* solstice, struct ssol_estimator* estimator) +{ + struct ssol_path path; + size_t ipath, npaths; + size_t nverts, nlines; + size_t offset; + ASSERT(solstice && estimator); + + /* Write the header */ + fprintf(solstice->output, "# vtk DataFile Version 2.0\n"); + fprintf(solstice->output, "Radiative paths\n"); + fprintf(solstice->output, "ASCII\n"); + fprintf(solstice->output, "DATASET POLYDATA\n"); + + /* Compute the overall number of path vertices & segments */ + nverts = 0; + SSOL(estimator_get_tracked_paths_count(estimator, &npaths)); + FOR_EACH(ipath, 0, npaths) { + size_t n; + SSOL(estimator_get_tracked_path(estimator, ipath, &path)); + SSOL(path_get_vertices_count(&path, &n)); + nverts += n; + nlines += n - 1; + } + + /* Write the positions of the tracked paths */ + fprintf(solstice->output, "POINTS %lu float\n", (unsigned long)nverts); + FOR_EACH(ipath, 0, npaths) { + SSOL(estimator_get_tracked_path(estimator, ipath, &path)); + dump_path_positions(solstice, &path); + } + + /* Write the segment of the tracked paths */ + offset = 0; + fprintf(solstice->output, "LINES %lu %lu\n", + (unsigned long)npaths, (unsigned long)nverts + npaths); + FOR_EACH(ipath, 0, npaths) { + size_t n; + SSOL(estimator_get_tracked_path(estimator, ipath, &path)); + SSOL(path_get_vertices_count(&path, &n)); + dump_path_segments(solstice, &path, offset); + offset += n; + } + + /* Write path type */ + fprintf(solstice->output, "CELL_DATA %lu\n", (unsigned long)npaths); + fprintf(solstice->output, "SCALARS Radiative_path_type float 1\n"); + fprintf(solstice->output, "LOOKUP_TABLE path_type\n"); + FOR_EACH(ipath, 0, npaths) { + enum ssol_path_type type; + SSOL(estimator_get_tracked_path(estimator, ipath, &path)); + SSOL(path_get_type(&path, &type)); + switch(type) { + case SSOL_PATH_MISSING: fprintf(solstice->output, "1.0\n"); break; + case SSOL_PATH_SUCCESS: fprintf(solstice->output, "0.5\n"); break; + case SSOL_PATH_SHADOW: fprintf(solstice->output, "0.0\n"); break; + default: FATAL("Unreachable code.\n"); break; + } + } + fprintf(solstice->output, "LOOKUP_TABLE path_type 3\n"); + fprintf(solstice->output, "1.0 0.0 0.0 1.0\n"); + fprintf(solstice->output, "0.0 0.0 1.0 1.0\n"); + fprintf(solstice->output, "1.0 1.0 0.0 1.0\n"); } /******************************************************************************* @@ -136,32 +398,38 @@ solstice_solve(struct solstice* solstice) } } - res = ssol_solve(solstice->scene, rng, solstice->nrealisations, - bin_stream, &estimator); + res = ssol_solve(solstice->scene, rng, solstice->nexperiments, + solstice->dump_paths ? &solstice->path_tracker : NULL, bin_stream, + &estimator); if(res != RES_OK) { fprintf(stderr, "Error in integrating the solar flux.\n"); goto error; } - write_global_mc(solstice, estimator); + if(solstice->dump_paths) { + write_paths(solstice, estimator); + } else { + write_mc_global(solstice, estimator); + write_per_receiver_mc_primitive(solstice, estimator); - if(solstice->output_hits) { - sz = (size_t)ftell(bin_stream); - rewind(bin_stream); - - while(sz) { - const size_t read_sz = MMIN(sz, sizeof(buf)); - if(fread(buf, 1, read_sz, bin_stream) != read_sz) { - fprintf(stderr, "Could not read the output binary stream.\n"); - res = RES_IO_ERR; - goto error; - } - if(fwrite(buf, 1, read_sz, solstice->output) != read_sz) { - fprintf(stderr, "Could not write the output binary stream.\n"); - res = RES_IO_ERR; - goto error; + if(solstice->output_hits) { + sz = (size_t)ftell(bin_stream); + rewind(bin_stream); + + while(sz) { + const size_t read_sz = MMIN(sz, sizeof(buf)); + if(fread(buf, 1, read_sz, bin_stream) != read_sz) { + fprintf(stderr, "Could not read the output binary stream.\n"); + res = RES_IO_ERR; + goto error; + } + if(fwrite(buf, 1, read_sz, solstice->output) != read_sz) { + fprintf(stderr, "Could not write the output binary stream.\n"); + res = RES_IO_ERR; + goto error; + } + sz -= read_sz; } - sz -= read_sz; } } diff --git a/src/test_solstice_args.c b/src/test_solstice_args.c @@ -83,13 +83,15 @@ test_rendering(void) cmd = cmd_create(0, "test", "-r", "img=1280x720", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); CHECK(args.rendering, 1); - CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(args.nexperiments, SOLSTICE_ARGS_DEFAULT.nexperiments); CHECK(d3_eq(args.camera.pos, SOLSTICE_ARGS_DEFAULT.camera.pos), 1); CHECK(d3_eq(args.camera.tgt, SOLSTICE_ARGS_DEFAULT.camera.tgt), 1); CHECK(d3_eq(args.camera.up, SOLSTICE_ARGS_DEFAULT.camera.up), 1); CHECK(args.camera.fov_x, SOLSTICE_ARGS_DEFAULT.camera.fov_x); CHECK(args.img.width, 1280); CHECK(args.img.height, 720); + CHECK(args.img.spp, SOLSTICE_ARGS_DEFAULT.img.spp); + CHECK(args.render_mode, SOLSTICE_ARGS_DEFAULT.render_mode); CHECK(args.quiet, 0); CHECK(args.output_filename, NULL); solstice_args_release(&args); @@ -98,32 +100,49 @@ test_rendering(void) cmd = cmd_create(0, "test", "-q", "-r", "img=640x480:fov=70:pos=1,2,3", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); CHECK(args.rendering, 1); - CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(args.nexperiments, SOLSTICE_ARGS_DEFAULT.nexperiments); CHECK(d3_eq(args.camera.pos, d3(tmp, 1, 2, 3)), 1); CHECK(d3_eq(args.camera.tgt, SOLSTICE_ARGS_DEFAULT.camera.tgt), 1); CHECK(d3_eq(args.camera.up, SOLSTICE_ARGS_DEFAULT.camera.up), 1); CHECK(args.img.width, 640); CHECK(args.img.height, 480); + CHECK(args.img.spp, SOLSTICE_ARGS_DEFAULT.img.spp); + CHECK(args.render_mode, SOLSTICE_ARGS_DEFAULT.render_mode); CHECK(args.quiet, 1); CHECK(eq_eps(args.camera.fov_x, 70, 1.e-6), 1); CHECK(args.output_filename, NULL); solstice_args_release(&args); cmd_delete(cmd); - cmd = cmd_create(0, "test", "-r", "up=0,0,1:tgt=0,-10,0", NULL); + cmd = cmd_create(0, "test", "-r", "up=0,0,1:tgt=0,-10,0:rmode=draft", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(args.nexperiments, SOLSTICE_ARGS_DEFAULT.nexperiments); CHECK(d3_eq(args.camera.pos, SOLSTICE_ARGS_DEFAULT.camera.pos), 1); CHECK(d3_eq(args.camera.tgt, d3(tmp, 0,-10, 0)), 1); CHECK(d3_eq(args.camera.up, d3(tmp, 0, 0, 1)), 1); CHECK(args.img.width, SOLSTICE_ARGS_DEFAULT.img.width); CHECK(args.img.height, SOLSTICE_ARGS_DEFAULT.img.height); + CHECK(args.img.spp, SOLSTICE_ARGS_DEFAULT.img.spp); + CHECK(args.render_mode, SOLSTICE_ARGS_RENDER_DRAFT); CHECK(args.rendering, 1); CHECK(args.quiet, 0); CHECK(args.output_filename, NULL); solstice_args_release(&args); cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "up=0,0,1:rmode=pt:spp=4", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.nexperiments, SOLSTICE_ARGS_DEFAULT.nexperiments); + CHECK(d3_eq(args.camera.up, d3(tmp, 0, 0, 1)), 1); + CHECK(args.img.width, SOLSTICE_ARGS_DEFAULT.img.width); + CHECK(args.img.height, SOLSTICE_ARGS_DEFAULT.img.height); + CHECK(args.rendering, 1); + CHECK(args.output_filename, NULL); + CHECK(args.img.spp, 4); + CHECK(args.render_mode, SOLSTICE_ARGS_RENDER_PATH_TRACING); + solstice_args_release(&args); + cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "up=0,10,0", "-o", "my_output", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); CHECK(d3_eq(args.camera.up, d3(tmp, 0, 10, 0)), 1); @@ -133,6 +152,21 @@ test_rendering(void) solstice_args_release(&args); cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "spp=16", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.img.spp, 16); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "rmode=none", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "rmode", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "up=0,1", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); cmd_delete(cmd); @@ -151,6 +185,10 @@ test_rendering(void) solstice_args_release(&args); cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "spp=0", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "img=32X32", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); cmd_delete(cmd); @@ -159,6 +197,18 @@ test_rendering(void) CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "img=0x64", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "img=64x0", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "img=32x32@12:up=0,0,1", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + cmd = cmd_create(0, "test", "-r", "tgt=1,1,1:img=32x32:12", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); cmd_delete(cmd); @@ -166,6 +216,22 @@ test_rendering(void) cmd = cmd_create(0, "test", "-r", "fov=123a", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "up", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "img=", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "fov::::", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "::tgt", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); } static void @@ -251,19 +317,19 @@ test_realisations_count(void) cmd = cmd_create(0, "test", "-D", "0,90", "-n", "1", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.nrealisations, 1); + CHECK(args.nexperiments, 1); solstice_args_release(&args); cmd_delete(cmd); cmd = cmd_create(0, "test", "-D", "0,90", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(args.nexperiments, SOLSTICE_ARGS_DEFAULT.nexperiments); solstice_args_release(&args); cmd_delete(cmd); cmd = cmd_create(0, "test", "-D", "0,90", "-n", "123", NULL); CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.nrealisations, 123); + CHECK(args.nexperiments, 123); solstice_args_release(&args); cmd_delete(cmd); @@ -443,6 +509,167 @@ 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); + + cmd = cmd_create(0, "test", "-g", "format=obj", "-r", "up=0,0,1", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-g", "format=obj", "-p", "default", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); +} + +static void +test_dump_paths(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_paths, 0); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "default", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(args.infinite_ray_length, SOLSTICE_ARGS_DEFAULT.infinite_ray_length); + CHECK(args.sun_ray_length, SOLSTICE_ARGS_DEFAULT.sun_ray_length); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "irlen=3.14:srlen=1.23", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(eq_eps(args.infinite_ray_length, 3.14, 1.e-6), 1); + CHECK(eq_eps(args.sun_ray_length, 1.23, 1.e-6), 1); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "irlen=0", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(eq_eps(args.infinite_ray_length, 0, 1.e-6), 1); + CHECK(args.sun_ray_length, SOLSTICE_ARGS_DEFAULT.sun_ray_length); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "srlen=-4", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(args.infinite_ray_length, SOLSTICE_ARGS_DEFAULT.infinite_ray_length); + CHECK(eq_eps(args.sun_ray_length, -4, 1.e-6), 1); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "srlen=3.14:default", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(args.infinite_ray_length, SOLSTICE_ARGS_DEFAULT.infinite_ray_length); + CHECK(args.sun_ray_length, SOLSTICE_ARGS_DEFAULT.sun_ray_length); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "default:srlen=1:irlen=2:", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.dump_paths, 1); + CHECK(args.sun_ray_length, 1); + CHECK(args.infinite_ray_length, 2); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "srlen=", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "irlen=", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "srlen=abcd", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "irlen", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "=abcd", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "default:srlen=1:irlen=2:", + "-r", "up=0,0,1", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-p", "default:srlen=1:irlen=2:", + "-g", "format=obj", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_BAD_ARG); + cmd_delete(cmd); +} + int main(int argc, char** argv) { @@ -456,6 +683,8 @@ main(int argc, char** argv) test_quiet(); test_receivers(); test_input(); + test_dump(); + test_dump_paths(); CHECK(mem_allocated_size(), 0); return 0; } diff --git a/src/test_solstice_simulation.c b/src/test_solstice_simulation.c @@ -0,0 +1,434 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200809L /* mkstemp support */ + +#include <rsys/rsys.h> +#include <rsys/math.h> + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef COMPILER_CL + /* Wrap POSIX functions and constants */ + #include <io.h> + #include <fcntl.h> + #include <sys/stat.h> + #define fdopen _fdopen + #define open _open +#endif + +enum side { + FRONT, + BACK +}; + +enum result_type { + FRONT_INTEGRATED_IRRADIANCE, + BACK_INTEGRATED_IRRADIANCE, + FRONT_REFLECTIVITY_LOSS, + BACK_REFLECTIVITY_LOSS, + FRONT_ABSORPTIVITY_LOSS, + BACK_ABSORPTIVITY_LOSS, + FRONT_COS_LOSS, + BACK_COS_LOSS, + FRONT_EFFICIENCY, + BACK_EFFICIENCY, + MAX_RESULTS_COUNT__ +}; + +#define MAX_LINE_LEN 2048 + +static const char +sundir_header [] = "#--- Sun direction:"; + +#define IS_NEW_BLOCK(Line, Header) (!strncmp((Line), (Header), strlen(Header))) + + +#ifdef COMPILER_CL +/* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright + * (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc. + * + * The GNU C Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. */ + +static const char letters [] = +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* Generate a temporary file name based on TMPL. TMPL must match the + * rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed + * does not exist at the time of the call to mkstemp. TMPL is + * overwritten with the result. */ +int +mkstemp(char *tmpl) +{ + size_t len; + char *XXXXXX; + static unsigned long long value; + unsigned long long random_time_bits; + unsigned int count; + int fd = -1; + int save_errno = errno; + + /* A lower bound on the number of temporary files to attempt to + * generate. The maximum total number of temporary file names that + * can exist for a given template is 62**6. It should never be + * necessary to try all these combinations. Instead if a reasonable + * number of names is tried (we define reasonable as 62**3) fail to + * give the system administrator the chance to remove the problems. */ + #define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To + * conform to POSIX, this must be no smaller than TMP_MAX. */ + #if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; + #else + unsigned int attempts = ATTEMPTS_MIN; + #endif + + len = strlen(tmpl); + if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX")) { + errno = EINVAL; + return -1; + } + + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6]; + + /* Get some more or less random data. */ + { + SYSTEMTIME stNow; + FILETIME ftNow; + + /* get system time */ + GetSystemTime(&stNow); + stNow.wMilliseconds = 500; + if (!SystemTimeToFileTime(&stNow, &ftNow)) { + errno = -1; + return -1; + } + + random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) + | (unsigned long long)ftNow.dwLowDateTime); + } + value += random_time_bits ^ (unsigned long long)GetCurrentThreadId(); + + for (count = 0; count < attempts; value += 7777, ++count) { + unsigned long long v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + fd = open(tmpl, O_RDWR|O_CREAT|O_EXCL, S_IREAD|S_IWRITE); + if (fd >= 0) { + errno = save_errno; + return fd; + } + else if (errno != EEXIST) + return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + errno = EEXIST; + return -1; +} +#endif + +static int +read_line(char* line, size_t max_line_len, FILE* stream) +{ + ASSERT(stream && line && max_line_len); + line = fgets(line, (int)max_line_len, stream); + if(!line) return 0; + CHECK(strlen(line) + 1 < max_line_len, 1); + return 1; +} + +static void +get_dir_and_counts + (FILE* ref_file, + double angles[2], + unsigned long* recv_count, + unsigned long* realisation_count) +{ + char line[MAX_LINE_LEN]; + int n; + + NCHECK(ref_file, NULL); + NCHECK(angles, NULL); + NCHECK(recv_count, NULL); + NCHECK(realisation_count, NULL); + + /* Get sun dir */ + CHECK(read_line(line, sizeof(line), ref_file), 1); + CHECK(IS_NEW_BLOCK(line, sundir_header), 1); + n = sscanf(line+strlen(sundir_header), "%lg%lg", &angles[0], &angles[1]); + CHECK(n, 2); + + /* Get #receivers and #realisations */ + CHECK(read_line(line, sizeof(line), ref_file), 1); + n = sscanf(line, "%lu%lu", recv_count, realisation_count); + CHECK(n, 2); +} + +static void +read_recv(const char* line, char name[], double E[], double SE[]) +{ + int n; + + NCHECK(line, NULL); + NCHECK(name, NULL); + NCHECK(E, NULL); + NCHECK(SE, NULL); + + n = sscanf(line, + "%s%*u%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg", + name, + &E[FRONT_INTEGRATED_IRRADIANCE], &SE[FRONT_INTEGRATED_IRRADIANCE], + &E[BACK_INTEGRATED_IRRADIANCE], &SE[BACK_INTEGRATED_IRRADIANCE], + &E[FRONT_REFLECTIVITY_LOSS], &SE[FRONT_REFLECTIVITY_LOSS], + &E[BACK_REFLECTIVITY_LOSS], &SE[BACK_REFLECTIVITY_LOSS], + &E[FRONT_ABSORPTIVITY_LOSS], &SE[FRONT_ABSORPTIVITY_LOSS], + &E[BACK_ABSORPTIVITY_LOSS], &SE[BACK_ABSORPTIVITY_LOSS], + &E[FRONT_COS_LOSS], &SE[FRONT_COS_LOSS], + &E[BACK_COS_LOSS], &SE[BACK_COS_LOSS], + &E[FRONT_EFFICIENCY], &SE[FRONT_EFFICIENCY], + &E[BACK_EFFICIENCY], &SE[BACK_EFFICIENCY]); + + CHECK(n, 2*MAX_RESULTS_COUNT__+1); +} + +#define POSITIVE_OR_M_ONE(x) ((x) == -1 || (x) >= 0) + +static FINLINE int +is_compatible_with + (const double ref_E, + const double ref_SE, + const double test_E, + const double test_SE) +{ + double SE; + + CHECK(POSITIVE_OR_M_ONE(ref_E), 1); + CHECK(POSITIVE_OR_M_ONE(ref_SE), 1); + CHECK(POSITIVE_OR_M_ONE(test_E), 1); + CHECK(POSITIVE_OR_M_ONE(test_SE), 1); + + if(ref_E == -1) { + CHECK(ref_SE, -1); + return (test_E == -1 && test_SE == -1); + } + + NCHECK(ref_SE, -1); + SE = ref_SE > 0 ? 2 * ref_SE : (ref_E > 0 ? ref_E * 1e-6 : 1e-6); + return (fabs(ref_E - test_E) <= SE && test_SE <= SE); +} + +static void +check_1_reference + (FILE* tested_file, + const char* rcv_name, + const double* reference_E, + const double* reference_SE) +{ + double a[2]; + unsigned long c1, c2; + int found = 0; + + NCHECK(tested_file, NULL); + NCHECK(rcv_name, NULL); + NCHECK(reference_E, NULL); + NCHECK(reference_SE, NULL); + + get_dir_and_counts(tested_file, a, &c1, &c2); /* Skip headers */ + + while(!feof(tested_file) && !found) { + char line[MAX_LINE_LEN]; + char tested_rcv_name[MAX_LINE_LEN]; + double tested_E[MAX_RESULTS_COUNT__], tested_SE[MAX_RESULTS_COUNT__]; + enum result_type r; + + CHECK(read_line(line, sizeof(line), tested_file), 1); + + read_recv(line, tested_rcv_name, tested_E, tested_SE); + if(strcmp(rcv_name, tested_rcv_name)) continue; + + FOR_EACH(r, FRONT_INTEGRATED_IRRADIANCE, MAX_RESULTS_COUNT__) { + CHECK(is_compatible_with + (reference_E[r], reference_SE[r], tested_E[r], tested_SE[r]), 1); + } + found = 1; + } + CHECK(found, 1); +} + +static void +check_1_global + (FILE* tested_file, + const double reference_E, + const double reference_SE, + const unsigned rank) +{ + char line[MAX_LINE_LEN]; + double a[2]; + unsigned long recv_count, r2; + unsigned i; + int nb; + double tested_E, tested_SE; + + get_dir_and_counts(tested_file, a, &recv_count, &r2); + + /* Skip receivers */ + while(recv_count--) CHECK(read_line(line, sizeof(line), tested_file), 1); + + /* Read the rank th global data */ + FOR_EACH(i, 0, rank+1) CHECK(read_line(line, sizeof(line), tested_file), 1); + + nb = sscanf(line, "%lg%lg", &tested_E, &tested_SE); + CHECK(nb, 2); + CHECK(is_compatible_with(reference_E, reference_SE, tested_E, tested_SE), 1); +} + +static void +check_references(FILE* ref_file, FILE* tested_file) +{ + char line[MAX_LINE_LEN]; + unsigned nb_global = 0; + fpos_t pos; + + NCHECK(ref_file, NULL); + NCHECK(tested_file, NULL); + + CHECK(fgetpos(ref_file, &pos), 0); + while(read_line(line, sizeof(line), ref_file)) { + double val, std; + int nb = 0; + + if(IS_NEW_BLOCK(line, sundir_header)) { + /* Keep the header as a part of the following block */ + CHECK(fsetpos(ref_file, &pos), 0); + break; + } + + nb = sscanf(line, "%lg%lg", &val, &std); + CHECK(nb == 0 || nb == 2, 1); + + rewind(tested_file); + if(nb != 0) { + check_1_global(tested_file, val, std, nb_global); + nb_global++; + } else { + char ref_name[MAX_LINE_LEN]; + double reference_E[MAX_RESULTS_COUNT__]; + double reference_SE[MAX_RESULTS_COUNT__]; + read_recv(line, ref_name, reference_E, reference_SE); + check_1_reference(tested_file, ref_name, reference_E, reference_SE); + } + + CHECK(fgetpos(ref_file, &pos), 0); + } +} + +static FINLINE int +create_tmp_file(char* name, const size_t max_sizeof_name) +{ + const char* template = "solstice_tmp_file_XXXXXX"; + int fd; + NCHECK(name, NULL); + CHECK(strlen(template)+1 <= max_sizeof_name-1, 1); + strcpy(name, template); + fd = mkstemp(name); + NCHECK(fd, -1); + return fd; +} + +static void +do_check(const char* binary, const char* dir, const char* base_name) +{ + char ref_file_name[128]; + FILE* ref_file; + unsigned long c1, realisation_count; + int n; + int err; + ASSERT(base_name); + + n = snprintf(ref_file_name, sizeof(ref_file_name), "%s%s.ref", dir, base_name); + CHECK((size_t)n < sizeof(ref_file_name), 1); + + ref_file = fopen(ref_file_name, "r"); + NCHECK(ref_file, NULL); + + while(!feof(ref_file)) { + char cmd[512]; + char tested_file_name[128]; + double sun_angles[2]; + FILE* fp = NULL; + int fd = -1; + + get_dir_and_counts(ref_file, sun_angles, &c1, &realisation_count); + + fd = create_tmp_file(tested_file_name, sizeof(tested_file_name)); + fp = fdopen(fd, "r"); + NCHECK(fp, NULL); + + n = snprintf(cmd, sizeof(cmd), + "%s -o %s -f -D %g,%g -n %lu -R %s%s_receiver.yaml %s%s.yaml", + binary, tested_file_name, SPLIT2(sun_angles), realisation_count, + dir, base_name, dir, base_name); + CHECK((unsigned)n < sizeof(cmd), 1); + + err = system(cmd); + CHECK(err, 0); + + check_references(ref_file, fp); + + fclose(fp); + remove(tested_file_name); + } +} + +int +main(int argc, char** argv) +{ + int err = 0; + + if(argc != 4) { + printf("Usage: %s <solstice-binary> <file-path> <file-base-name>\n", argv[0]); + goto error; + } + + do_check(argv[1], argv[2], argv[3]); + +exit: + return err; +error: + err = 1; + goto exit; +} + diff --git a/yaml/beam_down.ref b/yaml/beam_down.ref @@ -0,0 +1,12 @@ +#--- Sun direction: 0 90 (-3.7494e-33 -6.12323e-17 -1) +2 10000 +tower.secondary.hyperbol 10 465.464 0.00509812 0 0 0 0 0 0 0 0 0 0 34.5362 0.00509812 0 0 0.930847 1.01954e-05 0 0 +tower.receptor 14 465.464 0.00509812 -1 -1 0 0 -1 -1 0 0 -1 -1 34.5362 0.00509812 -1 -1 0.930847 1.01954e-05 -1 -1 +0 0 +0 0 +#--- Sun direction: 50 50 (-0.413176 -0.492404 -0.766044) +2 10000 +tower.secondary.hyperbol 10 400.231 0.107226 0 0 0 0 0 0 0 0 0 0 99.7686 0.107226 0 0 0.800393 0.000214433 0 0 +tower.receptor 14 136.51 1.90718 -1 -1 0 0 -1 -1 0 0 -1 -1 32.9896 0.464742 -1 -1 0.272997 0.00381404 -1 -1 +0 0 +0 0 diff --git a/yaml/beam_down.yaml b/yaml/beam_down.yaml @@ -0,0 +1,108 @@ +# Debug/solstice -D 90,90 -R ../yaml/beam_down_receiver.yaml ../yaml/beam_down.yaml +# Debug/solstice -D 90,90 -r pos=-100,-100,50:tgt=0,0,50:up=0,0,1:img=1000x800 -o ../yaml/beam_down.ppm -f ../yaml/beam_down.yaml +# +# 1 10000 +# tower.receptor 14 465.464 0.00509812 -1 -1 0 0 -1 -1 0 0 -1 -1 34.5362 0.00509812 -1 -1 0.930847 1.01954e-05 -1 -1 +# 0 0 +# 0 0 +# --- Sun direction: -3.7494e-33 -6.12323e-17 -1 + +- sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } + +- material: &mirror { mirror: { reflectivity: 1, roughness: 0 } } +- material: &black { matte: { reflectivity: 0 } } +- material: &virtual { virtual: } + +- template: &hyperbol + name: hyperbol + primary: 0 + geometry: + - hyperbol: + focals: &hyperbol_focals { real: 100, image: 20 } + clip: + - operation: AND + #vertices: [[-25, -25], [-25, 25], [25, 25], [25, -25]] + vertices: [[-5, 0], [20, -10], [35, 0], [20, 10]] + material: { front: *mirror, back: *virtual } + anchors: + - name: image_point + hyperboloid_image_focals: *hyperbol_focals + +- geometry: &target + - plane: + clip: + - operation: AND + vertices: [[-2.5, -2.5], [-2.5, 2.5], [2.5, 2.5], [2.5, -2.5]] + #vertices: [[-1, -1], [-1, 1], [1, 1], [1, -1]] + #vertices: [[-.5, -.5], [-.5, .5], [.5, .5], [.5, -.5]] + #vertices: [[-.1, -.1], [-.1, .1], [.1, .1], [.1, -.1]] + material: *black + +- geometry: &primary150 + - parabol: + focal: 150 + clip: + - operation: AND + vertices: [[-5, -5], [-5, 5], [5, 5], [5, -5]] + #vertices: [[-3, -3], [-3, 3], [3, 3], [3, -3]] + #vertices: [[-2, -2], [-2, 2], [2, 2], [2, -2]] + #vertices: [[-1, -1], [-1, 1], [1, 1], [1, -1]] + #vertices: [[-.01, -.01], [-.01, .01], [.01, .01], [.01, -.01]] + material: *mirror + +- template: &temp_heliostat150 + name: "temp-heliostat150" + primary: 0 + geometry: + - cylinder: { radius: 0.3, height: 10 } + transform: { translation: [0, 0, 5] } + material: *black + children: + - name: "pivot" + transform: { translation: [0, 0, 10] } + zx_pivot: + spacing: 1 + target: { anchor: tower.secondary.hyperbol.image_point } + children: + - name: "reflector" + transform: { rotation: [-90, 0, 0] } + primary: 1 + geometry: *primary150 + +- entity: + name: "tower" + children: + - name: secondary + children: [ *hyperbol ] + transform: { translation: [ 0, 0, 100 ] } + - name: receptor + geometry: *target + primary: 0 + - name: "building" + primary: 0 + geometry: + - cylinder: { radius: 1, height: 110 } + transform: { translation: [-4, 0, 55] } + material: *black + +- entity: + name: "heliostat1" + transform: { translation: [100, -30, 0] } + children: [ *temp_heliostat150 ] +- entity: + name: "heliostat2" + transform: { translation: [101, -15, 0] } + children: [ *temp_heliostat150 ] +- entity: + name: "heliostat3" + transform: { translation: [102, 0, 0] } + children: [ *temp_heliostat150 ] +- entity: + name: "heliostat4" + transform: { translation: [101, 15, 0] } + children: [ *temp_heliostat150 ] +- entity: + name: "heliostat5" + transform: { translation: [100, 30, 0] } + children: [ *temp_heliostat150 ] + +\ No newline at end of file diff --git a/yaml/beam_down_receiver.yaml b/yaml/beam_down_receiver.yaml @@ -0,0 +1,2 @@ +- { name: "tower.receptor", side: FRONT } +- { name: "tower.secondary.hyperbol" } +\ No newline at end of file diff --git a/yaml/test01.ref b/yaml/test01.ref @@ -0,0 +1,5 @@ +#--- Sun direction: 0 90 (-6.12323e-17 -0 -1) +1 10000 +square_receiver 2 -1 -1 1 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 1 0 +0 0 +0 0 diff --git a/yaml/test01.yaml b/yaml/test01.yaml @@ -0,0 +1,50 @@ +- sun: &sun + dni: 1 + spectrum: [{wavelength: 1, data: 1}] + +- material: &specular + front: + mirror: { reflectivity: 1, roughness: 0 } + back: + mirror: { reflectivity: 1, roughness: 0 } + + +- geometry: &small_square + - material: *specular + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + +- geometry: &big_square + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-5.00, -5.00] + - [-5.00, 5.00] + - [5.00, 5.00] + - [5.00, -5.00] + + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *small_square + + + +- entity: + name: "square_receiver" + primary: 0 + transform: { rotation: [0, 0, 0], translation: [0, 0, 2] } + geometry: *big_square + + + diff --git a/yaml/test01_receiver.yaml b/yaml/test01_receiver.yaml @@ -0,0 +1 @@ +- { name: "square_receiver", side: BACK } diff --git a/yaml/test02.ref b/yaml/test02.ref @@ -0,0 +1,5 @@ +#--- Sun direction: 0 90 (-6.12323e-17 -0 -1) +1 100000 +square_receiver 2 -1 -1 1 0.0313065 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0.01003 0.000315109 +0 0 +99 0.0313065 diff --git a/yaml/test02.yaml b/yaml/test02.yaml @@ -0,0 +1,47 @@ +- sun: &sun + dni: 1 + spectrum: [{wavelength: 1, data: 1}] + +- material: &specular + mirror: { reflectivity: 1, roughness: 0 } + + +- geometry: &small_square + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + +- geometry: &big_square + - material: *specular + plane: + clip: + - operation: AND + vertices: + - [-5.00, -5.00] + - [-5.00, 5.00] + - [5.00, 5.00] + - [5.00, -5.00] + + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *big_square + + + +- entity: + name: "square_receiver" + primary: 0 + transform: { rotation: [0, 0, 0], translation: [0, 0, 2] } + geometry: *small_square + + + diff --git a/yaml/test02_receiver.yaml b/yaml/test02_receiver.yaml @@ -0,0 +1 @@ +- { name: "square_receiver", side: BACK } diff --git a/yaml/test03.ref b/yaml/test03.ref @@ -0,0 +1,5 @@ +#--- Sun direction: 0 45 (-0.707107 -0 -0.707107) +1 10000 +square_receiver 2 -1 -1 0.707107 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0.292893 0 -1 -1 0.707107 0 +0 0 +0 0 diff --git a/yaml/test03.yaml b/yaml/test03.yaml @@ -0,0 +1,49 @@ +- sun: &sun + dni: 1 + spectrum: [{wavelength: 1, data: 1}] + +- material: &specular + front: + mirror: { reflectivity: 1, roughness: 0 } + back: + mirror: { reflectivity: 1, roughness: 0 } + +- geometry: &small_square + - material: *specular + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + +- geometry: &big_square + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-5.00, -5.00] + - [-5.00, 5.00] + - [5.00, 5.00] + - [5.00, -5.00] + + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *small_square + + + +- entity: + name: "square_receiver" + primary: 0 + transform: { rotation: [0, 0, 0], translation: [-2, 0, 2] } + geometry: *big_square + + + diff --git a/yaml/test03_receiver.yaml b/yaml/test03_receiver.yaml @@ -0,0 +1 @@ +- { name: "square_receiver", side: BACK } diff --git a/yaml/test04.ref b/yaml/test04.ref @@ -0,0 +1,4 @@ +#--- Sun direction: 0 45 (-0.707107 -0 -0.707107) +1 10000 +square_receiver 2 0 0 0.707107 0 0 0 0 0 0 0 0 0 0 0 0.292893 0 0 0 0.707107 0 +0 0 diff --git a/yaml/test04.yaml b/yaml/test04.yaml @@ -0,0 +1,52 @@ +- sun: &sun + dni: 1 + spectrum: [{wavelength: 1, data: 1}] + +- material: &specular + front: + mirror: { reflectivity: 1, roughness: 0 } + back: + mirror: { reflectivity: 1, roughness: 0 } + +- material: &black + matte: { reflectivity: 0 } + +- geometry: &small_square + - material: *specular + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + +- geometry: &big_square + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-5.00, -5.00] + - [-5.00, 5.00] + - [5.00, 5.00] + - [5.00, -5.00] + + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *small_square + + + +- entity: + name: "square_receiver" + primary: 0 + transform: { rotation: [0, -45, 0], translation: [-2, 0, 2] } + geometry: *big_square + + + diff --git a/yaml/test04_receiver.yaml b/yaml/test04_receiver.yaml @@ -0,0 +1 @@ +- { name: "square_receiver", side: FRONT_AND_BACK } diff --git a/yaml/test05.ref b/yaml/test05.ref @@ -0,0 +1,5 @@ +#--- Sun direction: 0 90 (-6.12323e-17 -0 -1) +1 10000 +spherical_receiver 2 -1 -1 1 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 1 0 +0 0 +0 0 diff --git a/yaml/test05.yaml b/yaml/test05.yaml @@ -0,0 +1,44 @@ +- sun: &sun + dni: 1 + spectrum: [{wavelength: 1, data: 1}] + +- material: &lambertian + front: + matte: { reflectivity: 1 } + back: + matte: { reflectivity: 1 } + +- geometry: &small_square + - material: *lambertian + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + +- geometry: &big_sphere + - material: { virtual: } + sphere: + radius: 2.0 + slices: 128 + + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *small_square + + + +- entity: + name: "spherical_receiver" + primary: 0 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *big_sphere + + + diff --git a/yaml/test05_receiver.yaml b/yaml/test05_receiver.yaml @@ -0,0 +1 @@ +- { name: "spherical_receiver", side: BACK }