Chi-Tech
raytrace_utils.cc
Go to the documentation of this file.
1#include "raytracing.h"
2#include "mesh/Cell/cell.h"
4
5#include <algorithm>
6
7//###################################################################
8/**Computes the intersection of a line with a plane.
9 *
10 * The first step of this algorithm is to compute v0 and v1. These
11 * are vectors from the plane's reference point to each of the line-points,
12 * respectively.
13 * We then take the dot-products of these
14 * vectors with the plane normal.
15 * We then say that the vectors have a positive sense if the dot-product
16 * is positive and a negative sense if the dot-product is negative.
17 * If the senses are not equal then the line intersects the plane.
18 *
19 * Since the face normal is a normalized vector the dot-product of v0 or v1
20 * will give the projection of the relevant vector along the normal to the
21 * plane. We can use this projection to compute a weight associated with
22 * each vector. This also then allows us to compute the intersection point.
23
24 \param plane_normal The normal associated with the plane
25 \param plane_point The reference point for the plane
26 \param line_point_0 The line's initial point
27 \param line_point_1 The line's destination point
28 \param intersection_point The point to be populated with the intersection
29 point
30 \param weights The weights associated with this intersection
31
32 \return Returns true if the line intersects the plane and false otherwise.
33
34 \author Jan*/
37 const chi_mesh::Vector3& plane_point,
38 const chi_mesh::Vector3& line_point_0,
39 const chi_mesh::Vector3& line_point_1,
40 chi_mesh::Vector3& intersection_point,
41 std::pair<double,double>* weights/*=nullptr*/)
42{
43 chi_mesh::Vector3 v0 = line_point_0 - plane_point;
44 chi_mesh::Vector3 v1 = line_point_1 - plane_point;
45
46 double dotp_0 = plane_normal.Dot(v0);
47 double dotp_1 = plane_normal.Dot(v1);
48
49 bool sense_0 = (dotp_0 >= 0.0);
50 bool sense_1 = (dotp_1 >= 0.0);
51
52 if (sense_0 != sense_1)
53 {
54 double dotp_total = std::fabs(dotp_0) + std::fabs(dotp_1);
55 double w0 = (std::fabs(dotp_0)/dotp_total);
56 double w1 = 1.0 - w0;
57 intersection_point = line_point_0*w1 + line_point_1*w0;
58
59 if (weights != nullptr)
60 *weights = {w0,w1};
61 return true;
62 }
63
64 return false;
65}
66
67//###################################################################
68/**Given a strip defined by two points (v0,v1) and a normal, n,
69 * (meaning infinite in the direction defined by (v1-v0).cross(n),
70 * this function determines if a line, defined from p0 to p1,
71 * intersects it. If it does then `true` is returned and
72 * `intersection_point` contains the point of intersection. If it does
73 * not then `false` is returned and `intersection_point` remains
74 * unchanged.
75 *
76 * */
78 const chi_mesh::Vector3& strip_point0,
79 const chi_mesh::Vector3& strip_point1,
80 const chi_mesh::Vector3& strip_normal,
81 const chi_mesh::Vector3& line_point0,
82 const chi_mesh::Vector3& line_point1,
83 chi_mesh::Vector3& intersection_point,
84 double* distance_to_intersection)
85{
86 chi_mesh::Vector3 plane_intersection_point;
87 std::pair<double,double> weights;
88
89 bool intersects_plane = chi_mesh::CheckPlaneLineIntersect(
90 strip_normal, strip_point0,
91 line_point0, line_point1,
92 plane_intersection_point, &weights);
93
94 if (!intersects_plane) return false;
95
96 chi_mesh::Vector3 edge_vec = strip_point1 - strip_point0;
97 chi_mesh::Vector3 ints_vec1 = plane_intersection_point - strip_point0;
98 chi_mesh::Vector3 ints_vec2 = plane_intersection_point - strip_point1;
99
100 bool sense1 = edge_vec.Dot(ints_vec1)>=0.0;
101 bool sense2 = edge_vec.Dot(ints_vec2)>=0.0;
102
103 if (distance_to_intersection != nullptr)
104 *distance_to_intersection =
105 (plane_intersection_point - line_point0).Norm();
106
107 if (sense1 != sense2)
108 {
109 intersection_point = plane_intersection_point;
110
111 return true;
112 }
113
114 return false;
115}
116
117//###################################################################
118/**Given a triangle defined by three points, computes whether a line
119 * intersects this triangle.
120 *
121 * */
122bool
124 const chi_mesh::Vector3& tri_point0,
125 const chi_mesh::Vector3& tri_point1,
126 const chi_mesh::Vector3& tri_point2,
127 const chi_mesh::Vector3& ray_posi,
128 const chi_mesh::Vector3& ray_dir,
129 chi_mesh::Vector3& intersection_point,
130 double* distance_to_intersection)
131{
132 double epsilon = 1.0e-12;
133 chi_mesh::Vector3 edge1 = tri_point1 - tri_point0;
134 chi_mesh::Vector3 edge2 = tri_point2 - tri_point0;
135
136 // Compute characteristic vector for incident angle
137 // This vector becomes perpendicular to the plane
138 // when the ray is parallel to triangle
139 chi_mesh::Vector3 h = ray_dir.Cross(edge2);
140
141 // If h is indeed perpendicular to the plane,
142 // the dot product of the other leg with this h will be close
143 // to zero.
144 double a = edge1.Dot(h);
145 if (std::fabs(a) < epsilon)
146 return false;
147
148 chi_mesh::Vector3 s = ray_posi - tri_point0;
149
150 double f = 1.0/a;
151
152 // If, s projected onto h, is greater than,
153 // v01 projected onto h, or negative, there is now way
154 // the ray can intersect
155 double u = f*(s.Dot(h));
156 if (u<0.0 or u>1.0)
157 return false;
158
159 chi_mesh::Vector3 q = s.Cross(edge1);
160
161 // If, q projected onto omega, is greater than,
162 // v01 projected onto h, or negative, there is now way
163 // the ray can intersect
164 double v = f*ray_dir.Dot(q);
165 if (v<0.0 or (u+v)>1.0)
166 return false;
167
168 double t = f*edge2.Dot(q);
169
170 if (distance_to_intersection != nullptr)
171 *distance_to_intersection = t;
172
173 if (t > epsilon and t<(1.0/epsilon))
174 {
175 intersection_point = ray_posi + ray_dir*t;
176 return true;
177 } else
178 {
179 return false;
180 }
181}
182
183//###################################################################
184/** Check whether a point lies in a triangle.*/
185bool
187 const chi_mesh::Vector3& v0,
188 const chi_mesh::Vector3& v1,
189 const chi_mesh::Vector3& v2,
190 const chi_mesh::Normal& n,
191 const chi_mesh::Vector3& point)
192{
193 auto v01 = v1 - v0;
194 auto v12 = v2 - v1;
195 auto v20 = v0 - v2;
196
197 auto v0p = point - v0;
198 auto v1p = point - v1;
199 auto v2p = point - v2;
200
201 auto vc0 = v01.Cross(v0p);
202 auto vc1 = v12.Cross(v1p);
203 auto vc2 = v20.Cross(v2p);
204
205 bool dp0 = (vc0.Dot(n) >= 0.0);
206 bool dp1 = (vc1.Dot(n) >= 0.0);
207 bool dp2 = (vc2.Dot(n) >= 0.0);
208
209 if (dp0 and dp1 and dp2)
210 return true;
211 else
212 return false;
213
214}
215
216//###################################################################
217/** This functions checks the intersection of a plane with a tetrahedron.
218 * The equation of a plane is
219 * nx(x-x0) + ny(y-y0) + nz(z-z0) = 0
220 * Where the plane normal is (nx,ny,nz) and the plane point is (x0,y0,z0).
221 * If we form a dot product between the normal and a vector
222 * (x-x0,y-y0,z-z0) then sign of the result gives the sense to the surface.
223 * Therefore, if we encounter differing senses then the plane is indeed
224 * intersecting.*/
226CheckPlaneTetIntersect(const chi_mesh::Normal& plane_normal,
227 const chi_mesh::Vector3& plane_point,
228 const std::vector<chi_mesh::Vector3>& tet_points)
229{
230 bool current_sense = false;
231
232 size_t num_points = tet_points.size();
233 for (size_t i=0; i<num_points; i++)
234 {
235 chi_mesh::Vector3 v = tet_points[i] - plane_point;
236 double dotp = plane_normal.Dot(v);
237
238 bool new_sense = (dotp >= 0.0);
239
240 if (i==0)
241 current_sense = new_sense;
242 else if (new_sense != current_sense)
243 return true;
244 }
245 return false;
246}
247
248
249
250//###################################################################
251/** Populates segment lengths along a ray. Sorted along the direction.*/
253 const chi_mesh::MeshContinuum& grid,
254 const Cell& cell,
255 const chi_mesh::Vector3& line_point0,
256 const chi_mesh::Vector3& line_point1,
257 const chi_mesh::Vector3& omega,
258 std::vector<double> &segment_lengths)
259{
260 const chi_mesh::Vector3 khat(0,0,1);
261 std::set<double> distance_set;
262
263 double track_length;
264 if (segment_lengths.empty())
265 {
266 track_length = (line_point1-line_point0).Norm();
267 segment_lengths.push_back(track_length);
268 }
269
270 track_length = segment_lengths.front();
271 distance_set.insert(track_length);
272
273 //======================================== Determine intersection points
274 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SLAB
275 // Since there are no segments within a slab we will only have
276 // a single segment length. It is already pushed
277
278 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% POLYGON
279 // A polygon can be decomposed into "sides" by means of its
280 // edges. Each side comprises a triangle formed by: the two
281 // vertices of the associated edge v0 and v1, and the cell
282 // centroid vc.
283 // Since the triangles all share an edge we only determine
284 // segment lengths from the strip defined by v0 to vc.
285 if (cell.Type() == chi_mesh::CellType::POLYGON)
286 {
287 int f=-1;
288 for (auto& face : cell.faces_) //edges
289 {
290 f++;
291 const auto& v0 = grid.vertices[face.vertex_ids_[0]];
292 const auto& vc = cell.centroid_;
293
294 auto n0 = (vc-v0).Cross(khat).Normalized();
295
296 chi_mesh::Vertex intersection_point;
297 double d = 0.0;
298 bool intersects = chi_mesh::CheckLineIntersectStrip(
299 v0, vc, n0,
300 line_point0, line_point1,
301 intersection_point, &d);
302
303 if (intersects)
304 {
305// double d = (intersection_point - line_point0).Norm();
306 distance_set.insert(d);
307 }
308
309 }//for face
310 }
311 else if (cell.Type() == chi_mesh::CellType::POLYHEDRON)
312 {
313 auto& vcc = cell.centroid_;
314
315 int f=-1;
316 for (auto& face : cell.faces_)
317 {
318 f++;
319 auto& vfc = face.centroid_;
320
321 //===================== Face center to vertex segments
322 for (auto vi : face.vertex_ids_)
323 {
324 auto& vert = grid.vertices[vi];
325
326 chi_mesh::Vertex intersection_point;
327
328 double d = 0.0;
330 vert,vfc,vcc,line_point0,omega,intersection_point,&d);
331
332 if (intersects)
333 {
334 if (d < track_length)
335 distance_set.insert(d);
336 }
337 }//for edge
338
339 //===================== Face edge to cell center segments
340 for (int v=0; v<face.vertex_ids_.size(); ++v)
341 {
342 uint64_t vid_0 = face.vertex_ids_[v];
343 uint64_t vid_1 = (v<(face.vertex_ids_.size() - 1)) ?
344 face.vertex_ids_[v + 1] :
345 face.vertex_ids_[0];
346
347 auto& v0 = grid.vertices[vid_0];
348 auto& v1 = grid.vertices[vid_1];
349 auto& v2 = vcc;
350
351 chi_mesh::Vertex intersection_point;
352
353 double d = 0.0;
355 v0,v1,v2,line_point0,omega,intersection_point,&d);
356
357 if (intersects)
358 {
359 if (d < track_length)
360 distance_set.insert(d);
361 }
362 }//for edge
363 }//for face
364 }
365
366 //======================================== Populate segment lengths
367 //if there are N segments intersected then there will always be
368 //N+1 distances.
369 segment_lengths.clear();
370 double last_distance = 0.0;
371 for (double dl : distance_set)
372 {
373 double new_seg_length = dl - last_distance;
374 last_distance = dl;
375 segment_lengths.push_back(new_seg_length);
376 }
377
378}
std::vector< CellFace > faces_
Definition: cell.h:82
CellType Type() const
Definition: cell.h:98
Vertex centroid_
Definition: cell.h:78
bool CheckPlaneTetIntersect(const chi_mesh::Normal &plane_normal, const chi_mesh::Vector3 &plane_point, const std::vector< chi_mesh::Vector3 > &tet_points)
bool CheckLineIntersectTriangle2(const chi_mesh::Vector3 &tri_point0, const chi_mesh::Vector3 &tri_point1, const chi_mesh::Vector3 &tri_point2, const chi_mesh::Vector3 &ray_posi, const chi_mesh::Vector3 &ray_dir, chi_mesh::Vector3 &intersection_point, double *distance_to_intersection=nullptr)
bool CheckPlaneLineIntersect(const chi_mesh::Normal &plane_normal, const chi_mesh::Vector3 &plane_point, const chi_mesh::Vector3 &line_point_0, const chi_mesh::Vector3 &line_point_1, chi_mesh::Vector3 &intersection_point, std::pair< double, double > *weights=nullptr)
void PopulateRaySegmentLengths(const chi_mesh::MeshContinuum &grid, const Cell &cell, const chi_mesh::Vector3 &line_point0, const chi_mesh::Vector3 &line_point1, const chi_mesh::Vector3 &omega, std::vector< double > &segment_lengths)
bool CheckLineIntersectStrip(const chi_mesh::Vector3 &strip_point0, const chi_mesh::Vector3 &strip_point1, const chi_mesh::Vector3 &strip_normal, const chi_mesh::Vector3 &line_point0, const chi_mesh::Vector3 &line_point1, chi_mesh::Vector3 &intersection_point, double *distance_to_intersection=nullptr)
bool CheckPointInTriangle(const chi_mesh::Vector3 &v0, const chi_mesh::Vector3 &v1, const chi_mesh::Vector3 &v2, const chi_mesh::Normal &n, const chi_mesh::Vector3 &point)
Vector3 Cross(const Vector3 &that) const
Vector3 Normalized() const
Vector3 Dot(const chi_mesh::TensorRank2Dim3 &that) const