Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: MSG Native Reader
4 : * Purpose: Basic types implementation.
5 : * Author: Frans van den Bergh, fvdbergh@csir.co.za
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2005, Frans van den Bergh <fvdbergh@csir.co.za>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "cpl_error.h"
15 : #include "msg_basic_types.h"
16 :
17 : #include <stdio.h>
18 :
19 : namespace msg_native_format
20 : {
21 :
22 : #ifndef SQR
23 : #define SQR(x) ((x) * (x))
24 : #endif
25 :
26 : // endian conversion routines
27 0 : void to_native(GP_PK_HEADER &h)
28 : {
29 0 : h.sourceSUId = CPL_MSBWORD32(h.sourceSUId);
30 0 : h.sequenceCount = CPL_MSBWORD16(h.sequenceCount);
31 0 : h.packetLength = CPL_MSBWORD32(h.packetLength);
32 0 : }
33 :
34 0 : void to_native(GP_PK_SH1 &h)
35 : {
36 0 : h.spacecraftId = CPL_MSBWORD16(h.spacecraftId);
37 0 : h.packetTime.day = CPL_MSBWORD16(h.packetTime.day);
38 0 : h.packetTime.ms = CPL_MSBWORD32(h.packetTime.ms);
39 0 : }
40 :
41 0 : void to_native(SUB_VISIRLINE &v)
42 : {
43 0 : v.satelliteId = CPL_MSBWORD16(v.satelliteId);
44 0 : v.lineNumberInVisirGrid = CPL_MSBWORD32(v.lineNumberInVisirGrid);
45 0 : }
46 :
47 0 : static void swap_64_bits(unsigned char *b)
48 : {
49 0 : CPL_SWAP64PTR(b);
50 0 : }
51 :
52 0 : void to_native(RADIOMETRIC_PROCESSING_RECORD &r)
53 : {
54 0 : for (int i = 0; i < 12; i++)
55 : {
56 0 : swap_64_bits((unsigned char *)&r.level1_5ImageCalibration[i].cal_slope);
57 0 : swap_64_bits(
58 0 : (unsigned char *)&r.level1_5ImageCalibration[i].cal_offset);
59 : }
60 0 : }
61 :
62 0 : static void to_native(REFERENCEGRID_VISIR &r)
63 : {
64 0 : r.numberOfLines = CPL_MSBWORD32(r.numberOfLines);
65 0 : r.numberOfColumns = CPL_MSBWORD32(r.numberOfColumns);
66 : // should floats be swapped too?
67 : float f;
68 :
69 : // convert float using CPL_MSBPTR32
70 0 : memcpy(&f, &r.lineDirGridStep, sizeof(f));
71 0 : CPL_MSBPTR32(&f);
72 0 : r.lineDirGridStep = f;
73 :
74 : // convert float using CPL_MSBPTR32
75 0 : memcpy(&f, &r.columnDirGridStep, sizeof(f));
76 0 : CPL_MSBPTR32(&f);
77 0 : r.columnDirGridStep = f;
78 0 : }
79 :
80 0 : static void to_native(PLANNED_COVERAGE_VISIR &r)
81 : {
82 0 : r.southernLinePlanned = CPL_MSBWORD32(r.southernLinePlanned);
83 0 : r.northernLinePlanned = CPL_MSBWORD32(r.northernLinePlanned);
84 0 : r.easternColumnPlanned = CPL_MSBWORD32(r.easternColumnPlanned);
85 0 : r.westernColumnPlanned = CPL_MSBWORD32(r.westernColumnPlanned);
86 0 : }
87 :
88 0 : static void to_native(PLANNED_COVERAGE_HRV &r)
89 : {
90 0 : r.lowerSouthLinePlanned = CPL_MSBWORD32(r.lowerSouthLinePlanned);
91 0 : r.lowerNorthLinePlanned = CPL_MSBWORD32(r.lowerNorthLinePlanned);
92 0 : r.lowerEastColumnPlanned = CPL_MSBWORD32(r.lowerEastColumnPlanned);
93 0 : r.lowerWestColumnPlanned = CPL_MSBWORD32(r.lowerWestColumnPlanned);
94 0 : r.upperSouthLinePlanned = CPL_MSBWORD32(r.upperSouthLinePlanned);
95 0 : r.upperNorthLinePlanned = CPL_MSBWORD32(r.upperNorthLinePlanned);
96 0 : r.upperEastColumnPlanned = CPL_MSBWORD32(r.upperEastColumnPlanned);
97 0 : r.upperWestColumnPlanned = CPL_MSBWORD32(r.upperWestColumnPlanned);
98 0 : }
99 :
100 0 : void to_native(IMAGE_DESCRIPTION_RECORD &r)
101 : {
102 : float f;
103 :
104 : // convert float using CPL_MSBPTR32
105 0 : memcpy(&f, &r.longitudeOfSSP, sizeof(f));
106 0 : CPL_MSBPTR32(&f);
107 0 : r.longitudeOfSSP = f;
108 :
109 0 : to_native(r.referencegrid_visir);
110 0 : to_native(r.referencegrid_hrv);
111 0 : to_native(r.plannedCoverage_visir);
112 0 : to_native(r.plannedCoverage_hrv);
113 0 : }
114 :
115 0 : void to_native(ACTUAL_L15_COVERAGE_VISIR_RECORD &r)
116 : {
117 0 : r.southernLineActual = CPL_MSBWORD32(r.southernLineActual);
118 0 : r.northernLineActual = CPL_MSBWORD32(r.northernLineActual);
119 0 : r.easternColumnActual = CPL_MSBWORD32(r.easternColumnActual);
120 0 : r.westernColumnActual = CPL_MSBWORD32(r.westernColumnActual);
121 0 : }
122 :
123 0 : void to_native(ACTUAL_L15_COVERAGE_HRV_RECORD &r)
124 : {
125 0 : r.lowerSouthLineActual = CPL_MSBWORD32(r.lowerSouthLineActual);
126 0 : r.lowerNorthLineActual = CPL_MSBWORD32(r.lowerNorthLineActual);
127 0 : r.lowerEastColumnActual = CPL_MSBWORD32(r.lowerEastColumnActual);
128 0 : r.lowerWestColumnActual = CPL_MSBWORD32(r.lowerWestColumnActual);
129 0 : r.upperSouthLineActual = CPL_MSBWORD32(r.upperSouthLineActual);
130 0 : r.upperNorthLineActual = CPL_MSBWORD32(r.upperNorthLineActual);
131 0 : r.upperEastColumnActual = CPL_MSBWORD32(r.upperEastColumnActual);
132 0 : r.upperWestColumnActual = CPL_MSBWORD32(r.upperWestColumnActual);
133 0 : }
134 :
135 0 : void to_string(PH_DATA &d)
136 : {
137 0 : d.name[29] = 0;
138 0 : d.value[49] = 0;
139 0 : }
140 :
141 : #ifdef notdef
142 : // unit tests on structures
143 : bool perform_type_size_check(void)
144 : {
145 : bool success = true;
146 : if (sizeof(MAIN_PROD_HEADER) != 3674)
147 : {
148 : fprintf(stderr, "MAIN_PROD_HEADER size not 3674 (%lu)\n", /*ok*/
149 : (unsigned long)sizeof(MAIN_PROD_HEADER));
150 : success = false;
151 : }
152 : if (sizeof(SECONDARY_PROD_HEADER) != 1120)
153 : {
154 : fprintf(stderr, "SECONDARY_PROD_HEADER size not 1120 (%lu)\n", /*ok*/
155 : (unsigned long)sizeof(SECONDARY_PROD_HEADER));
156 : success = false;
157 : }
158 : if (sizeof(SUB_VISIRLINE) != 27)
159 : {
160 : fprintf(stderr, "SUB_VISIRLINE size not 17 (%lu)\n", /*ok*/
161 : (unsigned long)sizeof(SUB_VISIRLINE));
162 : success = false;
163 : }
164 : if (sizeof(GP_PK_HEADER) != 22)
165 : {
166 : fprintf(stderr, "GP_PK_HEADER size not 22 (%lu)\n", /*ok*/
167 : (unsigned long)sizeof(GP_PK_HEADER));
168 : success = false;
169 : }
170 : if (sizeof(GP_PK_SH1) != 16)
171 : {
172 : fprintf(stderr, "GP_PK_SH1 size not 16 (%lu)\n", /*ok*/
173 : (unsigned long)sizeof(GP_PK_SH1));
174 : success = false;
175 : }
176 : return success;
177 : }
178 : #endif
179 :
180 : const double Conversions::altitude = 42164; // km from origin
181 : // the spheroid in CGMS 03 4.4.3.2 is unique - flattening is 1/295.488
182 : // note the req and rpol were revised in issue 2.8 of CGMS/DOC/12/0017 - these
183 : // are the revised values
184 : const double Conversions::req = 6378.1370; // earth equatorial radius
185 : const double Conversions::rpol = 6356.7523; // earth polar radius
186 :
187 : // replace the magic constants in the paper with the calculated values in case
188 : // of further change
189 : const double Conversions::dtp2 =
190 : (SQR(altitude) -
191 : SQR(req)); // square of the distance to the equatorial tangent point
192 : // first/last point sensed on the equator
193 :
194 : // given req and rpol, oblate is already defined. Unused afaik in the gdal code
195 : const double Conversions::oblate = ((req - rpol) / req); // oblateness of earth
196 : const double Conversions::eccentricity2 =
197 : (1.0 - (SQR(rpol) / SQR(req))); // 0.00669438...
198 : const double Conversions::ratio2 =
199 : SQR(rpol / req); // 0.9933056 1/x = 1.006739501
200 : const double Conversions::deg_to_rad = (M_PI / 180.0);
201 : const double Conversions::rad_to_deg = (180.0 / M_PI);
202 : const double Conversions::nlines = 3712; // number of lines in an image
203 : const double Conversions::step =
204 : 17.83 / nlines; // pixel / line step in degrees
205 :
206 : const int Conversions::CFAC = -781648343;
207 : const int Conversions::LFAC = -781648343;
208 : const int Conversions::COFF = 1856;
209 : const int Conversions::LOFF = 1856;
210 : const double Conversions::CFAC_scaled = ((double)CFAC / (1 << 16));
211 : const double Conversions::LFAC_scaled = ((double)LFAC / (1 << 16));
212 :
213 : #define SQR(x) ((x) * (x))
214 :
215 0 : void Conversions::convert_pixel_to_geo(double line, double column,
216 : double &longitude, double &latitude)
217 : {
218 : // x and y are angles in radians
219 0 : double x = (column - COFF - 0.0) / CFAC_scaled;
220 0 : double y = (line - LOFF - 0.0) / LFAC_scaled;
221 :
222 0 : double sd = sqrt(SQR(altitude * cos(x) * cos(y)) -
223 0 : (SQR(cos(y)) + SQR(sin(y)) / ratio2) * dtp2);
224 0 : double sn = (altitude * cos(x) * cos(y) - sd) /
225 0 : (SQR(cos(y)) + SQR(sin(y)) / ratio2);
226 0 : double s1 = altitude - sn * SQR(cos(y));
227 0 : double s2 = sn * sin(x) * cos(y);
228 0 : double s3 = -sn * sin(y);
229 0 : double sxy = sqrt(s1 * s1 + s2 * s2);
230 :
231 0 : longitude = atan(s2 / s1);
232 0 : latitude = atan((s3 / sxy) / ratio2);
233 :
234 0 : longitude = longitude * rad_to_deg;
235 0 : latitude = latitude * rad_to_deg;
236 0 : }
237 :
238 0 : void Conversions::compute_pixel_xyz(double line, double column, double &x,
239 : double &y, double &z)
240 : {
241 0 : double asamp = -(column - (nlines / 2.0 + 0.5)) * step;
242 0 : double aline = (line - (nlines / 2.0 + 0.5)) * step;
243 :
244 0 : asamp *= deg_to_rad;
245 0 : aline *= deg_to_rad;
246 :
247 0 : double tanal = tan(aline);
248 0 : double tanas = tan(asamp);
249 :
250 0 : double p = -1;
251 0 : double q = tanas;
252 0 : double r = tanal * sqrt(1 + q * q);
253 :
254 0 : double a = q * q + SQR((r * req / rpol)) + p * p;
255 0 : double b = 2 * altitude * p;
256 0 : double c = altitude * altitude - req * req;
257 :
258 0 : double det = b * b - 4 * a * c;
259 :
260 0 : if (det > 0)
261 : {
262 0 : double k = (-b - sqrt(det)) / (2 * a);
263 0 : x = altitude + k * p;
264 0 : y = k * q;
265 0 : z = k * r;
266 : }
267 : else
268 : {
269 0 : x = y = z = 0;
270 0 : CPLError(CE_Warning, CPLE_AppDefined, "Warning: pixel not visible");
271 : }
272 0 : }
273 :
274 0 : double Conversions::compute_pixel_area_sqkm(double line, double column)
275 : {
276 : double x1, x2;
277 : double y1, y2;
278 : double z1, z2;
279 :
280 0 : compute_pixel_xyz(line - 0.5, column - 0.5, x1, y1, z1);
281 0 : compute_pixel_xyz(line + 0.5, column - 0.5, x2, y2, z2);
282 :
283 0 : double xlen = sqrt(SQR(x1 - x2) + SQR(y1 - y2) + SQR(z1 - z2));
284 :
285 0 : compute_pixel_xyz(line - 0.5, column + 0.5, x2, y2, z2);
286 :
287 0 : double ylen = sqrt(SQR(x1 - x2) + SQR(y1 - y2) + SQR(z1 - z2));
288 :
289 0 : return xlen * ylen;
290 : }
291 :
292 0 : void Conversions::convert_geo_to_pixel(double longitude, double latitude,
293 : unsigned int &line, unsigned int &column)
294 : {
295 :
296 0 : latitude = latitude * deg_to_rad;
297 0 : longitude = longitude * deg_to_rad;
298 :
299 0 : double c_lat = atan(ratio2 * tan(latitude));
300 0 : double r_l = rpol / sqrt(1 - eccentricity2 * cos(c_lat) * cos(c_lat));
301 0 : double r1 = altitude - r_l * cos(c_lat) * cos(longitude);
302 0 : double r2 = -r_l * cos(c_lat) * sin(longitude);
303 0 : double r3 = r_l * sin(c_lat);
304 0 : double rn = sqrt(r1 * r1 + r2 * r2 + r3 * r3);
305 :
306 0 : double x = atan(-r2 / r1) * CFAC_scaled + COFF;
307 0 : double y = asin(-r3 / rn) * LFAC_scaled + LOFF;
308 :
309 0 : line = (unsigned int)floor(x + 0.5);
310 0 : column = (unsigned int)floor(y + 0.5);
311 0 : }
312 :
313 : } // namespace msg_native_format
|