File indexing completed on 2024-03-24 15:18:02
0001 /* 0002 SPDX-FileCopyrightText: 2007 Jason Harris <kstars@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "avtplotwidget.h" 0008 0009 #include "kstarsdata.h" 0010 #include "Options.h" 0011 0012 #include <QWidget> 0013 #include <QMouseEvent> 0014 #include <QPainter> 0015 #include <QTime> 0016 #include <QLinearGradient> 0017 0018 #include <KLocalizedString> 0019 #include <KPlotting/KPlotObject> 0020 #include <QDebug> 0021 0022 AVTPlotWidget::AVTPlotWidget(QWidget *parent) : KPlotWidget(parent) 0023 { 0024 setAntialiasing(true); 0025 0026 MousePoint = QPoint(-1, -1); 0027 } 0028 0029 void AVTPlotWidget::mousePressEvent(QMouseEvent *e) 0030 { 0031 mouseMoveEvent(e); 0032 } 0033 0034 void AVTPlotWidget::mouseDoubleClickEvent(QMouseEvent *) 0035 { 0036 MousePoint = QPoint(-1, -1); 0037 update(); 0038 } 0039 0040 void AVTPlotWidget::mouseMoveEvent(QMouseEvent *e) 0041 { 0042 QRect checkRect(leftPadding(), topPadding(), pixRect().width(), pixRect().height()); 0043 int Xcursor = e->x(); 0044 int Ycursor = e->y(); 0045 0046 if (!checkRect.contains(e->x(), e->y())) 0047 { 0048 if (e->x() < checkRect.left()) 0049 Xcursor = checkRect.left(); 0050 if (e->x() > checkRect.right()) 0051 Xcursor = checkRect.right(); 0052 if (e->y() < checkRect.top()) 0053 Ycursor = checkRect.top(); 0054 if (e->y() > checkRect.bottom()) 0055 Ycursor = checkRect.bottom(); 0056 } 0057 0058 Xcursor -= leftPadding(); 0059 Ycursor -= topPadding(); 0060 0061 MousePoint = QPoint(Xcursor, Ycursor); 0062 update(); 0063 } 0064 0065 void AVTPlotWidget::paintEvent(QPaintEvent *e) 0066 { 0067 Q_UNUSED(e) 0068 0069 QPainter p; 0070 0071 p.begin(this); 0072 p.setRenderHint(QPainter::Antialiasing, antialiasing()); 0073 p.fillRect(rect(), backgroundColor()); 0074 p.translate(leftPadding(), topPadding()); 0075 0076 setPixRect(); 0077 p.setClipRect(pixRect()); 0078 p.setClipping(true); 0079 0080 int pW = pixRect().width(); 0081 int pH = pixRect().height(); 0082 0083 QColor SkyColor(0, 100, 200); 0084 /* 0085 if (Options::darkAppColors()) 0086 SkyColor = QColor(200, 0, 0); // use something red, visible through a red filter 0087 */ 0088 0089 // Draw gradient representing lunar interference in the sky 0090 if (MoonIllum > 0.01) // do this only if Moon illumination is reasonable so it's important 0091 { 0092 int moonrise = int(pW * (0.5 + MoonRise)); 0093 int moonset = int(pW * (MoonSet - 0.5)); 0094 if (moonset < 0) 0095 moonset += pW; 0096 if (moonrise > pW) 0097 moonrise -= pW; 0098 int moonalpha = int(10 + MoonIllum * 130); 0099 int fadewidth = 0100 pW * 0101 0.01; // pW * fraction of day to fade the moon brightness over (0.01 corresponds to roughly 15 minutes, 0.007 to 10 minutes), both before and after actual set. 0102 QColor MoonColor(255, 255, 255, moonalpha); 0103 0104 if (moonset < moonrise) 0105 { 0106 QLinearGradient grad = 0107 QLinearGradient(QPointF(moonset - fadewidth, 0.0), QPointF(moonset + fadewidth, 0.0)); 0108 grad.setColorAt(0, MoonColor); 0109 grad.setColorAt(1, Qt::transparent); 0110 p.fillRect(QRectF(0.0, 0.0, moonset + fadewidth, pH), 0111 grad); // gradient should be padded until moonset - fadewidth (see QLinearGradient docs) 0112 grad.setStart(QPointF(moonrise + fadewidth, 0.0)); 0113 grad.setFinalStop(QPointF(moonrise - fadewidth, 0.0)); 0114 p.fillRect(QRectF(moonrise - fadewidth, 0.0, pW - moonrise + fadewidth, pH), grad); 0115 } 0116 else 0117 { 0118 p.fillRect(QRectF(moonrise + fadewidth, 0.0, moonset - moonrise - 2 * fadewidth, pH), MoonColor); 0119 QLinearGradient grad = 0120 QLinearGradient(QPointF(moonrise + fadewidth, 0.0), QPointF(moonrise - fadewidth, 0.0)); 0121 grad.setColorAt(0, MoonColor); 0122 grad.setColorAt(1, Qt::transparent); 0123 p.fillRect(QRectF(0.0, 0.0, moonrise + fadewidth, pH), grad); 0124 grad.setStart(QPointF(moonset - fadewidth, 0.0)); 0125 grad.setFinalStop(QPointF(moonset + fadewidth, 0.0)); 0126 p.fillRect(QRectF(moonset - fadewidth, 0.0, pW - moonset, pH), grad); 0127 } 0128 } 0129 //draw daytime sky if the Sun rises for the current date/location 0130 if (SunMaxAlt > -18.0) 0131 { 0132 //Display centered on midnight, so need to modulate dawn/dusk by 0.5 0133 int rise = int(pW * (0.5 + SunRise)); 0134 int set = int(pW * (SunSet - 0.5)); 0135 int da = int(pW * (0.5 + Dawn)); 0136 int du = int(pW * (Dusk - 0.5)); 0137 0138 if (SunMinAlt > 0.0) 0139 { 0140 // The sun never set and the sky is always blue 0141 p.fillRect(rect(), SkyColor); 0142 } 0143 else if (SunMaxAlt < 0.0 && SunMinAlt < -18.0) 0144 { 0145 // The sun never rise but the sky is not completely dark 0146 QLinearGradient grad = QLinearGradient(QPointF(0.0, 0.0), QPointF(du, 0.0)); 0147 0148 QColor gradStartColor = SkyColor; 0149 gradStartColor.setAlpha((1 - (SunMaxAlt / -18.0)) * 255); 0150 0151 grad.setColorAt(0, gradStartColor); 0152 grad.setColorAt(1, Qt::transparent); 0153 p.fillRect(QRectF(0.0, 0.0, du, pH), grad); 0154 grad.setStart(QPointF(pW, 0.0)); 0155 grad.setFinalStop(QPointF(da, 0.0)); 0156 p.fillRect(QRectF(da, 0.0, pW, pH), grad); 0157 } 0158 else if (SunMaxAlt < 0.0 && SunMinAlt > -18.0) 0159 { 0160 // The sun never rise but the sky is NEVER completely dark 0161 QLinearGradient grad = QLinearGradient(QPointF(0.0, 0.0), QPointF(pW, 0.0)); 0162 0163 QColor gradStartEndColor = SkyColor; 0164 gradStartEndColor.setAlpha((1 - (SunMaxAlt / -18.0)) * 255); 0165 QColor gradMidColor = SkyColor; 0166 gradMidColor.setAlpha((1 - (SunMinAlt / -18.0)) * 255); 0167 0168 grad.setColorAt(0, gradStartEndColor); 0169 grad.setColorAt(0.5, gradMidColor); 0170 grad.setColorAt(1, gradStartEndColor); 0171 p.fillRect(QRectF(0.0, 0.0, pW, pH), grad); 0172 } 0173 else if (Dawn < 0.0) 0174 { 0175 // The sun sets and rises but the sky is never completely dark 0176 p.fillRect(0, 0, set, int(0.5 * pH), SkyColor); 0177 p.fillRect(rise, 0, pW, int(0.5 * pH), SkyColor); 0178 0179 QLinearGradient grad = QLinearGradient(QPointF(set, 0.0), QPointF(rise, 0.0)); 0180 0181 QColor gradMidColor = SkyColor; 0182 gradMidColor.setAlpha((1 - (SunMinAlt / -18.0)) * 255); 0183 0184 grad.setColorAt(0, SkyColor); 0185 grad.setColorAt(0.5, gradMidColor); 0186 grad.setColorAt(1, SkyColor); 0187 p.fillRect(QRectF(set, 0.0, rise - set, pH), grad); 0188 } 0189 else 0190 { 0191 p.fillRect(0, 0, set, pH, SkyColor); 0192 p.fillRect(rise, 0, pW, pH, SkyColor); 0193 0194 QLinearGradient grad = QLinearGradient(QPointF(set, 0.0), QPointF(du, 0.0)); 0195 grad.setColorAt(0, SkyColor); 0196 grad.setColorAt( 0197 1, 0198 Qt::transparent); // FIXME?: The sky appears black well before the actual end of twilight if the gradient is too slow (eg: latitudes above arctic circle) 0199 p.fillRect(QRectF(set, 0.0, du - set, pH), grad); 0200 0201 grad.setStart(QPointF(rise, 0.0)); 0202 grad.setFinalStop(QPointF(da, 0.0)); 0203 p.fillRect(QRectF(da, 0.0, rise - da, pH), grad); 0204 } 0205 } 0206 0207 //draw ground 0208 p.fillRect(0, int(0.5 * pH), pW, int(0.5 * pH), 0209 KStarsData::Instance()->colorScheme()->colorNamed( 0210 "HorzColor")); // asimha changed to use color from scheme. Formerly was QColor( "#002200" ) 0211 0212 foreach (KPlotObject *po, plotObjects()) 0213 { 0214 po->draw(&p, this); 0215 } 0216 0217 p.setClipping(false); 0218 drawAxes(&p); 0219 0220 //Add vertical line indicating "now" 0221 QFont smallFont = p.font(); 0222 smallFont.setPointSize(smallFont.pointSize()); // wat? 0223 if (geo) 0224 { 0225 QTime t = geo->UTtoLT(KStarsDateTime::currentDateTimeUtc()) 0226 .time(); // convert the current system clock time to the TZ corresponding to geo 0227 double x = 12.0 + t.hour() + t.minute() / 60.0 + t.second() / 3600.0; 0228 while (x > 24.0) 0229 x -= 24.0; 0230 int ix = int(x * pW / 24.0); //convert to screen pixel coords 0231 p.setPen(QPen(QBrush("white"), 2.0, Qt::DotLine)); 0232 p.drawLine(ix, 0, ix, pH); 0233 0234 //Label this vertical line with the current time 0235 p.save(); 0236 p.setFont(smallFont); 0237 p.translate(ix + 10, pH - 20); 0238 p.rotate(-90); 0239 p.drawText( 0240 0, 0, 0241 QLocale().toString(t, QLocale::ShortFormat)); // short format necessary to avoid false time-zone labeling 0242 p.restore(); 0243 } 0244 0245 //Draw crosshairs at clicked position 0246 if (MousePoint.x() > 0) 0247 { 0248 p.setPen(QPen(QBrush("gold"), 1.0, Qt::SolidLine)); 0249 p.drawLine(QLineF(MousePoint.x() + 0.5, 0.5, MousePoint.x() + 0.5, pixRect().height() - 0.5)); 0250 p.drawLine(QLineF(0.5, MousePoint.y() + 0.5, pixRect().width() - 0.5, MousePoint.y() + 0.5)); 0251 0252 //Label each crosshair line (time and altitude) 0253 p.setFont(smallFont); 0254 double a = (pH - MousePoint.y()) * 180.0 / pH - 90.0; 0255 p.drawText(20, MousePoint.y() + 10, QString::number(a, 'f', 2) + QChar(176)); 0256 0257 double h = MousePoint.x() * 24.0 / pW - 12.0; 0258 if (h < 0.0) 0259 h += 24.0; 0260 QTime t = QTime(int(h), int(60. * (h - int(h)))); 0261 p.save(); 0262 p.translate(MousePoint.x() + 10, pH - 20); 0263 p.rotate(-90); 0264 p.drawText( 0265 0, 0, 0266 QLocale().toString(t, QLocale::ShortFormat)); // short format necessary to avoid false time-zone labeling 0267 p.restore(); 0268 } 0269 0270 p.end(); 0271 } 0272 0273 void AVTPlotWidget::setDawnDuskTimes(double da, double du) 0274 { 0275 Dawn = da; 0276 Dusk = du; 0277 update(); // fixme: should we always be calling update? It's probably cheap enough that we can. 0278 } 0279 0280 void AVTPlotWidget::setMinMaxSunAlt(double min, double max) 0281 { 0282 SunMinAlt = min; 0283 SunMaxAlt = max; 0284 update(); 0285 } 0286 0287 void AVTPlotWidget::setSunRiseSetTimes(double sr, double ss) 0288 { 0289 SunRise = sr; 0290 SunSet = ss; 0291 update(); 0292 } 0293 0294 void AVTPlotWidget::setMoonRiseSetTimes(double mr, double ms) 0295 { 0296 MoonRise = mr; 0297 MoonSet = ms; 0298 update(); 0299 } 0300 0301 void AVTPlotWidget::setMoonIllum(double mi) 0302 { 0303 MoonIllum = mi; 0304 update(); 0305 }