Cogs.Core
WMSRasterSource.cpp
1#include "WMSRasterSource.h"
2
3#include "Foundation/Logging/Logger.h"
4#include "Foundation/Collections/SmallVector.h"
5
6namespace{
7 using namespace Cogs::Core;
8 Cogs::Logging::Log logger = Cogs::Logging::getLogger("WMSRasterSource");
9
10 // Coordinate system WKIDs in WMS 1.3 where X,Y (Long,Lat) is switched to Y,X (Lat,Long)
11 // The WKIDS are given in a list of ranges
12 struct {
13 unsigned a;
14 unsigned b;
15 } latLongCRSRanges[] = {
16 { 4001, 4999 },
17 {2044, 2045}, {2081, 2083}, {2085, 2086}, {2093, 2093},
18 {2096, 2098}, {2105, 2132}, {2169, 2170}, {2176, 2180},
19 {2193, 2193}, {2200, 2200}, {2206, 2212}, {2319, 2319},
20 {2320, 2462}, {2523, 2549}, {2551, 2735}, {2738, 2758},
21 {2935, 2941}, {2953, 2953}, {3006, 3030}, {3034, 3035},
22 {3058, 3059}, {3068, 3068}, {3114, 3118}, {3126, 3138},
23 {3300, 3301}, {3328, 3335}, {3346, 3346}, {3350, 3352},
24 {3366, 3366}, {3416, 3416}, {20004, 20032}, {20064, 20092},
25 {21413, 21423}, {21473, 21483}, {21896, 21899}, {22171, 22177},
26 {22181, 22187}, {22191, 22197}, {25884, 25884}, {27205, 27232},
27 {27391, 27398}, {27492, 27492}, {28402, 28432}, {28462, 28492},
28 {30161, 30179}, {30800, 30800}, {31251, 31259}, {31275, 31279},
29 {31281, 31290}, {31466, 31700}
30 };
31
32 bool isLatLong(TerrainProvider::WMSVersion version, const Cogs::Core::TerrainProvider::CoordSys& coordSys)
33 {
34 if (version != TerrainProvider::WMSVersion::v1_3_0) return false;
35 if (coordSys.kind != TerrainProvider::CoordSys::Kind::EPSG) return false;
36 for (auto& range : latLongCRSRanges) {
37 if (range.a <= coordSys.id && coordSys.id <= range.b) return true;
38 }
39 return false;
40 }
41
42}
43
44Cogs::Core::TerrainProvider::WMSRasterSource::WMSRasterSource(Context* context)
45 : HTTPRasterSource(context)
46{
47}
48
49Cogs::Core::TerrainProvider::WMSRasterSource::~WMSRasterSource()
50{
51}
52
53bool Cogs::Core::TerrainProvider::WMSRasterSource::init(const WMSConfig& conf, std::unique_ptr<ICache>&& icache)
54{
55 layerDescriptions = conf.layerDescriptions;
56 otherArguments = conf.otherArguments;
57 version = conf.version;
58 dataType = conf.dataType;
59 serverIsLittleEndian = conf.serverIsLittleEndian;
60 retryFailedRequests = conf.retryFailedRequests;
61 return HTTPRasterSource::init(conf, std::move(icache));
62}
63
64void Cogs::Core::TerrainProvider::WMSRasterSource::getConfig(WMSConfig& conf) const
65{
66 HTTPRasterSource::getConfig(conf);
67 conf.layerDescriptions = layerDescriptions;
68 conf.otherArguments = otherArguments;
69 conf.version = version;
70 conf.dataType = dataType;
71 conf.serverIsLittleEndian = serverIsLittleEndian;
72 conf.retryFailedRequests = retryFailedRequests;
73}
74
75bool Cogs::Core::TerrainProvider::WMSRasterSource::createFetchTileUrl(std::string& url, TileId id)
76{
78
79 for (auto& item : layerDescriptions) {
80 if (item.minLevel <= id.level && id.level <= item.maxLevel) {
81 layers.push_back(&item);
82 }
83 }
84 if (layers.size() == 0) {
85 LOG_ERROR(logger, "No layer defined for level %u", id.level);
86 return false;
87 }
88
89 double tileSize = std::exp2(-double(id.level));
90
91 glm::dvec2 ta = tileSize * glm::dvec2(id.i, id.j);
92 glm::dvec2 tb = tileSize * glm::dvec2(id.i + 1, id.j + 1);
93
94 glm::dvec2 a = (glm::dvec2(1.0) - ta) * extent.min + ta * extent.max;
95 glm::dvec2 b = (glm::dvec2(1.0) - tb) * extent.min + tb * extent.max;
96
97 url.assign(Strings::getC(baseUrl));
98 url.append("?VERSION=");
99 switch (version) {
100 case WMSVersion::Unknown:
101 return false;
102 break;
103 case WMSVersion::v1_0_0:
104 url.append("1.0.0");
105 break;
106 case WMSVersion::v1_1_0:
107 url.append("1.1.0");
108 break;
109 case WMSVersion::v1_1_1:
110 url.append("1.1.1");
111 break;
112 case WMSVersion::v1_3_0:
113 url.append("1.3.0");
114 break;
115 default:
116 assert(false && "Garbage in conf.wms.version");
117 return false;
118 break;
119 }
120 url.append("&REQUEST=GetMap");
121 url.append("&CRS=");
122 switch (coordsys.kind) {
123 case CoordSys::Kind::EPSG:
124 url.append("EPSG:");
125 break;
126 default:
127 assert(false && "Garbage in conf.coordSys.kind");
128 return false;
129 }
130 url.append(std::to_string(coordsys.id));
131
132 if (isLatLong(version, coordsys)) {
133 url.append("&BBOX=");
134 url.append(std::to_string(a.y)); url.append(","); url.append(std::to_string(a.x)); url.append(",");
135 url.append(std::to_string(b.y)); url.append(","); url.append(std::to_string(b.x));
136 }
137 else {
138 url.append("&BBOX=");
139 url.append(std::to_string(a.x)); url.append(","); url.append(std::to_string(a.y)); url.append(",");
140 url.append(std::to_string(b.x)); url.append(","); url.append(std::to_string(b.y));
141 }
142 url.append("&WIDTH="); url.append(std::to_string(tiling.width));
143 url.append("&HEIGHT="); url.append(std::to_string(tiling.height));
144 url.append("&FORMAT=image/png");
145 url.append("&LAYERS=");
146 for (size_t i = 0, n=layers.size(); i < n; i++) {
147 if (i != 0) url.append(",");
148 url.append(Strings::getC(layers[i]->name));
149 }
150 url.append("&STYLES=");
151 for (size_t i = 0, n = layers.size(); i < n; i++) {
152 if (i != 0) url.append(",");
153 url.append(Strings::getC(layers[i]->style));
154 }
155 return true;
156}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
Log implementation class.
Definition: LogManager.h:139
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180