1 /******************************************************************************
2 * $Id: dted_create.c 3b0bbf7a8a012d69a783ee1f9cfeb5c52b370021 2017-06-27 20:57:02Z Even Rouault $
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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "dted_api.h"
31 #include <assert.h>
32
33 CPL_CVSID("$Id: dted_create.c 3b0bbf7a8a012d69a783ee1f9cfeb5c52b370021 2017-06-27 20:57:02Z Even Rouault $")
34
35 #define DTED_ABS_VERT_ACC "NA "
36 #define DTED_SECURITY "U"
37 #define DTED_EDITION 1
38
39 /************************************************************************/
40 /* DTEDFormatDMS() */
41 /************************************************************************/
42
DTEDFormatDMS(unsigned char * achField,size_t nTargetLenSize,size_t nOffset,double dfAngle,const char * pszLatLong,const char * pszFormat)43 static void DTEDFormatDMS( unsigned char *achField,
44 size_t nTargetLenSize,
45 size_t nOffset,
46 double dfAngle,
47 const char *pszLatLong, const char *pszFormat )
48
49 {
50 char chHemisphere;
51 int nDegrees, nMinutes, nSeconds;
52 double dfRemainder;
53
54 if( pszFormat == NULL )
55 pszFormat = "%03d%02d%02d%c";
56
57 assert( EQUAL(pszLatLong,"LAT") || EQUAL(pszLatLong,"LONG") );
58
59 if( EQUAL(pszLatLong,"LAT") )
60 {
61 if( dfAngle < 0.0 )
62 chHemisphere = 'S';
63 else
64 chHemisphere = 'N';
65 }
66 else
67 {
68 if( dfAngle < 0.0 )
69 chHemisphere = 'W';
70 else
71 chHemisphere = 'E';
72 }
73
74 dfAngle = ABS(dfAngle);
75
76 nDegrees = (int) floor(dfAngle + 0.5/3600.0);
77 dfRemainder = dfAngle - nDegrees;
78 nMinutes = (int) floor(dfRemainder*60.0 + 0.5/60.0);
79 dfRemainder = dfRemainder - nMinutes / 60.0;
80 nSeconds = (int) floor(dfRemainder * 3600.0 + 0.5);
81
82 snprintf( (char*)achField + nOffset, nTargetLenSize - nOffset,
83 pszFormat,
84 nDegrees, nMinutes, nSeconds, chHemisphere );
85 }
86
87 /************************************************************************/
88 /* DTEDFormat() */
89 /************************************************************************/
90
91 static void DTEDFormat( unsigned char *pszTarget,
92 size_t nTargetLenSize,
93 size_t nOffset,
94 const char *pszFormat, ... )
95 CPL_PRINT_FUNC_FORMAT (4, 5);
96
DTEDFormat(unsigned char * pszTarget,size_t nTargetLenSize,size_t nOffset,const char * pszFormat,...)97 static void DTEDFormat( unsigned char *pszTarget,
98 size_t nTargetLenSize,
99 size_t nOffset,
100 const char *pszFormat, ... )
101
102 {
103 va_list args;
104
105 va_start(args, pszFormat);
106 CPLvsnprintf( (char*)pszTarget + nOffset, nTargetLenSize - nOffset,
107 pszFormat, args );
108 va_end(args);
109 }
110
111 /************************************************************************/
112 /* DTEDCreate() */
113 /************************************************************************/
114
DTEDCreate(const char * pszFilename,int nLevel,int nLLOriginLat,int nLLOriginLong)115 const char *DTEDCreate( const char *pszFilename, int nLevel,
116 int nLLOriginLat, int nLLOriginLong )
117
118 {
119 VSILFILE *fp;
120 unsigned char achRecord[3601*2 + 12];
121 int nXSize, nYSize, nReferenceLat, iProfile;
122
123 /* -------------------------------------------------------------------- */
124 /* Establish resolution. */
125 /* -------------------------------------------------------------------- */
126 if( nLevel == 0 )
127 {
128 nXSize = 121;
129 nYSize = 121;
130 }
131 else if( nLevel == 1 )
132 {
133 nXSize = 1201;
134 nYSize = 1201;
135 }
136 else if( nLevel == 2 )
137 {
138 nXSize = 3601;
139 nYSize = 3601;
140 }
141 else
142 {
143 return CPLSPrintf( "Illegal DTED Level value %d, only 0-2 allowed.",
144 nLevel );
145 }
146
147 nReferenceLat = nLLOriginLat < 0 ? - (nLLOriginLat + 1) : nLLOriginLat;
148
149 if( nReferenceLat >= 80 )
150 nXSize = (nXSize - 1) / 6 + 1;
151 else if( nReferenceLat >= 75 )
152 nXSize = (nXSize - 1) / 4 + 1;
153 else if( nReferenceLat >= 70 )
154 nXSize = (nXSize - 1) / 3 + 1;
155 else if( nReferenceLat >= 50 )
156 nXSize = (nXSize - 1) / 2 + 1;
157
158 /* -------------------------------------------------------------------- */
159 /* Open the file. */
160 /* -------------------------------------------------------------------- */
161 fp = VSIFOpenL( pszFilename, "wb" );
162
163 if( fp == NULL )
164 {
165 return CPLSPrintf( "Unable to create file `%s'.", pszFilename );
166 }
167
168 /* -------------------------------------------------------------------- */
169 /* Format and write the UHL record. */
170 /* -------------------------------------------------------------------- */
171 memset( achRecord, ' ', DTED_UHL_SIZE );
172
173 DTEDFormat( achRecord, sizeof(achRecord), 0, "UHL1" );
174
175 DTEDFormatDMS( achRecord, sizeof(achRecord), 4, nLLOriginLong, "LONG", NULL );
176 DTEDFormatDMS( achRecord, sizeof(achRecord), 12, nLLOriginLat, "LAT", NULL );
177
178 DTEDFormat( achRecord, sizeof(achRecord), 20,
179 "%04d", (3600 / (nXSize-1)) * 10 );
180 DTEDFormat( achRecord, sizeof(achRecord), 24,
181 "%04d", (3600 / (nYSize-1)) * 10 );
182
183 DTEDFormat( achRecord, sizeof(achRecord), 28, "%4s", DTED_ABS_VERT_ACC );
184 DTEDFormat( achRecord, sizeof(achRecord), 32, "%-3s", DTED_SECURITY );
185 DTEDFormat( achRecord, sizeof(achRecord), 47, "%04d", nXSize );
186 DTEDFormat( achRecord, sizeof(achRecord), 51, "%04d", nYSize );
187 DTEDFormat( achRecord, sizeof(achRecord), 55, "%c", '0' );
188
189 if( VSIFWriteL( achRecord, DTED_UHL_SIZE, 1, fp ) != 1 )
190 return "UHL record write failed.";
191
192 /* -------------------------------------------------------------------- */
193 /* Format and write the DSI record. */
194 /* -------------------------------------------------------------------- */
195 memset( achRecord, ' ', DTED_DSI_SIZE );
196
197 DTEDFormat( achRecord, sizeof(achRecord), 0, "DSI" );
198 DTEDFormat( achRecord, sizeof(achRecord), 3, "%1s", DTED_SECURITY );
199
200 DTEDFormat( achRecord, sizeof(achRecord), 59, "DTED%d", nLevel );
201 DTEDFormat( achRecord, sizeof(achRecord), 64, "%015d", 0 );
202 DTEDFormat( achRecord, sizeof(achRecord), 87, "%02d", DTED_EDITION );
203 DTEDFormat( achRecord, sizeof(achRecord), 89, "%c", 'A' );
204 DTEDFormat( achRecord, sizeof(achRecord), 90, "%04d", 0 );
205 DTEDFormat( achRecord, sizeof(achRecord), 94, "%04d", 0 );
206 DTEDFormat( achRecord, sizeof(achRecord), 98, "%04d", 0 );
207 DTEDFormat( achRecord, sizeof(achRecord), 126, "PRF89020B");
208 DTEDFormat( achRecord, sizeof(achRecord), 135, "00");
209 DTEDFormat( achRecord, sizeof(achRecord), 137, "0005");
210 DTEDFormat( achRecord, sizeof(achRecord), 141, "MSL" );
211 DTEDFormat( achRecord, sizeof(achRecord), 144, "WGS84" );
212
213 /* origin */
214 DTEDFormatDMS( achRecord, sizeof(achRecord), 185, nLLOriginLat, "LAT",
215 "%02d%02d%02d.0%c" );
216 DTEDFormatDMS( achRecord, sizeof(achRecord), 194, nLLOriginLong, "LONG",
217 "%03d%02d%02d.0%c" );
218
219 /* SW */
220 DTEDFormatDMS( achRecord, sizeof(achRecord), 204,
221 nLLOriginLat, "LAT", "%02d%02d%02d%c" );
222 DTEDFormatDMS( achRecord, sizeof(achRecord), 211,
223 nLLOriginLong, "LONG", NULL );
224
225 /* NW */
226 DTEDFormatDMS( achRecord, sizeof(achRecord), 219,
227 nLLOriginLat+1, "LAT", "%02d%02d%02d%c" );
228 DTEDFormatDMS( achRecord, sizeof(achRecord), 226,
229 nLLOriginLong, "LONG", NULL );
230
231 /* NE */
232 DTEDFormatDMS( achRecord, sizeof(achRecord), 234,
233 nLLOriginLat+1, "LAT", "%02d%02d%02d%c" );
234 DTEDFormatDMS( achRecord, sizeof(achRecord), 241,
235 nLLOriginLong+1, "LONG", NULL );
236
237 /* SE */
238 DTEDFormatDMS( achRecord, sizeof(achRecord), 249,
239 nLLOriginLat, "LAT", "%02d%02d%02d%c" );
240 DTEDFormatDMS( achRecord, sizeof(achRecord), 256,
241 nLLOriginLong+1, "LONG", NULL );
242
243 DTEDFormat( achRecord, sizeof(achRecord), 264, "0000000.0" );
244 DTEDFormat( achRecord, sizeof(achRecord), 264, "0000000.0" );
245
246 DTEDFormat( achRecord, sizeof(achRecord), 273,
247 "%04d", (3600 / (nYSize-1)) * 10 );
248 DTEDFormat( achRecord, sizeof(achRecord), 277,
249 "%04d", (3600 / (nXSize-1)) * 10 );
250
251 DTEDFormat( achRecord, sizeof(achRecord), 281, "%04d", nYSize );
252 DTEDFormat( achRecord, sizeof(achRecord), 285, "%04d", nXSize );
253 DTEDFormat( achRecord, sizeof(achRecord), 289, "%02d", 0 );
254
255 if( VSIFWriteL( achRecord, DTED_DSI_SIZE, 1, fp ) != 1 )
256 return "DSI record write failed.";
257
258 /* -------------------------------------------------------------------- */
259 /* Create and write ACC record. */
260 /* -------------------------------------------------------------------- */
261 memset( achRecord, ' ', DTED_ACC_SIZE );
262
263 DTEDFormat( achRecord, sizeof(achRecord), 0, "ACC" );
264
265 DTEDFormat( achRecord, sizeof(achRecord), 3, "NA" );
266 DTEDFormat( achRecord, sizeof(achRecord), 7, "NA" );
267 DTEDFormat( achRecord, sizeof(achRecord), 11, "NA" );
268 DTEDFormat( achRecord, sizeof(achRecord), 15, "NA" );
269
270 DTEDFormat( achRecord, sizeof(achRecord), 55, "00" );
271
272 if( VSIFWriteL( achRecord, DTED_ACC_SIZE, 1, fp ) != 1 )
273 return "ACC record write failed.";
274
275 /* -------------------------------------------------------------------- */
276 /* Write blank template profile data records. */
277 /* -------------------------------------------------------------------- */
278 memset( achRecord, 0, nYSize*2 + 12 );
279 memset( achRecord + 8, 0xff, nYSize*2 );
280
281 achRecord[0] = 0252;
282
283 for( iProfile = 0; iProfile < nXSize; iProfile++ )
284 {
285 achRecord[1] = 0;
286 achRecord[2] = (GByte) (iProfile / 256);
287 achRecord[3] = (GByte) (iProfile % 256);
288
289 achRecord[4] = (GByte) (iProfile / 256);
290 achRecord[5] = (GByte) (iProfile % 256);
291
292 if( VSIFWriteL( achRecord, nYSize*2 + 12, 1, fp ) != 1 )
293 return "Data record write failed.";
294 }
295
296 if( VSIFCloseL( fp ) != 0 )
297 return "I/O error";
298
299 return NULL;
300 }
301