Warning, file /education/kstars/kstars/skycomponents/linelistlabel.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: 2007 James B. Bowlin <bowlin@mindspring.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "linelistlabel.h" 0007 0008 #include "linelist.h" 0009 #include "Options.h" 0010 #ifndef KSTARS_LITE 0011 #include "skymap.h" 0012 #endif 0013 #include "skylabeler.h" 0014 #include "projections/projector.h" 0015 0016 LineListLabel::LineListLabel(const QString &text) : m_text(text) 0017 { 0018 m_skyLabeler = SkyLabeler::Instance(); 0019 0020 // prevent a crash if drawGuideLabel() is called before reset() 0021 for (int i = 0; i < 4; i++) 0022 { 0023 m_labList[i] = nullptr; 0024 m_labIndex[i] = 0; 0025 } 0026 } 0027 0028 void LineListLabel::reset() 0029 { 0030 // These are the indices of the farthest left point, farthest right point, 0031 // etc. The are data members so the drawLabels() routine can use them. 0032 // Zero indicates an index that was never set and is considered invalid 0033 // inside of drawLabels(). 0034 for (int i = 0; i < 4; i++) 0035 { 0036 m_labList[i] = nullptr; 0037 m_labIndex[i] = 0; 0038 } 0039 0040 // These are used to keep track of the element that is farthest left, 0041 // farthest right, etc. 0042 m_farLeft = 100000.0; 0043 m_farRight = 0.0; 0044 m_farTop = 100000.0; 0045 m_farBot = 0.0; 0046 0047 m_skyLabeler->getMargins(m_text, &m_marginLeft, &m_marginRight, &m_marginTop, &m_marginBot); 0048 } 0049 0050 void LineListLabel::updateLabelCandidates(qreal x, qreal y, LineList *lineList, int i) 0051 { 0052 if (i < 1) 0053 return; 0054 0055 if (x < m_marginLeft || x > m_marginRight || y < m_marginTop || y > m_marginBot) 0056 return; 0057 0058 if (x < m_farLeft) 0059 { 0060 m_labIndex[LeftCandidate] = i; 0061 m_labList[LeftCandidate] = lineList; 0062 m_farLeft = x; 0063 } 0064 if (x > m_farRight) 0065 { 0066 m_labIndex[RightCandidate] = i; 0067 m_labList[RightCandidate] = lineList; 0068 m_farRight = x; 0069 } 0070 if (y > m_farBot) 0071 { 0072 m_labIndex[BotCandidate] = i; 0073 m_labList[BotCandidate] = lineList; 0074 m_farBot = x; 0075 } 0076 if (y < m_farTop) 0077 { 0078 m_labIndex[TopCandidate] = i; 0079 m_labList[TopCandidate] = lineList; 0080 m_farTop = x; 0081 } 0082 } 0083 0084 void LineListLabel::draw() 0085 { 0086 #ifndef KSTARS_LITE 0087 const Projector *proj = SkyMap::Instance()->projector(); 0088 0089 double comfyAngle = 40.0; // the first valid candidate with an angle 0090 // smaller than this gets displayed. If you set 0091 // this to > 90. then the first valid candidate 0092 // will be displayed, regardless of angle. 0093 0094 // We store info about the four candidate points in arrays to make several 0095 // of the steps easier, particularly choosing the valid candidate with the 0096 // smallest angle from the horizontal. 0097 0098 int idx[4]; // index of candidate 0099 LineList *list[4]; // LineList of candidate 0100 double a[4] = { 360.0, 360.0, 360.0, 360.0 }; // angle, default to large value 0101 QPointF o[4]; // candidate point 0102 bool okay[4] = { true, true, true, true }; // flag candidate false if it 0103 // overlaps a previous label. 0104 0105 // We no longer adjust the order but if we were to it would be here 0106 static int Order[4] = { LeftCandidate, BotCandidate, TopCandidate, LeftCandidate }; 0107 0108 for (int j = 0; j < 4; j++) 0109 { 0110 idx[j] = m_labIndex[Order[j]]; 0111 list[j] = m_labList[Order[j]]; 0112 } 0113 0114 // Make sure start with a valid candidate 0115 int first = 0; 0116 for (; first < 4; first++) 0117 { 0118 if (idx[first]) 0119 break; 0120 } 0121 0122 // return if there are no valid candidates 0123 if (first >= 4) 0124 return; 0125 0126 // Try the points in order and print the label if we can draw it at 0127 // a comfortable angle for viewing; 0128 for (int j = first; j < 4; j++) 0129 { 0130 o[j] = angleAt(proj, list[j], idx[j], &a[j]); 0131 0132 if (!idx[j] || !proj->checkVisibility(list[j]->at(idx[j]).get())) 0133 { 0134 okay[j] = false; 0135 continue; 0136 } 0137 0138 if (fabs(a[j]) > comfyAngle) 0139 continue; 0140 0141 if (m_skyLabeler->drawGuideLabel(o[j], m_text, a[j])) 0142 return; 0143 0144 okay[j] = false; 0145 } 0146 0147 //--- No angle was comfy so pick the one with the smallest angle --- 0148 0149 // Index of the index/angle/point that gets displayed 0150 int best = first; 0151 0152 // find first valid candidate that does not overlap existing labels 0153 for (; best < 4; best++) 0154 { 0155 if (idx[best] && okay[best]) 0156 break; 0157 } 0158 0159 // return if all candidates either overlap or are invalid 0160 if (best >= 4) 0161 return; 0162 0163 // find the valid non-overlap candidate with the smallest angle 0164 for (int j = best + 1; j < 4; j++) 0165 { 0166 if (idx[j] && okay[j] && fabs(a[j]) < fabs(a[best])) 0167 best = j; 0168 } 0169 0170 m_skyLabeler->drawGuideLabel(o[best], m_text, a[best]); 0171 #endif 0172 } 0173 0174 QPointF LineListLabel::angleAt(const Projector *proj, LineList *list, int i, double *angle) 0175 { 0176 const SkyPoint *pThis = list->at(i).get(); 0177 const SkyPoint *pLast = list->at(i-1).get(); 0178 0179 QPointF oThis = proj->toScreen(pThis); 0180 QPointF oLast = proj->toScreen(pLast); 0181 0182 double sx = double(oThis.x() - oLast.x()); 0183 double sy = double(oThis.y() - oLast.y()); 0184 0185 *angle = atan2(sy, sx) * 180.0 / dms::PI; 0186 0187 // FIXME: use clamp in KSUtils 0188 // Never draw the label upside down 0189 if (*angle < -90.0) 0190 *angle += 180.0; 0191 if (*angle > 90.0) 0192 *angle -= 180.0; 0193 0194 return oThis; 0195 }