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