[postgis-users] Added support for query conditions and specifying geom type to pgsql2shp
Vinko Vrsalovic
vinko at cprsig.cl
Mon Sep 15 11:09:34 PDT 2003
Hi,
I added support for query conditions with -c flag:
pgsql2shp -f filename -u user -c 'type = 0' database table
and also to force a specific geometry type (present in the
table) with -t flag:
pgsql2shp -f filename -u user -c 'type = 0' -t MULITPOINT database table
Beware of the -t option, if you pass [MULTI]POINT to a resultset of
POLYGONS or LINES, the shplib function crashes with segmentation
fault, but if you know what you're doing (ie, you're sure what
the resultset is going to have) this shouldn't be a problem.
HTHS,
--
Vinko Vrsalovic <el[|- at -|]vinko.cl>
http://www.cprsig.cl
-------------- next part --------------
//compile line for Refractions' Solaris machine...
//gcc -g -I/data3/postgresql-7.1.2/include -L/data3/postgresql-7.1.2/lib dump.c ../shapelib-1.2.8/shpopen.o ../shapelib-1.2.8/dbfopen.o -o dump -lpq
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "libpq-fe.h"
#include "shapefil.h"
#include "getopt.h"
static void exit_nicely(PGconn *conn){
PQfinish(conn);
exit(1);
}
int create_lines(char *str,int shape_id, SHPHandle shp,int dims);
int create_multilines(char *str,int shape_id, SHPHandle shp,int dims);
int create_points(char *str,SHPHandle shp,int dims);
int create_multipoints(char *str, SHPHandle shp,int dims);
int create_polygons(char *str,int shape_id, SHPHandle shp,int dims);
int create_multipolygons(char *str,int shape_id, SHPHandle shp,int dims);
int parse_points(char *str, int num_points, double *x,double *y,double *z);
int num_points(char *str);
int num_lines(char *str);
char *scan_to_same_level(char *str);
int points_per_sublist( char *str, int *npoints, long max_lists);
//main
//USAGE: pgsql2shp [<options>] <database> <table>
//OPTIONS:
// -d Set the dump file to 3 dimensions, if this option is not used
// all dumping will be 2d only.
// -f <filename> Use this option to specify the name of the file
// to create.
// -h <host> Allows you to specify connection to a database on a
// machine other than the localhost.
// -p <port> Allows you to specify a database port other than 5432.
// -P <password> Connect to the database with the specified password.
// -u <user> Connect to the database as the specified user.
// -g <geometry_column> Specify the geometry column to be exported.
int main(int ARGC, char **ARGV){
char *pghost,*pgport,*pgoptions,*dbName,*pgpass,
*query,*query1,*geo_str,*geo_str_left,
*geo_col_name,*geo_OID,*geo_type,
conn_string[512],field_name[32],table_OID[16],
*shp_file,*pguser, *table, *condition;
int nFields, is3d, c, errflg, curindex;
int i,j,type,size,flds;
int type_ary[256];
int OID,geovalue_field;
int found;
DBFHandle dbf;
SHPHandle shp;
PGconn *conn;
PGresult *res,*res2,*res3;
table = NULL;
geo_col_name = NULL;
geo_str = NULL;
geo_type = NULL;
dbName = NULL;
pghost = NULL;
shp_file = NULL;
pgport = NULL;
condition = NULL;
geovalue_field = -1;
pguser = "";
pgpass = "";
is3d = 0;
errflg = 0;
found = 0;
OID = 0;
while ((c = getopt(ARGC, ARGV, "f:h:du:p:P:g:c:t:")) != EOF){
switch (c) {
case 'f':
shp_file = optarg;
break;
case 'h':
pghost=optarg;
break;
case 'd':
is3d = 1;
break;
case 'u':
pguser = optarg;
break;
case 'p':
pgport = optarg;
break;
case 'P':
pgpass = optarg;
break;
case 'g':
geo_col_name = optarg;
break;
case 'c':
condition = optarg;
break;
case 't':
geo_type = optarg;
break;
case '?':
errflg=1;
}
}
curindex=0;
for ( ; optind < ARGC; optind++){
if(curindex ==0){
dbName = ARGV[optind];
}else if(curindex == 1){
table = ARGV[optind];
}
curindex++;
}
if(curindex != 2){
errflg = 1;
}
if (errflg==1) {
printf("\n**ERROR** invalid option or command parameters\n");
printf("\n");
printf("USAGE: pgsql2shp [<options>] <database> <table>\n");
printf("\n");
printf("OPTIONS:\n");
printf(" -d Set the dump file to 3 dimensions, if this option is not used\n");
printf(" all dumping will be 2d only.\n");
printf(" -f <filename> Use this option to specify the name of the file\n");
printf(" to create.\n");
printf(" -h <host> Allows you to specify connection to a database on a\n");
printf(" machine other than the localhost.\n");
printf(" -p <port> Allows you to specify a database port other than 5432.\n");
printf(" -P <password> Connect to the database with the specified password.\n");
printf(" -u <user> Connect to the database as the specified user.\n");
printf(" -g <geometry_column> Specify the geometry column to be exported.\n");
printf(" -c <condition> Specify a query condition to the export.\n");
printf(" -t <type> Specify the geometry type.\n");
printf("\n");
exit (2);
}
if(shp_file == NULL){
shp_file = malloc(strlen(table) + 1);
strcpy(shp_file,table);
}
if(pgport == NULL){
pgport = "5432";
}
if(pghost == NULL){
pghost = "localhost";
}
if(strcmp(pgpass,"")==0 && strcmp(pguser,"")==0){
pgoptions = malloc(1);
strcpy(pgoptions,"");
}else{
pgoptions = malloc(strlen(pguser) + strlen(pgpass) + 20);
if(strcmp(pguser,"")!=0){
strcpy(pgoptions,"user=");
strcat(pgoptions,pguser);
}
if(strcmp(pgpass,"") !=0 ){
strcat(pgoptions," password=");
strcat(pgoptions,pgpass);
}
}
printf(conn_string);
/* make a connection to the specified database */
sprintf(conn_string,"host=%s %s port=%s dbname=%s",pghost,pgoptions,pgport,dbName);
conn = PQconnectdb( conn_string );
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
fprintf(stderr, "%s", PQerrorMessage(conn));
exit_nicely(conn);
}
#ifdef DEBUG
debug = fopen("/tmp/trace.out", "w");
PQtrace(conn, debug);
#endif /* DEBUG */
//------------------------------------------------------------
//Get the OID of the geometry type
query1 = (char *)malloc(strlen("select OID, typname from pg_type where typname = 'geometry';")+2);
strcpy(query1,"select OID, typname from pg_type where typname = 'geometry';");
res = PQexec(conn, query1);
// printf("OID query result: %s\n",PQresultErrorMessage(res));
free (query1);
if(PQntuples(res) > 0 ){
char *temp_int = (char *)PQgetvalue(res, 0, 0);
OID = atoi(temp_int);
}else{
printf("Cannot determine geometry type OID, Data-Dump Failed.");
exit_nicely(conn);
}
PQclear(res);
//------------------------------------------------------------
//Get the table from the DB
if (condition != NULL) {
query= (char *)malloc(strlen(table) + strlen("select * from ") + strlen(condition) + strlen(" WHERE ") + 4);
strcpy(query, "select * from ") ;
strcat(query, table);
strcat(query, " WHERE ");
strcat(query,condition);
} else {
query= (char *)malloc(strlen(table) + strlen("select * from ") + 2);
strcpy(query, "select * from ") ;
strcat(query, table);
}
// printf("%s\n",query);
res = PQexec(conn, query);
if(PQntuples(res) > 0 ){
}else{
printf("Invalid table: '%s' (check spelling and existance of >0 tuples).\nData-Dump Failed.",table);
exit_nicely(conn);
}
//printf("Select * query result: %s\n",PQresultErrorMessage(res));
free (query);
//------------------------------------------------------------
//Create the dbf file
dbf = DBFCreate(shp_file);
if(dbf == NULL){
printf("DBF could not be created - Dump FAILED.");
exit_nicely(conn);
}
// add the fields to the DBF
nFields = PQnfields(res);
flds =0; //keep track of how many fields you have actually created
for (i = 0; i < nFields; i++){
if(strlen(PQfname(res, i)) <32){
strcpy(field_name, PQfname(res, i));
}else{
printf("field name %s is too long, must be less than 32 characters.\n",PQfname(res, i));
exit_nicely(conn);
}
for(j=0;j<i;j++){ //make sure the fields all have unique names, 10-digit limit on dbf names...
if(strncmp(field_name, PQfname(res, j),10) == 0){
printf("\nWarning: Field '%s' has first 10 characters which duplicate a previous field name's.\nRenaming it to be: '",field_name);
strncpy(field_name,field_name,9);
field_name[9] = 0;
sprintf(field_name,"%s%d",field_name,i);
printf("%s'\n\n",field_name);
}
}
type = PQftype(res,i);
size = PQfsize(res,i);
if(type == 1082){ //date field, which we store as a string so we need more width in the column
size = 10;
}
if(size==-1 && type != OID){ //-1 represents variable size in postgres, this should not occur, but use 32 bytes in case it does
//( this is ugly: don't forget counting the length
// when changing the fixed query strings )
query1 = (char *)malloc(
24+strlen(PQfname(res, i))+8+strlen(table)+1 );
strncpy(query1,"select max(octet_length(",24+1);
strcat(query1,PQfname(res, i));
strncat(query1,")) from ",8);
strcat(query1,table);
res2 = PQexec(conn, query1);
free(query1);
if(PQntuples(res2) > 0 ){
char *temp_int = (char *)PQgetvalue(res2, 0, 0);
size = atoi(temp_int);
}else{
size = 32;
}
}
if(type == 20 || type == 21 || type == 22 || type == 23){
if(DBFAddField(dbf, field_name,FTInteger,16,0) == -1)printf("error - Field could not be created.\n");
type_ary[i]=1;
flds++;
}else if(type == 700 || type == 701){
if(DBFAddField(dbf, field_name,FTDouble,32,10) == -1)printf("error - Field could not be created.\n");
type_ary[i]=2;
flds++;
}else if(type == OID){
if( geovalue_field == -1){
geovalue_field = i;
flds++;
}else if(geo_col_name != NULL && !strcasecmp(geo_col_name, field_name)){
geovalue_field = i;
}
type_ary[i]=9; //the geometry type field
}else{
if(DBFAddField(dbf, field_name,FTString,size,0) == -1)printf("error - Field could not be created.\n");
type_ary[i]=3;
flds++;
}
}
/* next, print out the instances */
for (i = 0; i < PQntuples(res); i++)
{
if(i%50 ==1){
printf("DBF tuple - %d added\n",i);
}
flds = 0;
for (j = 0; j < nFields; j++){
if(type_ary[j] == 1){
char *temp_int = (char *)PQgetvalue(res, i, j);
int temp = atoi(temp_int);
if(DBFWriteIntegerAttribute(dbf, i, flds,temp)== 0)printf("error(int) - Record could not be created\n");
flds++;
}else if(type_ary[j] == 2){
char *temp_dbl = PQgetvalue(res, i, j);
double temp = atof(temp_dbl);
if(DBFWriteDoubleAttribute( dbf, i, flds,temp)== 0)printf("error(double) - Record could not be created\n");
flds++;
}else if(type_ary[j] == 9){
//this is the geometry type field, would do all the .shp and .shx stuff here i imagine
}else{
char *temp = (char *)malloc(strlen(PQgetvalue(res, i, j))*8);
temp = (char *)PQgetvalue(res, i, j);
if(DBFWriteStringAttribute( dbf, i, flds,temp)== 0)printf("error(string) - Record could not be created\n");
flds++;
}
}
}
printf("DBF tuple - %d added\n",i);
if(flds==0){
printf("WARNING: There were no fields in the database. The DBF was not created properly, please add a field to the database and try again.");
}
DBFClose(dbf);
//--------------------------------------------------------------------
//Now parse the geo_value (All your base belong to us. For great justice.)
//field into the shx and shp files
query= (char *)malloc(strlen("select OID from pg_class where relname = ' '")+strlen(table)+2);
strcpy(query, "select OID from pg_class where relname = '") ;
strcat(query, table);
strcat(query, "'");
res3 = PQexec(conn, query);
if(PQntuples(res3) == 1 ){
strncpy(table_OID, (PQgetvalue(res3, 0,0)), 15 );
}else if(PQntuples(res3) == 0 ){
printf("ERROR: Cannot determine relation OID.\n");
exit_nicely(conn);
}else{
strncpy(table_OID, (PQgetvalue(res3, 0,0)), 15 );
printf("Warning: Multiple relations detected, the program will only dump the first relation.\n");
}
//get the geometry column
if(geo_col_name == NULL){
query= (char *)malloc(strlen("select attname from pg_attribute where attrelid = and atttypid = ")+38);
strcpy(query, "select attname from pg_attribute where attrelid = ");
strcat(query, table_OID);
strcat(query, " and atttypid = ");
geo_OID = (char *)malloc(34);
sprintf(geo_OID, "%i", OID);
strcat(query, geo_OID );
}else{
query = (char *)malloc(strlen("select attname from pg_attribute where attrelid = and atttypid = ")+
strlen("and attname = ''")+strlen(geo_col_name)+38);
strcpy(query, "select attname from pg_attribute where attrelid = ");
strcat(query, table_OID);
strcat(query, " and atttypid = ");
geo_OID = (char *)malloc(34);
sprintf(geo_OID, "%i", OID);
strcat(query, geo_OID );
strcat(query, " and attname = '");
strcat(query, geo_col_name);
strcat(query, "'");
}
res3 = PQexec(conn, query);
if(PQntuples(res3) == 1 ){
geo_col_name = (char *)malloc(strlen(PQgetvalue(res3, 0,0)) +2 );
geo_col_name = PQgetvalue(res3,0,0);
}else if(PQntuples(res3) == 0 ){
if(geo_col_name == NULL){
printf("ERROR: Cannot determine name of geometry column.\n");
}else{
printf("ERROR: Wrong geometry column name.\n");
}
exit_nicely(conn);
}else{
geo_col_name = (char *)malloc(strlen(PQgetvalue(res3, 0,0)) +2 );
geo_col_name = PQgetvalue(res3,0,0);
printf("Warning: Multiple geometry columns detected, the program will only dump the first geometry.\n");
}
//get what kind of Geometry type is in the table
query= (char *)malloc(strlen(table) + strlen("select distinct (geometrytype()) from ")+18);
strcpy(query, "select distinct (geometrytype(");
strcat(query, geo_col_name);
strcat(query, ")) from ") ;
strcat(query, table);
res3 = PQexec(conn, query);
if (geo_type == NULL) {
if(PQntuples(res3) == 1) {
geo_str = (char *)malloc(strlen(PQgetvalue(res3, 0, 0))+1);
memcpy(geo_str, (char *)PQgetvalue(res3, 0, 0),strlen(PQgetvalue(res3,0,0))+1);
}else if(PQntuples(res3) > 1){
printf("ERROR: Cannot have multiple geometry types in a shapefile.\nUse option -t to specify what type of geometry you want dumped\n\n");
exit_nicely(conn);
}else{
printf("ERROR: Cannot determine geometry type of table. \n");
exit_nicely(conn);
}
} else {
for (i=0;i<PQntuples(res3);i++) {
if (strncmp(PQgetvalue(res3,i,0),geo_type,8) == 0) {
found = 1;
}
}
if (!found) {
printf("ERROR: Specified geometry type (%s) is not present in the specified table (%s)\n\n",geo_type,table);
exit_nicely(conn);
}
geo_str = (char *) malloc(strlen(geo_type)+1);
strcpy(geo_str,geo_type);
}
geo_str_left = (char *)malloc(10);
strncpy(geo_str_left,geo_str,8);
free(geo_str);
if(strncmp(geo_str_left,"MULTILIN",8)==0 ){
//multilinestring ---------------------------------------------------
if(is3d == 0){
shp = SHPCreate(shp_file, SHPT_ARC );//2d line shp file
}else{
shp = SHPCreate(shp_file, SHPT_ARCZ );//3d line shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_multilines(geo_str,i,shp,is3d) ==0){
printf("Error writing multiline to shape file");
}
if(i%50 ==1){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else if (strncmp(geo_str_left,"LINESTRI",8)==0 ){
//linestring---------------------------------------------------
if(is3d==0){
shp = SHPCreate(shp_file, SHPT_ARC );//2d lines shp file
}else{
shp = SHPCreate(shp_file, SHPT_ARCZ );//3d lines shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_lines(geo_str,i,shp,is3d) ==0){
printf("Error writing line to shape file");
}
if(i%100 ==0){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else if (strncmp(geo_str_left,"POLYGON",7)==0 ){
//Polygon---------------------------------------------------
if(is3d==0){
shp = SHPCreate(shp_file, SHPT_POLYGON );//2d lines shp file
}else{
shp = SHPCreate(shp_file, SHPT_POLYGONZ );//3d lines shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_polygons(geo_str,i,shp,is3d) == 0){
printf("Error writing polygon to shape file");
}
if(i%100 == 0){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else if(strncmp(geo_str_left,"MULTIPOL",8)==0 ){
//multipolygon---------------------------------------------------
if(is3d==0){
shp = SHPCreate(shp_file, SHPT_POLYGON );//2d polygon shp file
}else{
shp = SHPCreate(shp_file, SHPT_POLYGONZ );//3d polygon shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_multipolygons(geo_str,i,shp,is3d) == 0){
printf("Error writing polygon to shape file");
}
if(i%100 == 0){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else if(strncmp(geo_str_left,"POINT",5)==0 ){
//point---------------------------------------------------
if(is3d==0){
shp = SHPCreate(shp_file, SHPT_POINT );//2d point shp file
}else{
shp = SHPCreate(shp_file, SHPT_POINTZ );//3d point shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_points(geo_str,shp,is3d) ==0){
printf("Error writing line to shape file");
}
if(i%100 ==0){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else if(strncmp(geo_str_left,"MULTIPOI",8)==0 ){
//multipoint---------------------------------------------------
if(is3d==0){
shp = SHPCreate(shp_file, SHPT_MULTIPOINT );//2d point shp file
}else{
shp = SHPCreate(shp_file, SHPT_MULTIPOINTZ );//3d point shp file
}
for(i=0;i<PQntuples(res);i++){
geo_str = (char *)malloc(strlen(PQgetvalue(res, i, geovalue_field))+1);
memcpy(geo_str, (char *)PQgetvalue(res, i, geovalue_field),strlen(PQgetvalue(res, i, geovalue_field))+1);
if(create_multipoints(geo_str,shp,is3d) ==0){
printf("Error writing line to shape file");
}
if(i%100 ==0){
printf("shape - %d added\n",i);
}
free(geo_str);
}
printf("shape - %d added\n",i);
}else{
printf("type '%s' is not Supported at this time.\nThe DBF file has been created but not the shx or shp files.\n",geo_str_left);
shp = NULL;
}
if(shp != NULL){
SHPClose( shp );
}
free(geo_str_left);
PQclear(res);
/* close the connection to the database and cleanup */
PQfinish(conn);
#ifdef DEBUG
fclose(debug);
#endif /* DEBUG */
return 0;
}
//reads points into x,y,z co-ord arrays
int parse_points(char *str, int num_points, double *x,double *y,double *z){
int keep_going;
int num_found= 0;
char *end_of_double;
if ( (str == NULL) || (str[0] == 0) ){
return 0; //either null string or empty string
}
//look ahead for the "("
str = strchr(str,'(') ;
if ( (str == NULL) || (str[1] == 0) ){ // str[0] = '(';
return 0; //either didnt find "(" or its at the end of the string
}
str++; //move forward one char
keep_going = 1;
while (keep_going == 1){
//attempt to get the point
//scanf is slow, so we use strtod()
x[num_found] = (double)strtod(str,&end_of_double);
if (end_of_double == str){
return 0; //error occured (nothing parsed)
}
str = end_of_double;
y[num_found] = strtod(str,&end_of_double);
if (end_of_double == str){
return 0; //error occured (nothing parsed)
}
str = end_of_double;
z[num_found] = strtod(str,&end_of_double); //will be zero if error occured
str = end_of_double;
num_found++;
str=strpbrk(str,",)"); // look for a "," or ")"
if (str != NULL && str[0] == ','){
str++;
}
keep_going = (str != NULL) && (str[0] != ')');
}
return num_found;
}
//returns how many points are in the first list in str
//
// 1. scan ahead looking for "("
// 2. find "," until hit a ")"
// 3. return number of points found
//
// NOTE: doesnt actually parse the points, so if the
// str contains an invalid geometry, this could give
// back the wrong answer.
//
// "(1 2 3, 4 5 6),(7 8, 9 10, 11 12 13)" => 2 (2nd list is not included)
int num_points(char *str){
int keep_going;
int points_found = 1; //no "," if only one point (and last point)
if ( (str == NULL) || (str[0] == 0) )
{
return 0; //either null string or empty string
}
//look ahead for the "("
str = strchr(str,'(') ;
if ( (str == NULL) || (str[1] == 0) ) // str[0] = '(';
{
return 0; //either didnt find "(" or its at the end of the string
}
keep_going = 1;
while (keep_going)
{
str=strpbrk(str,",)"); // look for a "," or ")"
keep_going = (str != NULL);
if (keep_going) // found a , or )
{
if (str[0] == ')')
{
//finished
return points_found;
}
else //str[0] = ","
{
points_found++;
str++; //move 1 char forward
}
}
}
return points_found; // technically it should return an error.
}
//number of sublist in a string.
// Find the number of lines in a Multiline
// OR
// The number of rings in a Polygon
// OR
// The number of polygons in a multipolygon
// ( (..),(..),(..) ) -> 3
// ( ( (..),(..) ), ( (..) )) -> 2
// ( ) -> 0
// scan through the list, for every "(", depth (nesting) increases by 1
// for every ")", depth (nesting) decreases by 1
// if find a "(" at depth 1, then there is a sub list
//
// example:
// "(((..),(..)),((..)))"
//depth 12333223332112333210
// + + increase here
int num_lines(char *str){
int current_depth = 0;
int numb_lists = 0;
while ( (str != NULL) && (str[0] != 0) )
{
str=strpbrk(str,"()"); //look for "(" or ")"
if (str != NULL)
{
if (str[0] == '(')
{
current_depth++;
if (current_depth == 2)
numb_lists ++;
}
if (str[0] == ')')
{
current_depth--;
if (current_depth == 0)
return numb_lists ;
}
str++;
}
}
return numb_lists ; // probably should give an error
}
//simple scan-forward to find the next "(" at the same level
// ( (), (),(), ),(...
// + return this location
char *scan_to_same_level(char *str){
//scan forward in string looking for at "(" at the same level
// as the one its already pointing at
int current_depth = 0;
int first_one=1;
while ( (str != NULL) && (str[0] != 0) )
{
str=strpbrk(str,"()");
if (str != NULL)
{
if (str[0] == '(')
{
if (!(first_one))
{
if (current_depth == 0)
return str;
}
else
first_one = 0; //ignore the first opening "("
current_depth++;
}
if (str[0] == ')')
{
current_depth--;
}
str++;
}
}
return str ; // probably should give an error
}
// Find out how many points are in each sublist, put the result in the array npoints[]
// (for at most max_list sublists)
//
// ( (L1),(L2),(L3) ) --> npoints[0] = points in L1,
// npoints[1] = points in L2,
// npoints[2] = points in L3
//
// We find these by, again, scanning through str looking for "(" and ")"
// to determine the current depth. We dont actually parse the points.
int points_per_sublist( char *str, int *npoints, long max_lists){
//scan through, noting depth and ","s
int current_depth = 0;
int current_list =-1 ;
while ( (str != NULL) && (str[0] != 0) )
{
str=strpbrk(str,"(),"); //find "(" or ")" or ","
if (str != NULL)
{
if (str[0] == '(')
{
current_depth++;
if (current_depth == 2)
{
current_list ++;
if (current_list >=max_lists)
return 1; // too many sub lists found
npoints[current_list] = 1;
}
// might want to return an error if depth>2
}
if (str[0] == ')')
{
current_depth--;
if (current_depth == 0)
return 1 ;
}
if (str[0] == ',')
{
if (current_depth==2)
{
npoints[current_list] ++;
}
}
str++;
}
}
return 1 ; // probably should give an error
}
int create_multilines(char *str,int shape_id, SHPHandle shp,int dims){
int lines,i,j,max_points,index;
int *points;
int *part_index;
double *x;
double *y;
double *z;
double *totx;
double *toty;
double *totz;
SHPObject *obj;
lines = num_lines(str);
points = (int *)malloc(sizeof(int) * lines);
if(points_per_sublist(str, points, lines) ==0){
printf("error - points_per_sublist failed");
}
max_points = 0;
for(j=0;j<lines;j++){
max_points += points[j];
}
part_index = (int *)malloc(sizeof(int) * lines);
totx = (double *)malloc(sizeof(double) * max_points);
toty = (double *)malloc(sizeof(double) * max_points);
totz = (double *)malloc(sizeof(double) * max_points);
index=0;
for(i=0;i<lines;i++){
str = strchr(str,'(') ;
if(str[0] =='(' && str[1] == '('){
str++;
}
x = (double *)malloc(sizeof(double) * points[i]);
y = (double *)malloc(sizeof(double) * points[i]);
z = (double *)malloc(sizeof(double) * points[i]);
parse_points(str,points[i],x,y,z);
str = scan_to_same_level(str);
part_index[i] = index;
for(j=0;j<points[i];j++){
totx[index] = x[j];
toty[index] = y[j];
totz[index] = z[j];
index++;
}
free(x);
free(y);
free(z);
}
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateObject(SHPT_ARC,shape_id,lines,part_index,NULL,max_points,totx,toty,totz,NULL);
}else{
obj = SHPCreateObject(SHPT_ARCZ,shape_id,lines,part_index,NULL,max_points,totx,toty,totz,NULL);
}
free(part_index);
free(points);
free(totx);
free(toty);
free(totz);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
int create_lines(char *str,int shape_id, SHPHandle shp,int dims){
int points;
int *part_index;
double *x,
*y,
*z;
SHPObject *obj;
part_index = (int *)malloc(sizeof(int)); //we know lines only have 1 part so make the array of size 1
part_index[0] = 0;
points = num_points(str);
x = (double *)malloc(sizeof(double) * points);
y = (double *)malloc(sizeof(double) * points);
z = (double *)malloc(sizeof(double) * points);
parse_points(str,points,x,y,z);
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateObject(SHPT_ARC,shape_id,1,part_index,NULL,points,x,y,z,NULL);
}else{
obj = SHPCreateObject(SHPT_ARCZ,shape_id,1,part_index,NULL,points,x,y,z,NULL);
}
free(part_index);
free(x);
free(y);
free(z);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
int create_points(char *str, SHPHandle shp,int dims){
double *x,
*y,
*z;
SHPObject *obj;
x = (double *)malloc(sizeof(double));
y = (double *)malloc(sizeof(double));
z = (double *)malloc(sizeof(double));
parse_points(str,1,x,y,z);
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateSimpleObject(SHPT_POINT,1,x,y,z);
}else{
obj = SHPCreateSimpleObject(SHPT_POINTZ,1,x,y,z);
}
free(x);
free(y);
free(z);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
int create_multipoints(char *str, SHPHandle shp,int dims){
int points;
double *x,
*y,
*z;
SHPObject *obj;
points = num_points(str);
x = (double *)malloc(sizeof(double)*points);
y = (double *)malloc(sizeof(double)*points);
z = (double *)malloc(sizeof(double)*points);
parse_points(str,points,x,y,z);
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateSimpleObject(SHPT_MULTIPOINT ,1,x,y,z);
}else{
obj = SHPCreateSimpleObject(SHPT_MULTIPOINTZ ,1,x,y,z);
}
free(x);
free(y);
free(z);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
int create_polygons(char *str,int shape_id, SHPHandle shp,int dims){
int rings,i,j,max_points,index;
int *points;
int *part_index;
double *x;
double *y;
double *z;
double *totx;
double *toty;
double *totz;
SHPObject *obj;
rings = num_lines(str); //the number of rings in the polygon
points = (int *)malloc(sizeof(int) * rings);
if(points_per_sublist(str, points, rings) ==0){
printf("error - points_per_sublist failed");
}
max_points = 0;
for(j=0;j<rings;j++){
max_points += points[j];
}
part_index = (int *)malloc(sizeof(int) * rings);
totx = (double *)malloc(sizeof(double) * max_points);
toty = (double *)malloc(sizeof(double) * max_points);
totz = (double *)malloc(sizeof(double) * max_points);
index=0;
for(i=0;i<rings;i++){
str = strchr(str,'(') ;
if(str[0] =='(' && str[1] == '('){
str++;
}
x = (double *)malloc(sizeof(double) * points[i]);
y = (double *)malloc(sizeof(double) * points[i]);
z = (double *)malloc(sizeof(double) * points[i]);
parse_points(str,points[i],x,y,z);
str = scan_to_same_level(str);
part_index[i] = index;
for(j=0;j<points[i];j++){
totx[index] = x[j];
toty[index] = y[j];
totz[index] = z[j];
index++;
}
free(x);
free(y);
free(z);
}
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateObject(SHPT_POLYGON,shape_id,rings,part_index,NULL,max_points,totx,toty,totz,NULL);
}else{
obj = SHPCreateObject(SHPT_POLYGONZ,shape_id,rings,part_index,NULL,max_points,totx,toty,totz,NULL);
}
free(part_index);
free(points);
free(totx);
free(toty);
free(totz);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
int create_multipolygons(char *str,int shape_id, SHPHandle shp,int dims){
int polys,rings,i,j,k,max_points;
int index,indexk,index2part,tot_rings,final_max_points;
int *points;
int *part_index;
int *final_part_index;
char *temp;
char *temp_addr;
double *x;
double *y;
double *z;
double *totx;
double *toty;
double *totz;
double *finalx;
double *finaly;
double *finalz;
SHPObject *obj;
points=0;
polys = num_lines(str); //the number of rings in the polygon
final_max_points =0;
temp_addr = (char *)malloc(strlen(str) +1 );
temp = temp_addr; //keep original pointer to free the mem later
strcpy(temp,str);
tot_rings=0;
index2part=0;
indexk=0;
for(i=0;i<polys;i++){
temp = strstr(temp,"((") ;
if(temp[0] =='(' && temp[1] == '(' && temp[2] =='('){
temp++;
}
rings = num_lines(temp);
points = (int *)malloc(sizeof(int) * rings);
points_per_sublist(temp, points, rings);
tot_rings += rings;
for(j=0;j<rings;j++){
final_max_points += points[j];
}
temp+= 2;
}
free(points);
temp= temp_addr;
final_part_index = (int *)malloc(sizeof(int) * tot_rings);
finalx = (double *)malloc(sizeof(double) * final_max_points);
finaly = (double *)malloc(sizeof(double) * final_max_points);
finalz = (double *)malloc(sizeof(double) * final_max_points);
for(k=0;k<polys ; k++){ //for each polygon
str = strstr(str,"((") ;
if(strlen(str) >2 && str[0] =='(' && str[1] == '(' && str[2] =='('){
str++;
}
rings = num_lines(str);
points = (int *)malloc(sizeof(int) * rings);
if(points_per_sublist(str, points, rings) ==0){
printf("error - points_per_sublist failed");
}
max_points = 0;
for(j=0;j<rings;j++){
max_points += points[j];
}
part_index = (int *)malloc(sizeof(int) * rings);
totx = (double *)malloc(sizeof(double) * max_points);
toty = (double *)malloc(sizeof(double) * max_points);
totz = (double *)malloc(sizeof(double) * max_points);
index=0;
for(i=0;i<rings;i++){
str = strchr(str,'(') ;
if(str[0] =='(' && str[1] == '('){
str++;
}
x = (double *)malloc(sizeof(double) * points[i]);
y = (double *)malloc(sizeof(double) * points[i]);
z = (double *)malloc(sizeof(double) * points[i]);
parse_points(str,points[i],x,y,z);
str = scan_to_same_level(str);
part_index[i] = index;
for(j=0;j<points[i];j++){
totx[index] = x[j];
toty[index] = y[j];
totz[index] = z[j];
index++;
}
free(x);
free(y);
free(z);
}
for(j=0;j<i;j++){
final_part_index[index2part] = part_index[j]+indexk ;
index2part++;
}
for(j=0;j<index;j++){
finalx[indexk] = totx[j];
finaly[indexk] = toty[j];
finalz[indexk] = totz[j];
indexk++;
}
free(points);
free(part_index);
free(totx);
free(toty);
free(totz);
str -= 1;
}//end for (k...
obj = (SHPObject *)malloc(sizeof(SHPObject));
if(dims == 0){
obj = SHPCreateObject(SHPT_POLYGON,shape_id,tot_rings,final_part_index,NULL,final_max_points,finalx,finaly,finalz,NULL);
}else{
obj = SHPCreateObject(SHPT_POLYGONZ,shape_id,tot_rings,final_part_index,NULL,final_max_points,finalx,finaly,finalz,NULL);
}
free(final_part_index);
free(finalx);
free(finaly);
free(finalz);
if(SHPWriteObject(shp,-1,obj)!= -1){
SHPDestroyObject(obj);
return 1;
}else{
SHPDestroyObject(obj);
return 0;
}
}
More information about the postgis-users
mailing list