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