Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Microstation DGN Access Library
4 : * Purpose: DGN Access Library file open code.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "dgnlibp.h"
30 :
31 : /************************************************************************/
32 : /* DGNTestOpen() */
33 : /************************************************************************/
34 :
35 : /**
36 : * Test if header is DGN.
37 : *
38 : * @param pabyHeader block of header data from beginning of file.
39 : * @param nByteCount number of bytes in pabyHeader.
40 : *
41 : * @return TRUE if the header appears to be from a DGN file, otherwise FALSE.
42 : */
43 :
44 3712 : int DGNTestOpen(GByte *pabyHeader, int nByteCount)
45 :
46 : {
47 3712 : if (nByteCount < 4)
48 0 : return FALSE;
49 :
50 : // Is it a cell library?
51 3712 : if (pabyHeader[0] == 0x08 && pabyHeader[1] == 0x05 &&
52 0 : pabyHeader[2] == 0x17 && pabyHeader[3] == 0x00)
53 0 : return TRUE;
54 :
55 : // Is it not a regular 2D or 3D file?
56 3712 : if ((pabyHeader[0] != 0x08 && pabyHeader[0] != 0xC8) ||
57 226 : pabyHeader[1] != 0x09 || pabyHeader[2] != 0xFE || pabyHeader[3] != 0x02)
58 3486 : return FALSE;
59 :
60 226 : return TRUE;
61 : }
62 :
63 : /************************************************************************/
64 : /* DGNOpen() */
65 : /************************************************************************/
66 :
67 : /**
68 : * Open a DGN file.
69 : *
70 : * The file is opened, and minimally verified to ensure it is a DGN (ISFF)
71 : * file. If the file cannot be opened for read access an error with code
72 : * CPLE_OpenFailed with be reported via CPLError() and NULL returned.
73 : * If the file header does
74 : * not appear to be a DGN file, an error with code CPLE_AppDefined will be
75 : * reported via CPLError(), and NULL returned.
76 : *
77 : * If successful a handle for further access is returned. This should be
78 : * closed with DGNClose() when no longer needed.
79 : *
80 : * DGNOpen() does not scan the file on open, and should be very fast even for
81 : * large files.
82 : *
83 : * @param pszFilename name of file to try opening.
84 : * @param bUpdate should the file be opened with read+update (r+) mode?
85 : *
86 : * @return handle to use for further access to file using DGN API, or NULL
87 : * if open fails.
88 : */
89 :
90 106 : DGNHandle DGNOpen(const char *pszFilename, int bUpdate)
91 :
92 : {
93 : /* -------------------------------------------------------------------- */
94 : /* Open the file. */
95 : /* -------------------------------------------------------------------- */
96 106 : VSILFILE *fp = VSIFOpenL(pszFilename, bUpdate ? "rb+" : "rb");
97 106 : if (fp == nullptr)
98 : {
99 0 : CPLError(CE_Failure, CPLE_OpenFailed,
100 : "Unable to open `%s' for read access.\n", pszFilename);
101 0 : return nullptr;
102 : }
103 :
104 : /* -------------------------------------------------------------------- */
105 : /* Verify the format ... add later. */
106 : /* -------------------------------------------------------------------- */
107 : GByte abyHeader[512];
108 : const int nHeaderBytes =
109 106 : static_cast<int>(VSIFReadL(abyHeader, 1, sizeof(abyHeader), fp));
110 106 : if (!DGNTestOpen(abyHeader, nHeaderBytes))
111 : {
112 0 : CPLError(CE_Failure, CPLE_AppDefined,
113 : "File `%s' does not have expected DGN header.\n", pszFilename);
114 0 : VSIFCloseL(fp);
115 0 : return nullptr;
116 : }
117 :
118 106 : VSIRewindL(fp);
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Create the info structure. */
122 : /* -------------------------------------------------------------------- */
123 106 : DGNInfo *psDGN = static_cast<DGNInfo *>(CPLCalloc(sizeof(DGNInfo), 1));
124 106 : psDGN->fp = fp;
125 106 : psDGN->next_element_id = 0;
126 :
127 106 : psDGN->got_tcb = false;
128 106 : psDGN->scale = 1.0;
129 106 : psDGN->origin_x = 0.0;
130 106 : psDGN->origin_y = 0.0;
131 106 : psDGN->origin_z = 0.0;
132 :
133 106 : psDGN->index_built = false;
134 106 : psDGN->element_count = 0;
135 106 : psDGN->element_index = nullptr;
136 :
137 106 : psDGN->got_bounds = false;
138 :
139 106 : if (abyHeader[0] == 0xC8)
140 42 : psDGN->dimension = 3;
141 : else
142 64 : psDGN->dimension = 2;
143 :
144 106 : psDGN->has_spatial_filter = false;
145 106 : psDGN->sf_converted_to_uor = false;
146 106 : psDGN->select_complex_group = false;
147 106 : psDGN->in_complex_group = false;
148 :
149 106 : return (DGNHandle)psDGN;
150 : }
151 :
152 : /************************************************************************/
153 : /* DGNSetOptions() */
154 : /************************************************************************/
155 :
156 : /**
157 : * Set file access options.
158 : *
159 : * Sets a flag affecting how the file is accessed. Currently
160 : * there is only one support flag:
161 : *
162 : * DGNO_CAPTURE_RAW_DATA: If this is enabled (it is off by default),
163 : * then the raw binary data associated with elements will be kept in
164 : * the raw_data field within the DGNElemCore when they are read. This
165 : * is required if the application needs to interpret the raw data itself.
166 : * It is also necessary if the element is to be written back to this file,
167 : * or another file using DGNWriteElement(). Off by default (to conserve
168 : * memory).
169 : *
170 : * @param hDGN handle to file returned by DGNOpen().
171 : * @param nOptions ORed option flags.
172 : */
173 :
174 33 : void DGNSetOptions(DGNHandle hDGN, int nOptions)
175 :
176 : {
177 33 : DGNInfo *psDGN = (DGNInfo *)hDGN;
178 :
179 33 : psDGN->options = nOptions;
180 33 : }
181 :
182 : /************************************************************************/
183 : /* DGNSetSpatialFilter() */
184 : /************************************************************************/
185 :
186 : /**
187 : * Set rectangle for which features are desired.
188 : *
189 : * If a spatial filter is set with this function, DGNReadElement() will
190 : * only return spatial elements (elements with a known bounding box) and
191 : * only those elements for which this bounding box overlaps the requested
192 : * region.
193 : *
194 : * If all four values (dfXMin, dfXMax, dfYMin and dfYMax) are zero, the
195 : * spatial filter is disabled. Note that installing a spatial filter
196 : * won't reduce the amount of data read from disk. All elements are still
197 : * scanned, but the amount of processing work for elements outside the
198 : * spatial filter is minimized.
199 : *
200 : * @param hDGN Handle from DGNOpen() for file to update.
201 : * @param dfXMin minimum x coordinate for extents (georeferenced coordinates).
202 : * @param dfYMin minimum y coordinate for extents (georeferenced coordinates).
203 : * @param dfXMax maximum x coordinate for extents (georeferenced coordinates).
204 : * @param dfYMax maximum y coordinate for extents (georeferenced coordinates).
205 : */
206 :
207 2 : void DGNSetSpatialFilter(DGNHandle hDGN, double dfXMin, double dfYMin,
208 : double dfXMax, double dfYMax)
209 :
210 : {
211 2 : DGNInfo *psDGN = (DGNInfo *)hDGN;
212 :
213 2 : if (dfXMin == 0.0 && dfXMax == 0.0 && dfYMin == 0.0 && dfYMax == 0.0)
214 : {
215 1 : psDGN->has_spatial_filter = false;
216 1 : return;
217 : }
218 :
219 1 : psDGN->has_spatial_filter = true;
220 1 : psDGN->sf_converted_to_uor = false;
221 :
222 1 : psDGN->sf_min_x_geo = dfXMin;
223 1 : psDGN->sf_min_y_geo = dfYMin;
224 1 : psDGN->sf_max_x_geo = dfXMax;
225 1 : psDGN->sf_max_y_geo = dfYMax;
226 :
227 1 : DGNSpatialFilterToUOR(psDGN);
228 : }
229 :
230 : /************************************************************************/
231 : /* DGNSpatialFilterToUOR() */
232 : /************************************************************************/
233 :
234 2 : void DGNSpatialFilterToUOR(DGNInfo *psDGN)
235 :
236 : {
237 2 : if (psDGN->sf_converted_to_uor || !psDGN->has_spatial_filter ||
238 2 : !psDGN->got_tcb)
239 1 : return;
240 :
241 1 : DGNPoint sMin = {psDGN->sf_min_x_geo, psDGN->sf_min_y_geo, 0};
242 :
243 1 : DGNPoint sMax = {psDGN->sf_max_x_geo, psDGN->sf_max_y_geo, 0};
244 :
245 1 : DGNInverseTransformPoint(psDGN, &sMin);
246 1 : DGNInverseTransformPoint(psDGN, &sMax);
247 :
248 1 : psDGN->sf_min_x = (GUInt32)(sMin.x + 2147483648.0);
249 1 : psDGN->sf_min_y = (GUInt32)(sMin.y + 2147483648.0);
250 1 : psDGN->sf_max_x = (GUInt32)(sMax.x + 2147483648.0);
251 1 : psDGN->sf_max_y = (GUInt32)(sMax.y + 2147483648.0);
252 :
253 1 : psDGN->sf_converted_to_uor = true;
254 : }
255 :
256 : /************************************************************************/
257 : /* DGNClose() */
258 : /************************************************************************/
259 :
260 : /**
261 : * Close DGN file.
262 : *
263 : * @param hDGN Handle from DGNOpen() for file to close.
264 : */
265 :
266 106 : void DGNClose(DGNHandle hDGN)
267 :
268 : {
269 106 : DGNInfo *psDGN = (DGNInfo *)hDGN;
270 :
271 106 : VSIFCloseL(psDGN->fp);
272 106 : CPLFree(psDGN->element_index);
273 106 : CPLFree(psDGN);
274 106 : }
275 :
276 : /************************************************************************/
277 : /* DGNGetDimension() */
278 : /************************************************************************/
279 :
280 : /**
281 : * Return 2D/3D dimension of file.
282 : *
283 : * Return 2 or 3 depending on the dimension value of the provided file.
284 : */
285 :
286 40 : int DGNGetDimension(DGNHandle hDGN)
287 :
288 : {
289 40 : DGNInfo *psDGN = (DGNInfo *)hDGN;
290 :
291 40 : return psDGN->dimension;
292 : }
|