1 : /******************************************************************************
2 : * $Id: dgnopen.cpp 10645 2007-01-18 02:22:39Z warmerdam $
3 : *
4 : * Project: Microstation DGN Access Library
5 : * Purpose: DGN Access Library file open code.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.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 "dgnlibp.h"
31 :
32 : CPL_CVSID("$Id: dgnopen.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
33 :
34 : /************************************************************************/
35 : /* DGNTestOpen() */
36 : /************************************************************************/
37 :
38 : /**
39 : * Test if header is DGN.
40 : *
41 : * @param pabyHeader block of header data from beginning of file.
42 : * @param nByteCount number of bytes in pabyHeader.
43 : *
44 : * @return TRUE if the header appears to be from a DGN file, otherwise FALSE.
45 : */
46 :
47 77 : int DGNTestOpen( GByte *pabyHeader, int nByteCount )
48 :
49 : {
50 77 : if( nByteCount < 4 )
51 0 : return TRUE;
52 :
53 : // Is it a cell library?
54 85 : if( pabyHeader[0] == 0x08
55 8 : && pabyHeader[1] == 0x05
56 0 : && pabyHeader[2] == 0x17
57 0 : && pabyHeader[3] == 0x00 )
58 0 : return TRUE;
59 :
60 : // Is it not a regular 2D or 3D file?
61 101 : if( (pabyHeader[0] != 0x08 && pabyHeader[0] != 0xC8)
62 8 : || pabyHeader[1] != 0x09
63 16 : || pabyHeader[2] != 0xFE || pabyHeader[3] != 0x02 )
64 69 : return FALSE;
65 :
66 8 : return TRUE;
67 : }
68 :
69 : /************************************************************************/
70 : /* DGNOpen() */
71 : /************************************************************************/
72 :
73 : /**
74 : * Open a DGN file.
75 : *
76 : * The file is opened, and minimally verified to ensure it is a DGN (ISFF)
77 : * file. If the file cannot be opened for read access an error with code
78 : * CPLE_OpenFailed with be reported via CPLError() and NULL returned.
79 : * If the file header does
80 : * not appear to be a DGN file, an error with code CPLE_AppDefined will be
81 : * reported via CPLError(), and NULL returned.
82 : *
83 : * If successful a handle for further access is returned. This should be
84 : * closed with DGNClose() when no longer needed.
85 : *
86 : * DGNOpen() does not scan the file on open, and should be very fast even for
87 : * large files.
88 : *
89 : * @param pszFilename name of file to try opening.
90 : * @param bUpdate should the file be opened with read+update (r+) mode?
91 : *
92 : * @return handle to use for further access to file using DGN API, or NULL
93 : * if open fails.
94 : */
95 :
96 5 : DGNHandle DGNOpen( const char * pszFilename, int bUpdate )
97 :
98 : {
99 : DGNInfo *psDGN;
100 : FILE *fp;
101 :
102 : /* -------------------------------------------------------------------- */
103 : /* Open the file. */
104 : /* -------------------------------------------------------------------- */
105 5 : if( bUpdate )
106 1 : fp = VSIFOpen( pszFilename, "rb+" );
107 : else
108 4 : fp = VSIFOpen( pszFilename, "rb" );
109 5 : if( fp == NULL )
110 : {
111 : CPLError( CE_Failure, CPLE_OpenFailed,
112 : "Unable to open `%s' for read access.\n",
113 0 : pszFilename );
114 0 : return NULL;
115 : }
116 :
117 : /* -------------------------------------------------------------------- */
118 : /* Verify the format ... add later. */
119 : /* -------------------------------------------------------------------- */
120 : GByte abyHeader[512];
121 :
122 5 : VSIFRead( abyHeader, 1, sizeof(abyHeader), fp );
123 5 : if( !DGNTestOpen( abyHeader, sizeof(abyHeader) ) )
124 : {
125 : CPLError( CE_Failure, CPLE_AppDefined,
126 : "File `%s' does not have expected DGN header.\n",
127 0 : pszFilename );
128 0 : VSIFClose( fp );
129 0 : return NULL;
130 : }
131 :
132 5 : VSIRewind( fp );
133 :
134 : /* -------------------------------------------------------------------- */
135 : /* Create the info structure. */
136 : /* -------------------------------------------------------------------- */
137 5 : psDGN = (DGNInfo *) CPLCalloc(sizeof(DGNInfo),1);
138 5 : psDGN->fp = fp;
139 5 : psDGN->next_element_id = 0;
140 :
141 5 : psDGN->got_tcb = FALSE;
142 5 : psDGN->scale = 1.0;
143 5 : psDGN->origin_x = 0.0;
144 5 : psDGN->origin_y = 0.0;
145 5 : psDGN->origin_z = 0.0;
146 :
147 5 : psDGN->index_built = FALSE;
148 5 : psDGN->element_count = 0;
149 5 : psDGN->element_index = NULL;
150 :
151 5 : psDGN->got_bounds = FALSE;
152 :
153 5 : if( abyHeader[0] == 0xC8 )
154 0 : psDGN->dimension = 3;
155 : else
156 5 : psDGN->dimension = 2;
157 :
158 5 : psDGN->has_spatial_filter = FALSE;
159 5 : psDGN->sf_converted_to_uor = FALSE;
160 5 : psDGN->select_complex_group = FALSE;
161 5 : psDGN->in_complex_group = FALSE;
162 :
163 5 : return (DGNHandle) psDGN;
164 : }
165 :
166 : /************************************************************************/
167 : /* DGNSetOptions() */
168 : /************************************************************************/
169 :
170 : /**
171 : * Set file access options.
172 : *
173 : * Sets a flag affecting how the file is accessed. Currently
174 : * there is only one support flag:
175 : *
176 : * DGNO_CAPTURE_RAW_DATA: If this is enabled (it is off by default),
177 : * then the raw binary data associated with elements will be kept in
178 : * the raw_data field within the DGNElemCore when they are read. This
179 : * is required if the application needs to interprete the raw data itself.
180 : * It is also necessary if the element is to be written back to this file,
181 : * or another file using DGNWriteElement(). Off by default (to conserve
182 : * memory).
183 : *
184 : * @param hDGN handle to file returned by DGNOpen().
185 : * @param nOptions ORed option flags.
186 : */
187 :
188 1 : void DGNSetOptions( DGNHandle hDGN, int nOptions )
189 :
190 : {
191 1 : DGNInfo *psDGN = (DGNInfo *) hDGN;
192 :
193 1 : psDGN->options = nOptions;
194 1 : }
195 :
196 : /************************************************************************/
197 : /* DGNSetSpatialFilter() */
198 : /************************************************************************/
199 :
200 : /**
201 : * Set rectangle for which features are desired.
202 : *
203 : * If a spatial filter is set with this function, DGNReadElement() will
204 : * only return spatial elements (elements with a known bounding box) and
205 : * only those elements for which this bounding box overlaps the requested
206 : * region.
207 : *
208 : * If all four values (dfXMin, dfXMax, dfYMin and dfYMax) are zero, the
209 : * spatial filter is disabled. Note that installing a spatial filter
210 : * won't reduce the amount of data read from disk. All elements are still
211 : * scanned, but the amount of processing work for elements outside the
212 : * spatial filter is minimized.
213 : *
214 : * @param hDGN Handle from DGNOpen() for file to update.
215 : * @param dfXMin minimum x coordinate for extents (georeferenced coordinates).
216 : * @param dfYMin minimum y coordinate for extents (georeferenced coordinates).
217 : * @param dfXMax maximum x coordinate for extents (georeferenced coordinates).
218 : * @param dfYMax maximum y coordinate for extents (georeferenced coordinates).
219 : */
220 :
221 2 : void DGNSetSpatialFilter( DGNHandle hDGN,
222 : double dfXMin, double dfYMin,
223 : double dfXMax, double dfYMax )
224 :
225 : {
226 2 : DGNInfo *psDGN = (DGNInfo *) hDGN;
227 :
228 2 : if( dfXMin == 0.0 && dfXMax == 0.0
229 : && dfYMin == 0.0 && dfYMax == 0.0 )
230 : {
231 1 : psDGN->has_spatial_filter = FALSE;
232 1 : return;
233 : }
234 :
235 1 : psDGN->has_spatial_filter = TRUE;
236 1 : psDGN->sf_converted_to_uor = FALSE;
237 :
238 1 : psDGN->sf_min_x_geo = dfXMin;
239 1 : psDGN->sf_min_y_geo = dfYMin;
240 1 : psDGN->sf_max_x_geo = dfXMax;
241 1 : psDGN->sf_max_y_geo = dfYMax;
242 :
243 1 : DGNSpatialFilterToUOR( psDGN );
244 :
245 : }
246 :
247 : /************************************************************************/
248 : /* DGNSpatialFilterToUOR() */
249 : /************************************************************************/
250 :
251 1 : void DGNSpatialFilterToUOR( DGNInfo *psDGN )
252 :
253 : {
254 : DGNPoint sMin, sMax;
255 :
256 1 : if( psDGN->sf_converted_to_uor
257 : || !psDGN->has_spatial_filter
258 : || !psDGN->got_tcb )
259 0 : return;
260 :
261 1 : sMin.x = psDGN->sf_min_x_geo;
262 1 : sMin.y = psDGN->sf_min_y_geo;
263 1 : sMin.z = 0;
264 :
265 1 : sMax.x = psDGN->sf_max_x_geo;
266 1 : sMax.y = psDGN->sf_max_y_geo;
267 1 : sMax.z = 0;
268 :
269 1 : DGNInverseTransformPoint( psDGN, &sMin );
270 1 : DGNInverseTransformPoint( psDGN, &sMax );
271 :
272 1 : psDGN->sf_min_x = (GUInt32) (sMin.x + 2147483648.0);
273 1 : psDGN->sf_min_y = (GUInt32) (sMin.y + 2147483648.0);
274 1 : psDGN->sf_max_x = (GUInt32) (sMax.x + 2147483648.0);
275 1 : psDGN->sf_max_y = (GUInt32) (sMax.y + 2147483648.0);
276 :
277 1 : psDGN->sf_converted_to_uor = TRUE;
278 : }
279 :
280 : /************************************************************************/
281 : /* DGNClose() */
282 : /************************************************************************/
283 :
284 : /**
285 : * Close DGN file.
286 : *
287 : * @param hDGN Handle from DGNOpen() for file to close.
288 : */
289 :
290 5 : void DGNClose( DGNHandle hDGN )
291 :
292 : {
293 5 : DGNInfo *psDGN = (DGNInfo *) hDGN;
294 :
295 5 : VSIFClose( psDGN->fp );
296 5 : CPLFree( psDGN->element_index );
297 5 : CPLFree( psDGN );
298 5 : }
299 :
300 : /************************************************************************/
301 : /* DGNGetDimension() */
302 : /************************************************************************/
303 :
304 : /**
305 : * Return 2D/3D dimension of file.
306 : *
307 : * Return 2 or 3 depending on the dimension value of the provided file.
308 : */
309 :
310 21 : int DGNGetDimension( DGNHandle hDGN )
311 :
312 : {
313 21 : DGNInfo *psDGN = (DGNInfo *) hDGN;
314 :
315 21 : return psDGN->dimension;
316 : }
|