Isis 3 Programmer Reference
EmbreeShapeModel.cpp
Go to the documentation of this file.
1 
25 #include "EmbreeShapeModel.h"
26 
27 #include <numeric>
28 
29 #include <QtGlobal>
30 #include <QList>
31 
32 #include "IException.h"
33 #include "IString.h"
34 #include "Latitude.h"
35 #include "Longitude.h"
36 #include "NaifStatus.h"
37 #include "Pvl.h"
38 #include "ShapeModel.h"
39 #include "Target.h"
40 
41 
42 using namespace std;
43 
44 namespace Isis {
45 
49  EmbreeShapeModel::EmbreeShapeModel()
50  : ShapeModel(),
51  m_targetShape(0),
52  m_targetManager(0),
53  m_tolerance(DBL_MAX),
54  m_shapeFile("") {
55  // defaults for ShapeModel parent class include:
56  // name = empty string
57  // surfacePoint = null sp
58  // hasIntersection = false
59  // hasNormal = false
60  // normal = (0,0,0)
61  // hasEllipsoidIntersection = false
62  setName("Embree");
63  }
64 
65 
79  EmbreeTargetManager *targetManager)
80  : ShapeModel(target),
81  m_targetShape(0),
82  m_targetManager(targetManager),
83  m_tolerance(DBL_MAX),
84  m_shapeFile("") {
85 
86  // defaults for ShapeModel parent class include:
87  // name = empty string
88  // surfacePoint = null sp
89  // hasIntersection = false
90  // hasNormal = false
91  // normal = (0,0,0)
92  // hasEllipsoidIntersection = false
93 
94  setName("Embree"); // Really is used as type in the system at present!
95 
96  PvlGroup &kernels = pvl.findGroup("Kernels", Pvl::Traverse);
97 
98  if (kernels.hasKeyword("ElevationModel")) {
99  m_shapeFile = (QString) kernels["ElevationModel"];
100  }
101  else { // if (kernels.hasKeyword("ShapeModel")) {
102  m_shapeFile = (QString) kernels["ShapeModel"];
103  }
104 
105  try {
106  // Request the EmbreeTargetShape from the manager
107  // If the shapefile is being used by something else this will get a pointer
108  // to the same target shape, otherwise it creates a new one.
109  m_targetShape = m_targetManager->create(m_shapeFile);
110  }
111  catch(IException &e) {
112  QString msg = "Cannot create a EmbreeShape from " + m_shapeFile;
113  throw IException(e, IException::User, msg, _FILEINFO_);
114  }
115  }
116 
117 
125  EmbreeShapeModel::EmbreeShapeModel(Target *target, const QString &shapefile,
126  EmbreeTargetManager *targetManager)
127  : ShapeModel(target),
128  m_targetShape(0),
129  m_targetManager(targetManager),
130  m_tolerance(DBL_MAX),
131  m_shapeFile(shapefile) {
132 
133  // defaults for ShapeModel parent class include:
134  // name = empty string
135  // surfacePoint = null sp
136  // hasIntersection = false
137  // hasNormal = false
138  // normal = (0,0,0)
139  // hasEllipsoidIntersection = false
140 
141  setName("Embree"); // Really is used as type in the system at present!
142 
143  try {
144  // Request the EmbreeTargetShape from the manager
145  // If the shapefile is being used by something else this will get a pointer
146  // to the same target shape, otherwise it creates a new one.
147  m_targetShape = m_targetManager->create(m_shapeFile);
148  }
149  catch(IException &e) {
150  QString msg = "Cannot create a EmbreeShape from " + m_shapeFile;
151  throw IException(e, IException::User, msg, _FILEINFO_);
152  }
153  }
154 
155 
163  if ( m_targetManager && !m_shapeFile.isEmpty() ) {
165  }
166  }
167 
168 
178  bool EmbreeShapeModel::intersectSurface(std::vector<double> observerPos,
179  std::vector<double> lookDirection) {
180  // Remove any previous intersection
182 
183  // Create a ray from the observer in the look direction
184  RTCMultiHitRay ray(observerPos, lookDirection);
185 
186  m_targetShape->intersectRay(ray);
187 
188  // If nothing was hit
189  if (ray.lastHit < 0) {
190  setHasIntersection(false);
191  }
192  else {
193  // Get the intersection point and the surface normal
194  RayHitInformation hitInfo = m_targetShape->getHitInformation(ray, 0);
195 
196  // Update the surface point and surface normal
197  updateIntersection(hitInfo);
198  }
199 
200  return hasIntersection();
201  }
202 
203 
224  const std::vector<double> &observerPos,
225  const bool &backCheck) {
226  // Remove any previous intersection
228 
229  // Create a ray from the origin through the surface point
230  RTCMultiHitRay ray = latlonToRay(lat,lon);
231 
232  m_targetShape->intersectRay(ray);
233 
234  // If no intersections (unlikely for this case), we are done!
235  if ( ray.lastHit < 0 ) {
236  return ( false );
237  }
238  LinearAlgebra::Vector observer = LinearAlgebra::vector(observerPos[0],
239  observerPos[1],
240  observerPos[2]);
241 
242  // Sorts hits based on distance to the observer
243  QVector<RayHitInformation> hits = sortHits(ray, observer);
244 
245  // If desired, check occlusion
246  if ( backCheck ) {
247  for (int i = 0 ; i < hits.size() ; i++) {
248  LinearAlgebra::Vector obsToIntersection = hits[i].intersection - observer;
249  LinearAlgebra::Vector lookVector = LinearAlgebra::normalize(obsToIntersection);
250 
251  // Cast a ray from the observer to the intersection and check if it is occluded
252  RTCOcclusionRay obsRay;
253  obsRay.org[0] = observerPos[0];
254  obsRay.org[1] = observerPos[1];
255  obsRay.org[2] = observerPos[2];
256  obsRay.dir[0] = lookVector[0];
257  obsRay.dir[1] = lookVector[1];
258  obsRay.dir[2] = lookVector[2];
259  obsRay.tnear = 0.0;
260  obsRay.tfar = LinearAlgebra::magnitude(obsToIntersection) - 0.0005;
261  obsRay.instID = RTC_INVALID_GEOMETRY_ID;
262  obsRay.geomID = RTC_INVALID_GEOMETRY_ID;
263  obsRay.primID = RTC_INVALID_GEOMETRY_ID;
264  obsRay.mask = 0xFFFFFFFF;
265  obsRay.ignorePrimID = hits[i].primID;
266 
267  // If the intersection point is not occluded,
268  // then it is the closest intersection to the oberserver.
269  if ( !m_targetShape->isOccluded(obsRay) ) {
270  updateIntersection( hits[i] );
271  break;
272  }
273  }
274  }
275  else {
276  // If not testing for occlusion, take the hit closest to the observer
277  updateIntersection( hits[0] );
278  }
279 
280  return ( hasIntersection() );
281  }
282 
283 
302  const std::vector<double> &observerPos,
303  const bool &backCheck) {
304  // Remove any previous intersection
306 
307  // Set up for finding all rays along origin vector through lat/lon surface point
308  RTCMultiHitRay ray = pointToRay(surfpt);
309 
310  // Extend the ray to be 1.5 times the length of the SurfacePoint's radius
311  ray.tfar *= 1.5;
312 
313  m_targetShape->intersectRay(ray);
314 
315  // If no intersections (unlikely for this case), we are done!
316  if ( ray.lastHit < 0 ) {
317  return ( false );
318  }
319  // Convert the observer to a LinearAlgebra vector for occlusion testing
320  LinearAlgebra::Vector observer = LinearAlgebra::vector(observerPos[0],
321  observerPos[1],
322  observerPos[2]);
323 
324  // Convert the surface point to a LinearAlgebra vector for sorting hits
325  LinearAlgebra::Vector surfPoint(3);
326  surfpt.ToNaifArray( &surfPoint[0] );
327 
328  // Sorts hits based on distance to the surface point
329  QVector< RayHitInformation > hits = sortHits(ray, surfPoint);
330 
331  // If desired, check occlusion
332  if ( backCheck ) {
333  for (int i = 0 ; i < hits.size() ; i++) {
334  LinearAlgebra::Vector obsToIntersection = hits[i].intersection - observer;
335  LinearAlgebra::Vector lookVector = LinearAlgebra::normalize(obsToIntersection);
336 
337  // Cast a ray from the observer to the intersection and check if it is occluded
338  RTCOcclusionRay obsRay;
339  obsRay.org[0] = observerPos[0];
340  obsRay.org[1] = observerPos[1];
341  obsRay.org[2] = observerPos[2];
342  obsRay.dir[0] = lookVector[0];
343  obsRay.dir[1] = lookVector[1];
344  obsRay.dir[2] = lookVector[2];
345  obsRay.tnear = 0.0;
346  obsRay.tfar = LinearAlgebra::magnitude(obsToIntersection);
347  obsRay.instID = RTC_INVALID_GEOMETRY_ID;
348  obsRay.geomID = RTC_INVALID_GEOMETRY_ID;
349  obsRay.primID = RTC_INVALID_GEOMETRY_ID;
350  obsRay.mask = 0xFFFFFFFF;
351  obsRay.ignorePrimID = hits[i].primID;
352 
353  // If the intersection point is no occluded,
354  // then it is the closest intersection to the oberserver.
355  if ( !m_targetShape->isOccluded(obsRay) ) {
356  updateIntersection( hits[i] );
357  break;
358  }
359  }
360  }
361  else {
362  // If not testing for occlusion, take the hit closest to the surface point
363  updateIntersection( hits[0] );
364  }
365 
366  return ( hasIntersection() );
367  }
368 
369 
376  // Flag that there is an intersection
377  setHasIntersection(true);
378 
379  // Create the surfacepoint
380  SurfacePoint intersectPoint;
381  std::vector<double> intersectArray(3);
382  std::copy( hitInfo.intersection.data().begin(),
383  hitInfo.intersection.data().end(),
384  intersectArray.begin() );
385  intersectPoint.FromNaifArray( &intersectArray[0] );
386  setSurfacePoint(intersectPoint);
387 
388  // Save the surface normal
389  setNormal( hitInfo.surfaceNormal[0],
390  hitInfo.surfaceNormal[1],
391  hitInfo.surfaceNormal[2] );
392  }
393 
394 
403  setHasNormal(false);
404  return;
405  }
406 
407 
420  const Longitude &lon) {
421 
422  // Create a ray from the origin to the surface point
423  RTCMultiHitRay ray = latlonToRay(lat,lon);
424 
425  // Extend the ray to 2.5 times the maximum radius
426  ray.tfar *= 2.5;
427 
428  m_targetShape->intersectRay(ray);
429 
430  // If no intersections (unlikely for this case), we are done!
431  if ( ray.lastHit < 0 ) {
432  return ( Distance() );
433  }
434  // Otherwise, get the first intersection
435  RayHitInformation hitInfo = m_targetShape->getHitInformation( ray, 0 );
436 
437  // Return the distance to the intersection
440  }
441 
442 
450  bool EmbreeShapeModel::isDEM() const {
451  return false;
452  }
453 
454 
465  bool EmbreeShapeModel::isVisibleFrom(const std::vector<double> observerPos,
466  const std::vector<double> lookDirection) {
467  //TODO check if there is a saved intersection
468  // Create a ray from the observer in the look direction
469  RTCMultiHitRay ray(observerPos, lookDirection);
470 
471  m_targetShape->intersectRay(ray);
472 
473  // If nothing was hit, something went really wrong. Just return false.
474  if (ray.lastHit < 0) {
475  return false;
476  }
477  else {
478  // Get the new intersection point
479  RayHitInformation hitInfo = m_targetShape->getHitInformation(ray, 0);
480 
481  // Check the distance between the new intersection and the saved intersection
482  std::vector<double> intersectVect(3);
483  surfaceIntersection()->ToNaifArray( &intersectVect[0] );
484  LinearAlgebra::Vector oldIntersection = LinearAlgebra::vector( intersectVect[0],
485  intersectVect[1],
486  intersectVect[2] );
487  return ( LinearAlgebra::magnitude(oldIntersection - hitInfo.intersection) < getTolerance() );
488  }
489  }
490 
491 
518  // Sanity check
519  if ( !hasIntersection() ) { // hasIntersection() <==> hasNormall()
520  QString mess = "Intercept point does not exist - cannot provide normal vector";
522  }
523 
524  return;
525  }
526 
527 
532  // ShapeModel (parent class) throws error if no intersection
534  }
535 
536 
541  // ShapeModel (parent class) throws error if no intersection
542  setNormal(ellipsoidNormal().toStdVector());// this takes care of setHasNormal(true);
543  return;
544  }
545 
546 
562 
563  // Sanity check on state
564  if ( !hasIntersection() ) {
565  QString msg = "An intersection must be defined before computing the surface normal.";
567  }
568 
569  if ( !surfaceIntersection()->Valid() ) {
570  QString msg = "The surface point intersection must be valid to compute the surface normal.";
572  }
573 
574  if (!hasValidTarget()) {
575  QString msg = "A valid target must be defined before computing the surface normal.";
577  }
578 
579  // Get the coordinates of the current surface point
580  SpiceDouble pB[3];
582 
583  // Get the body radii and compute the true normal of the ellipsoid
584  QVector<double> norm(3);
585  // need a case for target == NULL
588  surfnm_c(radii[0].kilometers(), radii[1].kilometers(), radii[2].kilometers(),
589  pB, &norm[0]);
591 
592  return (norm);
593  }
594 
595 
612  double EmbreeShapeModel::incidenceAngle(const std::vector<double> &illuminatorBodyFixedPosition) {
613 
614  // If there is already a normal save it, because it's probably the local normal
615  std::vector<double> localNormal;
616  bool hadNormal = hasNormal();
617  if ( hadNormal ) {
618  localNormal = normal();
619  }
620 
621  // Calculate the ellipsoid surface normal
623 
624  // Use ShapeModel to calculate the ellipsoid incidence angle
625  double ellipsoidEmission = ShapeModel::incidenceAngle(illuminatorBodyFixedPosition);
626 
627  // If there's a saved normal, reset it
628  if ( hadNormal ) {
629  setNormal(localNormal);
630  }
631 
632  // Return the ellipsoid incidence angle
633  return ellipsoidEmission;
634  }
635 
636 
650  // Initialize ray
651  RTCMultiHitRay ray;
652  ray.org[0] = 0.0;
653  ray.org[1] = 0.0;
654  ray.org[2] = 0.0;
655 
656  // Convert the lat, lon to a unit look direction
657  double latAngle = lat.radians();
658  double lonAngle = lon.radians();
659  ray.dir[0] = cos(latAngle) * cos(lonAngle);
660  ray.dir[1] = cos(latAngle) * sin(lonAngle);
661  ray.dir[2] = sin(latAngle);
662 
663  // Set the ray's length to extend to the scene boundary
664  ray.tfar = m_targetShape->maximumSceneDistance();
665 
666  return (ray);
667  }
668 
669 
680  // Setup everything but the direction component
681  RTCMultiHitRay ray;
682  ray.org[0] = 0.0;
683  ray.org[1] = 0.0;
684  ray.org[2] = 0.0;
685  ray.tnear = 0.0;
686  ray.instID = RTC_INVALID_GEOMETRY_ID; // instance
687  ray.geomID = RTC_INVALID_GEOMETRY_ID;
688  ray.primID = RTC_INVALID_GEOMETRY_ID; // primitive id (triangle id)
689  ray.mask = 0xFFFFFFFF;
690  ray.lastHit = -1;
691 
692  // Get the vector from the origin to the surface point
693  std::vector<double> surfVect(3);
694  surfpt.ToNaifArray( &surfVect[0] );
695  LinearAlgebra::Vector direction = LinearAlgebra::vector( surfVect[0],
696  surfVect[1],
697  surfVect[2] );
698 
699  // Normalize the vector and store it in the ray
700  direction = LinearAlgebra::normalize(direction);
701  ray.dir[0] = direction[0];
702  ray.dir[1] = direction[1];
703  ray.dir[2] = direction[2];
704 
705  // Extend the ray to the surface point
706  ray.tfar = surfpt.GetLocalRadius().kilometers();
707  return (ray);
708  }
709 
710 
726  LinearAlgebra::Vector &observer) {
727  int hitCount = ray.lastHit + 1;
728  // Container that holds the hit (x, y, z) and distance from the origin
729  // QMap sorts based upon the key, distance, so this handles sorting hits.
731  for (int i = 0 ; i < hitCount ; i++) {
732  RayHitInformation hitInfo = m_targetShape->getHitInformation( ray, i );
733  hitsMap.insert( LinearAlgebra::magnitude(observer - hitInfo.intersection), hitInfo );
734  }
735 
736  // Return sorted vector of hits
737  return ( QVector< RayHitInformation >::fromList( hitsMap.values() ) );
738  }
739 
740 
750  return m_tolerance;
751  }
752 
753 
762  void EmbreeShapeModel::setTolerance(const double &tolerance) {
763  m_tolerance = tolerance;
764  }
765 }; // namespace Isis
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:148
Container that holds the body fixed intersection point and unit surface normal for a hit...
std::vector< double > normal()
Returns the local surface normal at the current intersection point.
Definition: ShapeModel.cpp:395
static Vector vector(double v0, double v1, double v2)
Constructs a 3 dimensional vector with the given component values.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
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.
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
bool hasValidTarget() const
Returns the status of the target.
Definition: ShapeModel.cpp:443
QVector< RayHitInformation > sortHits(RTCMultiHitRay &ray, LinearAlgebra::Vector &observer)
Sort all intersections by a ray based on distance to a point.
virtual void calculateSurfaceNormal()
Return the surface normal of the ellipsoid.
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...
void free(const QString &shapeFile)
Notify the manager that an EmbreeTargetShape is no longer in use.
virtual void calculateLocalNormal(QVector< double *> cornerNeighborPoints)
Compute the normal for a local region of surface points.
void setNormal(const std::vector< double >)
Sets the normal for the currect intersection point.
Definition: ShapeModel.cpp:481
double radians() const
Convert an angle to a double.
Definition: Angle.h:243
virtual ~EmbreeShapeModel()
Destructor that notifies the target shape manager that the target shape is no longer in use...
bool hasIntersection()
Returns intersection status.
Definition: ShapeModel.cpp:362
double m_tolerance
!< This manages EmbreeTargetShapes to allow for sharing of them between EmbreeShapeModels and deletes...
static double magnitude(const Vector &vector)
Computes the magnitude (i.e., the length) of the given vector using the Euclidean norm (L2 norm)...
Namespace for the standard library.
void setTolerance(const double &tolerance)
Set the tolerance used when checking if the stored surface point is visible.
double maximumSceneDistance() const
Return the maximum distance within the scene.
Struct for capturing multiple intersections when using embree::rtcintersectscene. ...
QString m_shapeFile
!< Tolerance for checking visibility.
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:63
The distance is being specified in kilometers.
Definition: Distance.h:58
Search child objects.
Definition: PvlObject.h:170
SurfacePoint * surfaceIntersection() const
Returns the surface intersection for this ShapeModel.
Definition: ShapeModel.cpp:352
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 error is for when a programmer made an API call that was illegal.
Definition: IException.h:162
EmbreeShapeModel()
Default constructor sets type to a TIN.
double kilometers() const
Get the distance in kilometers.
Definition: Distance.cpp:118
Distance measurement, usually in meters.
Definition: Distance.h:47
double getTolerance() const
Get the tolerance used when checking if the stored surface point is visible.
Class for managing the construction and destruction of EmbreeTargetShapes.
std::vector< Distance > targetRadii() const
Returns the radii of the body in km.
Definition: ShapeModel.cpp:459
LinearAlgebra::Vector surfaceNormal
The unit surface normal vector at the intersection.
void setHasIntersection(bool b)
Sets the flag to indicate whether this ShapeModel has an intersection.
Definition: ShapeModel.cpp:548
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:52
boost::numeric::ublas::vector< double > Vector
Definition for an Isis::LinearAlgebra::Vector of doubles.
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...
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
unsigned ignorePrimID
IDs of the primitives (trinagles) which should be ignored.
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:142
virtual double incidenceAngle(const std::vector< double > &uB)
Computes and returns incidence angle, in degrees, given the illuminator position. ...
Definition: ShapeModel.cpp:226
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...
void intersectRay(RTCMultiHitRay &ray)
Intersect a ray with the target shape.
Container for cube-like labels.
Definition: Pvl.h:135
virtual void clearSurfacePoint()
Clears or resets the current surface point.
Definition: ShapeModel.cpp:380
LinearAlgebra::Vector intersection
The (x, y, z) intersection location.
This class is used to create and store valid Isis3 targets.
Definition: Target.h:76
Define shapes and provide utilities for Isis3 targets.
Definition: ShapeModel.h:78
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
virtual bool isDEM() const
Indicates that this shape model is not from a DEM.
RayHitInformation getHitInformation(RTCMultiHitRay &ray, int hitIndex)
Extract the intersection point and unit surface normal from an RTCMultiHitRay that has been intersect...
Struct for capturing occluded plates when using embree::rtcintersectscene.
void ToNaifArray(double naifOutput[3]) const
A naif array is a c-style array of size 3.
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...
void FromNaifArray(const double naifValues[3])
A naif array is a c-style array of size 3.
virtual void setSurfacePoint(const SurfacePoint &surfacePoint)
Set surface intersection point.
Definition: ShapeModel.cpp:559
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Definition: NaifStatus.cpp:43
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
void setName(QString name)
Sets the shape name.
Definition: ShapeModel.cpp:526
void setHasNormal(bool status)
Sets the flag to indicate whether this ShapeModel has a surface normal.
Definition: ShapeModel.cpp:575
virtual void calculateDefaultNormal()
Return the surface normal of the ellipsoid as the default.
QVector< double > ellipsoidNormal()
Compute the true surface normal vector of an ellipsoid.
int lastHit
Index of the last hit in the hit containers.
virtual double incidenceAngle(const std::vector< double > &uB)
Computes and returns incidence angle, in degrees, given the illuminator position. ...
bool isOccluded(RTCOcclusionRay &ray)
Check if a ray intersects the target body.
Distance GetLocalRadius() const
Return the radius of the surface point.
EmbreeTargetManager * m_targetManager
!< The target body and Embree objects for intersection.
void updateIntersection(const RayHitInformation hitInfo)
Update the ShapeModel given an intersection and normal.
bool hasNormal() const
Returns surface point normal status.
Definition: ShapeModel.cpp:372
EmbreeTargetShape * create(const QString &shapeFile)
Get a pointer to an EmbreeTargetShape containing the information from a shape file.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.