sdis_heat_path_conductive_custom_Xd.h (6363B)
1 /* Copyright (C) 2016-2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "sdis.h" 17 #include "sdis_log.h" 18 #include "sdis_medium_c.h" 19 #include "sdis_scene_c.h" 20 21 #include <rsys/cstr.h> 22 23 #include "sdis_Xd_begin.h" 24 25 /******************************************************************************* 26 * Helper function 27 ******************************************************************************/ 28 static res_T 29 XD(check_sampled_path) 30 (struct sdis_scene* scn, 31 const struct rwalk* rwalk, 32 const struct sdis_path* path) 33 { 34 int null_prim = 0; 35 res_T res = RES_OK; 36 ASSERT(scn && path); 37 38 null_prim = SXD_PRIMITIVE_EQ(&path->XD(prim), &SXD_PRIMITIVE_NULL); 39 40 /* Check end of path */ 41 if(!path->at_limit && null_prim) { 42 log_err(scn->dev, 43 "%s: the sampled path should have reached a limit condition or a boundary" 44 " -- pos=("FORMAT_VECX")\n", 45 FUNC_NAME, SPLITX(path->vtx.P)); 46 res = RES_BAD_ARG; 47 goto error; 48 } 49 50 /* Check path time */ 51 if(path->vtx.time > rwalk->vtx.time) { 52 log_err(scn->dev, 53 "%s: the sampled trajectory cannot be in the future. " 54 "It can only go back in time -- starting time=%g s; current time=%g s\n", 55 FUNC_NAME, rwalk->vtx.time, path->vtx.time); 56 res = RES_BAD_ARG; 57 goto error; 58 } 59 60 if(!null_prim) { 61 struct sXd(primitive) prim; 62 const unsigned iprim = path->XD(prim).prim_id; 63 64 /* Check intersected primitive */ 65 res = sXd(scene_view_get_primitive)(scn->sXd(view), iprim, &prim); 66 if(res != RES_OK || !SXD_PRIMITIVE_EQ(&path->XD(prim), &prim)) { 67 log_err(scn->dev, 68 "%s: invalid intersected primitive on sampled path -- %s\n", 69 FUNC_NAME, res_to_cstr(res)); 70 goto error; 71 } 72 } 73 74 exit: 75 return res; 76 error: 77 goto exit; 78 } 79 80 static int 81 XD(keep_only_one_primitive) 82 (const struct sXd(hit)* hit, 83 const float org[DIM], 84 const float dir[DIM], 85 const float range[2], 86 void* query_data, 87 void* filter_data) 88 { 89 const struct sXd(primitive)* prim = query_data; 90 (void)org, (void)dir, (void)range, (void)filter_data; 91 return !SXD_PRIMITIVE_EQ(prim, &hit->prim); 92 } 93 94 static res_T 95 XD(get_path_hit) 96 (struct sdis_scene* scn, 97 struct sdis_path* path, 98 const struct sdis_medium* mdm, 99 struct sXd(hit)* hit) 100 { 101 struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL; 102 float query_radius = 0; 103 float query_pos[DIM] = {0}; 104 double delta = 0; 105 res_T res = RES_OK; 106 ASSERT(scn && path && hit); 107 108 filter_data.XD(custom_filter) = XD(keep_only_one_primitive); 109 filter_data.custom_filter_data = &path->XD(prim); 110 111 /* Search for the hit corresponding to the path position on a primitive. Search 112 * at a maximum distance from the delta of the medium, as this hit should be 113 * very close to the submitted position, since it should represent the same 114 * point. */ 115 delta = solid_get_delta(mdm, &path->vtx); 116 fX_set_dX(query_pos, path->vtx.P); 117 query_radius = (float)delta; 118 SXD(scene_view_closest_point(scn->sXd(view), query_pos, query_radius, 119 &filter_data, hit)); 120 ASSERT(SXD_PRIMITIVE_EQ(&hit->prim, &path->XD(prim))); 121 122 if(SXD_HIT_NONE(hit)) { 123 log_warn(scn->dev, 124 "%s: the position returned by custom sampling of the conductive path " 125 "is too far from the primitive it should be on -- " 126 "query position=("FORMAT_VECX"); search distance=%g\n", 127 FUNC_NAME, SPLITX(path->vtx.P), delta); 128 res = RES_BAD_OP; 129 goto error; 130 } 131 132 exit: 133 return res; 134 error: 135 goto exit; 136 } 137 138 /******************************************************************************* 139 * Local function 140 ******************************************************************************/ 141 res_T 142 XD(conductive_path_custom) 143 (struct sdis_scene* scn, 144 const unsigned enc_id, 145 const struct sdis_medium* mdm, 146 struct rwalk* rwalk, 147 struct ssp_rng* rng, 148 struct temperature* T) 149 { 150 struct sdis_path path = SDIS_PATH_NULL; 151 res_T res = RES_OK; 152 153 /* Check pre-conditions */ 154 ASSERT(scn && rwalk && rng && T); 155 ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID); 156 ASSERT(mdm->shader.solid.sample_path); 157 158 /* Sample a conductive path */ 159 path.vtx = rwalk->vtx; 160 res = mdm->shader.solid.sample_path(scn, rng, &path, mdm->data); 161 if(res != RES_OK) { 162 log_err(scn->dev, 163 "%s: error in customized sampling of a conductive path " 164 "from pos=("FORMAT_VECX") -- %s\n", 165 FUNC_NAME, SPLITX(rwalk->vtx.P), res_to_cstr(res)); 166 goto error; 167 } 168 169 res = XD(check_sampled_path)(scn, rwalk, &path); 170 if(res!= RES_OK) goto error; 171 172 /* Update random walk position and time from sampled path */ 173 rwalk->elapsed_time += rwalk->vtx.time - path.vtx.time; 174 rwalk->vtx = path.vtx; 175 176 /* Calculate path intersection with geometry if it hasn't already reached a 177 * boundary condition */ 178 if(!path.at_limit) { 179 res = XD(get_path_hit)(scn, &path, mdm, &rwalk->XD(hit)); 180 if(res != RES_OK) goto error; 181 } 182 183 184 /* The path reached a boundary */ 185 if(!SXD_HIT_NONE(&rwalk->XD(hit))) { 186 unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; 187 188 rwalk->enc_id = ENCLOSURE_ID_NULL; /* Not in an enclosure */ 189 190 /* Define which side of the interface the path is on */ 191 scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids); 192 if(enc_id == enc_ids[SDIS_FRONT]) rwalk->hit_side = SDIS_FRONT; 193 else if(enc_id == enc_ids[SDIS_BACK]) rwalk->hit_side = SDIS_BACK; 194 else FATAL("Unreachable code.\n"); 195 } 196 197 /* Update Monte Carlo weight */ 198 T->value += path.weight; 199 T->done = path.at_limit; 200 201 /* The path either reaches a boundary condition and will be stopped, or is 202 * on a boundary and a boundary path must be sampled */ 203 T->func = XD(boundary_path); 204 205 exit: 206 return res; 207 error: 208 goto exit; 209 } 210 211 #include "sdis_Xd_end.h"