Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: Implements OGRAVCBinLayer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.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 "ogr_avc.h"
30 : #include "ogr_api.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : #include <cstdlib>
35 :
36 : /************************************************************************/
37 : /* OGRAVCBinLayer() */
38 : /************************************************************************/
39 :
40 7 : OGRAVCBinLayer::OGRAVCBinLayer(OGRAVCBinDataSource *poDSIn,
41 7 : AVCE00Section *psSectionIn)
42 : : OGRAVCLayer(psSectionIn->eType, poDSIn), m_psSection(psSectionIn),
43 : hFile(nullptr), poArcLayer(nullptr), bNeedReset(false), hTable(nullptr),
44 7 : nTableBaseField(-1), nTableAttrIndex(-1), nNextFID(1)
45 : {
46 7 : SetupFeatureDefinition(m_psSection->pszName);
47 :
48 7 : szTableName[0] = '\0';
49 7 : if (m_psSection->eType == AVCFilePAL)
50 1 : snprintf(szTableName, sizeof(szTableName), "%s.PAT",
51 1 : poDS->GetCoverageName());
52 6 : else if (m_psSection->eType == AVCFileRPL)
53 0 : snprintf(szTableName, sizeof(szTableName), "%s.PAT%s",
54 0 : poDS->GetCoverageName(), m_psSection->pszName);
55 6 : else if (m_psSection->eType == AVCFileARC)
56 2 : snprintf(szTableName, sizeof(szTableName), "%s.AAT",
57 2 : poDS->GetCoverageName());
58 4 : else if (m_psSection->eType == AVCFileLAB)
59 : {
60 : AVCE00ReadPtr psInfo =
61 3 : static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
62 :
63 6 : snprintf(szTableName, sizeof(szTableName), "%s.PAT",
64 3 : poDS->GetCoverageName());
65 :
66 41 : for (int iSection = 0; iSection < psInfo->numSections; iSection++)
67 : {
68 38 : if (psInfo->pasSections[iSection].eType == AVCFilePAL)
69 1 : nTableAttrIndex = poFeatureDefn->GetFieldIndex("PolyId");
70 : }
71 : }
72 :
73 7 : CheckSetupTable();
74 7 : }
75 :
76 : /************************************************************************/
77 : /* ~OGRAVCBinLayer() */
78 : /************************************************************************/
79 :
80 14 : OGRAVCBinLayer::~OGRAVCBinLayer()
81 :
82 : {
83 7 : OGRAVCBinLayer::ResetReading();
84 14 : }
85 :
86 : /************************************************************************/
87 : /* ResetReading() */
88 : /************************************************************************/
89 :
90 14 : void OGRAVCBinLayer::ResetReading()
91 :
92 : {
93 14 : if (hFile != nullptr)
94 : {
95 7 : AVCBinReadClose(hFile);
96 7 : hFile = nullptr;
97 : }
98 :
99 14 : bNeedReset = false;
100 14 : nNextFID = 1;
101 14 : m_bEOF = false;
102 :
103 14 : if (hTable != nullptr)
104 : {
105 4 : AVCBinReadClose(hTable);
106 4 : hTable = nullptr;
107 : }
108 14 : }
109 :
110 : /************************************************************************/
111 : /* GetFeature() */
112 : /************************************************************************/
113 :
114 209 : OGRFeature *OGRAVCBinLayer::GetFeature(GIntBig nFID)
115 :
116 : {
117 209 : if (!CPL_INT64_FITS_ON_INT32(nFID))
118 0 : return nullptr;
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* If we haven't started yet, open the file now. */
122 : /* -------------------------------------------------------------------- */
123 209 : if (hFile == nullptr)
124 : {
125 : AVCE00ReadPtr psInfo =
126 7 : static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
127 :
128 14 : hFile = AVCBinReadOpen(psInfo->pszCoverPath, m_psSection->pszFilename,
129 7 : psInfo->eCoverType, m_psSection->eType,
130 : psInfo->psDBCSInfo);
131 7 : if (hFile == nullptr)
132 0 : return nullptr;
133 : }
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* Read the raw feature - the SERIAL_ACCESS_FID fid is a special flag
137 : */
138 : /* indicating serial access. */
139 : /* -------------------------------------------------------------------- */
140 209 : void *pFeature = nullptr;
141 :
142 209 : if (nFID == SERIAL_ACCESS_FID)
143 : {
144 357 : while ((pFeature = AVCBinReadNextObject(hFile)) != nullptr &&
145 176 : !MatchesSpatialFilter(pFeature))
146 : {
147 0 : nNextFID++;
148 : }
149 : }
150 : else
151 : {
152 28 : bNeedReset = true;
153 28 : pFeature = AVCBinReadObject(hFile, (int)nFID);
154 : }
155 :
156 209 : if (pFeature == nullptr)
157 5 : return nullptr;
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Translate the feature. */
161 : /* -------------------------------------------------------------------- */
162 204 : OGRFeature *poFeature = TranslateFeature(pFeature);
163 204 : if (poFeature == nullptr)
164 0 : return nullptr;
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* LAB's we have to assign the FID to directly, since it */
168 : /* doesn't seem to be stored in the file structure. */
169 : /* -------------------------------------------------------------------- */
170 204 : if (m_psSection->eType == AVCFileLAB)
171 : {
172 160 : if (nFID == SERIAL_ACCESS_FID)
173 160 : poFeature->SetFID(nNextFID++);
174 : else
175 0 : poFeature->SetFID(nFID);
176 : }
177 :
178 : /* -------------------------------------------------------------------- */
179 : /* If this is a polygon layer, try to assemble the arcs to form */
180 : /* the whole polygon geometry. */
181 : /* -------------------------------------------------------------------- */
182 204 : if (m_psSection->eType == AVCFilePAL || m_psSection->eType == AVCFileRPL)
183 8 : FormPolygonGeometry(poFeature, (AVCPal *)pFeature);
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* If we have an attribute table, append the attributes now. */
187 : /* -------------------------------------------------------------------- */
188 204 : AppendTableFields(poFeature);
189 :
190 204 : return poFeature;
191 : }
192 :
193 : /************************************************************************/
194 : /* GetNextFeature() */
195 : /************************************************************************/
196 :
197 179 : OGRFeature *OGRAVCBinLayer::GetNextFeature()
198 :
199 : {
200 179 : if (m_bEOF)
201 0 : return nullptr;
202 :
203 179 : if (bNeedReset)
204 0 : ResetReading();
205 :
206 179 : OGRFeature *poFeature = GetFeature(SERIAL_ACCESS_FID);
207 :
208 : // Skip universe polygon.
209 185 : if (poFeature != nullptr && poFeature->GetFID() == 1 &&
210 6 : m_psSection->eType == AVCFilePAL)
211 : {
212 2 : OGRFeature::DestroyFeature(poFeature);
213 2 : poFeature = GetFeature(SERIAL_ACCESS_FID);
214 : }
215 :
216 353 : while (poFeature != nullptr &&
217 174 : ((m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poFeature)) ||
218 174 : !FilterGeometry(poFeature->GetGeometryRef())))
219 : {
220 0 : OGRFeature::DestroyFeature(poFeature);
221 0 : poFeature = GetFeature(SERIAL_ACCESS_FID);
222 : }
223 :
224 179 : if (poFeature == nullptr)
225 5 : m_bEOF = true;
226 :
227 179 : return poFeature;
228 : }
229 :
230 : /************************************************************************/
231 : /* TestCapability() */
232 : /************************************************************************/
233 :
234 0 : int OGRAVCBinLayer::TestCapability(const char *pszCap)
235 :
236 : {
237 0 : if (eSectionType == AVCFileARC && EQUAL(pszCap, OLCRandomRead))
238 0 : return TRUE;
239 :
240 0 : return OGRAVCLayer::TestCapability(pszCap);
241 : }
242 :
243 : /************************************************************************/
244 : /* FormPolygonGeometry() */
245 : /* */
246 : /* Collect all the arcs forming edges to this polygon and form */
247 : /* them into the appropriate OGR geometry on the target feature. */
248 : /************************************************************************/
249 :
250 8 : bool OGRAVCBinLayer::FormPolygonGeometry(OGRFeature *poFeature, AVCPal *psPAL)
251 :
252 : {
253 : /* -------------------------------------------------------------------- */
254 : /* Try to find the corresponding ARC layer if not already */
255 : /* recorded. */
256 : /* -------------------------------------------------------------------- */
257 8 : if (poArcLayer == nullptr)
258 : {
259 5 : for (int i = 0; i < poDS->GetLayerCount(); i++)
260 : {
261 : OGRAVCBinLayer *poLayer =
262 4 : static_cast<OGRAVCBinLayer *>(poDS->GetLayer(i));
263 :
264 4 : if (poLayer->eSectionType == AVCFileARC)
265 1 : poArcLayer = poLayer;
266 : }
267 :
268 1 : if (poArcLayer == nullptr)
269 0 : return false;
270 : }
271 :
272 : /* -------------------------------------------------------------------- */
273 : /* Read all the arcs related to this polygon, making a working */
274 : /* copy of them since the one returned by AVC is temporary. */
275 : /* -------------------------------------------------------------------- */
276 16 : OGRGeometryCollection oArcs;
277 :
278 38 : for (int iArc = 0; iArc < psPAL->numArcs; iArc++)
279 : {
280 30 : if (psPAL->pasArcs[iArc].nArcId == 0)
281 2 : continue;
282 :
283 : // If the other side of the line is the same polygon then this
284 : // arc is a "bridge" arc and can be discarded. If we don't discard
285 : // it, then we should double it as bridge arcs seem to only appear
286 : // once. But by discarding it we ensure a multi-ring polygon will be
287 : // properly formed.
288 28 : if (psPAL->pasArcs[iArc].nAdjPoly == psPAL->nPolyId)
289 0 : continue;
290 :
291 : OGRFeature *poArc =
292 28 : poArcLayer->GetFeature(std::abs(psPAL->pasArcs[iArc].nArcId));
293 :
294 28 : if (poArc == nullptr)
295 0 : return false;
296 :
297 28 : if (poArc->GetGeometryRef() == nullptr)
298 0 : return false;
299 :
300 28 : oArcs.addGeometry(poArc->GetGeometryRef());
301 28 : OGRFeature::DestroyFeature(poArc);
302 : }
303 :
304 : OGRErr eErr;
305 8 : OGRGeometry *poPolygon = OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
306 : (OGRGeometryH)&oArcs, TRUE, FALSE, 0.0, &eErr));
307 8 : if (poPolygon != nullptr)
308 : {
309 8 : poPolygon->assignSpatialReference(GetSpatialRef());
310 8 : poFeature->SetGeometryDirectly(poPolygon);
311 : }
312 :
313 8 : return eErr == OGRERR_NONE;
314 : }
315 :
316 : /************************************************************************/
317 : /* CheckSetupTable() */
318 : /* */
319 : /* Check if the named table exists, and if so, setup access to */
320 : /* it (open it), and add its fields to the feature class */
321 : /* definition. */
322 : /************************************************************************/
323 :
324 7 : bool OGRAVCBinLayer::CheckSetupTable()
325 :
326 : {
327 7 : if (szTableName[0] == '\0')
328 1 : return false;
329 :
330 : /* -------------------------------------------------------------------- */
331 : /* Scan for the indicated section. */
332 : /* -------------------------------------------------------------------- */
333 6 : AVCE00ReadPtr psInfo = static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
334 :
335 6 : AVCE00Section *l_psSection = nullptr;
336 86 : for (int iSection = 0; iSection < psInfo->numSections; iSection++)
337 : {
338 160 : if (EQUAL(szTableName,
339 163 : CPLString(psInfo->pasSections[iSection].pszName).Trim()) &&
340 3 : psInfo->pasSections[iSection].eType == AVCFileTABLE)
341 3 : l_psSection = psInfo->pasSections + iSection;
342 : }
343 :
344 6 : if (l_psSection == nullptr)
345 : {
346 3 : szTableName[0] = '\0';
347 3 : return false;
348 : }
349 :
350 : /* -------------------------------------------------------------------- */
351 : /* Try opening the table. */
352 : /* -------------------------------------------------------------------- */
353 3 : hTable =
354 3 : AVCBinReadOpen(psInfo->pszInfoPath, szTableName, psInfo->eCoverType,
355 : AVCFileTABLE, psInfo->psDBCSInfo);
356 :
357 3 : if (hTable == nullptr)
358 : {
359 0 : szTableName[0] = '\0';
360 0 : return false;
361 : }
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Setup attributes. */
365 : /* -------------------------------------------------------------------- */
366 3 : nTableBaseField = poFeatureDefn->GetFieldCount();
367 :
368 3 : AppendTableDefinition(hTable->hdr.psTableDef);
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Close table so we don't have to many files open at once. */
372 : /* -------------------------------------------------------------------- */
373 3 : AVCBinReadClose(hTable);
374 :
375 3 : hTable = nullptr;
376 :
377 3 : return true;
378 : }
379 :
380 : /************************************************************************/
381 : /* AppendTableFields() */
382 : /************************************************************************/
383 :
384 204 : bool OGRAVCBinLayer::AppendTableFields(OGRFeature *poFeature)
385 :
386 : {
387 204 : AVCE00ReadPtr psInfo = static_cast<OGRAVCBinDataSource *>(poDS)->GetInfo();
388 :
389 204 : if (szTableName[0] == '\0')
390 36 : return false;
391 :
392 : /* -------------------------------------------------------------------- */
393 : /* Open the table if it is currently closed. */
394 : /* -------------------------------------------------------------------- */
395 168 : if (hTable == nullptr)
396 : {
397 4 : hTable =
398 4 : AVCBinReadOpen(psInfo->pszInfoPath, szTableName, psInfo->eCoverType,
399 : AVCFileTABLE, psInfo->psDBCSInfo);
400 : }
401 :
402 168 : if (hTable == nullptr)
403 0 : return false;
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Read the info record. */
407 : /* */
408 : /* We usually assume the FID of the feature is the key but in a */
409 : /* polygon coverage we need to use the PolyId attribute of LAB */
410 : /* features to lookup the related attributes. In this case */
411 : /* nTableAttrIndex will already be setup to refer to the */
412 : /* PolyId field. */
413 : /* -------------------------------------------------------------------- */
414 168 : const int nRecordId = nTableAttrIndex == -1
415 168 : ? static_cast<int>(poFeature->GetFID())
416 0 : : poFeature->GetFieldAsInteger(nTableAttrIndex);
417 :
418 168 : void *hRecord = AVCBinReadObject(hTable, nRecordId);
419 168 : if (hRecord == nullptr)
420 0 : return false;
421 :
422 : /* -------------------------------------------------------------------- */
423 : /* Translate it. */
424 : /* -------------------------------------------------------------------- */
425 336 : return TranslateTableFields(poFeature, nTableBaseField,
426 168 : hTable->hdr.psTableDef, (AVCField *)hRecord);
427 : }
|