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