File indexing completed on 2025-01-12 09:34:20
0001 /* 0002 SPDX-FileCopyrightText: 2015 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "noprecessindex.h" 0010 0011 #include <memory> 0012 0013 class TestArtificialHorizon; 0014 0015 // An ArtificialHorizonEntity is a set of Azimuth & Altitude values defining 0016 // a series of connected line segments. Assuming ceiling is false (the default) 0017 // these lines define a horizon--coordinates indicating where the view is blocked 0018 // (below the line segments, lower in altitude) and where it is not blocked 0019 // (above the line segments, higher altitude values). If ceiling is true, then 0020 // this definition is flipped--the sky higher in altitude than the line segments 0021 // is considered blocked. 0022 class ArtificialHorizonEntity 0023 { 0024 public: 0025 ArtificialHorizonEntity() = default; 0026 ~ArtificialHorizonEntity(); 0027 0028 QString region() const; 0029 void setRegion(const QString &Region); 0030 0031 bool enabled() const; 0032 void setEnabled(bool Enabled); 0033 0034 bool ceiling() const; 0035 void setCeiling(bool value); 0036 0037 void clearList(); 0038 void setList(const std::shared_ptr<LineList> &list); 0039 std::shared_ptr<LineList> list() const; 0040 0041 // Returns the altitude constraint for the azimuth angle (degrees). 0042 // constraintExists will be set to false if there is no constraint for the azimuth. 0043 double altitudeConstraint(double azimuthDegrees, bool *constraintExists) const; 0044 0045 private: 0046 QString m_Region; 0047 bool m_Enabled { false }; 0048 bool m_Ceiling { false }; 0049 std::shared_ptr<LineList> m_List; 0050 }; 0051 0052 // ArtificialHorizon can contain several ArtificialHorizonEntities. That is, 0053 // it can have several sets of connected line segments. Assuming all the entities 0054 // are not ceilings, then the view is considered blocked below the highest line 0055 // segment that intersects a given azimuth. If none of the line segments cross 0056 // a given azimuth, then the view is not blocked at any altitude for that azimuth. 0057 // Similarly, if there are only "ceiling" horizon entities, then the view is blocked 0058 // at altitudes above the lowest ceiling. If there are a mix of ceilings and standard 0059 // entities, then for the given azimuth, at an altitude A, the view is blocked if 0060 // either the closest line below is a ceiling, or if the closest line above is a non-ceiling. 0061 class ArtificialHorizon 0062 { 0063 public: 0064 ArtificialHorizon() {} 0065 ~ArtificialHorizon(); 0066 0067 ArtificialHorizonEntity *findRegion(const QString ®ionName); 0068 void addRegion(const QString ®ionName, bool enabled, const std::shared_ptr<LineList> &list, bool ceiling); 0069 void removeRegion(const QString ®ionName, bool lineOnly = false); 0070 bool enabled(int i) const; 0071 void load(const QList<ArtificialHorizonEntity *> &list); 0072 0073 const QList<ArtificialHorizonEntity *> *horizonList() const 0074 { 0075 return &m_HorizonList; 0076 } 0077 0078 // Returns true if one or more artificial horizons are enabled. 0079 bool altitudeConstraintsExist() const; 0080 0081 // Returns true if the azimuth/altitude point is not blocked by the artificial horzon entities. 0082 bool isVisible(double azimuthDegrees, double altitudeDegrees, QString *reason = nullptr) const; 0083 // Like isVisible, but uses the cache if there are no ceiling constraints. 0084 bool isAltitudeOK(double azimuthDegrees, double altitudeDegrees, QString *reason) const; 0085 0086 // returns the (highest) altitude constraint at the given azimuth. 0087 // If there are no constraints, then it returns -90. 0088 double altitudeConstraint(double azimuthDegrees) const; 0089 0090 // Finds the nearest enabled constraint at the azimuth and above or below (not not exactly at) 0091 // the altitude given. 0092 const ArtificialHorizonEntity *getConstraintAbove(double azimuthDegrees, double altitudeDegrees, 0093 const ArtificialHorizonEntity *ignore = nullptr) const; 0094 const ArtificialHorizonEntity *getConstraintBelow(double azimuthDegrees, double altitudeDegrees, 0095 const ArtificialHorizonEntity *ignore = nullptr) const; 0096 0097 // Draw the blocked areas on the skymap using the SkyPainter. 0098 // If painter is a nullptr, nothing is drawn. 0099 // If regious is not a nullpointer, all the polygon coordinates are placed 0100 // in the QList (for testing). 0101 void drawPolygons(SkyPainter *painter, QList<LineList> *regions = nullptr); 0102 0103 private: 0104 // Removes a call to KStars::Instance() which is not necessary in testing. 0105 void setTesting() 0106 { 0107 testing = true; 0108 } 0109 void drawPolygons(int entity, SkyPainter *painter, QList<LineList> *regions = nullptr); 0110 void drawSampledPolygons(int entity, double az1, double alt1, double az2, double alt2, 0111 double sampling, SkyPainter *painter, QList<LineList> *regions); 0112 bool computePolygon(int entity, double az1, double alt1, double az2, double alt2, 0113 double sampling, LineList *region); 0114 0115 QList<ArtificialHorizonEntity *> m_HorizonList; 0116 bool testing { false }; 0117 0118 // Methods and data structure for precomputing altitudeConstraint(azimuth). 0119 // This way, we don't traverse the potentially horizon list each time 0120 // we query the horizon constraint. 0121 void precomputeConstraints() const; 0122 void resetPrecomputeConstraints() const; 0123 double precomputedConstraint(double azimuth) const; 0124 double altitudeConstraintInternal(double azimuthDegrees) const; 0125 mutable QVector<double> precomputedConstraints; 0126 bool noCeilingConstraints { true }; 0127 void checkForCeilings(); 0128 friend TestArtificialHorizon; 0129 }; 0130 0131 /** 0132 * @class ArtificialHorizon 0133 * Represents custom area from the horizon upwards which represent blocked views from the vantage point of the user. 0134 * Such blocked views could stem for example from tall trees or buildings. The user can define a series of line segments to 0135 * represent the blocked areas. 0136 * 0137 * @author Jasem Mutlaq 0138 * @version 0.1 0139 */ 0140 class ArtificialHorizonComponent : public NoPrecessIndex 0141 { 0142 public: 0143 /** 0144 * @short Constructor 0145 * 0146 * @p parent pointer to the parent SkyComposite object 0147 * name is the name of the subclass 0148 */ 0149 explicit ArtificialHorizonComponent(SkyComposite *parent); 0150 0151 virtual ~ArtificialHorizonComponent() override; 0152 0153 bool selected() override; 0154 void draw(SkyPainter *skyp) override; 0155 0156 void setLivePreview(const std::shared_ptr<LineList> &preview) 0157 { 0158 livePreview = preview; 0159 } 0160 void setSelectedPreviewPoint(int index) 0161 { 0162 selectedPreviewPoint = index; 0163 } 0164 void addRegion(const QString ®ionName, bool enabled, const std::shared_ptr<LineList> &list, bool ceiling); 0165 void removeRegion(const QString ®ionName, bool lineOnly = false); 0166 0167 const ArtificialHorizon &getHorizon() 0168 { 0169 return horizon; 0170 } 0171 0172 bool load(); 0173 void save(); 0174 0175 protected: 0176 void preDraw(SkyPainter *skyp) override; 0177 0178 private: 0179 ArtificialHorizon horizon; 0180 std::shared_ptr<LineList> livePreview; 0181 int selectedPreviewPoint { -1 }; 0182 0183 friend class TestArtificialHorizon; 0184 };