Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Idrisi Translator
4 : * Purpose: Implements OGRIdrisiLayer class.
5 : * Author: Even Rouault, <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.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 "cpl_conv.h"
30 : #include "cpl_string.h"
31 : #include "ogr_idrisi.h"
32 : #include "ogr_p.h"
33 : #include "ogr_srs_api.h"
34 :
35 : /************************************************************************/
36 : /* OGRIdrisiLayer() */
37 : /************************************************************************/
38 :
39 3 : OGRIdrisiLayer::OGRIdrisiLayer(const char *pszFilename,
40 : const char *pszLayerName, VSILFILE *fpIn,
41 : OGRwkbGeometryType eGeomTypeIn,
42 3 : const char *pszWTKString)
43 3 : : poFeatureDefn(new OGRFeatureDefn(pszLayerName)), poSRS(nullptr),
44 : eGeomType(eGeomTypeIn), fp(fpIn), fpAVL(nullptr), bEOF(false),
45 : nNextFID(1), bExtentValid(false), dfMinX(0.0), dfMinY(0.0), dfMaxX(0.0),
46 3 : dfMaxY(0.0), nTotalFeatures(0)
47 : {
48 3 : if (pszWTKString)
49 : {
50 3 : poSRS = new OGRSpatialReference();
51 3 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
52 3 : poSRS->importFromWkt(pszWTKString);
53 : }
54 :
55 3 : SetDescription(poFeatureDefn->GetName());
56 3 : poFeatureDefn->Reference();
57 3 : poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
58 3 : poFeatureDefn->SetGeomType(eGeomType);
59 :
60 6 : OGRFieldDefn oFieldDefn("id", OFTReal);
61 3 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
62 :
63 3 : VSIFSeekL(fp, 1, SEEK_SET);
64 3 : if (VSIFReadL(&nTotalFeatures, sizeof(unsigned int), 1, fp) != 1)
65 0 : nTotalFeatures = 0;
66 3 : CPL_LSBPTR32(&nTotalFeatures);
67 :
68 3 : if (nTotalFeatures != 0)
69 : {
70 3 : if (!Detect_AVL_ADC(pszFilename))
71 : {
72 2 : if (fpAVL != nullptr)
73 0 : VSIFCloseL(fpAVL);
74 2 : fpAVL = nullptr;
75 : }
76 : }
77 :
78 3 : OGRIdrisiLayer::ResetReading();
79 3 : }
80 :
81 : /************************************************************************/
82 : /* ~OGRIdrisiLayer() */
83 : /************************************************************************/
84 :
85 6 : OGRIdrisiLayer::~OGRIdrisiLayer()
86 :
87 : {
88 3 : if (poSRS != nullptr)
89 3 : poSRS->Release();
90 :
91 3 : poFeatureDefn->Release();
92 :
93 3 : VSIFCloseL(fp);
94 :
95 3 : if (fpAVL != nullptr)
96 1 : VSIFCloseL(fpAVL);
97 6 : }
98 :
99 : /************************************************************************/
100 : /* Detect_AVL_ADC() */
101 : /************************************************************************/
102 :
103 3 : bool OGRIdrisiLayer::Detect_AVL_ADC(const char *pszFilename)
104 : {
105 : // --------------------------------------------------------------------
106 : // Look for .adc file
107 : // --------------------------------------------------------------------
108 3 : const char *pszADCFilename = CPLResetExtension(pszFilename, "adc");
109 3 : VSILFILE *fpADC = VSIFOpenL(pszADCFilename, "rb");
110 3 : if (fpADC == nullptr)
111 : {
112 2 : pszADCFilename = CPLResetExtension(pszFilename, "ADC");
113 2 : fpADC = VSIFOpenL(pszADCFilename, "rb");
114 : }
115 :
116 3 : char **papszADC = nullptr;
117 3 : if (fpADC != nullptr)
118 : {
119 1 : VSIFCloseL(fpADC);
120 1 : fpADC = nullptr;
121 :
122 1 : CPLPushErrorHandler(CPLQuietErrorHandler);
123 1 : papszADC = CSLLoad2(pszADCFilename, 1024, 256, nullptr);
124 1 : CPLPopErrorHandler();
125 1 : CPLErrorReset();
126 : }
127 :
128 3 : if (papszADC == nullptr)
129 2 : return false;
130 :
131 1 : CSLSetNameValueSeparator(papszADC, ":");
132 :
133 1 : const char *pszVersion = CSLFetchNameValue(papszADC, "file format");
134 1 : if (pszVersion == nullptr || !EQUAL(pszVersion, "IDRISI Values A.1"))
135 : {
136 0 : CSLDestroy(papszADC);
137 0 : return false;
138 : }
139 :
140 1 : const char *pszFileType = CSLFetchNameValue(papszADC, "file type");
141 1 : if (pszFileType == nullptr || !EQUAL(pszFileType, "ascii"))
142 : {
143 0 : CPLDebug("IDRISI", ".adc file found, but file type != ascii");
144 0 : CSLDestroy(papszADC);
145 0 : return false;
146 : }
147 :
148 1 : const char *pszRecords = CSLFetchNameValue(papszADC, "records");
149 1 : if (pszRecords == nullptr || atoi(pszRecords) != (int)nTotalFeatures)
150 : {
151 0 : CPLDebug("IDRISI", ".adc file found, but 'records' not found or not "
152 : "consistent with feature number declared in .vdc");
153 0 : CSLDestroy(papszADC);
154 0 : return false;
155 : }
156 :
157 1 : const char *pszFields = CSLFetchNameValue(papszADC, "fields");
158 1 : if (pszFields == nullptr || atoi(pszFields) <= 1)
159 : {
160 0 : CPLDebug("IDRISI",
161 : ".adc file found, but 'fields' not found or invalid");
162 0 : CSLDestroy(papszADC);
163 0 : return false;
164 : }
165 :
166 : // --------------------------------------------------------------------
167 : // Look for .avl file
168 : // --------------------------------------------------------------------
169 1 : const char *pszAVLFilename = CPLResetExtension(pszFilename, "avl");
170 1 : fpAVL = VSIFOpenL(pszAVLFilename, "rb");
171 1 : if (fpAVL == nullptr)
172 : {
173 0 : pszAVLFilename = CPLResetExtension(pszFilename, "AVL");
174 0 : fpAVL = VSIFOpenL(pszAVLFilename, "rb");
175 : }
176 1 : if (fpAVL == nullptr)
177 : {
178 0 : CSLDestroy(papszADC);
179 0 : return false;
180 : }
181 :
182 : // --------------------------------------------------------------------
183 : // Build layer definition
184 : // --------------------------------------------------------------------
185 :
186 : char szKey[32];
187 1 : int iCurField = 0;
188 1 : snprintf(szKey, sizeof(szKey), "field %d", iCurField);
189 :
190 1 : char **papszIter = papszADC;
191 1 : const char *pszLine = nullptr;
192 1 : bool bFieldFound = false;
193 2 : CPLString osFieldName;
194 14 : while ((pszLine = *papszIter) != nullptr)
195 : {
196 : // CPLDebug("IDRISI", "%s", pszLine);
197 13 : if (strncmp(pszLine, szKey, strlen(szKey)) == 0)
198 : {
199 4 : const char *pszColon = strchr(pszLine, ':');
200 4 : if (pszColon)
201 : {
202 4 : osFieldName = pszColon + 1;
203 4 : bFieldFound = true;
204 : }
205 : }
206 9 : else if (bFieldFound && STARTS_WITH(pszLine, "data type:"))
207 : {
208 4 : const char *pszFieldType = pszLine + strlen("data type:");
209 :
210 : OGRFieldDefn oFieldDefn(osFieldName.c_str(),
211 4 : EQUAL(pszFieldType, "integer") ? OFTInteger
212 2 : : EQUAL(pszFieldType, "real") ? OFTReal
213 6 : : OFTString);
214 :
215 4 : if (iCurField == 0 && oFieldDefn.GetType() != OFTInteger)
216 : {
217 0 : CSLDestroy(papszADC);
218 0 : return false;
219 : }
220 :
221 4 : if (iCurField != 0)
222 3 : poFeatureDefn->AddFieldDefn(&oFieldDefn);
223 :
224 4 : iCurField++;
225 4 : snprintf(szKey, sizeof(szKey), "field %d", iCurField);
226 : }
227 :
228 13 : papszIter++;
229 : }
230 :
231 1 : CSLDestroy(papszADC);
232 :
233 1 : return true;
234 : }
235 :
236 : /************************************************************************/
237 : /* ResetReading() */
238 : /************************************************************************/
239 :
240 11 : void OGRIdrisiLayer::ResetReading()
241 :
242 : {
243 11 : nNextFID = 1;
244 11 : bEOF = false;
245 11 : VSIFSeekL(fp, 0x105, SEEK_SET);
246 11 : if (fpAVL != nullptr)
247 5 : VSIFSeekL(fpAVL, 0, SEEK_SET);
248 11 : }
249 :
250 : /************************************************************************/
251 : /* TestCapability() */
252 : /************************************************************************/
253 :
254 6 : int OGRIdrisiLayer::TestCapability(const char *pszCap)
255 :
256 : {
257 6 : if (EQUAL(pszCap, OLCFastFeatureCount))
258 3 : return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
259 :
260 3 : if (EQUAL(pszCap, OLCFastGetExtent))
261 3 : return bExtentValid;
262 :
263 0 : return FALSE;
264 : }
265 :
266 : /************************************************************************/
267 : /* GetNextRawFeature() */
268 : /************************************************************************/
269 :
270 10 : OGRFeature *OGRIdrisiLayer::GetNextRawFeature()
271 : {
272 10 : if (bEOF)
273 0 : return nullptr;
274 :
275 : while (true)
276 : {
277 17 : if (eGeomType == wkbPoint)
278 : {
279 7 : double dfId = 0.0;
280 7 : double dfX = 0.0;
281 7 : double dfY = 0.0;
282 7 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
283 13 : VSIFReadL(&dfX, sizeof(double), 1, fp) != 1 ||
284 6 : VSIFReadL(&dfY, sizeof(double), 1, fp) != 1)
285 : {
286 4 : return nullptr;
287 : }
288 6 : CPL_LSBPTR64(&dfId);
289 6 : CPL_LSBPTR64(&dfX);
290 6 : CPL_LSBPTR64(&dfY);
291 :
292 6 : if (m_poFilterGeom != nullptr &&
293 4 : (dfX < m_sFilterEnvelope.MinX || dfX > m_sFilterEnvelope.MaxX ||
294 1 : dfY < m_sFilterEnvelope.MinY || dfY > m_sFilterEnvelope.MaxY))
295 : {
296 3 : nNextFID++;
297 3 : continue;
298 : }
299 :
300 3 : OGRPoint *poGeom = new OGRPoint(dfX, dfY);
301 3 : if (poSRS)
302 3 : poGeom->assignSpatialReference(poSRS);
303 3 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
304 3 : poFeature->SetField(0, dfId);
305 3 : poFeature->SetFID(nNextFID++);
306 3 : poFeature->SetGeometryDirectly(poGeom);
307 3 : ReadAVLLine(poFeature);
308 3 : return poFeature;
309 : }
310 10 : else if (eGeomType == wkbLineString)
311 : {
312 5 : double dfId = 0.0;
313 5 : double dfMinXShape = 0.0;
314 5 : double dfMaxXShape = 0.0;
315 5 : double dfMinYShape = 0.0;
316 5 : double dfMaxYShape = 0.0;
317 :
318 5 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
319 4 : VSIFReadL(&dfMinXShape, sizeof(double), 1, fp) != 1 ||
320 4 : VSIFReadL(&dfMaxXShape, sizeof(double), 1, fp) != 1 ||
321 13 : VSIFReadL(&dfMinYShape, sizeof(double), 1, fp) != 1 ||
322 4 : VSIFReadL(&dfMaxYShape, sizeof(double), 1, fp) != 1)
323 : {
324 1 : bEOF = true;
325 3 : return nullptr;
326 : }
327 4 : CPL_LSBPTR64(&dfId);
328 4 : CPL_LSBPTR64(&dfMinXShape);
329 4 : CPL_LSBPTR64(&dfMaxXShape);
330 4 : CPL_LSBPTR64(&dfMinYShape);
331 4 : CPL_LSBPTR64(&dfMaxYShape);
332 :
333 4 : unsigned int nNodes = 0;
334 4 : if (VSIFReadL(&nNodes, sizeof(unsigned int), 1, fp) != 1)
335 : {
336 0 : bEOF = true;
337 0 : return nullptr;
338 : }
339 4 : CPL_LSBPTR32(&nNodes);
340 :
341 4 : if (nNodes > 100 * 1000 * 1000)
342 : {
343 0 : bEOF = true;
344 0 : return nullptr;
345 : }
346 :
347 4 : if (m_poFilterGeom != nullptr &&
348 2 : (dfMaxXShape < m_sFilterEnvelope.MinX ||
349 2 : dfMinXShape > m_sFilterEnvelope.MaxX ||
350 0 : dfMaxYShape < m_sFilterEnvelope.MinY ||
351 0 : dfMinYShape > m_sFilterEnvelope.MaxY))
352 : {
353 2 : nNextFID++;
354 2 : VSIFSeekL(fp, sizeof(OGRRawPoint) * nNodes, SEEK_CUR);
355 2 : continue;
356 : }
357 :
358 : OGRRawPoint *poRawPoints = static_cast<OGRRawPoint *>(
359 2 : VSI_MALLOC2_VERBOSE(sizeof(OGRRawPoint), nNodes));
360 2 : if (poRawPoints == nullptr)
361 : {
362 0 : bEOF = true;
363 0 : return nullptr;
364 : }
365 :
366 2 : if (static_cast<unsigned int>(VSIFReadL(
367 2 : poRawPoints, sizeof(OGRRawPoint), nNodes, fp)) != nNodes)
368 : {
369 0 : VSIFree(poRawPoints);
370 0 : bEOF = true;
371 0 : return nullptr;
372 : }
373 :
374 : #if defined(CPL_MSB)
375 : for (unsigned int iNode = 0; iNode < nNodes; iNode++)
376 : {
377 : CPL_LSBPTR64(&poRawPoints[iNode].x);
378 : CPL_LSBPTR64(&poRawPoints[iNode].y);
379 : }
380 : #endif
381 :
382 2 : OGRLineString *poGeom = new OGRLineString();
383 2 : poGeom->setPoints(nNodes, poRawPoints, nullptr);
384 :
385 2 : VSIFree(poRawPoints);
386 :
387 2 : if (poSRS)
388 2 : poGeom->assignSpatialReference(poSRS);
389 2 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
390 2 : poFeature->SetField(0, dfId);
391 2 : poFeature->SetFID(nNextFID++);
392 2 : poFeature->SetGeometryDirectly(poGeom);
393 2 : ReadAVLLine(poFeature);
394 2 : return poFeature;
395 : }
396 : else // if (eGeomType == wkbPolygon)
397 : {
398 5 : double dfId = 0.0;
399 5 : double dfMinXShape = 0.0;
400 5 : double dfMaxXShape = 0.0;
401 5 : double dfMinYShape = 0.0;
402 5 : double dfMaxYShape = 0.0;
403 :
404 5 : if (VSIFReadL(&dfId, sizeof(double), 1, fp) != 1 ||
405 4 : VSIFReadL(&dfMinXShape, sizeof(double), 1, fp) != 1 ||
406 4 : VSIFReadL(&dfMaxXShape, sizeof(double), 1, fp) != 1 ||
407 13 : VSIFReadL(&dfMinYShape, sizeof(double), 1, fp) != 1 ||
408 4 : VSIFReadL(&dfMaxYShape, sizeof(double), 1, fp) != 1)
409 : {
410 1 : bEOF = true;
411 3 : return nullptr;
412 : }
413 4 : CPL_LSBPTR64(&dfId);
414 4 : CPL_LSBPTR64(&dfMinXShape);
415 4 : CPL_LSBPTR64(&dfMaxXShape);
416 4 : CPL_LSBPTR64(&dfMinYShape);
417 4 : CPL_LSBPTR64(&dfMaxYShape);
418 4 : unsigned int nParts = 0;
419 4 : unsigned int nTotalNodes = 0;
420 8 : if (VSIFReadL(&nParts, sizeof(unsigned int), 1, fp) != 1 ||
421 4 : VSIFReadL(&nTotalNodes, sizeof(unsigned int), 1, fp) != 1)
422 : {
423 0 : bEOF = true;
424 0 : return nullptr;
425 : }
426 4 : CPL_LSBPTR32(&nParts);
427 4 : CPL_LSBPTR32(&nTotalNodes);
428 :
429 4 : if (nParts > 100000 || nTotalNodes > 100 * 1000 * 1000)
430 : {
431 0 : bEOF = true;
432 0 : return nullptr;
433 : }
434 :
435 4 : if (m_poFilterGeom != nullptr &&
436 2 : (dfMaxXShape < m_sFilterEnvelope.MinX ||
437 2 : dfMinXShape > m_sFilterEnvelope.MaxX ||
438 0 : dfMaxYShape < m_sFilterEnvelope.MinY ||
439 0 : dfMinYShape > m_sFilterEnvelope.MaxY))
440 : {
441 2 : VSIFSeekL(fp,
442 2 : sizeof(unsigned int) * nParts +
443 2 : sizeof(OGRRawPoint) * nTotalNodes,
444 : SEEK_CUR);
445 2 : nNextFID++;
446 2 : continue;
447 : }
448 :
449 : OGRRawPoint *poRawPoints = static_cast<OGRRawPoint *>(
450 2 : VSI_MALLOC2_VERBOSE(sizeof(OGRRawPoint), nTotalNodes));
451 2 : if (poRawPoints == nullptr)
452 : {
453 0 : bEOF = true;
454 0 : return nullptr;
455 : }
456 2 : unsigned int *panNodesCount = nullptr;
457 2 : if (nParts > 1)
458 : {
459 : panNodesCount = static_cast<unsigned int *>(
460 1 : CPLMalloc(sizeof(unsigned int) * nParts));
461 1 : if (VSIFReadL(panNodesCount, sizeof(unsigned int) * nParts, 1,
462 1 : fp) != 1)
463 : {
464 0 : VSIFree(poRawPoints);
465 0 : VSIFree(panNodesCount);
466 0 : bEOF = true;
467 0 : return nullptr;
468 : }
469 : #if defined(CPL_MSB)
470 : for (unsigned int iPart = 0; iPart < nParts; iPart++)
471 : {
472 : CPL_LSBPTR32(&panNodesCount[iPart]);
473 : }
474 : #endif
475 : }
476 : else
477 : {
478 1 : unsigned int nNodes = 0;
479 1 : if (VSIFReadL(&nNodes, sizeof(unsigned int) * nParts, 1, fp) !=
480 : 1)
481 : {
482 0 : VSIFree(poRawPoints);
483 0 : bEOF = true;
484 0 : return nullptr;
485 : }
486 1 : CPL_LSBPTR32(&nNodes);
487 1 : if (nNodes != nTotalNodes)
488 : {
489 0 : VSIFree(poRawPoints);
490 0 : bEOF = true;
491 0 : return nullptr;
492 : }
493 : }
494 :
495 2 : OGRPolygon *poGeom = new OGRPolygon();
496 5 : for (unsigned int iPart = 0; iPart < nParts; iPart++)
497 : {
498 3 : unsigned int nNodes =
499 3 : (nParts > 1) ? panNodesCount[iPart] : nTotalNodes;
500 6 : if (nNodes > nTotalNodes ||
501 3 : static_cast<unsigned int>(VSIFReadL(poRawPoints,
502 : sizeof(OGRRawPoint),
503 3 : nNodes, fp)) != nNodes)
504 : {
505 0 : VSIFree(poRawPoints);
506 0 : VSIFree(panNodesCount);
507 0 : delete poGeom;
508 0 : bEOF = true;
509 0 : return nullptr;
510 : }
511 :
512 : #if defined(CPL_MSB)
513 : for (unsigned int iNode = 0; iNode < nNodes; iNode++)
514 : {
515 : CPL_LSBPTR64(&poRawPoints[iNode].x);
516 : CPL_LSBPTR64(&poRawPoints[iNode].y);
517 : }
518 : #endif
519 :
520 3 : OGRLinearRing *poLR = new OGRLinearRing();
521 3 : poGeom->addRingDirectly(poLR);
522 3 : poLR->setPoints(nNodes, poRawPoints, nullptr);
523 : }
524 :
525 2 : VSIFree(poRawPoints);
526 2 : VSIFree(panNodesCount);
527 :
528 2 : if (poSRS)
529 2 : poGeom->assignSpatialReference(poSRS);
530 2 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
531 2 : poFeature->SetField(0, dfId);
532 2 : poFeature->SetFID(nNextFID++);
533 2 : poFeature->SetGeometryDirectly(poGeom);
534 2 : ReadAVLLine(poFeature);
535 2 : return poFeature;
536 : }
537 7 : }
538 : }
539 :
540 : /************************************************************************/
541 : /* ReadAVLLine() */
542 : /************************************************************************/
543 :
544 7 : void OGRIdrisiLayer::ReadAVLLine(OGRFeature *poFeature)
545 : {
546 7 : if (fpAVL == nullptr)
547 4 : return;
548 :
549 3 : const char *pszLine = CPLReadLineL(fpAVL);
550 3 : if (pszLine == nullptr)
551 0 : return;
552 :
553 3 : char **papszTokens = CSLTokenizeStringComplex(pszLine, "\t", TRUE, TRUE);
554 3 : if (CSLCount(papszTokens) == poFeatureDefn->GetFieldCount())
555 : {
556 3 : const int nID = atoi(papszTokens[0]);
557 3 : if (nID == poFeature->GetFID())
558 : {
559 8 : for (int i = 1; i < poFeatureDefn->GetFieldCount(); i++)
560 : {
561 6 : poFeature->SetField(i, papszTokens[i]);
562 : }
563 : }
564 : }
565 3 : CSLDestroy(papszTokens);
566 : }
567 :
568 : /************************************************************************/
569 : /* SetExtent() */
570 : /************************************************************************/
571 :
572 3 : void OGRIdrisiLayer::SetExtent(double dfMinXIn, double dfMinYIn,
573 : double dfMaxXIn, double dfMaxYIn)
574 : {
575 3 : bExtentValid = true;
576 3 : dfMinX = dfMinXIn;
577 3 : dfMinY = dfMinYIn;
578 3 : dfMaxX = dfMaxXIn;
579 3 : dfMaxY = dfMaxYIn;
580 3 : }
581 :
582 : /************************************************************************/
583 : /* GetExtent() */
584 : /************************************************************************/
585 :
586 3 : OGRErr OGRIdrisiLayer::GetExtent(OGREnvelope *psExtent, int bForce)
587 : {
588 3 : if (!bExtentValid)
589 0 : return OGRLayer::GetExtent(psExtent, bForce);
590 :
591 3 : psExtent->MinX = dfMinX;
592 3 : psExtent->MinY = dfMinY;
593 3 : psExtent->MaxX = dfMaxX;
594 3 : psExtent->MaxY = dfMaxY;
595 3 : return OGRERR_NONE;
596 : }
597 :
598 : /************************************************************************/
599 : /* GetFeatureCount() */
600 : /************************************************************************/
601 :
602 3 : GIntBig OGRIdrisiLayer::GetFeatureCount(int bForce)
603 : {
604 3 : if (nTotalFeatures > 0 && m_poFilterGeom == nullptr &&
605 3 : m_poAttrQuery == nullptr)
606 3 : return nTotalFeatures;
607 :
608 0 : return OGRLayer::GetFeatureCount(bForce);
609 : }
|