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:
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, ¶boloid->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(¶bol->polyclips), 1);
+ polyclip = darray_polyclip_cdata_get(¶bol->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, ¶boloid->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, ¶boloid->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 }