File indexing completed on 2025-01-19 09:46:02
0001 /* 0002 SPDX-FileCopyrightText: 2007 James B. Bowlin <bowlin@mindspring.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "skymesh.h" 0008 0009 #include "kstarsdata.h" 0010 #ifndef KSTARS_LITE 0011 #include "skymap.h" 0012 #endif 0013 #include "htmesh/MeshIterator.h" 0014 #include "htmesh/MeshBuffer.h" 0015 #include "projections/projector.h" 0016 #include "skyobjects/starobject.h" 0017 0018 #include <QPainter> 0019 #include <QPolygonF> 0020 #include <QPointF> 0021 0022 QMap<int, SkyMesh *> SkyMesh::pinstances; 0023 int SkyMesh::defaultLevel = -1; 0024 0025 SkyMesh *SkyMesh::Create(int level) 0026 { 0027 SkyMesh *newInstance = pinstances.value(level, nullptr); 0028 if (newInstance != nullptr) 0029 return newInstance; 0030 0031 newInstance = new SkyMesh(level); 0032 pinstances.insert(level, newInstance); 0033 if (defaultLevel < 0) 0034 defaultLevel = newInstance->level(); 0035 0036 return newInstance; 0037 } 0038 0039 SkyMesh *SkyMesh::Instance() 0040 { 0041 return pinstances.value(defaultLevel, nullptr); 0042 } 0043 0044 SkyMesh *SkyMesh::Instance(int level) 0045 { 0046 return pinstances.value(level, nullptr); 0047 } 0048 0049 SkyMesh::SkyMesh(int level) 0050 : HTMesh(level, level, NUM_MESH_BUF), m_drawID(0), m_KSNumbers(0) 0051 { 0052 errLimit = HTMesh::size() / 4; 0053 m_inDraw = false; 0054 } 0055 0056 void SkyMesh::aperture(SkyPoint *p0, double radius, MeshBufNum_t bufNum) 0057 { 0058 KStarsData *data = KStarsData::Instance(); 0059 // FIXME: simple copying leads to incorrect results because RA0 && dec0 are both zero sometimes 0060 SkyPoint p1(p0->ra(), p0->dec()); 0061 long double now = data->updateNum()->julianDay(); 0062 p1.catalogueCoord(now); 0063 0064 if (radius == 1.0) 0065 { 0066 SkyPoint p2 = p1; 0067 p2.updateCoordsNow(data->updateNum()); 0068 } 0069 0070 HTMesh::intersect(p1.ra().Degrees(), p1.dec().Degrees(), radius, (BufNum)bufNum); 0071 m_drawID++; 0072 } 0073 0074 Trixel SkyMesh::index(const SkyPoint *p) 0075 { 0076 return HTMesh::index(p->ra0().Degrees(), p->dec0().Degrees()); 0077 } 0078 0079 Trixel SkyMesh::indexStar(StarObject *star) 0080 { 0081 double ra, dec; 0082 star->getIndexCoords(&m_KSNumbers, &ra, &dec); 0083 return HTMesh::index(ra, dec); 0084 } 0085 0086 void SkyMesh::indexStar(StarObject *star1, StarObject *star2) 0087 { 0088 double ra1, ra2, dec1, dec2; 0089 star1->getIndexCoords(&m_KSNumbers, &ra1, &dec1); 0090 star2->getIndexCoords(&m_KSNumbers, &ra2, &dec2); 0091 HTMesh::intersect(ra1, dec1, ra2, dec2); 0092 } 0093 0094 void SkyMesh::index(const SkyPoint *p, double radius, MeshBufNum_t bufNum) 0095 { 0096 HTMesh::intersect(p->ra().Degrees(), p->dec().Degrees(), radius, (BufNum)bufNum); 0097 } 0098 0099 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2) 0100 { 0101 HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees()); 0102 } 0103 0104 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3) 0105 { 0106 HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees(), 0107 p3->ra0().Degrees(), p3->dec0().Degrees()); 0108 } 0109 0110 void SkyMesh::index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3, const SkyPoint *p4) 0111 { 0112 HTMesh::intersect(p1->ra0().Degrees(), p1->dec0().Degrees(), p2->ra0().Degrees(), p2->dec0().Degrees(), 0113 p3->ra0().Degrees(), p3->dec0().Degrees(), p4->ra0().Degrees(), p4->dec0().Degrees()); 0114 } 0115 0116 void SkyMesh::index(const QPointF &p1, const QPointF &p2, const QPointF &p3) 0117 { 0118 HTMesh::intersect(p1.x() * 15.0, p1.y(), p2.x() * 15.0, p2.y(), p3.x() * 15.0, p3.y()); 0119 } 0120 0121 void SkyMesh::index(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4) 0122 { 0123 HTMesh::intersect(p1.x() * 15.0, p1.y(), p2.x() * 15.0, p2.y(), p3.x() * 15.0, p3.y(), p4.x() * 15.0, p4.y()); 0124 } 0125 0126 const IndexHash &SkyMesh::indexLine(SkyList *points) 0127 { 0128 return indexLine(points, nullptr); 0129 } 0130 0131 const IndexHash &SkyMesh::indexStarLine(SkyList *points) 0132 { 0133 SkyPoint *pThis, *pLast; 0134 0135 indexHash.clear(); 0136 0137 if (points->isEmpty()) 0138 return indexHash; 0139 0140 pLast = points->at(0).get(); 0141 for (int i = 1; i < points->size(); i++) 0142 { 0143 pThis = points->at(i).get(); 0144 0145 indexStar((StarObject *)pThis, (StarObject *)pLast); 0146 MeshIterator region(this); 0147 0148 while (region.hasNext()) 0149 { 0150 indexHash[region.next()] = true; 0151 } 0152 pLast = pThis; 0153 } 0154 return indexHash; 0155 } 0156 0157 const IndexHash &SkyMesh::indexLine(SkyList *points, IndexHash *skip) 0158 { 0159 SkyPoint *pThis, *pLast; 0160 0161 indexHash.clear(); 0162 0163 if (points->isEmpty()) 0164 return indexHash; 0165 0166 pLast = points->at(0).get(); 0167 for (int i = 1; i < points->size(); i++) 0168 { 0169 pThis = points->at(i).get(); 0170 0171 if (skip != nullptr && skip->contains(i)) 0172 { 0173 pLast = pThis; 0174 continue; 0175 } 0176 0177 index(pThis, pLast); 0178 MeshIterator region(this); 0179 0180 if (region.size() > errLimit) 0181 { 0182 HTMesh::setDebug(10); 0183 index(pThis, pLast); 0184 HTMesh::setDebug(0); 0185 } 0186 0187 // This was used to track down a bug in my HTMesh code. The bug was caught 0188 // and fixed but I've left this debugging code in for now. -jbb 0189 0190 else 0191 { 0192 while (region.hasNext()) 0193 { 0194 indexHash[region.next()] = true; 0195 } 0196 } 0197 pLast = pThis; 0198 } 0199 return indexHash; 0200 } 0201 0202 // ----- Create HTMesh Index for Polygons ----- 0203 // Create (mostly) 4-point polygons that cover the mw polygon and 0204 // all share the same first vertex. Use indexHash to eliminate 0205 // the many duplicate indices that are generated with this procedure. 0206 // There are probably faster and better ways to do this. 0207 0208 const IndexHash &SkyMesh::indexPoly(SkyList *points) 0209 { 0210 indexHash.clear(); 0211 0212 if (points->size() < 3) 0213 return indexHash; 0214 0215 SkyPoint *startP = points->first().get(); 0216 0217 int end = points->size() - 2; // 1) size - 1 -> last index, 0218 // 2) minimum of 2 points 0219 0220 for (int p = 1; p <= end; p += 2) 0221 { 0222 if (p == end) 0223 { 0224 index(startP, points->at(p).get(), points->at(p + 1).get()); 0225 } 0226 else 0227 { 0228 index(startP, points->at(p).get(), points->at(p + 1).get(), points->at(p + 2).get()); 0229 } 0230 0231 MeshIterator region(this); 0232 while (region.hasNext()) 0233 { 0234 indexHash[region.next()] = true; 0235 } 0236 } 0237 return indexHash; 0238 } 0239 0240 const IndexHash &SkyMesh::indexPoly(const QPolygonF *points) 0241 { 0242 indexHash.clear(); 0243 0244 if (points->size() < 3) 0245 return indexHash; 0246 0247 const QPointF startP = points->first(); 0248 0249 int end = points->size() - 2; // 1) size - 1 -> last index, 0250 // 2) minimum of 2 points 0251 for (int p = 1; p <= end; p += 2) 0252 { 0253 if (p == end) 0254 { 0255 index(startP, points->at(p), points->at(p + 1)); 0256 } 0257 else 0258 { 0259 index(startP, points->at(p), points->at(p + 1), points->at(p + 2)); 0260 } 0261 0262 MeshIterator region(this); 0263 while (region.hasNext()) 0264 { 0265 indexHash[region.next()] = true; 0266 } 0267 } 0268 return indexHash; 0269 } 0270 0271 // NOTE: SkyMesh::draw() is primarily used for debugging purposes, to 0272 // show the trixels to enable visualizing them. Thus, it is not 0273 // necessary that this be compatible with GL unless we abandon the 0274 // QPainter some day, or the need arises to use this for some other 0275 // purpose. -- asimha 0276 void SkyMesh::draw(QPainter &psky, MeshBufNum_t bufNum) 0277 { 0278 #ifndef KSTARS_LITE 0279 SkyMap *map = SkyMap::Instance(); 0280 KStarsData *data = KStarsData::Instance(); 0281 0282 double r1, d1, r2, d2, r3, d3; 0283 0284 MeshIterator region(this, bufNum); 0285 while (region.hasNext()) 0286 { 0287 Trixel trixel = region.next(); 0288 vertices(trixel, &r1, &d1, &r2, &d2, &r3, &d3); 0289 SkyPoint s1(r1 / 15.0, d1); 0290 SkyPoint s2(r2 / 15.0, d2); 0291 SkyPoint s3(r3 / 15.0, d3); 0292 s1.EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0293 s2.EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0294 s3.EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0295 QPointF q1 = map->projector()->toScreen(&s1); 0296 QPointF q2 = map->projector()->toScreen(&s2); 0297 QPointF q3 = map->projector()->toScreen(&s3); 0298 psky.drawLine(q1, q2); 0299 psky.drawLine(q2, q3); 0300 psky.drawLine(q3, q1); 0301 // Draw the name of the trixel 0302 QString TrixelNumberString; 0303 TrixelNumberString.setNum(trixel); 0304 psky.drawText((q1 + q2 + q3) / 3.0, TrixelNumberString); 0305 } 0306 #else 0307 Q_UNUSED(psky); 0308 Q_UNUSED(bufNum); 0309 #endif 0310 } 0311 0312 const SkyRegion &SkyMesh::skyRegion(const SkyPoint &_p1, const SkyPoint &_p2) 0313 { 0314 std::shared_ptr<SkyPoint> p1(new SkyPoint(_p1)); 0315 std::shared_ptr<SkyPoint> p2(new SkyPoint(_p2)); 0316 std::shared_ptr<SkyPoint> p3(new SkyPoint(p1->ra(), p2->dec())); 0317 std::shared_ptr<SkyPoint> p4(new SkyPoint(p2->ra(), p1->dec())); 0318 SkyList skylist; 0319 0320 skylist.push_back(p1); 0321 skylist.push_back(p2); 0322 skylist.push_back(p3); 0323 skylist.push_back(p4); 0324 return indexPoly(&skylist); 0325 }