9#include "mosaictiles.h"
10#include "kstarsdata.h"
18 m_Pen.setColor(
QColor(200, 200, 200, 100));
23 m_TextPen.setWidth(2);
25 m_FocalLength = Options::telescopeFocalLength();
26 m_FocalReducer = Options::telescopeFocalReducer();
27 m_CameraSize.setWidth(Options::cameraWidth());
28 m_CameraSize.setHeight(Options::cameraHeight());
29 m_PixelSize.setWidth(Options::cameraPixelWidth());
30 m_PixelSize.setHeight(Options::cameraPixelHeight());
31 m_PositionAngle = Options::cameraRotation();
34 m_MosaicFOV = m_CameraFOV = calculateCameraFOV();
39MosaicTiles::~MosaicTiles()
43bool MosaicTiles::isValid()
const
45 return m_MosaicFOV.width() > 0 && m_MosaicFOV.height() > 0;
48void MosaicTiles::setPositionAngle(
double value)
50 m_PositionAngle = value;
53void MosaicTiles::setOverlap(
double value)
55 m_Overlap = (value < 0) ? 0 : (value > 100) ? 100 : value;
58std::shared_ptr<MosaicTiles::OneTile> MosaicTiles::oneTile(
int row,
int col)
60 int offset = row * m_GridSize.width() + col;
62 if (offset < 0 || offset >= m_Tiles.size())
65 return m_Tiles[offset];
68bool MosaicTiles::fromXML(
const QString &filename)
76 LilXML *xmlParser = newLilXML();
77 char errmsg[2048] = {0};
78 XMLEle *root =
nullptr;
82 m_OperationMode = MODE_OPERATION;
89 bool mosaicInfoFound =
false;
92 m_TrackChecked = m_FocusChecked = m_AlignChecked = m_GuideChecked =
false;
96 root = readXMLEle(xmlParser, c, errmsg);
100 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
102 const char *tag = tagXMLEle(ep);
103 if (!strcmp(tag,
"Mosaic"))
105 mosaicInfoFound =
true;
106 XMLEle *subEP =
nullptr;
107 for (subEP = nextXMLEle(ep, 1); subEP !=
nullptr; subEP = nextXMLEle(ep, 0))
109 const char *subTag = tagXMLEle(subEP);
110 if (!strcmp(subTag,
"Target"))
111 setTargetName(pcdataXMLEle(subEP));
112 else if (!strcmp(subTag,
"Group"))
113 setGroup(pcdataXMLEle(subEP));
114 else if (!strcmp(subTag,
"FinishSequence"))
115 setCompletionCondition(subTag);
116 else if (!strcmp(subTag,
"FinishRepeat"))
117 setCompletionCondition(subTag, pcdataXMLEle(subEP));
118 else if (!strcmp(subTag,
"FinishSLoop"))
119 setCompletionCondition(subTag);
120 else if (!strcmp(subTag,
"Sequence"))
121 setSequenceFile(pcdataXMLEle(subEP));
122 else if (!strcmp(subTag,
"Directory"))
123 setOutputDirectory(pcdataXMLEle(subEP));
124 else if (!strcmp(subTag,
"FocusEveryN"))
125 setFocusEveryN(cLocale.
toInt(pcdataXMLEle(subEP)));
126 else if (!strcmp(subTag,
"AlignEveryN"))
127 setAlignEveryN(cLocale.
toInt(pcdataXMLEle(subEP)));
128 else if (!strcmp(subTag,
"TrackChecked"))
129 m_TrackChecked =
true;
130 else if (!strcmp(subTag,
"FocusChecked"))
131 m_FocusChecked =
true;
132 else if (!strcmp(subTag,
"AlignChecked"))
133 m_AlignChecked =
true;
134 else if (!strcmp(subTag,
"GuideChecked"))
135 m_GuideChecked =
true;
136 else if (!strcmp(subTag,
"Overlap"))
137 setOverlap(cLocale.
toDouble(pcdataXMLEle(subEP)));
138 else if (!strcmp(subTag,
"CenterRA"))
141 ra.setH(cLocale.
toDouble(pcdataXMLEle(subEP)));
144 else if (!strcmp(subTag,
"CenterDE"))
150 else if (!strcmp(subTag,
"GridW"))
151 m_GridSize.setWidth(cLocale.
toInt(pcdataXMLEle(subEP)));
152 else if (!strcmp(subTag,
"GridH"))
153 m_GridSize.setHeight(cLocale.
toInt(pcdataXMLEle(subEP)));
154 else if (!strcmp(subTag,
"FOVW"))
155 m_MosaicFOV.setWidth(cLocale.
toDouble(pcdataXMLEle(subEP)));
156 else if (!strcmp(subTag,
"FOVH"))
157 m_MosaicFOV.setHeight(cLocale.
toDouble(pcdataXMLEle(subEP)));
158 else if (!strcmp(subTag,
"CameraFOVW"))
159 m_CameraFOV.setWidth(cLocale.
toDouble(pcdataXMLEle(subEP)));
160 else if (!strcmp(subTag,
"CameraFOVH"))
161 m_CameraFOV.setHeight(cLocale.
toDouble(pcdataXMLEle(subEP)));
164 else if (mosaicInfoFound && !strcmp(tag,
"Job"))
165 processJobInfo(ep, index++);
171 delLilXML(xmlParser);
176 delLilXML(xmlParser);
179 return mosaicInfoFound;
182bool MosaicTiles::processJobInfo(XMLEle *root,
int index)
191 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
193 newTile.index = index;
194 if (!strcmp(tagXMLEle(ep),
"Coordinates"))
196 subEP = findXMLEle(ep,
"J2000RA");
200 ra.setH(cLocale.
toDouble(pcdataXMLEle(subEP)));
201 newTile.skyCenter.setRA0(
ra);
203 subEP = findXMLEle(ep,
"J2000DE");
208 newTile.skyCenter.setDec0(de);
211 else if (!strcmp(tagXMLEle(ep),
"TileCenter"))
213 if ((subEP = findXMLEle(ep,
"X")))
214 newTile.center.setX(cLocale.
toDouble(pcdataXMLEle(subEP)));
215 if ((subEP = findXMLEle(ep,
"Y")))
216 newTile.center.setY(cLocale.
toDouble(pcdataXMLEle(subEP)));
217 if ((subEP = findXMLEle(ep,
"Rotation")))
218 newTile.rotation = cLocale.
toDouble(pcdataXMLEle(subEP));
220 else if (!strcmp(tagXMLEle(ep),
"PositionAngle"))
222 m_PositionAngle = cLocale.
toDouble(pcdataXMLEle(ep));
226 newTile.skyCenter.updateCoordsNow(KStarsData::Instance()->updateNum());
244void MosaicTiles::appendTile(
const OneTile &value)
246 m_Tiles.append(std::make_shared<OneTile>(value));
249void MosaicTiles::appendEmptyTile()
251 m_Tiles.append(std::make_shared<OneTile>());
254void MosaicTiles::clearTiles()
268 return QSizeF(tileCoord.
x() / 60.0 * toSpherical.width(), tileCoord.
y() / 60.0 * toSpherical.height());
271void MosaicTiles::createTiles(
bool s_shaped)
273 m_SShaped = s_shaped;
277void MosaicTiles::updateTiles()
280 const auto fovW = m_CameraFOV.width();
281 const auto fovH = m_CameraFOV.height();
282 const auto gridW = m_GridSize.width();
283 const auto gridH = m_GridSize.height();
286 double const xOffset = fovW * (1 - m_Overlap / 100.0);
287 double const yOffset = fovH * (1 - m_Overlap / 100.0);
290 double initX = +(fovW + xOffset * (gridW - 1)) / 2.0 - fovW;
291 double initY = -(fovH + yOffset * (gridH - 1)) / 2.0;
293 double x = initX, y = initY;
302 for (
int col = 0; col < gridW; col++)
304 y = (m_SShaped && (col % 2)) ? (y - yOffset) : initY;
306 for (
int row = 0; row < gridH; row++)
309 QPointF tile_center(pos.x() + (fovW / 2.0), pos.y() + (fovH / 2.0));
312 const auto tileSkyLocation = QPointF(0, 0) - rotatePoint(tile_center, QPointF(), m_PositionAngle);
315 const auto tileSkyOffsetScaled = adjustCoordinate(tileSkyLocation);
317 auto adjusted_ra0 = (
ra0().
Degrees() + tileSkyOffsetScaled.width()) / 15.0;
318 auto adjusted_de0 = (
dec0().
Degrees() + tileSkyOffsetScaled.height());
319 SkyPoint sky_center(adjusted_ra0, adjusted_de0);
320 sky_center.apparentCoord(
static_cast<long double>(J2000), KStarsData::Instance()->ut().djd());
322 auto tile_center_ra0 = sky_center.ra0().Degrees();
324 auto rotation = tile_center_ra0 - mosaic_center_ra0;
327 if (abs(rotation) <= 90.0)
329 auto next_index = ++index;
330 MosaicTiles::OneTile tile = {pos, tile_center, sky_center, rotation, next_index};
338 y += (m_SShaped && (col % 2)) ? -yOffset : +yOffset;
345void MosaicTiles::draw(
QPainter *painter)
347 if (m_Tiles.size() == 0)
350 auto pixelScale = Options::zoomFactor() *
dms::DegToRad / 60.0;
351 const auto fovW = m_CameraFOV.width() * pixelScale;
352 const auto fovH = m_CameraFOV.height() * pixelScale;
353 const auto mosaicFOVW = m_MosaicFOV.width() * pixelScale;
354 const auto mosaicFOVH = m_MosaicFOV.height() * pixelScale;
355 const auto gridW = m_GridSize.width();
356 const auto gridH = m_GridSize.height();
358 QFont defaultFont = painter->
font();
359 QRect
const oneRect(-fovW / 2, -fovH / 2, fovW, fovH);
361 auto alphaValue = m_PainterAlpha;
363 if (m_PainterAlphaAuto)
371 if (m_Tiles.size() > 1)
372 alphaValue = (40 - m_Overlap / 2);
379 painter->
setPen(QPen(painter->
brush(), 2, Qt::PenStyle::DotLine));
380 painter->
drawRect(QRectF(QPointF(-mosaicFOVW / 2, -mosaicFOVH / 2), QSizeF(mosaicFOVW, mosaicFOVH)));
383 QBrush tileBrush(QColor(0, 255, 0, (200 * alphaValue) / 100),
Qt::SolidPattern);
386 for (
int row = 0; row < gridH; row++)
388 for (
int col = 0; col < gridW; col++)
390 auto tile = oneTile(row, col);
395 painter->
translate(tile->center * pixelScale);
396 painter->
rotate(tile->rotation);
409 for (
int row = 0; row < gridH; row++)
411 for (
int col = 0; col < gridW; col++)
413 auto tile = oneTile(row, col);
418 painter->
translate(tile->center * pixelScale);
423 painter->
rotate(tile->rotation);
426 painter->
setPen(m_TextPen);
428 defaultFont.
setPointSize(qMax(1., 4 * pixelScale * m_CameraFOV.width() / 60.));
432 defaultFont.
setPointSize(qMax(1., 4 * pixelScale * m_CameraFOV.width() / 60.));
435 .arg(tile->skyCenter.ra0().toHMSString(), tile->skyCenter.dec0().toDMSString()));
437 .arg(tile->rotation >= 0.01 ?
'+' : tile->rotation <= -0.01 ?
'-' :
'~')
438 .arg(abs(tile->rotation), 5,
'f', 2));
451 double cosTheta = cos(angleInRadians);
452 double sinTheta = sin(angleInRadians);
454 QPointF rotation_point;
456 rotation_point.
setX((cosTheta * (pointToRotate.
x() - centerPoint.
x()) -
457 sinTheta * (pointToRotate.
y() - centerPoint.
y()) + centerPoint.
x()));
458 rotation_point.
setY((sinTheta * (pointToRotate.
x() - centerPoint.
x()) +
459 cosTheta * (pointToRotate.
y() - centerPoint.
y()) + centerPoint.
y()));
461 return rotation_point;
464QSizeF MosaicTiles::calculateTargetMosaicFOV()
const
466 const auto xFOV = m_CameraFOV.
width() * (1 - m_Overlap / 100.0);
467 const auto yFOV = m_CameraFOV.height() * (1 - m_Overlap / 100.0);
468 return QSizeF(xFOV, yFOV);
471QSize MosaicTiles::mosaicFOVToGrid()
const
474 const auto xFOV = m_CameraFOV.
width() * (1 - m_Overlap / 100.0);
475 const auto yFOV = m_CameraFOV.height() * (1 - m_Overlap / 100.0);
476 const auto xTiles = 1 + ceil((m_MosaicFOV.width() - m_CameraFOV.width()) / xFOV);
477 const auto yTiles = 1 + ceil((m_MosaicFOV.height() - m_CameraFOV.height()) / yFOV);
478 return QSize(xTiles, yTiles);
481QSizeF MosaicTiles::calculateCameraFOV()
const
483 auto reducedFocalLength = m_FocalLength * m_FocalReducer;
486 206264.8062470963552 * m_CameraSize.
width() * m_PixelSize.width() / 60000.0 / reducedFocalLength;
488 206264.8062470963552 * m_CameraSize.height() * m_PixelSize.height() / 60000.0 / reducedFocalLength;
489 return QSizeF(fov_x, fov_y);
492void MosaicTiles::syncFOVs()
494 m_CameraFOV = calculateCameraFOV();
495 m_MosaicFOV = calculateTargetMosaicFOV();
Provides all necessary information about an object in the sky: its coordinates, name(s),...
const CachingDms & dec() const
SkyPoint(const dms &r, const dms &d)
Default constructor: Sets RA, Dec and RA0, Dec0 according to arguments.
const CachingDms & ra0() const
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
const CachingDms & ra() const
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
const CachingDms & dec0() const
void setDec0(dms d)
Sets Dec0, the catalog Declination.
virtual void setD(const double &x)
Sets floating-point value of angle, in degrees.
const double & Degrees() const
static constexpr double DegToRad
DegToRad is a const static member equal to the number of radians in one degree (dms::PI/180....
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
void setPointSize(int pointSize)
double toDouble(QStringView s, bool *ok) const const
int toInt(QStringView s, bool *ok) const const
const QBrush & brush() const const
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
const QFont & font() const const
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void translate(const QPoint &offset)
qreal width() const const