/src/shapelib/shputils.c
C | 1072 lines | 722 code | 93 blank | 257 comment | 260 complexity | cf071f7f1cc129205ccfe0f3de305ff9 MD5 | raw file
Possible License(s): LGPL-2.0
- /******************************************************************************
- * $Id: shputils.c,v 1.10 2007-12-13 19:59:23 fwarmerdam Exp $
- *
- * Project: Shapelib
- * Purpose:
- * Altered "shpdump" and "dbfdump" to allow two files to be appended.
- * Other Functions:
- * Selecting from the DBF before the write occurs.
- * Change the UNITS between Feet and Meters and Shift X,Y.
- * Clip and Erase boundary. The program only passes thru the
- * data once.
- *
- * Bill Miller North Carolina - Department of Transporation
- * Feb. 1997 -- bmiller@dot.state.nc.us
- * There was not a lot of time to debug hidden problems;
- * And the code is not very well organized or documented.
- * The clip/erase function was not well tested.
- * Oct. 2000 -- bmiller@dot.state.nc.us
- * Fixed the problem when select is using numbers
- * larger than short integer. It now reads long integer.
- * NOTE: DBF files created using windows NT will read as a string with
- * a length of 381 characters. This is a bug in "dbfopen".
- *
- *
- * Author: Bill Miller (bmiller@dot.state.nc.us)
- *
- ******************************************************************************
- * Copyright (c) 1999, Frank Warmerdam
- *
- * This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
- * option is discussed in more detail in shapelib.html.
- *
- * --
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- ******************************************************************************
- *
- * $Log: shputils.c,v $
- * Revision 1.10 2007-12-13 19:59:23 fwarmerdam
- * reindent code, avoid some warnings.
- *
- * Revision 1.9 2004/01/14 14:56:00 fwarmerdam
- * Some cleanlyness improvements.
- *
- * Revision 1.8 2004/01/14 14:40:22 fwarmerdam
- * Fixed exit() call to include code.
- *
- * Revision 1.7 2003/02/25 17:20:22 warmerda
- * Set psCShape to NULL after SHPDestroyObject() to avoid multi-frees of
- * the same memory ... as submitted by Fred Fox.
- *
- * Revision 1.6 2001/08/28 13:57:14 warmerda
- * fixed DBFAddField return value check
- *
- * Revision 1.5 2000/11/02 13:52:48 warmerda
- * major upgrade from Bill Miller
- *
- * Revision 1.4 1999/11/05 14:12:05 warmerda
- * updated license terms
- *
- * Revision 1.3 1998/12/03 15:47:39 warmerda
- * Did a bunch of rewriting to make it work with the V1.2 API.
- *
- * Revision 1.2 1998/06/18 01:19:49 warmerda
- * Made C++ compilable.
- *
- * Revision 1.1 1997/05/27 20:40:27 warmerda
- * Initial revision
- */
- #include "shapefil.h"
- #include "string.h"
- #include <stdlib.h>
- SHP_CVSID("$Id: shputils.c,v 1.10 2007-12-13 19:59:23 fwarmerdam Exp $")
- #ifndef FALSE
- # define FALSE 0
- # define TRUE 1
- #endif
- char infile[80], outfile[80], temp[400];
- /* Variables for shape files */
- SHPHandle hSHP;
- SHPHandle hSHPappend;
- int nShapeType, nEntities, iPart;
- int nShapeTypeAppend, nEntitiesAppend;
- SHPObject *psCShape;
- double adfBoundsMin[4], adfBoundsMax[4];
- /* Variables for DBF files */
- DBFHandle hDBF;
- DBFHandle hDBFappend;
-
- DBFFieldType iType;
- DBFFieldType jType;
-
- char iszTitle[12];
- char jszTitle[12];
- int *pt;
- char iszFormat[32], iszField[1024];
- char jszFormat[32], jszField[1024];
- int i, ti, iWidth, iDecimals, iRecord;
- int j, tj, jWidth, jDecimals, jRecord;
- int clip_boundary();
- double findunit(char *unit);
- void openfiles(void);
- void setext(char *pt, char *ext);
- int strncasecmp2(char *s1, char *s2, int n);
- void mergefields(void);
- void findselect(void);
- void showitems(void);
- int selectrec();
- void check_theme_bnd();
- int clip_boundary();
- void error();
- /* -------------------------------------------------------------------- */
- /* Variables for the DESCRIBE function */
- /* -------------------------------------------------------------------- */
- int ilist = FALSE, iall = FALSE;
- /* -------------------------------------------------------------------- */
- /* Variables for the SELECT function */
- /* -------------------------------------------------------------------- */
- int found = FALSE, newdbf = FALSE;
- char selectitem[40], *cpt;
- long int selectvalues[150], selcount=0;
- int iselect = FALSE, iselectitem = -1;
- int iunselect = FALSE;
- /* -------------------------------------------------------------------- */
- /* Variables for the CLIP and ERASE functions */
- /* -------------------------------------------------------------------- */
- double cxmin, cymin, cxmax, cymax;
- int iclip = FALSE, ierase = FALSE;
- int itouch = FALSE, iinside = FALSE, icut = FALSE;
- int ibound = FALSE, ipoly = FALSE;
- char clipfile[80];
- /* -------------------------------------------------------------------- */
- /* Variables for the FACTOR function */
- /* -------------------------------------------------------------------- */
- double infactor,outfactor,factor = 0; /* NO FACTOR */
- int iunit = FALSE;
- int ifactor = FALSE;
-
- /* -------------------------------------------------------------------- */
- /* Variables for the SHIFT function */
- /* -------------------------------------------------------------------- */
- double xshift = 0, yshift = 0; /* NO SHIFT */
-
- int main( int argc, char ** argv )
- {
- /* -------------------------------------------------------------------- */
- /* Check command line usage. */
- /* -------------------------------------------------------------------- */
- if( argc < 2 ) error();
- strcpy(infile, argv[1]);
- if (argc > 2) {
- strcpy(outfile,argv[2]);
- if (strncasecmp2(outfile, "LIST",0) == 0) { ilist = TRUE; }
- if (strncasecmp2(outfile, "ALL",0) == 0) { iall = TRUE; }
- }
- if (ilist || iall || argc == 2 ) {
- setext(infile, "shp");
- printf("DESCRIBE: %s\n",infile);
- strcpy(outfile,"");
- }
- /* -------------------------------------------------------------------- */
- /* Look for other functions on the command line. (SELECT, UNIT) */
- /* -------------------------------------------------------------------- */
- for (i = 3; i < argc; i++)
- {
- if ((strncasecmp2(argv[i], "SEL",3) == 0) ||
- (strncasecmp2(argv[i], "UNSEL",5) == 0))
- {
- if (strncasecmp2(argv[i], "UNSEL",5) == 0) iunselect=TRUE;
- i++;
- if (i >= argc) error();
- strcpy(selectitem,argv[i]);
- i++;
- if (i >= argc) error();
- selcount=0;
- strcpy(temp,argv[i]);
- cpt=temp;
- tj = atoi(cpt);
- ti = 0;
- while (tj>0) {
- selectvalues[selcount] = tj;
- while( *cpt >= '0' && *cpt <= '9')
- cpt++;
- while( *cpt > '\0' && (*cpt < '0' || *cpt > '9') )
- cpt++;
- tj=atoi(cpt);
- selcount++;
- }
- iselect=TRUE;
- } /*** End SEL & UNSEL ***/
- else
- if ((strncasecmp2(argv[i], "CLIP",4) == 0) ||
- (strncasecmp2(argv[i], "ERASE",5) == 0))
- {
- if (strncasecmp2(argv[i], "ERASE",5) == 0) ierase=TRUE;
- i++;
- if (i >= argc) error();
- strcpy(clipfile,argv[i]);
- sscanf(argv[i],"%lf",&cxmin);
- i++;
- if (i >= argc) error();
- if (strncasecmp2(argv[i], "BOUND",5) == 0) {
- setext(clipfile, "shp");
- hSHP = SHPOpen( clipfile, "rb" );
- if( hSHP == NULL )
- {
- printf( "ERROR: Unable to open the clip shape file:%s\n", clipfile );
- exit( 1 );
- }
- SHPGetInfo( hSHPappend, NULL, NULL,
- adfBoundsMin, adfBoundsMax );
- cxmin = adfBoundsMin[0];
- cymin = adfBoundsMin[1];
- cxmax = adfBoundsMax[0];
- cymax = adfBoundsMax[1];
- printf("Theme Clip Boundary: (%lf,%lf) - (%lf,%lf)\n",
- cxmin, cymin, cxmax, cymax);
- ibound=TRUE;
- } else { /*** xmin,ymin,xmax,ymax ***/
- sscanf(argv[i],"%lf",&cymin);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&cxmax);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&cymax);
- printf("Clip Box: (%lf,%lf) - (%lf,%lf)\n",cxmin, cymin, cxmax, cymax);
- }
- i++;
- if (i >= argc) error();
- if (strncasecmp2(argv[i], "CUT",3) == 0) icut=TRUE;
- else if (strncasecmp2(argv[i], "TOUCH",5) == 0) itouch=TRUE;
- else if (strncasecmp2(argv[i], "INSIDE",6) == 0) iinside=TRUE;
- else error();
- iclip=TRUE;
- } /*** End CLIP & ERASE ***/
- else if (strncasecmp2(argv[i], "FACTOR",0) == 0)
- {
- i++;
- if (i >= argc) error();
- infactor=findunit(argv[i]);
- if (infactor == 0) error();
- iunit=TRUE;
- i++;
- if (i >= argc) error();
- outfactor=findunit(argv[i]);
- if (outfactor == 0)
- {
- sscanf(argv[i],"%lf",&factor);
- if (factor == 0) error();
- }
- if (factor == 0)
- {
- if (infactor ==0)
- { puts("ERROR: Input unit must be defined before output unit"); exit(1); }
- factor=infactor/outfactor;
- }
- printf("Output file coordinate values will be factored by %lg\n",factor);
- ifactor=(factor != 1); /* True if a valid factor */
- } /*** End FACTOR ***/
- else if (strncasecmp2(argv[i],"SHIFT",5) == 0)
- {
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&xshift);
- i++;
- if (i >= argc) error();
- sscanf(argv[i],"%lf",&yshift);
- iunit=TRUE;
- printf("X Shift: %lg Y Shift: %lg\n",xshift,yshift);
- } /*** End SHIFT ***/
- else {
- printf("ERROR: Unknown function %s\n",argv[i]); error();
- }
- }
- /* -------------------------------------------------------------------- */
- /* If there is no data in this file let the user know. */
- /* -------------------------------------------------------------------- */
- openfiles(); /* Open the infile and the outfile for shape and dbf. */
- if( DBFGetFieldCount(hDBF) == 0 )
- {
- puts( "There are no fields in this table!" );
- exit( 1 );
- }
- /* -------------------------------------------------------------------- */
- /* Print out the file bounds. */
- /* -------------------------------------------------------------------- */
- iRecord = DBFGetRecordCount( hDBF );
- SHPGetInfo( hSHP, NULL, NULL, adfBoundsMin, adfBoundsMax );
- printf( "Input Bounds: (%lg,%lg) - (%lg,%lg) Entities: %d DBF: %d\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntities, iRecord );
-
- if (strcmp(outfile,"") == 0) /* Describe the shapefile; No other functions */
- {
- ti = DBFGetFieldCount( hDBF );
- showitems();
- exit(0);
- }
-
- if (iclip) check_theme_bnd();
-
- jRecord = DBFGetRecordCount( hDBFappend );
- SHPGetInfo( hSHPappend, NULL, NULL, adfBoundsMin, adfBoundsMax );
- if (nEntitiesAppend == 0)
- puts("New Output File\n");
- else
- printf( "Append Bounds: (%lg,%lg)-(%lg,%lg) Entities: %d DBF: %d\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntitiesAppend, jRecord );
-
- /* -------------------------------------------------------------------- */
- /* Find matching fields in the append file or add new items. */
- /* -------------------------------------------------------------------- */
- mergefields();
- /* -------------------------------------------------------------------- */
- /* Find selection field if needed. */
- /* -------------------------------------------------------------------- */
- if (iselect) findselect();
- /* -------------------------------------------------------------------- */
- /* Read all the records */
- /* -------------------------------------------------------------------- */
- jRecord = DBFGetRecordCount( hDBFappend );
- for( iRecord = 0; iRecord < nEntities; iRecord++) /** DBFGetRecordCount(hDBF) **/
- {
- /* -------------------------------------------------------------------- */
- /* SELECT for values if needed. (Can the record be skipped.) */
- /* -------------------------------------------------------------------- */
- if (iselect)
- if (selectrec() == 0) goto SKIP_RECORD; /** SKIP RECORD **/
- /* -------------------------------------------------------------------- */
- /* Read a Shape record */
- /* -------------------------------------------------------------------- */
- psCShape = SHPReadObject( hSHP, iRecord );
- /* -------------------------------------------------------------------- */
- /* Clip coordinates of shapes if needed. */
- /* -------------------------------------------------------------------- */
- if (iclip)
- if (clip_boundary() == 0) goto SKIP_RECORD; /** SKIP RECORD **/
- /* -------------------------------------------------------------------- */
- /* Read a DBF record and copy each field. */
- /* -------------------------------------------------------------------- */
- for( i = 0; i < DBFGetFieldCount(hDBF); i++ )
- {
- /* -------------------------------------------------------------------- */
- /* Store the record according to the type and formatting */
- /* information implicit in the DBF field description. */
- /* -------------------------------------------------------------------- */
- if (pt[i] > -1) /* if the current field exists in output file */
- {
- switch( DBFGetFieldInfo( hDBF, i, NULL, &iWidth, &iDecimals ) )
- {
- case FTString:
- case FTLogical:
- DBFWriteStringAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadStringAttribute( hDBF, iRecord, i )) );
- break;
- case FTInteger:
- DBFWriteIntegerAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadIntegerAttribute( hDBF, iRecord, i )) );
- break;
- case FTDouble:
- DBFWriteDoubleAttribute(hDBFappend, jRecord, pt[i],
- (DBFReadDoubleAttribute( hDBF, iRecord, i )) );
- break;
- case FTInvalid:
- break;
- }
- }
- }
- jRecord++;
- /* -------------------------------------------------------------------- */
- /* Change FACTOR and SHIFT coordinates of shapes if needed. */
- /* -------------------------------------------------------------------- */
- if (iunit)
- {
- for( j = 0; j < psCShape->nVertices; j++ )
- {
- psCShape->padfX[j] = psCShape->padfX[j] * factor + xshift;
- psCShape->padfY[j] = psCShape->padfY[j] * factor + yshift;
- }
- }
-
- /* -------------------------------------------------------------------- */
- /* Write the Shape record after recomputing current extents. */
- /* -------------------------------------------------------------------- */
- SHPComputeExtents( psCShape );
- SHPWriteObject( hSHPappend, -1, psCShape );
- SKIP_RECORD:
- SHPDestroyObject( psCShape );
- psCShape = NULL;
- j=0;
- }
- /* -------------------------------------------------------------------- */
- /* Print out the # of Entities and the file bounds. */
- /* -------------------------------------------------------------------- */
- jRecord = DBFGetRecordCount( hDBFappend );
- SHPGetInfo( hSHPappend, &nEntitiesAppend, &nShapeTypeAppend,
- adfBoundsMin, adfBoundsMax );
-
- printf( "Output Bounds: (%lg,%lg) - (%lg,%lg) Entities: %d DBF: %d\n\n",
- adfBoundsMin[0], adfBoundsMin[1],
- adfBoundsMax[0], adfBoundsMax[1],
- nEntitiesAppend, jRecord );
- /* -------------------------------------------------------------------- */
- /* Close the both shapefiles. */
- /* -------------------------------------------------------------------- */
- SHPClose( hSHP );
- SHPClose( hSHPappend );
- DBFClose( hDBF );
- DBFClose( hDBFappend );
- if (nEntitiesAppend == 0) {
- puts("Remove the output files.");
- setext(outfile, "dbf");
- remove(outfile);
- setext(outfile, "shp");
- remove(outfile);
- setext(outfile, "shx");
- remove(outfile);
- }
- return( 0 );
- }
- /************************************************************************/
- /* openfiles() */
- /************************************************************************/
- void openfiles() {
- /* -------------------------------------------------------------------- */
- /* Open the DBF file. */
- /* -------------------------------------------------------------------- */
- setext(infile, "dbf");
- hDBF = DBFOpen( infile, "rb" );
- if( hDBF == NULL )
- {
- printf( "ERROR: Unable to open the input DBF:%s\n", infile );
- exit( 1 );
- }
- /* -------------------------------------------------------------------- */
- /* Open the append DBF file. */
- /* -------------------------------------------------------------------- */
- if (strcmp(outfile,"")) {
- setext(outfile, "dbf");
- hDBFappend = DBFOpen( outfile, "rb+" );
- newdbf=0;
- if( hDBFappend == NULL )
- {
- newdbf=1;
- hDBFappend = DBFCreate( outfile );
- if( hDBFappend == NULL )
- {
- printf( "ERROR: Unable to open the append DBF:%s\n", outfile );
- exit( 1 );
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Open the passed shapefile. */
- /* -------------------------------------------------------------------- */
- setext(infile, "shp");
- hSHP = SHPOpen( infile, "rb" );
- if( hSHP == NULL )
- {
- printf( "ERROR: Unable to open the input shape file:%s\n", infile );
- exit( 1 );
- }
- SHPGetInfo( hSHP, &nEntities, &nShapeType, NULL, NULL );
- /* -------------------------------------------------------------------- */
- /* Open the passed append shapefile. */
- /* -------------------------------------------------------------------- */
- if (strcmp(outfile,"")) {
- setext(outfile, "shp");
- hSHPappend = SHPOpen( outfile, "rb+" );
- if( hSHPappend == NULL )
- {
- hSHPappend = SHPCreate( outfile, nShapeType );
- if( hSHPappend == NULL )
- {
- printf( "ERROR: Unable to open the append shape file:%s\n",
- outfile );
- exit( 1 );
- }
- }
- SHPGetInfo( hSHPappend, &nEntitiesAppend, &nShapeTypeAppend,
- NULL, NULL );
- if (nShapeType != nShapeTypeAppend)
- {
- puts( "ERROR: Input and Append shape files are of different types.");
- exit( 1 );
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Change the extension. If there is any extension on the */
- /* filename, strip it off and add the new extension */
- /* -------------------------------------------------------------------- */
- void setext(char *pt, char *ext)
- {
- int i;
- for( i = strlen(pt)-1;
- i > 0 && pt[i] != '.' && pt[i] != '/' && pt[i] != '\\';
- i-- ) {}
- if( pt[i] == '.' )
- pt[i] = '\0';
-
- strcat(pt,".");
- strcat(pt,ext);
- }
- /* -------------------------------------------------------------------- */
- /* Find matching fields in the append file. */
- /* Output file must have zero records to add any new fields. */
- /* -------------------------------------------------------------------- */
- void mergefields()
- {
- int i,j;
- ti = DBFGetFieldCount( hDBF );
- tj = DBFGetFieldCount( hDBFappend );
- /* Create a pointer array for the max # of fields in the output file */
- pt = (int *) malloc( (ti+tj+1) * sizeof(int) );
-
- for( i = 0; i < ti; i++ )
- {
- pt[i]= -1; /* Initial pt values to -1 */
- }
- /* DBF must be empty before adding items */
- jRecord = DBFGetRecordCount( hDBFappend );
- for( i = 0; i < ti; i++ )
- {
- iType = DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals );
- found=FALSE;
- {
- for( j = 0; j < tj; j++ ) /* Search all field names for a match */
- {
- jType = DBFGetFieldInfo( hDBFappend, j, jszTitle, &jWidth, &jDecimals );
- if (iType == jType && (strcmp(iszTitle, jszTitle) == 0) )
- {
- if (found || newdbf)
- {
- if (i == j) pt[i]=j;
- printf("Warning: Duplicate field name found (%s)\n",iszTitle);
- /* Duplicate field name
- (Try to guess the correct field by position) */
- }
- else
- {
- pt[i]=j; found=TRUE;
- }
- }
- }
- }
-
- if (pt[i] == -1 && (! found) ) /* Try to force into an existing field */
- { /* Ignore the field name, width, and decimal places */
- jType = DBFGetFieldInfo( hDBFappend, j, jszTitle, &jWidth, &jDecimals );
- if (iType == jType)
- {
- pt[i]=i; found=1;
- }
- }
- if ( (! found) && jRecord == 0) /* Add missing field to the append table */
- { /* The output DBF must be is empty */
- pt[i]=tj;
- tj++;
- if( DBFAddField( hDBFappend, iszTitle, iType, iWidth, iDecimals )
- == -1 )
- {
- printf( "Warning: DBFAddField(%s, TYPE:%d, WIDTH:%d DEC:%d, ITEM#:%d of %d) failed.\n",
- iszTitle, iType, iWidth, iDecimals, (i+1), (ti+1) );
- pt[i]=-1;
- }
- }
- }
- }
- void findselect()
- {
- /* Find the select field name */
- iselectitem = -1;
- for( i = 0; i < ti && iselectitem < 0; i++ )
- {
- iType = DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals );
- if (strncasecmp2(iszTitle, selectitem, 0) == 0) iselectitem = i;
- }
- if (iselectitem == -1)
- {
- printf("Warning: Item not found for selection (%s)\n",selectitem);
- iselect = FALSE;
- iall = FALSE;
- showitems();
- printf("Continued... (Selecting entire file)\n");
- }
- /* Extract all of the select values (by field type) */
-
- }
- void showitems()
- {
- char stmp[40],slow[40],shigh[40];
- double dtmp,dlow,dhigh,dsum,mean;
- long int itmp,ilow,ihigh,isum;
- long int maxrec;
- char *pt;
- printf("Available Items: (%d)",ti);
- maxrec = DBFGetRecordCount(hDBF);
- if (maxrec > 5000 && ! iall)
- { maxrec=5000; printf(" ** ESTIMATED RANGES (MEAN) For more records use \"All\""); }
- else { printf(" RANGES (MEAN)"); }
-
- for( i = 0; i < ti; i++ )
- {
- switch( DBFGetFieldInfo( hDBF, i, iszTitle, &iWidth, &iDecimals ) )
- {
- case FTString:
- case FTLogical:
- strcpy(slow, "~");
- strcpy(shigh,"\0");
- printf("\n String %3d %-16s",iWidth,iszTitle);
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- strncpy(stmp,DBFReadStringAttribute( hDBF, iRecord, i ),39);
- if (strcmp(stmp,"!!") > 0) {
- if (strncasecmp2(stmp,slow,0) < 0) strncpy(slow, stmp,39);
- if (strncasecmp2(stmp,shigh,0) > 0) strncpy(shigh,stmp,39);
- }
- }
- pt=slow+strlen(slow)-1;
- while(*pt == ' ') { *pt='\0'; pt--; }
- pt=shigh+strlen(shigh)-1;
- while(*pt == ' ') { *pt='\0'; pt--; }
- if (strncasecmp2(slow,shigh,0) < 0) printf("%s to %s",slow,shigh);
- else if (strncasecmp2(slow,shigh,0) == 0) printf("= %s",slow);
- else printf("No Values");
- break;
- case FTInteger:
- printf("\n Integer %3d %-16s",iWidth,iszTitle);
- ilow = 1999999999;
- ihigh= -1999999999;
- isum = 0;
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- itmp = DBFReadIntegerAttribute( hDBF, iRecord, i );
- if (ilow > itmp) ilow = itmp;
- if (ihigh < itmp) ihigh = itmp;
- isum = isum + itmp;
- }
- mean=isum/maxrec;
- if (ilow < ihigh) printf("%ld to %ld \t(%.1f)",ilow,ihigh,mean);
- else if (ilow == ihigh) printf("= %ld",ilow);
- else printf("No Values");
- break;
- case FTDouble:
- printf("\n Real %3d,%d %-16s",iWidth,iDecimals,iszTitle);
- dlow = 999999999999999.0;
- dhigh= -999999999999999.0;
- dsum = 0;
- for( iRecord = 0; iRecord < maxrec; iRecord++ ) {
- dtmp = DBFReadDoubleAttribute( hDBF, iRecord, i );
- if (dlow > dtmp) dlow = dtmp;
- if (dhigh < dtmp) dhigh = dtmp;
- dsum = dsum + dtmp;
- }
- mean=dsum/maxrec;
- sprintf(stmp,"%%.%df to %%.%df \t(%%.%df)",iDecimals,iDecimals,iDecimals);
- if (dlow < dhigh) printf(stmp,dlow,dhigh,mean);
- else if (dlow == dhigh) {
- sprintf(stmp,"= %%.%df",iDecimals);
- printf(stmp,dlow);
- }
- else printf("No Values");
- break;
- case FTInvalid:
- break;
- }
- }
- printf("\n");
- }
- int selectrec()
- {
- long int value, ty;
- ty = DBFGetFieldInfo( hDBF, iselectitem, NULL, &iWidth, &iDecimals);
- switch(ty)
- {
- case FTString:
- puts("Invalid Item");
- iselect=FALSE;
- break;
- case FTInteger:
- value = DBFReadIntegerAttribute( hDBF, iRecord, iselectitem );
- for (j = 0; j<selcount; j++)
- {
- if (selectvalues[j] == value)
- {
- if (iunselect) return(0); /* Keep this record */
- else return(1); /* Skip this record */
- }
- }
- break;
- case FTDouble:
- puts("Invalid Item");
- iselect=FALSE;
- break;
- }
- if (iunselect) return(1); /* Skip this record */
- else return(0); /* Keep this record */
- }
- void check_theme_bnd()
- {
- if ( (adfBoundsMin[0] >= cxmin) && (adfBoundsMax[0] <= cxmax) &&
- (adfBoundsMin[1] >= cymin) && (adfBoundsMax[1] <= cymax) )
- { /** Theme is totally inside clip area **/
- if (ierase) nEntities=0; /** SKIP THEME **/
- else iclip=FALSE; /** WRITE THEME (Clip not needed) **/
- }
-
- if ( ( (adfBoundsMin[0] < cxmin) && (adfBoundsMax[0] < cxmin) ) ||
- ( (adfBoundsMin[1] < cymin) && (adfBoundsMax[1] < cymin) ) ||
- ( (adfBoundsMin[0] > cxmax) && (adfBoundsMax[0] > cxmax) ) ||
- ( (adfBoundsMin[1] > cymax) && (adfBoundsMax[1] > cymax) ) )
- { /** Theme is totally outside clip area **/
- if (ierase) iclip=FALSE; /** WRITE THEME (Clip not needed) **/
- else nEntities=0; /** SKIP THEME **/
- }
-
- if (nEntities == 0)
- puts("WARNING: Theme is outside the clip area."); /** SKIP THEME **/
- }
- int clip_boundary()
- {
- int inside;
- int prev_outside;
- int i2;
- int j2;
-
- /*** FIRST check the boundary of the feature ***/
- if ( ( (psCShape->dfXMin < cxmin) && (psCShape->dfXMax < cxmin) ) ||
- ( (psCShape->dfYMin < cymin) && (psCShape->dfYMax < cymin) ) ||
- ( (psCShape->dfXMin > cxmax) && (psCShape->dfXMax > cxmax) ) ||
- ( (psCShape->dfYMin > cymax) && (psCShape->dfYMax > cymax) ) )
- { /** Feature is totally outside clip area **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- }
-
- if ( (psCShape->dfXMin >= cxmin) && (psCShape->dfXMax <= cxmax) &&
- (psCShape->dfYMin >= cymin) && (psCShape->dfYMax <= cymax) )
- { /** Feature is totally inside clip area **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
-
- if (iinside)
- { /** INSIDE * Feature might touch the boundary or could be outside **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- }
-
- if (itouch)
- { /** TOUCH **/
- if ( ( (psCShape->dfXMin <= cxmin) || (psCShape->dfXMax >= cxmax) ) &&
- (psCShape->dfYMin >= cymin) && (psCShape->dfYMax <= cymax) )
- { /** Feature intersects the clip boundary only on the X axis **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
- if ( (psCShape->dfXMin >= cxmin) && (psCShape->dfXMax <= cxmax) &&
- ( (psCShape->dfYMin <= cymin) || (psCShape->dfYMax >= cymax) ) )
- { /** Feature intersects the clip boundary only on the Y axis **/
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
-
- for( j2 = 0; j2 < psCShape->nVertices; j2++ )
- { /** At least one vertex must be inside the clip boundary **/
- if ( (psCShape->padfX[j2] >= cxmin && psCShape->padfX[j2] <= cxmax) ||
- (psCShape->padfY[j2] >= cymin && psCShape->padfY[j2] <= cymax) )
- {
- if (ierase) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- }
- }
-
- /** All vertices are outside the clip boundary **/
- if (ierase) return(1); /** WRITE RECORD **/
- else return(0); /** SKIP RECORD **/
- } /** End TOUCH **/
-
- if (icut)
- { /** CUT **/
- /*** Check each vertex in the feature with the Boundary and "CUT" ***/
- /*** THIS CODE WAS NOT COMPLETED! READ NOTE AT THE BOTTOM ***/
- i2=0;
- prev_outside=FALSE;
- for( j2 = 0; j2 < psCShape->nVertices; j2++ )
- {
- inside = psCShape->padfX[j2] >= cxmin && psCShape->padfX[j2] <= cxmax &&
- psCShape->padfY[j2] >= cymin && psCShape->padfY[j2] <= cymax ;
-
- if (ierase) inside=(! inside);
- if (inside)
- {
- if (i2 != j2)
- {
- if (prev_outside)
- {
- /*** AddIntersection(i2); ***/ /*** Add intersection ***/
- prev_outside=FALSE;
- }
- psCShape->padfX[i2]=psCShape->padfX[j2]; /** move vertex **/
- psCShape->padfY[i2]=psCShape->padfY[j2];
- }
- i2++;
- } else {
- if ( (! prev_outside) && (j2 > 0) )
- {
- /*** AddIntersection(i2); ***//*** Add intersection (Watch out for j2==i2-1) ***/
- /*** Also a polygon may overlap twice and will split into a several parts ***/
- prev_outside=TRUE;
- }
- }
- }
-
- printf("Vertices:%d OUT:%d Number of Parts:%d\n",
- psCShape->nVertices,i2, psCShape->nParts );
-
- psCShape->nVertices = i2;
-
- if (i2 < 2) return(0); /** SKIP RECORD **/
- /*** (WE ARE NOT CREATING INTERESECTIONS and some lines could be reduced to one point) **/
-
- if (i2 == 0) return(0); /** SKIP RECORD **/
- else return(1); /** WRITE RECORD **/
- } /** End CUT **/
- }
- /************************************************************************/
- /* strncasecmp2() */
- /* */
- /* Compare two strings up to n characters */
- /* If n=0 then s1 and s2 must be an exact match */
- /************************************************************************/
- int strncasecmp2(char *s1, char *s2, int n)
- {
- int j,i;
- if (n<1) n=strlen(s1)+1;
- for (i=0; i<n; i++)
- {
- if (*s1 != *s2)
- {
- if (*s1 >= 'a' && *s1 <= 'z') {
- j=*s1-32;
- if (j != *s2) return(*s1-*s2);
- } else {
- if (*s1 >= 'A' && *s1 <= 'Z') { j=*s1+32; }
- else { j=*s1; }
- if (j != *s2) return(*s1-*s2);
- }
- }
- s1++;
- s2++;
- }
- return(0);
- }
- #define NKEYS (sizeof(unitkeytab) / sizeof(struct unitkey))
- double findunit(char *unit)
- {
- struct unitkey {
- char *name;
- double value;
- } unitkeytab[] = {
- "CM", 39.37,
- "CENTIMETER", 39.37,
- "CENTIMETERS", 39.37, /** # of inches * 100 in unit **/
- "METER", 3937,
- "METERS", 3937,
- "KM", 3937000,
- "KILOMETER", 3937000,
- "KILOMETERS", 3937000,
- "INCH", 100,
- "INCHES", 100,
- "FEET", 1200,
- "FOOT", 1200,
- "YARD", 3600,
- "YARDS", 3600,
- "MILE", 6336000,
- "MILES", 6336000
- };
- double unitfactor=0;
- for (j = 0; j < NKEYS; j++) {
- if (strncasecmp2(unit, unitkeytab[j].name, 0) == 0) unitfactor=unitkeytab[j].value;
- }
- return(unitfactor);
- }
- /* -------------------------------------------------------------------- */
- /* Display a usage message. */
- /* -------------------------------------------------------------------- */
- void error()
- {
- puts( "The program will append to an existing shape file or it will" );
- puts( "create a new file if needed." );
- puts( "Only the items in the first output file will be preserved." );
- puts( "When an item does not match with the append theme then the item");
- puts( "might be placed to an existing item at the same position and type." );
- puts( " OTHER FUNCTIONS:" );
- puts( " - Describe all items in the dbase file (Use ALL for more than 5000 recs.)");
- puts( " - Select a group of shapes from a comma separated selection list.");
- puts( " - UnSelect a group of shapes from a comma separated selection list.");
- puts( " - Clip boundary extent or by theme boundary." );
- puts( " Touch writes all the shapes that touch the boundary.");
- puts( " Inside writes all the shapes that are completely within the boundary.");
- puts( " Boundary clips are only the min and max of a theme boundary." );
- puts( " - Erase boundary extent or by theme boundary." );
- puts( " Erase is the direct opposite of the Clip function." );
- puts( " - Change coordinate value units between meters and feet.");
- puts( " There is no way to determine the input unit of a shape file.");
- puts( " Skip this function if the shape file is already in the correct unit.");
- puts( " Clip and Erase will be done before the unit is changed.");
- puts( " A shift will be done after the unit is changed.");
- puts( " - Shift X and Y coordinates.\n" );
- puts( "Finally, There can only be one select or unselect in the command line.");
- puts( " There can only be one clip or erase in the command line.");
- puts( " There can only be one unit and only one shift in the command line.\n");
- puts( "Ex: shputils in.shp out.shp SELECT countycode 3,5,9,13,17,27");
- puts( " shputils in.shp out.shp CLIP 10 10 90 90 Touch FACTOR Meter Feet");
- puts( " shputils in.shp out.shp FACTOR Meter 3.0");
- puts( " shputils in.shp out.shp CLIP clip.shp Boundary Touch SHIFT 40 40");
- puts( " shputils in.shp out.shp SELECT co 112 CLIP clip.shp Boundary Touch\n");
- puts( "USAGE: shputils <DescribeShape> {ALL}");
- puts( "USAGE: shputils <InputShape> <OutShape|AppendShape>" );
- puts( " { <FACTOR> <FEET|MILES|METERS|KM> <FEET|MILES|METERS|KM|factor> }" );
- puts( " { <SHIFT> <xshift> <yshift> }" );
- puts( " { <SELECT|UNSEL> <Item> <valuelist> }" );
- puts( " { <CLIP|ERASE> <xmin> <ymin> <xmax> <ymax> <TOUCH|INSIDE|CUT> }" );
- puts( " { <CLIP|ERASE> <theme> <BOUNDARY> <TOUCH|INSIDE|CUT> }" );
- puts( " Note: CUT is not complete and does not create intersections.");
- puts( " For more information read programmer comment.");
-
- /**** Clip functions for Polygon and Cut is not supported
- There are several web pages that describe methods of doing this function.
- It seem easy to impliment until you start writting code. I don't have the
- time to add these functions but a did leave a simple cut routine in the
- program that can be called by using CUT instead of TOUCH in the
- CLIP or ERASE functions. It does not add the intersection of the line and
- the clip box, so polygons could look incomplete and lines will come up short.
-
- Information about clipping lines with a box:
- http://www.csclub.uwaterloo.ca/u/mpslager/articles/sutherland/wr.html
- Information about finding the intersection of two lines:
- http://www.whisqu.se/per/docs/math28.htm
-
- THE CODE LOOKS LIKE THIS:
- ********************************************************
- void Intersect_Lines(float x0,float y0,float x1,float y1,
- float x2,float y2,float x3,float y3,
- float *xi,float *yi)
- {
- // this function computes the intersection of the sent lines
- // and returns the intersection point, note that the function assumes
- // the lines intersect. the function can handle vertical as well
- // as horizontal lines. note the function isn't very clever, it simply
- // applies the math, but we don't need speed since this is a
- // pre-processing step
- // The Intersect_lines program came from (http://www.whisqu.se/per/docs/math28.htm)
- float a1,b1,c1, // constants of linear equations
- a2,b2,c2,
- det_inv, // the inverse of the determinant of the coefficientmatrix
- m1,m2; // the slopes of each line
-
- // compute slopes, note the cludge for infinity, however, this will
- // be close enough
- if ((x1-x0)!=0)
- m1 = (y1-y0)/(x1-x0);
- else
- m1 = (float)1e+10; // close enough to infinity
-
-
- if ((x3-x2)!=0)
- m2 = (y3-y2)/(x3-x2);
- else
- m2 = (float)1e+10; // close enough to infinity
-
- // compute constants
- a1 = m1;
- a2 = m2;
- b1 = -1;
- b2 = -1;
- c1 = (y0-m1*x0);
- c2 = (y2-m2*x2);
- // compute the inverse of the determinate
- det_inv = 1/(a1*b2 - a2*b1);
- // use Kramers rule to compute xi and yi
- *xi=((b1*c2 - b2*c1)*det_inv);
- *yi=((a2*c1 - a1*c2)*det_inv);
- } // end Intersect_Lines
- **********************************************************/
- exit( 1 );
- }