Isis 3 Programmer Reference
ZoomTool.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include <iostream>
10
11#include <QAction>
12#include <QApplication>
13#include <QHBoxLayout>
14#include <QLabel>
15#include <QLineEdit>
16#include <QMenu>
17#include <QMenuBar>
18#include <QMessageBox>
19#include <QPushButton>
20#include <QStackedWidget>
21#include <QToolButton>
22#include <QValidator>
23
24#include "IException.h"
25#include "IString.h"
26#include "MainWindow.h"
27#include "MdiCubeViewport.h"
28#include "RubberBandTool.h"
29#include "ToolPad.h"
30#include "Workspace.h"
31#include "ZoomTool.h"
32
33namespace Isis {
40 ZoomTool::ZoomTool(QWidget *parent) : Tool(parent) {
41 p_zoomIn2X = new QAction(parent);
42 p_zoomIn2X->setShortcut(Qt::Key_Plus);
43 p_zoomIn2X->setText("Zoom In");
44 p_zoomIn2X->setIcon(QPixmap(toolIconDir() + "/viewmag+.png"));
45 connect(p_zoomIn2X, SIGNAL(triggered()), this, SLOT(zoomIn2X()));
46
47 p_zoomIn4X = new QAction(parent);
48 p_zoomIn4X->setText("Zoom In 4X");
49 p_zoomIn4X->setShortcut(Qt::CTRL + Qt::Key_Plus);
50 connect(p_zoomIn4X, SIGNAL(triggered()), this, SLOT(zoomIn4X()));
51
52 p_zoomIn8X = new QAction(parent);
53 p_zoomIn8X->setShortcut(Qt::ALT + Qt::Key_Plus);
54 p_zoomIn8X->setText("Zoom In 8X");
55 connect(p_zoomIn8X, SIGNAL(triggered()), this, SLOT(zoomIn8X()));
56
57 p_zoomOut2X = new QAction(parent);
58 p_zoomOut2X->setShortcut(Qt::Key_Minus);
59 p_zoomOut2X->setText("Zoom Out");
60 p_zoomOut2X->setIcon(QPixmap(toolIconDir() + "/viewmag-.png"));
61 connect(p_zoomOut2X, SIGNAL(triggered()), this, SLOT(zoomOut2X()));
62
63 p_zoomOut4X = new QAction(parent);
64 p_zoomOut4X->setShortcut(Qt::CTRL + Qt::Key_Minus);
65 p_zoomOut4X->setText("Zoom Out 4X");
66 connect(p_zoomOut4X, SIGNAL(triggered()), this, SLOT(zoomOut4X()));
67
68 p_zoomOut8X = new QAction(parent);
69 p_zoomOut8X->setShortcut(Qt::ALT + Qt::Key_Minus);
70 p_zoomOut8X->setText("Zoom Out 8X");
71 connect(p_zoomOut8X, SIGNAL(triggered()), this, SLOT(zoomOut8X()));
72
73 p_zoomActual = new QAction(parent);
74 p_zoomActual->setShortcut(Qt::Key_Slash);
75 p_zoomActual->setText("&Actual Pixels");
76 p_zoomActual->setIcon(QPixmap(toolIconDir() + "/viewmag1.png"));
77 connect(p_zoomActual, SIGNAL(triggered()), this, SLOT(zoomActual()));
78
79 p_zoomFit = new QAction(parent);
80 p_zoomFit->setShortcut(Qt::Key_Asterisk);
81 p_zoomFit->setText("&Fit in Window");
82 p_zoomFit->setIcon(QPixmap(toolIconDir() + "/viewmagfit.png"));
83 connect(p_zoomFit, SIGNAL(triggered()), this, SLOT(zoomFit()));
84
85 }
86
97 QAction *action = new QAction(toolpad);
98 action->setIcon(QPixmap(toolIconDir() + "/viewmag.png"));
99 action->setToolTip("Zoom (Z)");
100 action->setShortcut(Qt::Key_Z);
101 QString text =
102 "<b>Function:</b> Zoom in or out of the current cube. \
103 <p><b>Shortcut:</b> Z</p> ";
104 action->setWhatsThis(text);
105 return action;
106 }
107
108
117 void ZoomTool::addTo(QMenu *menu) {
118 menu->addAction(p_zoomFit);
119 menu->addAction(p_zoomActual);
120 menu->addAction(p_zoomIn2X);
121 menu->addAction(p_zoomOut2X);
122 }
123
124
143 QWidget *ZoomTool::createToolBarWidget(QStackedWidget *parent) {
144 QWidget *hbox = new QWidget(parent);
145
146 QToolButton *zoomInButton = new QToolButton(hbox);
147 zoomInButton->setIcon(QPixmap(toolIconDir() + "/viewmag+.png"));
148 zoomInButton->setToolTip("Zoom In");
149 QString text =
150 "<b>Function:</b> Zoom in 2X at the center of the active viewport \
151 <p><b>Shortcut:</b> +</p> \
152 <p><b>Mouse:</b> LeftButton zooms in 2X under pointer</p> \
153 <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \
154 using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
155 <p><b>Hint:</b> Left click and drag for a local zoom which scales data \
156 in the red marquee to the viewport</p>";
157 zoomInButton->setWhatsThis(text);
158 connect(zoomInButton, SIGNAL(clicked()), this, SLOT(zoomIn2X()));
159 zoomInButton->setAutoRaise(true);
160 zoomInButton->setIconSize(QSize(22, 22));
161
162 QToolButton *zoomOutButton = new QToolButton(hbox);
163 zoomOutButton->setIcon(QPixmap(toolIconDir() + "/viewmag-.png"));
164 zoomOutButton->setToolTip("Zoom Out");
165 text =
166 "<b>Function:</b> Zoom out 2X at the center of the active viewport \
167 <p><b>Shortcut:</b> +</p> \
168 <p><b>Mouse:</b> RightButton zooms out 2X under pointer</p> \
169 <p><b>Modifiers:</b> Shortcuts and mouse clicks can be augmented \
170 using the Ctrl or Alt key for 4X and 8X zooms, respectively</p> \
171 <p><b>Hint:</b> Left click and drag for a local zoom which scales data \
172 in the red marquee to the viewport</p>";
173 zoomOutButton->setWhatsThis(text);
174 connect(zoomOutButton, SIGNAL(clicked()), this, SLOT(zoomOut2X()));
175 zoomOutButton->setAutoRaise(true);
176 zoomOutButton->setIconSize(QSize(22, 22));
177
178 QToolButton *zoomActButton = new QToolButton(hbox);
179 zoomActButton->setIcon(QPixmap(toolIconDir() + "/viewmag1.png"));
180 zoomActButton->setToolTip("Zoom 1:1");
181 text =
182 "<b>Function:</b> Zoom the active viewport to 1:1 such that one \
183 viewport pixel represents one cube pixel. That is, 100% scale. \
184 <p><b>Shortcut:</b> /</p> \
185 <p><b>Mouse:</b> Ctrl+MiddleButton zooms 1:1 under pointer</p> \
186 <p><b>Hint:</b> MiddleButton (without Ctrl) retains current \
187 scale but moves the pixel under the pointer to the center of the \
188 viewport</p>";
189 zoomActButton->setWhatsThis(text);
190 connect(zoomActButton, SIGNAL(clicked()), this, SLOT(zoomActual()));
191 zoomActButton->setAutoRaise(true);
192 zoomActButton->setIconSize(QSize(22, 22));
193
194 // Create menu on the zoomFit button to select fitting the cube for
195 // width or height.
196 QMenu *zoomFitMenu = new QMenu();
197 QAction *fitWidth = new QAction(this);
198 fitWidth->setText("Fit Width");
199 connect(fitWidth, SIGNAL(triggered(bool)), this, SLOT(zoomFitWidth()));
200 zoomFitMenu->addAction(fitWidth);
201
202 QAction *fitHeight = new QAction(this);
203 fitHeight->setText("Fit Height");
204 connect(fitHeight, SIGNAL(triggered(bool)), this, SLOT(zoomFitHeight()));
205 zoomFitMenu->addAction(fitHeight);
206
207 QToolButton *zoomFitButton = new QToolButton(hbox);
208 zoomFitButton->setIcon(QPixmap(toolIconDir() + "/viewmagfit.png"));
209 zoomFitButton->setMenu(zoomFitMenu);
210 zoomFitButton->setPopupMode(QToolButton::MenuButtonPopup);
211 zoomFitButton->setToolTip("Fit in viewport");
212 text =
213 "<b>Function:</b> Fit the entire cube inside the active viewport. For \
214 extremely large cubes, this may not be possible. \
215 <p><b>Shortcut:</b> *</p> \
216 <p><b>Hint:</b> Many shortcuts for the zoom tool and other tools \
217 are easily available on the numeric keypad </p>";
218 zoomFitButton->setWhatsThis(text);
219 connect(zoomFitButton, SIGNAL(clicked()), this, SLOT(zoomFit()));
220 zoomFitButton->setAutoRaise(true);
221 zoomFitButton->setIconSize(QSize(22, 22));
222
223 p_zoomLineEdit = new QLineEdit(hbox);
224 p_zoomLineEdit->setText("");
225 p_zoomLineEdit->setMaxLength(8);
226 p_zoomLineEdit->setMaximumWidth(80);
227
228 QDoubleValidator *dval = new QDoubleValidator(hbox);
229 p_zoomLineEdit->setValidator(dval);
230
231 QSizePolicy policy = p_zoomLineEdit->sizePolicy();
232 policy.setHorizontalPolicy(QSizePolicy::Fixed);
233 p_zoomLineEdit->setSizePolicy(policy);
234
235 p_zoomLineEdit->setToolTip("Scale");
236 text =
237 "<b>Function:</b> Shows the scale of the active viewport. Additionally, \
238 you can manually enter the scale.";
239 p_zoomLineEdit->setWhatsThis(text);
240 connect(p_zoomLineEdit, SIGNAL(returnPressed()), this, SLOT(zoomManual()));
241
242 QHBoxLayout *layout = new QHBoxLayout(hbox);
243 layout->setMargin(0);
244 layout->addWidget(zoomInButton);
245 layout->addWidget(zoomOutButton);
246 layout->addWidget(zoomActButton);
247 layout->addWidget(zoomFitButton);
248 layout->addWidget(p_zoomLineEdit);
249 layout->addStretch(1);
250 hbox->setLayout(layout);
251 return hbox;
252 }
253
259 zoomBy(2.0);
260 }
261
262
268 zoomBy(4.0);
269 }
270
271
277 zoomBy(8.0);
278 }
279
280
286 zoomBy(1.0 / 2.0);
287 }
288
289
295 zoomBy(1.0 / 4.0);
296 }
297
298
304 zoomBy(1.0 / 8.0);
305 }
306
307
313 // zoom factor passed in is 0
314 // this will indicate to set new scale to 1 in zoomBy()
315 zoomBy(0.0);
316 }
317
318
330 void ZoomTool::zoomBy(double factor) {
332 if(d == NULL) return;
333 double newScale = d->scale() * factor;
334 if(newScale == 0.0) {
335 // if zoomActual was called (1:1) the factor was set to 0.
336 // change scale to 1.0
337 newScale = 1.0;
338 }
339 setScale(d, newScale);
340 updateTool();
341
342 if(cubeViewport()->isLinked()) {
343 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
344 d = (*(cubeViewportList()))[i];
345 if(d == cubeViewport()) continue;
346 if(d->isLinked()) {
347 newScale = d->scale() * factor;
348 if(newScale == 0.0) {
349 // if zoomActual was called (1:1) the factor was set to 0.
350 // change scale to 1.0
351 newScale = 1.0;
352 }
353 setScale(d, newScale);
354 }
355 }
356 }
357 }
358
359
370 if (d == NULL) return;
371 setScale(d, d->fitScale(), d->cubeSamples() / 2.0 + 0.5, d->cubeLines() / 2.0 + 0.5);
372 updateTool();
373
374 if (d->isLinked()) {
375 for (int i = 0; i < (int)cubeViewportList()->size(); i++) {
376 d = (*(cubeViewportList()))[i];
377 if (d == cubeViewport()) continue;
378 if (d->isLinked()) {
379 setScale(d, d->fitScale(), d->cubeSamples() / 2.0 + 0.5, d->cubeLines() / 2.0 + 0.5);
380 }
381 }
382 }
383 }
384
385
386
396 if (d == NULL) return;
397 setScale(d, d->fitScaleWidth(), d->cubeSamples() / 2.0 + 0.5, d->cubeLines() / 2.0 + 0.5);
398 updateTool();
399
400 if (d->isLinked()) {
401 for (int i = 0; i < (int)cubeViewportList()->size(); i++) {
402 d = (*(cubeViewportList()))[i];
403 if (d == cubeViewport()) continue;
404 if (d->isLinked()) {
405 setScale(d, d->fitScaleWidth(), d->cubeSamples() / 2.0 + 0.5, d->cubeLines() / 2.0 + 0.5);
406 }
407 }
408 }
409 }
410
411
422 if (d == NULL) return;
423 setScale(d, d->fitScaleHeight(), d->cubeSamples() / 2.0 + 0.5, d->cubeLines() / 2.0 + 0.5);
424 updateTool();
425
426 if (d->isLinked()) {
427 for (int i = 0; i < (int)cubeViewportList()->size(); i++) {
428 d = (*(cubeViewportList()))[i];
429 if (d == cubeViewport()) continue;
430 if (d->isLinked()) {
431 setScale(d, d->fitScaleHeight(), d->cubeSamples() / 2.0 + 0.5,
432 d->cubeLines() / 2.0 + 0.5);
433 }
434 }
435 }
436 }
437
438
449 if(d == NULL) return;
450 QString strScale = p_zoomLineEdit->text();
451 double newScale = strScale.toDouble() / 100.;
452 setScale(d, newScale);
453 d->setFocus();
454 updateTool();
455
456 if(d->isLinked()) {
457 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
458 d = (*(cubeViewportList()))[i];
459 if(d == cubeViewport()) continue;
460 if(d->isLinked()) setScale(d, newScale);
461 }
462 }
463 }
464
465
472 if(cubeViewport() == NULL) {
473 p_zoomLineEdit->setText("");
474 }
475 else {
476 double scale = cubeViewport()->scale() * 100.0;
477 QString strScale;
478 strScale.setNum(scale);
479 p_zoomLineEdit->setText(strScale);
480 }
481 }
482
483
497 QApplication::processEvents();
499 if(!rubberBandTool()->isValid()) return;
500
501 // The RubberBandTool has a rectangle
502 if(!rubberBandTool()->figureIsPoint()) {
503 QRect r = rubberBandTool()->rectangle();
504 if((r.width() >= 5) && (r.height() >= 5)) {
505 int x = r.x() + r.width() / 2;
506 int y = r.y() + r.height() / 2;
507 double xscale = (double) d->viewport()->width() / r.width();
508 double yscale = (double) d->viewport()->height() / r.height();
509 double newScale = xscale < yscale ? xscale : yscale;
510 if(rubberBandTool()->mouseButton() & Qt::RightButton) {
511 newScale = 1.0 / newScale;
512 }
513 newScale *= d->scale();
514 setScale(d, newScale, x, y);
515 updateTool();
516 if(d->isLinked()) {
517 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
518 d = (*(cubeViewportList()))[i];
519 if(d == cubeViewport()) continue;
520 if(d->isLinked()) {
521 int x = r.x() + r.width() / 2;
522 int y = r.y() + r.height() / 2;
523 double xscale = (double) d->viewport()->width() / r.width();
524 double yscale = (double) d->viewport()->height() / r.height();
525 double newScale = xscale < yscale ? xscale : yscale;
526 if(rubberBandTool()->mouseButton() & Qt::RightButton) {
527 newScale = 1.0 / newScale;
528 }
529 newScale *= d->scale();
530 setScale(d, newScale, x, y);
531 }
532 }
533 }
534 }
535 }
536 // The RubberBandTool has a point (mouse click)
537 else {
538 double factor = 2.0;
539 if(rubberBandTool()->mouseButton() & Qt::ControlModifier) {
540 factor = 4.0;
541 }
542 if(rubberBandTool()->mouseButton() & Qt::ShiftModifier) {
543 factor = 8.0;
544 }
545 if(rubberBandTool()->mouseButton() & Qt::RightButton) {
546 factor = 1.0 / factor;
547 }
548 if(rubberBandTool()->mouseButton() & Qt::MidButton) {
549 factor = 1.0;
550 }
551 if(rubberBandTool()->mouseButton() == Qt::MidButton + Qt::ControlModifier) {
552 factor = 0.0;
553 }
554// MdiCubeViewport *d = cubeViewport();
555 double newScale = d->scale() * factor;
556 if(newScale == 0.0) {
557 // ctrl+middle (1:1) the factor was set to 0.
558 // change scale to 1.0
559 newScale = 1.0;
560 }
561 QPoint p = rubberBandTool()->vertices()[0];
562 setScale(d, newScale, p.x(), p.y());
563 updateTool();
564
565 if(d->isLinked()) {
566 for(int i = 0; i < (int)cubeViewportList()->size(); i++) {
567 d = (*(cubeViewportList()))[i];
568 if(d == cubeViewport()) continue;
569 if(d->isLinked()) {
570 newScale = d->scale() * factor;
571 if(newScale == 0.0) {
572 // ctrl+middle (1:1) the factor was set to 0.
573 // change scale to 1.0
574 newScale = 1.0;
575 }
576 newScale = setScale(d, newScale, p.x(), p.y());
577 }
578 }
579 }
580 p_lastScale = newScale;
581 }
582 }
583
584
591 rubberBandTool()->enable(RubberBandTool::RectangleMode);
592 rubberBandTool()->enablePoints();
593 rubberBandTool()->enableAllClicks();
594 rubberBandTool()->setDrawActiveViewportOnly(false);
595 }
596
614 double ZoomTool::setScale(MdiCubeViewport *d, double newScale) {
615
616 double oldScale = d->scale();
617 try {
618 if (newScale <= 0.0) {
620 "Scale value must be greater than 0.",
621 _FILEINFO_);
622 }
623 d->setScale(newScale);
624 }
625 catch (IException &e) {
626 IException fullError(e,
628 "Unable to rescale image to ["
629 + IString(newScale*100) + "]",
630 _FILEINFO_);
631 QString message = fullError.toString();
632 QMessageBox::warning((QWidget *)parent(), "Warning", message);
633 newScale = oldScale;
634 d->setScale(newScale);
635 }
636 return newScale;
637 }
638
639
660 double ZoomTool::setScale(MdiCubeViewport *d, double newScale, int x, int y) {
661 double oldScale = d->scale();
662 try {
663 if (newScale <= 0.0) {
665 "Scale value must be greater than 0.", _FILEINFO_);
666 }
667 d->setScale(newScale, x, y);
668 }
669 catch (IException &e) {
670 IException fullError(e, IException::User,
671 "Unable to rescale image to ["
672 + IString(newScale * 100) + "]",
673 _FILEINFO_);
674 QString message = fullError.toString();
675 QMessageBox::warning((QWidget *)parent(), "Warning", message);
676 newScale = oldScale;
677 d->setScale(newScale, x, y);
678 }
679 return newScale;
680 }
681
702 double ZoomTool::setScale(MdiCubeViewport *d, double newScale, double samp, double line) {
703 double oldScale = d->scale();
704 try {
705 if (newScale <= 0.0) {
707 "Scale value must be greater than 0.", _FILEINFO_);
708 }
709 d->setScale(newScale, samp, line);
710 }
711 catch (IException &e) {
712 IException fullError(e,
714 "Unable to rescale image to ["
715 + IString(newScale*100) + "]",
716 _FILEINFO_);
717 QString message = fullError.toString();
718 QMessageBox::warning((QWidget *)parent(), "Warning", message);
719 newScale = oldScale;
720 d->setScale(newScale, samp, line);
721 }
722 return newScale;
723 }
724
725}
double scale() const
int cubeLines() const
Return the number of lines in the cube.
double fitScaleHeight() const
Determine the scale of cube in heighth to fit in the viewport.
int cubeSamples() const
Return the number of samples in the cube.
double fitScale() const
Determine the scale that causes the full cube to fit in the viewport.
void setScale(double scale)
Change the scale of the cube to the given parameter value.
double fitScaleWidth() const
Determine the scale of cube in the width to fit in the viewport.
Isis exception class.
Definition IException.h:91
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
Adds specific functionality to C++ strings.
Definition IString.h:165
Cube display widget for certain Isis MDI applications.
bool isLinked() const
Is the viewport linked with other viewports.
QRect rectangle()
This method returns a rectangle from the vertices set by the RubberBandTool.
void setDrawActiveViewportOnly(bool activeOnly=false)
This called to set whether rubber band is drawn on active viewport only rather than all linked viewpo...
QList< QPoint > vertices()
This method returns the vertices.
Qt::MouseButton mouseButton()
This method returns the mouse button modifier.
void enable(RubberBandMode mode, bool showIndicatorColors=false)
This is called when changing modes or turning on.
Base class for the Qisis tools.
Definition Tool.h:67
CubeViewportList * cubeViewportList() const
Return the list of cubeviewports.
Definition Tool.cpp:390
MdiCubeViewport * cubeViewport() const
Return the current cubeviewport.
Definition Tool.h:197
QString toolIconDir() const
returns the path to the icon directory.
Definition Tool.h:113
void updateTool()
This method updates the line edits text to the correct zoom value.
Definition ZoomTool.cpp:471
void rubberBandComplete()
This method is called when the RubberBandTool is complete.
Definition ZoomTool.cpp:496
ZoomTool(QWidget *parent)
ZoomTool constructor.
Definition ZoomTool.cpp:40
QAction * p_zoomIn8X
Zoom in 8 times.
Definition ZoomTool.h:104
void zoomFitHeight()
Slot for the "Fit to Heighth" menu item on the Fit button.
Definition ZoomTool.cpp:420
QAction * p_zoomOut4X
Zoom out 4 times.
Definition ZoomTool.h:107
void zoomOut8X()
Zoom out 8 times.
Definition ZoomTool.cpp:303
void zoomIn2X()
Zooms in 2 times.
Definition ZoomTool.cpp:258
QAction * p_zoomOut2X
Zoom out 2 times.
Definition ZoomTool.h:106
double p_lastScale
Last scale.
Definition ZoomTool.h:114
void addTo(QMenu *menu)
Adds the zoom action to the given menu.
Definition ZoomTool.cpp:117
QAction * p_zoomFit
Fit the cube in the viewport action.
Definition ZoomTool.h:111
void zoomFitWidth()
Slot for the "Fit to Width" menu item on the Fit button.
Definition ZoomTool.cpp:394
void zoomIn8X()
Zooms in 8 times.
Definition ZoomTool.cpp:276
void zoomOut2X()
Zoom out 2 times.
Definition ZoomTool.cpp:285
double setScale(MdiCubeViewport *d, double newScale)
This method will attempt to reset the scale for the given MdiCubeViewport using the new scale value.
Definition ZoomTool.cpp:614
QAction * p_zoomIn4X
Zoom in 4 times.
Definition ZoomTool.h:103
void zoomBy(double factor)
Zoom by the given factor.
Definition ZoomTool.cpp:330
QAction * p_zoomIn2X
Zoom in 2 times.
Definition ZoomTool.h:102
QAction * toolPadAction(ToolPad *toolpad)
Adds the action to the toolpad.
Definition ZoomTool.cpp:96
QAction * p_zoomActual
Zoom to actual size action.
Definition ZoomTool.h:110
void enableRubberBandTool()
This methods enables the RubberBandTool, it also sets the RubberBandTool to allow points and to allow...
Definition ZoomTool.cpp:590
void zoomActual()
Zoom back to 1 to 1.
Definition ZoomTool.cpp:312
void zoomFit()
Fits the cube in the viewport.
Definition ZoomTool.cpp:368
void zoomManual()
This method zooms by the value input in the line edit next to the zoom tools.
Definition ZoomTool.cpp:447
QWidget * createToolBarWidget(QStackedWidget *parent)
Creates the widget to add to the tool bar.
Definition ZoomTool.cpp:143
QAction * p_zoomOut8X
Zoom out 8 times.
Definition ZoomTool.h:108
void zoomIn4X()
Zooms in 4 times.
Definition ZoomTool.cpp:267
void zoomOut4X()
Zoom out 4 times.
Definition ZoomTool.cpp:294
QLineEdit * p_zoomLineEdit
Line edit for manual zoom factor.
Definition ZoomTool.h:113
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16