[postgis-users] shp2pgsql Non-MULTI patch

Markus Schaber schabi at logix-tt.com
Thu Oct 5 03:10:58 PDT 2006


Hi,

Markus Schaber wrote:

> I attached a small and untested patch to add an -S option to shp2pgsql
> which makes LINESTRINGS and POLYGONS instead of the MULTI* geometries,
> and enforces this restriction.

Here's an updated patch that also corrects table creation, and the man page.


Please test.

If I don't hear any complaints the next days, I'll commit :-)

Markus


-- 
Markus Schaber | Logical Tracking&Tracing International AG
Dipl. Inf.     | Software Development GIS

Fight against software patents in Europe! www.ffii.org
www.nosoftwarepatents.org
-------------- next part --------------
Index: doc/man/shp2pgsql.1
===================================================================
--- doc/man/shp2pgsql.1	(revision 2497)
+++ doc/man/shp2pgsql.1	(working copy)
@@ -52,6 +52,13 @@
 Coerce all integers to standard 32\-bit integers, do not create 64\-bit bigints, even if the DBF header signature appears to warrant it.
 
 .TP 
+\fB\-S\fR
+Generate simple Geometries instead of MULTIgeometries. Shape files don't differ between LINESTRINGs
+and MULTILINESTRINGs, so shp2pgsql generates MULTILINESTRINGs by default. This switch will produce
+LINESTRINGs instead, but shp2pgsql will fail when it hits a real MULTILINESTRING. The same works
+for POLYGONs vs. MULTIPOLYGONs.
+
+.TP 
 \fB\-w\fR
 Output WKT format, for use with older (0.x) versions of PostGIS.
 Note that this will introduce coordinate drifts and will drop
Index: loader/shp2pgsql.c
===================================================================
--- loader/shp2pgsql.c	(revision 2497)
+++ loader/shp2pgsql.c	(working copy)
@@ -69,6 +69,7 @@
 
 /* globals */
 int	dump_format = 0; /* 0=insert statements, 1 = dump */
+int     simple_geometries = 0; /* 0 = MULTILINESTRING/MULTIPOLYGON, 1 = LINESTRING/POLYGON */
 int	quoteidentifiers = 0;
 int	forceint4 = 0;
 int	createindex = 0;
@@ -759,6 +760,8 @@
 	fprintf(stderr, "\n");
 	fprintf(stderr, "  -I  Create a GiST index on the geometry column.\n");
 	fprintf(stderr, "\n");
+	fprintf(stderr, "  -S  Generate simple geometries instead of MULTI geometries.\n");
+	fprintf(stderr, "\n");
 	fprintf(stderr, "  -w  Use wkt format (for postgis-0.x support - drops M - drifts coordinates).\n");
 #ifdef USE_ICONV
 	fprintf(stderr, "\n");
@@ -792,9 +795,17 @@
 	if (!dump_format) printf("'");
 	if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
 
-	print_wkb_byte(getEndianByte());
-	print_wkb_int(wkbtype);
-	print_wkb_int(obj->nParts);
+	if (simple_geometries==0) // We write MULTI geometries, so generate Header 
+	{
+		print_wkb_byte(getEndianByte());
+		print_wkb_int(wkbtype);
+		print_wkb_int(obj->nParts); /* npolys */
+	} 
+	else if ((obj->nParts)!=1) // We write Non-MULTI geometries, but have several parts: 
+	{
+		fprintf(stderr, "We have a MultiLineString with %d parts, can't use -S switch!\n", obj->nParts);
+		exit(1);		
+	}
 
 	for (pi=0; pi<obj->nParts; pi++)
 	{
@@ -845,6 +856,22 @@
 
 	if (dump_format) printf("SRID=%s;MULTILINESTRING(",sr_id);
 	else printf("GeometryFromText('MULTILINESTRING (");
+	
+	if (dump_format) printf("SRID=%s;",sr_id );
+	else printf("GeometryFromText('");
+	
+	if (simple_geometries==0) // We write MULTI geometries, so generate Header 
+	{
+		printf("MULTILINESTRING(");
+	} else if ((obj->nParts)==1)
+	{
+		printf("POLYGON");
+	}
+	else // We write Non-MULTI geometries, but have several parts: 
+	{
+		fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", obj->nParts);
+		exit(1);		
+	} 
 
 	for (pi=0; pi<obj->nParts; pi++)
 	{
@@ -874,8 +901,10 @@
 				
 	}
 
-	if (dump_format) printf(")\n");
-	else printf(")',%s) );\n",sr_id);
+	if (simple_geometries==0) printf(")");
+
+	if (dump_format) printf("\n");
+	else printf("',%s) );\n",sr_id);
 }
 
 int
