1 : /******************************************************************************
2 : * $Id: ogrogdilayer.cpp 19711 2010-05-14 21:26:42Z rouault $
3 : *
4 : * Project: OGDI Bridge
5 : * Purpose: Implements OGROGDILayer class.
6 : * Author: Daniel Morissette, danmo@videotron.ca
7 : * (Based on some code contributed by Frank Warmerdam :)
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2000, Daniel Morissette
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ******************************************************************************
30 : * http://bugzilla.remotesensing.org/show_bug.cgi?id=372
31 : *
32 : * Revision 1.6 2003/05/21 03:58:49 warmerda
33 : * expand tabs
34 : *
35 : * Revision 1.5 2001/07/18 04:55:16 warmerda
36 : * added CPL_CSVID
37 : *
38 : * Revision 1.4 2001/06/19 15:50:23 warmerda
39 : * added feature attribute query support
40 : *
41 : * Revision 1.3 2001/04/17 21:41:02 warmerda
42 : * Added use of cln_GetLayerCapabilities() to query list of available layers.
43 : * Restructured OGROGDIDataSource and OGROGDILayer classes somewhat to
44 : * avoid passing so much information in the layer creation call. Added support
45 : * for preserving text on OGDI text features.
46 : *
47 : * Revision 1.2 2000/08/30 01:36:57 danmo
48 : * Added GetSpatialRef() support
49 : *
50 : * Revision 1.1 2000/08/24 04:16:19 danmo
51 : * Initial revision
52 : *
53 : */
54 :
55 : #include "ogrogdi.h"
56 : #include "cpl_conv.h"
57 : #include "cpl_string.h"
58 :
59 : CPL_CVSID("$Id: ogrogdilayer.cpp 19711 2010-05-14 21:26:42Z rouault $");
60 :
61 : /************************************************************************/
62 : /* OGROGDILayer() */
63 : /************************************************************************/
64 :
65 : OGROGDILayer::OGROGDILayer( OGROGDIDataSource *poODS,
66 57 : const char * pszName, ecs_Family eFamily )
67 :
68 : {
69 57 : m_poODS = poODS;
70 57 : m_nClientID = m_poODS->GetClientID();
71 57 : m_eFamily = eFamily;
72 :
73 57 : m_pszOGDILayerName = CPLStrdup(pszName);
74 :
75 57 : m_sFilterBounds = *(m_poODS->GetGlobalBounds());
76 :
77 57 : m_iNextShapeId = 0;
78 57 : m_nTotalShapeCount = -1;
79 57 : m_poFeatureDefn = NULL;
80 :
81 : // Keep a reference on the SpatialRef (owned by the dataset).
82 57 : m_poSpatialRef = m_poODS->GetSpatialRef();
83 :
84 : // Select layer and feature family.
85 57 : ResetReading();
86 :
87 57 : BuildFeatureDefn();
88 57 : }
89 :
90 : /************************************************************************/
91 : /* ~OGROGDILayer() */
92 : /************************************************************************/
93 :
94 57 : OGROGDILayer::~OGROGDILayer()
95 :
96 : {
97 57 : if( m_nFeaturesRead > 0 && m_poFeatureDefn != NULL )
98 : {
99 : CPLDebug( "OGDI", "%d features read on layer '%s'.",
100 : (int) m_nFeaturesRead,
101 4 : m_poFeatureDefn->GetName() );
102 : }
103 :
104 57 : if (m_poFeatureDefn)
105 57 : m_poFeatureDefn->Release();
106 :
107 57 : CPLFree(m_pszOGDILayerName);
108 :
109 : // Note: we do not delete m_poSpatialRef since it is owned by the dataset
110 57 : }
111 :
112 : /************************************************************************/
113 : /* SetSpatialFilter() */
114 : /************************************************************************/
115 :
116 0 : void OGROGDILayer::SetSpatialFilter( OGRGeometry * poGeomIn )
117 :
118 : {
119 0 : if( !InstallFilter( poGeomIn ) )
120 0 : return;
121 :
122 0 : ResetReading();
123 :
124 0 : m_nTotalShapeCount = -1;
125 : }
126 :
127 : /************************************************************************/
128 : /* ResetReading() */
129 : /************************************************************************/
130 :
131 70 : void OGROGDILayer::ResetReading()
132 :
133 : {
134 : ecs_Result *psResult;
135 : ecs_LayerSelection sSelectionLayer;
136 :
137 70 : sSelectionLayer.Select = m_pszOGDILayerName;
138 70 : sSelectionLayer.F = m_eFamily;
139 :
140 70 : psResult = cln_SelectLayer(m_nClientID, &sSelectionLayer);
141 70 : if( ECSERROR( psResult ) )
142 : {
143 : CPLError( CE_Failure, CPLE_AppDefined,
144 : "Access to layer '%s' Failed: %s\n",
145 0 : m_pszOGDILayerName, psResult->message );
146 0 : return;
147 : }
148 :
149 : /* Reset spatial filter */
150 70 : if( m_poFilterGeom != NULL )
151 : {
152 0 : OGREnvelope oEnv;
153 :
154 0 : m_poFilterGeom->getEnvelope(&oEnv);
155 :
156 0 : m_sFilterBounds.north = oEnv.MaxY;
157 0 : m_sFilterBounds.south = oEnv.MinY;
158 0 : m_sFilterBounds.east = oEnv.MinX;
159 0 : m_sFilterBounds.west = oEnv.MaxX;
160 :
161 0 : psResult = cln_SelectRegion( m_nClientID, &m_sFilterBounds);
162 0 : if( ECSERROR(psResult) )
163 : {
164 : CPLError( CE_Failure, CPLE_AppDefined,
165 0 : "%s", psResult->message );
166 0 : return;
167 : }
168 : }
169 : else
170 : {
171 : /* Reset to global bounds */
172 70 : psResult = cln_SelectRegion( m_nClientID, m_poODS->GetGlobalBounds() );
173 70 : if( ECSERROR(psResult) )
174 : {
175 : CPLError( CE_Failure, CPLE_AppDefined,
176 0 : "%s", psResult->message );
177 0 : return;
178 : }
179 : }
180 :
181 70 : m_iNextShapeId = 0;
182 : }
183 :
184 : /************************************************************************/
185 : /* GetNextFeature() */
186 : /************************************************************************/
187 :
188 70 : OGRFeature *OGROGDILayer::GetNextFeature()
189 :
190 : {
191 70 : OGRFeature *poFeature=NULL;
192 : ecs_Result *psResult;
193 : int i;
194 :
195 : /* Reset reading if we are not the current layer */
196 : /* WARNING : this does not allow interleaved reading of layers */
197 70 : if( m_poODS->GetCurrentLayer() != this )
198 : {
199 5 : m_poODS->SetCurrentLayer(this);
200 5 : ResetReading();
201 : }
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Retrieve object from OGDI server and create new feature */
205 : /* -------------------------------------------------------------------- */
206 70 : TryAgain:
207 70 : psResult = cln_GetNextObject(m_nClientID);
208 70 : if (! ECSSUCCESS(psResult))
209 : {
210 : // We probably reached EOF... keep track of shape count.
211 4 : m_nTotalShapeCount = m_iNextShapeId;
212 4 : return NULL;
213 : }
214 :
215 66 : poFeature = new OGRFeature(m_poFeatureDefn);
216 :
217 66 : poFeature->SetFID( m_iNextShapeId++ );
218 66 : m_nFeaturesRead++;
219 :
220 : /* -------------------------------------------------------------------- */
221 : /* Process geometry */
222 : /* -------------------------------------------------------------------- */
223 66 : if (m_eFamily == Point)
224 : {
225 40 : ecs_Point *psPoint = &(ECSGEOM(psResult).point);
226 40 : OGRPoint *poOGRPoint = new OGRPoint(psPoint->c.x, psPoint->c.y);
227 :
228 40 : poFeature->SetGeometryDirectly(poOGRPoint);
229 : }
230 26 : else if (m_eFamily == Line)
231 : {
232 16 : ecs_Line *psLine = &(ECSGEOM(psResult).line);
233 16 : OGRLineString *poOGRLine = new OGRLineString();
234 :
235 16 : poOGRLine->setNumPoints( psLine->c.c_len );
236 :
237 910 : for( i=0; i < (int) psLine->c.c_len; i++ )
238 : {
239 894 : poOGRLine->setPoint(i, psLine->c.c_val[i].x, psLine->c.c_val[i].y);
240 : }
241 :
242 16 : poFeature->SetGeometryDirectly(poOGRLine);
243 : }
244 10 : else if (m_eFamily == Area)
245 : {
246 6 : ecs_Area *psArea = &(ECSGEOM(psResult).area);
247 6 : OGRPolygon *poOGRPolygon = new OGRPolygon();
248 :
249 12 : for(int iRing=0; iRing < (int) psArea->ring.ring_len; iRing++)
250 : {
251 6 : ecs_FeatureRing *psRing = &(psArea->ring.ring_val[iRing]);
252 6 : OGRLinearRing *poOGRRing = new OGRLinearRing();
253 :
254 6 : poOGRRing->setNumPoints( psRing->c.c_len );
255 :
256 1787 : for( i=0; i < (int) psRing->c.c_len; i++ )
257 : {
258 : poOGRRing->setPoint(i, psRing->c.c_val[i].x,
259 1781 : psRing->c.c_val[i].y);
260 : }
261 6 : poOGRPolygon->addRingDirectly(poOGRRing);
262 : }
263 :
264 : // __TODO__
265 : // When OGR supports polygon centroids then we should carry them here
266 :
267 6 : poFeature->SetGeometryDirectly(poOGRPolygon);
268 : }
269 4 : else if (m_eFamily == Text)
270 : {
271 : // __TODO__
272 : // For now text is treated as a point and string is lost
273 : //
274 4 : ecs_Text *psText = &(ECSGEOM(psResult).text);
275 4 : OGRPoint *poOGRPoint = new OGRPoint(psText->c.x, psText->c.y);
276 :
277 4 : poFeature->SetGeometryDirectly(poOGRPoint);
278 : }
279 : else
280 : {
281 0 : CPLAssert(FALSE);
282 : }
283 :
284 : /* -------------------------------------------------------------------- */
285 : /* Set attributes */
286 : /* -------------------------------------------------------------------- */
287 66 : char *pszAttrList = ECSOBJECTATTR(psResult);
288 :
289 452 : for( int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++ )
290 : {
291 : char *pszFieldStart;
292 : int nNameLen;
293 : char chSavedChar;
294 :
295 : /* parse out the next attribute value */
296 386 : if( !ecs_FindElement( pszAttrList, &pszFieldStart, &pszAttrList,
297 : &nNameLen, NULL ) )
298 : {
299 0 : nNameLen = 0;
300 0 : pszFieldStart = pszAttrList;
301 : }
302 :
303 : /* Skip any trailing white space (for string constants). */
304 :
305 386 : if( nNameLen > 0 && pszFieldStart[nNameLen-1] == ' ' )
306 112 : nNameLen--;
307 :
308 : /* skip leading white space */
309 934 : while( pszFieldStart[0] == ' ' && nNameLen > 0 )
310 : {
311 162 : pszFieldStart++;
312 162 : nNameLen--;
313 : }
314 :
315 : /* zero terminate the single field value, but save the */
316 : /* character we overwrote, so we can restore it when done. */
317 :
318 386 : chSavedChar = pszFieldStart[nNameLen];
319 386 : pszFieldStart[nNameLen] = '\0';
320 :
321 : /* OGR takes care of all field type conversions for us! */
322 :
323 386 : poFeature->SetField(iField, pszFieldStart);
324 :
325 386 : pszFieldStart[nNameLen] = chSavedChar;
326 : }
327 :
328 : /* -------------------------------------------------------------------- */
329 : /* Apply the text associated with text features if appropriate. */
330 : /* -------------------------------------------------------------------- */
331 66 : if( m_eFamily == Text )
332 : {
333 4 : poFeature->SetField( "text", ECSGEOM(psResult).text.desc );
334 : }
335 :
336 : /* -------------------------------------------------------------------- */
337 : /* Do we need to apply an attribute test? */
338 : /* -------------------------------------------------------------------- */
339 66 : if( (m_poAttrQuery != NULL
340 : && !m_poAttrQuery->Evaluate( poFeature ) )
341 : || (m_poFilterGeom != NULL
342 : && !FilterGeometry( poFeature->GetGeometryRef() ) ) )
343 : {
344 0 : delete poFeature;
345 0 : goto TryAgain;
346 : }
347 :
348 66 : return poFeature;
349 : }
350 :
351 : /************************************************************************/
352 : /* GetFeature() */
353 : /************************************************************************/
354 :
355 0 : OGRFeature *OGROGDILayer::GetFeature( long nFeatureId )
356 :
357 : {
358 : ecs_Result *psResult;
359 :
360 0 : if (m_nTotalShapeCount != -1 && nFeatureId > m_nTotalShapeCount)
361 0 : return NULL;
362 :
363 0 : if (m_iNextShapeId > nFeatureId )
364 0 : ResetReading();
365 :
366 0 : while(m_iNextShapeId != nFeatureId)
367 : {
368 0 : psResult = cln_GetNextObject(m_nClientID);
369 0 : if (ECSSUCCESS(psResult))
370 0 : m_iNextShapeId++;
371 : else
372 : {
373 : // We probably reached EOF... keep track of shape count.
374 0 : m_nTotalShapeCount = m_iNextShapeId;
375 0 : return NULL;
376 : }
377 : }
378 :
379 : // OK, we're ready to read the requested feature...
380 0 : return GetNextFeature();
381 : }
382 :
383 : /************************************************************************/
384 : /* GetFeatureCount() */
385 : /* */
386 : /* If a spatial filter is in effect, we turn control over to */
387 : /* the generic counter. Otherwise we return the total count. */
388 : /* Eventually we should consider implementing a more efficient */
389 : /* way of counting features matching a spatial query. */
390 : /************************************************************************/
391 :
392 4 : int OGROGDILayer::GetFeatureCount( int bForce )
393 :
394 : {
395 4 : if( m_nTotalShapeCount == -1)
396 : {
397 4 : m_nTotalShapeCount = OGRLayer::GetFeatureCount( bForce );
398 : }
399 :
400 4 : return m_nTotalShapeCount;
401 : }
402 :
403 : /************************************************************************/
404 : /* TestCapability() */
405 : /************************************************************************/
406 :
407 0 : int OGROGDILayer::TestCapability( const char * pszCap )
408 :
409 : {
410 : /* -------------------------------------------------------------------- */
411 : /* Hummm... what are the proper capabilities... */
412 : /* Does OGDI have any idea of capabilities??? */
413 : /* For now just return FALSE for everything. */
414 : /* -------------------------------------------------------------------- */
415 : #ifdef __TODO__
416 : if( EQUAL(pszCap,OLCRandomRead) )
417 : return TRUE;
418 :
419 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
420 : return m_poFilterGeom == NULL;
421 :
422 : else if( EQUAL(pszCap,OLCFastSpatialFilter) )
423 : return FALSE;
424 :
425 : else
426 : return FALSE;
427 : #endif
428 :
429 0 : return FALSE;
430 : }
431 :
432 :
433 :
434 : /************************************************************************/
435 : /* BuildFeatureDefn() */
436 : /* */
437 : /* (private) Initializes the schema in m_poFeatureDefn */
438 : /************************************************************************/
439 :
440 57 : void OGROGDILayer::BuildFeatureDefn()
441 : {
442 : ecs_Result *psResult;
443 : ecs_ObjAttributeFormat *oaf;
444 : int i, numFields;
445 : const char *pszGeomName;
446 : OGRwkbGeometryType eLayerGeomType;
447 :
448 : /* -------------------------------------------------------------------- */
449 : /* Feature Defn name will be "<OGDILyrName>_<FeatureFamily>" */
450 : /* -------------------------------------------------------------------- */
451 :
452 57 : switch(m_eFamily)
453 : {
454 : case Point:
455 13 : pszGeomName = "point";
456 13 : eLayerGeomType = wkbPoint;
457 13 : break;
458 : case Line:
459 16 : pszGeomName = "line";
460 16 : eLayerGeomType = wkbLineString;
461 16 : break;
462 : case Area:
463 20 : pszGeomName = "area";
464 20 : eLayerGeomType = wkbPolygon;
465 20 : break;
466 : case Text:
467 8 : pszGeomName = "text";
468 8 : eLayerGeomType = wkbPoint;
469 8 : break;
470 : default:
471 0 : pszGeomName = "unknown";
472 0 : eLayerGeomType = wkbUnknown;
473 : break;
474 : }
475 :
476 : char* pszFeatureDefnName;
477 57 : if (m_poODS->LaunderLayerNames())
478 : {
479 0 : pszFeatureDefnName = CPLStrdup(m_pszOGDILayerName);
480 0 : char* pszAt = strchr(pszFeatureDefnName, '@');
481 0 : if (pszAt)
482 0 : *pszAt = '_';
483 0 : char* pszLeftParenthesis = strchr(pszFeatureDefnName, '(');
484 0 : if (pszLeftParenthesis)
485 0 : *pszLeftParenthesis = '\0';
486 : }
487 : else
488 : pszFeatureDefnName = CPLStrdup(CPLSPrintf("%s_%s",
489 : m_pszOGDILayerName,
490 57 : pszGeomName ));
491 :
492 57 : m_poFeatureDefn = new OGRFeatureDefn(pszFeatureDefnName);
493 57 : CPLFree(pszFeatureDefnName);
494 57 : pszFeatureDefnName = NULL;
495 :
496 57 : m_poFeatureDefn->SetGeomType(eLayerGeomType);
497 57 : m_poFeatureDefn->Reference();
498 :
499 : /* -------------------------------------------------------------------- */
500 : /* Fetch schema from OGDI server and map to OGR types */
501 : /* -------------------------------------------------------------------- */
502 57 : psResult = cln_GetAttributesFormat( m_nClientID );
503 57 : if( ECSERROR( psResult ) )
504 : {
505 : CPLError(CE_Failure, CPLE_AppDefined,
506 0 : "ECSERROR: %s\n", psResult->message);
507 0 : return;
508 : }
509 :
510 57 : oaf = &(ECSRESULT(psResult).oaf);
511 57 : numFields = oaf->oa.oa_len;
512 474 : for( i = 0; i < numFields; i++ )
513 : {
514 417 : OGRFieldDefn oField("", OFTInteger);
515 :
516 417 : oField.SetName( oaf->oa.oa_val[i].name );
517 417 : oField.SetPrecision( 0 );
518 :
519 417 : switch( oaf->oa.oa_val[i].type )
520 : {
521 : case Decimal:
522 : case Smallint:
523 : case Integer:
524 335 : oField.SetType( OFTInteger );
525 335 : if( oaf->oa.oa_val[i].lenght > 0 )
526 335 : oField.SetWidth( oaf->oa.oa_val[i].lenght );
527 : else
528 0 : oField.SetWidth( 11 );
529 335 : break;
530 :
531 : case Numeric:
532 : case Real:
533 : case Float:
534 : case Double:
535 0 : oField.SetType( OFTReal );
536 0 : if( oaf->oa.oa_val[i].lenght > 0 )
537 : {
538 0 : oField.SetWidth( oaf->oa.oa_val[i].lenght );
539 0 : oField.SetPrecision( oaf->oa.oa_val[i].precision );
540 : }
541 : else
542 : {
543 0 : oField.SetWidth( 18 );
544 0 : oField.SetPrecision( 7 );
545 : }
546 0 : break;
547 :
548 : case Char:
549 : case Varchar:
550 : case Longvarchar:
551 : default:
552 82 : oField.SetType( OFTString );
553 82 : if( oaf->oa.oa_val[i].lenght > 0 )
554 57 : oField.SetWidth( oaf->oa.oa_val[i].lenght );
555 : else
556 25 : oField.SetWidth( 64 );
557 : break;
558 :
559 : }
560 :
561 417 : m_poFeatureDefn->AddFieldDefn( &oField );
562 : }
563 :
564 : /* -------------------------------------------------------------------- */
565 : /* Add a text attribute for text objects. */
566 : /* -------------------------------------------------------------------- */
567 57 : if( m_eFamily == Text )
568 : {
569 8 : OGRFieldDefn oField("text", OFTString);
570 :
571 8 : m_poFeatureDefn->AddFieldDefn( &oField );
572 : }
573 :
574 : }
575 :
576 :
577 :
578 :
|