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