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