1 : /******************************************************************************
2 : * $Id: vfkfeature.cpp 25702 2013-03-07 17:17:54Z martinl $
3 : *
4 : * Project: VFK Reader - Feature definition
5 : * Purpose: Implements IVFKFeature/VFKFeature class.
6 : * Author: Martin Landa, landa.martin gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009-2010, 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 "vfkreader.h"
33 : #include "vfkreaderp.h"
34 :
35 : #include "cpl_conv.h"
36 : #include "cpl_error.h"
37 :
38 : /*!
39 : \brief IVFKFeature constructor
40 :
41 : \param poDataBlock pointer to VFKDataBlock instance
42 : */
43 133 : IVFKFeature::IVFKFeature(IVFKDataBlock *poDataBlock)
44 : {
45 133 : CPLAssert(NULL != poDataBlock);
46 133 : m_poDataBlock = poDataBlock;
47 :
48 133 : m_nFID = -1;
49 133 : m_nGeometryType = poDataBlock->GetGeometryType();
50 133 : m_bGeometry = FALSE;
51 133 : m_bValid = FALSE;
52 133 : m_paGeom = NULL;
53 133 : }
54 :
55 : /*!
56 : \brief IVFKFeature destructor
57 : */
58 133 : IVFKFeature::~IVFKFeature()
59 : {
60 133 : if (m_paGeom)
61 80 : delete m_paGeom;
62 :
63 133 : m_poDataBlock = NULL;
64 133 : }
65 :
66 : /*!
67 : \brief Set feature geometry type
68 : */
69 0 : void IVFKFeature::SetGeometryType(OGRwkbGeometryType nGeomType)
70 : {
71 0 : m_nGeometryType = nGeomType;
72 0 : }
73 :
74 : /*!
75 : \brief Set feature id
76 :
77 : FID: 0 for next, -1 for same
78 :
79 : \param nFID feature id
80 : */
81 0 : void IVFKFeature::SetFID(long nFID)
82 : {
83 0 : if (m_nFID > 0) {
84 0 : m_nFID = nFID;
85 : }
86 : else {
87 0 : m_nFID = m_poDataBlock->GetFeatureCount() + 1;
88 : }
89 0 : }
90 :
91 : /*!
92 : \brief Set feature geometry
93 :
94 : Also checks if given geometry is valid
95 :
96 : \param poGeom pointer to OGRGeometry
97 :
98 : \return TRUE on valid feature or otherwise FALSE
99 : */
100 80 : bool IVFKFeature::SetGeometry(OGRGeometry *poGeom)
101 : {
102 80 : m_bGeometry = TRUE;
103 :
104 80 : delete m_paGeom;
105 80 : m_paGeom = NULL;
106 80 : m_bValid = TRUE;
107 :
108 80 : if (!poGeom) {
109 0 : return m_bValid;
110 : }
111 :
112 : /* check empty geometries */
113 80 : if (m_nGeometryType == wkbNone && poGeom->IsEmpty()) {
114 : CPLDebug("OGR-VFK", "%s: empty geometry fid = %ld",
115 0 : m_poDataBlock->GetName(), m_nFID);
116 0 : m_bValid = FALSE;
117 : }
118 :
119 : /* check coordinates */
120 80 : if (m_nGeometryType == wkbPoint) {
121 : double x, y;
122 26 : x = ((OGRPoint *) poGeom)->getX();
123 26 : y = ((OGRPoint *) poGeom)->getY();
124 26 : if (x > -430000 || x < -910000 ||
125 : y > -930000 || y < -1230000) {
126 : CPLDebug("OGR-VFK", "%s: invalid point fid = %ld",
127 0 : m_poDataBlock->GetName(), m_nFID);
128 0 : m_bValid = FALSE;
129 : }
130 : }
131 :
132 : /* check degenerated linestrings */
133 80 : if (m_nGeometryType == wkbLineString &&
134 : ((OGRLineString *) poGeom)->getNumPoints() < 2) {
135 : CPLDebug("OGR-VFK", "%s: invalid linestring fid = %ld",
136 0 : m_poDataBlock->GetName(), m_nFID);
137 0 : m_bValid = FALSE;
138 : }
139 :
140 : /* check degenerated polygons */
141 80 : if (m_nGeometryType == wkbPolygon) {
142 : OGRLinearRing *poRing;
143 2 : poRing = ((OGRPolygon *) poGeom)->getExteriorRing();
144 2 : if (!poRing || poRing->getNumPoints() < 3) {
145 : CPLDebug("OGR-VFK", "%s: invalid polygon fid = %ld",
146 0 : m_poDataBlock->GetName(), m_nFID);
147 0 : m_bValid = FALSE;
148 : }
149 : }
150 :
151 80 : if (m_bValid)
152 80 : m_paGeom = (OGRGeometry *) poGeom->clone(); /* make copy */
153 :
154 80 : return m_bValid;
155 : }
156 :
157 : /*!
158 : \brief Get feature geometry
159 :
160 : \return pointer to OGRGeometry or NULL on error
161 : */
162 105 : OGRGeometry *IVFKFeature::GetGeometry()
163 : {
164 105 : if (m_nGeometryType != wkbNone && !m_bGeometry)
165 0 : LoadGeometry();
166 :
167 105 : return m_paGeom;
168 : }
169 :
170 :
171 : /*!
172 : \brief Load geometry
173 :
174 : \return TRUE on success or FALSE on failure
175 : */
176 0 : bool IVFKFeature::LoadGeometry()
177 : {
178 : const char *pszName;
179 0 : CPLString osSQL;
180 :
181 0 : if (m_bGeometry)
182 0 : return TRUE;
183 :
184 0 : pszName = m_poDataBlock->GetName();
185 :
186 0 : if (EQUAL (pszName, "SOBR") ||
187 : EQUAL (pszName, "OBBP") ||
188 : EQUAL (pszName, "SPOL") ||
189 : EQUAL (pszName, "OB") ||
190 : EQUAL (pszName, "OP") ||
191 : EQUAL (pszName, "OBPEJ")) {
192 : /* -> wkbPoint */
193 :
194 0 : return LoadGeometryPoint();
195 : }
196 0 : else if (EQUAL (pszName, "SBP")) {
197 : /* -> wkbLineString */
198 0 : return LoadGeometryLineStringSBP();
199 : }
200 0 : else if (EQUAL (pszName, "HP") ||
201 : EQUAL (pszName, "DPM")) {
202 : /* -> wkbLineString */
203 0 : return LoadGeometryLineStringHP();
204 : }
205 0 : else if (EQUAL (pszName, "PAR") ||
206 : EQUAL (pszName, "BUD")) {
207 : /* -> wkbPolygon */
208 0 : return LoadGeometryPolygon();
209 : }
210 :
211 0 : return FALSE;
212 : }
213 :
214 : /*!
215 : \brief VFKFeature constructor
216 :
217 : \param poDataBlock pointer to VFKDataBlock instance
218 : */
219 53 : VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, long iFID) : IVFKFeature(poDataBlock)
220 : {
221 53 : m_nFID = iFID;
222 53 : m_propertyList.assign(poDataBlock->GetPropertyCount(), VFKProperty());
223 53 : CPLAssert(size_t (poDataBlock->GetPropertyCount()) == m_propertyList.size());
224 53 : }
225 :
226 : /*!
227 : \brief Set feature properties
228 :
229 : \param pszLine pointer to line containing feature definition
230 :
231 : \return TRUE on success or FALSE on failure
232 : */
233 53 : bool VFKFeature::SetProperties(const char *pszLine)
234 : {
235 : unsigned int iIndex, nLength;
236 : const char *poChar, *poProp;
237 : char* pszProp;
238 : bool inString;
239 :
240 53 : std::vector<CPLString> oPropList;
241 :
242 53 : pszProp = NULL;
243 :
244 53 : for (poChar = pszLine; *poChar != '\0' && *poChar != ';'; poChar++)
245 : /* skip data block name */
246 : ;
247 53 : if (poChar == '\0')
248 0 : return FALSE; /* nothing to read */
249 :
250 53 : poChar++; /* skip ';' after data block name*/
251 :
252 : /* read properties into the list */
253 53 : poProp = poChar;
254 53 : iIndex = nLength = 0;
255 53 : inString = FALSE;
256 3753 : while(*poChar != '\0') {
257 3648 : if (*poChar == '"' &&
258 : (*(poChar-1) == ';' || *(poChar+1) == ';' || *(poChar+1) == '\0')) {
259 177 : poChar++; /* skip '"' */
260 177 : inString = inString ? FALSE : TRUE;
261 177 : if (inString) {
262 109 : poProp = poChar;
263 109 : if (*poChar == '"') {
264 41 : poChar++;
265 41 : inString = FALSE;
266 : }
267 : }
268 177 : if (*poChar == '\0')
269 1 : break;
270 : }
271 4246 : if (*poChar == ';' && !inString) {
272 599 : pszProp = (char *) CPLRealloc(pszProp, nLength + 1);
273 599 : if (nLength > 0)
274 445 : strncpy(pszProp, poProp, nLength);
275 599 : pszProp[nLength] = '\0';
276 599 : oPropList.push_back(pszProp);
277 599 : iIndex++;
278 599 : poProp = ++poChar;
279 599 : nLength = 0;
280 : }
281 : else {
282 3048 : poChar++;
283 3048 : nLength++;
284 : }
285 : }
286 : /* append last property */
287 53 : if (inString) {
288 0 : nLength--; /* ignore '"' */
289 : }
290 53 : pszProp = (char *) CPLRealloc(pszProp, nLength + 1);
291 53 : if (nLength > 0)
292 27 : strncpy(pszProp, poProp, nLength);
293 53 : pszProp[nLength] = '\0';
294 53 : oPropList.push_back(pszProp);
295 :
296 : /* set properties from the list */
297 53 : if (oPropList.size() != (size_t) m_poDataBlock->GetPropertyCount()) {
298 : /* try to read also invalid records */
299 : CPLDebug("OGR-VFK", "%s: invalid number of properties %d should be %d",
300 : m_poDataBlock->GetName(),
301 0 : (int) oPropList.size(), m_poDataBlock->GetPropertyCount());
302 0 : return FALSE;
303 : }
304 53 : iIndex = 0;
305 705 : for (std::vector<CPLString>::iterator ip = oPropList.begin();
306 : ip != oPropList.end(); ++ip) {
307 652 : SetProperty(iIndex++, (*ip).c_str());
308 : }
309 :
310 : /* set fid
311 : if (EQUAL(m_poDataBlock->GetName(), "SBP")) {
312 : GUIntBig id;
313 : const VFKProperty *poVfkProperty;
314 :
315 : poVfkProperty = GetProperty("PORADOVE_CISLO_BODU");
316 : if (poVfkProperty)
317 : {
318 : id = strtoul(poVfkProperty->GetValueS(), NULL, 0);
319 : if (id == 1)
320 : SetFID(0);
321 : else
322 : SetFID(-1);
323 : }
324 : }
325 : else {
326 : SetFID(0);
327 : }
328 : */
329 53 : CPLFree(pszProp);
330 :
331 53 : return TRUE;
332 : }
333 :
334 : /*!
335 : \brief Set feature property
336 :
337 : \param iIndex property index
338 : \param pszValue property value
339 :
340 : \return TRUE on success
341 : \return FALSE on failure
342 : */
343 652 : bool VFKFeature::SetProperty(int iIndex, const char *pszValue)
344 : {
345 652 : if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
346 : size_t(iIndex) >= m_propertyList.size())
347 0 : return FALSE;
348 :
349 652 : if (strlen(pszValue) < 1)
350 180 : m_propertyList[iIndex] = VFKProperty();
351 : else {
352 : OGRFieldType fType;
353 :
354 : const char *pszEncoding;
355 : char *pszValueEnc;
356 :
357 472 : fType = m_poDataBlock->GetProperty(iIndex)->GetType();
358 472 : switch (fType) {
359 : case OFTInteger:
360 139 : m_propertyList[iIndex] = VFKProperty(atoi(pszValue));
361 139 : break;
362 : case OFTReal:
363 26 : m_propertyList[iIndex] = VFKProperty(CPLAtof(pszValue));
364 26 : break;
365 : default:
366 307 : pszEncoding = m_poDataBlock->GetProperty(iIndex)->GetEncoding();
367 307 : if (pszEncoding) {
368 : pszValueEnc = CPLRecode(pszValue, pszEncoding,
369 28 : CPL_ENC_UTF8);
370 28 : m_propertyList[iIndex] = VFKProperty(pszValueEnc);
371 28 : CPLFree(pszValueEnc);
372 : }
373 : else {
374 279 : m_propertyList[iIndex] = VFKProperty(pszValue);
375 : }
376 : break;
377 : }
378 : }
379 652 : return TRUE;
380 : }
381 :
382 : /*!
383 : \brief Get property value by index
384 :
385 : \param iIndex property index
386 :
387 : \return property value
388 : \return NULL on error
389 : */
390 652 : const VFKProperty *VFKFeature::GetProperty(int iIndex) const
391 : {
392 652 : if (iIndex < 0 || iIndex >= m_poDataBlock->GetPropertyCount() ||
393 : size_t(iIndex) >= m_propertyList.size())
394 0 : return NULL;
395 :
396 652 : const VFKProperty* poProperty = &m_propertyList[iIndex];
397 652 : return poProperty;
398 : }
399 :
400 : /*!
401 : \brief Get property value by name
402 :
403 : \param pszName property name
404 :
405 : \return property value
406 : \return NULL on error
407 : */
408 0 : const VFKProperty *VFKFeature::GetProperty(const char *pszName) const
409 : {
410 0 : return GetProperty(m_poDataBlock->GetPropertyIndex(pszName));
411 : }
412 :
413 : /*!
414 : \brief Load geometry (point layers)
415 :
416 : \todo Really needed?
417 :
418 : \return TRUE on success
419 : \return FALSE on failure
420 : */
421 0 : bool VFKFeature::LoadGeometryPoint()
422 : {
423 : double x, y;
424 : int i_idxX, i_idxY;
425 :
426 0 : i_idxY = m_poDataBlock->GetPropertyIndex("SOURADNICE_Y");
427 0 : i_idxX = m_poDataBlock->GetPropertyIndex("SOURADNICE_X");
428 0 : if (i_idxY < 0 || i_idxX < 0)
429 0 : return FALSE;
430 :
431 0 : x = -1.0 * GetProperty(i_idxY)->GetValueD();
432 0 : y = -1.0 * GetProperty(i_idxX)->GetValueD();
433 0 : OGRPoint pt(x, y);
434 0 : SetGeometry(&pt);
435 :
436 0 : return TRUE;
437 : }
438 :
439 : /*!
440 : \brief Load geometry (linestring SBP layer)
441 :
442 : \todo Really needed?
443 :
444 : \return TRUE on success or FALSE on failure
445 : */
446 0 : bool VFKFeature::LoadGeometryLineStringSBP()
447 : {
448 : int id, idxId, idxBp_Id, idxPCB, ipcb;
449 :
450 : VFKDataBlock *poDataBlockPoints;
451 : VFKFeature *poPoint, *poLine;
452 :
453 0 : OGRLineString OGRLine;
454 :
455 0 : poDataBlockPoints = (VFKDataBlock *) m_poDataBlock->GetReader()->GetDataBlock("SOBR");
456 0 : if (!poDataBlockPoints)
457 0 : return FALSE;
458 :
459 0 : idxId = poDataBlockPoints->GetPropertyIndex("ID");
460 0 : idxBp_Id = m_poDataBlock->GetPropertyIndex("BP_ID");
461 0 : idxPCB = m_poDataBlock->GetPropertyIndex("PORADOVE_CISLO_BODU");
462 0 : if (idxId < 0 || idxBp_Id < 0 || idxPCB < 0)
463 0 : return false;
464 :
465 0 : poLine = this;
466 0 : while (TRUE)
467 : {
468 0 : id = poLine->GetProperty(idxBp_Id)->GetValueI();
469 0 : ipcb = poLine->GetProperty(idxPCB)->GetValueI();
470 0 : if (OGRLine.getNumPoints() > 0 && ipcb == 1)
471 : {
472 0 : m_poDataBlock->GetPreviousFeature(); /* push back */
473 0 : break;
474 : }
475 :
476 0 : poPoint = poDataBlockPoints->GetFeature(idxId, id);
477 0 : if (!poPoint)
478 : {
479 0 : continue;
480 : }
481 0 : OGRPoint *pt = (OGRPoint *) poPoint->GetGeometry();
482 0 : OGRLine.addPoint(pt);
483 :
484 0 : poLine = (VFKFeature *) m_poDataBlock->GetNextFeature();
485 0 : if (!poLine)
486 0 : break;
487 : };
488 :
489 0 : OGRLine.setCoordinateDimension(2); /* force 2D */
490 0 : SetGeometry(&OGRLine);
491 :
492 : /* reset reading */
493 0 : poDataBlockPoints->ResetReading();
494 :
495 0 : return TRUE;
496 : }
497 :
498 : /*!
499 : \brief Load geometry (linestring HP/DPM layer)
500 :
501 : \todo Really needed?
502 :
503 : \return TRUE on success or FALSE on failure
504 : */
505 0 : bool VFKFeature::LoadGeometryLineStringHP()
506 : {
507 : int id, idxId, idxHp_Id;
508 : VFKDataBlock *poDataBlockLines;
509 : VFKFeature *poLine;
510 :
511 0 : poDataBlockLines = (VFKDataBlock *) m_poDataBlock->GetReader()->GetDataBlock("SBP");
512 0 : if (!poDataBlockLines)
513 0 : return FALSE;
514 :
515 0 : idxId = m_poDataBlock->GetPropertyIndex("ID");
516 0 : idxHp_Id = poDataBlockLines->GetPropertyIndex("HP_ID");
517 0 : if (idxId < 0 || idxHp_Id < 0)
518 0 : return FALSE;
519 :
520 0 : id = GetProperty(idxId)->GetValueI();
521 0 : poLine = poDataBlockLines->GetFeature(idxHp_Id, id);
522 0 : if (!poLine || !poLine->GetGeometry())
523 0 : return FALSE;
524 :
525 0 : SetGeometry(poLine->GetGeometry());
526 0 : poDataBlockLines->ResetReading();
527 :
528 0 : return TRUE;
529 : }
530 :
531 : /*!
532 : \brief Load geometry (polygon BUD/PAR layers)
533 :
534 : \todo Implement (really needed?)
535 :
536 : \return TRUE on success or FALSE on failure
537 : */
538 0 : bool VFKFeature::LoadGeometryPolygon()
539 : {
540 0 : return FALSE;
541 : }
542 0 : OGRErr VFKFeature::LoadProperties(OGRFeature *poFeature)
543 : {
544 0 : for (int iField = 0; iField < m_poDataBlock->GetPropertyCount(); iField++) {
545 0 : if (GetProperty(iField)->IsNull())
546 0 : continue;
547 0 : OGRFieldType fType = poFeature->GetDefnRef()->GetFieldDefn(iField)->GetType();
548 0 : if (fType == OFTInteger)
549 : poFeature->SetField(iField,
550 0 : GetProperty(iField)->GetValueI());
551 0 : else if (fType == OFTReal)
552 : poFeature->SetField(iField,
553 0 : GetProperty(iField)->GetValueD());
554 : else
555 : poFeature->SetField(iField,
556 0 : GetProperty(iField)->GetValueS());
557 : }
558 :
559 0 : return OGRERR_NONE;
560 : }
|