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