Kstars

linelistlabel.cpp
1/*
2 SPDX-FileCopyrightText: 2007 James B. Bowlin <bowlin@mindspring.com>
3 SPDX-License-Identifier: GPL-2.0-or-later
4*/
5
6#include "linelistlabel.h"
7
8#include "linelist.h"
9#include "Options.h"
10#ifndef KSTARS_LITE
11#include "skymap.h"
12#endif
13#include "skylabeler.h"
14#include "projections/projector.h"
15
16LineListLabel::LineListLabel(const QString &text) : m_text(text)
17{
18 m_skyLabeler = SkyLabeler::Instance();
19
20 // prevent a crash if drawGuideLabel() is called before reset()
21 for (int i = 0; i < 4; i++)
22 {
23 m_labList[i] = nullptr;
24 m_labIndex[i] = 0;
25 }
26}
27
28void LineListLabel::reset()
29{
30 // These are the indices of the farthest left point, farthest right point,
31 // etc. The are data members so the drawLabels() routine can use them.
32 // Zero indicates an index that was never set and is considered invalid
33 // inside of drawLabels().
34 for (int i = 0; i < 4; i++)
35 {
36 m_labList[i] = nullptr;
37 m_labIndex[i] = 0;
38 }
39
40 // These are used to keep track of the element that is farthest left,
41 // farthest right, etc.
42 m_farLeft = 100000.0;
43 m_farRight = 0.0;
44 m_farTop = 100000.0;
45 m_farBot = 0.0;
46
47 m_skyLabeler->getMargins(m_text, &m_marginLeft, &m_marginRight, &m_marginTop, &m_marginBot);
48}
49
50void LineListLabel::updateLabelCandidates(qreal x, qreal y, LineList *lineList, int i)
51{
52 if (i < 1)
53 return;
54
55 if (x < m_marginLeft || x > m_marginRight || y < m_marginTop || y > m_marginBot)
56 return;
57
58 if (x < m_farLeft)
59 {
60 m_labIndex[LeftCandidate] = i;
61 m_labList[LeftCandidate] = lineList;
62 m_farLeft = x;
63 }
64 if (x > m_farRight)
65 {
66 m_labIndex[RightCandidate] = i;
67 m_labList[RightCandidate] = lineList;
68 m_farRight = x;
69 }
70 if (y > m_farBot)
71 {
72 m_labIndex[BotCandidate] = i;
73 m_labList[BotCandidate] = lineList;
74 m_farBot = x;
75 }
76 if (y < m_farTop)
77 {
78 m_labIndex[TopCandidate] = i;
79 m_labList[TopCandidate] = lineList;
80 m_farTop = x;
81 }
82}
83
84void LineListLabel::draw()
85{
86#ifndef KSTARS_LITE
87 const Projector *proj = SkyMap::Instance()->projector();
88
89 double comfyAngle = 40.0; // the first valid candidate with an angle
90 // smaller than this gets displayed. If you set
91 // this to > 90. then the first valid candidate
92 // will be displayed, regardless of angle.
93
94 // We store info about the four candidate points in arrays to make several
95 // of the steps easier, particularly choosing the valid candidate with the
96 // smallest angle from the horizontal.
97
98 int idx[4]; // index of candidate
99 LineList *list[4]; // LineList of candidate
100 double a[4] = { 360.0, 360.0, 360.0, 360.0 }; // angle, default to large value
101 QPointF o[4]; // candidate point
102 bool okay[4] = { true, true, true, true }; // flag candidate false if it
103 // overlaps a previous label.
104
105 // We no longer adjust the order but if we were to it would be here
106 static int Order[4] = { LeftCandidate, BotCandidate, TopCandidate, LeftCandidate };
107
108 for (int j = 0; j < 4; j++)
109 {
110 idx[j] = m_labIndex[Order[j]];
111 list[j] = m_labList[Order[j]];
112 }
113
114 // Make sure start with a valid candidate
115 int first = 0;
116 for (; first < 4; first++)
117 {
118 if (idx[first])
119 break;
120 }
121
122 // return if there are no valid candidates
123 if (first >= 4)
124 return;
125
126 // Try the points in order and print the label if we can draw it at
127 // a comfortable angle for viewing;
128 for (int j = first; j < 4; j++)
129 {
130 o[j] = angleAt(proj, list[j], idx[j], &a[j]);
131
132 if (!idx[j] || !proj->checkVisibility(list[j]->at(idx[j]).get()))
133 {
134 okay[j] = false;
135 continue;
136 }
137
138 if (fabs(a[j]) > comfyAngle)
139 continue;
140
141 if (m_skyLabeler->drawGuideLabel(o[j], m_text, a[j]))
142 return;
143
144 okay[j] = false;
145 }
146
147 //--- No angle was comfy so pick the one with the smallest angle ---
148
149 // Index of the index/angle/point that gets displayed
150 int best = first;
151
152 // find first valid candidate that does not overlap existing labels
153 for (; best < 4; best++)
154 {
155 if (idx[best] && okay[best])
156 break;
157 }
158
159 // return if all candidates either overlap or are invalid
160 if (best >= 4)
161 return;
162
163 // find the valid non-overlap candidate with the smallest angle
164 for (int j = best + 1; j < 4; j++)
165 {
166 if (idx[j] && okay[j] && fabs(a[j]) < fabs(a[best]))
167 best = j;
168 }
169
170 m_skyLabeler->drawGuideLabel(o[best], m_text, a[best]);
171#endif
172}
173
174QPointF LineListLabel::angleAt(const Projector *proj, LineList *list, int i, double *angle)
175{
176 const SkyPoint *pThis = list->at(i).get();
177 const SkyPoint *pLast = list->at(i-1).get();
178
179 QPointF oThis = proj->toScreen(pThis);
180 QPointF oLast = proj->toScreen(pLast);
181
182 double sx = double(oThis.x() - oLast.x());
183 double sy = double(oThis.y() - oLast.y());
184
185 *angle = atan2(sy, sx) * 180.0 / dms::PI;
186
187 // FIXME: use clamp in KSUtils
188 // Never draw the label upside down
189 if (*angle < -90.0)
190 *angle += 180.0;
191 if (*angle > 90.0)
192 *angle -= 180.0;
193
194 return oThis;
195}
A simple data container used by LineListIndex.
Definition linelist.h:25
The Projector class is the primary class that serves as an interface to handle projections.
Definition projector.h:58
QPointF toScreen(const SkyPoint *o, bool oRefract=true, bool *onVisibleHemisphere=nullptr) const
This is exactly the same as toScreenVec but it returns a QPointF.
Definition projector.cpp:93
bool checkVisibility(const SkyPoint *p) const
Determine if the skypoint p is likely to be visible in the display window.
void getMargins(const QString &text, float *left, float *right, float *top, float *bot)
sets four margins for help in keeping labels entirely on the screen.
bool drawGuideLabel(QPointF &o, const QString &text, double angle)
Tries to draw the text at the position and angle specified.
const Projector * projector() const
Get the current projector.
Definition skymap.h:300
The sky coordinates of a point in the sky.
Definition skypoint.h:45
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
Definition dms.h:385
KIOCORE_EXPORT QStringList list(const QString &fileClass)
const_reference at(qsizetype i) const const
qreal x() const const
qreal y() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:52 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.