31 #if SDL_VERSION_ATLEAST(2, 0, 10) 32 using MapPositionType = float;
34 using MapPositionType = int;
38 static constexpr std::string_view ChronoMapProjection{
"MapProjection"};
39 static constexpr std::string_view ChronoMapDepiction{
"MapDepiction"};
83 static constexpr
Size MapImageSize(
MapSize mapSize) {
88 return Size{1320, 660};
90 return Size{1980, 990};
92 return Size{2640,1320};
107 return (static_cast<uint32_t>(mapSize) << 2u) | (
static_cast<uint32_t
>(mapDepiction) << 1u) |
static_cast<uint32_t
>(illumination);
118 std::stringstream sstrm{};
120 switch (mapDepiction) {
122 sstrm <<
"World_Topo_";
125 sstrm <<
"Countries";
131 switch (illumination) {
142 auto size = MapImageSize(mapSize);
143 sstrm << size.w <<
'x' << size.h;
151 static constexpr T rad2deg(T r) noexcept {
152 return 180. * (r/M_PI);
157 static constexpr T deg2rad(T d) noexcept {
158 return M_PI * (d/180.);
173 constexpr
explicit GeoPosition(
bool endPoint) : GeoPosition() {
183 constexpr
GeoPosition(
double latitude,
double longitude,
bool rad =
false) {
186 lat = std::clamp(latitude, -M_PI_2, M_PI_2);
187 lon = std::clamp(longitude, -M_PI, M_PI);
189 lat = std::clamp(latitude, -90., 90.);
190 lon = std::clamp(longitude, -180., 180.);
200 return GeoPosition{*
this};
204 g.lat = deg2rad(lat);
205 g.lon = deg2rad(lon);
218 g.lat = rad2deg(lat);
219 g.lon = rad2deg(lon);
222 return GeoPosition{*
this};
230 [[nodiscard]]
double distance(
const GeoPosition &other)
const {
231 auto r = toRadians();
233 return acos(sin(r.lat) * sin(o.lat) + cos(r.lat) * cos(o.lat) * cos(r.lon - o.lon));
244 [[nodiscard]] GeoPosition
midpoint(
const GeoPosition &other,
double distance,
double fraction = 0.5)
const {
245 auto r = toRadians();
247 auto A = sin((1. - fraction) * distance) / sin(distance);
248 auto B = sin(fraction * distance) / sin(distance);
249 auto x = A * cos(r.lat) * cos(r.lon) + B * cos(o.lat) * cos(o.lon);
250 auto y = A * cos(r.lat) * sin(r.lon) + B * cos(o.lat) * sin(o.lon);
251 auto z = A * sin(r.lat) + B * sin(o.lat);
253 return GeoPosition{atan2(z, sqrt(x * x + y * y)), atan2(y, x),
true};
263 [[nodiscard]] GeoPosition
midpoint(
const GeoPosition &other,
double fraction = 0.5)
const {
264 return midpoint(other, distance(other), fraction);
267 std::ostream &printOn(std::ostream &strm)
const {
268 auto g = toDegrees();
269 return strm <<
'(' << g.lat <<
',' << g.lon <<
')';
273 static constexpr
double EquatorLatitude = 0.;
274 static constexpr
double TropicLatitude = 23.4365;
275 static constexpr
double ArcticCircle = 66.5635;
276 static constexpr
double PrimeMeridian = 0.;
277 static constexpr std::array<GeoPosition, 21> InternationalDateLine = {
303 enum class MapOverLayImage : size_t {
310 MapOverLayImage mapOverLayImage;
311 std::string_view fileName;
320 enum ShortCutCode : uint32_t {
322 StationMercatorProjection,
330 std::shared_ptr<TimerTick> mTimerTick{};
356 std::array<gm::Surface,2> mMapSurface{};
357 std::array<gm::Surface,2> mAzSurface{};
359 std::array<gm::Surface,2> mMercatorTemp{};
360 std::array<gm::Surface,2> mAzimuthalTemp{};
362 std::array<gm::Texture,2> mMercator{};
363 std::array<gm::Texture,2> mAzimuthal{};
365 std::atomic_bool mAbortFuture{};
374 static constexpr std::array<double, 3> GrayLineCos = {-0.105,
377 static constexpr
double GrayLinePow = .80;
401 static std::tuple<bool, double, double>
418 auto sinY = sin(qthRad.
lat);
419 auto cosY = cos(qthRad.
lat);
420 for (
int y = 0; y < mapImageSize.h; y += 1) {
421 for (
int x = 0; x < mapImageSize.w; x += 1) {
427 auto[valid, lat, lon] =
xyToAzLatLong(x, y, mapImageSize, qthRad, sinY, cosY);
429 auto xx = std::min(mapImageSize.w - 1,
430 (
int) round((
double) mapImageSize.w * ((lon + M_PI) / (2 * M_PI))));
431 auto yy = std::min(mapImageSize.h - 1,
432 (
int) round((
double) mapImageSize.h * ((M_PI_2 - lat) / M_PI)));
434 for (
auto idx = 0; idx < N; ++idx)
451 return azimuthalProjectionSet(mAbortFuture, mQthRad, mMapImgSize, mAzSurface, mMapSurface);
458 bool mMapProjectionsInvalid{
true};
471 bool setForegroundBackground();
486 explicit MapProjection(std::shared_ptr<TimerTick> timerTick, std::filesystem::path& xdgDataPath);
498 static constexpr std::string_view
id =
"MapProjection";
499 std::string_view nodeId() const noexcept
override {
514 void addedToContainer()
override;
519 void cacheCurrentMaps();
525 static std::tuple<double, double>
subSolar();
530 auto getQth()
const {
539 return !mMapProjectionsInvalid;
566 int splitPixel =
util::roundToInt((
double) drawSize.w * ((mQth.lon) / 360.));
568 splitPixel += drawSize.w;
586 switch (mProjection) {
589 auto split = mapRectangle.w / 2 + mapRectangle.x;
590 return (p0.x < split && p1.x < split) || (p0.x > split && p1.x > split);
594 splitPixel = projectionSplitPixel(mapRectangle.
size());
597 return abs(p0.x - p1.x) <
static_cast<MapPositionType
>(mapRectangle.w) / 4 &&
598 abs(p0.y - p1.y) <
static_cast<MapPositionType
>(mapRectangle.h) / 4;
603 auto p0 = geoToMap(begin.
toRadians(), mProjection, splitPixel, mapRectangle) + mapRectangle.
position();
606 auto g1 = increment(g0,
false);
607 auto p1 = geoToMap(g1.toRadians(), mProjection, splitPixel, mapRectangle) + mapRectangle.
position();
608 if (gapTest(p0, p1)) {
614 for (g1 = increment(g0,
true); !g1.end; g1 = increment(g1,
true)) {
615 p1 = geoToMap(g1.toRadians(), mProjection, splitPixel, mapRectangle) + mapRectangle.
position();
616 if (gapTest(p0, p1)) {
641 auto plotPoints = [
this,&splitPixel,&mapRect,&gapTest,&drawing,&context](
GeoPosition &g0,
GeoPosition &g1) ->
bool {
642 auto p0 = geoToMap(g0, mProjection, splitPixel, mapRect) + mapRect.position();
643 auto p1 = geoToMap(g1, mProjection, splitPixel, mapRect) + mapRect.position();
644 if (gapTest(p0, p1)) {
645 drawing.renderLine(context, p0, p1);
651 switch (mProjection) {
654 auto split = mapRect.w / 2 + mapRect.x;
655 return (p0.x < split && p1.x < split) || (p0.x > split && p1.x > split);
659 splitPixel = projectionSplitPixel(mapRect.size());
662 return abs(p0.x - p1.x) < mapRect.w / 4 &&
663 abs(p0.y - p1.y) < mapRect.h / 4;
668 for (
auto r = r0.distance(r1); r > deg2rad(0.25); r = r0.distance(r1)) {
669 if (plotPoints(r0, r1)) {
670 auto midPoint = r0.midpoint(r1, r, 0.5);
671 if (plotPoints(r0, midPoint)) {
672 plotPoints(midPoint, r1);
692 template<
typename Iterator>
695 double StepSize = deg2rad(3.);
696 for (
auto idx = first; idx != last - 1; ++idx) {
697 auto g1 = (idx + 1)->toRadians();
698 auto g0 = idx->toRadians();
700 auto dist = g0.distance(g1);
703 double fInc = 1. /
static_cast<double>(steps);
706 for (
int fIdx = 0; fIdx <= steps; fIdx++) {
709 auto r1 = g0.midpoint(g1, dist, f);
710 drawInterpolate(context, drawing, mapRect, r0, r1);
725 static constexpr
double fineInc = 1.;
726 static constexpr
double coarseInc = 3.;
727 double begin = -abs(latitudeBound);
728 double end = abs(latitudeBound);
729 drawMapLine(context, drawing,
GeoPosition{begin, longitude}, mapRect,
753 static constexpr
double begin = -180.;
754 static constexpr
double end = 180.;
755 static constexpr
double fineInc = 1.;
756 static constexpr
double coarseInc = 3.;
757 drawMapLine(context, drawing,
GeoPosition{latitude, begin}, mapRect,
765 r.end = r.lon > end + coarseInc;
772 inline std::ostream &operator<<(std::ostream &strm,
rose::GeoPosition &geoPosition) {
773 return geoPosition.printOn(strm);
Definition: MapProjection.h:318
Sun position in the sky.
Definition: Plan13.h:282
auto getProjection() const
Accessor for the type of projection.
Definition: MapProjection.h:546
int roundToInt(T value, T multiplier=1.)
Round a floating point value to an integer.
Definition: Math.h:34
A Widget which manages contained Widgets.
Definition: Visual.h:697
bool radians
Values are in radians when true.
Definition: MapProjection.h:168
A wrapper class for SDL_Surface pointers.
Definition: Surface.h:50
std::tuple< double, double > subSolar()
Compute the sub-solar geographic coordinates, used in plotting the solar ilumination.
Definition: MapProjection.cpp:457
bool mapProjectionsValid() const
Determine if map projections are valid.
Definition: MapProjection.h:538
constexpr GeoPosition(double latitude, double longitude, bool rad=false)
Create a geographic position.
Definition: MapProjection.h:183
bool computeAzimuthalMaps()
Compute Azimuthal map projections.
Definition: MapProjection.h:450
std::shared_ptr< Slot< Args... > > slot_type
Composed Slot type.
Definition: Signals.h:123
Standard Mercator split a the International Date Line.
double lat
Latitude value.
Definition: MapProjection.h:166
Definition: AntiAliasedDrawing.h:23
void drawInterpolate(gm::Context &context, AntiAliasedDrawing &drawing, Rectangle mapRect, GeoPosition &geo0, GeoPosition &geo1)
Definition: MapProjection.h:630
int projectionSplitPixel(Size drawSize) const
Computer the StationMercator split pixel given a map drawing size.
Definition: MapProjection.h:565
void drawLatitude(gm::Context &context, AntiAliasedDrawing &drawing, double latitude, Rectangle mapRect)
Draw a line of Latitude at latitude.
Definition: MapProjection.h:752
void drawMapLine(gm::Context &context, AntiAliasedDrawing &drawing, GeoPosition begin, Rectangle mapRectangle, const std::function< GeoPosition(GeoPosition &, bool fine)> &increment)
Draw a line on the projected map.
Definition: MapProjection.h:581
MapSize
Definition: MapProjection.h:70
MapIllumination
Definition: MapProjection.h:62
An abstraction of a geographic position.
Definition: MapProjection.h:165
std::future< bool > mComputeAzimuthalMapsFuture
The std::future result of computeAzimuthalMaps()
Definition: MapProjection.h:455
Context
Definition: GraphicsModel.h:76
Definition: SettingsNames.h:13
Position< int > position() const noexcept
Get a Position from a Rectangle.
Definition: Types.h:346
Abstraction of the graphics model.
Fetching and caching web resources.
GeoPosition midpoint(const GeoPosition &other, double distance, double fraction=0.5) const
Find a mid-point on the Great Circle between this GeoPosition and another.
Definition: MapProjection.h:244
double distance(const GeoPosition &other) const
Computer the Great Circle distance between this GeoPosition and another.
Definition: MapProjection.h:230
GeoPosition midpoint(const GeoPosition &other, double fraction=0.5) const
Find a mid-point on the Great Circle between this GeoPosition and another.
Definition: MapProjection.h:263
GeoPosition constexpr toRadians() const
Convert the position from degrees to radians.
Definition: MapProjection.h:198
Azimuthal with the Station location centered on the left hemisphere.
MapProjectionType
Definition: MapProjection.h:45
A composite of a Position and a Size.
Definition: Types.h:307
MapDepiction
Definition: MapProjection.h:54
bool renderLine(gm::Context &context, Position< T > p0, Position< T > p1)
Draw an anti-aliased line.
Definition: AntiAliasedDrawing.h:90
static bool azimuthalProjectionSet(std::atomic_bool &abort, const GeoPosition &qthRad, const Size &mapImageSize, std::array< gm::Surface, N > &projected, std::array< gm::Surface, N > &map)
Compute Azimuthal projection of a set of the same sized maps.
Definition: MapProjection.h:416
double lon
Longitude value.
Definition: MapProjection.h:167
A size in integer dimensions.
Definition: Types.h:230
ToDo: There is an issue that the initial scroll interaction is lost if the click/press lands on a Wid...
Definition: CelestialOverlay.cpp:13
Mercator split so the Station location is centred.
std::future< bool > mForegroundBackgroundFuture
The std::future result of setForegroundBackground()
Definition: MapProjection.h:461
User Interface Visual types.
GeoPosition constexpr toDegrees() const
Convert the position from radians to degrees.
Definition: MapProjection.h:214
void drawLongitude(gm::Context &context, AntiAliasedDrawing &drawing, double longitude, double latitudeBound, Rectangle mapRect)
Draw a line of Longitude at longitude.
Definition: MapProjection.h:723
Definition: MapProjection.h:309
void drawMapLine(gm::Context &context, AntiAliasedDrawing &drawing, Rectangle mapRect, Iterator first, Iterator last)
Draw a line on the projected map using points in a standard container.
Definition: MapProjection.h:693
Size size() const noexcept
Get a Size from a Rectangle.
Definition: Types.h:351
std::tuple< bool, double, double > xyToAzLatLong(int x, int y, const Size &mapSize, const GeoPosition &location, double siny, double cosy)
Transform a Mercator map pixel into an Azimuthal map latitude and longitude in radians.
Definition: MapProjection.cpp:403