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
ShapeModelFactory.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7
8#include "ShapeModelFactory.h"
9
10#include <string>
11
12#include "BulletShapeModel.h"
13#include "BulletTargetShape.h"
14#include "Cube.h"
15#include "DemShape.h"
16#include "EllipsoidShape.h"
17#include "EmbreeShapeModel.h"
18#include "EmbreeTargetManager.h"
19#include "EquatorialCylindricalShape.h"
20#include "FileName.h"
21#include "IException.h"
22#include "IString.h"
23#include "NaifDskShape.h"
24#include "NaifStatus.h"
25#include "PlaneShape.h"
26#include "Projection.h"
27#include "Preference.h"
28#include "Pvl.h"
29#include "PvlFlatMap.h"
30#include "PvlGroup.h"
31#include "PvlKeyword.h"
32#include "Target.h"
33
34using namespace std;
35
36namespace Isis {
44
45
49
50
64
65 // get kernels and instrument Pvl groups
66 PvlGroup &kernelsPvlGroup = pvl.findGroup("Kernels", Pvl::Traverse);
67
68 // Get user preferences to determine preferred model
69 PvlFlatMap parameters(kernelsPvlGroup);
70 if ( Preference::Preferences().hasGroup("ShapeModel") ) {
71 parameters.merge(PvlFlatMap(Preference::Preferences().findGroup("ShapeModel")));
72 }
73
74 // Do we need a sky shape model, member variable, or neither? For now treat sky as ellipsoid
75 bool skyTarget = target->isSky();
76
77 // Determine if target is a plane??? target name has rings in it?
78 // Another keyword in label to indicate plane? What about lander/rovers?
79 // bool planeTarget = false;
80
81 // shape model file name
82 QString shapeModelFilenames = "";
83
84 // TODO: We differentiate between "Elevation" and "Shape" models on the
85 // labels, but we assign either one to the shapeModelFilename. Do we
86 // need a shapeModelFilename AND an elevationModelFilename?
87 // is this historical? Interchangeable?
88 if (skyTarget) {
89 // Sky targets are ellipsoid shapes
90 }
91 else if (kernelsPvlGroup.hasKeyword("ElevationModel") &&
92 !kernelsPvlGroup["ElevationModel"].isNull()) {
93 shapeModelFilenames = (QString) kernelsPvlGroup["ElevationModel"];
94 }
95 else if (kernelsPvlGroup.hasKeyword("ShapeModel") &&
96 !kernelsPvlGroup["ShapeModel"].isNull()) {
97 shapeModelFilenames = (QString) kernelsPvlGroup["ShapeModel"];
98 }
99
100 // Create shape model
101 ShapeModel *shapeModel = NULL;
102
103 // TODO: If there is no shape model filename, the shape model type defaults to an
104 // ellipsoid (should it?).
105
106 // This exception will be thrown at the end of this method if no shape model is constructed.
107 // More specific exceptions will be appended before throwing this error.
108 IException finalError(IException::Programmer,
109 "Unable to create a shape model from given target and pvl.",
110 _FILEINFO_);
111
112 if (shapeModelFilenames == "") {
113 // No file name given. If EllipsoidShape throws an error or returns null, the following
114 // exception will be appended to the finalError.
115 QString msg = "Unable to construct an Ellipsoid shape model.";
116
117 try {
118 shapeModel = new EllipsoidShape(target);
119 }
120 catch (IException &e) {
121 // No file name given and ellipsoid fails. Append e to new exception
122 // with above message. Append this to finalError and throw.
123 finalError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
124 throw finalError;
125 }
126 // in case no error was thrown, but constructor returned NULL
127 finalError.append(IException(IException::Unknown, msg, _FILEINFO_));
128 }
129 else if (shapeModelFilenames == "RingPlane") {
130 // No file name given, RingPlane indicated. If PlaneShape throws an error or returns
131 // null, the following exception will be appended to the finalError.
132 QString msg = "Unable to construct a RingPlane shape model.";
133
134 try {
135 shapeModel = new PlaneShape(target, pvl);
136 }
137 catch (IException &e) {
138 // No file name given, RingPlane specified. Append a message to the finalError and throw it.
139 finalError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
140 throw finalError;
141 }
142 // in case no error was thrown, but constructor returned NULL
143 finalError.append(IException(IException::Unknown, msg, _FILEINFO_));
144 }
145 else { // assume shape model given is a Bullet, Embree, NAIF DSK or DEM cube file name
146
147 QString preferred = parameters.get("RayTraceEngine", "None").toLower();
148 QString onerror = parameters.get("OnError", "Continue").toLower();
149 double tolerance = toDouble(parameters.get("Tolerance", toString(DBL_MAX)));
150
151 // A file error message will be appened to the finalError, if no shape model is constructed.
152 QString fileErrorMsg = "Invalid shape model file ["
153 + shapeModelFilenames + "] in Kernels group.";
154 IException fileError(IException::Io, fileErrorMsg, _FILEINFO_);
155
156 //-------------- Check for bullet engine first -------------------------------//
157 if ( "bullet" == preferred ) {
158 // Check to see of ISIS cube DEMs get a pass
159 FileName v_shapefile(shapeModelFilenames);
160 QString ext = v_shapefile.extension().toLower();
161 // Cubes are not supported at this time.
162
163 try {
164 BulletTargetShape *bullet = BulletTargetShape::load(shapeModelFilenames);
165 if ( 0 == bullet ) {
166
167 // Bullet failed to load the kernel...test failure conditions
168 if ("cub" == ext) {
169 QString mess = "Bullet could not initialize ISIS Cube DEM";
170 throw IException(IException::Unknown, mess, _FILEINFO_);
171 }
172
173 // Always throw an error in this case
174 QString b_msg = "Bullet could not initialize DEM!";
175 throw IException(IException::Unknown, b_msg, _FILEINFO_);
176 }
177 else {
178
179 // Allocate the real shape model
180 BulletShapeModel *b_model = new BulletShapeModel(bullet, target, pvl);
181 b_model->setTolerance(tolerance);
182
183 // Do this here, otherwise default behavior will ensue from here on out
184 kernelsPvlGroup.addKeyword(PvlKeyword("RayTraceEngine", preferred), PvlContainer::Replace);
185 kernelsPvlGroup.addKeyword(PvlKeyword("OnError", onerror), PvlContainer::Replace);
186 kernelsPvlGroup.addKeyword(PvlKeyword("Tolerance", toString(tolerance)),
187 PvlContainer::Replace);
188
189 return ( b_model );
190 }
191 }
192 catch (IException &ie) {
193 fileError.append(ie);
194 QString mess = "Unable to create preferred BulletShapeModel";
195 fileError.append(IException(IException::Unknown, mess, _FILEINFO_));
196 if ("fail" == onerror) {
197 throw fileError;
198 }
199 }
200
201 // Don't have ShapeModel yet - invoke pre-exising behavior (2017-03-23)
202 }
203
204 //-------------- Check for Embree engine -------------------------------//
205 if ( "embree" == preferred ) {
206
207 // Check to see of ISIS cube DEMs get a pass
208 FileName v_shapefile(shapeModelFilenames);
209 QString ext = v_shapefile.extension().toLower();
210 // Cubes are not supported at this time
211
212 try {
213
214 // Allocate the shape model
216 EmbreeShapeModel *embreeModel = new EmbreeShapeModel(target, shapeModelFilenames,
217 targetManager);
218 embreeModel->setTolerance(tolerance);
219
220 // Do this here, otherwise default behavior will ensue from here on out
221 kernelsPvlGroup.addKeyword(PvlKeyword("RayTraceEngine", preferred), PvlContainer::Replace);
222 kernelsPvlGroup.addKeyword(PvlKeyword("OnError", onerror), PvlContainer::Replace);
223 kernelsPvlGroup.addKeyword(PvlKeyword("Tolerance", toString(tolerance)),
224 PvlContainer::Replace);
225
226 return ( embreeModel );
227
228 } catch (IException &ie) {
229 fileError.append(ie);
230 QString mess = "Unable to create preferred EmbreeShapeModel";
231 fileError.append(IException(IException::Unknown, mess, _FILEINFO_));
232 if ("fail" == onerror) {
233 throw fileError;
234 }
235 }
236 }
237
238 //-------------- Is the shape model a NAIF DSK? ------------------------------//
239
240 // If NaifDskShape throws an error or returns null and DEM construction is
241 // unsuccessful, the following exception will be appended to the fileError.
242 QString msg = "The given shape model file is not a valid NAIF DSK file. "
243 "Unable to construct a NAIF DSK shape model.";
244 IException dskError(IException::Unknown, msg, _FILEINFO_);
245
246 try {
247 // try to create a NaifDskShape object
248 shapeModel = new NaifDskShape(target, pvl);
249 }
250 catch (IException &e) {
251 // append a message to the fileError, but don't throw it.
252 // We will make sure it's not a DEM before throwing the error.
253 dskError.append(e);
254 }
255
256 if (shapeModel == NULL) {
257
258 // in case no error was thrown, but constructor returned NULL
259 fileError.append(dskError);
260
261 //-------------- Is the shape model an ISIS DEM? ------------------------------//
262 // TODO Deal with stacks -- this could be a list of DEMs
263 Isis::Cube* shapeModelCube = new Isis::Cube;
264 try {
265 // first, try to open the shape model file as an Isis cube
266 shapeModelCube->open(FileName(shapeModelFilenames).expanded(), "r" );
267 }
268 catch (IException &e) {
269 // The file is neither a valid DSK nor an ISIS cube. Append a message and throw the error.
270 QString msg = "The given shape model file is not a valid ISIS DEM. "
271 "Unable to open as an ISIS cube.";
272 fileError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
273 finalError.append(fileError);
274 throw finalError;
275 }
276
277 Projection *projection = NULL;
278 try {
279 // get projection of shape model cube
280 projection = shapeModelCube->projection();
281 }
282 catch (IException &e) {
283 // The file is neither a valid DSK nor a valid ISIS DEM. Append message and throw the error.
284 QString msg = "The given shape model file is not a valid ISIS DEM cube. "
285 "It is not map-projected.";
286 fileError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
287 finalError.append(fileError);
288 throw finalError;
289 }
290
291 if (projection->IsEquatorialCylindrical()) {
292 // If the EquatorialCylindricalShape constructor throws an error or returns null, the
293 // following exception will be appended to the fileError. (Later added to the finalError)
294 QString msg = "Unable to construct a DEM shape model from the given "
295 "EquatorialCylindrical projected ISIS cube.";
296
297 try {
298 shapeModel = new EquatorialCylindricalShape(target, pvl);
299 }
300 catch (IException &e) {
301 // The file is an equatorial cylindrical ISIS cube. Append fileError and throw.
302 fileError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
303 finalError.append(fileError);
304 throw finalError;
305 }
306 // in case no error was thrown, but constructor returned NULL
307 fileError.append(IException(IException::Unknown, msg, _FILEINFO_));
308 }
309 else {
310 // If the DemShape constructor throws an error or returns null, the following
311 // exception will be appended to the fileError. (Later added to the finalError)
312 QString msg = "Unable to construct a DEM shape model "
313 "from the given projected ISIS cube file.";
314
315 try {
316 shapeModel = new DemShape(target, pvl);
317 }
318 catch (IException &e) {
319 // The file is projected ISIS cube (assumed to be DEM). Append fileError and throw.
320 fileError.append(IException(e, IException::Unknown, msg, _FILEINFO_));
321 finalError.append(fileError);
322 throw finalError;
323 }
324 // in case no error was thrown, but constructor returned NULL
325 fileError.append(IException(IException::Unknown, msg, _FILEINFO_));
326 }
327
328 delete shapeModelCube;
329
330 }
331
332 // in case no error was thrown, but DSK, Equatorial, or DEM constructor returned NULL
333 finalError.append(fileError);
334 }
335
336 // TODO Add Naif DSK shape and stack?
337
338 if (shapeModel == NULL) {
339 throw finalError;
340 }
341
342 return shapeModel;
343 }
344} // end namespace isis
Shape model that uses the Bullet library to perform ray tracing.
void setTolerance(const double &tolerance)
Sets the occlusion tolerance.
Bullet Target Shape for planetary bodies.
static BulletTargetShape * load(const QString &dem, const Pvl *conf=0)
Load a DEM file into the target shape.
IO Handler for Isis Cubes.
Definition Cube.h:168
void open(const QString &cfile, QString access="r")
This method will try to open a file as either a cube or geotiff in either read or read/write.
Definition Cube.cpp:792
Projection * projection()
Definition Cube.cpp:2068
Define shapes and provide utilities for targets stored as ISIS maps.
Definition DemShape.h:50
Define shapes and provide utilities for ISIS targets.
General purpose Embree ray tracing model.
void setTolerance(const double &tolerance)
Set the tolerance used when checking if the stored surface point is visible.
Class for managing the construction and destruction of EmbreeTargetShapes.
static EmbreeTargetManager * getInstance()
Retrieve reference to Singleton instance of this object.
Define shapes and provide utilities for shapes stored as ISIS EquatorialCylindrical map.
Provides support for NAIF's Digital Shape Kernel (DSK)
Define plane shape model.
Definition PlaneShape.h:44
Base class for Map Projections.
Definition Projection.h:154
virtual bool IsEquatorialCylindrical()
This method returns true if the projection is equatorial cylindrical.
Provides a flat map of PvlKeywords.
Definition PvlFlatMap.h:218
QString get(const QString &key, const int &index=0) const
Gets the value of a keyword in the PvlFlatMap.
int merge(const PvlFlatMap &other)
Adds the keywords from another PvlFlatMap.
ShapeModelFactory()
Constructor is private to avoid instantiating the class.
static ShapeModel * create(Target *target, Pvl &pvl)
Construct a valid shape model from the given target and contents of kernels group.
Define shapes and provide utilities for Isis targets.
Definition ShapeModel.h:65
This class is used to create and store valid Isis targets.
Definition Target.h:63
bool isSky() const
Return if our target is the sky.
Definition Target.cpp:215
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.
Namespace for the standard library.