/src/gdal/frmts/dted/dted_create.c
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: DTED Translator |
4 | | * Purpose: Implementation of DTEDCreate() portion of DTED API. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2001, Frank Warmerdam |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "dted_api.h" |
14 | | #include <assert.h> |
15 | | |
16 | 0 | #define DTED_ABS_VERT_ACC "NA " |
17 | 0 | #define DTED_SECURITY "U" |
18 | 0 | #define DTED_EDITION 1 |
19 | | |
20 | | /************************************************************************/ |
21 | | /* DTEDFormatDMS() */ |
22 | | /************************************************************************/ |
23 | | |
24 | | static void DTEDFormatDMS(unsigned char *achField, size_t nTargetLenSize, |
25 | | size_t nOffset, double dfAngle, |
26 | | const char *pszLatLong, const char *pszFormat) |
27 | | |
28 | 0 | { |
29 | 0 | char chHemisphere; |
30 | 0 | int nDegrees, nMinutes, nSeconds; |
31 | 0 | double dfRemainder; |
32 | |
|
33 | 0 | if (pszFormat == NULL) |
34 | 0 | pszFormat = "%03d%02d%02d%c"; |
35 | |
|
36 | 0 | assert(EQUAL(pszLatLong, "LAT") || EQUAL(pszLatLong, "LONG")); |
37 | |
|
38 | 0 | if (EQUAL(pszLatLong, "LAT")) |
39 | 0 | { |
40 | 0 | if (dfAngle < 0.0) |
41 | 0 | chHemisphere = 'S'; |
42 | 0 | else |
43 | 0 | chHemisphere = 'N'; |
44 | 0 | } |
45 | 0 | else |
46 | 0 | { |
47 | 0 | if (dfAngle < 0.0) |
48 | 0 | chHemisphere = 'W'; |
49 | 0 | else |
50 | 0 | chHemisphere = 'E'; |
51 | 0 | } |
52 | |
|
53 | 0 | dfAngle = CPL_ABS(dfAngle); |
54 | |
|
55 | 0 | nDegrees = (int)floor(dfAngle + 0.5 / 3600.0); |
56 | 0 | dfRemainder = dfAngle - nDegrees; |
57 | 0 | nMinutes = (int)floor(dfRemainder * 60.0 + 0.5 / 60.0); |
58 | 0 | dfRemainder = dfRemainder - nMinutes / 60.0; |
59 | 0 | nSeconds = (int)floor(dfRemainder * 3600.0 + 0.5); |
60 | |
|
61 | 0 | snprintf((char *)achField + nOffset, nTargetLenSize - nOffset, pszFormat, |
62 | 0 | nDegrees, nMinutes, nSeconds, chHemisphere); |
63 | 0 | } |
64 | | |
65 | | /************************************************************************/ |
66 | | /* DTEDFormat() */ |
67 | | /************************************************************************/ |
68 | | |
69 | | static void DTEDFormat(unsigned char *pszTarget, size_t nTargetLenSize, |
70 | | size_t nOffset, const char *pszFormat, ...) |
71 | | CPL_PRINT_FUNC_FORMAT(4, 5); |
72 | | |
73 | | static void DTEDFormat(unsigned char *pszTarget, size_t nTargetLenSize, |
74 | | size_t nOffset, const char *pszFormat, ...) |
75 | | |
76 | 0 | { |
77 | 0 | va_list args; |
78 | |
|
79 | 0 | va_start(args, pszFormat); |
80 | 0 | CPLvsnprintf((char *)pszTarget + nOffset, nTargetLenSize - nOffset, |
81 | 0 | pszFormat, args); |
82 | 0 | va_end(args); |
83 | 0 | } |
84 | | |
85 | | /************************************************************************/ |
86 | | /* DTEDCreate() */ |
87 | | /************************************************************************/ |
88 | | |
89 | | const char *DTEDCreate(const char *pszFilename, int nLevel, int nLLOriginLat, |
90 | | int nLLOriginLong) |
91 | | |
92 | 0 | { |
93 | 0 | VSILFILE *fp; |
94 | 0 | unsigned char achRecord[3601 * 2 + 12]; |
95 | 0 | int nXSize, nYSize, nReferenceLat, iProfile; |
96 | | |
97 | | /* -------------------------------------------------------------------- */ |
98 | | /* Establish resolution. */ |
99 | | /* -------------------------------------------------------------------- */ |
100 | 0 | if (nLevel == 0) |
101 | 0 | { |
102 | 0 | nXSize = 121; |
103 | 0 | nYSize = 121; |
104 | 0 | } |
105 | 0 | else if (nLevel == 1) |
106 | 0 | { |
107 | 0 | nXSize = 1201; |
108 | 0 | nYSize = 1201; |
109 | 0 | } |
110 | 0 | else if (nLevel == 2) |
111 | 0 | { |
112 | 0 | nXSize = 3601; |
113 | 0 | nYSize = 3601; |
114 | 0 | } |
115 | 0 | else |
116 | 0 | { |
117 | 0 | return CPLSPrintf("Illegal DTED Level value %d, only 0-2 allowed.", |
118 | 0 | nLevel); |
119 | 0 | } |
120 | | |
121 | 0 | nReferenceLat = nLLOriginLat < 0 ? -(nLLOriginLat + 1) : nLLOriginLat; |
122 | |
|
123 | 0 | if (nReferenceLat >= 80) |
124 | 0 | nXSize = (nXSize - 1) / 6 + 1; |
125 | 0 | else if (nReferenceLat >= 75) |
126 | 0 | nXSize = (nXSize - 1) / 4 + 1; |
127 | 0 | else if (nReferenceLat >= 70) |
128 | 0 | nXSize = (nXSize - 1) / 3 + 1; |
129 | 0 | else if (nReferenceLat >= 50) |
130 | 0 | nXSize = (nXSize - 1) / 2 + 1; |
131 | | |
132 | | /* -------------------------------------------------------------------- */ |
133 | | /* Open the file. */ |
134 | | /* -------------------------------------------------------------------- */ |
135 | 0 | fp = VSIFOpenL(pszFilename, "wb"); |
136 | |
|
137 | 0 | if (fp == NULL) |
138 | 0 | { |
139 | 0 | return CPLSPrintf("Unable to create file `%s'.", pszFilename); |
140 | 0 | } |
141 | | |
142 | | /* -------------------------------------------------------------------- */ |
143 | | /* Format and write the UHL record. */ |
144 | | /* -------------------------------------------------------------------- */ |
145 | 0 | memset(achRecord, ' ', DTED_UHL_SIZE); |
146 | |
|
147 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 0, "UHL1"); |
148 | |
|
149 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 4, nLLOriginLong, "LONG", NULL); |
150 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 12, nLLOriginLat, "LAT", NULL); |
151 | |
|
152 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 20, "%04d", |
153 | 0 | (3600 / (nXSize - 1)) * 10); |
154 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 24, "%04d", |
155 | 0 | (3600 / (nYSize - 1)) * 10); |
156 | |
|
157 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 28, "%4s", DTED_ABS_VERT_ACC); |
158 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 32, "%-3s", DTED_SECURITY); |
159 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 47, "%04d", nXSize); |
160 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 51, "%04d", nYSize); |
161 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 55, "%c", '0'); |
162 | |
|
163 | 0 | if (VSIFWriteL(achRecord, DTED_UHL_SIZE, 1, fp) != 1) |
164 | 0 | return "UHL record write failed."; |
165 | | |
166 | | /* -------------------------------------------------------------------- */ |
167 | | /* Format and write the DSI record. */ |
168 | | /* -------------------------------------------------------------------- */ |
169 | 0 | memset(achRecord, ' ', DTED_DSI_SIZE); |
170 | |
|
171 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 0, "DSI"); |
172 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 3, "%1s", DTED_SECURITY); |
173 | |
|
174 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 59, "DTED%d", nLevel); |
175 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 64, "%015d", 0); |
176 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 87, "%02d", DTED_EDITION); |
177 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 89, "%c", 'A'); |
178 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 90, "%04d", 0); |
179 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 94, "%04d", 0); |
180 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 98, "%04d", 0); |
181 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 126, "PRF89020B"); |
182 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 135, "00"); |
183 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 137, "0005"); |
184 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 141, "MSL"); |
185 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 144, "WGS84"); |
186 | | |
187 | | /* origin */ |
188 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 185, nLLOriginLat, "LAT", |
189 | 0 | "%02d%02d%02d.0%c"); |
190 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 194, nLLOriginLong, "LONG", |
191 | 0 | "%03d%02d%02d.0%c"); |
192 | | |
193 | | /* SW */ |
194 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 204, nLLOriginLat, "LAT", |
195 | 0 | "%02d%02d%02d%c"); |
196 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 211, nLLOriginLong, "LONG", |
197 | 0 | NULL); |
198 | | |
199 | | /* NW */ |
200 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 219, nLLOriginLat + 1, "LAT", |
201 | 0 | "%02d%02d%02d%c"); |
202 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 226, nLLOriginLong, "LONG", |
203 | 0 | NULL); |
204 | | |
205 | | /* NE */ |
206 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 234, nLLOriginLat + 1, "LAT", |
207 | 0 | "%02d%02d%02d%c"); |
208 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 241, nLLOriginLong + 1, "LONG", |
209 | 0 | NULL); |
210 | | |
211 | | /* SE */ |
212 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 249, nLLOriginLat, "LAT", |
213 | 0 | "%02d%02d%02d%c"); |
214 | 0 | DTEDFormatDMS(achRecord, sizeof(achRecord), 256, nLLOriginLong + 1, "LONG", |
215 | 0 | NULL); |
216 | |
|
217 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 264, "0000000.0"); |
218 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 264, "0000000.0"); |
219 | |
|
220 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 273, "%04d", |
221 | 0 | (3600 / (nYSize - 1)) * 10); |
222 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 277, "%04d", |
223 | 0 | (3600 / (nXSize - 1)) * 10); |
224 | |
|
225 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 281, "%04d", nYSize); |
226 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 285, "%04d", nXSize); |
227 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 289, "%02d", 0); |
228 | |
|
229 | 0 | if (VSIFWriteL(achRecord, DTED_DSI_SIZE, 1, fp) != 1) |
230 | 0 | return "DSI record write failed."; |
231 | | |
232 | | /* -------------------------------------------------------------------- */ |
233 | | /* Create and write ACC record. */ |
234 | | /* -------------------------------------------------------------------- */ |
235 | 0 | memset(achRecord, ' ', DTED_ACC_SIZE); |
236 | |
|
237 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 0, "ACC"); |
238 | |
|
239 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 3, "NA"); |
240 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 7, "NA"); |
241 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 11, "NA"); |
242 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 15, "NA"); |
243 | |
|
244 | 0 | DTEDFormat(achRecord, sizeof(achRecord), 55, "00"); |
245 | |
|
246 | 0 | if (VSIFWriteL(achRecord, DTED_ACC_SIZE, 1, fp) != 1) |
247 | 0 | return "ACC record write failed."; |
248 | | |
249 | | /* -------------------------------------------------------------------- */ |
250 | | /* Write blank template profile data records. */ |
251 | | /* -------------------------------------------------------------------- */ |
252 | 0 | memset(achRecord, 0, nYSize * 2 + 12); |
253 | 0 | memset(achRecord + 8, 0xff, nYSize * 2); |
254 | |
|
255 | 0 | achRecord[0] = 0252; |
256 | |
|
257 | 0 | for (iProfile = 0; iProfile < nXSize; iProfile++) |
258 | 0 | { |
259 | 0 | achRecord[1] = 0; |
260 | 0 | achRecord[2] = (GByte)(iProfile / 256); |
261 | 0 | achRecord[3] = (GByte)(iProfile % 256); |
262 | |
|
263 | 0 | achRecord[4] = (GByte)(iProfile / 256); |
264 | 0 | achRecord[5] = (GByte)(iProfile % 256); |
265 | |
|
266 | 0 | if (VSIFWriteL(achRecord, nYSize * 2 + 12, 1, fp) != 1) |
267 | 0 | return "Data record write failed."; |
268 | 0 | } |
269 | | |
270 | 0 | if (VSIFCloseL(fp) != 0) |
271 | 0 | return "I/O error"; |
272 | | |
273 | 0 | return NULL; |
274 | 0 | } |