USGS

Isis 3.0 Object Programmers' Reference

Home

TriangularPlate.cpp
Go to the documentation of this file.
1 
24 #include "TriangularPlate.h"
25 
26 #include <string>
27 #include <vector>
28 #include <numeric>
29 
30 #include <QtGlobal>
31 
32 #include "AbstractPlate.h"
33 #include "Angle.h"
34 #include "Distance.h"
35 #include "Intercept.h"
36 #include "IException.h"
37 #include "IString.h"
38 #include "Latitude.h"
39 #include "Longitude.h"
40 #include "NaifDskApi.h"
41 #include "SurfacePoint.h"
42 
43 using namespace std;
44 
45 namespace Isis {
46 
48  // no need to implement this method since it is private and never called
49  // within this class
50  // TriangularPlate::TriangularPlate() : AbstractPlate(), m_plate(3, 3, 0.0) { }
51 
53  TriangularPlate::TriangularPlate(const NaifTriangle &plate, const int &plateId) :
54  AbstractPlate(), m_plate(plate.copy()),
55  m_plateId(plateId) { }
56 
57  TriangularPlate::~TriangularPlate() { }
58 
59  int TriangularPlate::id() const {
60  return m_plateId;
61  }
62 
63  QString TriangularPlate::name() const {
64  return "TriangularPlate";
65  }
66 
82  double radius = qMax(qMax(vnorm_c(m_plate[0]), vnorm_c(m_plate[1])),
83  vnorm_c(m_plate[2]));
84  return ( Distance(radius, Distance::Kilometers) );
85  }
86 
87  Distance TriangularPlate::minRadius() const {
88  double radius = qMin(qMin(vnorm_c(m_plate[0]), vnorm_c(m_plate[1])),
89  vnorm_c(m_plate[2]));
90  return ( Distance(radius, Distance::Kilometers) );
91  }
92 
102  double TriangularPlate::area() const {
103 
104  // Get the lengths of each side
105  NaifVector edge(3);
106  vsub_c(m_plate[1], m_plate[0], &edge[0]);
107  double s1 = vnorm_c(&edge[0]);
108 
109  vsub_c(m_plate[2], m_plate[0], &edge[0]);
110  double s2 = vnorm_c(&edge[0]);
111 
112  vsub_c(m_plate[2], m_plate[1], &edge[0]);
113  double s3 = vnorm_c(&edge[0]);
114 
115  // Heron's formula for area
116  double S = (s1 + s2 + s3) / 2.0;
117  double p_area = std::sqrt(S * (S - s1) * (S - s2) * (S - s3));
118 
119  return (p_area);
120  }
121 
133 
134  // Get the lengths of each side
135  NaifVector edge1(3);
136  vsub_c(m_plate[1], m_plate[0], &edge1[0]);
137 
138  NaifVector edge2(3);
139  vsub_c(m_plate[2], m_plate[0], &edge2[0]);
140 
141  NaifVector norm(3);
142  ucrss_c(&edge1[0], &edge2[0], &norm[0]);
143 
144  return (norm);
145  }
146 
147  NaifVector TriangularPlate::center() const {
148  double third(0.33333333333333331);
149  NaifVector midPt(3);
150  vlcom3_c(third, m_plate[0], third, m_plate[1], third, m_plate[2], &midPt[0]);
151  return (midPt);
152  }
153 
171  // Get two sides
172  NaifVector norm(normal());
173  double sepang = vsep_c(&norm[0], &raydir[0]);
174  return ( Angle(sepang, Angle::Radians) );
175  }
176 
194  const NaifVector &raydir) const {
196  return (findPlateIntercept(vertex, raydir, point));
197  }
198 
216  const Longitude &lon) const {
217 
218  // Extend the maximum height of the plate to a resonable distance
219  double maxrad = maxRadius().kilometers() * 1.5;
220 
221  // Create a surface point above the highest plate vertex
222  SurfacePoint point(lat, lon, Distance(maxrad, Distance::Kilometers));
223  NaifVertex obs(3);
224  point.ToNaifArray(&obs[0]);
225 
226  // Set the ray direction back toward the center of the body
227  NaifVector raydir(3);
228  vminus_c(&obs[0], &raydir[0]);
229 
230  // Determine where the point/ray intercepts the plate
231  NaifVertex xpt;
232  return (findPlateIntercept(obs, raydir, xpt));
233  }
234 
255  const Longitude &lon) const {
256  // Extend the maximum height of the plate
257  double maxrad = maxRadius().kilometers() * 1.5;
258 
259  // Create a surface point 1.5 times above the highest plate vertex
260  SurfacePoint point(lat, lon, Distance(maxrad, Distance::Kilometers));
261  NaifVertex obs(3);
262  point.ToNaifArray(&obs[0]);
263 
264  // Set the ray direction back toward the center of the body
265  NaifVector raydir(3);
266  vminus_c(&obs[0], &raydir[0]);
267 
268  // Determine if the point/ray intercepts the plate
269  NaifVertex xpt;
270  if ( !findPlateIntercept(obs, raydir, xpt) ) return (0);
271 
272  // Construct the intercept point and return it
273  SurfacePoint *ipoint(new SurfacePoint());
274  ipoint->FromNaifArray(&xpt[0]);
275  return (ipoint);
276  }
277 
278 
298  const NaifVector &raydir) const {
300  if ( !findPlateIntercept(vertex, raydir, point) ) return (0);
301 
302  // Got a valid intercept. Construct it and return
303  SurfacePoint *xpt = new SurfacePoint();
304  xpt->FromNaifArray(&point[0]);
305  return (new Intercept(vertex, raydir, xpt, clone()));
306  }
307 
308 
324  NaifVertex vec(3);
325  if ( (v < 0) || (v > 2) ) {
326  QString msg = "Unable to get TriangularPlate vertex for index ["
327  + toString(v) + "]. Valid index range is 0-2.";
329  }
330  for ( int i = 0 ; i < 3 ; i++ ) {
331  vec[i] = m_plate[v][i];
332  }
333  return (vec);
334  }
335 
336 
351  return (new TriangularPlate(m_plate, m_plateId));
352  }
353 
375  const NaifVector &raydir,
376  NaifVertex &point) const {
377 
378  // Construct three edges of the solid tehtrahderal between plate and observer
379  NaifVector e1(3), e2(3), e3(3);
380  vsub_c(m_plate[0], &obs[0], &e1[0]);
381  vsub_c(m_plate[1], &obs[0], &e2[0]);
382  vsub_c(m_plate[2], &obs[0], &e3[0]);
383 
384  // Test to see if the ray direction and plate normal are perpendicular
385  NaifVector tnorm12(3);
386  vcrss_c(&e1[0], &e2[0], &tnorm12[0]);
387  double tdot12 = vdot_c(&raydir[0], &tnorm12[0]);
388  double en = vdot_c(&e3[0], &tnorm12[0]);
389 
390  // Check for e3 perpendicular to plate normal. If true, e3 is a linear
391  // combination of e1 and e2.
392  if ( qFuzzyCompare(en+1.0, 1.0) ) return (false);
393 
394  // Check if raydir and e3 are in same half space
395  if ( (en > 0.0) && (tdot12 < 0.0) ) return (false);
396  if ( (en < 0.0) && (tdot12 > 0.0) ) return (false);
397 
398  // Check that raydir and e1 are on the same side of the plane spanned by e2
399  // and e3.
400  NaifVector tnorm23(3);
401  vcrss_c(&e2[0], &e3[0], &tnorm23[0]);
402  double tdot23 = vdot_c(&raydir[0], &tnorm23[0]);
403 
404  // Check if raydir and e3 are in same halfspace
405  if ( (en > 0.0) && (tdot23 < 0.0) ) return (false);
406  if ( (en < 0.0) && (tdot23 > 0.0) ) return (false);
407 
408  // Finally check that raydir and e2 are in the same half space bounded by e3
409  // and e2.
410  NaifVector tnorm31(3);
411  vcrss_c(&e3[0], &e1[0], &tnorm31[0]);
412  double tdot31 = vdot_c(&raydir[0], &tnorm31[0]);
413 
414  // Check if raydir and e2 are in same halfspace
415  if ( (en > 0.0) && (tdot31 < 0.0) ) return (false);
416  if ( (en < 0.0) && (tdot31 > 0.0) ) return (false);
417 
418  // Ok, we know raydir intersects the plate. Compute the intercept point if
419  // the denominator is not 0.
420  double denom = tdot12 + tdot23 + tdot31;
421 
422  // NOTE: If we have gotten this far in the method,
423  // we have checked that en != 0
424  // if en < 0, then tdot12 <= 0, tdot23 <= 0 and tdot31 <= 0
425  // if en > 0, then tdot12 >= 0, tdot23 >= 0 and tdot31 >= 0
426  // So, in order for the denominator to be 0, then it must be that
427  // tdot12 == tdot23 == tdot31 == 0
428  if ( qFuzzyCompare(denom+1.0, 1.0) ) return (false);
429 
430  double scale = en / denom;
431  NaifVertex xpt(3);
432  vlcom_c(1.0, &obs[0], scale, &raydir[0], &xpt[0]);
433  point = xpt;
434  return (true);
435  }
436 
437 } // namespace Isis