/**************************************************************** * * MODULE: v.in.ogr * * AUTHOR(S): Radim Blazek * * PURPOSE: Import OGR vectors * * COPYRIGHT: (C) 2001 by the GRASS Development Team * * This program is free software under the * GNU General Public License (>=v2). * Read the file COPYING that comes with GRASS * for details. * **************************************************************/ #include #include #include #include #include #include "ogr_api.h" #include "global.h" /* Add categories to centroids inside polygon */ int centroid(OGRGeometryH hGeom, CENTR *Centr, SPATIAL_INDEX *Sindex, int field, int cat, double min_area, int type) { int i, j, np, nr, ret; static int first = 1; static struct line_pnts *Points; struct line_pnts **IPoints; static struct line_cats *BCats, *Cats ; OGRwkbGeometryType eType; OGRGeometryH hRing; double size; static struct ilist *List; BOUND_BOX box; G_debug ( 3, "centroid() cat = %d", cat ); if ( first ) { Points = Vect_new_line_struct (); BCats = Vect_new_cats_struct (); Cats = Vect_new_cats_struct (); List = Vect_new_list (); first = 0; } else { Vect_reset_line ( Points ); Vect_reset_cats ( Cats ); Vect_reset_cats ( BCats ); Vect_cat_set ( Cats, field, cat ); } eType = wkbFlatten(OGR_G_GetGeometryType(hGeom)); if( eType == wkbPolygon ) { nr = OGR_G_GetGeometryCount( hGeom ); G_debug ( 3, "polygon: %d rings", nr ); /* SFS: 1 exterior boundary and 0 or more interior boundaries. * So I hope that exterior is the first one, even if it is not explicitly told */ /* Area */ hRing = OGR_G_GetGeometryRef( hGeom, 0 ); np = OGR_G_GetPointCount(hRing); Vect_reset_line ( Points ); for( j = 0; j < np; j++ ) { Vect_append_point ( Points, OGR_G_GetX(hRing,j), OGR_G_GetY(hRing,j), OGR_G_GetZ(hRing,j) ); } /* Degenerate is ignored */ if ( Points->n_points < 4 ) return 0; /* Small areas ignored because boundaries are not imported */ size = G_area_of_polygon(Points->x, Points->y, Points->n_points); if ( size < min_area ) return 0; /* Isles */ IPoints = (struct line_pnts **) G_malloc ( (nr-1) * sizeof (struct line_pnts *) ); for( i = 1; i < nr; i++ ) { IPoints[i-1] = Vect_new_line_struct (); hRing = OGR_G_GetGeometryRef( hGeom, i ); np = OGR_G_GetPointCount(hRing); for( j = 0; j < np; j++ ) { Vect_append_point ( IPoints[i-1], OGR_G_GetX(hRing,j), OGR_G_GetY(hRing,j), OGR_G_GetZ(hRing,j) ); } } /* Find centroids */ if ( Points->n_points >= 4 ) { int centr, in; double x,y; Vect_line_box (Points, &box); Vect_spatial_index_select (Sindex, &box, List); for( i = 0; i < List->n_values; i++ ) { centr = List->value[i]; x = Centr[centr].x; y = Centr[centr].y; ret = Vect_point_in_poly ( x, y, Points); if ( ret == 0 ) continue; /* outside */ in = 1; for( j = 1; j < nr; j++ ) { ret = Vect_point_in_poly ( x, y, IPoints[j-1] ); if ( ret == 1 ) { /* centroid in inner ring */ in = 0; break; /* inside isle */ } } if ( !in ) continue; G_debug ( 3, "Centroid %d : layer %d cat %d", centr, field, cat ); Vect_cat_set ( Centr[centr].cats, field, cat); } } for( i = 1; i < nr; i++ ) { Vect_destroy_line_struct ( IPoints[i-1] ); } if ( nr > 1 ) G_free ( IPoints ); } /* I did not test this because I did not have files of these types */ else if( eType == wkbGeometryCollection || eType == wkbMultiPolygon ) { G_debug (3, "GeometryCollection or MultiPolygon/LineString/Point" ); nr = OGR_G_GetGeometryCount( hGeom ); for( i = 0; i < nr; i++ ) { hRing = OGR_G_GetGeometryRef( hGeom, i ); ret = centroid( hRing, Centr, Sindex, field, cat, min_area, type ); } } return 0; } /* Write geometry to output map */ int geom(OGRGeometryH hGeom, struct Map_info *Map, int field, int cat, double min_area, int type, int mk_centr) { int i, j, np, nr, ret, otype; static int first = 1; static struct line_pnts *Points; struct line_pnts **IPoints; static struct line_cats *BCats, *Cats ; OGRwkbGeometryType eType; OGRGeometryH hRing; double x, y; double size; G_debug (3, "geom() cat = %d", cat ); if ( first ) { Points = Vect_new_line_struct (); BCats = Vect_new_cats_struct (); Cats = Vect_new_cats_struct (); first = 0; } Vect_reset_line ( Points ); Vect_reset_cats ( Cats ); Vect_reset_cats ( BCats ); Vect_cat_set ( Cats, field, cat ); eType = wkbFlatten(OGR_G_GetGeometryType(hGeom)); if( eType == wkbPoint ) { Vect_append_point ( Points, OGR_G_GetX(hGeom,0), OGR_G_GetY(hGeom,0), OGR_G_GetZ(hGeom,0) ); if ( type & GV_CENTROID ) otype = GV_CENTROID; else otype = GV_POINT; Vect_write_line ( Map, otype, Points, Cats); } else if( eType == wkbLineString ) { np = OGR_G_GetPointCount(hGeom); for( i = 0; i < np; i++ ) { Vect_append_point ( Points, OGR_G_GetX(hGeom,i), OGR_G_GetY(hGeom,i), OGR_G_GetZ(hGeom,i) ); } if ( type & GV_BOUNDARY ) otype = GV_BOUNDARY; else otype = GV_LINE; Vect_write_line ( Map, otype, Points, Cats); } else if( eType == wkbPolygon ) { G_debug (3, "Polygon" ); n_polygons++; nr = OGR_G_GetGeometryCount( hGeom ); /* SFS: 1 exterior boundary and 0 or more interior boundaries. * So I hope that exterior is the first one, even if it is not explicitly told */ /* Area */ hRing = OGR_G_GetGeometryRef( hGeom, 0 ); np = OGR_G_GetPointCount(hRing); Vect_reset_line ( Points ); for( j = 0; j < np; j++ ) { Vect_append_point ( Points, OGR_G_GetX(hRing,j), OGR_G_GetY(hRing,j), OGR_G_GetZ(hRing,j) ); } /* Degenerate is not ignored because it may be useful to see where it is, * but may be eliminated by min_area option */ if ( Points->n_points < 4 ) G_warning ( "Degenerate polygon (%d vertices).", Points->n_points ); size = G_area_of_polygon(Points->x, Points->y, Points->n_points); if ( size < min_area ) { G_warning ( "Area size %.1e, area not imported.", size); return 0; } if ( type & GV_LINE ) otype = GV_LINE; else otype = GV_BOUNDARY; Vect_write_line ( Map, otype, Points, BCats); /* Isles */ IPoints = (struct line_pnts **) G_malloc ( (nr-1) * sizeof (struct line_pnts *) ); for( i = 1; i < nr; i++ ) { G_debug (3, "Inner ring %d", i ); IPoints[i-1] = Vect_new_line_struct (); hRing = OGR_G_GetGeometryRef( hGeom, i ); np = OGR_G_GetPointCount(hRing); for( j = 0; j < np; j++ ) { Vect_append_point ( IPoints[i-1], OGR_G_GetX(hRing,j), OGR_G_GetY(hRing,j), OGR_G_GetZ(hRing,j) ); } if ( IPoints[i-1]->n_points < 4 ) G_warning ( "Degenerate island (%d vertices).", IPoints[i-1]->n_points ); size = G_area_of_polygon(Points->x, Points->y, Points->n_points); if ( size < min_area ) { G_warning ( "Island size %.1e, island not imported.", size); } else { if ( type & GV_LINE ) otype = GV_LINE; else otype = GV_BOUNDARY; Vect_write_line ( Map, otype, IPoints[i-1], BCats); } } /* Centroid */ /* Vect_get_point_in_poly_isl() would fail for degenerate polygon */ if ( mk_centr ) { if ( Points->n_points >= 4 ) { ret = Vect_get_point_in_poly_isl ( Points, IPoints, nr-1, &x, &y); if ( ret == -1 ) { G_warning ( "Cannot calculate centroid" ); } else { Vect_reset_line ( Points ); Vect_append_point ( Points, x, y, 0.0 ); if ( type & GV_POINT ) otype = GV_POINT; else otype = GV_CENTROID; Vect_write_line ( Map, otype, Points, Cats); } } else if ( Points->n_points > 0 ) { if ( Points->n_points >= 2 ) { /* center of 1. segment ( 2. point is not best for 3 vertices as 3. may be the same as 1.) */ x = (Points->x[0] + Points->x[1]) / 2; y = (Points->y[0] + Points->y[1]) / 2; } else { /* one point */ x = Points->x[0]; y = Points->y[0]; } Vect_reset_line ( Points ); Vect_append_point ( Points, x, y, 0.0 ); if ( type & GV_POINT ) otype = GV_POINT; else otype = GV_CENTROID; Vect_write_line ( Map, otype, Points, Cats); } else { /* 0 points */ G_warning ( "No centroid written for polygon with 0 vertices." ); } } for( i = 1; i < nr; i++ ) { Vect_destroy_line_struct ( IPoints[i-1] ); } G_free ( IPoints ); } /* I did not test this because I did not have files of these types */ else if( eType == wkbGeometryCollection || eType == wkbMultiPolygon || eType == wkbMultiLineString || eType == wkbMultiPoint ) { G_debug (3, "GeometryCollection or MultiPolygon/LineString/Point" ); nr = OGR_G_GetGeometryCount( hGeom ); for( i = 0; i < nr; i++ ) { hRing = OGR_G_GetGeometryRef( hGeom, i ); ret = geom( hRing, Map, field, cat, min_area, type, mk_centr ); if ( ret == -1 ) { G_warning ("Cannot write part of geometry" ); } } } else { G_fatal_error ("Unknown geometry type"); } return 0; }