Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
EmbreeShapeModel.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7
8#include "EmbreeShapeModel.h"
9
10#include <numeric>
11#include <float.h>
12
13#include <QtGlobal>
14#include <QList>
15
16#include "IException.h"
17#include "IString.h"
18#include "Latitude.h"
19#include "Longitude.h"
20#include "NaifStatus.h"
21#include "Pvl.h"
22#include "ShapeModel.h"
23#include "Target.h"
24
25
26using namespace std;
27
28namespace Isis {
29
34 : ShapeModel(),
35 m_targetShape(0),
37 m_tolerance(DBL_MAX),
38 m_shapeFile("") {
39 // defaults for ShapeModel parent class include:
40 // name = empty string
41 // surfacePoint = null sp
42 // hasIntersection = false
43 // hasNormal = false
44 // normal = (0,0,0)
45 // hasEllipsoidIntersection = false
46 setName("Embree");
47 }
48
49
63 EmbreeTargetManager *targetManager)
64 : ShapeModel(target),
65 m_targetShape(0),
66 m_targetManager(targetManager),
67 m_tolerance(DBL_MAX),
68 m_shapeFile("") {
69
70 // defaults for ShapeModel parent class include:
71 // name = empty string
72 // surfacePoint = null sp
73 // hasIntersection = false
74 // hasNormal = false
75 // normal = (0,0,0)
76 // hasEllipsoidIntersection = false
77
78 setName("Embree"); // Really is used as type in the system at present!
79
80 PvlGroup &kernels = pvl.findGroup("Kernels", Pvl::Traverse);
81
82 if (kernels.hasKeyword("ElevationModel")) {
83 m_shapeFile = (QString) kernels["ElevationModel"];
84 }
85 else { // if (kernels.hasKeyword("ShapeModel")) {
86 m_shapeFile = (QString) kernels["ShapeModel"];
87 }
88
89 try {
90 // Request the EmbreeTargetShape from the manager
91 // If the shapefile is being used by something else this will get a pointer
92 // to the same target shape, otherwise it creates a new one.
93 m_targetShape = m_targetManager->create(m_shapeFile);
94 }
95 catch(IException &e) {
96 QString msg = "Cannot create a EmbreeShape from " + m_shapeFile;
97 throw IException(e, IException::User, msg, _FILEINFO_);
98 }
99 }
100
101
109 EmbreeShapeModel::EmbreeShapeModel(Target *target, const QString &shapefile,
110 EmbreeTargetManager *targetManager)
111 : ShapeModel(target),
112 m_targetShape(0),
113 m_targetManager(targetManager),
114 m_tolerance(DBL_MAX),
115 m_shapeFile(shapefile) {
116
117 // defaults for ShapeModel parent class include:
118 // name = empty string
119 // surfacePoint = null sp
120 // hasIntersection = false
121 // hasNormal = false
122 // normal = (0,0,0)
123 // hasEllipsoidIntersection = false
124
125 setName("Embree"); // Really is used as type in the system at present!
126
127 try {
128 // Request the EmbreeTargetShape from the manager
129 // If the shapefile is being used by something else this will get a pointer
130 // to the same target shape, otherwise it creates a new one.
131 m_targetShape = m_targetManager->create(m_shapeFile);
132 }
133 catch(IException &e) {
134 QString msg = "Cannot create a EmbreeShape from " + m_shapeFile;
135 throw IException(e, IException::User, msg, _FILEINFO_);
136 }
137 }
138
139
147 if ( m_targetManager && !m_shapeFile.isEmpty() ) {
149 }
150 }
151
152
162 bool EmbreeShapeModel::intersectSurface(std::vector<double> observerPos,
163 std::vector<double> lookDirection) {
164 // Remove any previous intersection
166
167 // Create a ray from the observer in the look direction
168 RTCMultiHitRay ray(observerPos, lookDirection);
169
170 m_targetShape->intersectRay(ray);
171
172 // If nothing was hit
173 if (ray.lastHit < 0) {
174 setHasIntersection(false);
175 }
176 else {
177 // Get the intersection point and the surface normal
178 RayHitInformation hitInfo = m_targetShape->getHitInformation(ray, 0);
179
180 // Update the surface point and surface normal
181 updateIntersection(hitInfo);
182 }
183
184 return hasIntersection();
185 }
186
187
208 const std::vector<double> &observerPos,
209 const bool &backCheck) {
210 // Remove any previous intersection
212
213 // Create a ray from the origin through the surface point
214 RTCMultiHitRay ray = latlonToRay(lat,lon);
215
216 m_targetShape->intersectRay(ray);
217
218 // If no intersections (unlikely for this case), we are done!
219 if ( ray.lastHit < 0 ) {
220 return ( false );
221 }
222 LinearAlgebra::Vector observer = LinearAlgebra::vector(observerPos[0],
223 observerPos[1],
224 observerPos[2]);
225
226 // Sorts hits based on distance to the observer
227 QVector<RayHitInformation> hits = sortHits(ray, observer);
228
229 // If desired, check occlusion
230 if ( backCheck ) {
231 for (int i = 0 ; i < hits.size() ; i++) {
232 LinearAlgebra::Vector obsToIntersection = hits[i].intersection - observer;
233 LinearAlgebra::Vector lookVector = LinearAlgebra::normalize(obsToIntersection);
234
235 // Cast a ray from the observer to the intersection and check if it is occluded
236 RTCOcclusionRay obsRay;
237 obsRay.ray.org_x = observerPos[0];
238 obsRay.ray.org_y = observerPos[1];
239 obsRay.ray.org_z = observerPos[2];
240 obsRay.ray.dir_x = lookVector[0];
241 obsRay.ray.dir_y = lookVector[1];
242 obsRay.ray.dir_z = lookVector[2];
243 obsRay.ray.tnear = 0.0;
244 obsRay.ray.tfar = LinearAlgebra::magnitude(obsToIntersection) - 0.0005;
245 obsRay.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
246 obsRay.hit.geomID = RTC_INVALID_GEOMETRY_ID;
247 obsRay.hit.primID = RTC_INVALID_GEOMETRY_ID;
248 obsRay.ray.mask = 0xFFFFFFFF;
249 obsRay.ignorePrimID = hits[i].primID;
250
251 // If the intersection point is not occluded,
252 // then it is the closest intersection to the oberserver.
253 if ( !m_targetShape->isOccluded(obsRay) ) {
254 updateIntersection( hits[i] );
255 break;
256 }
257 }
258 }
259 else {
260 // If not testing for occlusion, take the hit closest to the observer
261 updateIntersection( hits[0] );
262 }
263
264 return ( hasIntersection() );
265 }
266
267
286 const std::vector<double> &observerPos,
287 const bool &backCheck) {
288 // Remove any previous intersection
290
291 // Set up for finding all rays along origin vector through lat/lon surface point
292 RTCMultiHitRay ray = pointToRay(surfpt);
293
294 // Extend the ray to be 1.5 times the length of the SurfacePoint's radius
295 ray.ray.tfar *= 1.5;
296
297 m_targetShape->intersectRay(ray);
298
299 // If no intersections (unlikely for this case), we are done!
300 if ( ray.lastHit < 0 ) {
301 return ( false );
302 }
303 // Convert the observer to a LinearAlgebra vector for occlusion testing
304 LinearAlgebra::Vector observer = LinearAlgebra::vector(observerPos[0],
305 observerPos[1],
306 observerPos[2]);
307
308 // Convert the surface point to a LinearAlgebra vector for sorting hits
309 LinearAlgebra::Vector surfPoint(3);
310 surfpt.ToNaifArray( &surfPoint[0] );
311
312 // Sorts hits based on distance to the surface point
313 QVector< RayHitInformation > hits = sortHits(ray, surfPoint);
314
315 // If desired, check occlusion
316 if ( backCheck ) {
317 for (int i = 0 ; i < hits.size() ; i++) {
318 LinearAlgebra::Vector obsToIntersection = hits[i].intersection - observer;
319 LinearAlgebra::Vector lookVector = LinearAlgebra::normalize(obsToIntersection);
320
321 // Cast a ray from the observer to the intersection and check if it is occluded
322 RTCOcclusionRay obsRay;
323 obsRay.ray.org_x = observerPos[0];
324 obsRay.ray.org_y = observerPos[1];
325 obsRay.ray.org_z = observerPos[2];
326 obsRay.ray.dir_x = lookVector[0];
327 obsRay.ray.dir_y = lookVector[1];
328 obsRay.ray.dir_z = lookVector[2];
329 obsRay.ray.tnear = 0.0;
330 obsRay.ray.tfar = LinearAlgebra::magnitude(obsToIntersection);
331 obsRay.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
332 obsRay.hit.geomID = RTC_INVALID_GEOMETRY_ID;
333 obsRay.hit.primID = RTC_INVALID_GEOMETRY_ID;
334 obsRay.ray.mask = 0xFFFFFFFF;
335 obsRay.ignorePrimID = hits[i].primID;
336
337 // If the intersection point is no occluded,
338 // then it is the closest intersection to the oberserver.
339 if ( !m_targetShape->isOccluded(obsRay) ) {
340 updateIntersection( hits[i] );
341 break;
342 }
343 }
344 }
345 else {
346 // If not testing for occlusion, take the hit closest to the surface point
347 updateIntersection( hits[0] );
348 }
349
350 return ( hasIntersection() );
351 }
352
353
360 // Flag that there is an intersection
361 setHasIntersection(true);
362
363 // Create the surfacepoint
364 SurfacePoint intersectPoint;
365 std::vector<double> intersectArray(3);
366 std::copy( hitInfo.intersection.data().begin(),
367 hitInfo.intersection.data().end(),
368 intersectArray.begin() );
369 intersectPoint.FromNaifArray( &intersectArray[0] );
370 setSurfacePoint(intersectPoint);
371
372 // Save the surface normal
373 setLocalNormal( hitInfo.surfaceNormal[0],
374 hitInfo.surfaceNormal[1],
375 hitInfo.surfaceNormal[2] );
376 }
377
378
391
392
405 const Longitude &lon) {
406
407 // Create a ray from the origin to the surface point
408 RTCMultiHitRay ray = latlonToRay(lat,lon);
409
410 // Extend the ray to 2.5 times the maximum radius
411 ray.ray.tfar *= 2.5;
412
413 m_targetShape->intersectRay(ray);
414
415 // If no intersections (unlikely for this case), we are done!
416 if ( ray.lastHit < 0 ) {
417 return ( Distance() );
418 }
419 // Otherwise, get the first intersection
420 RayHitInformation hitInfo = m_targetShape->getHitInformation( ray, 0 );
421
422 // Return the distance to the intersection
425 }
426
427
436 return false;
437 }
438
439
450 bool EmbreeShapeModel::isVisibleFrom(const std::vector<double> observerPos,
451 const std::vector<double> lookDirection) {
452 //TODO check if there is a saved intersection
453 // Create a ray from the observer in the look direction
454 RTCMultiHitRay ray(observerPos, lookDirection);
455
456 m_targetShape->intersectRay(ray);
457
458 // If nothing was hit, something went really wrong. Just return false.
459 if (ray.lastHit < 0) {
460 return false;
461 }
462 else {
463 // Get the new intersection point
464 RayHitInformation hitInfo = m_targetShape->getHitInformation(ray, 0);
465
466 // Check the distance between the new intersection and the saved intersection
467 std::vector<double> intersectVect(3);
468 surfaceIntersection()->ToNaifArray( &intersectVect[0] );
469 LinearAlgebra::Vector oldIntersection = LinearAlgebra::vector( intersectVect[0],
470 intersectVect[1],
471 intersectVect[2] );
472 return ( LinearAlgebra::magnitude(oldIntersection - hitInfo.intersection) < getTolerance() );
473 }
474 }
475
476
503 // Sanity check
504 if ( !hasIntersection() ) { // hasIntersection() <==> hasNormall()
505 QString mess = "Intercept point does not exist - cannot provide normal vector";
506 throw IException(IException::Programmer, mess, _FILEINFO_);
507 }
508
509 return;
510 }
511
512
526 // Initialize ray
527 RTCMultiHitRay ray;
528 ray.ray.org_x = 0.0;
529 ray.ray.org_y = 0.0;
530 ray.ray.org_z = 0.0;
531
532 // Convert the lat, lon to a unit look direction
533 double latAngle = lat.radians();
534 double lonAngle = lon.radians();
535 ray.ray.dir_x = cos(latAngle) * cos(lonAngle);
536 ray.ray.dir_y = cos(latAngle) * sin(lonAngle);
537 ray.ray.dir_z = sin(latAngle);
538
539 // Set the ray's length to extend to the scene boundary
540 ray.ray.tfar = m_targetShape->maximumSceneDistance();
541
542 return (ray);
543 }
544
545
556 // Setup everything but the direction component
557 RTCMultiHitRay ray;
558 ray.ray.org_x = 0.0;
559 ray.ray.org_y = 0.0;
560 ray.ray.org_z = 0.0;
561 ray.ray.tnear = 0.0;
562 ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; // instance
563 ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
564 ray.hit.primID = RTC_INVALID_GEOMETRY_ID; // primitive id (triangle id)
565 ray.ray.mask = 0xFFFFFFFF;
566 ray.lastHit = -1;
567
568 // Get the vector from the origin to the surface point
569 std::vector<double> surfVect(3);
570 surfpt.ToNaifArray( &surfVect[0] );
571 LinearAlgebra::Vector direction = LinearAlgebra::vector( surfVect[0],
572 surfVect[1],
573 surfVect[2] );
574
575 // Normalize the vector and store it in the ray
576 direction = LinearAlgebra::normalize(direction);
577 ray.ray.dir_x = direction[0];
578 ray.ray.dir_y = direction[1];
579 ray.ray.dir_z = direction[2];
580
581 // Extend the ray to the surface point
582 ray.ray.tfar = surfpt.GetLocalRadius().kilometers();
583 return (ray);
584 }
585
586
602 LinearAlgebra::Vector &observer) {
603 int hitCount = ray.lastHit + 1;
604 // Container that holds the hit (x, y, z) and distance from the origin
605 // QMap sorts based upon the key, distance, so this handles sorting hits.
607 for (int i = 0 ; i < hitCount ; i++) {
608 RayHitInformation hitInfo = m_targetShape->getHitInformation( ray, i );
609 hitsMap.insert( LinearAlgebra::magnitude(observer - hitInfo.intersection), hitInfo );
610 }
611
612 // Return sorted vector of hits
613 return ( QVector< RayHitInformation >::fromList( hitsMap.values() ) );
614 }
615
616
626 return m_tolerance;
627 }
628
629
638 void EmbreeShapeModel::setTolerance(const double &tolerance) {
639 m_tolerance = tolerance;
640 }
641}; // namespace Isis
double radians() const
Convert an angle to a double.
Definition Angle.h:226
Distance measurement, usually in meters.
Definition Distance.h:34
double kilometers() const
Get the distance in kilometers.
Definition Distance.cpp:106
@ Kilometers
The distance is being specified in kilometers.
Definition Distance.h:45
EmbreeTargetManager * m_targetManager
!< The target body and Embree objects for intersection.
virtual bool isVisibleFrom(const std::vector< double > observerPos, const std::vector< double > lookDirection)
Check if the current internalized surface point is visible from an observer position and look directi...
RTCMultiHitRay pointToRay(const SurfacePoint &point) const
Given a surface point, create a ray that goes from the origin of the target to the surface point.
virtual bool intersectSurface(std::vector< double > observerPos, std::vector< double > lookDirection)
This method computes an intercept point given an observer location and look direction using the Embre...
virtual Distance localRadius(const Latitude &lat, const Longitude &lon)
Determine radius at a given lat/lon grid point.
virtual void clearSurfacePoint()
Flag that the ShapeModel does not have a surface point or normal.
void setTolerance(const double &tolerance)
Set the tolerance used when checking if the stored surface point is visible.
QString m_shapeFile
!< Tolerance for checking visibility.
RTCMultiHitRay latlonToRay(const Latitude &lat, const Longitude &lon) const
Given a latitude and longitude, create a ray that goes from the origin of the target through that lat...
virtual ~EmbreeShapeModel()
Destructor that notifies the target shape manager that the target shape is no longer in use.
void updateIntersection(const RayHitInformation hitInfo)
Update the ShapeModel given an intersection and normal.
double getTolerance() const
Get the tolerance used when checking if the stored surface point is visible.
double m_tolerance
!< This manages EmbreeTargetShapes to allow for sharing of them between EmbreeShapeModels and deletes...
virtual bool isDEM() const
Indicates that this shape model is not from a DEM.
QVector< RayHitInformation > sortHits(RTCMultiHitRay &ray, LinearAlgebra::Vector &observer)
Sort all intersections by a ray based on distance to a point.
virtual void calculateLocalNormal(QVector< double * > cornerNeighborPoints)
Compute the normal for a local region of surface points.
EmbreeShapeModel()
Default constructor sets type to a TIN.
Class for managing the construction and destruction of EmbreeTargetShapes.
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
static Vector vector(double v0, double v1, double v2)
Constructs a 3 dimensional vector with the given component values.
static double magnitude(const Vector &vector)
Computes the magnitude (i.e., the length) of the given vector using the Euclidean norm (L2 norm).
boost::numeric::ublas::vector< double > Vector
Definition for an Isis::LinearAlgebra::Vector of doubles.
static Vector normalize(const Vector &vector)
Returns a unit vector that is codirectional with the given vector by dividing each component of the v...
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
virtual void clearSurfacePoint()
Clears or resets the current surface point.
void setHasNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a surface normal.
bool hasIntersection()
Returns intersection status.
void setHasIntersection(bool b)
Sets the flag to indicate whether this ShapeModel has an intersection.
void setLocalNormal(const std::vector< double >)
Sets the local normal for the currect intersection point.
virtual SurfacePoint * surfaceIntersection() const
Returns the surface intersection for this ShapeModel.
virtual void setSurfacePoint(const SurfacePoint &surfacePoint)
Set surface intersection point.
void setHasLocalNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a local normal.
ShapeModel()
Default constructor creates ShapeModel object, initializing name to an empty string,...
void setName(QString name)
Sets the shape name.
This class defines a body-fixed surface point.
void ToNaifArray(double naifOutput[3]) const
A naif array is a c-style array of size 3.
void FromNaifArray(const double naifValues[3])
A naif array is a c-style array of size 3.
Distance GetLocalRadius() const
Return the radius of the surface point.
This class is used to create and store valid Isis targets.
Definition Target.h:63
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.
Struct for capturing multiple intersections when using embree::rtcintersectscene.
int lastHit
Index of the last hit in the hit containers.
Struct for capturing occluded plates when using embree::rtcintersectscene.
unsigned ignorePrimID
IDs of the primitives (trinagles) which should be ignored.
Container that holds the body fixed intersection point and unit surface normal for a hit.
LinearAlgebra::Vector intersection
The (x, y, z) intersection location.
LinearAlgebra::Vector surfaceNormal
The unit surface normal vector at the intersection.