Isis 3 Programmer Reference
PixelFOV.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "PixelFOV.h"
8
9#include <QDebug>
10#include <QList>
11#include <QPoint>
12#include <QPointF>
13#include <QScopedPointer>
14
15#include <geos/geom/CoordinateSequence.h>
16#include <geos/geom/CoordinateSequence.h>
17#include <geos/geom/LineString.h>
18#include <geos/geom/MultiPolygon.h>
19#include <geos/geom/Polygon.h>
20
21#include "Camera.h"
22#include "CameraDistortionMap.h"
23#include "PolygonTools.h"
24
25using namespace std;
26
27namespace Isis {
28
35
36
43
44
67 QList< QList<QPointF> > PixelFOV::latLonVertices(Camera &camera,
68 const double sample,
69 const double line,
70 const int numIfovs) const {
71
72 // Output list
73 QList< QList<QPointF> > boundaryVertices;
74
75 // Polygon pieces are sorted based on average longitude. lowerVertices contains pieces with
76 // average longitude less than 180. upperVertices contains the rest.
77 QList<QPointF> lowerVertices;
78 QList<QPointF> upperVertices;
79
80
81 if (numIfovs < 1) {
82 QString msg = "The number of instantaneous field of views must be a positive integer.";
83 throw IException(IException::Programmer, msg, _FILEINFO_);
84 }
85
86 // If computing an instantaneous fov
87 if (numIfovs == 1) {
88
89 camera.SetImage(line, sample);
90 boundaryVertices.append(instantaneousFov(camera));
91 return boundaryVertices;
92 }
93
94 // If computing a full fov
95 else {
96
97 // Collect the instantaneous fovs
98 double timeStep = 0.0;
99 try {
100 timeStep = camera.exposureDuration(line, sample)/(numIfovs - 1);
101 }
102 catch (IException &e) {
103 throw IException(e, IException::Unknown, "Unable to get FOV for full exposure.", _FILEINFO_);
104 }
105 for (int i = 0; i < numIfovs; i++) {
106 camera.SetImage(line, sample,
107 timeStep * i - camera.exposureDuration(line, sample)/2);
108 QList<QPointF> iFov = instantaneousFov(camera);
109
110 // If the Ifov does not intersect the target move on
111 if (iFov.isEmpty()) {
112 break;
113 }
114
115 // Determine if the Ifov needs to be split
116 bool crosses = false;
117 int numVerts = iFov.size();
118 for (int j = 0; j < numVerts - 1; j++) {
119 if (fabs(iFov[j].y() - iFov[j+1].y()) > 180.0) {
120 crosses = true;
121 }
122 }
123
124 // If it needs to be split
125 if (crosses) {
126 QList< QList<QPointF> > splitIFov = splitIfov(iFov);
127
128 // Sort the pieces based on average longitude.
129 for (int j = 0; j < splitIFov.size(); j++) {
130 double averageLong = 0;
131 int numSubVerts = splitIFov[j].size();
132 for (int k = 0; k < numSubVerts; k++) {
133 averageLong += splitIFov[j][k].y();
134 }
135 averageLong = averageLong / numSubVerts;
136 if (averageLong < 180) {
137 lowerVertices.append(splitIFov[j]);
138 }
139 else {
140 upperVertices.append(splitIFov[j]);
141 }
142 }
143 }
144
145 // If it does not need to be split
146 else {
147 // Put the Ifov in the proper class
148 double averageLong = 0;
149 for (int j = 0; j < numVerts; j++) {
150 averageLong += iFov[j].y();
151 }
152 averageLong = averageLong / numVerts;
153 if (averageLong < 180) {
154 lowerVertices.append(iFov);
155 }
156 else {
157 upperVertices.append(iFov);
158 }
159 }
160 }
161 }
162
163 // Compute convex hulls for the two sets of points and append to output list.
164 // If a set is empty then it is not output.
165 if (!lowerVertices.isEmpty()) {
166 boundaryVertices.append(envelope(lowerVertices));
167 }
168 if (!upperVertices.isEmpty()) {
169 boundaryVertices.append(envelope(upperVertices));
170 }
171
172 return boundaryVertices;
173 }
174
175
188 QList<QPointF> PixelFOV::instantaneousFov(Camera &camera) const {
189
190 QList<QPointF> vertices;
191
192 QList<QPointF> offsets = camera.PixelIfovOffsets();
193 int numVertices = offsets.size();
194
195 double saveLook[3];
196 double newLook[3];
197 double unitNewLook[3];
198 camera.LookDirection(saveLook);
199 double focalLength = camera.FocalLength();
200
201 // For highly distorted instruments, take fpx, fpy (which are undistorted) convert to distorted,
202 // add offsets, undistort. Only need to worry about if distortion high on a pixel to pixel
203 // basis. If this is done, save samp/line and reset the camera (SetImage).
204 double scale = focalLength / saveLook[2];
205 for (int i = 0; i < numVertices; i++) {
206 double focalPlaneX = saveLook[0] * scale;
207 double focalPlaneY = saveLook[1] * scale;
208 focalPlaneX += offsets[i].x();
209 focalPlaneY += offsets[i].y();
210 newLook[0] = focalPlaneX;
211 newLook[1] = focalPlaneY;
212 newLook[2] = camera.DistortionMap()->UndistortedFocalPlaneZ();
213 vhat_c(newLook, unitNewLook);
214 if (camera.SetLookDirection(unitNewLook)) {
215 vertices.append(QPointF(camera.UniversalLatitude(), camera.UniversalLongitude()));
216 }
217 }
218 // Reset look direction back to center of pixel
219 camera.SetLookDirection(saveLook);
220 return vertices;
221 }
222
223
231 QList<QPointF> PixelFOV::envelope(QList<QPointF> vertices) const{
232
233 //Put the vertices in a line string
234 QScopedPointer<geos::geom::CoordinateSequence> points(new geos::geom::CoordinateSequence());
235
236 for (int i = 0; i < vertices.size(); i++) {
237 points->add(geos::geom::Coordinate(vertices[i].x(), vertices[i].y()));
238 }
239 QScopedPointer<geos::geom::LineString> pointString(Isis::globalFactory->createLineString(
240 *points).release());
241
242 //Compute a convex hull for the line string
243 QScopedPointer<geos::geom::Geometry> boundingHull(pointString->convexHull().release());
244
245 //Get the points
246 geos::geom::CoordinateSequence *boundingPoints = boundingHull->getCoordinates().release();
247
248 QList<QPointF> boundingVertices;
249 for (unsigned int i = 0; i < boundingPoints->getSize(); i++) {
250 boundingVertices.append(QPointF(boundingPoints->getAt(i).x,boundingPoints->getAt(i).y));
251 }
252
253 return boundingVertices;
254 }
255
256
268 QList< QList<QPointF> > PixelFOV::splitIfov(QList<QPointF> vertices) const{
269 // Create output list.
270 QList< QList<QPointF> > splitPoints;
271
272 // Create a polygon to split.
273 QScopedPointer<geos::geom::CoordinateSequence> pts(new geos::geom::CoordinateSequence());
274 for (int i = 0; i < vertices.size(); i++) {
275 pts->add(geos::geom::Coordinate(vertices[i].y(), vertices[i].x()));
276 }
277 pts->add(geos::geom::Coordinate(vertices[0].y(), vertices[0].x()));
278 QScopedPointer<geos::geom::Polygon> originalPoly(Isis::globalFactory->createPolygon(
279 globalFactory->createLinearRing(*pts)).release());
280
281 // Split the polygon
282 QScopedPointer<geos::geom::MultiPolygon> splitPolygons(
283 PolygonTools::SplitPolygonOn360(originalPoly.data()));
284
285 // Extract the vertices coordinates.
286 QList< QList<QPointF> > splitVertices;
287 for (unsigned int i = 0; i < splitPolygons->getNumGeometries(); i++) {
288 QList<QPointF> subVertices;
289 // The following objects don't need to be deleted, as the splitPolygons object will
290 // delete them when it is deleted.
291 const geos::geom::Polygon *subPolygon =
292 dynamic_cast<const geos::geom::Polygon *>(splitPolygons->getGeometryN(i));
293 geos::geom::CoordinateSequence *subCoordinates = subPolygon->getExteriorRing()->getCoordinates().release();
294 for (unsigned int j = 0; j < subCoordinates->getSize(); j++) {
295 subVertices.append(QPointF(subCoordinates->getAt(j).y,subCoordinates->getAt(j).x));
296 }
297
298 // Put the vertices in the output list.
299 splitPoints.append(subVertices);
300
301 }
302
303 return splitPoints;
304 }
305}
double UndistortedFocalPlaneZ() const
Gets the z-value in the undistorted focal plane coordinate system.
virtual double exposureDuration() const
Return the exposure duration for the pixel that the camera is set to.
Definition Camera.cpp:3093
virtual 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:156
double FocalLength() const
Returns the focal length.
Definition Camera.cpp:2762
CameraDistortionMap * DistortionMap()
Returns a pointer to the CameraDistortionMap object.
Definition Camera.cpp:2856
virtual QList< QPointF > PixelIfovOffsets()
Returns the pixel ifov offsets from center of pixel, which defaults to the (pixel pitch * summing mod...
Definition Camera.cpp:2785
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
~PixelFOV()
Destroys a PixelFOV object/.
Definition PixelFOV.cpp:41
QList< QPointF > instantaneousFov(Camera &camera) const
Compute the instantaneous fov for the pixel and time that the input camera is set to.
Definition PixelFOV.cpp:188
QList< QList< QPointF > > splitIfov(QList< QPointF > vertices) const
Split an instantaneous field of view across the 360/0 boundary.
Definition PixelFOV.cpp:268
QList< QList< QPointF > > latLonVertices(Camera &camera, const double sample, const double line, const int numIfovs=1) const
Produces an fov for the given line sample.
Definition PixelFOV.cpp:67
PixelFOV()
Constructs an empty PixelFOV object.
Definition PixelFOV.cpp:33
QList< QPointF > envelope(QList< QPointF > vertices) const
Produces a list of boundary points for the convex hull containing the input vertices.
Definition PixelFOV.cpp:231
static geos::geom::MultiPolygon * SplitPolygonOn360(const geos::geom::Polygon *inPoly)
If the cube crosses the 0/360 boundary and does not include a pole, this will divide the polygon into...
virtual double UniversalLatitude() const
Returns the planetocentric latitude, in degrees, at the surface intersection point in the body fixed ...
Definition Sensor.cpp:212
virtual double UniversalLongitude() const
Returns the positive east, 0-360 domain longitude, in degrees, at the surface intersection point in t...
Definition Sensor.cpp:235
void LookDirection(double v[3]) const
Returns the look direction in the camera coordinate system.
Definition Sensor.cpp:527
bool SetLookDirection(const double v[3])
Sets the look direction of the spacecraft.
Definition Sensor.cpp:143
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.