1 : /******************************************************************************
2 : * $Id: ogrdgndatasource.cpp 12822 2007-11-16 22:52:15Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Frank Warmerdam (warmerdam@pobox.com)
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 "ogr_dgn.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrdgndatasource.cpp 12822 2007-11-16 22:52:15Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRDGNDataSource() */
38 : /************************************************************************/
39 :
40 191 : OGRDGNDataSource::OGRDGNDataSource()
41 :
42 : {
43 191 : papoLayers = NULL;
44 191 : nLayers = 0;
45 191 : hDGN = NULL;
46 191 : pszName = NULL;
47 191 : papszOptions = NULL;
48 191 : }
49 :
50 : /************************************************************************/
51 : /* ~OGRDGNDataSource() */
52 : /************************************************************************/
53 :
54 382 : OGRDGNDataSource::~OGRDGNDataSource()
55 :
56 : {
57 195 : for( int i = 0; i < nLayers; i++ )
58 4 : delete papoLayers[i];
59 :
60 191 : CPLFree( papoLayers );
61 191 : CPLFree( pszName );
62 191 : CSLDestroy( papszOptions );
63 :
64 191 : if( hDGN != NULL )
65 4 : DGNClose( hDGN );
66 382 : }
67 :
68 : /************************************************************************/
69 : /* Open() */
70 : /************************************************************************/
71 :
72 190 : int OGRDGNDataSource::Open( const char * pszNewName,
73 : int bTestOpen,
74 : int bUpdate )
75 :
76 : {
77 : CPLAssert( nLayers == 0 );
78 :
79 : /* -------------------------------------------------------------------- */
80 : /* For now we require files to have the .dgn or .DGN */
81 : /* extension. Eventually we will implement a more */
82 : /* sophisticated test to see if it is a dgn file. */
83 : /* -------------------------------------------------------------------- */
84 190 : if( bTestOpen )
85 : {
86 : FILE *fp;
87 : GByte abyHeader[512];
88 190 : int nHeaderBytes = 0;
89 :
90 190 : fp = VSIFOpen( pszNewName, "rb" );
91 190 : if( fp == NULL )
92 72 : return FALSE;
93 :
94 118 : nHeaderBytes = (int) VSIFRead( abyHeader, 1, sizeof(abyHeader), fp );
95 :
96 118 : VSIFClose( fp );
97 :
98 118 : if( nHeaderBytes < 512 )
99 46 : return FALSE;
100 :
101 72 : if( !DGNTestOpen( abyHeader, nHeaderBytes ) )
102 69 : return FALSE;
103 : }
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Try to open the file as a DGN file. */
107 : /* -------------------------------------------------------------------- */
108 3 : hDGN = DGNOpen( pszNewName, bUpdate );
109 3 : if( hDGN == NULL )
110 : {
111 0 : if( !bTestOpen )
112 : CPLError( CE_Failure, CPLE_AppDefined,
113 : "Unable to open %s as a Microstation .dgn file.\n",
114 0 : pszNewName );
115 0 : return FALSE;
116 : }
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Create the layer object. */
120 : /* -------------------------------------------------------------------- */
121 : OGRDGNLayer *poLayer;
122 :
123 3 : poLayer = new OGRDGNLayer( "elements", hDGN, bUpdate );
124 3 : pszName = CPLStrdup( pszNewName );
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* Add layer to data source layer list. */
128 : /* -------------------------------------------------------------------- */
129 : papoLayers = (OGRDGNLayer **)
130 3 : CPLRealloc( papoLayers, sizeof(OGRDGNLayer *) * (nLayers+1) );
131 3 : papoLayers[nLayers++] = poLayer;
132 :
133 3 : return TRUE;
134 : }
135 :
136 : /************************************************************************/
137 : /* TestCapability() */
138 : /************************************************************************/
139 :
140 0 : int OGRDGNDataSource::TestCapability( const char * pszCap )
141 :
142 : {
143 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
144 0 : return TRUE;
145 : else
146 0 : return FALSE;
147 : }
148 :
149 : /************************************************************************/
150 : /* GetLayer() */
151 : /************************************************************************/
152 :
153 5 : OGRLayer *OGRDGNDataSource::GetLayer( int iLayer )
154 :
155 : {
156 5 : if( iLayer < 0 || iLayer >= nLayers )
157 0 : return NULL;
158 : else
159 5 : return papoLayers[iLayer];
160 : }
161 :
162 :
163 : /************************************************************************/
164 : /* PreCreate() */
165 : /* */
166 : /* Called by OGRDGNDriver::Create() method to setup a stub */
167 : /* OGRDataSource object without the associated file created */
168 : /* yet. It will be created by the CreateLayer() call. */
169 : /************************************************************************/
170 :
171 1 : int OGRDGNDataSource::PreCreate( const char *pszFilename,
172 : char **papszOptions )
173 :
174 : {
175 1 : this->papszOptions = CSLDuplicate( papszOptions );
176 1 : pszName = CPLStrdup( pszFilename );
177 :
178 1 : return TRUE;
179 : }
180 :
181 : /************************************************************************/
182 : /* CreateLayer() */
183 : /************************************************************************/
184 :
185 1 : OGRLayer *OGRDGNDataSource::CreateLayer( const char *pszLayerName,
186 : OGRSpatialReference *poSRS,
187 : OGRwkbGeometryType eGeomType,
188 : char **papszExtraOptions )
189 :
190 : {
191 1 : const char *pszSeed, *pszMasterUnit = "m", *pszSubUnit = "cm";
192 : const char *pszValue;
193 1 : int nUORPerSU=1, nSUPerMU=100;
194 1 : int nCreationFlags = 0, b3DRequested;
195 1 : double dfOriginX = -21474836.0, /* default origin centered on zero */
196 1 : dfOriginY = -21474836.0, /* with two decimals of precision */
197 1 : dfOriginZ = -21474836.0;
198 :
199 : /* -------------------------------------------------------------------- */
200 : /* Ensure only one layer gets created. */
201 : /* -------------------------------------------------------------------- */
202 1 : if( nLayers > 0 )
203 : {
204 : CPLError( CE_Failure, CPLE_AppDefined,
205 0 : "DGN driver only supports one layer will all the elements in it." );
206 0 : return NULL;
207 : }
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* If the coordinate system is geographic, we should use a */
211 : /* localized default origin and resolution. */
212 : /* -------------------------------------------------------------------- */
213 1 : if( poSRS != NULL && poSRS->IsGeographic() )
214 : {
215 0 : dfOriginX = -200.0;
216 0 : dfOriginY = -200.0;
217 :
218 0 : pszMasterUnit = "d";
219 0 : pszSubUnit = "s";
220 0 : nSUPerMU = 3600;
221 0 : nUORPerSU = 1000;
222 : }
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* Parse out various creation options. */
226 : /* -------------------------------------------------------------------- */
227 1 : CSLInsertStrings( papszOptions, 0, papszExtraOptions );
228 :
229 : b3DRequested = CSLFetchBoolean( papszOptions, "3D",
230 1 : (((int) eGeomType) & wkb25DBit) );
231 :
232 1 : pszSeed = CSLFetchNameValue( papszOptions, "SEED" );
233 1 : if( pszSeed )
234 0 : nCreationFlags |= DGNCF_USE_SEED_ORIGIN | DGNCF_USE_SEED_UNITS;
235 1 : else if( b3DRequested )
236 0 : pszSeed = CPLFindFile( "gdal", "seed_3d.dgn" );
237 : else
238 1 : pszSeed = CPLFindFile( "gdal", "seed_2d.dgn" );
239 :
240 1 : if( pszSeed == NULL )
241 : {
242 : CPLError( CE_Failure, CPLE_AppDefined,
243 0 : "No seed file provided, and unable to find seed_2d.dgn." );
244 0 : return NULL;
245 : }
246 :
247 1 : if( CSLFetchBoolean( papszOptions, "COPY_WHOLE_SEED_FILE", TRUE ) )
248 1 : nCreationFlags |= DGNCF_COPY_WHOLE_SEED_FILE;
249 1 : if( CSLFetchBoolean( papszOptions, "COPY_SEED_FILE_COLOR_TABLE", TRUE ) )
250 1 : nCreationFlags |= DGNCF_COPY_SEED_FILE_COLOR_TABLE;
251 :
252 1 : pszValue = CSLFetchNameValue( papszOptions, "MASTER_UNIT_NAME" );
253 1 : if( pszValue != NULL )
254 : {
255 0 : nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
256 0 : pszMasterUnit = pszValue;
257 : }
258 :
259 1 : pszValue = CSLFetchNameValue( papszOptions, "SUB_UNIT_NAME" );
260 1 : if( pszValue != NULL )
261 : {
262 0 : nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
263 0 : pszSubUnit = pszValue;
264 : }
265 :
266 :
267 1 : pszValue = CSLFetchNameValue( papszOptions, "SUB_UNITS_PER_MASTER_UNIT" );
268 1 : if( pszValue != NULL )
269 : {
270 1 : nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
271 1 : nSUPerMU = atoi(pszValue);
272 : }
273 :
274 1 : pszValue = CSLFetchNameValue( papszOptions, "UOR_PER_SUB_UNIT" );
275 1 : if( pszValue != NULL )
276 : {
277 1 : nCreationFlags &= ~DGNCF_USE_SEED_UNITS;
278 1 : nUORPerSU = atoi(pszValue);
279 : }
280 :
281 1 : pszValue = CSLFetchNameValue( papszOptions, "ORIGIN" );
282 1 : if( pszValue != NULL )
283 : {
284 : char **papszTuple = CSLTokenizeStringComplex( pszValue, " ,",
285 1 : FALSE, FALSE );
286 :
287 1 : nCreationFlags &= ~DGNCF_USE_SEED_ORIGIN;
288 1 : if( CSLCount(papszTuple) == 3 )
289 : {
290 1 : dfOriginX = atof(papszTuple[0]);
291 1 : dfOriginY = atof(papszTuple[1]);
292 1 : dfOriginZ = atof(papszTuple[2]);
293 : }
294 0 : else if( CSLCount(papszTuple) == 2 )
295 : {
296 0 : dfOriginX = atof(papszTuple[0]);
297 0 : dfOriginY = atof(papszTuple[1]);
298 0 : dfOriginZ = 0.0;
299 : }
300 : else
301 : {
302 0 : CSLDestroy(papszTuple);
303 : CPLError( CE_Failure, CPLE_AppDefined,
304 : "ORIGIN is not a valid 2d or 3d tuple.\n"
305 0 : "Separate tuple values with comma." );
306 0 : return FALSE;
307 : }
308 1 : CSLDestroy(papszTuple);
309 : }
310 :
311 : /* -------------------------------------------------------------------- */
312 : /* Try creating the base file. */
313 : /* -------------------------------------------------------------------- */
314 : hDGN = DGNCreate( pszName, pszSeed, nCreationFlags,
315 : dfOriginX, dfOriginY, dfOriginZ,
316 1 : nSUPerMU, nUORPerSU, pszMasterUnit, pszSubUnit );
317 1 : if( hDGN == NULL )
318 0 : return NULL;
319 :
320 : /* -------------------------------------------------------------------- */
321 : /* Create the layer object. */
322 : /* -------------------------------------------------------------------- */
323 : OGRDGNLayer *poLayer;
324 :
325 1 : poLayer = new OGRDGNLayer( pszLayerName, hDGN, TRUE );
326 :
327 : /* -------------------------------------------------------------------- */
328 : /* Add layer to data source layer list. */
329 : /* -------------------------------------------------------------------- */
330 : papoLayers = (OGRDGNLayer **)
331 1 : CPLRealloc( papoLayers, sizeof(OGRDGNLayer *) * (nLayers+1) );
332 1 : papoLayers[nLayers++] = poLayer;
333 :
334 1 : return poLayer;
335 : }
|