Kstars

linelistlabel.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 James B. Bowlin <[email protected]>
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 
16 LineListLabel::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 
28 void 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 
50 void 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 
84 void 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 
174 QPointF 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 }
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:380
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
const T & at(int i) const const
qreal x() const const
qreal y() const const
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
const Projector * projector() const
Get the current projector.
Definition: skymap.h:299
bool checkVisibility(const SkyPoint *p) const
Determine if the skypoint p is likely to be visible in the display window.
Definition: projector.cpp:183
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Aug 11 2022 04:00:01 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.