1 /******************************************************************************
2 * $Id: ogrgrasslayer.cpp 28831 2015-04-01 16:46:05Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implements OGRGRASSLayer class.
6 * Author: Radim Blazek, radim.blazek@gmail.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2005, Radim Blazek <radim.blazek@gmail.com>
10 * Copyright (c) 2008-2010, Even Rouault <even dot rouault at mines-paris dot org>
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
31 #include <signal.h>
32 #include "ogrgrass.h"
33 #include "cpl_conv.h"
34
35 CPL_CVSID("$Id: ogrgrasslayer.cpp 28831 2015-04-01 16:46:05Z rouault $");
36
37 /************************************************************************/
38 /* OGRGRASSLayer() */
39 /************************************************************************/
OGRGRASSLayer(int layerIndex,struct Map_info * map)40 OGRGRASSLayer::OGRGRASSLayer( int layerIndex, struct Map_info * map )
41 {
42 CPLDebug ( "GRASS", "OGRGRASSLayer::OGRGRASSLayer layerIndex = %d", layerIndex );
43
44 iLayerIndex = layerIndex;
45 poMap = map;
46 poSRS = NULL;
47 iNextId = 0;
48 poPoints = Vect_new_line_struct();
49 poCats = Vect_new_cats_struct();
50 pszQuery = NULL;
51 paQueryMatch = NULL;
52 paSpatialMatch = NULL;
53
54 iLayer = Vect_cidx_get_field_number ( poMap, iLayerIndex);
55 CPLDebug ( "GRASS", "iLayer = %d", iLayer );
56
57 poLink = Vect_get_field ( poMap, iLayer ); // May be NULL if not defined
58
59 // Layer name
60 if ( poLink && poLink->name )
61 {
62 pszName = CPLStrdup( poLink->name );
63 }
64 else
65 {
66 char buf[20];
67 sprintf ( buf, "%d", iLayer );
68 pszName = CPLStrdup( buf );
69 }
70
71 // Because we don't represent centroids as any simple feature, we have to scan
72 // category index and create index of feature IDs pointing to category index
73 nTotalCount = Vect_cidx_get_type_count(poMap,iLayer, GV_POINT|GV_LINES|GV_AREA);
74 CPLDebug ( "GRASS", "nTotalCount = %d", nTotalCount );
75 paFeatureIndex = (int *) CPLMalloc ( nTotalCount * sizeof(int) );
76
77 int n = Vect_cidx_get_type_count(poMap,iLayer, GV_POINTS|GV_LINES|GV_AREA);
78 int cnt = 0;
79 for ( int i = 0; i < n; i++ )
80 {
81 int cat,type, id;
82
83 Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, i, &cat, &type, &id );
84
85 if ( !( type & (GV_POINT|GV_LINES|GV_AREA) ) ) continue;
86 paFeatureIndex[cnt++] = i;
87 }
88
89 poFeatureDefn = new OGRFeatureDefn( pszName );
90 SetDescription( poFeatureDefn->GetName() );
91 poFeatureDefn->Reference();
92
93 // Get type definition
94 int nTypes = Vect_cidx_get_num_types_by_index ( poMap, iLayerIndex );
95 int types = 0;
96 for ( int i = 0; i < nTypes; i++ ) {
97 int type, count;
98 Vect_cidx_get_type_count_by_index ( poMap, iLayerIndex, i, &type, &count);
99 if ( !(type & (GV_POINT|GV_LINES|GV_AREA) ) ) continue;
100 types |= type;
101 CPLDebug ( "GRASS", "type = %d types = %d", type, types );
102 }
103
104 OGRwkbGeometryType eGeomType = wkbUnknown;
105 if ( types == GV_LINE || types == GV_BOUNDARY || types == GV_LINES )
106 {
107 eGeomType = wkbLineString;
108 }
109 else if ( types == GV_POINT )
110 {
111 eGeomType = wkbPoint;
112 }
113 else if ( types == GV_AREA )
114 {
115 CPLDebug ( "GRASS", "set wkbPolygon" );
116 eGeomType = wkbPolygon;
117 }
118
119 if (Vect_is_3d(poMap))
120 poFeatureDefn->SetGeomType ( wkbSetZ(eGeomType) );
121 else
122 poFeatureDefn->SetGeomType ( eGeomType );
123
124 // Get attributes definition
125 poDbString = (dbString*) CPLMalloc ( sizeof(dbString) );
126 poCursor = (dbCursor*) CPLMalloc ( sizeof(dbCursor) );
127 bCursorOpened = FALSE;
128
129 poDriver = NULL;
130 bHaveAttributes = false;
131 db_init_string ( poDbString );
132 if ( poLink )
133 {
134 if ( StartDbDriver() )
135 {
136 db_set_string ( poDbString, poLink->table );
137 dbTable *table;
138 if ( db_describe_table ( poDriver, poDbString, &table) == DB_OK )
139 {
140 nFields = db_get_table_number_of_columns ( table );
141 iCatField = -1;
142 for ( int i = 0; i < nFields; i++)
143 {
144 dbColumn *column = db_get_table_column ( table, i );
145 int ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) );
146
147 OGRFieldType ogrFtype = OFTInteger;
148 switch ( ctype ) {
149 case DB_C_TYPE_INT:
150 ogrFtype = OFTInteger;
151 break;
152 case DB_C_TYPE_DOUBLE:
153 ogrFtype = OFTReal;
154 break;
155 case DB_C_TYPE_STRING:
156 ogrFtype = OFTString;
157 break;
158 case DB_C_TYPE_DATETIME:
159 ogrFtype = OFTDateTime;
160 break;
161 }
162
163 CPLDebug ( "GRASS", "column = %s type = %d",
164 db_get_column_name(column), ctype );
165
166 OGRFieldDefn oField ( db_get_column_name(column), ogrFtype );
167 poFeatureDefn->AddFieldDefn( &oField );
168
169 if ( G_strcasecmp(db_get_column_name(column),poLink->key) == 0 )
170 {
171 iCatField = i;
172 }
173 }
174 if ( iCatField >= 0 )
175 {
176 bHaveAttributes = true;
177 }
178 else
179 {
180 CPLError( CE_Failure, CPLE_AppDefined, "Cannot find key field" );
181 db_close_database_shutdown_driver ( poDriver );
182 poDriver = NULL;
183 }
184 }
185 else
186 {
187 CPLError( CE_Failure, CPLE_AppDefined, "Cannot describe table %s",
188 poLink->table );
189
190 }
191 db_close_database_shutdown_driver ( poDriver );
192 poDriver = NULL;
193 }
194 }
195
196 if ( !bHaveAttributes && iLayer > 0 ) // Because features in layer 0 have no cats
197 {
198 OGRFieldDefn oField("cat", OFTInteger);
199 poFeatureDefn->AddFieldDefn( &oField );
200 }
201
202 if ( getenv("GISBASE") ) // We have some projection info in GISBASE
203 {
204 struct Key_Value *projinfo, *projunits;
205
206 // Note: we dont have to reset GISDBASE and LOCATION_NAME because
207 // OGRGRASSLayer constructor is called from OGRGRASSDataSource::Open
208 // where those variables are set
209
210 projinfo = G_get_projinfo();
211 projunits = G_get_projunits();
212
213 char *srsWkt = GPJ_grass_to_wkt ( projinfo, projunits, 0, 0);
214 if ( srsWkt )
215 {
216 poSRS = new OGRSpatialReference ( srsWkt );
217 G_free ( srsWkt );
218 }
219
220 G_free_key_value(projinfo);
221 G_free_key_value(projunits);
222 }
223 }
224
225 /************************************************************************/
226 /* ~OGRGRASSLayer() */
227 /************************************************************************/
~OGRGRASSLayer()228 OGRGRASSLayer::~OGRGRASSLayer()
229 {
230 if ( bCursorOpened )
231 {
232 db_close_cursor ( poCursor);
233 }
234
235 if ( poDriver )
236 {
237 StopDbDriver();
238 }
239
240 if ( pszName ) CPLFree ( pszName );
241 if ( poFeatureDefn )
242 poFeatureDefn->Release();
243 if ( poSRS )
244 poSRS->Release();
245
246 if ( pszQuery ) CPLFree ( pszQuery );
247
248 if ( paFeatureIndex ) CPLFree ( paFeatureIndex );
249
250 if ( poLink ) G_free ( poLink );
251
252 Vect_destroy_line_struct ( poPoints );
253 Vect_destroy_cats_struct ( poCats );
254
255 db_free_string ( poDbString );
256 CPLFree ( poDbString );
257 CPLFree ( poCursor );
258
259 if ( paSpatialMatch ) CPLFree ( paSpatialMatch );
260 if ( paQueryMatch ) CPLFree ( paQueryMatch );
261 }
262
263 /************************************************************************/
264 /* StartDbDriver */
265 /************************************************************************/
StartDbDriver()266 bool OGRGRASSLayer::StartDbDriver()
267 {
268 CPLDebug ( "GRASS", "StartDbDriver()" );
269
270 bCursorOpened = false;
271
272 if ( !poLink )
273 {
274 return false;
275 }
276 poDriver = db_start_driver_open_database ( poLink->driver, poLink->database );
277
278 if ( poDriver == NULL)
279 {
280 CPLError( CE_Failure, CPLE_AppDefined, "Cannot open database %s by driver %s, "
281 "check if GISBASE environment variable is set, the driver is available "
282 " and the database is accessible.", poLink->driver, poLink->database );
283 return false;
284 }
285 return true;
286 }
287
288 /************************************************************************/
289 /* StopDbDriver */
290 /************************************************************************/
StopDbDriver()291 bool OGRGRASSLayer::StopDbDriver()
292 {
293 if ( !poDriver )
294 {
295 CPLError( CE_Failure, CPLE_AppDefined, "Driver is not started" );
296 return true; // I think that true is OK here
297 }
298
299 // TODO!!!: Because of bug in GRASS library it is impossible
300 // to stop drivers in FIFO order. Until this is fixed
301 // we have to use kill
302 CPLDebug ( "GRASS", "driver PID = %d", poDriver->pid );
303
304 #if defined(_WIN32) || defined(__WIN32__)
305 db_close_database_shutdown_driver ( poDriver );
306 #else
307 if ( kill (poDriver->pid, SIGINT) != 0 )
308 {
309 if ( kill (poDriver->pid, SIGKILL) != 0 )
310 {
311 CPLError( CE_Failure, CPLE_AppDefined, "Cannot stop database "
312 "driver pid = %d", poDriver->pid );
313 }
314 }
315 #endif
316
317 bCursorOpened = false;
318
319 return true;
320 }
321
322 /************************************************************************/
323 /* ResetReading() */
324 /************************************************************************/
ResetReading()325 void OGRGRASSLayer::ResetReading()
326 {
327 iNextId = 0;
328
329 if ( bCursorOpened ) {
330 ResetSequentialCursor();
331 }
332 }
333
334 /************************************************************************/
335 /* SetNextByIndex() */
336 /* */
337 /* If we already have an FID list, we can easily resposition */
338 /* ourselves in it. */
339 /************************************************************************/
SetNextByIndex(GIntBig nIndex)340 OGRErr OGRGRASSLayer::SetNextByIndex( GIntBig nIndex )
341 {
342 if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
343 {
344 iNextId = 0;
345 int count = 0;
346
347 while ( true ) {
348 if( iNextId >= nTotalCount ) break;
349 if ( count == nIndex ) break;
350
351 // Attributes
352 if( pszQuery != NULL && !paQueryMatch[iNextId] ) {
353 iNextId++;
354 continue;
355 }
356
357 // Spatial
358 if( m_poFilterGeom && !paSpatialMatch[iNextId] ) {
359 iNextId++;
360 continue;
361 }
362 count++;
363 }
364 }
365
366 iNextId = nIndex;
367
368 return OGRERR_NONE;
369 }
370
371 /************************************************************************/
372 /* SetAttributeFilter */
373 /************************************************************************/
SetAttributeFilter(const char * query)374 OGRErr OGRGRASSLayer::SetAttributeFilter( const char *query )
375 {
376 CPLDebug ( "GRASS", "SetAttributeFilter: %s", query );
377
378 if ( query == NULL ) {
379 // Release old if any
380 if ( pszQuery ) {
381 CPLFree ( pszQuery );
382 pszQuery = NULL;
383 }
384 if ( paQueryMatch ) {
385 CPLFree ( paQueryMatch );
386 paQueryMatch = NULL;
387 }
388 return OGRERR_NONE;
389 }
390
391 paQueryMatch = (char *) CPLMalloc ( nTotalCount );
392 memset ( paQueryMatch, 0x0, nTotalCount );
393 pszQuery = CPLStrdup(query);
394
395 OGRLayer::SetAttributeFilter(query); // Otherwise crash on delete
396
397 if ( bHaveAttributes ) {
398
399 if ( !poDriver )
400 {
401 StartDbDriver();
402 }
403
404 if ( poDriver )
405 {
406 if ( bCursorOpened )
407 {
408 db_close_cursor ( poCursor );
409 bCursorOpened = false;
410 }
411 OpenSequentialCursor();
412 if ( bCursorOpened )
413 {
414 SetQueryMatch();
415 db_close_cursor ( poCursor );
416 bCursorOpened = false;
417 }
418 else
419 {
420 CPLFree ( pszQuery );
421 pszQuery = NULL;
422 return OGRERR_FAILURE;
423 }
424 db_close_database_shutdown_driver ( poDriver );
425 poDriver = NULL;
426 }
427 else
428 {
429 CPLFree ( pszQuery );
430 pszQuery = NULL;
431 return OGRERR_FAILURE;
432 }
433 }
434 else
435 {
436 // Use OGR to evaluate category match
437 for ( int i = 0; i < nTotalCount; i++ )
438 {
439 OGRFeature *feature = GetFeature(i);
440 CPLDebug ( "GRASS", "i = %d eval = %d", i, m_poAttrQuery->Evaluate ( feature ) );
441 if ( m_poAttrQuery->Evaluate ( feature ) )
442 {
443 paQueryMatch[i] = 1;
444 }
445 }
446 }
447
448 return OGRERR_NONE;
449 }
450
451 /************************************************************************/
452 /* SetQueryMatch */
453 /************************************************************************/
SetQueryMatch()454 bool OGRGRASSLayer::SetQueryMatch()
455 {
456 CPLDebug ( "GRASS", "SetQueryMatch" );
457
458 // NOTE: we don't have to call ResetSequentialCursor() first because
459 // this method is called immediately after OpenSequentialCursor()
460
461 if ( !bCursorOpened ) {
462 CPLError( CE_Failure, CPLE_AppDefined, "Cursor is not opened.");
463 return false;
464 }
465
466 int more;
467 int cidx = 0; // index to category index
468 int fidx = 0; // index to feature index (paFeatureIndex)
469 // number of categories in category index
470 int ncats = Vect_cidx_get_num_cats_by_index ( poMap, iLayerIndex );
471 dbTable *table = db_get_cursor_table ( poCursor );
472 while ( true ) {
473 if( db_fetch ( poCursor, DB_NEXT, &more) != DB_OK )
474 {
475 CPLError( CE_Failure, CPLE_AppDefined, "Cannot fetch attributes.");
476 return false;
477 }
478 if ( !more ) break;
479
480 dbColumn *column = db_get_table_column ( table, iCatField );
481 dbValue *value = db_get_column_value ( column );
482 int cat = db_get_value_int ( value );
483
484 // NOTE: because of bug in GRASS library it is impossible to use
485 // Vect_cidx_find_next
486
487 // Go through category index until first record of current category
488 // is found or a category > current is found
489 int cidxcat, type, id;
490 while ( cidx < ncats ) {
491 Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx,
492 &cidxcat, &type, &id );
493
494 if ( cidxcat < cat ) {
495 cidx++;
496 continue;
497 }
498 if ( cidxcat > cat ) break; // Not found
499
500 // We have the category we want, check type
501 if ( !(type & (GV_POINT|GV_LINES|GV_AREA)) )
502 {
503 cidx++;
504 continue;
505 }
506
507 // Both category and type match -> find feature and set it on
508 while ( true ) {
509 if ( fidx > nTotalCount || paFeatureIndex[fidx] > cidx ) {
510 // should not happen
511 break;
512 }
513
514 if ( paFeatureIndex[fidx] == cidx ) {
515 paQueryMatch[fidx] = 1;
516 fidx++;
517 break;
518 }
519 fidx++;
520 }
521 cidx++;
522 }
523
524 if ( id < 0 ) continue; // not found
525 }
526
527 return true;
528 }
529
530 /************************************************************************/
531 /* OpenSequentialCursor */
532 /************************************************************************/
OpenSequentialCursor()533 bool OGRGRASSLayer::OpenSequentialCursor()
534 {
535 CPLDebug ( "GRASS", "OpenSequentialCursor: %s", pszQuery );
536
537 if ( !poDriver )
538 {
539 CPLError( CE_Failure, CPLE_AppDefined, "Driver not opened.");
540 return false;
541 }
542
543 if ( bCursorOpened )
544 {
545 db_close_cursor ( poCursor );
546 bCursorOpened = false;
547 }
548
549 char buf[2000];
550 sprintf ( buf, "SELECT * FROM %s ", poLink->table );
551 db_set_string ( poDbString, buf);
552
553 if ( pszQuery ) {
554 sprintf ( buf, "WHERE %s ", pszQuery );
555 db_append_string ( poDbString, buf);
556 }
557
558 sprintf ( buf, "ORDER BY %s", poLink->key);
559 db_append_string ( poDbString, buf);
560
561 CPLDebug ( "GRASS", "Query: %s", db_get_string(poDbString) );
562
563 if ( db_open_select_cursor ( poDriver, poDbString,
564 poCursor, DB_SCROLL) == DB_OK )
565 {
566 iCurrentCat = -1;
567 bCursorOpened = true;
568 CPLDebug ( "GRASS", "num rows = %d", db_get_num_rows ( poCursor ) );
569 }
570 else
571 {
572 CPLError( CE_Failure, CPLE_AppDefined, "Cannot open cursor.");
573 return false;
574 }
575 return true;
576 }
577
578 /************************************************************************/
579 /* ResetSequentialCursor */
580 /************************************************************************/
ResetSequentialCursor()581 bool OGRGRASSLayer::ResetSequentialCursor()
582 {
583 CPLDebug ( "GRASS", "ResetSequentialCursor" );
584
585 int more;
586 if( db_fetch ( poCursor, DB_FIRST, &more) != DB_OK )
587 {
588 CPLError( CE_Failure, CPLE_AppDefined, "Cannot reset cursor.");
589 return false;
590 }
591 if( db_fetch ( poCursor, DB_PREVIOUS, &more) != DB_OK )
592 {
593 CPLError( CE_Failure, CPLE_AppDefined, "Cannot reset cursor.");
594 return false;
595 }
596 return true;
597 }
598
599 /************************************************************************/
600 /* SetSpatialFilter */
601 /************************************************************************/
SetSpatialFilter(OGRGeometry * poGeomIn)602 void OGRGRASSLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
603 {
604 CPLDebug ( "GRASS", "SetSpatialFilter" );
605
606 OGRLayer::SetSpatialFilter ( poGeomIn );
607
608 if ( poGeomIn == NULL ) {
609 // Release old if any
610 if ( paSpatialMatch ) {
611 CPLFree ( paSpatialMatch );
612 paSpatialMatch = NULL;
613 }
614 return;
615 }
616
617 SetSpatialMatch();
618 }
619
620 /************************************************************************/
621 /* SetSpatialMatch */
622 /************************************************************************/
SetSpatialMatch()623 bool OGRGRASSLayer::SetSpatialMatch()
624 {
625 CPLDebug ( "GRASS", "SetSpatialMatch" );
626
627 if ( !paSpatialMatch )
628 {
629 paSpatialMatch = (char *) CPLMalloc ( nTotalCount );
630 }
631 memset ( paSpatialMatch, 0x0, nTotalCount );
632
633 OGRGeometry *geom;
634 OGRLineString *lstring = new OGRLineString();
635 lstring->setNumPoints ( 5 );
636 geom = lstring;
637
638 for ( int i = 0; i < nTotalCount; i++ ) {
639 int cidx = paFeatureIndex[i];
640
641 int cat, type, id;
642
643 Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx, &cat, &type, &id );
644
645 #if GRASS_VERSION_MAJOR >= 7
646 struct bound_box box;
647 #else
648 BOUND_BOX box;
649 #endif
650
651 switch ( type )
652 {
653 case GV_POINT:
654 case GV_LINE:
655 case GV_BOUNDARY:
656 Vect_get_line_box ( poMap, id, &box );
657 break;
658
659 case GV_AREA:
660 Vect_get_area_box ( poMap, id, &box );
661 break;
662 }
663
664 lstring->setPoint( 0, box.W, box.N, 0. );
665 lstring->setPoint( 1, box.W, box.S, 0. );
666 lstring->setPoint( 2, box.E, box.S, 0. );
667 lstring->setPoint( 3, box.E, box.N, 0. );
668 lstring->setPoint( 4, box.W, box.N, 0. );
669
670 if ( FilterGeometry(geom) ) {
671 CPLDebug ( "GRASS", "Feature %d in filter", i );
672 paSpatialMatch[i] = 1;
673 }
674 }
675 delete lstring;
676 return true;
677 }
678
679 /************************************************************************/
680 /* GetNextFeature() */
681 /************************************************************************/
GetNextFeature()682 OGRFeature *OGRGRASSLayer::GetNextFeature()
683 {
684 CPLDebug ( "GRASS", "OGRGRASSLayer::GetNextFeature" );
685 OGRFeature *poFeature = NULL;
686
687 int cat;
688
689 // Get next iNextId
690 while ( true ) {
691 if( iNextId >= nTotalCount ) // No more features
692 {
693 // Close cursor / driver if opened
694 if ( bCursorOpened )
695 {
696 db_close_cursor ( poCursor);
697 bCursorOpened = false;
698 }
699 if ( poDriver )
700 {
701 db_close_database_shutdown_driver ( poDriver );
702 poDriver = NULL;
703 }
704
705 return NULL;
706 }
707
708 // Attributes
709 if( pszQuery != NULL && !paQueryMatch[iNextId] ) {
710 iNextId++;
711 continue;
712 }
713
714 // Spatial
715 if( m_poFilterGeom && !paSpatialMatch[iNextId] ) {
716 iNextId++;
717 continue;
718 }
719
720 break; // Attributes & spatial filter match
721 }
722
723 OGRGeometry *poOGR = GetFeatureGeometry ( iNextId, &cat );
724
725 poFeature = new OGRFeature( poFeatureDefn );
726 poFeature->SetGeometryDirectly( poOGR );
727 poFeature->SetFID ( iNextId );
728 iNextId++;
729
730 // Get attributes
731 CPLDebug ( "GRASS", "bHaveAttributes = %d", bHaveAttributes );
732 if ( bHaveAttributes )
733 {
734 if ( !poDriver )
735 {
736 StartDbDriver();
737 }
738 if ( poDriver ) {
739 if ( !bCursorOpened )
740 {
741 OpenSequentialCursor();
742 }
743 if ( bCursorOpened )
744 {
745 dbTable *table = db_get_cursor_table ( poCursor );
746 if ( iCurrentCat < cat )
747 {
748 while ( true ) {
749 int more;
750 if( db_fetch ( poCursor, DB_NEXT, &more) != DB_OK )
751 {
752 CPLError( CE_Failure, CPLE_AppDefined,
753 "Cannot fetch attributes.");
754 break;
755 }
756 if ( !more ) break;
757
758 dbColumn *column = db_get_table_column ( table, iCatField );
759 dbValue *value = db_get_column_value ( column );
760 iCurrentCat = db_get_value_int ( value );
761
762 if ( iCurrentCat >= cat ) break;
763 }
764 }
765 if ( cat == iCurrentCat )
766 {
767 SetAttributes ( poFeature, table );
768 }
769 else
770 {
771 CPLError( CE_Failure, CPLE_AppDefined, "Attributes not found.");
772 }
773 }
774 }
775 }
776 else if ( iLayer > 0 ) // Add category
777 {
778 poFeature->SetField( 0, cat );
779 }
780
781 m_nFeaturesRead++;
782 return poFeature;
783 }
784 /************************************************************************/
785 /* GetFeature() */
786 /************************************************************************/
GetFeature(GIntBig nFeatureId)787 OGRFeature *OGRGRASSLayer::GetFeature( GIntBig nFeatureId )
788
789 {
790 CPLDebug ( "GRASS", "OGRGRASSLayer::GetFeature nFeatureId = %ld", nFeatureId );
791
792 int cat;
793 OGRFeature *poFeature = NULL;
794
795 OGRGeometry *poOGR = GetFeatureGeometry ( nFeatureId, &cat );
796
797 poFeature = new OGRFeature( poFeatureDefn );
798 poFeature->SetGeometryDirectly( poOGR );
799 poFeature->SetFID ( nFeatureId );
800
801 // Get attributes
802 if ( bHaveAttributes && !poDriver )
803 {
804 StartDbDriver();
805 }
806 if ( poDriver )
807 {
808 if ( bCursorOpened )
809 {
810 db_close_cursor ( poCursor);
811 bCursorOpened = false;
812 }
813 CPLDebug ( "GRASS", "Open cursor for key = %d", cat );
814 char buf[2000];
815 sprintf ( buf, "SELECT * FROM %s WHERE %s = %d",
816 poLink->table, poLink->key, cat );
817 db_set_string ( poDbString, buf);
818 if ( db_open_select_cursor ( poDriver, poDbString,
819 poCursor, DB_SEQUENTIAL) == DB_OK )
820 {
821 iCurrentCat = cat; // Not important
822 bCursorOpened = true;
823 }
824 else
825 {
826 CPLError( CE_Failure, CPLE_AppDefined, "Cannot open cursor.");
827 }
828
829 if ( bCursorOpened )
830 {
831 int more;
832 if( db_fetch ( poCursor, DB_NEXT, &more) != DB_OK )
833 {
834 CPLError( CE_Failure, CPLE_AppDefined, "Cannot fetch attributes.");
835 }
836 else
837 {
838 if ( !more )
839 {
840 CPLError( CE_Failure, CPLE_AppDefined, "Attributes not found.");
841 }
842 else
843 {
844 dbTable *table = db_get_cursor_table ( poCursor );
845 SetAttributes ( poFeature, table );
846 }
847 }
848 db_close_cursor ( poCursor);
849 bCursorOpened = false;
850 }
851 }
852 else if ( iLayer > 0 ) // Add category
853 {
854 poFeature->SetField( 0, cat );
855 }
856
857 m_nFeaturesRead++;
858 return poFeature;
859 }
860
861 /************************************************************************/
862 /* GetFeatureGeometry() */
863 /************************************************************************/
GetFeatureGeometry(long nFeatureId,int * cat)864 OGRGeometry *OGRGRASSLayer::GetFeatureGeometry ( long nFeatureId, int *cat )
865 {
866 CPLDebug ( "GRASS", "OGRGRASSLayer::GetFeatureGeometry nFeatureId = %ld", nFeatureId );
867
868 int cidx = paFeatureIndex[(int)nFeatureId];
869
870 int type, id;
871 Vect_cidx_get_cat_by_index ( poMap, iLayerIndex, cidx, cat, &type, &id );
872
873 //CPLDebug ( "GRASS", "cat = %d type = %d id = %d", *cat, type, id );
874
875 OGRGeometry *poOGR = NULL;
876 int bIs3D = Vect_is_3d(poMap);
877
878 switch ( type ) {
879 case GV_POINT:
880 {
881 Vect_read_line ( poMap, poPoints, poCats, id);
882 if (bIs3D)
883 poOGR = new OGRPoint( poPoints->x[0], poPoints->y[0], poPoints->z[0] );
884 else
885 poOGR = new OGRPoint( poPoints->x[0], poPoints->y[0] );
886 }
887 break;
888
889 case GV_LINE:
890 case GV_BOUNDARY:
891 {
892 Vect_read_line ( poMap, poPoints, poCats, id);
893 OGRLineString *poOGRLine = new OGRLineString();
894 if (bIs3D)
895 poOGRLine->setPoints( poPoints->n_points,
896 poPoints->x, poPoints->y, poPoints->z );
897 else
898 poOGRLine->setPoints( poPoints->n_points,
899 poPoints->x, poPoints->y );
900
901 poOGR = poOGRLine;
902 }
903 break;
904
905 case GV_AREA:
906 {
907 Vect_get_area_points ( poMap, id, poPoints );
908
909 OGRPolygon *poOGRPoly;
910 poOGRPoly = new OGRPolygon();
911
912 OGRLinearRing *poRing;
913 poRing = new OGRLinearRing();
914 if (bIs3D)
915 poRing->setPoints( poPoints->n_points,
916 poPoints->x, poPoints->y, poPoints->z );
917 else
918 poRing->setPoints( poPoints->n_points,
919 poPoints->x, poPoints->y );
920
921 poOGRPoly->addRingDirectly( poRing );
922
923 // Islands
924 int nisles = Vect_get_area_num_isles ( poMap, id );
925 for ( int i = 0; i < nisles; i++ ) {
926 int isle = Vect_get_area_isle ( poMap, id, i );
927 Vect_get_isle_points ( poMap, isle, poPoints );
928
929 poRing = new OGRLinearRing();
930 if (bIs3D)
931 poRing->setPoints( poPoints->n_points,
932 poPoints->x, poPoints->y, poPoints->z );
933 else
934 poRing->setPoints( poPoints->n_points,
935 poPoints->x, poPoints->y );
936
937 poOGRPoly->addRingDirectly( poRing );
938 }
939
940 poOGR = poOGRPoly;
941 }
942 break;
943
944 default: // Should not happen
945 {
946 CPLError( CE_Failure, CPLE_AppDefined, "Unknown GRASS feature type.");
947 return NULL;
948 }
949 }
950
951 return poOGR;
952 }
953
954 /************************************************************************/
955 /* SetAttributes() */
956 /************************************************************************/
SetAttributes(OGRFeature * poFeature,dbTable * table)957 bool OGRGRASSLayer::SetAttributes ( OGRFeature *poFeature, dbTable *table )
958 {
959 CPLDebug ( "GRASS", "OGRGRASSLayer::SetAttributes" );
960
961 for ( int i = 0; i < nFields; i++)
962 {
963 dbColumn *column = db_get_table_column ( table, i );
964 dbValue *value = db_get_column_value ( column );
965
966 int ctype = db_sqltype_to_Ctype ( db_get_column_sqltype(column) );
967
968 if ( !db_test_value_isnull(value) )
969 {
970 switch ( ctype ) {
971 case DB_C_TYPE_INT:
972 poFeature->SetField( i, db_get_value_int ( value ));
973 break;
974 case DB_C_TYPE_DOUBLE:
975 poFeature->SetField( i, db_get_value_double ( value ));
976 break;
977 case DB_C_TYPE_STRING:
978 poFeature->SetField( i, db_get_value_string ( value ));
979 break;
980 case DB_C_TYPE_DATETIME:
981 db_convert_column_value_to_string ( column, poDbString );
982 poFeature->SetField( i, db_get_string ( poDbString ));
983 break;
984 }
985 }
986
987 db_convert_column_value_to_string ( column, poDbString );
988 //CPLDebug ( "GRASS", "val = %s", db_get_string ( poDbString ));
989 }
990 return true;
991 }
992
993 /************************************************************************/
994 /* ISetFeature() */
995 /************************************************************************/
ISetFeature(OGRFeature * poFeature)996 OGRErr OGRGRASSLayer::ISetFeature( OGRFeature *poFeature )
997 {
998 return OGRERR_FAILURE;
999 }
1000
1001 /************************************************************************/
1002 /* ICreateFeature() */
1003 /************************************************************************/
ICreateFeature(OGRFeature * poFeature)1004 OGRErr OGRGRASSLayer::ICreateFeature( OGRFeature *poFeature )
1005 {
1006 return OGRERR_FAILURE;
1007 }
1008
1009 /************************************************************************/
1010 /* GetFeatureCount() */
1011 /* */
1012 /* If a spatial filter is in effect, we turn control over to */
1013 /* the generic counter. Otherwise we return the total count. */
1014 /* Eventually we should consider implementing a more efficient */
1015 /* way of counting features matching a spatial query. */
1016 /************************************************************************/
GetFeatureCount(int bForce)1017 GIntBig OGRGRASSLayer::GetFeatureCount( int bForce )
1018 {
1019 if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
1020 return OGRLayer::GetFeatureCount( bForce );
1021
1022 return nTotalCount;
1023 }
1024
1025 /************************************************************************/
1026 /* GetExtent() */
1027 /* */
1028 /* Fetch extent of the data currently stored in the dataset. */
1029 /* The bForce flag has no effect on SHO files since that value */
1030 /* is always in the header. */
1031 /* */
1032 /* Returns OGRERR_NONE/OGRRERR_FAILURE. */
1033 /************************************************************************/
GetExtent(OGREnvelope * psExtent,int bForce)1034 OGRErr OGRGRASSLayer::GetExtent (OGREnvelope *psExtent, int bForce)
1035 {
1036 #if GRASS_VERSION_MAJOR >= 7
1037 struct bound_box box;
1038 #else
1039 BOUND_BOX box;
1040 #endif
1041
1042 Vect_get_map_box ( poMap, &box );
1043
1044 psExtent->MinX = box.W;
1045 psExtent->MinY = box.S;
1046 psExtent->MaxX = box.E;
1047 psExtent->MaxY = box.N;
1048
1049 return OGRERR_NONE;
1050 }
1051
1052 /************************************************************************/
1053 /* TestCapability() */
1054 /************************************************************************/
TestCapability(const char * pszCap)1055 int OGRGRASSLayer::TestCapability( const char * pszCap )
1056 {
1057 if( EQUAL(pszCap,OLCRandomRead) )
1058 return TRUE;
1059
1060 else if( EQUAL(pszCap,OLCFastFeatureCount) )
1061 return TRUE;
1062
1063 else if( EQUAL(pszCap,OLCFastSpatialFilter) )
1064 return FALSE;
1065
1066 else if( EQUAL(pszCap,OLCFastGetExtent) )
1067 return TRUE;
1068
1069 else if( EQUAL(pszCap,OLCFastSetNextByIndex) )
1070 return TRUE;
1071
1072 else
1073 return FALSE;
1074 }
1075
1076 /************************************************************************/
1077 /* CreateField() */
1078 /************************************************************************/
CreateField(OGRFieldDefn * poField,int bApproxOK)1079 OGRErr OGRGRASSLayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
1080 {
1081 CPLError( CE_Failure, CPLE_NotSupported,
1082 "Can't create fields on a GRASS layer.\n");
1083
1084 return OGRERR_FAILURE;
1085 }
1086
1087 /************************************************************************/
1088 /* GetSpatialRef() */
1089 /************************************************************************/
GetSpatialRef()1090 OGRSpatialReference *OGRGRASSLayer::GetSpatialRef()
1091 {
1092 return poSRS;
1093 }
1094
1095