@@ -1051,9 +1080,17 @@
 	if (!dump_format) printf("'");
 	if ( sr_id && sr_id != "-1" ) printf("SRID=%s;", sr_id);
 
-	print_wkb_byte(getEndianByte());
-	print_wkb_int(wkbtype);
-	print_wkb_int(out_index); /* npolys */
+	if (simple_geometries==0) // We write MULTI geometries, so generate Header 
+	{
+		print_wkb_byte(getEndianByte());
+		print_wkb_int(wkbtype);
+		print_wkb_int(out_index); /* npolys */
+	} 
+	else if (out_index!=1) // We write Non-MULTI geometries, but have several parts: 
+	{
+		fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", out_index);
+		exit(1);		
+	}
 
 	/* Write the coordinates */
 	for(pi=0; pi<out_index; pi++)
@@ -1112,8 +1149,22 @@
 
 	out_index = FindPolygons(obj, &Outer);
 
-	if (dump_format) printf("SRID=%s;MULTIPOLYGON(",sr_id );
-	else printf("GeometryFromText('MULTIPOLYGON(");
+	if (dump_format) printf("SRID=%s;",sr_id );
+	else printf("GeometryFromText('");
+	
+	if (simple_geometries==0) // We write MULTI geometries, so generate Header 
+	{
+		printf("MULTIPOLYGON(");
+	} 
+	else if (out_index==1) 
+	{
+		printf("POLYGON");
+	}
+	else
+	{ // We write Non-MULTI geometries, but have several parts: 
+		fprintf(stderr, "We have a Multipolygon with %d parts, can't use -S switch!\n", out_index);
+		exit(1);		
+	}
 
 	/* Write the coordinates */
 	for(pi=0; pi<out_index; pi++)
@@ -1149,8 +1200,10 @@
 
 	}
 
-	if (dump_format) printf(")\n");
-	else printf(")',%s) );\n",sr_id);
+	if (simple_geometries==0) printf(")");
+	
+	if (dump_format) printf("\n");
+	else printf("',%s) );\n",sr_id);
 
 	/* Release all memory */
 	ReleasePolygons(Outer, out_index);
@@ -1228,7 +1281,7 @@
 	extern char *optarg;
 	extern int optind;
 
-	while ((c = getopt(ARGC, ARGV, "kcdapDs:g:iW:wIN:")) != EOF){
+	while ((c = getopt(ARGC, ARGV, "kcdapDs:Sg:iW:wIN:")) != EOF){
                switch (c) {
                case 'c':
                     if (opt == ' ')
@@ -1257,6 +1310,9 @@
 	       case 'D':
 		    dump_format =1;
                     break;
+               case 'S':
+                    simple_geometries =1;
+                    break;
                case 's':
                     sr_id = optarg;
                     break;
@@ -1449,6 +1505,13 @@
 				shpfiletype);
 			break;
 	}
+
+        if (simple_geometries)
+        {
+                // adjust geometry name for CREATE TABLE by skipping MULTI
+                if ((wkbtype & 0x7) == MULTIPOLYGONTYPE) pgtype += 5;
+                if ((wkbtype & 0x7) == MULTILINETYPE) pgtype += 5;
+        }                        
 }
 
 char *