Warning, file /education/kstars/kstars/skymaplite.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "skymaplite.h" 0007 #include "kstarsdata.h" 0008 #include "kstarslite.h" 0009 0010 #include "indi/inditelescopelite.h" 0011 #include "indi/clientmanagerlite.h" 0012 #include "kstarslite/skyitems/telescopesymbolsitem.h" 0013 0014 #include "projections/projector.h" 0015 #include "projections/lambertprojector.h" 0016 #include "projections/gnomonicprojector.h" 0017 #include "projections/stereographicprojector.h" 0018 #include "projections/orthographicprojector.h" 0019 #include "projections/azimuthalequidistantprojector.h" 0020 #include "projections/equirectangularprojector.h" 0021 0022 #include "kstarslite/skypointlite.h" 0023 #include "kstarslite/skyobjectlite.h" 0024 0025 #include "skylabeler.h" 0026 #include "Options.h" 0027 #include "skymesh.h" 0028 0029 #include "kstarslite/skyitems/rootnode.h" 0030 #include "kstarslite/skyitems/skynodes/skynode.h" 0031 0032 #include "ksplanetbase.h" 0033 #include "ksutils.h" 0034 0035 #include <QSGSimpleRectNode> 0036 //#include <QSGNode> 0037 #include <QBitmap> 0038 #include <QSGTexture> 0039 #include <QQuickWindow> 0040 #include <QLinkedList> 0041 #include <QQmlContext> 0042 #include <QScreen> 0043 0044 #include "kstarslite/deviceorientation.h" 0045 0046 namespace 0047 { 0048 // Draw bitmap for zoom cursor. Width is size of pen to draw with. 0049 QBitmap zoomCursorBitmap(int width) 0050 { 0051 QBitmap b(32, 32); 0052 b.fill(Qt::color0); 0053 int mx = 16, my = 16; 0054 // Begin drawing 0055 QPainter p; 0056 p.begin(&b); 0057 p.setPen(QPen(Qt::color1, width)); 0058 p.drawEllipse(mx - 7, my - 7, 14, 14); 0059 p.drawLine(mx + 5, my + 5, mx + 11, my + 11); 0060 p.end(); 0061 return b; 0062 } 0063 0064 // Draw bitmap for default cursor. Width is size of pen to draw with. 0065 QBitmap defaultCursorBitmap(int width) 0066 { 0067 QBitmap b(32, 32); 0068 b.fill(Qt::color0); 0069 int mx = 16, my = 16; 0070 // Begin drawing 0071 QPainter p; 0072 p.begin(&b); 0073 p.setPen(QPen(Qt::color1, width)); 0074 // 1. diagonal 0075 p.drawLine(mx - 2, my - 2, mx - 8, mx - 8); 0076 p.drawLine(mx + 2, my + 2, mx + 8, mx + 8); 0077 // 2. diagonal 0078 p.drawLine(mx - 2, my + 2, mx - 8, mx + 8); 0079 p.drawLine(mx + 2, my - 2, mx + 8, mx - 8); 0080 p.end(); 0081 return b; 0082 } 0083 } 0084 0085 SkyMapLite *SkyMapLite::pinstance = nullptr; 0086 0087 RootNode *SkyMapLite::m_rootNode = nullptr; 0088 0089 int SkyMapLite::starColorMode = 0; 0090 0091 SkyMapLite::SkyMapLite() 0092 : data(KStarsData::Instance()) 0093 #if defined(Q_OS_ANDROID) 0094 , 0095 m_deviceOrientation(new DeviceOrientation(this)) 0096 #endif 0097 { 0098 setAcceptHoverEvents(true); 0099 setAcceptedMouseButtons(Qt::AllButtons); 0100 setFlag(ItemHasContents, true); 0101 0102 m_rootNode = nullptr; 0103 m_magLim = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35; 0104 0105 setSlewing(false); 0106 0107 m_ClickedObjectLite = new SkyObjectLite; 0108 m_ClickedPointLite = new SkyPointLite; 0109 0110 qmlRegisterType<SkyObjectLite>("KStarsLite", 1, 0, "SkyObjectLite"); 0111 qmlRegisterType<SkyPointLite>("KStarsLite", 1, 0, "SkyPointLite"); 0112 0113 m_tapBeganTimer.setSingleShot(true); 0114 0115 setupProjector(); 0116 0117 // Set pinstance to yourself 0118 pinstance = this; 0119 0120 connect(this, SIGNAL(destinationChanged()), this, SLOT(slewFocus())); 0121 connect(KStarsData::Instance(), SIGNAL(skyUpdate(bool)), this, SLOT(slotUpdateSky(bool))); 0122 0123 ClientManagerLite *clientMng = KStarsLite::Instance()->clientManagerLite(); 0124 0125 connect(clientMng, &ClientManagerLite::telescopeAdded, 0126 [this](TelescopeLite * newTelescope) 0127 { 0128 this->m_newTelescopes.append(newTelescope->getDevice()); 0129 }); 0130 connect(clientMng, &ClientManagerLite::telescopeRemoved, 0131 [this](TelescopeLite * newTelescope) 0132 { 0133 this->m_delTelescopes.append(newTelescope->getDevice()); 0134 }); 0135 #if defined(Q_OS_ANDROID) 0136 //Automatic mode 0137 automaticModeTimer.setInterval(5); 0138 connect(&automaticModeTimer, SIGNAL(timeout()), this, SLOT(updateAutomaticMode())); 0139 setAutomaticMode(false); 0140 #endif 0141 } 0142 0143 QSGNode *SkyMapLite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) 0144 { 0145 Q_UNUSED(updatePaintNodeData); 0146 RootNode *n = static_cast<RootNode *>(oldNode); 0147 0148 /* This code deletes all nodes that are representing dynamic stars and not needed anymore (under construction) */ 0149 //qDeleteAll(m_deleteNodes); 0150 //m_deleteNodes.clear(); 0151 0152 if (m_loadingFinished && isInitialized) 0153 { 0154 if (!n) 0155 { 0156 n = new RootNode(); 0157 m_rootNode = n; 0158 } 0159 /** Add or delete telescope crosshairs **/ 0160 if (m_newTelescopes.count() > 0) 0161 { 0162 foreach (INDI::BaseDevice *telescope, m_newTelescopes) 0163 { 0164 n->telescopeSymbolsItem()->addTelescope(telescope); 0165 } 0166 m_newTelescopes.clear(); 0167 } 0168 0169 if (m_delTelescopes.count() > 0) 0170 { 0171 foreach (INDI::BaseDevice *telescope, m_delTelescopes) 0172 { 0173 n->telescopeSymbolsItem()->removeTelescope(telescope); 0174 } 0175 m_delTelescopes.clear(); 0176 } 0177 //Notify RootNode that textures for point node should be recreated 0178 n->update(clearTextures); 0179 clearTextures = false; 0180 } 0181 0182 //Memory Leaks test 0183 /*if(m_loadingFinished) { 0184 if(!n) { 0185 n = new RootNode(); 0186 } 0187 n->testLeakAdd(); 0188 n->update(); 0189 m_loadingFinished = false; 0190 } else { 0191 if (n) { 0192 n->testLeakDelete(); 0193 } 0194 m_loadingFinished = true; 0195 }*/ 0196 return n; 0197 } 0198 0199 double SkyMapLite::deleteLimit() 0200 { 0201 double lim = (MAXZOOM / MINZOOM) / sqrt(Options::zoomFactor()) / 3; //(MAXZOOM/MINZOOM - Options::zoomFactor())/130; 0202 return lim; 0203 } 0204 0205 void SkyMapLite::deleteSkyNode(SkyNode *skyNode) 0206 { 0207 m_deleteNodes.append(skyNode); 0208 } 0209 0210 QSGTexture *SkyMapLite::getCachedTexture(int size, char spType) 0211 { 0212 return textureCache[harvardToIndex(spType)][size]; 0213 } 0214 0215 SkyMapLite *SkyMapLite::createInstance() 0216 { 0217 delete pinstance; 0218 pinstance = new SkyMapLite(); 0219 return pinstance; 0220 } 0221 0222 void SkyMapLite::initialize(QQuickItem *parent) 0223 { 0224 if (parent) 0225 { 0226 setParentItem(parent); 0227 // Whenever the wrapper's(parent) dimensions changed, change SkyMapLite too 0228 connect(parent, &QQuickItem::widthChanged, this, &SkyMapLite::resizeItem); 0229 connect(parent, &QQuickItem::heightChanged, this, &SkyMapLite::resizeItem); 0230 0231 isInitialized = true; 0232 } 0233 0234 resizeItem(); /* Set initial size pf SkyMapLite. Without it on Android SkyMapLite is 0235 not displayed until screen orientation is not changed*/ 0236 0237 //Initialize images for stars 0238 initStarImages(); 0239 } 0240 0241 SkyMapLite::~SkyMapLite() 0242 { 0243 // Delete image cache 0244 for (auto &imgCache : imageCache) 0245 qDeleteAll(imgCache); 0246 0247 // Delete textures generated from image cache 0248 for (auto &tCache : textureCache) 0249 qDeleteAll(tCache); 0250 } 0251 0252 void SkyMapLite::setFocus(SkyPoint *p) 0253 { 0254 setFocus(p->ra(), p->dec()); 0255 } 0256 0257 void SkyMapLite::setFocus(const dms &ra, const dms &dec) 0258 { 0259 Options::setFocusRA(ra.Hours()); 0260 Options::setFocusDec(dec.Degrees()); 0261 0262 focus()->set(ra, dec); 0263 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0264 } 0265 0266 void SkyMapLite::setFocusAltAz(const dms &alt, const dms &az) 0267 { 0268 Options::setFocusRA(focus()->ra().Hours()); 0269 Options::setFocusDec(focus()->dec().Degrees()); 0270 focus()->setAlt(alt); 0271 focus()->setAz(az); 0272 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0273 0274 setSlewing(false); 0275 forceUpdate(); //need a total update, or slewing with the arrow keys doesn't work. 0276 } 0277 0278 void SkyMapLite::setDestination(const SkyPoint &p) 0279 { 0280 setDestination(p.ra(), p.dec()); 0281 } 0282 0283 void SkyMapLite::setDestination(const dms &ra, const dms &dec) 0284 { 0285 destination()->set(ra, dec); 0286 destination()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0287 emit destinationChanged(); 0288 } 0289 0290 void SkyMapLite::setDestinationAltAz(const dms &alt, const dms &az, bool altIsRefracted) 0291 { 0292 if (altIsRefracted) 0293 { 0294 // The alt in the SkyPoint is always actual, not apparent 0295 destination()->setAlt(SkyPoint::unrefract(alt)); 0296 } 0297 else 0298 { 0299 destination()->setAlt(alt); 0300 } 0301 destination()->setAz(az); 0302 destination()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0303 emit destinationChanged(); 0304 } 0305 0306 void SkyMapLite::setClickedPoint(SkyPoint *f) 0307 { 0308 ClickedPoint = *f; 0309 m_ClickedPointLite->setPoint(f); 0310 } 0311 0312 void SkyMapLite::setClickedObject(SkyObject *o) 0313 { 0314 ClickedObject = o; 0315 m_ClickedObjectLite->setObject(o); 0316 } 0317 0318 void SkyMapLite::setFocusObject(SkyObject *o) 0319 { 0320 FocusObject = o; 0321 if (FocusObject) 0322 Options::setFocusObject(FocusObject->name()); 0323 else 0324 Options::setFocusObject(i18n("nothing")); 0325 } 0326 0327 void SkyMapLite::slotCenter() 0328 { 0329 /*KStars* kstars = KStars::Instance(); 0330 TrailObject* trailObj = dynamic_cast<TrailObject*>( focusObject() );*/ 0331 0332 setFocusPoint(clickedPoint()); 0333 if (Options::useAltAz()) 0334 { 0335 focusPoint()->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false); 0336 focusPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0337 } 0338 else 0339 { 0340 focusPoint()->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false); 0341 } 0342 qDebug() << "Centering on " << focusPoint()->ra().toHMSString() << " " << focusPoint()->dec().toDMSString(); 0343 0344 //clear the planet trail of old focusObject, if it was temporary 0345 /*if( trailObj && data->temporaryTrail ) { 0346 trailObj->clearTrail(); 0347 data->temporaryTrail = false; 0348 }*/ 0349 0350 //If the requested object is below the opaque horizon, issue a warning message 0351 //(unless user is already pointed below the horizon) 0352 if (Options::useAltAz() && Options::showGround() && focus()->alt().Degrees() > SkyPoint::altCrit && 0353 focusPoint()->alt().Degrees() <= SkyPoint::altCrit) 0354 { 0355 QString caption = i18n("Requested Position Below Horizon"); 0356 QString message = i18n("The requested position is below the horizon.\nWould you like to go there anyway?"); 0357 /*if ( KMessageBox::warningYesNo( this, message, caption, 0358 KGuiItem(i18n("Go Anyway")), KGuiItem(i18n("Keep Position")), "dag_focus_below_horiz" )==KMessageBox::No ) { 0359 setClickedObject( nullptr ); 0360 setFocusObject( nullptr ); 0361 Options::setIsTracking( false ); 0362 0363 return; 0364 }*/ 0365 } 0366 0367 //set FocusObject before slewing. Otherwise, KStarsData::updateTime() can reset 0368 //destination to previous object... 0369 setFocusObject(ClickedObject); 0370 Options::setIsTracking(true); 0371 /*if ( kstars ) { 0372 kstars->actionCollection()->action("track_object")->setIcon( QIcon::fromTheme("document-encrypt") ); 0373 kstars->actionCollection()->action("track_object")->setText( i18n( "Stop &Tracking" ) ); 0374 }*/ 0375 0376 //If focusObject is a SS body and doesn't already have a trail, set the temporaryTrail 0377 0378 /*if( Options::useAutoTrail() && trailObj && trailObj->hasTrail() ) { 0379 trailObj->addToTrail(); 0380 data->temporaryTrail = true; 0381 }*/ 0382 0383 //update the destination to the selected coordinates 0384 if (Options::useAltAz()) 0385 { 0386 setDestinationAltAz(focusPoint()->alt(), focusPoint()->az(), false); 0387 } 0388 else 0389 { 0390 setDestination(*focusPoint()); 0391 } 0392 0393 focusPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0394 0395 //display coordinates in statusBar 0396 emit mousePointChanged(focusPoint()); 0397 //showFocusCoords(); //update FocusBox 0398 //Lock center so that user could only zoom on touch-enabled devices 0399 } 0400 0401 void SkyMapLite::slewFocus() 0402 { 0403 //Don't slew if the mouse button is pressed 0404 //Also, no animated slews if the Manual Clock is active 0405 //08/2002: added possibility for one-time skipping of slew with snapNextFocus 0406 if (!mouseButtonDown) 0407 { 0408 bool goSlew = (Options::useAnimatedSlewing() && !data->snapNextFocus()) && 0409 !(data->clock()->isManualMode() && data->clock()->isActive()); 0410 if (goSlew) 0411 { 0412 double dX, dY; 0413 double maxstep = 10.0; 0414 if (Options::useAltAz()) 0415 { 0416 dX = destination()->az().Degrees() - focus()->az().Degrees(); 0417 dY = destination()->alt().Degrees() - focus()->alt().Degrees(); 0418 } 0419 else 0420 { 0421 dX = destination()->ra().Degrees() - focus()->ra().Degrees(); 0422 dY = destination()->dec().Degrees() - focus()->dec().Degrees(); 0423 } 0424 0425 //switch directions to go the short way around the celestial sphere, if necessary. 0426 dX = KSUtils::reduceAngle(dX, -180.0, 180.0); 0427 0428 double r0 = sqrt(dX * dX + dY * dY); 0429 if (r0 < 20.0) //smaller slews have smaller maxstep 0430 { 0431 maxstep *= (10.0 + 0.5 * r0) / 20.0; 0432 } 0433 double step = 0.1; 0434 double r = r0; 0435 while (r > step) 0436 { 0437 //DEBUG 0438 //qDebug() << step << ": " << r << ": " << r0 << endl; 0439 double fX = dX / r; 0440 double fY = dY / r; 0441 0442 if (Options::useAltAz()) 0443 { 0444 focus()->setAlt(focus()->alt().Degrees() + fY * step); 0445 focus()->setAz(dms(focus()->az().Degrees() + fX * step).reduce()); 0446 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0447 } 0448 else 0449 { 0450 fX = fX / 15.; //convert RA degrees to hours 0451 SkyPoint newFocus(focus()->ra().Hours() + fX * step, focus()->dec().Degrees() + fY * step); 0452 setFocus(&newFocus); 0453 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0454 } 0455 0456 setSlewing(true); 0457 0458 forceUpdate(); 0459 qApp->processEvents(); //keep up with other stuff 0460 0461 if (Options::useAltAz()) 0462 { 0463 dX = destination()->az().Degrees() - focus()->az().Degrees(); 0464 dY = destination()->alt().Degrees() - focus()->alt().Degrees(); 0465 } 0466 else 0467 { 0468 dX = destination()->ra().Degrees() - focus()->ra().Degrees(); 0469 dY = destination()->dec().Degrees() - focus()->dec().Degrees(); 0470 } 0471 0472 //switch directions to go the short way around the celestial sphere, if necessary. 0473 dX = KSUtils::reduceAngle(dX, -180.0, 180.0); 0474 r = sqrt(dX * dX + dY * dY); 0475 0476 //Modify step according to a cosine-shaped profile 0477 //centered on the midpoint of the slew 0478 //NOTE: don't allow the full range from -PI/2 to PI/2 0479 //because the slew will never reach the destination as 0480 //the speed approaches zero at the end! 0481 double t = dms::PI * (r - 0.5 * r0) / (1.05 * r0); 0482 step = cos(t) * maxstep; 0483 } 0484 } 0485 0486 //Either useAnimatedSlewing==false, or we have slewed, and are within one step of destination 0487 //set focus=destination. 0488 if (Options::useAltAz()) 0489 { 0490 setFocusAltAz(destination()->alt(), destination()->az()); 0491 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0492 } 0493 else 0494 { 0495 setFocus(destination()); 0496 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0497 } 0498 0499 setSlewing(false); 0500 0501 //Turn off snapNextFocus, we only want it to happen once 0502 if (data->snapNextFocus()) 0503 { 0504 data->setSnapNextFocus(false); 0505 } 0506 0507 //Start the HoverTimer. if the user leaves the mouse in place after a slew, 0508 //we want to attach a label to the nearest object. 0509 if (Options::useHoverLabel()) 0510 m_HoverTimer.start(HOVER_INTERVAL); 0511 0512 forceUpdate(); 0513 } 0514 } 0515 0516 void SkyMapLite::slotClockSlewing() 0517 { 0518 //If the current timescale exceeds slewTimeScale, set clockSlewing=true, and stop the clock. 0519 if ((fabs(data->clock()->scale()) > Options::slewTimeScale()) ^ clockSlewing) 0520 { 0521 data->clock()->setManualMode(!clockSlewing); 0522 clockSlewing = !clockSlewing; 0523 // don't change automatically the DST status 0524 KStarsLite *kstars = KStarsLite::Instance(); 0525 if (kstars) 0526 kstars->updateTime(false); 0527 } 0528 } 0529 0530 /*void SkyMapLite::updateFocus() { 0531 if( slewing ) 0532 return; 0533 0534 //Tracking on an object 0535 if ( Options::isTracking() && focusObject() != nullptr ) { 0536 if ( Options::useAltAz() ) { 0537 //Tracking any object in Alt/Az mode requires focus updates 0538 focusObject()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0539 setFocusAltAz( focusObject()->alt(), focusObject()->az() ); 0540 focus()->HorizontalToEquatorial( data->lst(), data->geo()->lat() ); 0541 setDestination( *focus() ); 0542 } else { 0543 //Tracking in equatorial coords 0544 setFocus( focusObject() ); 0545 focus()->EquatorialToHorizontal( data->lst(), data->geo()->lat() ); 0546 setDestination( *focus() ); 0547 } 0548 0549 //Tracking on empty sky 0550 } else if ( Options::isTracking() && focusPoint() != nullptr ) { 0551 if ( Options::useAltAz() ) { 0552 //Tracking on empty sky in Alt/Az mode 0553 setFocus( focusPoint() ); 0554 focus()->EquatorialToHorizontal( data->lst(), data->geo()->lat() ); 0555 setDestination( *focus() ); 0556 } 0557 0558 // Not tracking and not slewing, let sky drift by 0559 // This means that horizontal coordinates are constant. 0560 } else { 0561 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat() ); 0562 } 0563 }*/ 0564 0565 void SkyMapLite::resizeItem() 0566 { 0567 if (parentItem()) 0568 { 0569 setWidth(parentItem()->width()); 0570 setHeight(parentItem()->height()); 0571 } 0572 forceUpdate(); 0573 } 0574 0575 void SkyMapLite::slotZoomIn() 0576 { 0577 setZoomFactor(Options::zoomFactor() * DZOOM); 0578 } 0579 0580 void SkyMapLite::slotZoomOut() 0581 { 0582 setZoomFactor(Options::zoomFactor() / DZOOM); 0583 } 0584 0585 void SkyMapLite::slotZoomDefault() 0586 { 0587 setZoomFactor(DEFAULTZOOM); 0588 } 0589 0590 void SkyMapLite::slotSelectObject(SkyObject *skyObj) 0591 { 0592 ClickedPoint = *skyObj; 0593 ClickedObject = skyObj; 0594 /*if ( Options::useAltAz() ) { 0595 setDestinationAltAz( skyObj->altRefracted(), skyObj->az() ); 0596 } else { 0597 setDestination( *skyObj ); 0598 }*/ 0599 //Update selected SkyObject (used in FindDialog, DetailDialog) 0600 m_ClickedObjectLite->setObject(skyObj); 0601 emit objectLiteChanged(); 0602 slotCenter(); 0603 } 0604 0605 void SkyMapLite::setSkyRotation(double skyRotation) 0606 { 0607 if (m_skyRotation != skyRotation) 0608 { 0609 m_skyRotation = skyRotation; 0610 emit skyRotationChanged(skyRotation); 0611 0612 if (skyRotation >= 0 && skyRotation < 90) 0613 { 0614 m_skyMapOrientation = SkyMapOrientation::Top0; 0615 } 0616 else if (skyRotation >= 90 && skyRotation < 180) 0617 { 0618 m_skyMapOrientation = SkyMapOrientation::Right90; 0619 } 0620 else if (skyRotation >= 180 && skyRotation < 270) 0621 { 0622 m_skyMapOrientation = SkyMapOrientation::Bottom180; 0623 } 0624 else if (skyRotation >= 270 && skyRotation < 360) 0625 { 0626 m_skyMapOrientation = SkyMapOrientation::Left270; 0627 } 0628 } 0629 } 0630 0631 void SkyMapLite::setZoomFactor(double factor) 0632 { 0633 Options::setZoomFactor(KSUtils::clamp(factor, MINZOOM, MAXZOOM)); 0634 0635 forceUpdate(); 0636 emit zoomChanged(); 0637 } 0638 0639 void SkyMapLite::forceUpdate() 0640 { 0641 setupProjector(); 0642 0643 // We delay one draw cycle before re-indexing 0644 // we MUST ensure CLines do not get re-indexed while we use DRAW_BUF 0645 // so we do it here. 0646 //m_CLines->reindex( &m_reindexNum ); 0647 // This queues re-indexing for the next draw cycle 0648 //m_reindexNum = KSNumbers( data->updateNum()->julianDay() ); 0649 0650 // This ensures that the JIT updates are synchronized for the entire draw 0651 // cycle so the sky moves as a single sheet. May not be needed. 0652 data->syncUpdateIDs(); 0653 0654 SkyMesh *m_skyMesh = SkyMesh::Instance(3); 0655 if (m_skyMesh) 0656 { 0657 // prepare the aperture 0658 // FIXME_FOV: We may want to rejigger this to allow 0659 // wide-angle views --hdevalence 0660 double radius = m_proj->fov(); 0661 if (radius > 180.0) 0662 radius = 180.0; 0663 0664 if (m_skyMesh->inDraw()) 0665 { 0666 printf("Warning: aborting concurrent SkyMapComposite::draw()\n"); 0667 return; 0668 } 0669 0670 //m_skyMesh->inDraw( true ); 0671 m_skyMesh->aperture(&Focus, radius + 1.0, DRAW_BUF); // divide by 2 for testing 0672 0673 // create the no-precess aperture if needed 0674 if (Options::showEquatorialGrid() || Options::showHorizontalGrid() || Options::showCBounds() || 0675 Options::showEquator()) 0676 { 0677 m_skyMesh->index(&Focus, radius + 1.0, NO_PRECESS_BUF); 0678 } 0679 } 0680 update(); 0681 } 0682 0683 void SkyMapLite::slotUpdateSky(bool now) 0684 { 0685 Q_UNUSED(now); 0686 updateFocus(); 0687 forceUpdate(); 0688 } 0689 0690 void SkyMapLite::updateFocus() 0691 { 0692 if (getSlewing()) 0693 return; 0694 0695 //Tracking on an object 0696 if (Options::isTracking() && focusObject() != nullptr) 0697 { 0698 if (Options::useAltAz()) 0699 { 0700 //Tracking any object in Alt/Az mode requires focus updates 0701 focusObject()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0702 setFocusAltAz(focusObject()->alt(), focusObject()->az()); 0703 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0704 setDestination(*focus()); 0705 } 0706 else 0707 { 0708 //Tracking in equatorial coords 0709 setFocus(focusObject()); 0710 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0711 setDestination(*focus()); 0712 } 0713 0714 //Tracking on empty sky 0715 } 0716 else if (Options::isTracking() && focusPoint() != nullptr) 0717 { 0718 if (Options::useAltAz()) 0719 { 0720 //Tracking on empty sky in Alt/Az mode 0721 setFocus(focusPoint()); 0722 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0723 setDestination(*focus()); 0724 } 0725 0726 // Not tracking and not slewing, let sky drift by 0727 // This means that horizontal coordinates are constant. 0728 } 0729 else 0730 { 0731 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); 0732 } 0733 } 0734 0735 void SkyMapLite::setupProjector() 0736 { 0737 //Update View Parameters for projection 0738 ViewParams p; 0739 p.focus = focus(); 0740 p.height = height(); 0741 p.width = width(); 0742 p.useAltAz = Options::useAltAz(); 0743 p.useRefraction = Options::useRefraction(); 0744 p.zoomFactor = Options::zoomFactor(); 0745 p.fillGround = Options::showGround(); 0746 0747 //Check if we need a new projector 0748 if (m_proj && Options::projection() == m_proj->type()) 0749 m_proj->setViewParams(p); 0750 else 0751 { 0752 delete m_proj; 0753 switch (Options::projection()) 0754 { 0755 case Projector::Gnomonic: 0756 m_proj = new GnomonicProjector(p); 0757 break; 0758 case Projector::Stereographic: 0759 m_proj = new StereographicProjector(p); 0760 break; 0761 case Projector::Orthographic: 0762 m_proj = new OrthographicProjector(p); 0763 break; 0764 case Projector::AzimuthalEquidistant: 0765 m_proj = new AzimuthalEquidistantProjector(p); 0766 break; 0767 case Projector::Equirectangular: 0768 m_proj = new EquirectangularProjector(p); 0769 break; 0770 case Projector::Lambert: 0771 default: 0772 //TODO: implement other projection classes 0773 m_proj = new LambertProjector(p); 0774 break; 0775 } 0776 } 0777 } 0778 0779 void SkyMapLite::setZoomMouseCursor() 0780 { 0781 mouseMoveCursor = false; // no mousemove cursor 0782 QBitmap cursor = zoomCursorBitmap(2); 0783 QBitmap mask = zoomCursorBitmap(4); 0784 setCursor(QCursor(cursor, mask)); 0785 } 0786 0787 void SkyMapLite::setDefaultMouseCursor() 0788 { 0789 mouseMoveCursor = false; // no mousemove cursor 0790 QBitmap cursor = defaultCursorBitmap(2); 0791 QBitmap mask = defaultCursorBitmap(3); 0792 setCursor(QCursor(cursor, mask)); 0793 } 0794 0795 void SkyMapLite::setMouseMoveCursor() 0796 { 0797 if (mouseButtonDown) 0798 { 0799 setCursor(Qt::SizeAllCursor); // cursor shape defined in qt 0800 mouseMoveCursor = true; 0801 } 0802 } 0803 0804 bool SkyMapLite::isSlewing() const 0805 { 0806 return (getSlewing() || (clockSlewing && data->clock()->isActive())); 0807 } 0808 0809 int SkyMapLite::harvardToIndex(char c) 0810 { 0811 // Convert spectral class to numerical index. 0812 // If spectral class is invalid return index for white star (A class) 0813 0814 switch (c) 0815 { 0816 case 'o': 0817 case 'O': 0818 return 0; 0819 case 'b': 0820 case 'B': 0821 return 1; 0822 case 'a': 0823 case 'A': 0824 return 2; 0825 case 'f': 0826 case 'F': 0827 return 3; 0828 case 'g': 0829 case 'G': 0830 return 4; 0831 case 'k': 0832 case 'K': 0833 return 5; 0834 case 'm': 0835 case 'M': 0836 return 6; 0837 // For unknown spectral class assume A class (white star) 0838 default: 0839 return 2; 0840 } 0841 } 0842 0843 QVector<QVector<QPixmap *>> SkyMapLite::getImageCache() 0844 { 0845 return imageCache; 0846 } 0847 0848 QSGTexture *SkyMapLite::textToTexture(QString text, QColor color, bool zoomFont) 0849 { 0850 if (isInitialized) 0851 { 0852 QFont f; 0853 0854 if (zoomFont) 0855 { 0856 f = SkyLabeler::Instance()->drawFont(); 0857 } 0858 else 0859 { 0860 f = SkyLabeler::Instance()->stdFont(); 0861 } 0862 0863 qreal ratio = window()->effectiveDevicePixelRatio(); 0864 0865 QFontMetrics fm(f); 0866 0867 int width = fm.width(text); 0868 int height = fm.height(); 0869 // double rotation = 0; 0870 0871 //// switch(m_skyMapOrientation) { 0872 //// case(SkyMapOrientation::Top0): 0873 //// width = fm.width(text); 0874 //// height = fm.height(); 0875 //// rotation = 0; 0876 //// break; 0877 //// case(SkyMapOrientation::Right90): 0878 //// width = fm.height(); 0879 //// height = fm.width(text); 0880 //// rotation = 90; 0881 //// case(SkyMapOrientation::Bottom180): 0882 ////// width = ; 0883 ////// height = ; 0884 //// rotation = 180; 0885 //// case(SkyMapOrientation::Left270): 0886 ////// width = ; 0887 ////// height; 0888 //// rotation = 270; 0889 //// } 0890 0891 f.setPointSizeF(f.pointSizeF() * ratio); 0892 0893 QImage label((width)*ratio, (height)*ratio, QImage::Format_ARGB32_Premultiplied); 0894 0895 label.fill(Qt::transparent); 0896 0897 m_painter.begin(&label); 0898 0899 m_painter.setFont(f); 0900 0901 m_painter.setPen(color); 0902 0903 // m_painter.drawRect(0,0, label.width(), label.height()); 0904 // m_painter.rotate(getSkyRotation()); 0905 m_painter.drawText(0, (height - fm.descent()) * ratio, text); 0906 0907 m_painter.end(); 0908 0909 QSGTexture *texture = window()->createTextureFromImage(label, QQuickWindow::TextureCanUseAtlas); 0910 return texture; 0911 } 0912 else 0913 { 0914 return nullptr; 0915 } 0916 } 0917 0918 void SkyMapLite::addFOVSymbol(const QString &FOVName, bool initialState) 0919 { 0920 m_FOVSymbols.append(FOVName); 0921 //Emit signal whenever new value was added 0922 emit symbolsFOVChanged(m_FOVSymbols); 0923 0924 m_FOVSymVisible.append(initialState); 0925 } 0926 0927 bool SkyMapLite::isFOVVisible(int index) 0928 { 0929 return m_FOVSymVisible.value(index); 0930 } 0931 0932 void SkyMapLite::setFOVVisible(int index, bool visible) 0933 { 0934 if (index >= 0 && index < m_FOVSymVisible.size()) 0935 { 0936 m_FOVSymVisible[index] = visible; 0937 forceUpdate(); 0938 } 0939 } 0940 0941 void SkyMapLite::setSlewing(bool newSlewing) 0942 { 0943 if (m_slewing != newSlewing) 0944 { 0945 m_slewing = newSlewing; 0946 emit slewingChanged(newSlewing); 0947 } 0948 } 0949 0950 void SkyMapLite::setCenterLocked(bool centerLocked) 0951 { 0952 m_centerLocked = centerLocked; 0953 emit centerLockedChanged(centerLocked); 0954 } 0955 0956 void SkyMapLite::setAutomaticMode(bool automaticMode) 0957 { 0958 #if defined(Q_OS_ANDROID) 0959 if (m_automaticMode != automaticMode) 0960 { 0961 m_automaticMode = automaticMode; 0962 if (automaticMode) 0963 { 0964 m_deviceOrientation->startSensors(); 0965 automaticModeTimer.start(); 0966 } 0967 else 0968 { 0969 automaticModeTimer.stop(); 0970 m_deviceOrientation->stopSensors(); 0971 } 0972 } 0973 #else 0974 Q_UNUSED(automaticMode); 0975 #endif 0976 } 0977 0978 void SkyMapLite::updateAutomaticMode() 0979 { 0980 #if defined(Q_OS_ANDROID) 0981 m_deviceOrientation->getOrientation(); 0982 if (Options::useRefraction() && Options::useAltAz()) 0983 { 0984 setFocusAltAz(SkyPoint::unrefract(dms(m_deviceOrientation->getAltitude())), dms(m_deviceOrientation->getAzimuth())); 0985 } 0986 else 0987 { 0988 setFocusAltAz(dms(m_deviceOrientation->getAltitude()), dms(m_deviceOrientation->getAzimuth())); 0989 } 0990 0991 setSkyRotation(-1 * m_deviceOrientation->getRoll()); 0992 #endif 0993 } 0994 0995 void SkyMapLite::initStarImages() 0996 { 0997 if (isInitialized) 0998 { 0999 //Delete all existing pixmaps 1000 if (imageCache.length() != 0) 1001 { 1002 foreach (QVector<QPixmap *> vec, imageCache) 1003 { 1004 qDeleteAll(vec.begin(), vec.end()); 1005 } 1006 clearTextures = true; 1007 } 1008 1009 imageCache = QVector<QVector<QPixmap *>>(nSPclasses); 1010 1011 QMap<char, QColor> ColorMap; 1012 const int starColorIntensity = Options::starColorIntensity(); 1013 1014 //On high-dpi screens star will look pixelized if don't multiply scaling factor by this ratio 1015 //Check PointNode::setNode() to see how it works 1016 qreal ratio = window()->effectiveDevicePixelRatio(); 1017 1018 switch (Options::starColorMode()) 1019 { 1020 case 1: // Red stars. 1021 ColorMap.insert('O', QColor::fromRgb(255, 0, 0)); 1022 ColorMap.insert('B', QColor::fromRgb(255, 0, 0)); 1023 ColorMap.insert('A', QColor::fromRgb(255, 0, 0)); 1024 ColorMap.insert('F', QColor::fromRgb(255, 0, 0)); 1025 ColorMap.insert('G', QColor::fromRgb(255, 0, 0)); 1026 ColorMap.insert('K', QColor::fromRgb(255, 0, 0)); 1027 ColorMap.insert('M', QColor::fromRgb(255, 0, 0)); 1028 break; 1029 case 2: // Black stars. 1030 ColorMap.insert('O', QColor::fromRgb(0, 0, 0)); 1031 ColorMap.insert('B', QColor::fromRgb(0, 0, 0)); 1032 ColorMap.insert('A', QColor::fromRgb(0, 0, 0)); 1033 ColorMap.insert('F', QColor::fromRgb(0, 0, 0)); 1034 ColorMap.insert('G', QColor::fromRgb(0, 0, 0)); 1035 ColorMap.insert('K', QColor::fromRgb(0, 0, 0)); 1036 ColorMap.insert('M', QColor::fromRgb(0, 0, 0)); 1037 break; 1038 case 3: // White stars 1039 ColorMap.insert('O', QColor::fromRgb(255, 255, 255)); 1040 ColorMap.insert('B', QColor::fromRgb(255, 255, 255)); 1041 ColorMap.insert('A', QColor::fromRgb(255, 255, 255)); 1042 ColorMap.insert('F', QColor::fromRgb(255, 255, 255)); 1043 ColorMap.insert('G', QColor::fromRgb(255, 255, 255)); 1044 ColorMap.insert('K', QColor::fromRgb(255, 255, 255)); 1045 ColorMap.insert('M', QColor::fromRgb(255, 255, 255)); 1046 case 0: // Real color 1047 default: // And use real color for everything else 1048 ColorMap.insert('O', QColor::fromRgb(0, 0, 255)); 1049 ColorMap.insert('B', QColor::fromRgb(0, 200, 255)); 1050 ColorMap.insert('A', QColor::fromRgb(0, 255, 255)); 1051 ColorMap.insert('F', QColor::fromRgb(200, 255, 100)); 1052 ColorMap.insert('G', QColor::fromRgb(255, 255, 0)); 1053 ColorMap.insert('K', QColor::fromRgb(255, 100, 0)); 1054 ColorMap.insert('M', QColor::fromRgb(255, 0, 0)); 1055 } 1056 1057 for (char color : ColorMap.keys()) 1058 { 1059 //Add new spectral class 1060 1061 QPixmap BigImage(15, 15); 1062 BigImage.fill(Qt::transparent); 1063 1064 QPainter p; 1065 p.begin(&BigImage); 1066 1067 if (Options::starColorMode() == 0) 1068 { 1069 qreal h, s, v, a; 1070 p.setRenderHint(QPainter::Antialiasing, false); 1071 QColor starColor = ColorMap[color]; 1072 starColor.getHsvF(&h, &s, &v, &a); 1073 for (int i = 0; i < 8; i++) 1074 { 1075 for (int j = 0; j < 8; j++) 1076 { 1077 qreal x = i - 7; 1078 qreal y = j - 7; 1079 qreal dist = sqrt(x * x + y * y) / 7.0; 1080 starColor.setHsvF(h, qMin(qreal(1), dist < (10 - starColorIntensity) / 10.0 ? 0 : dist), v, 1081 qMax(qreal(0), dist < (10 - starColorIntensity) / 20.0 ? 1 : 1 - dist)); 1082 p.setPen(starColor); 1083 p.drawPoint(i, j); 1084 p.drawPoint((14 - i), j); 1085 p.drawPoint(i, (14 - j)); 1086 p.drawPoint((14 - i), (14 - j)); 1087 } 1088 } 1089 } 1090 else 1091 { 1092 p.setRenderHint(QPainter::Antialiasing, true); 1093 p.setPen(QPen(ColorMap[color], 2.0)); 1094 p.setBrush(p.pen().color()); 1095 p.drawEllipse(QRectF(2, 2, 10, 10)); 1096 } 1097 p.end(); 1098 //[nSPclasses][nStarSizes]; 1099 // Cache array slice 1100 1101 QVector<QPixmap *> *pmap = &imageCache[harvardToIndex(color)]; 1102 pmap->append(new QPixmap(BigImage)); 1103 for (int size = 1; size < nStarSizes; size++) 1104 { 1105 pmap->append(new QPixmap( 1106 BigImage.scaled(size * ratio, size * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation))); 1107 } 1108 } 1109 //} 1110 starColorMode = Options::starColorMode(); 1111 } 1112 }