Isis 3 Programmer Reference
PixelFOV.cpp
1 #include "PixelFOV.h"
2 
3 #include <QDebug>
4 #include <QList>
5 #include <QPoint>
6 #include <QPointF>
7 #include <QScopedPointer>
8 
9 #include <geos/geom/CoordinateArraySequence.h>
10 #include <geos/geom/CoordinateSequence.h>
11 #include <geos/geom/LineString.h>
12 #include <geos/geom/MultiPolygon.h>
13 #include <geos/geom/Polygon.h>
14 
15 #include "Camera.h"
16 #include "CameraDistortionMap.h"
17 #include "PolygonTools.h"
18 
19 using namespace std;
20 
21 namespace Isis {
22 
27  PixelFOV::PixelFOV() {
28  }
29 
30 
35  PixelFOV::~PixelFOV() {
36  }
37 
38 
61  QList< QList<QPointF> > PixelFOV::latLonVertices(Camera &camera,
62  const double sample,
63  const double line,
64  const int numIfovs) const {
65 
66  // Output list
67  QList< QList<QPointF> > boundaryVertices;
68 
69  // Polygon pieces are sorted based on average longitude. lowerVertices contains pieces with
70  // average longitude less than 180. upperVertices contains the rest.
71  QList<QPointF> lowerVertices;
72  QList<QPointF> upperVertices;
73 
74 
75  if (numIfovs < 1) {
76  QString msg = "The number of instantaneous field of views must be a positive integer.";
77  throw IException(IException::Programmer, msg, _FILEINFO_);
78  }
79 
80  // If computing an instantaneous fov
81  if (numIfovs == 1) {
82 
83  camera.SetImage(line, sample);
84  boundaryVertices.append(instantaneousFov(camera));
85  return boundaryVertices;
86  }
87 
88  // If computing a full fov
89  else {
90 
91  // Collect the instantaneous fovs
92  double timeStep = 0.0;
93  try {
94  timeStep = camera.exposureDuration(line, sample)/(numIfovs - 1);
95  }
96  catch (IException &e) {
97  throw IException(e, IException::Unknown, "Unable to get FOV for full exposure.", _FILEINFO_);
98  }
99  for (int i = 0; i < numIfovs; i++) {
100  camera.SetImage(line, sample,
101  timeStep * i - camera.exposureDuration(line, sample)/2);
102  QList<QPointF> iFov = instantaneousFov(camera);
103 
104  // If the Ifov does not intersect the target move on
105  if (iFov.isEmpty()) {
106  break;
107  }
108 
109  // Determine if the Ifov needs to be split
110  bool crosses = false;
111  int numVerts = iFov.size();
112  for (int j = 0; j < numVerts - 1; j++) {
113  if (fabs(iFov[j].y() - iFov[j+1].y()) > 180.0) {
114  crosses = true;
115  }
116  }
117 
118  // If it needs to be split
119  if (crosses) {
120  QList< QList<QPointF> > splitIFov = splitIfov(iFov);
121 
122  // Sort the pieces based on average longitude.
123  for (int j = 0; j < splitIFov.size(); j++) {
124  double averageLong = 0;
125  int numSubVerts = splitIFov[j].size();
126  for (int k = 0; k < numSubVerts; k++) {
127  averageLong += splitIFov[j][k].y();
128  }
129  averageLong = averageLong / numSubVerts;
130  if (averageLong < 180) {
131  lowerVertices.append(splitIFov[j]);
132  }
133  else {
134  upperVertices.append(splitIFov[j]);
135  }
136  }
137  }
138 
139  // If it does not need to be split
140  else {
141  // Put the Ifov in the proper class
142  double averageLong = 0;
143  for (int j = 0; j < numVerts; j++) {
144  averageLong += iFov[j].y();
145  }
146  averageLong = averageLong / numVerts;
147  if (averageLong < 180) {
148  lowerVertices.append(iFov);
149  }
150  else {
151  upperVertices.append(iFov);
152  }
153  }
154  }
155  }
156 
157  // Compute convex hulls for the two sets of points and append to output list.
158  // If a set is empty then it is not output.
159  if (!lowerVertices.isEmpty()) {
160  boundaryVertices.append(envelope(lowerVertices));
161  }
162  if (!upperVertices.isEmpty()) {
163  boundaryVertices.append(envelope(upperVertices));
164  }
165 
166  return boundaryVertices;
167  }
168 
169 
182  QList<QPointF> PixelFOV::instantaneousFov(Camera &camera) const {
183 
184  QList<QPointF> vertices;
185 
186  QList<QPointF> offsets = camera.PixelIfovOffsets();
187  int numVertices = offsets.size();
188 
189  double saveLook[3];
190  double newLook[3];
191  double unitNewLook[3];
192  camera.LookDirection(saveLook);
193  double focalLength = camera.FocalLength();
194 
195  // For highly distorted instruments, take fpx, fpy (which are undistorted) convert to distorted,
196  // add offsets, undistort. Only need to worry about if distortion high on a pixel to pixel
197  // basis. If this is done, save samp/line and reset the camera (SetImage).
198  double scale = focalLength / saveLook[2];
199  for (int i = 0; i < numVertices; i++) {
200  double focalPlaneX = saveLook[0] * scale;
201  double focalPlaneY = saveLook[1] * scale;
202  focalPlaneX += offsets[i].x();
203  focalPlaneY += offsets[i].y();
204  newLook[0] = focalPlaneX;
205  newLook[1] = focalPlaneY;
206  newLook[2] = camera.DistortionMap()->UndistortedFocalPlaneZ();
207  vhat_c(newLook, unitNewLook);
208  if (camera.SetLookDirection(unitNewLook)) {
209  vertices.append(QPointF(camera.UniversalLatitude(), camera.UniversalLongitude()));
210  }
211  }
212  // Reset look direction back to center of pixel
213  camera.SetLookDirection(saveLook);
214  return vertices;
215  }
216 
217 
225  QList<QPointF> PixelFOV::envelope(QList<QPointF> vertices) const{
226 
227  //Put the vertices in a line string
228  QScopedPointer<geos::geom::CoordinateSequence> points(new geos::geom::CoordinateArraySequence());
229 
230  for (int i = 0; i < vertices.size(); i++) {
231  points->add(geos::geom::Coordinate(vertices[i].x(), vertices[i].y()));
232  }
233  QScopedPointer<geos::geom::LineString> pointString(Isis::globalFactory.createLineString(
234  points.take()));
235 
236  //Compute a convex hull for the line string
237  QScopedPointer<geos::geom::Geometry> boundingHull(pointString->convexHull());
238 
239  //Get the points
240  geos::geom::CoordinateSequence *boundingPoints = boundingHull->getCoordinates();
241 
242  QList<QPointF> boundingVertices;
243  for (unsigned int i = 0; i < boundingPoints->getSize(); i++) {
244  boundingVertices.append(QPointF(boundingPoints->getAt(i).x,boundingPoints->getAt(i).y));
245  }
246 
247  return boundingVertices;
248  }
249 
250 
262  QList< QList<QPointF> > PixelFOV::splitIfov(QList<QPointF> vertices) const{
263  // Create output list.
264  QList< QList<QPointF> > splitPoints;
265 
266  // Create a polygon to split.
267  QScopedPointer<geos::geom::CoordinateSequence> pts(new geos::geom::CoordinateArraySequence());
268  for (int i = 0; i < vertices.size(); i++) {
269  pts->add(geos::geom::Coordinate(vertices[i].y(), vertices[i].x()));
270  }
271  pts->add(geos::geom::Coordinate(vertices[0].y(), vertices[0].x()));
272  QScopedPointer<geos::geom::Polygon> originalPoly(Isis::globalFactory.createPolygon(
273  globalFactory.createLinearRing(pts.take()),
274  NULL));
275 
276  // Split the polygon
277  QScopedPointer<geos::geom::MultiPolygon> splitPolygons(
278  PolygonTools::SplitPolygonOn360(originalPoly.data()));
279 
280  // Extract the vertices coordinates.
281  QList< QList<QPointF> > splitVertices;
282  for (unsigned int i = 0; i < splitPolygons->getNumGeometries(); i++) {
283  QList<QPointF> subVertices;
284  // The following objects don't need to be deleted, as the splitPolygons object will
285  // delete them when it is deleted.
286  const geos::geom::Polygon *subPolygon =
287  dynamic_cast<const geos::geom::Polygon *>(splitPolygons->getGeometryN(i));
288  geos::geom::CoordinateSequence *subCoordinates = subPolygon->
289  getExteriorRing()->getCoordinates();
290  for (unsigned int j = 0; j < subCoordinates->getSize(); j++) {
291  subVertices.append(QPointF(subCoordinates->getAt(j).y,subCoordinates->getAt(j).x));
292  }
293 
294  // Put the vertices in the output list.
295  splitPoints.append(subVertices);
296 
297  }
298 
299  return splitPoints;
300  }
301 }
CameraDistortionMap * DistortionMap()
Returns a pointer to the CameraDistortionMap object.
Definition: Camera.cpp:2838
double UniversalLatitude() const
Returns the planetocentric latitude, in degrees, at the surface intersection point in the body fixed ...
Definition: Sensor.cpp:225
double UndistortedFocalPlaneZ() const
Gets the z-value in the undistorted focal plane coordinate system.
Namespace for the standard library.
bool SetLookDirection(const double v[3])
Sets the look direction of the spacecraft.
Definition: Sensor.cpp:156
bool SetImage(const double sample, const double line)
Sets the sample/line values of the image to get the lat/lon values.
Definition: Camera.cpp:170
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
double FocalLength() const
Returns the focal length.
Definition: Camera.cpp:2744
double UniversalLongitude() const
Returns the positive east, 0-360 domain longitude, in degrees, at the surface intersection point in t...
Definition: Sensor.cpp:248
void LookDirection(double v[3]) const
Returns the look direction in the camera coordinate system.
Definition: Sensor.cpp:538
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
virtual QList< QPointF > PixelIfovOffsets()
Returns the pixel ifov offsets from center of pixel, which defaults to the (pixel pitch * summing mod...
Definition: Camera.cpp:2767
virtual double exposureDuration() const
Return the exposure duration for the pixel that the camera is set to.
Definition: Camera.cpp:3075