1 : /******************************************************************************
2 : * $Id: vfkdatablocksqlite.cpp 25721 2013-03-09 16:21:46Z martinl $
3 : *
4 : * Project: VFK Reader - Data block definition (SQLite)
5 : * Purpose: Implements VFKDataBlockSQLite
6 : * Author: Martin Landa, landa.martin gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2012-2013, Martin Landa <landa.martin gmail.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person
12 : * obtaining a copy of this software and associated documentation
13 : * files (the "Software"), to deal in the Software without
14 : * restriction, including without limitation the rights to use, copy,
15 : * modify, merge, publish, distribute, sublicense, and/or sell copies
16 : * of the Software, and to permit persons to whom the Software is
17 : * furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be
20 : * included in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26 : * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 : * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 : * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 : * SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include <algorithm>
33 :
34 : #include "vfkreader.h"
35 : #include "vfkreaderp.h"
36 :
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 :
40 : /*!
41 : \brief Load geometry (point layers)
42 :
43 : \return number of invalid features
44 : */
45 2 : int VFKDataBlockSQLite::LoadGeometryPoint()
46 : {
47 : int nInvalid, rowId, nGeometries;
48 : bool bSkipInvalid;
49 : long iFID;
50 : double x, y;
51 :
52 2 : CPLString osSQL;
53 : sqlite3_stmt *hStmt;
54 :
55 : VFKFeatureSQLite *poFeature;
56 : VFKReaderSQLite *poReader;
57 :
58 2 : nInvalid = nGeometries = 0;
59 2 : poReader = (VFKReaderSQLite*) m_poReader;
60 :
61 2 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
62 1 : return 0;
63 :
64 1 : bSkipInvalid = EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBBP");
65 : osSQL.Printf("SELECT SOURADNICE_Y,SOURADNICE_X,%s,rowid FROM %s",
66 1 : FID_COLUMN, m_pszName);
67 1 : hStmt = poReader->PrepareStatement(osSQL.c_str());
68 :
69 1 : if (poReader->IsSpatial())
70 1 : poReader->ExecuteSQL("BEGIN");
71 :
72 1 : while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
73 : /* read values */
74 13 : x = -1.0 * sqlite3_column_double(hStmt, 0); /* S-JTSK coordinate system expected */
75 13 : y = -1.0 * sqlite3_column_double(hStmt, 1);
76 13 : iFID = sqlite3_column_double(hStmt, 2);
77 13 : rowId = sqlite3_column_int(hStmt, 3);
78 :
79 13 : poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
80 13 : CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
81 :
82 : /* create geometry */
83 13 : OGRPoint pt(x, y);
84 13 : if (!poFeature->SetGeometry(&pt)) {
85 0 : nInvalid++;
86 0 : continue;
87 : }
88 :
89 : /* store also geometry in DB */
90 13 : if (poReader->IsSpatial() &&
91 : SaveGeometryToDB(&pt, rowId) != OGRERR_FAILURE)
92 13 : nGeometries++;
93 : }
94 :
95 : /* update number of geometries in 'vfk_blocks' table */
96 1 : UpdateVfkBlocks(nGeometries);
97 :
98 1 : if (poReader->IsSpatial())
99 1 : poReader->ExecuteSQL("COMMIT");
100 :
101 1 : return bSkipInvalid ? 0 : nInvalid;
102 : }
103 :
104 : /*!
105 : \brief Load geometry (linestring SBP layer)
106 :
107 : \return number of invalid features
108 : */
109 2 : int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
110 : {
111 : int nInvalid, nGeometries, rowId;
112 : long int iFID;
113 : GUIntBig id, ipcb;
114 : bool bValid;
115 :
116 2 : std::vector<int> rowIdFeat;
117 2 : CPLString osSQL;
118 : sqlite3_stmt *hStmt;
119 :
120 : VFKReaderSQLite *poReader;
121 : VFKDataBlockSQLite *poDataBlockPoints;
122 : VFKFeatureSQLite *poFeature, *poPoint, *poLine;
123 :
124 2 : OGRLineString oOGRLine;
125 :
126 2 : nInvalid = nGeometries = 0;
127 2 : poReader = (VFKReaderSQLite*) m_poReader;
128 2 : poLine = NULL;
129 :
130 2 : poDataBlockPoints = (VFKDataBlockSQLite *) m_poReader->GetDataBlock("SOBR");
131 2 : if (NULL == poDataBlockPoints) {
132 : CPLError(CE_Failure, CPLE_FileIO,
133 0 : "Data block %s not found.\n", m_pszName);
134 0 : return nInvalid;
135 : }
136 :
137 2 : poDataBlockPoints->LoadGeometry();
138 :
139 2 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
140 1 : return 0;
141 :
142 1 : osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN);
143 1 : poReader->ExecuteSQL(osSQL.c_str());
144 1 : bValid = TRUE;
145 1 : iFID = 1;
146 3 : for (int i = 0; i < 2; i++) {
147 : /* first collect linestrings related to HP, OB or DPM
148 : then collect rest of linestrings */
149 2 : if (i == 0)
150 : osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,_rowid_ FROM '%s' WHERE "
151 : "HP_ID IS NOT NULL OR OB_ID IS NOT NULL OR DPM_ID IS NOT NULL "
152 1 : "ORDER BY HP_ID,OB_ID,DPM_ID,PORADOVE_CISLO_BODU", m_pszName);
153 : else
154 : osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,_rowid_ FROM '%s' WHERE "
155 : "OB_ID IS NULL AND HP_ID IS NULL AND DPM_ID IS NULL "
156 1 : "ORDER BY ID,PORADOVE_CISLO_BODU", m_pszName);
157 :
158 2 : hStmt = poReader->PrepareStatement(osSQL.c_str());
159 :
160 2 : if (poReader->IsSpatial())
161 2 : poReader->ExecuteSQL("BEGIN");
162 :
163 30 : while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
164 : // read values
165 26 : id = sqlite3_column_double(hStmt, 0);
166 26 : ipcb = sqlite3_column_double(hStmt, 1);
167 26 : rowId = sqlite3_column_int(hStmt, 2);
168 :
169 26 : if (ipcb == 1) {
170 : /* add feature to the array */
171 13 : poFeature = new VFKFeatureSQLite(this, rowId, iFID);
172 26 : CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
173 13 : AddFeature(poFeature);
174 :
175 13 : if (poLine) {
176 12 : oOGRLine.setCoordinateDimension(2); /* force 2D */
177 12 : if (bValid) {
178 12 : if (!poLine->SetGeometry(&oOGRLine)) {
179 0 : bValid = FALSE;
180 0 : nInvalid++;
181 : }
182 : }
183 : else {
184 0 : poLine->SetGeometry(NULL);
185 0 : nInvalid++;
186 : }
187 :
188 : /* update fid column */
189 12 : UpdateFID(poLine->GetFID(), rowIdFeat);
190 :
191 : /* store also geometry in DB */
192 12 : CPLAssert(0 != rowIdFeat.size());
193 12 : if (bValid && poReader->IsSpatial() &&
194 : SaveGeometryToDB(bValid ? &oOGRLine : NULL,
195 : rowIdFeat[0]) != OGRERR_FAILURE)
196 12 : nGeometries++;
197 :
198 12 : rowIdFeat.clear();
199 12 : oOGRLine.empty(); /* restore line */
200 : }
201 13 : bValid = TRUE;
202 13 : poLine = poFeature;
203 13 : iFID++;
204 : }
205 :
206 26 : poPoint = (VFKFeatureSQLite *) poDataBlockPoints->GetFeature("ID", id);
207 26 : if (poPoint) {
208 26 : OGRPoint *pt = (OGRPoint *) poPoint->GetGeometry();
209 26 : if (pt) {
210 26 : oOGRLine.addPoint(pt);
211 : }
212 : else {
213 : CPLDebug("OGR-VFK",
214 0 : "Geometry (point ID = %lld) not valid", id);
215 0 : bValid = FALSE;
216 : }
217 : }
218 : else {
219 : CPLDebug("OGR-VFK",
220 : "Point ID = %lld not found (rowid = %d)",
221 0 : id, rowId);
222 0 : bValid = FALSE;
223 : }
224 :
225 : /* add vertex to the linestring */
226 26 : rowIdFeat.push_back(rowId);
227 : }
228 :
229 : /* add last line */
230 2 : if (poLine) {
231 1 : oOGRLine.setCoordinateDimension(2); /* force 2D */
232 1 : if (bValid) {
233 1 : if (!poLine->SetGeometry(&oOGRLine))
234 0 : nInvalid++;
235 : }
236 : else {
237 0 : poLine->SetGeometry(NULL);
238 0 : nInvalid++;
239 : }
240 :
241 : /* update fid column */
242 1 : UpdateFID(poLine->GetFID(), rowIdFeat);
243 :
244 : /* store also geometry in DB */
245 1 : CPLAssert(0 != rowIdFeat.size());
246 1 : if (poReader->IsSpatial() &&
247 : SaveGeometryToDB(bValid ? &oOGRLine : NULL,
248 : rowIdFeat[0]) != OGRERR_FAILURE && bValid)
249 1 : nGeometries++;
250 : }
251 2 : poLine = NULL;
252 2 : rowIdFeat.clear();
253 2 : oOGRLine.empty(); /* restore line */
254 :
255 2 : if (poReader->IsSpatial())
256 2 : poReader->ExecuteSQL("COMMIT");
257 : }
258 :
259 : /* update number of geometries in 'vfk_blocks' table */
260 1 : UpdateVfkBlocks(nGeometries);
261 :
262 1 : return nInvalid;
263 : }
264 :
265 : /*!
266 : \brief Load geometry (linestring HP/DPM layer)
267 :
268 : \return number of invalid features
269 : */
270 2 : int VFKDataBlockSQLite::LoadGeometryLineStringHP()
271 : {
272 : int nInvalid, nGeometries;
273 : int rowId;
274 : long iFID;
275 :
276 2 : CPLString osColumn, osSQL;
277 : const char *vrColumn[2];
278 : GUIntBig vrValue[2];
279 :
280 : sqlite3_stmt *hStmt;
281 :
282 : OGRGeometry *poOgrGeometry;
283 : VFKReaderSQLite *poReader;
284 : VFKDataBlockSQLite *poDataBlockLines;
285 : VFKFeatureSQLite *poFeature, *poLine;
286 :
287 2 : nInvalid = nGeometries = 0;
288 2 : poReader = (VFKReaderSQLite*) m_poReader;
289 :
290 2 : poDataBlockLines = (VFKDataBlockSQLite *) m_poReader->GetDataBlock("SBP");
291 2 : if (NULL == poDataBlockLines) {
292 : CPLError(CE_Failure, CPLE_FileIO,
293 0 : "Data block %s not found", m_pszName);
294 0 : return nInvalid;
295 : }
296 :
297 2 : poDataBlockLines->LoadGeometry();
298 :
299 2 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
300 1 : return 0;
301 :
302 1 : osColumn.Printf("%s_ID", m_pszName);
303 1 : vrColumn[0] = osColumn.c_str();
304 1 : vrColumn[1] = "PORADOVE_CISLO_BODU";
305 1 : vrValue[1] = 1; /* reduce to first segment */
306 :
307 1 : osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
308 : /* TODO: handle points in DPM */
309 1 : if (EQUAL(m_pszName, "DPM"))
310 0 : osSQL += " WHERE SOURADNICE_X IS NULL";
311 1 : hStmt = poReader->PrepareStatement(osSQL.c_str());
312 :
313 1 : if (poReader->IsSpatial())
314 1 : poReader->ExecuteSQL("BEGIN");
315 :
316 15 : while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
317 : /* read values */
318 13 : vrValue[0] = sqlite3_column_double(hStmt, 0);
319 13 : iFID = sqlite3_column_double(hStmt, 1);
320 13 : rowId = sqlite3_column_int(hStmt, 2);
321 :
322 13 : poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
323 13 : CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
324 :
325 13 : poLine = poDataBlockLines->GetFeature(vrColumn, vrValue, 2, TRUE);
326 13 : if (!poLine) {
327 0 : poOgrGeometry = NULL;
328 : }
329 : else {
330 13 : poOgrGeometry = poLine->GetGeometry();
331 : }
332 13 : if (!poOgrGeometry || !poFeature->SetGeometry(poOgrGeometry)) {
333 0 : nInvalid++;
334 0 : continue;
335 : }
336 :
337 : /* store also geometry in DB */
338 13 : if (poReader->IsSpatial() &&
339 : SaveGeometryToDB(poOgrGeometry, rowId) != OGRERR_FAILURE &&
340 : poOgrGeometry)
341 13 : nGeometries++;
342 : }
343 :
344 : /* update number of geometries in 'vfk_blocks' table */
345 1 : UpdateVfkBlocks(nGeometries);
346 :
347 1 : if (poReader->IsSpatial())
348 1 : poReader->ExecuteSQL("COMMIT");
349 :
350 1 : return nInvalid;
351 : }
352 :
353 : /*!
354 : \brief Load geometry (polygon BUD/PAR layers)
355 :
356 : \return number of invalid features
357 : */
358 2 : int VFKDataBlockSQLite::LoadGeometryPolygon()
359 : {
360 : int nInvalidNoLines, nInvalidNoRings, nGeometries, nBridges;
361 : int rowId, nCount, nCountMax;
362 : size_t nLines;
363 : long iFID;
364 : bool bIsPar, bNewRing, bFound;
365 :
366 2 : CPLString osSQL;
367 : const char *vrColumn[2];
368 : GUIntBig vrValue[2];
369 : GUIntBig id, idOb;
370 :
371 : sqlite3_stmt *hStmt;
372 :
373 : VFKReaderSQLite *poReader;
374 : VFKDataBlockSQLite *poDataBlockLines1, *poDataBlockLines2;
375 : VFKFeatureSQLite *poFeature;
376 :
377 2 : VFKFeatureSQLiteList poLineList;
378 : /* first is to be considered as exterior */
379 2 : PointListArray poRingList;
380 :
381 2 : std::vector<OGRLinearRing *> poLinearRingList;
382 2 : OGRPolygon ogrPolygon;
383 : OGRLinearRing *poOgrRing;
384 :
385 2 : nInvalidNoLines = nInvalidNoRings = nGeometries = 0;
386 2 : poReader = (VFKReaderSQLite*) m_poReader;
387 :
388 2 : if (EQUAL (m_pszName, "PAR")) {
389 2 : poDataBlockLines1 = (VFKDataBlockSQLite *) m_poReader->GetDataBlock("HP");
390 2 : poDataBlockLines2 = poDataBlockLines1;
391 2 : bIsPar = TRUE;
392 : }
393 : else {
394 0 : poDataBlockLines1 = (VFKDataBlockSQLite *) m_poReader->GetDataBlock("OB");
395 0 : poDataBlockLines2 = (VFKDataBlockSQLite *) m_poReader->GetDataBlock("SBP");
396 0 : bIsPar = FALSE;
397 : }
398 2 : if (NULL == poDataBlockLines1 || NULL == poDataBlockLines2) {
399 : CPLError(CE_Failure, CPLE_FileIO,
400 0 : "Data block %s not found", m_pszName);
401 0 : return -1;
402 : }
403 :
404 2 : poDataBlockLines1->LoadGeometry();
405 2 : poDataBlockLines2->LoadGeometry();
406 :
407 2 : if (LoadGeometryFromDB()) /* try to load geometry from DB */
408 1 : return 0;
409 :
410 1 : if (bIsPar) {
411 1 : vrColumn[0] = "PAR_ID_1";
412 1 : vrColumn[1] = "PAR_ID_2";
413 : }
414 : else {
415 0 : vrColumn[0] = "OB_ID";
416 0 : vrColumn[1] = "PORADOVE_CISLO_BODU";
417 0 : vrValue[1] = 1;
418 : }
419 :
420 1 : osSQL.Printf("SELECT ID,%s,rowid FROM %s", FID_COLUMN, m_pszName);
421 1 : hStmt = poReader->PrepareStatement(osSQL.c_str());
422 :
423 1 : if (poReader->IsSpatial())
424 1 : poReader->ExecuteSQL("BEGIN");
425 :
426 3 : while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
427 1 : nBridges = 0;
428 :
429 : /* read values */
430 1 : id = sqlite3_column_double(hStmt, 0);
431 1 : iFID = sqlite3_column_double(hStmt, 1);
432 1 : rowId = sqlite3_column_int(hStmt, 2);
433 :
434 1 : poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
435 1 : CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
436 :
437 1 : if (bIsPar) {
438 1 : vrValue[0] = vrValue[1] = id;
439 1 : poLineList = poDataBlockLines1->GetFeatures(vrColumn, vrValue, 2);
440 : }
441 : else {
442 : VFKFeatureSQLite *poLineSbp;
443 0 : std::vector<VFKFeatureSQLite *> poLineListOb;
444 : sqlite3_stmt *hStmtOb;
445 :
446 : osSQL.Printf("SELECT ID FROM %s WHERE BUD_ID = " CPL_FRMT_GUIB,
447 0 : poDataBlockLines1->GetName(), id);
448 0 : if (poReader->IsSpatial()) {
449 0 : CPLString osColumn;
450 :
451 0 : osColumn.Printf(" AND %s IS NULL", GEOM_COLUMN);
452 0 : osSQL += osColumn;
453 : }
454 0 : hStmtOb = poReader->PrepareStatement(osSQL.c_str());
455 :
456 0 : while(poReader->ExecuteSQL(hStmtOb) == OGRERR_NONE) {
457 0 : idOb = sqlite3_column_double(hStmtOb, 0);
458 0 : vrValue[0] = idOb;
459 0 : poLineSbp = poDataBlockLines2->GetFeature(vrColumn, vrValue, 2);
460 0 : if (poLineSbp)
461 0 : poLineList.push_back(poLineSbp);
462 0 : }
463 : }
464 1 : nLines = poLineList.size();
465 1 : if (nLines < 1) {
466 : CPLDebug("OGR-VFK",
467 : "%s: unable to collect rings for polygon fid = %ld (no lines)",
468 0 : m_pszName, iFID);
469 0 : nInvalidNoLines++;
470 0 : continue;
471 : }
472 :
473 : /* clear */
474 1 : ogrPolygon.empty();
475 1 : poRingList.clear();
476 :
477 : /* collect rings from lines */
478 1 : bFound = FALSE;
479 1 : nCount = 0;
480 1 : nCountMax = nLines * 2;
481 15 : while (poLineList.size() > 0 && nCount < nCountMax) {
482 13 : bNewRing = !bFound ? TRUE : FALSE;
483 13 : bFound = FALSE;
484 13 : int i = 1;
485 51 : for (VFKFeatureSQLiteList::iterator iHp = poLineList.begin(), eHp = poLineList.end();
486 : iHp != eHp; ++iHp, ++i) {
487 51 : const OGRLineString *pLine = (OGRLineString *) (*iHp)->GetGeometry();
488 51 : if (pLine && AppendLineToRing(&poRingList, pLine, bNewRing)) {
489 13 : bFound = TRUE;
490 13 : poLineList.erase(iHp);
491 13 : break;
492 : }
493 : }
494 13 : nCount++;
495 : }
496 : CPLDebug("OGR-VFK", "%s: fid = %ld nlines = %d -> nrings = %d", m_pszName,
497 1 : iFID, (int)nLines, (int)poRingList.size());
498 :
499 1 : if (poLineList.size() > 0) {
500 : CPLDebug("OGR-VFK",
501 : "%s: unable to collect rings for polygon fid = %ld",
502 0 : m_pszName, iFID);
503 0 : nInvalidNoRings++;
504 0 : continue;
505 : }
506 :
507 : /* build rings */
508 1 : poLinearRingList.clear();
509 1 : int i = 1;
510 2 : for (PointListArray::const_iterator iRing = poRingList.begin(), eRing = poRingList.end();
511 : iRing != eRing; ++iRing) {
512 : OGRPoint *poPoint;
513 1 : PointList *poList = *iRing;
514 :
515 1 : poLinearRingList.push_back(new OGRLinearRing());
516 1 : poOgrRing = poLinearRingList.back();
517 1 : CPLAssert(NULL != poOgrRing);
518 :
519 15 : for (PointList::iterator iPoint = poList->begin(), ePoint = poList->end();
520 : iPoint != ePoint; ++iPoint) {
521 14 : poPoint = &(*iPoint);
522 14 : poOgrRing->addPoint(poPoint);
523 : }
524 1 : i++;
525 : }
526 :
527 : /* find exterior ring */
528 1 : if (poLinearRingList.size() > 1) {
529 : double dArea, dMaxArea;
530 0 : std::vector<OGRLinearRing *>::iterator exteriorRing;
531 :
532 0 : exteriorRing = poLinearRingList.begin();
533 0 : dMaxArea = -1.;
534 0 : for (std::vector<OGRLinearRing *>::iterator iRing = poLinearRingList.begin(),
535 0 : eRing = poLinearRingList.end(); iRing != eRing; ++iRing) {
536 0 : poOgrRing = *iRing;
537 0 : if (!IsRingClosed(poOgrRing))
538 0 : continue; /* skip unclosed rings */
539 :
540 0 : dArea = poOgrRing->get_Area();
541 0 : if (dArea > dMaxArea) {
542 0 : dMaxArea = dArea;
543 0 : exteriorRing = iRing;
544 : }
545 : }
546 0 : if (exteriorRing != poLinearRingList.begin()) {
547 0 : std::swap(*poLinearRingList.begin(), *exteriorRing);
548 : }
549 : }
550 :
551 : /* build polygon from rings */
552 3 : for (std::vector<OGRLinearRing *>::iterator iRing = poLinearRingList.begin(),
553 1 : eRing = poLinearRingList.end(); iRing != eRing; ++iRing) {
554 1 : poOgrRing = *iRing;
555 :
556 : /* check if ring is closed */
557 1 : if (IsRingClosed(poOgrRing)) {
558 1 : ogrPolygon.addRing(poOgrRing);
559 : }
560 : else {
561 0 : if (poOgrRing->getNumPoints() == 2) {
562 : CPLDebug("OGR-VFK", "%s: Polygon (fid = %ld) bridge removed",
563 0 : m_pszName, iFID);
564 0 : nBridges++;
565 : }
566 : else {
567 : CPLDebug("OGR-VFK",
568 : "%s: Polygon (fid = %ld) unclosed ring skipped",
569 0 : m_pszName, iFID);
570 : }
571 : }
572 1 : delete poOgrRing;
573 1 : *iRing = NULL;
574 : }
575 :
576 : /* set polygon */
577 1 : ogrPolygon.setCoordinateDimension(2); /* force 2D */
578 1 : if (ogrPolygon.getNumInteriorRings() + nBridges != (int) poLinearRingList.size() - 1 ||
579 : !poFeature->SetGeometry(&ogrPolygon)) {
580 0 : nInvalidNoRings++;
581 0 : continue;
582 : }
583 :
584 : /* store also geometry in DB */
585 1 : if (poReader->IsSpatial() &&
586 : SaveGeometryToDB(&ogrPolygon, rowId) != OGRERR_FAILURE)
587 1 : nGeometries++;
588 : }
589 :
590 : /* free ring list */
591 2 : for (PointListArray::iterator iRing = poRingList.begin(), eRing = poRingList.end();
592 : iRing != eRing; ++iRing) {
593 1 : delete (*iRing);
594 1 : *iRing = NULL;
595 : }
596 :
597 : CPLDebug("OGR-VFK", "%s: nolines = %d norings = %d",
598 1 : m_pszName, nInvalidNoLines, nInvalidNoRings);
599 :
600 : /* update number of geometries in 'vfk_blocks' table */
601 1 : UpdateVfkBlocks(nGeometries);
602 :
603 1 : if (poReader->IsSpatial())
604 1 : poReader->ExecuteSQL("COMMIT");
605 :
606 1 : return nInvalidNoLines + nInvalidNoRings;
607 : }
608 :
609 : /*!
610 : \brief Get feature by FID
611 :
612 : Modifies next feature id.
613 :
614 : \param nFID feature id
615 :
616 : \return pointer to feature definition or NULL on failure (not found)
617 : */
618 0 : IVFKFeature *VFKDataBlockSQLite::GetFeature(long nFID)
619 : {
620 : int rowId;
621 0 : CPLString osSQL;
622 : VFKReaderSQLite *poReader;
623 :
624 : sqlite3_stmt *hStmt;
625 :
626 0 : if (m_nFeatureCount < 0) {
627 0 : m_poReader->ReadDataRecords(this);
628 : }
629 :
630 0 : if (nFID < 1 || nFID > m_nFeatureCount)
631 0 : return NULL;
632 :
633 0 : if (m_bGeometryPerBlock && !m_bGeometry) {
634 0 : LoadGeometry();
635 : }
636 :
637 0 : poReader = (VFKReaderSQLite*) m_poReader;
638 :
639 : osSQL.Printf("SELECT rowid FROM %s WHERE %s = %ld",
640 0 : m_pszName, FID_COLUMN, nFID);
641 0 : if (EQUAL(m_pszName, "SBP")) {
642 0 : osSQL += " AND PORADOVE_CISLO_BODU = 1";
643 : }
644 0 : hStmt = poReader->PrepareStatement(osSQL.c_str());
645 :
646 0 : rowId = -1;
647 0 : if (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
648 0 : rowId = sqlite3_column_int(hStmt, 0);
649 : }
650 0 : sqlite3_finalize(hStmt);
651 :
652 0 : return GetFeatureByIndex(rowId - 1);
653 : }
654 :
655 : /*!
656 : \brief Get first found feature based on it's property
657 :
658 : \param column property name
659 : \param value property value
660 : \param bGeom True to check also geometry != NULL
661 :
662 : \return pointer to feature definition or NULL on failure (not found)
663 : */
664 26 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char *column, GUIntBig value,
665 : bool bGeom)
666 : {
667 : int idx;
668 26 : CPLString osSQL;
669 : VFKReaderSQLite *poReader;
670 :
671 : sqlite3_stmt *hStmt;
672 :
673 26 : poReader = (VFKReaderSQLite*) m_poReader;
674 :
675 : osSQL.Printf("SELECT %s from %s WHERE %s = " CPL_FRMT_GUIB,
676 26 : FID_COLUMN, m_pszName, column, value);
677 26 : if (bGeom) {
678 0 : CPLString osColumn;
679 :
680 0 : osColumn.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
681 0 : osSQL += osColumn;
682 : }
683 :
684 26 : hStmt = poReader->PrepareStatement(osSQL.c_str());
685 26 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
686 0 : return NULL;
687 :
688 26 : idx = sqlite3_column_int(hStmt, 0) - 1;
689 26 : if (idx < 0 || idx >= m_nFeatureCount) // ? assert
690 0 : return NULL;
691 :
692 26 : sqlite3_finalize(hStmt);
693 :
694 26 : return (VFKFeatureSQLite *) GetFeatureByIndex(idx);
695 : }
696 :
697 : /*!
698 : \brief Get first found feature based on it's properties (AND)
699 :
700 : \param column array of property names
701 : \param value array of property values
702 : \param num number of array items
703 : \param bGeom True to check also geometry != NULL
704 :
705 : \return pointer to feature definition or NULL on failure (not found)
706 : */
707 13 : VFKFeatureSQLite *VFKDataBlockSQLite::GetFeature(const char **column, GUIntBig *value, int num,
708 : bool bGeom)
709 : {
710 : int idx;
711 13 : CPLString osSQL, osItem;
712 : VFKReaderSQLite *poReader;
713 :
714 : sqlite3_stmt *hStmt;
715 :
716 13 : poReader = (VFKReaderSQLite*) m_poReader;
717 :
718 13 : osSQL.Printf("SELECT %s FROM %s WHERE ", FID_COLUMN, m_pszName);
719 39 : for (int i = 0; i < num; i++) {
720 26 : if (i > 0)
721 13 : osItem.Printf(" AND %s = " CPL_FRMT_GUIB, column[i], value[i]);
722 : else
723 13 : osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
724 26 : osSQL += osItem;
725 : }
726 13 : if (bGeom) {
727 13 : osItem.Printf(" AND %s IS NOT NULL", GEOM_COLUMN);
728 13 : osSQL += osItem;
729 : }
730 :
731 13 : hStmt = poReader->PrepareStatement(osSQL.c_str());
732 13 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
733 0 : return NULL;
734 :
735 13 : idx = sqlite3_column_int(hStmt, 0) - 1; /* rowid starts at 1 */
736 :
737 13 : if (idx < 0 || idx >= m_nFeatureCount) // ? assert
738 0 : return NULL;
739 :
740 13 : sqlite3_finalize(hStmt);
741 :
742 13 : return (VFKFeatureSQLite *) GetFeatureByIndex(idx);
743 : }
744 :
745 : /*!
746 : \brief Get features based on properties
747 :
748 : \param column array of property names
749 : \param value array of property values
750 : \param num number of array items
751 :
752 : \return list of features
753 : */
754 1 : VFKFeatureSQLiteList VFKDataBlockSQLite::GetFeatures(const char **column, GUIntBig *value, int num)
755 : {
756 : int iRowId;
757 1 : CPLString osSQL, osItem;
758 :
759 : VFKReaderSQLite *poReader;
760 1 : VFKFeatureSQLiteList fList;
761 :
762 : sqlite3_stmt *hStmt;
763 :
764 1 : poReader = (VFKReaderSQLite*) m_poReader;
765 :
766 1 : osSQL.Printf("SELECT rowid from %s WHERE ", m_pszName);
767 3 : for (int i = 0; i < num; i++) {
768 2 : if (i > 0)
769 1 : osItem.Printf(" OR %s = " CPL_FRMT_GUIB, column[i], value[i]);
770 : else
771 1 : osItem.Printf("%s = " CPL_FRMT_GUIB, column[i], value[i]);
772 2 : osSQL += osItem;
773 : }
774 1 : osSQL += " ORDER BY ";
775 1 : osSQL += FID_COLUMN;
776 :
777 1 : hStmt = poReader->PrepareStatement(osSQL.c_str());
778 15 : while (poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
779 13 : iRowId = sqlite3_column_int(hStmt, 0);
780 13 : fList.push_back((VFKFeatureSQLite *)GetFeatureByIndex(iRowId - 1));
781 : }
782 :
783 1 : return fList;
784 : }
785 :
786 : /*!
787 : \brief Save geometry to DB (as WKB)
788 :
789 : \param poGeom pointer to OGRGeometry to be saved
790 : \param iRowId row id to update
791 :
792 : \return OGRERR_NONE on success otherwise OGRERR_FAILURE
793 : */
794 40 : OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom, int iRowId)
795 : {
796 : int rc, nWKBLen;
797 : GByte *pabyWKB;
798 40 : CPLString osSQL;
799 :
800 : sqlite3_stmt *hStmt;
801 :
802 : VFKReaderSQLite *poReader;
803 :
804 40 : poReader = (VFKReaderSQLite*) m_poReader;
805 :
806 40 : if (poGeom) {
807 40 : nWKBLen = poGeom->WkbSize();
808 40 : pabyWKB = (GByte *) CPLMalloc(nWKBLen + 1);
809 40 : poGeom->exportToWkb(wkbNDR, pabyWKB);
810 :
811 : osSQL.Printf("UPDATE %s SET %s = ? WHERE rowid = %d",
812 40 : m_pszName, GEOM_COLUMN, iRowId);
813 40 : hStmt = poReader->PrepareStatement(osSQL.c_str());
814 :
815 40 : rc = sqlite3_bind_blob(hStmt, 1, pabyWKB, nWKBLen, CPLFree);
816 40 : if (rc != SQLITE_OK) {
817 0 : sqlite3_finalize(hStmt);
818 : CPLError(CE_Failure, CPLE_AppDefined,
819 0 : "Storing geometry in DB failed");
820 0 : return OGRERR_FAILURE;
821 : }
822 : }
823 : else { /* invalid */
824 : osSQL.Printf("UPDATE %s SET %s = NULL WHERE rowid = %d",
825 0 : m_pszName, GEOM_COLUMN, iRowId);
826 0 : hStmt = poReader->PrepareStatement(osSQL.c_str());
827 : }
828 :
829 40 : return poReader->ExecuteSQL(hStmt); /* calls sqlite3_finalize() */
830 : }
831 :
832 : /*!
833 : \brief Load geometry from DB
834 :
835 : \return TRUE geometry successfully loaded otherwise FALSE
836 : */
837 8 : bool VFKDataBlockSQLite::LoadGeometryFromDB()
838 : {
839 : int nInvalid, nGeometries, nGeometriesCount, nBytes, rowId;
840 : long iFID;
841 : bool bAddFeature, bSkipInvalid;
842 :
843 8 : CPLString osSQL;
844 :
845 : OGRGeometry *poGeometry;
846 :
847 : VFKFeatureSQLite *poFeature;
848 : VFKReaderSQLite *poReader;
849 :
850 : sqlite3_stmt *hStmt;
851 :
852 8 : poReader = (VFKReaderSQLite*) m_poReader;
853 :
854 8 : if (!poReader->IsSpatial()) /* check if DB is spatial */
855 0 : return FALSE;
856 :
857 : osSQL.Printf("SELECT num_geometries FROM 'vfk_blocks' WHERE table_name = '%s'",
858 8 : m_pszName);
859 8 : hStmt = poReader->PrepareStatement(osSQL.c_str());
860 8 : if (poReader->ExecuteSQL(hStmt) != OGRERR_NONE)
861 0 : return FALSE;
862 8 : nGeometries = sqlite3_column_int(hStmt, 0);
863 8 : sqlite3_finalize(hStmt);
864 :
865 8 : if (nGeometries < 1)
866 4 : return FALSE;
867 :
868 4 : bAddFeature = EQUAL(m_pszName, "SBP");
869 4 : bSkipInvalid = EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBBP");
870 :
871 : /* load geometry from DB */
872 4 : nInvalid = nGeometriesCount = 0;
873 : osSQL.Printf("SELECT %s,rowid,%s FROM %s ",
874 4 : GEOM_COLUMN, FID_COLUMN, m_pszName);
875 4 : if (EQUAL(m_pszName, "SBP"))
876 1 : osSQL += "WHERE PORADOVE_CISLO_BODU = 1 ";
877 4 : osSQL += "ORDER BY ";
878 4 : osSQL += FID_COLUMN;
879 4 : hStmt = poReader->PrepareStatement(osSQL.c_str());
880 :
881 48 : while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
882 40 : rowId = sqlite3_column_int(hStmt, 1);
883 40 : iFID = sqlite3_column_double(hStmt, 2);
884 :
885 40 : if (bAddFeature) {
886 : /* add feature to the array */
887 13 : poFeature = new VFKFeatureSQLite(this, rowId, iFID);
888 13 : AddFeature(poFeature);
889 : }
890 : else {
891 27 : poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
892 : }
893 40 : CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
894 :
895 : // read geometry from DB
896 40 : nBytes = sqlite3_column_bytes(hStmt, 0);
897 40 : if (nBytes > 0 &&
898 : OGRGeometryFactory::createFromWkb((GByte*) sqlite3_column_blob(hStmt, 0),
899 : NULL, &poGeometry, nBytes) == OGRERR_NONE) {
900 40 : nGeometriesCount++;
901 40 : if (!poFeature->SetGeometry(poGeometry)) {
902 0 : nInvalid++;
903 : }
904 : }
905 : else {
906 0 : nInvalid++;
907 : }
908 : }
909 :
910 : CPLDebug("OGR-VFK", "%s: %d geometries loaded from DB",
911 4 : m_pszName, nGeometriesCount);
912 :
913 4 : if (nGeometriesCount != nGeometries) {
914 : CPLError(CE_Warning, CPLE_AppDefined,
915 : "%s: %d geometries loaded (should be %d)",
916 0 : m_pszName, nGeometriesCount, nGeometries);
917 : }
918 :
919 4 : if (nInvalid > 0 && !bSkipInvalid) {
920 : CPLError(CE_Warning, CPLE_AppDefined,
921 : "%s: %d invalid features found",
922 0 : m_pszName, nInvalid);
923 : }
924 :
925 4 : return TRUE;
926 : }
927 :
928 : /*!
929 : \brief Update vfk_blocks table
930 :
931 : \param nGeometries number of geometries to update
932 : */
933 4 : void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries) {
934 4 : CPLString osSQL;
935 :
936 : VFKReaderSQLite *poReader;
937 :
938 4 : poReader = (VFKReaderSQLite*) m_poReader;
939 :
940 4 : if (nGeometries > 0) {
941 : CPLDebug("OGR-VFK",
942 4 : "%d geometries in '%s' saved", nGeometries, m_pszName);
943 :
944 : /* update number of geometries in 'vfk_blocks' table */
945 : osSQL.Printf("UPDATE vfk_blocks SET num_geometries = %d WHERE table_name = '%s'",
946 4 : nGeometries, m_pszName);
947 4 : poReader->ExecuteSQL(osSQL.c_str());
948 4 : }
949 4 : }
950 :
951 : /*!
952 : \brief Update feature id (see SBP)
953 :
954 : \param iFID feature id to set up
955 : \param rowId list of rows to update
956 : */
957 13 : void VFKDataBlockSQLite::UpdateFID(long int iFID, std::vector<int> rowId)
958 : {
959 13 : CPLString osSQL, osValue;
960 : VFKReaderSQLite *poReader;
961 :
962 13 : poReader = (VFKReaderSQLite*) m_poReader;
963 :
964 : /* update number of geometries in 'vfk_blocks' table */
965 : osSQL.Printf("UPDATE %s SET %s = %ld WHERE rowid IN (",
966 13 : m_pszName, FID_COLUMN, iFID);
967 39 : for (size_t i = 0; i < rowId.size(); i++) {
968 26 : if (i > 0)
969 13 : osValue.Printf(",%d", rowId[i]);
970 : else
971 13 : osValue.Printf("%d", rowId[i]);
972 26 : osSQL += osValue;
973 : }
974 13 : osSQL += ")";
975 :
976 13 : poReader->ExecuteSQL(osSQL.c_str());
977 13 : }
978 :
979 : /*!
980 : \brief Check is ring is closed
981 :
982 : \param poRing pointer to OGRLinearRing to check
983 :
984 : \return TRUE if closed otherwise FALSE
985 : */
986 1 : bool VFKDataBlockSQLite::IsRingClosed(const OGRLinearRing *poRing)
987 : {
988 : int nPoints;
989 :
990 1 : nPoints = poRing->getNumPoints();
991 1 : if (nPoints < 3)
992 0 : return FALSE;
993 :
994 1 : if (poRing->getX(0) == poRing->getX(nPoints-1) &&
995 : poRing->getY(0) == poRing->getY(nPoints-1))
996 1 : return TRUE;
997 :
998 0 : return FALSE;
999 : }
1000 :
1001 : /*!
1002 : \brief Get primary key
1003 :
1004 : \return property name or NULL
1005 : */
1006 4 : const char *VFKDataBlockSQLite::GetKey() const
1007 : {
1008 : const char *pszKey;
1009 : const VFKPropertyDefn *poPropDefn;
1010 :
1011 4 : if (GetPropertyCount() > 1) {
1012 4 : poPropDefn = GetProperty(0);
1013 4 : pszKey = poPropDefn->GetName();
1014 4 : if (EQUAL(pszKey, "ID"))
1015 4 : return pszKey;
1016 : }
1017 :
1018 0 : return NULL;
1019 : }
|