shapelib-1.3.0/0000750042715500116100000000000011741051742012620 5ustar warmerdamengshapelib-1.3.0/shapefil.h0000640042715500116100000005447511671227046014610 0ustar warmerdameng#ifndef SHAPEFILE_H_INCLUDED #define SHAPEFILE_H_INCLUDED /****************************************************************************** * $Id: shapefil.h,v 1.52 2011-12-11 22:26:46 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Primary include file for Shapelib. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shapefil.h,v $ * Revision 1.52 2011-12-11 22:26:46 fwarmerdam * upgrade .qix access code to use SAHooks (gdal #3365) * * Revision 1.51 2011-07-24 05:59:25 fwarmerdam * minimize use of CPLError in favor of SAHooks.Error() * * Revision 1.50 2011-05-13 17:35:17 fwarmerdam * added DBFReorderFields() and DBFAlterFields() functions (from Even) * * Revision 1.49 2011-04-16 14:38:21 fwarmerdam * avoid warnings with gcc on SHP_CVSID * * Revision 1.48 2010-08-27 23:42:52 fwarmerdam * add SHPAPI_CALL attribute in code * * Revision 1.47 2010-01-28 11:34:34 fwarmerdam * handle the shape file length limits more gracefully (#3236) * * Revision 1.46 2008-11-12 14:28:15 fwarmerdam * DBFCreateField() now works on files with records * * Revision 1.45 2008/11/11 17:47:10 fwarmerdam * added DBFDeleteField() function * * Revision 1.44 2008/01/16 20:05:19 bram * Add file hooks that accept UTF-8 encoded filenames on some platforms. Use SASetupUtf8Hooks * tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability. Currently, this * is only available on the Windows platform that decodes the UTF-8 filenames to wide * character strings and feeds them to _wfopen and _wremove. * * Revision 1.43 2008/01/10 16:35:30 fwarmerdam * avoid _ prefix on #defined symbols (bug 1840) * * Revision 1.42 2007/12/18 18:28:14 bram * - create hook for client specific atof (bugzilla ticket 1615) * - check for NULL handle before closing cpCPG file, and close after reading. * * Revision 1.41 2007/12/15 20:25:32 bram * dbfopen.c now reads the Code Page information from the DBF file, and exports * this information as a string through the DBFGetCodePage function. This is * either the number from the LDID header field ("LDID/") or as the * content of an accompanying .CPG file. When creating a DBF file, the code can * be set using DBFCreateEx. * * Revision 1.40 2007/12/06 07:00:25 fwarmerdam * dbfopen now using SAHooks for fileio * * Revision 1.39 2007/12/04 20:37:56 fwarmerdam * preliminary implementation of hooks api for io and errors * * Revision 1.38 2007/11/21 22:39:56 fwarmerdam * close shx file in readonly mode (GDAL #1956) * * Revision 1.37 2007/10/27 03:31:14 fwarmerdam * limit default depth of tree to 12 levels (gdal ticket #1594) * * Revision 1.36 2007/09/10 23:33:15 fwarmerdam * Upstreamed support for visibility flag in SHPAPI_CALL for the needs * of GDAL (gdal ticket #1810). * * Revision 1.35 2007/09/03 19:48:10 fwarmerdam * move DBFReadAttribute() static dDoubleField into dbfinfo * * Revision 1.34 2006/06/17 15:33:32 fwarmerdam * added pszWorkField - bug 1202 (rso) * * Revision 1.33 2006/02/15 01:14:30 fwarmerdam * added DBFAddNativeFieldType * * Revision 1.32 2006/01/26 15:07:32 fwarmerdam * add bMeasureIsUsed flag from Craig Bruce: Bug 1249 * * Revision 1.31 2006/01/05 01:27:27 fwarmerdam * added dbf deletion mark/fetch * * Revision 1.30 2005/01/03 22:30:13 fwarmerdam * added support for saved quadtrees * * Revision 1.29 2004/09/26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.28 2003/12/29 06:02:18 fwarmerdam * added cpl_error.h option * * Revision 1.27 2003/04/21 18:30:37 warmerda * added header write/update public methods * * Revision 1.26 2002/09/29 00:00:08 warmerda * added FTLogical and logical attribute read/write calls * * Revision 1.25 2002/05/07 13:46:30 warmerda * added DBFWriteAttributeDirectly(). * * Revision 1.24 2002/04/10 16:59:54 warmerda * added SHPRewindObject * * Revision 1.23 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.22 2002/01/15 14:32:00 warmerda * try to improve SHPAPI_CALL docs */ #include #ifdef USE_DBMALLOC #include #endif #ifdef __cplusplus extern "C" { #endif /************************************************************************/ /* Configuration options. */ /************************************************************************/ /* -------------------------------------------------------------------- */ /* Should the DBFReadStringAttribute() strip leading and */ /* trailing white space? */ /* -------------------------------------------------------------------- */ #define TRIM_DBF_WHITESPACE /* -------------------------------------------------------------------- */ /* Should we write measure values to the Multipatch object? */ /* Reportedly ArcView crashes if we do write it, so for now it */ /* is disabled. */ /* -------------------------------------------------------------------- */ #define DISABLE_MULTIPATCH_MEASURE /* -------------------------------------------------------------------- */ /* SHPAPI_CALL */ /* */ /* The following two macros are present to allow forcing */ /* various calling conventions on the Shapelib API. */ /* */ /* To force __stdcall conventions (needed to call Shapelib */ /* from Visual Basic and/or Dephi I believe) the makefile could */ /* be modified to define: */ /* */ /* /DSHPAPI_CALL=__stdcall */ /* */ /* If it is desired to force export of the Shapelib API without */ /* using the shapelib.def file, use the following definition. */ /* */ /* /DSHAPELIB_DLLEXPORT */ /* */ /* To get both at once it will be necessary to hack this */ /* include file to define: */ /* */ /* #define SHPAPI_CALL __declspec(dllexport) __stdcall */ /* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */ /* */ /* The complexity of the situtation is partly caused by the */ /* peculiar requirement of Visual C++ that __stdcall appear */ /* after any "*"'s in the return value of a function while the */ /* __declspec(dllexport) must appear before them. */ /* -------------------------------------------------------------------- */ #ifdef SHAPELIB_DLLEXPORT # define SHPAPI_CALL __declspec(dllexport) # define SHPAPI_CALL1(x) __declspec(dllexport) x #endif #ifndef SHPAPI_CALL # if defined(USE_GCC_VISIBILITY_FLAG) # define SHPAPI_CALL __attribute__ ((visibility("default"))) # define SHPAPI_CALL1(x) __attribute__ ((visibility("default"))) x # else # define SHPAPI_CALL # endif #endif #ifndef SHPAPI_CALL1 # define SHPAPI_CALL1(x) x SHPAPI_CALL #endif /* -------------------------------------------------------------------- */ /* Macros for controlling CVSID and ensuring they don't appear */ /* as unreferenced variables resulting in lots of warnings. */ /* -------------------------------------------------------------------- */ #ifndef DISABLE_CVSID # if defined(__GNUC__) && __GNUC__ >= 4 # define SHP_CVSID(string) static char cpl_cvsid[] __attribute__((used)) = string; # else # define SHP_CVSID(string) static char cpl_cvsid[] = string; \ static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); } # endif #else # define SHP_CVSID(string) #endif /* -------------------------------------------------------------------- */ /* On some platforms, additional file IO hooks are defined that */ /* UTF-8 encoded filenames Unicode filenames */ /* -------------------------------------------------------------------- */ #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # define SHPAPI_WINDOWS # define SHPAPI_UTF8_HOOKS #endif /* -------------------------------------------------------------------- */ /* IO/Error hook functions. */ /* -------------------------------------------------------------------- */ typedef int *SAFile; #ifndef SAOffset typedef unsigned long SAOffset; #endif typedef struct { SAFile (*FOpen) ( const char *filename, const char *access); SAOffset (*FRead) ( void *p, SAOffset size, SAOffset nmemb, SAFile file); SAOffset (*FWrite)( void *p, SAOffset size, SAOffset nmemb, SAFile file); SAOffset (*FSeek) ( SAFile file, SAOffset offset, int whence ); SAOffset (*FTell) ( SAFile file ); int (*FFlush)( SAFile file ); int (*FClose)( SAFile file ); int (*Remove) ( const char *filename ); void (*Error) ( const char *message ); double (*Atof) ( const char *str ); } SAHooks; void SHPAPI_CALL SASetupDefaultHooks( SAHooks *psHooks ); #ifdef SHPAPI_UTF8_HOOKS void SHPAPI_CALL SASetupUtf8Hooks( SAHooks *psHooks ); #endif /************************************************************************/ /* SHP Support. */ /************************************************************************/ typedef struct { SAHooks sHooks; SAFile fpSHP; SAFile fpSHX; int nShapeType; /* SHPT_* */ unsigned int nFileSize; /* SHP file */ int nRecords; int nMaxRecords; unsigned int *panRecOffset; unsigned int *panRecSize; double adBoundsMin[4]; double adBoundsMax[4]; int bUpdated; unsigned char *pabyRec; int nBufSize; } SHPInfo; typedef SHPInfo * SHPHandle; /* -------------------------------------------------------------------- */ /* Shape types (nSHPType) */ /* -------------------------------------------------------------------- */ #define SHPT_NULL 0 #define SHPT_POINT 1 #define SHPT_ARC 3 #define SHPT_POLYGON 5 #define SHPT_MULTIPOINT 8 #define SHPT_POINTZ 11 #define SHPT_ARCZ 13 #define SHPT_POLYGONZ 15 #define SHPT_MULTIPOINTZ 18 #define SHPT_POINTM 21 #define SHPT_ARCM 23 #define SHPT_POLYGONM 25 #define SHPT_MULTIPOINTM 28 #define SHPT_MULTIPATCH 31 /* -------------------------------------------------------------------- */ /* Part types - everything but SHPT_MULTIPATCH just uses */ /* SHPP_RING. */ /* -------------------------------------------------------------------- */ #define SHPP_TRISTRIP 0 #define SHPP_TRIFAN 1 #define SHPP_OUTERRING 2 #define SHPP_INNERRING 3 #define SHPP_FIRSTRING 4 #define SHPP_RING 5 /* -------------------------------------------------------------------- */ /* SHPObject - represents on shape (without attributes) read */ /* from the .shp file. */ /* -------------------------------------------------------------------- */ typedef struct { int nSHPType; int nShapeId; /* -1 is unknown/unassigned */ int nParts; int *panPartStart; int *panPartType; int nVertices; double *padfX; double *padfY; double *padfZ; double *padfM; double dfXMin; double dfYMin; double dfZMin; double dfMMin; double dfXMax; double dfYMax; double dfZMax; double dfMMax; int bMeasureIsUsed; } SHPObject; /* -------------------------------------------------------------------- */ /* SHP API Prototypes */ /* -------------------------------------------------------------------- */ /* If pszAccess is read-only, the fpSHX field of the returned structure */ /* will be NULL as it is not necessary to keep the SHX file open */ SHPHandle SHPAPI_CALL SHPOpen( const char * pszShapeFile, const char * pszAccess ); SHPHandle SHPAPI_CALL SHPOpenLL( const char *pszShapeFile, const char *pszAccess, SAHooks *psHooks ); SHPHandle SHPAPI_CALL SHPCreate( const char * pszShapeFile, int nShapeType ); SHPHandle SHPAPI_CALL SHPCreateLL( const char * pszShapeFile, int nShapeType, SAHooks *psHooks ); void SHPAPI_CALL SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType, double * padfMinBound, double * padfMaxBound ); SHPObject SHPAPI_CALL1(*) SHPReadObject( SHPHandle hSHP, int iShape ); int SHPAPI_CALL SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject ); void SHPAPI_CALL SHPDestroyObject( SHPObject * psObject ); void SHPAPI_CALL SHPComputeExtents( SHPObject * psObject ); SHPObject SHPAPI_CALL1(*) SHPCreateObject( int nSHPType, int nShapeId, int nParts, const int * panPartStart, const int * panPartType, int nVertices, const double * padfX, const double * padfY, const double * padfZ, const double * padfM ); SHPObject SHPAPI_CALL1(*) SHPCreateSimpleObject( int nSHPType, int nVertices, const double * padfX, const double * padfY, const double * padfZ ); int SHPAPI_CALL SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ); void SHPAPI_CALL SHPClose( SHPHandle hSHP ); void SHPAPI_CALL SHPWriteHeader( SHPHandle hSHP ); const char SHPAPI_CALL1(*) SHPTypeName( int nSHPType ); const char SHPAPI_CALL1(*) SHPPartTypeName( int nPartType ); /* -------------------------------------------------------------------- */ /* Shape quadtree indexing API. */ /* -------------------------------------------------------------------- */ /* this can be two or four for binary or quad tree */ #define MAX_SUBNODE 4 /* upper limit of tree levels for automatic estimation */ #define MAX_DEFAULT_TREE_DEPTH 12 typedef struct shape_tree_node { /* region covered by this node */ double adfBoundsMin[4]; double adfBoundsMax[4]; /* list of shapes stored at this node. The papsShapeObj pointers or the whole list can be NULL */ int nShapeCount; int *panShapeIds; SHPObject **papsShapeObj; int nSubNodes; struct shape_tree_node *apsSubNode[MAX_SUBNODE]; } SHPTreeNode; typedef struct { SHPHandle hSHP; int nMaxDepth; int nDimension; int nTotalCount; SHPTreeNode *psRoot; } SHPTree; SHPTree SHPAPI_CALL1(*) SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth, double *padfBoundsMin, double *padfBoundsMax ); void SHPAPI_CALL SHPDestroyTree( SHPTree * hTree ); int SHPAPI_CALL SHPWriteTree( SHPTree *hTree, const char * pszFilename ); int SHPAPI_CALL SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject ); int SHPAPI_CALL SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId ); void SHPAPI_CALL SHPTreeTrimExtraNodes( SHPTree * hTree ); int SHPAPI_CALL1(*) SHPTreeFindLikelyShapes( SHPTree * hTree, double * padfBoundsMin, double * padfBoundsMax, int * ); int SHPAPI_CALL SHPCheckBoundsOverlap( double *, double *, double *, double *, int ); int SHPAPI_CALL1(*) SHPSearchDiskTree( FILE *fp, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount ); typedef struct SHPDiskTreeInfo* SHPTreeDiskHandle; SHPTreeDiskHandle SHPAPI_CALL SHPOpenDiskTree( const char* pszQIXFilename, SAHooks *psHooks ); void SHPAPI_CALL SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree ); int SHPAPI_CALL1(*) SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount ); int SHPAPI_CALL SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, SAHooks *psHooks ); /************************************************************************/ /* DBF Support. */ /************************************************************************/ typedef struct { SAHooks sHooks; SAFile fp; int nRecords; int nRecordLength; int nHeaderLength; int nFields; int *panFieldOffset; int *panFieldSize; int *panFieldDecimals; char *pachFieldType; char *pszHeader; int nCurrentRecord; int bCurrentRecordModified; char *pszCurrentRecord; int nWorkFieldLength; char *pszWorkField; int bNoHeader; int bUpdated; double dfDoubleField; int iLanguageDriver; char *pszCodePage; } DBFInfo; typedef DBFInfo * DBFHandle; typedef enum { FTString, FTInteger, FTDouble, FTLogical, FTInvalid } DBFFieldType; #define XBASE_FLDHDR_SZ 32 DBFHandle SHPAPI_CALL DBFOpen( const char * pszDBFFile, const char * pszAccess ); DBFHandle SHPAPI_CALL DBFOpenLL( const char * pszDBFFile, const char * pszAccess, SAHooks *psHooks ); DBFHandle SHPAPI_CALL DBFCreate( const char * pszDBFFile ); DBFHandle SHPAPI_CALL DBFCreateEx( const char * pszDBFFile, const char * pszCodePage ); DBFHandle SHPAPI_CALL DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks ); int SHPAPI_CALL DBFGetFieldCount( DBFHandle psDBF ); int SHPAPI_CALL DBFGetRecordCount( DBFHandle psDBF ); int SHPAPI_CALL DBFAddField( DBFHandle hDBF, const char * pszFieldName, DBFFieldType eType, int nWidth, int nDecimals ); int SHPAPI_CALL DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName, char chType, int nWidth, int nDecimals ); int SHPAPI_CALL DBFDeleteField( DBFHandle hDBF, int iField ); int SHPAPI_CALL DBFReorderFields( DBFHandle psDBF, int* panMap ); int SHPAPI_CALL DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName, char chType, int nWidth, int nDecimals ); DBFFieldType SHPAPI_CALL DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ); int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName); int SHPAPI_CALL DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField ); double SHPAPI_CALL DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField ); const char SHPAPI_CALL1(*) DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField ); const char SHPAPI_CALL1(*) DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField ); int SHPAPI_CALL DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField ); int SHPAPI_CALL DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField, int nFieldValue ); int SHPAPI_CALL DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField, double dFieldValue ); int SHPAPI_CALL DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField, const char * pszFieldValue ); int SHPAPI_CALL DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField ); int SHPAPI_CALL DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField, const char lFieldValue); int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void * pValue ); const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity ); int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ); int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape ); int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, int bIsDeleted ); DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ); void SHPAPI_CALL DBFClose( DBFHandle hDBF ); void SHPAPI_CALL DBFUpdateHeader( DBFHandle hDBF ); char SHPAPI_CALL DBFGetNativeFieldType( DBFHandle hDBF, int iField ); const char SHPAPI_CALL1(*) DBFGetCodePage(DBFHandle psDBF ); #ifdef __cplusplus } #endif #endif /* ndef SHAPEFILE_H_INCLUDED */ shapelib-1.3.0/makefile.vc0000640042715500116100000000525710761617604014747 0ustar warmerdameng #CFLAGS = /DSHPAPI_CALL=__stdcall CFLAGS = /nologo /Ox /MD /DSHAPELIB_DLLEXPORT IMPORT_LIB = shapelib_i.lib STATIC_LIB = shapelib.lib DLLNAME = shapelib.dll LINK_LIB = $(IMPORT_LIB) OBJ = shpopen.obj dbfopen.obj shptree.obj safileio.obj all: $(STATIC_LIB) $(DLLNAME) \ shpcreate.exe shpadd.exe shpdump.exe shprewind.exe dbfcreate.exe \ dbfadd.exe dbfdump.exe shptest.exe shptreedump.exe shpopen.obj: shpopen.c shapefil.h $(CC) $(CFLAGS) -c shpopen.c shptree.obj: shptree.c shapefil.h $(CC) $(CFLAGS) -c shptree.c dbfopen.obj: dbfopen.c shapefil.h $(CC) $(CFLAGS) -c dbfopen.c safileio.obj: safileio.c shapefil.h $(CC) $(CFLAGS) -c safileio.c shpcreate.exe: shpcreate.c $(LINK_LIB) $(CC) $(CFLAGS) shpcreate.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpadd.exe: shpadd.c $(LINK_LIB) $(CC) $(CFLAGS) shpadd.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpdump.exe: shpdump.c $(LINK_LIB) $(CC) $(CFLAGS) shpdump.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shprewind.exe: shprewind.c $(LINK_LIB) $(CC) $(CFLAGS) shprewind.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 dbfcreate.exe: dbfcreate.c $(LINK_LIB) $(CC) $(CFLAGS) dbfcreate.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 dbfadd.exe: dbfadd.c $(LINK_LIB) $(CC) $(CFLAGS) dbfadd.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 dbfdump.exe: dbfdump.c $(LINK_LIB) $(CC) $(CFLAGS) dbfdump.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shptest.exe: shptest.c $(LINK_LIB) $(CC) $(CFLAGS) shptest.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shputils.exe: shputils.c $(LINK_LIB) $(CC) $(CFLAGS) shputils.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shptreedump.exe: shptreedump.c $(LINK_LIB) $(CC) $(CFLAGS) shptreedump.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpdiff.exe: shpdiff.c $(LINK_LIB) $(CC) $(CFLAGS) shpdiff.c $(LINK_LIB) $(LINKOPT) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 clean: -del *.obj -del *.exe -del *.lib -del *.dll -del *.manifest $(STATIC_LIB): $(OBJ) lib /nologo /out:$(STATIC_LIB) $(OBJ) $(IMPORT_LIB): $(DLLNAME) $(DLLNAME): $(OBJ) link /nologo /dll /out:$(DLLNAME) /implib:$(IMPORT_LIB) $(OBJ) if exist $(DLLNAME).manifest mt /nologo -manifest $(DLLNAME).manifest -outputresource:$(DLLNAME);2 shapelib-1.3.0/shpopen.c0000640042715500116100000025637011707630635014464 0ustar warmerdameng/****************************************************************************** * $Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Implementation of core Shapefile read/write functions. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1999, 2001, 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: shpopen.c,v $ * Revision 1.73 2012-01-24 22:33:01 fwarmerdam * fix memory leak on failure to open .shp (gdal #4410) * * Revision 1.72 2011-12-11 22:45:28 fwarmerdam * fix failure return from SHPOpenLL. * * Revision 1.71 2011-09-15 03:33:58 fwarmerdam * fix missing cast (#2344) * * Revision 1.70 2011-07-24 05:59:25 fwarmerdam * minimize use of CPLError in favor of SAHooks.Error() * * Revision 1.69 2011-07-24 03:24:22 fwarmerdam * fix memory leaks in error cases creating shapefiles (#2061) * * Revision 1.68 2010-08-27 23:42:52 fwarmerdam * add SHPAPI_CALL attribute in code * * Revision 1.67 2010-07-01 08:15:48 fwarmerdam * do not error out on an object with zero vertices * * Revision 1.66 2010-07-01 07:58:57 fwarmerdam * minor cleanup of error handling * * Revision 1.65 2010-07-01 07:27:13 fwarmerdam * white space formatting adjustments * * Revision 1.64 2010-01-28 11:34:34 fwarmerdam * handle the shape file length limits more gracefully (#3236) * * Revision 1.63 2010-01-28 04:04:40 fwarmerdam * improve numerical accuracy of SHPRewind() algs (gdal #3363) * * Revision 1.62 2010-01-17 05:34:13 fwarmerdam * Remove asserts on x/y being null (#2148). * * Revision 1.61 2010-01-16 05:07:42 fwarmerdam * allow 0/nulls in shpcreateobject (#2148) * * Revision 1.60 2009-09-17 20:50:02 bram * on Win32, define snprintf as alias to _snprintf * * Revision 1.59 2008-03-14 05:25:31 fwarmerdam * Correct crash on buggy geometries (gdal #2218) * * Revision 1.58 2008/01/08 23:28:26 bram * on line 2095, use a float instead of a double to avoid a compiler warning * * Revision 1.57 2007/12/06 07:00:25 fwarmerdam * dbfopen now using SAHooks for fileio * * Revision 1.56 2007/12/04 20:37:56 fwarmerdam * preliminary implementation of hooks api for io and errors * * Revision 1.55 2007/11/21 22:39:56 fwarmerdam * close shx file in readonly mode (GDAL #1956) * * Revision 1.54 2007/11/15 00:12:47 mloskot * Backported recent changes from GDAL (Ticket #1415) to Shapelib. * * Revision 1.53 2007/11/14 22:31:08 fwarmerdam * checks after mallocs to detect for corrupted/voluntary broken shapefiles. * http://trac.osgeo.org/gdal/ticket/1991 * * Revision 1.52 2007/06/21 15:58:33 fwarmerdam * fix for SHPRewindObject when rings touch at one vertex (gdal #976) * * Revision 1.51 2006/09/04 15:24:01 fwarmerdam * Fixed up log message for 1.49. * * Revision 1.50 2006/09/04 15:21:39 fwarmerdam * fix of last fix * * Revision 1.49 2006/09/04 15:21:00 fwarmerdam * MLoskot: Added stronger test of Shapefile reading failures, e.g. truncated * files. The problem was discovered by Tim Sutton and reported here * https://svn.qgis.org/trac/ticket/200 * * Revision 1.48 2006/01/26 15:07:32 fwarmerdam * add bMeasureIsUsed flag from Craig Bruce: Bug 1249 * * Revision 1.47 2006/01/04 20:07:23 fwarmerdam * In SHPWriteObject() make sure that the record length is updated * when rewriting an existing record. * * Revision 1.46 2005/02/11 17:17:46 fwarmerdam * added panPartStart[0] validation * * Revision 1.45 2004/09/26 20:09:48 fwarmerdam * const correctness changes * * Revision 1.44 2003/12/29 00:18:39 fwarmerdam * added error checking for failed IO and optional CPL error reporting * * Revision 1.43 2003/12/01 16:20:08 warmerda * be careful of zero vertex shapes * * Revision 1.42 2003/12/01 14:58:27 warmerda * added degenerate object check in SHPRewindObject() * * Revision 1.41 2003/07/08 15:22:43 warmerda * avoid warning * * Revision 1.40 2003/04/21 18:30:37 warmerda * added header write/update public methods * * Revision 1.39 2002/08/26 06:46:56 warmerda * avoid c++ comments * * Revision 1.38 2002/05/07 16:43:39 warmerda * Removed debugging printf. * * Revision 1.37 2002/04/10 17:35:22 warmerda * fixed bug in ring reversal code * * Revision 1.36 2002/04/10 16:59:54 warmerda * added SHPRewindObject * * Revision 1.35 2001/12/07 15:10:44 warmerda * fix if .shx fails to open * * Revision 1.34 2001/11/01 16:29:55 warmerda * move pabyRec into SHPInfo for thread safety * * Revision 1.33 2001/07/03 12:18:15 warmerda * Improved cleanup if SHX not found, provied by Riccardo Cohen. * * Revision 1.32 2001/06/22 01:58:07 warmerda * be more careful about establishing initial bounds in face of NULL shapes * * Revision 1.31 2001/05/31 19:35:29 warmerda * added support for writing null shapes * * Revision 1.30 2001/05/28 12:46:29 warmerda * Add some checking on reasonableness of record count when opening. * * Revision 1.29 2001/05/23 13:36:52 warmerda * added use of SHPAPI_CALL * * Revision 1.28 2001/02/06 22:25:06 warmerda * fixed memory leaks when SHPOpen() fails * * Revision 1.27 2000/07/18 15:21:33 warmerda * added better enforcement of -1 for append in SHPWriteObject * * Revision 1.26 2000/02/16 16:03:51 warmerda * added null shape support * * Revision 1.25 1999/12/15 13:47:07 warmerda * Fixed record size settings in .shp file (was 4 words too long) * Added stdlib.h. * * Revision 1.24 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.23 1999/07/27 00:53:46 warmerda * added support for rewriting shapes * * Revision 1.22 1999/06/11 19:19:11 warmerda * Cleanup pabyRec static buffer on SHPClose(). * * Revision 1.21 1999/06/02 14:57:56 kshih * Remove unused variables * * Revision 1.20 1999/04/19 21:04:17 warmerda * Fixed syntax error. * * Revision 1.19 1999/04/19 21:01:57 warmerda * Force access string to binary in SHPOpen(). * * Revision 1.18 1999/04/01 18:48:07 warmerda * Try upper case extensions if lower case doesn't work. * * Revision 1.17 1998/12/31 15:29:39 warmerda * Disable writing measure values to multipatch objects if * DISABLE_MULTIPATCH_MEASURE is defined. * * Revision 1.16 1998/12/16 05:14:33 warmerda * Added support to write MULTIPATCH. Fixed reading Z coordinate of * MULTIPATCH. Fixed record size written for all feature types. * * Revision 1.15 1998/12/03 16:35:29 warmerda * r+b is proper binary access string, not rb+. * * Revision 1.14 1998/12/03 15:47:56 warmerda * Fixed setting of nVertices in SHPCreateObject(). * * Revision 1.13 1998/12/03 15:33:54 warmerda * Made SHPCalculateExtents() separately callable. * * Revision 1.12 1998/11/11 20:01:50 warmerda * Fixed bug writing ArcM/Z, and PolygonM/Z for big endian machines. * * Revision 1.11 1998/11/09 20:56:44 warmerda * Fixed up handling of file wide bounds. * * Revision 1.10 1998/11/09 20:18:51 warmerda * Converted to support 3D shapefiles, and use of SHPObject. * * Revision 1.9 1998/02/24 15:09:05 warmerda * Fixed memory leak. * * Revision 1.8 1997/12/04 15:40:29 warmerda * Fixed byte swapping of record number, and record length fields in the * .shp file. * * Revision 1.7 1995/10/21 03:15:58 warmerda * Added support for binary file access, the magic cookie 9997 * and tried to improve the int32 selection logic for 16bit systems. * * Revision 1.6 1995/09/04 04:19:41 warmerda * Added fix for file bounds. * * Revision 1.5 1995/08/25 15:16:44 warmerda * Fixed a couple of problems with big endian systems ... one with bounds * and the other with multipart polygons. * * Revision 1.4 1995/08/24 18:10:17 warmerda * Switch to use SfRealloc() to avoid problems with pre-ANSI realloc() * functions (such as on the Sun). * * Revision 1.3 1995/08/23 02:23:15 warmerda * Added support for reading bounds, and fixed up problems in setting the * file wide bounds. * * Revision 1.2 1995/08/04 03:16:57 warmerda * Added header. * */ #include "shapefil.h" #include #include #include #include #include #include SHP_CVSID("$Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $") typedef unsigned char uchar; #if UINT_MAX == 65535 typedef unsigned long int32; #else typedef unsigned int int32; #endif #ifndef FALSE # define FALSE 0 # define TRUE 1 #endif #define ByteCopy( a, b, c ) memcpy( b, a, c ) #ifndef MAX # define MIN(a,b) ((ab) ? a : b) #endif #if defined(WIN32) || defined(_WIN32) # ifndef snprintf # define snprintf _snprintf # endif #endif static int bBigEndian; /************************************************************************/ /* SwapWord() */ /* */ /* Swap a 2, 4 or 8 byte word. */ /************************************************************************/ static void SwapWord( int length, void * wordP ) { int i; uchar temp; for( i=0; i < length/2; i++ ) { temp = ((uchar *) wordP)[i]; ((uchar *)wordP)[i] = ((uchar *) wordP)[length-i-1]; ((uchar *) wordP)[length-i-1] = temp; } } /************************************************************************/ /* SfRealloc() */ /* */ /* A realloc cover function that will access a NULL pointer as */ /* a valid input. */ /************************************************************************/ static void * SfRealloc( void * pMem, int nNewSize ) { if( pMem == NULL ) return( (void *) malloc(nNewSize) ); else return( (void *) realloc(pMem,nNewSize) ); } /************************************************************************/ /* SHPWriteHeader() */ /* */ /* Write out a header for the .shp and .shx files as well as the */ /* contents of the index (.shx) file. */ /************************************************************************/ void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP ) { uchar abyHeader[100]; int i; int32 i32; double dValue; int32 *panSHX; if (psSHP->fpSHX == NULL) { psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed"); return; } /* -------------------------------------------------------------------- */ /* Prepare header block for .shp file. */ /* -------------------------------------------------------------------- */ for( i = 0; i < 100; i++ ) abyHeader[i] = 0; abyHeader[2] = 0x27; /* magic cookie */ abyHeader[3] = 0x0a; i32 = psSHP->nFileSize/2; /* file size */ ByteCopy( &i32, abyHeader+24, 4 ); if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); i32 = 1000; /* version */ ByteCopy( &i32, abyHeader+28, 4 ); if( bBigEndian ) SwapWord( 4, abyHeader+28 ); i32 = psSHP->nShapeType; /* shape type */ ByteCopy( &i32, abyHeader+32, 4 ); if( bBigEndian ) SwapWord( 4, abyHeader+32 ); dValue = psSHP->adBoundsMin[0]; /* set bounds */ ByteCopy( &dValue, abyHeader+36, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+36 ); dValue = psSHP->adBoundsMin[1]; ByteCopy( &dValue, abyHeader+44, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+44 ); dValue = psSHP->adBoundsMax[0]; ByteCopy( &dValue, abyHeader+52, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+52 ); dValue = psSHP->adBoundsMax[1]; ByteCopy( &dValue, abyHeader+60, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+60 ); dValue = psSHP->adBoundsMin[2]; /* z */ ByteCopy( &dValue, abyHeader+68, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+68 ); dValue = psSHP->adBoundsMax[2]; ByteCopy( &dValue, abyHeader+76, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+76 ); dValue = psSHP->adBoundsMin[3]; /* m */ ByteCopy( &dValue, abyHeader+84, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+84 ); dValue = psSHP->adBoundsMax[3]; ByteCopy( &dValue, abyHeader+92, 8 ); if( bBigEndian ) SwapWord( 8, abyHeader+92 ); /* -------------------------------------------------------------------- */ /* Write .shp file header. */ /* -------------------------------------------------------------------- */ if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0 || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 ) { psSHP->sHooks.Error( "Failure writing .shp header" ); return; } /* -------------------------------------------------------------------- */ /* Prepare, and write .shx file header. */ /* -------------------------------------------------------------------- */ i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */ ByteCopy( &i32, abyHeader+24, 4 ); if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0 || psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 ) { psSHP->sHooks.Error( "Failure writing .shx header" ); return; } /* -------------------------------------------------------------------- */ /* Write out the .shx contents. */ /* -------------------------------------------------------------------- */ panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords); for( i = 0; i < psSHP->nRecords; i++ ) { panSHX[i*2 ] = psSHP->panRecOffset[i]/2; panSHX[i*2+1] = psSHP->panRecSize[i]/2; if( !bBigEndian ) SwapWord( 4, panSHX+i*2 ); if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 ); } if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX ) != psSHP->nRecords ) { psSHP->sHooks.Error( "Failure writing .shx contents" ); } free( panSHX ); /* -------------------------------------------------------------------- */ /* Flush to disk. */ /* -------------------------------------------------------------------- */ psSHP->sHooks.FFlush( psSHP->fpSHP ); psSHP->sHooks.FFlush( psSHP->fpSHX ); } /************************************************************************/ /* SHPOpen() */ /************************************************************************/ SHPHandle SHPAPI_CALL SHPOpen( const char * pszLayer, const char * pszAccess ) { SAHooks sHooks; SASetupDefaultHooks( &sHooks ); return SHPOpenLL( pszLayer, pszAccess, &sHooks ); } /************************************************************************/ /* SHPOpen() */ /* */ /* Open the .shp and .shx files based on the basename of the */ /* files or either file name. */ /************************************************************************/ SHPHandle SHPAPI_CALL SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks ) { char *pszFullname, *pszBasename; SHPHandle psSHP; uchar *pabyBuf; int i; double dValue; /* -------------------------------------------------------------------- */ /* Ensure the access string is one of the legal ones. We */ /* ensure the result string indicates binary to avoid common */ /* problems on Windows. */ /* -------------------------------------------------------------------- */ if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0 || strcmp(pszAccess,"r+") == 0 ) pszAccess = "r+b"; else pszAccess = "rb"; /* -------------------------------------------------------------------- */ /* Establish the byte order on this machine. */ /* -------------------------------------------------------------------- */ i = 1; if( *((uchar *) &i) == 1 ) bBigEndian = FALSE; else bBigEndian = TRUE; /* -------------------------------------------------------------------- */ /* Initialize the info structure. */ /* -------------------------------------------------------------------- */ psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1); psSHP->bUpdated = FALSE; memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) ); /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszLayer)+5); strcpy( pszBasename, pszLayer ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; /* -------------------------------------------------------------------- */ /* Open the .shp and .shx files. Note that files pulled from */ /* a PC to Unix with upper case filenames won't work! */ /* -------------------------------------------------------------------- */ pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.shp", pszBasename ) ; psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess ); if( psSHP->fpSHP == NULL ) { sprintf( pszFullname, "%s.SHP", pszBasename ); psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess ); } if( psSHP->fpSHP == NULL ) { char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256); sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.", pszBasename, pszBasename ); psHooks->Error( pszMessage ); free( pszMessage ); free( psSHP ); free( pszBasename ); free( pszFullname ); return NULL; } sprintf( pszFullname, "%s.shx", pszBasename ); psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess ); if( psSHP->fpSHX == NULL ) { sprintf( pszFullname, "%s.SHX", pszBasename ); psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess ); } if( psSHP->fpSHX == NULL ) { char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256); sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.", pszBasename, pszBasename ); psHooks->Error( pszMessage ); free( pszMessage ); psSHP->sHooks.FClose( psSHP->fpSHP ); free( psSHP ); free( pszBasename ); free( pszFullname ); return( NULL ); } free( pszFullname ); free( pszBasename ); /* -------------------------------------------------------------------- */ /* Read the file size from the SHP file. */ /* -------------------------------------------------------------------- */ pabyBuf = (uchar *) malloc(100); psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP ); psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256 + (unsigned int)pabyBuf[25] * 256 * 256 + (unsigned int)pabyBuf[26] * 256 + (unsigned int)pabyBuf[27]) * 2; /* -------------------------------------------------------------------- */ /* Read SHX file Header info */ /* -------------------------------------------------------------------- */ if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1 || pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 || (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) ) { psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." ); psSHP->sHooks.FClose( psSHP->fpSHP ); psSHP->sHooks.FClose( psSHP->fpSHX ); free( psSHP ); return( NULL ); } psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256 + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256; psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8; psSHP->nShapeType = pabyBuf[32]; if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 ) { char szError[200]; sprintf( szError, "Record count in .shp header is %d, which seems\n" "unreasonable. Assuming header is corrupt.", psSHP->nRecords ); psSHP->sHooks.Error( szError ); psSHP->sHooks.FClose( psSHP->fpSHP ); psSHP->sHooks.FClose( psSHP->fpSHX ); free( psSHP ); free(pabyBuf); return( NULL ); } /* -------------------------------------------------------------------- */ /* Read the bounds. */ /* -------------------------------------------------------------------- */ if( bBigEndian ) SwapWord( 8, pabyBuf+36 ); memcpy( &dValue, pabyBuf+36, 8 ); psSHP->adBoundsMin[0] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+44 ); memcpy( &dValue, pabyBuf+44, 8 ); psSHP->adBoundsMin[1] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+52 ); memcpy( &dValue, pabyBuf+52, 8 ); psSHP->adBoundsMax[0] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+60 ); memcpy( &dValue, pabyBuf+60, 8 ); psSHP->adBoundsMax[1] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */ memcpy( &dValue, pabyBuf+68, 8 ); psSHP->adBoundsMin[2] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+76 ); memcpy( &dValue, pabyBuf+76, 8 ); psSHP->adBoundsMax[2] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */ memcpy( &dValue, pabyBuf+84, 8 ); psSHP->adBoundsMin[3] = dValue; if( bBigEndian ) SwapWord( 8, pabyBuf+92 ); memcpy( &dValue, pabyBuf+92, 8 ); psSHP->adBoundsMax[3] = dValue; free( pabyBuf ); /* -------------------------------------------------------------------- */ /* Read the .shx file to get the offsets to each record in */ /* the .shp file. */ /* -------------------------------------------------------------------- */ psSHP->nMaxRecords = psSHP->nRecords; psSHP->panRecOffset = (unsigned int *) malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) ); psSHP->panRecSize = (unsigned int *) malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) ); pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) ); if (psSHP->panRecOffset == NULL || psSHP->panRecSize == NULL || pabyBuf == NULL) { char szError[200]; sprintf(szError, "Not enough memory to allocate requested memory (nRecords=%d).\n" "Probably broken SHP file", psSHP->nRecords ); psSHP->sHooks.Error( szError ); psSHP->sHooks.FClose( psSHP->fpSHP ); psSHP->sHooks.FClose( psSHP->fpSHX ); if (psSHP->panRecOffset) free( psSHP->panRecOffset ); if (psSHP->panRecSize) free( psSHP->panRecSize ); if (pabyBuf) free( pabyBuf ); free( psSHP ); return( NULL ); } if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) != psSHP->nRecords ) { char szError[200]; sprintf( szError, "Failed to read all values for %d records in .shx file.", psSHP->nRecords ); psSHP->sHooks.Error( szError ); /* SHX is short or unreadable for some reason. */ psSHP->sHooks.FClose( psSHP->fpSHP ); psSHP->sHooks.FClose( psSHP->fpSHX ); free( psSHP->panRecOffset ); free( psSHP->panRecSize ); free( pabyBuf ); free( psSHP ); return( NULL ); } /* In read-only mode, we can close the SHX now */ if (strcmp(pszAccess, "rb") == 0) { psSHP->sHooks.FClose( psSHP->fpSHX ); psSHP->fpSHX = NULL; } for( i = 0; i < psSHP->nRecords; i++ ) { int32 nOffset, nLength; memcpy( &nOffset, pabyBuf + i * 8, 4 ); if( !bBigEndian ) SwapWord( 4, &nOffset ); memcpy( &nLength, pabyBuf + i * 8 + 4, 4 ); if( !bBigEndian ) SwapWord( 4, &nLength ); psSHP->panRecOffset[i] = nOffset*2; psSHP->panRecSize[i] = nLength*2; } free( pabyBuf ); return( psSHP ); } /************************************************************************/ /* SHPClose() */ /* */ /* Close the .shp and .shx files. */ /************************************************************************/ void SHPAPI_CALL SHPClose(SHPHandle psSHP ) { if( psSHP == NULL ) return; /* -------------------------------------------------------------------- */ /* Update the header if we have modified anything. */ /* -------------------------------------------------------------------- */ if( psSHP->bUpdated ) SHPWriteHeader( psSHP ); /* -------------------------------------------------------------------- */ /* Free all resources, and close files. */ /* -------------------------------------------------------------------- */ free( psSHP->panRecOffset ); free( psSHP->panRecSize ); if ( psSHP->fpSHX != NULL) psSHP->sHooks.FClose( psSHP->fpSHX ); psSHP->sHooks.FClose( psSHP->fpSHP ); if( psSHP->pabyRec != NULL ) { free( psSHP->pabyRec ); } free( psSHP ); } /************************************************************************/ /* SHPGetInfo() */ /* */ /* Fetch general information about the shape file. */ /************************************************************************/ void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int * pnEntities, int * pnShapeType, double * padfMinBound, double * padfMaxBound ) { int i; if( psSHP == NULL ) return; if( pnEntities != NULL ) *pnEntities = psSHP->nRecords; if( pnShapeType != NULL ) *pnShapeType = psSHP->nShapeType; for( i = 0; i < 4; i++ ) { if( padfMinBound != NULL ) padfMinBound[i] = psSHP->adBoundsMin[i]; if( padfMaxBound != NULL ) padfMaxBound[i] = psSHP->adBoundsMax[i]; } } /************************************************************************/ /* SHPCreate() */ /* */ /* Create a new shape file and return a handle to the open */ /* shape file with read/write access. */ /************************************************************************/ SHPHandle SHPAPI_CALL SHPCreate( const char * pszLayer, int nShapeType ) { SAHooks sHooks; SASetupDefaultHooks( &sHooks ); return SHPCreateLL( pszLayer, nShapeType, &sHooks ); } /************************************************************************/ /* SHPCreate() */ /* */ /* Create a new shape file and return a handle to the open */ /* shape file with read/write access. */ /************************************************************************/ SHPHandle SHPAPI_CALL SHPCreateLL( const char * pszLayer, int nShapeType, SAHooks *psHooks ) { char *pszBasename = NULL, *pszFullname = NULL; int i; SAFile fpSHP = NULL, fpSHX = NULL; uchar abyHeader[100]; int32 i32; double dValue; /* -------------------------------------------------------------------- */ /* Establish the byte order on this system. */ /* -------------------------------------------------------------------- */ i = 1; if( *((uchar *) &i) == 1 ) bBigEndian = FALSE; else bBigEndian = TRUE; /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszLayer)+5); strcpy( pszBasename, pszLayer ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; /* -------------------------------------------------------------------- */ /* Open the two files so we can write their headers. */ /* -------------------------------------------------------------------- */ pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.shp", pszBasename ); fpSHP = psHooks->FOpen(pszFullname, "wb" ); if( fpSHP == NULL ) { psHooks->Error( "Failed to create file .shp file." ); goto error; } sprintf( pszFullname, "%s.shx", pszBasename ); fpSHX = psHooks->FOpen(pszFullname, "wb" ); if( fpSHX == NULL ) { psHooks->Error( "Failed to create file .shx file." ); goto error; } free( pszFullname ); pszFullname = NULL; free( pszBasename ); pszBasename = NULL; /* -------------------------------------------------------------------- */ /* Prepare header block for .shp file. */ /* -------------------------------------------------------------------- */ for( i = 0; i < 100; i++ ) abyHeader[i] = 0; abyHeader[2] = 0x27; /* magic cookie */ abyHeader[3] = 0x0a; i32 = 50; /* file size */ ByteCopy( &i32, abyHeader+24, 4 ); if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); i32 = 1000; /* version */ ByteCopy( &i32, abyHeader+28, 4 ); if( bBigEndian ) SwapWord( 4, abyHeader+28 ); i32 = nShapeType; /* shape type */ ByteCopy( &i32, abyHeader+32, 4 ); if( bBigEndian ) SwapWord( 4, abyHeader+32 ); dValue = 0.0; /* set bounds */ ByteCopy( &dValue, abyHeader+36, 8 ); ByteCopy( &dValue, abyHeader+44, 8 ); ByteCopy( &dValue, abyHeader+52, 8 ); ByteCopy( &dValue, abyHeader+60, 8 ); /* -------------------------------------------------------------------- */ /* Write .shp file header. */ /* -------------------------------------------------------------------- */ if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 ) { psHooks->Error( "Failed to write .shp header." ); goto error; } /* -------------------------------------------------------------------- */ /* Prepare, and write .shx file header. */ /* -------------------------------------------------------------------- */ i32 = 50; /* file size */ ByteCopy( &i32, abyHeader+24, 4 ); if( !bBigEndian ) SwapWord( 4, abyHeader+24 ); if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 ) { psHooks->Error( "Failed to write .shx header." ); goto error; } /* -------------------------------------------------------------------- */ /* Close the files, and then open them as regular existing files. */ /* -------------------------------------------------------------------- */ psHooks->FClose( fpSHP ); psHooks->FClose( fpSHX ); return( SHPOpenLL( pszLayer, "r+b", psHooks ) ); error: if (pszFullname) free(pszFullname); if (pszBasename) free(pszBasename); if (fpSHP) psHooks->FClose( fpSHP ); if (fpSHX) psHooks->FClose( fpSHX ); return NULL; } /************************************************************************/ /* _SHPSetBounds() */ /* */ /* Compute a bounds rectangle for a shape, and set it into the */ /* indicated location in the record. */ /************************************************************************/ static void _SHPSetBounds( uchar * pabyRec, SHPObject * psShape ) { ByteCopy( &(psShape->dfXMin), pabyRec + 0, 8 ); ByteCopy( &(psShape->dfYMin), pabyRec + 8, 8 ); ByteCopy( &(psShape->dfXMax), pabyRec + 16, 8 ); ByteCopy( &(psShape->dfYMax), pabyRec + 24, 8 ); if( bBigEndian ) { SwapWord( 8, pabyRec + 0 ); SwapWord( 8, pabyRec + 8 ); SwapWord( 8, pabyRec + 16 ); SwapWord( 8, pabyRec + 24 ); } } /************************************************************************/ /* SHPComputeExtents() */ /* */ /* Recompute the extents of a shape. Automatically done by */ /* SHPCreateObject(). */ /************************************************************************/ void SHPAPI_CALL SHPComputeExtents( SHPObject * psObject ) { int i; /* -------------------------------------------------------------------- */ /* Build extents for this object. */ /* -------------------------------------------------------------------- */ if( psObject->nVertices > 0 ) { psObject->dfXMin = psObject->dfXMax = psObject->padfX[0]; psObject->dfYMin = psObject->dfYMax = psObject->padfY[0]; psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0]; psObject->dfMMin = psObject->dfMMax = psObject->padfM[0]; } for( i = 0; i < psObject->nVertices; i++ ) { psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]); psObject->dfYMin = MIN(psObject->dfYMin, psObject->padfY[i]); psObject->dfZMin = MIN(psObject->dfZMin, psObject->padfZ[i]); psObject->dfMMin = MIN(psObject->dfMMin, psObject->padfM[i]); psObject->dfXMax = MAX(psObject->dfXMax, psObject->padfX[i]); psObject->dfYMax = MAX(psObject->dfYMax, psObject->padfY[i]); psObject->dfZMax = MAX(psObject->dfZMax, psObject->padfZ[i]); psObject->dfMMax = MAX(psObject->dfMMax, psObject->padfM[i]); } } /************************************************************************/ /* SHPCreateObject() */ /* */ /* Create a shape object. It should be freed with */ /* SHPDestroyObject(). */ /************************************************************************/ SHPObject SHPAPI_CALL1(*) SHPCreateObject( int nSHPType, int nShapeId, int nParts, const int * panPartStart, const int * panPartType, int nVertices, const double *padfX, const double *padfY, const double * padfZ, const double * padfM ) { SHPObject *psObject; int i, bHasM, bHasZ; psObject = (SHPObject *) calloc(1,sizeof(SHPObject)); psObject->nSHPType = nSHPType; psObject->nShapeId = nShapeId; psObject->bMeasureIsUsed = FALSE; /* -------------------------------------------------------------------- */ /* Establish whether this shape type has M, and Z values. */ /* -------------------------------------------------------------------- */ if( nSHPType == SHPT_ARCM || nSHPType == SHPT_POINTM || nSHPType == SHPT_POLYGONM || nSHPType == SHPT_MULTIPOINTM ) { bHasM = TRUE; bHasZ = FALSE; } else if( nSHPType == SHPT_ARCZ || nSHPType == SHPT_POINTZ || nSHPType == SHPT_POLYGONZ || nSHPType == SHPT_MULTIPOINTZ || nSHPType == SHPT_MULTIPATCH ) { bHasM = TRUE; bHasZ = TRUE; } else { bHasM = FALSE; bHasZ = FALSE; } /* -------------------------------------------------------------------- */ /* Capture parts. Note that part type is optional, and */ /* defaults to ring. */ /* -------------------------------------------------------------------- */ if( nSHPType == SHPT_ARC || nSHPType == SHPT_POLYGON || nSHPType == SHPT_ARCM || nSHPType == SHPT_POLYGONM || nSHPType == SHPT_ARCZ || nSHPType == SHPT_POLYGONZ || nSHPType == SHPT_MULTIPATCH ) { psObject->nParts = MAX(1,nParts); psObject->panPartStart = (int *) calloc(sizeof(int), psObject->nParts); psObject->panPartType = (int *) malloc(sizeof(int) * psObject->nParts); psObject->panPartStart[0] = 0; psObject->panPartType[0] = SHPP_RING; for( i = 0; i < nParts; i++ ) { if( psObject->panPartStart != NULL ) psObject->panPartStart[i] = panPartStart[i]; if( panPartType != NULL ) psObject->panPartType[i] = panPartType[i]; else psObject->panPartType[i] = SHPP_RING; } if( psObject->panPartStart[0] != 0 ) psObject->panPartStart[0] = 0; } /* -------------------------------------------------------------------- */ /* Capture vertices. Note that X, Y, Z and M are optional. */ /* -------------------------------------------------------------------- */ if( nVertices > 0 ) { psObject->padfX = (double *) calloc(sizeof(double),nVertices); psObject->padfY = (double *) calloc(sizeof(double),nVertices); psObject->padfZ = (double *) calloc(sizeof(double),nVertices); psObject->padfM = (double *) calloc(sizeof(double),nVertices); for( i = 0; i < nVertices; i++ ) { if( padfX != NULL ) psObject->padfX[i] = padfX[i]; if( padfY != NULL ) psObject->padfY[i] = padfY[i]; if( padfZ != NULL && bHasZ ) psObject->padfZ[i] = padfZ[i]; if( padfM != NULL && bHasM ) psObject->padfM[i] = padfM[i]; } if( padfM != NULL && bHasM ) psObject->bMeasureIsUsed = TRUE; } /* -------------------------------------------------------------------- */ /* Compute the extents. */ /* -------------------------------------------------------------------- */ psObject->nVertices = nVertices; SHPComputeExtents( psObject ); return( psObject ); } /************************************************************************/ /* SHPCreateSimpleObject() */ /* */ /* Create a simple (common) shape object. Destroy with */ /* SHPDestroyObject(). */ /************************************************************************/ SHPObject SHPAPI_CALL1(*) SHPCreateSimpleObject( int nSHPType, int nVertices, const double * padfX, const double * padfY, const double * padfZ ) { return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL, nVertices, padfX, padfY, padfZ, NULL ) ); } /************************************************************************/ /* SHPWriteObject() */ /* */ /* Write out the vertices of a new structure. Note that it is */ /* only possible to write vertices at the end of the file. */ /************************************************************************/ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) { unsigned int nRecordOffset, nRecordSize=0; int i; uchar *pabyRec; int32 i32; psSHP->bUpdated = TRUE; /* -------------------------------------------------------------------- */ /* Ensure that shape object matches the type of the file it is */ /* being written to. */ /* -------------------------------------------------------------------- */ assert( psObject->nSHPType == psSHP->nShapeType || psObject->nSHPType == SHPT_NULL ); /* -------------------------------------------------------------------- */ /* Ensure that -1 is used for appends. Either blow an */ /* assertion, or if they are disabled, set the shapeid to -1 */ /* for appends. */ /* -------------------------------------------------------------------- */ assert( nShapeId == -1 || (nShapeId >= 0 && nShapeId < psSHP->nRecords) ); if( nShapeId != -1 && nShapeId >= psSHP->nRecords ) nShapeId = -1; /* -------------------------------------------------------------------- */ /* Add the new entity to the in memory index. */ /* -------------------------------------------------------------------- */ if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords ) { psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100); psSHP->panRecOffset = (unsigned int *) SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords ); psSHP->panRecSize = (unsigned int *) SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * psSHP->nMaxRecords ); } /* -------------------------------------------------------------------- */ /* Initialize record. */ /* -------------------------------------------------------------------- */ pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double) + psObject->nParts * 8 + 128); /* -------------------------------------------------------------------- */ /* Extract vertices for a Polygon or Arc. */ /* -------------------------------------------------------------------- */ if( psObject->nSHPType == SHPT_POLYGON || psObject->nSHPType == SHPT_POLYGONZ || psObject->nSHPType == SHPT_POLYGONM || psObject->nSHPType == SHPT_ARC || psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_ARCM || psObject->nSHPType == SHPT_MULTIPATCH ) { int32 nPoints, nParts; int i; nPoints = psObject->nVertices; nParts = psObject->nParts; _SHPSetBounds( pabyRec + 12, psObject ); if( bBigEndian ) SwapWord( 4, &nPoints ); if( bBigEndian ) SwapWord( 4, &nParts ); ByteCopy( &nPoints, pabyRec + 40 + 8, 4 ); ByteCopy( &nParts, pabyRec + 36 + 8, 4 ); nRecordSize = 52; /* * Write part start positions. */ ByteCopy( psObject->panPartStart, pabyRec + 44 + 8, 4 * psObject->nParts ); for( i = 0; i < psObject->nParts; i++ ) { if( bBigEndian ) SwapWord( 4, pabyRec + 44 + 8 + 4*i ); nRecordSize += 4; } /* * Write multipatch part types if needed. */ if( psObject->nSHPType == SHPT_MULTIPATCH ) { memcpy( pabyRec + nRecordSize, psObject->panPartType, 4*psObject->nParts ); for( i = 0; i < psObject->nParts; i++ ) { if( bBigEndian ) SwapWord( 4, pabyRec + nRecordSize ); nRecordSize += 4; } } /* * Write the (x,y) vertex values. */ for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfX + i, pabyRec + nRecordSize, 8 ); ByteCopy( psObject->padfY + i, pabyRec + nRecordSize + 8, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize + 8 ); nRecordSize += 2 * 8; } /* * Write the Z coordinates (if any). */ if( psObject->nSHPType == SHPT_POLYGONZ || psObject->nSHPType == SHPT_ARCZ || psObject->nSHPType == SHPT_MULTIPATCH ) { ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } } /* * Write the M values, if any. */ if( psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_POLYGONM || psObject->nSHPType == SHPT_ARCM #ifndef DISABLE_MULTIPATCH_MEASURE || psObject->nSHPType == SHPT_MULTIPATCH #endif || psObject->nSHPType == SHPT_POLYGONZ || psObject->nSHPType == SHPT_ARCZ) ) { ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } } } /* -------------------------------------------------------------------- */ /* Extract vertices for a MultiPoint. */ /* -------------------------------------------------------------------- */ else if( psObject->nSHPType == SHPT_MULTIPOINT || psObject->nSHPType == SHPT_MULTIPOINTZ || psObject->nSHPType == SHPT_MULTIPOINTM ) { int32 nPoints; int i; nPoints = psObject->nVertices; _SHPSetBounds( pabyRec + 12, psObject ); if( bBigEndian ) SwapWord( 4, &nPoints ); ByteCopy( &nPoints, pabyRec + 44, 4 ); for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 ); ByteCopy( psObject->padfY + i, pabyRec + 48 + i*16 + 8, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 ); if( bBigEndian ) SwapWord( 8, pabyRec + 48 + i*16 + 8 ); } nRecordSize = 48 + 16 * psObject->nVertices; if( psObject->nSHPType == SHPT_MULTIPOINTZ ) { ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } } if( psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_MULTIPOINTZ || psObject->nSHPType == SHPT_MULTIPOINTM) ) { ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; for( i = 0; i < psObject->nVertices; i++ ) { ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } } } /* -------------------------------------------------------------------- */ /* Write point. */ /* -------------------------------------------------------------------- */ else if( psObject->nSHPType == SHPT_POINT || psObject->nSHPType == SHPT_POINTZ || psObject->nSHPType == SHPT_POINTM ) { ByteCopy( psObject->padfX, pabyRec + 12, 8 ); ByteCopy( psObject->padfY, pabyRec + 20, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + 12 ); if( bBigEndian ) SwapWord( 8, pabyRec + 20 ); nRecordSize = 28; if( psObject->nSHPType == SHPT_POINTZ ) { ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } if( psObject->bMeasureIsUsed && (psObject->nSHPType == SHPT_POINTZ || psObject->nSHPType == SHPT_POINTM) ) { ByteCopy( psObject->padfM, pabyRec + nRecordSize, 8 ); if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize ); nRecordSize += 8; } } /* -------------------------------------------------------------------- */ /* Not much to do for null geometries. */ /* -------------------------------------------------------------------- */ else if( psObject->nSHPType == SHPT_NULL ) { nRecordSize = 12; } else { /* unknown type */ assert( FALSE ); } /* -------------------------------------------------------------------- */ /* Establish where we are going to put this record. If we are */ /* rewriting and existing record, and it will fit, then put it */ /* back where the original came from. Otherwise write at the end. */ /* -------------------------------------------------------------------- */ if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 ) { unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize; if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow { char str[128]; sprintf( str, "Failed to write shape object. " "File size cannot reach %u + %u.", psSHP->nFileSize, nRecordSize ); psSHP->sHooks.Error( str ); free( pabyRec ); return -1; } if( nShapeId == -1 ) nShapeId = psSHP->nRecords++; psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize; psSHP->panRecSize[nShapeId] = nRecordSize-8; psSHP->nFileSize += nRecordSize; } else { nRecordOffset = psSHP->panRecOffset[nShapeId]; psSHP->panRecSize[nShapeId] = nRecordSize-8; } /* -------------------------------------------------------------------- */ /* Set the shape type, record number, and record size. */ /* -------------------------------------------------------------------- */ i32 = nShapeId+1; /* record # */ if( !bBigEndian ) SwapWord( 4, &i32 ); ByteCopy( &i32, pabyRec, 4 ); i32 = (nRecordSize-8)/2; /* record size */ if( !bBigEndian ) SwapWord( 4, &i32 ); ByteCopy( &i32, pabyRec + 4, 4 ); i32 = psObject->nSHPType; /* shape type */ if( bBigEndian ) SwapWord( 4, &i32 ); ByteCopy( &i32, pabyRec + 8, 4 ); /* -------------------------------------------------------------------- */ /* Write out record. */ /* -------------------------------------------------------------------- */ if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 ) { psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." ); free( pabyRec ); return -1; } if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 ) { psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." ); free( pabyRec ); return -1; } free( pabyRec ); /* -------------------------------------------------------------------- */ /* Expand file wide bounds based on this shape. */ /* -------------------------------------------------------------------- */ if( psSHP->adBoundsMin[0] == 0.0 && psSHP->adBoundsMax[0] == 0.0 && psSHP->adBoundsMin[1] == 0.0 && psSHP->adBoundsMax[1] == 0.0 ) { if( psObject->nSHPType == SHPT_NULL || psObject->nVertices == 0 ) { psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = 0.0; psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = 0.0; psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = 0.0; psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = 0.0; } else { psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0]; psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0]; psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0]; psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0]; } } for( i = 0; i < psObject->nVertices; i++ ) { psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]); psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]); psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]); psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]); psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]); psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]); psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]); psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]); } return( nShapeId ); } /************************************************************************/ /* SHPReadObject() */ /* */ /* Read the vertices, parts, and other non-attribute information */ /* for one shape. */ /************************************************************************/ SHPObject SHPAPI_CALL1(*) SHPReadObject( SHPHandle psSHP, int hEntity ) { int nEntitySize, nRequiredSize; SHPObject *psShape; char szErrorMsg[128]; /* -------------------------------------------------------------------- */ /* Validate the record/entity number. */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity >= psSHP->nRecords ) return( NULL ); /* -------------------------------------------------------------------- */ /* Ensure our record buffer is large enough. */ /* -------------------------------------------------------------------- */ nEntitySize = psSHP->panRecSize[hEntity]+8; if( nEntitySize > psSHP->nBufSize ) { psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize); if (psSHP->pabyRec == NULL) { char szError[200]; /* Reallocate previous successfull size for following features */ psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize); sprintf( szError, "Not enough memory to allocate requested memory (nBufSize=%d). " "Probably broken SHP file", psSHP->nBufSize ); psSHP->sHooks.Error( szError ); return NULL; } /* Only set new buffer size after successfull alloc */ psSHP->nBufSize = nEntitySize; } /* In case we were not able to reallocate the buffer on a previous step */ if (psSHP->pabyRec == NULL) { return NULL; } /* -------------------------------------------------------------------- */ /* Read the record. */ /* -------------------------------------------------------------------- */ if( psSHP->sHooks.FSeek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ) != 0 ) { /* * TODO - mloskot: Consider detailed diagnostics of shape file, * for example to detect if file is truncated. */ char str[128]; sprintf( str, "Error in fseek() reading object from .shp file at offset %u", psSHP->panRecOffset[hEntity]); psSHP->sHooks.Error( str ); return NULL; } if( psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP ) != 1 ) { /* * TODO - mloskot: Consider detailed diagnostics of shape file, * for example to detect if file is truncated. */ char str[128]; sprintf( str, "Error in fread() reading object of size %u at offset %u from .shp file", nEntitySize, psSHP->panRecOffset[hEntity] ); psSHP->sHooks.Error( str ); return NULL; } /* -------------------------------------------------------------------- */ /* Allocate and minimally initialize the object. */ /* -------------------------------------------------------------------- */ psShape = (SHPObject *) calloc(1,sizeof(SHPObject)); psShape->nShapeId = hEntity; psShape->bMeasureIsUsed = FALSE; if ( 8 + 4 > nEntitySize ) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 ); if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) ); /* ==================================================================== */ /* Extract vertices for a Polygon or Arc. */ /* ==================================================================== */ if( psShape->nSHPType == SHPT_POLYGON || psShape->nSHPType == SHPT_ARC || psShape->nSHPType == SHPT_POLYGONZ || psShape->nSHPType == SHPT_POLYGONM || psShape->nSHPType == SHPT_ARCZ || psShape->nSHPType == SHPT_ARCM || psShape->nSHPType == SHPT_MULTIPATCH ) { int32 nPoints, nParts; int i, nOffset; if ( 40 + 8 + 4 > nEntitySize ) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } /* -------------------------------------------------------------------- */ /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); /* -------------------------------------------------------------------- */ /* Extract part/point count, and build vertex and part arrays */ /* to proper size. */ /* -------------------------------------------------------------------- */ memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 ); memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 ); if( bBigEndian ) SwapWord( 4, &nPoints ); if( bBigEndian ) SwapWord( 4, &nParts ); if (nPoints < 0 || nParts < 0 || nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.", hEntity, nPoints, nParts); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } /* With the previous checks on nPoints and nParts, */ /* we should not overflow here and after */ /* since 50 M * (16 + 8 + 8) = 1 600 MB */ nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints; if ( psShape->nSHPType == SHPT_POLYGONZ || psShape->nSHPType == SHPT_ARCZ || psShape->nSHPType == SHPT_MULTIPATCH ) { nRequiredSize += 16 + 8 * nPoints; } if( psShape->nSHPType == SHPT_MULTIPATCH ) { nRequiredSize += 4 * nParts; } if (nRequiredSize > nEntitySize) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.", hEntity, nPoints, nParts, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } psShape->nVertices = nPoints; psShape->padfX = (double *) calloc(nPoints,sizeof(double)); psShape->padfY = (double *) calloc(nPoints,sizeof(double)); psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); psShape->padfM = (double *) calloc(nPoints,sizeof(double)); psShape->nParts = nParts; psShape->panPartStart = (int *) calloc(nParts,sizeof(int)); psShape->panPartType = (int *) calloc(nParts,sizeof(int)); if (psShape->padfX == NULL || psShape->padfY == NULL || psShape->padfZ == NULL || psShape->padfM == NULL || psShape->panPartStart == NULL || psShape->panPartType == NULL) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. " "Probably broken SHP file", hEntity, nPoints, nParts ); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } for( i = 0; i < nParts; i++ ) psShape->panPartType[i] = SHPP_RING; /* -------------------------------------------------------------------- */ /* Copy out the part array from the record. */ /* -------------------------------------------------------------------- */ memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts ); for( i = 0; i < nParts; i++ ) { if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i ); /* We check that the offset is inside the vertex array */ if (psShape->panPartStart[i] < 0 || (psShape->panPartStart[i] >= psShape->nVertices && psShape->nVertices > 0) ) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d", hEntity, i, psShape->panPartStart[i], psShape->nVertices); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } if (i > 0 && psShape->panPartStart[i] <= psShape->panPartStart[i-1]) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d", hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } } nOffset = 44 + 8 + 4*nParts; /* -------------------------------------------------------------------- */ /* If this is a multipatch, we will also have parts types. */ /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_MULTIPATCH ) { memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts ); for( i = 0; i < nParts; i++ ) { if( bBigEndian ) SwapWord( 4, psShape->panPartType+i ); } nOffset += 4*nParts; } /* -------------------------------------------------------------------- */ /* Copy out the vertices from the record. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nPoints; i++ ) { memcpy(psShape->padfX + i, psSHP->pabyRec + nOffset + i * 16, 8 ); memcpy(psShape->padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); } nOffset += 16*nPoints; /* -------------------------------------------------------------------- */ /* If we have a Z coordinate, collect that now. */ /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_POLYGONZ || psShape->nSHPType == SHPT_ARCZ || psShape->nSHPType == SHPT_MULTIPATCH ) { memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfZ + i, psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); } nOffset += 16 + 8*nPoints; } /* -------------------------------------------------------------------- */ /* If we have a M measure value, then read it now. We assume */ /* that the measure can be present for any shape if the size is */ /* big enough, but really it will only occur for the Z shapes */ /* (options), and the M shapes. */ /* -------------------------------------------------------------------- */ if( nEntitySize >= nOffset + 16 + 8*nPoints ) { memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfM + i, psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); } psShape->bMeasureIsUsed = TRUE; } } /* ==================================================================== */ /* Extract vertices for a MultiPoint. */ /* ==================================================================== */ else if( psShape->nSHPType == SHPT_MULTIPOINT || psShape->nSHPType == SHPT_MULTIPOINTM || psShape->nSHPType == SHPT_MULTIPOINTZ ) { int32 nPoints; int i, nOffset; if ( 44 + 4 > nEntitySize ) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } memcpy( &nPoints, psSHP->pabyRec + 44, 4 ); if( bBigEndian ) SwapWord( 4, &nPoints ); if (nPoints < 0 || nPoints > 50 * 1000 * 1000) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nPoints = %d", hEntity, nPoints); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } nRequiredSize = 48 + nPoints * 16; if( psShape->nSHPType == SHPT_MULTIPOINTZ ) { nRequiredSize += 16 + nPoints * 8; } if (nRequiredSize > nEntitySize) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d", hEntity, nPoints, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } psShape->nVertices = nPoints; psShape->padfX = (double *) calloc(nPoints,sizeof(double)); psShape->padfY = (double *) calloc(nPoints,sizeof(double)); psShape->padfZ = (double *) calloc(nPoints,sizeof(double)); psShape->padfM = (double *) calloc(nPoints,sizeof(double)); if (psShape->padfX == NULL || psShape->padfY == NULL || psShape->padfZ == NULL || psShape->padfM == NULL) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. " "Probably broken SHP file", hEntity, nPoints ); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } for( i = 0; i < nPoints; i++ ) { memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 ); memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); if( bBigEndian ) SwapWord( 8, psShape->padfY + i ); } nOffset = 48 + 16*nPoints; /* -------------------------------------------------------------------- */ /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ memcpy( &(psShape->dfXMin), psSHP->pabyRec + 8 + 4, 8 ); memcpy( &(psShape->dfYMin), psSHP->pabyRec + 8 + 12, 8 ); memcpy( &(psShape->dfXMax), psSHP->pabyRec + 8 + 20, 8 ); memcpy( &(psShape->dfYMax), psSHP->pabyRec + 8 + 28, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfXMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfYMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfXMax) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfYMax) ); /* -------------------------------------------------------------------- */ /* If we have a Z coordinate, collect that now. */ /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_MULTIPOINTZ ) { memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 ); memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) ); for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfZ + i, psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); } nOffset += 16 + 8*nPoints; } /* -------------------------------------------------------------------- */ /* If we have a M measure value, then read it now. We assume */ /* that the measure can be present for any shape if the size is */ /* big enough, but really it will only occur for the Z shapes */ /* (options), and the M shapes. */ /* -------------------------------------------------------------------- */ if( nEntitySize >= nOffset + 16 + 8*nPoints ) { memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 ); memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 ); if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) ); if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) ); for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfM + i, psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); } psShape->bMeasureIsUsed = TRUE; } } /* ==================================================================== */ /* Extract vertices for a point. */ /* ==================================================================== */ else if( psShape->nSHPType == SHPT_POINT || psShape->nSHPType == SHPT_POINTM || psShape->nSHPType == SHPT_POINTZ ) { int nOffset; psShape->nVertices = 1; psShape->padfX = (double *) calloc(1,sizeof(double)); psShape->padfY = (double *) calloc(1,sizeof(double)); psShape->padfZ = (double *) calloc(1,sizeof(double)); psShape->padfM = (double *) calloc(1,sizeof(double)); if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize) { snprintf(szErrorMsg, sizeof(szErrorMsg), "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity, nEntitySize); psSHP->sHooks.Error( szErrorMsg ); SHPDestroyObject(psShape); return NULL; } memcpy( psShape->padfX, psSHP->pabyRec + 12, 8 ); memcpy( psShape->padfY, psSHP->pabyRec + 20, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfX ); if( bBigEndian ) SwapWord( 8, psShape->padfY ); nOffset = 20 + 8; /* -------------------------------------------------------------------- */ /* If we have a Z coordinate, collect that now. */ /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_POINTZ ) { memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ ); nOffset += 8; } /* -------------------------------------------------------------------- */ /* If we have a M measure value, then read it now. We assume */ /* that the measure can be present for any shape if the size is */ /* big enough, but really it will only occur for the Z shapes */ /* (options), and the M shapes. */ /* -------------------------------------------------------------------- */ if( nEntitySize >= nOffset + 8 ) { memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM ); psShape->bMeasureIsUsed = TRUE; } /* -------------------------------------------------------------------- */ /* Since no extents are supplied in the record, we will apply */ /* them from the single vertex. */ /* -------------------------------------------------------------------- */ psShape->dfXMin = psShape->dfXMax = psShape->padfX[0]; psShape->dfYMin = psShape->dfYMax = psShape->padfY[0]; psShape->dfZMin = psShape->dfZMax = psShape->padfZ[0]; psShape->dfMMin = psShape->dfMMax = psShape->padfM[0]; } return( psShape ); } /************************************************************************/ /* SHPTypeName() */ /************************************************************************/ const char SHPAPI_CALL1(*) SHPTypeName( int nSHPType ) { switch( nSHPType ) { case SHPT_NULL: return "NullShape"; case SHPT_POINT: return "Point"; case SHPT_ARC: return "Arc"; case SHPT_POLYGON: return "Polygon"; case SHPT_MULTIPOINT: return "MultiPoint"; case SHPT_POINTZ: return "PointZ"; case SHPT_ARCZ: return "ArcZ"; case SHPT_POLYGONZ: return "PolygonZ"; case SHPT_MULTIPOINTZ: return "MultiPointZ"; case SHPT_POINTM: return "PointM"; case SHPT_ARCM: return "ArcM"; case SHPT_POLYGONM: return "PolygonM"; case SHPT_MULTIPOINTM: return "MultiPointM"; case SHPT_MULTIPATCH: return "MultiPatch"; default: return "UnknownShapeType"; } } /************************************************************************/ /* SHPPartTypeName() */ /************************************************************************/ const char SHPAPI_CALL1(*) SHPPartTypeName( int nPartType ) { switch( nPartType ) { case SHPP_TRISTRIP: return "TriangleStrip"; case SHPP_TRIFAN: return "TriangleFan"; case SHPP_OUTERRING: return "OuterRing"; case SHPP_INNERRING: return "InnerRing"; case SHPP_FIRSTRING: return "FirstRing"; case SHPP_RING: return "Ring"; default: return "UnknownPartType"; } } /************************************************************************/ /* SHPDestroyObject() */ /************************************************************************/ void SHPAPI_CALL SHPDestroyObject( SHPObject * psShape ) { if( psShape == NULL ) return; if( psShape->padfX != NULL ) free( psShape->padfX ); if( psShape->padfY != NULL ) free( psShape->padfY ); if( psShape->padfZ != NULL ) free( psShape->padfZ ); if( psShape->padfM != NULL ) free( psShape->padfM ); if( psShape->panPartStart != NULL ) free( psShape->panPartStart ); if( psShape->panPartType != NULL ) free( psShape->panPartType ); free( psShape ); } /************************************************************************/ /* SHPRewindObject() */ /* */ /* Reset the winding of polygon objects to adhere to the */ /* specification. */ /************************************************************************/ int SHPAPI_CALL SHPRewindObject( SHPHandle hSHP, SHPObject * psObject ) { int iOpRing, bAltered = 0; /* -------------------------------------------------------------------- */ /* Do nothing if this is not a polygon object. */ /* -------------------------------------------------------------------- */ if( psObject->nSHPType != SHPT_POLYGON && psObject->nSHPType != SHPT_POLYGONZ && psObject->nSHPType != SHPT_POLYGONM ) return 0; if( psObject->nVertices == 0 || psObject->nParts == 0 ) return 0; /* -------------------------------------------------------------------- */ /* Process each of the rings. */ /* -------------------------------------------------------------------- */ for( iOpRing = 0; iOpRing < psObject->nParts; iOpRing++ ) { int bInner, iVert, nVertCount, nVertStart, iCheckRing; double dfSum, dfTestX, dfTestY; /* -------------------------------------------------------------------- */ /* Determine if this ring is an inner ring or an outer ring */ /* relative to all the other rings. For now we assume the */ /* first ring is outer and all others are inner, but eventually */ /* we need to fix this to handle multiple island polygons and */ /* unordered sets of rings. */ /* */ /* -------------------------------------------------------------------- */ /* Use point in the middle of segment to avoid testing * common points of rings. */ dfTestX = ( psObject->padfX[psObject->panPartStart[iOpRing]] + psObject->padfX[psObject->panPartStart[iOpRing] + 1] ) / 2; dfTestY = ( psObject->padfY[psObject->panPartStart[iOpRing]] + psObject->padfY[psObject->panPartStart[iOpRing] + 1] ) / 2; bInner = FALSE; for( iCheckRing = 0; iCheckRing < psObject->nParts; iCheckRing++ ) { int iEdge; if( iCheckRing == iOpRing ) continue; nVertStart = psObject->panPartStart[iCheckRing]; if( iCheckRing == psObject->nParts-1 ) nVertCount = psObject->nVertices - psObject->panPartStart[iCheckRing]; else nVertCount = psObject->panPartStart[iCheckRing+1] - psObject->panPartStart[iCheckRing]; for( iEdge = 0; iEdge < nVertCount; iEdge++ ) { int iNext; if( iEdge < nVertCount-1 ) iNext = iEdge+1; else iNext = 0; /* Rule #1: * Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY) * The rule #1 also excludes edges collinear with the ray. */ if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY && dfTestY <= psObject->padfY[iNext+nVertStart] ) || ( psObject->padfY[iNext+nVertStart] < dfTestY && dfTestY <= psObject->padfY[iEdge+nVertStart] ) ) { /* Rule #2: * Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY) */ double const intersect = ( psObject->padfX[iEdge+nVertStart] + ( dfTestY - psObject->padfY[iEdge+nVertStart] ) / ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] ) * ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) ); if (intersect < dfTestX) { bInner = !bInner; } } } } /* for iCheckRing */ /* -------------------------------------------------------------------- */ /* Determine the current order of this ring so we will know if */ /* it has to be reversed. */ /* -------------------------------------------------------------------- */ nVertStart = psObject->panPartStart[iOpRing]; if( iOpRing == psObject->nParts-1 ) nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing]; else nVertCount = psObject->panPartStart[iOpRing+1] - psObject->panPartStart[iOpRing]; if (nVertCount < 2) continue; dfSum = psObject->padfX[nVertStart] * (psObject->padfY[nVertStart+1] - psObject->padfY[nVertStart+nVertCount-1]); for( iVert = nVertStart + 1; iVert < nVertStart+nVertCount-1; iVert++ ) { dfSum += psObject->padfX[iVert] * (psObject->padfY[iVert+1] - psObject->padfY[iVert-1]); } dfSum += psObject->padfX[iVert] * (psObject->padfY[nVertStart] - psObject->padfY[iVert-1]); /* -------------------------------------------------------------------- */ /* Reverse if necessary. */ /* -------------------------------------------------------------------- */ if( (dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner) ) { int i; bAltered++; for( i = 0; i < nVertCount/2; i++ ) { double dfSaved; /* Swap X */ dfSaved = psObject->padfX[nVertStart+i]; psObject->padfX[nVertStart+i] = psObject->padfX[nVertStart+nVertCount-i-1]; psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved; /* Swap Y */ dfSaved = psObject->padfY[nVertStart+i]; psObject->padfY[nVertStart+i] = psObject->padfY[nVertStart+nVertCount-i-1]; psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved; /* Swap Z */ if( psObject->padfZ ) { dfSaved = psObject->padfZ[nVertStart+i]; psObject->padfZ[nVertStart+i] = psObject->padfZ[nVertStart+nVertCount-i-1]; psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved; } /* Swap M */ if( psObject->padfM ) { dfSaved = psObject->padfM[nVertStart+i]; psObject->padfM[nVertStart+i] = psObject->padfM[nVertStart+nVertCount-i-1]; psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved; } } } } return bAltered; } shapelib-1.3.0/mkinstalldirs0000640042715500116100000000122707070147031015423 0ustar warmerdameng#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here shapelib-1.3.0/contrib/0000750042715500116100000000000011741051742014260 5ustar warmerdamengshapelib-1.3.0/contrib/dbfinfo.c0000640042715500116100000000556511612707332016047 0ustar warmerdameng/* * Copyright (c) 1999 Carl Anderson * * This code is in the public domain. * * This code is based in part on the earlier work of Frank Warmerdam * * requires shapelib 1.2 * gcc dbfinfo dbfopen.o dbfinfo * * * $Log: dbfinfo.c,v $ * Revision 1.3 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.2 1999-05-26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * */ #include #include #include "shapefil.h" int main( int argc, char ** argv ) { DBFHandle hDBF; int *panWidth, i, iRecord; char szFormat[32], szField[1024]; char ftype[15], cTitle[32], nTitle[32]; int nWidth, nDecimals; int cnWidth, cnDecimals; DBFHandle cDBF; DBFFieldType hType,cType; int ci, ciRecord; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 2 ) { printf( "dbfinfo xbase_file\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the file. */ /* -------------------------------------------------------------------- */ hDBF = DBFOpen( argv[1], "rb" ); if( hDBF == NULL ) { printf( "DBFOpen(%s,\"r\") failed.\n", argv[1] ); exit( 2 ); } printf ("Info for %s\n",argv[1]); /* -------------------------------------------------------------------- */ /* If there is no data in this file let the user know. */ /* -------------------------------------------------------------------- */ i = DBFGetFieldCount(hDBF); printf ("%ld Columns, %ld Records in file\n",i,DBFGetRecordCount(hDBF)); /* -------------------------------------------------------------------- */ /* Compute offsets to use when printing each of the field */ /* values. We make each field as wide as the field title+1, or */ /* the field value + 1. */ /* -------------------------------------------------------------------- */ panWidth = (int *) malloc( DBFGetFieldCount( hDBF ) * sizeof(int) ); for( i = 0; i < DBFGetFieldCount(hDBF); i++ ) { char szTitle[12]; DBFFieldType eType; switch ( DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals )) { case FTString: strcpy (ftype, "string");; break; case FTInteger: strcpy (ftype, "integer"); break; case FTDouble: strcpy (ftype, "float"); break; case FTInvalid: strcpy (ftype, "invalid/unsupported"); break; default: strcpy (ftype, "unknown"); break; } printf ("%15.15s\t%15s (%d,%d)\n",szTitle, ftype, nWidth, nDecimals); } DBFClose( hDBF ); return( 0 ); } shapelib-1.3.0/contrib/my_nan.h0000640042715500116100000000275607417601454015733 0ustar warmerdameng/* `NAN' constant for IEEE 754 machines. Copyright (C) 1992, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNU_NAN_H #define _GNU_NAN_H 1 /* hacked to define NAN on Solaris 2.7 if it wasn't defined */ /* IEEE Not A Number. */ #ifdef _BIG_ENDIAN # define __nan_bytes { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 } #endif #ifdef _LITTLE_ENDIAN # define __nan_bytes { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f } #endif #ifdef __GNUC__ # define NAN \ (__extension__ ((union { unsigned char __c[8]; \ double __d; }) \ { __nan_bytes }).__d) #else /* Not GCC. */ static const char __nan[8] = __nan_bytes; # define NAN (*(const double *) __nan) #endif #endif /* gnu_nan.h */ shapelib-1.3.0/contrib/makefile.vc0000640042715500116100000000205310761617604016376 0ustar warmerdameng CFLAGS = /Ox /MD /nologo /I.. /IC:\OSGeo4W\include \ /D_LITTLE_ENDIAN -DPROJ4 LINKARGS = ..\shapelib_i.lib C:\OSGeo4W\lib\proj_i.lib default: all all: shpcat.exe shpcentrd.exe shpdxf.exe shpinfo.exe shpproj.exe shpcat.exe: shpcat.obj shpgeo.obj $(CC) $(CFLAGS) shpcat.obj $(LINKARGS) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpcentrd.exe: shpcentrd.obj shpgeo.obj $(CC) $(CFLAGS) shpcentrd.obj shpgeo.obj $(LINKARGS) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpproj.exe: shpproj.obj shpgeo.obj $(CC) $(CFLAGS) shpproj.obj shpgeo.obj $(LINKARGS) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpdxf.exe: shpdxf.obj shpgeo.obj $(CC) $(CFLAGS) shpdxf.obj $(LINKARGS) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 shpinfo.exe: shpinfo.obj shpgeo.obj $(CC) $(CFLAGS) shpinfo.obj $(LINKARGS) if exist $@.manifest mt -manifest $@.manifest -outputresource:$@;1 clean: -del *.obj -del *.exe -del *.manifest shapelib-1.3.0/contrib/shpcat.c0000640042715500116100000000672111612707332015715 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * shpcat * * gcc shpcat.c ../shpopen.o -o shpcat * * Utility program to concatenate two shapefiles * Must be used in concert with dbfcat * */ #include #include #include "shapefil.h" int dbfcat_main( int argc, char ** argv ); int main( int argc, char ** argv ) { SHPHandle hSHP, cSHP; int nShapeType, i, nEntities, nShpInFile; SHPObject *shape; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 3 ) { printf( "shpcat from_shpfile to_shpfile\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( argv[1], "rb" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( hSHP, &nEntities, &nShapeType, NULL, NULL ); fprintf(stderr,"Opened From File %s, with %d shapes\n",argv[1],nEntities); /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ cSHP = SHPOpen( argv[2], "rb+" ); if( cSHP == NULL ) { printf( "Unable to open:%s\n", argv[2] ); exit( 1 ); } SHPGetInfo( cSHP, &nShpInFile, NULL, NULL, NULL ); fprintf(stderr,"Opened to file %s with %d shapes, ready to add %d\n", argv[2],nShpInFile,nEntities); /* -------------------------------------------------------------------- */ /* Skim over the list of shapes, printing all the vertices. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nEntities; i++ ) { shape = SHPReadObject( hSHP, i ); SHPWriteObject( cSHP, -1, shape ); SHPDestroyObject ( shape ); } SHPClose( hSHP ); SHPClose( cSHP ); exit( 0 ); } shapelib-1.3.0/contrib/shpinfo.c0000640042715500116100000000753611612707332016106 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * requires shapelib 1.2 * gcc shpinfoj shpopen.o -o shpinfo * * * $Log: shpinfo.c,v $ * Revision 1.4 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.3 2002-04-15 21:33:03 warmerda * Avoid dereference arrays. * * Revision 1.2 2002/04/15 18:40:31 warmerda * Fixed size of adfBnds{Min,Max} as per bug from David Fowler. * * Revision 1.1 1999/05/26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * */ #include #include #include "shapefil.h" int main( int argc, char ** argv ) { SHPHandle hSHP, cSHP; int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart; double *padVertices, adfBndsMin[4], adfBndsMax[4]; const char *pszPlus; int cShapeType, cEntities, cVertices, cParts, *cpanParts, ci, cPart; double *cpadVertices, cadBounds[4]; const char *cpszPlus; char sType [15]= ""; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 2 ) { printf( "shpinfo shp_file\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( argv[1], "rb" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( hSHP, &nEntities, &nShapeType, adfBndsMin, adfBndsMax ); switch ( nShapeType ) { case SHPT_POINT: strcpy(sType,"Point"); break; case SHPT_ARC: strcpy(sType,"Polyline"); break; case SHPT_POLYGON: strcpy(sType,"Polygon"); break; case SHPT_MULTIPOINT: strcpy(sType,"MultiPoint"); break; } /* -------------------------------------------------------------------- */ printf ("Info for %s\n",argv[1]); printf ("%s(%d), %ld Records in file\n",sType,nShapeType,nEntities); /* -------------------------------------------------------------------- */ /* Print out the file bounds. */ /* -------------------------------------------------------------------- */ printf( "File Bounds: (%15.10lg,%15.10lg)\n\t(%15.10lg,%15.10lg)\n", adfBndsMin[0], adfBndsMin[1], adfBndsMax[0], adfBndsMax[1] ); SHPClose( hSHP ); } shapelib-1.3.0/contrib/csv2shp.c0000640042715500116100000003104310252343063016012 0ustar warmerdameng/* csv2shp - converts a character delimited file to a ESRI shapefile Copyright (C) 2005 Springs Rescue Mission LICENSE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The GNU General Public License is also available from the web site . GRATITUDE Like this program? Donate at . COMPILING INSTRUCTIONS This program was written and tested using Shapefile C Library version 1.2.10 available at . To compile, copy csv2shp.c to the directory with Shapefile C Library. Then, compile Shapefile C library. Then, run something like this: gcc -pedantic -Wall -o csv2shp csv2shp.c -I. *o USAGE NOTES This program operates on single points only (not polygons or lines). The input file may be a .csv file (comma separated values) or tab-separated values, or it may be separated by any other character. The first row must contain column names. There must be each a column named longitude and latitude in the input file. The .csv parser does not understand text delimiters (e.g. quotation mark). It parses fields only by the given field delimiter (e.g. comma or tab). The program has not been tested with null values, and in this case, the behavior is undefined. The program will not accept lines with a trailing delimiter character. All columns (including longitude and latitude) in the input file are exported to the .dbf file. The program attempts to find the best type (integer, decimal, string) and smallest size of the fields necessary for the .dbf file. SUPPORT Springs Rescue Mission does not offer any support for this program. CONTACT INFORMATION Springs Rescue Mission 5 West Las Vegas St PO Box 2108 Colorado Springs CO 80901 Web: Email: */ #include #include #include #include "shapefil.h" #include "regex.h" #define MAX_COLUMNS 30 typedef struct column_t { DBFFieldType eType; int nWidth; int nDecimals; } column; /* counts the number of occurances of the character in the string */ int strnchr(const char *s, char c) { int n = 0; int x = 0; for (; x < strlen(s); x++) { if (c == s[x]) { n++; } } return n; } /* Returns a field given by column n (0-based) in a character- delimited string s */ char * delimited_column(char *s, char delim, int n) { static char szreturn[4096]; char szbuffer[4096]; /* a copy of s */ char * pchar; int x; char szdelimiter[2]; /* delim converted to string */ if (strnchr(s, delim) < n) { fprintf(stderr, "delimited_column: n is too large\n"); return NULL; } strcpy(szbuffer, s); szdelimiter[0] = delim; szdelimiter[1] = '\0'; x = 0; pchar = strtok(szbuffer, szdelimiter); while (x < n) { pchar = strtok(NULL, szdelimiter); x++; } if (NULL == pchar) { return NULL; } strcpy(szreturn, pchar); return szreturn; } /* Determines the most specific column type. The most specific types from most to least are integer, float, string. */ DBFFieldType str_to_fieldtype(const char *s) { regex_t regex_i; regex_t regex_d; if (0 != regcomp(®ex_i, "^[0-9]+$", REG_NOSUB|REG_EXTENDED)) { fprintf(stderr, "integer regex complication failed\n"); exit (EXIT_FAILURE); } if (0 == regexec(®ex_i, s, 0, NULL, 0)) { regfree(®ex_i); return FTInteger; } regfree(®ex_i); if (0 != regcomp(®ex_d, "^-?[0-9]+\\.[0-9]+$", REG_NOSUB|REG_EXTENDED)) { fprintf(stderr, "integer regex complication failed\n"); exit (EXIT_FAILURE); } if (0 == regexec(®ex_d, s, 0, NULL, 0)) { regfree(®ex_d); return FTDouble; } regfree(®ex_d); return FTString; } int float_width(const char *s) { regex_t regex_d; regmatch_t pmatch[2]; char szbuffer[4096]; if (0 != regcomp(®ex_d, "^(-?[0-9]+)\\.[0-9]+$", REG_EXTENDED)) { fprintf(stderr, "integer regex complication failed\n"); exit (EXIT_FAILURE); } if (0 != regexec(®ex_d, s, 2, &pmatch[0], 0)) { return -1; } strncpy(szbuffer, &s[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); szbuffer[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0'; regfree(®ex_d); return strlen(szbuffer); } /* returns the field width */ int str_to_nwidth(const char *s, DBFFieldType eType) { switch (eType) { case FTString: case FTInteger: case FTDouble: return strlen(s); default: fprintf(stderr, "str_to_nwidth: unexpected type\n"); exit (EXIT_FAILURE); } } /* returns the number of decimals in a real number given as a string s */ int str_to_ndecimals(const char *s) { regex_t regex_d; regmatch_t pmatch[2]; char szbuffer[4096]; if (0 != regcomp(®ex_d, "^-?[0-9]+\\.([0-9]+)$", REG_EXTENDED)) { fprintf(stderr, "integer regex complication failed\n"); exit (EXIT_FAILURE); } if (0 != regexec(®ex_d, s, 2, &pmatch[0], 0)) { return -1; } strncpy(szbuffer, &s[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so); szbuffer[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0'; regfree(®ex_d); return strlen(szbuffer); } /* returns true if f1 is more general than f2, otherwise false */ int more_general_field_type(DBFFieldType t1, DBFFieldType t2) { if (FTInteger == t2 && t1 != FTInteger) { return 1; } if (FTDouble == t2 && FTString == t1) { return 1; } return 0; } void strip_crlf (char *line) { /* remove trailing CR/LF */ if (strchr (line, 0x0D)) { char *pszline; pszline = strchr (line, 0x0D); pszline[0] = '\0'; } if (strchr (line, 0x0A)) { char *pszline; pszline = strchr (line, 0x0A); pszline[0] = '\0'; } } int main( int argc, char ** argv ) { FILE *csv_f; char sbuffer[4096]; char delimiter; int n_columns; /* 1-based */ int n_line; int n_longitude = -1; /* column with x, 0 based */ int n_latitude = -1; /* column with y, 0 based */ int x; DBFHandle dbf_h; SHPHandle shp_h; column columns[MAX_COLUMNS + 1]; printf("csv2shp version 1, Copyright (C) 2005 Springs Rescue Mission\n"); if (4 != argc) { fprintf(stderr, "csv2shp comes with ABSOLUTELY NO WARRANTY; for details\n"); fprintf(stderr, "see csv2shp.c. This is free software, and you are welcome\n"); fprintf(stderr, "to redistribute it under certain conditions; see csv2shp.c\n"); fprintf(stderr, "for details\n"); fprintf(stderr, "\n"); fprintf(stderr, "USAGE\n"); fprintf(stderr, "csv2shp csv_filename delimiter_character shp_filename\n"); fprintf(stderr, " csv_filename\n"); fprintf(stderr, " columns named longitude and latitude must exist\n"); fprintf(stderr, " delimiter_character\n"); fprintf(stderr, " one character only\n"); fprintf(stderr, " shp_filename\n"); fprintf(stderr, " base name, do not give the extension\n"); return EXIT_FAILURE; } if (strlen(argv[2]) > 1) { fprintf(stderr, "delimiter must be one character in length\n"); return EXIT_FAILURE; } delimiter = argv[2][0]; csv_f = fopen(argv[1], "r"); if (NULL == csv_f) { perror("could not open csv file"); exit (EXIT_FAILURE); } fgets(sbuffer, 4000, csv_f); /* check first row */ strip_crlf(sbuffer); if (delimiter == sbuffer[strlen(sbuffer)- 1]) { fprintf(stderr, "lines must not end with the delimiter character\n"); return EXIT_FAILURE; } /* count columns and verify consistency*/ n_columns = strnchr(sbuffer, delimiter); if (n_columns > MAX_COLUMNS) { fprintf(stderr, "too many columns, maximum is %i\n", MAX_COLUMNS); return EXIT_FAILURE; } n_line = 1; while (!feof(csv_f)) { n_line++; fgets(sbuffer, 4000, csv_f); if (n_columns != strnchr(sbuffer, delimiter)) { fprintf(stderr, "Number of columns on row %i does not match number of columns on row 1\n", n_columns); return EXIT_FAILURE; } } /* identify longitude and latitude columns */ fseek(csv_f, 0, SEEK_SET); fgets(sbuffer, 4000, csv_f); strip_crlf(sbuffer); for (x = 0; x <= n_columns; x++) { if (0 == strcasecmp("Longitude", delimited_column(sbuffer, delimiter, x))) { n_longitude = x; } if (0 == strcasecmp("Latitude", delimited_column(sbuffer, delimiter, x))) { n_latitude = x; } } #ifdef DEBUG printf("debug lat/long = %i/%i\n", n_latitude, n_longitude); #endif if (-1 == n_longitude || -1 == n_latitude) { fprintf(stderr, "The header row must define one each a column named longitude and latitude\n"); return EXIT_FAILURE; } /* determine best fit for each column */ printf ("Anaylzing column types...\n"); #ifdef DEBUG printf("debug: string type = %i\n", FTString); printf("debug: int type = %i\n", FTInteger); printf("debug: double type = %i\n", FTDouble); #endif for (x = 0; x <= n_columns; x++) { #ifdef DEBUG printf("debug: examining column %i\n", x); #endif columns[x].eType = FTInteger; columns[x].nWidth = 2; columns[x].nDecimals = 0; fseek(csv_f, 0, SEEK_SET); fgets(sbuffer, 4000, csv_f); while (!feof(csv_f)) { char szfield[4096]; #ifdef DEBUG printf ("column %i, type = %i, w = %i, d = %i\n", x, columns[x].eType, columns[x].nWidth, columns[x].nDecimals); #endif if (NULL == fgets(sbuffer, 4000, csv_f)) { if (!feof(csv_f)) { fprintf(stderr, "error during fgets()\n"); } continue; } strcpy(szfield, delimited_column(sbuffer, delimiter, x)); if (more_general_field_type(str_to_fieldtype(szfield), columns[x].eType)) { columns[x].eType = str_to_fieldtype(szfield); columns[x].nWidth = 2; columns[x].nDecimals = 0; fseek(csv_f, 0, SEEK_SET); fgets(sbuffer, 4000, csv_f); continue; } if (columns[x].nWidth < str_to_nwidth(szfield, columns[x].eType)) { columns[x].nWidth = str_to_nwidth(szfield, columns[x].eType); } if (FTDouble == columns[x].eType && columns[x].nDecimals < str_to_ndecimals(szfield)) { columns[x].nDecimals = str_to_ndecimals(szfield); } } } /* initilize output files */ printf ("Initializing output files...\n"); shp_h = SHPCreate(argv[3], SHPT_POINT); dbf_h = DBFCreate(argv[3]); if (NULL == dbf_h) { fprintf(stderr, "DBFCreate failed\n"); exit (EXIT_FAILURE); } fseek(csv_f, 0, SEEK_SET); fgets(sbuffer, 4000, csv_f); strip_crlf(sbuffer); for (x = 0; x <= n_columns; x++) { #ifdef DEBUG printf ("debug: final: column %i, type = %i, w = %i, d = %i, name=|%s|\n", x, columns[x].eType, columns[x].nWidth, columns[x].nDecimals, delimited_column(sbuffer, delimiter, x)); #endif if (-1 == DBFAddField(dbf_h, delimited_column(sbuffer, delimiter, x), columns[x].eType, columns[x].nWidth, columns[x].nDecimals)) { fprintf(stderr, "DBFFieldAdd failed column %i\n", x + 1); exit (EXIT_FAILURE); } } /* write data */ printf ("Writing data...\n"); fseek(csv_f, 0, SEEK_SET); fgets(sbuffer, 4000, csv_f); /* skip header */ n_columns = strnchr(sbuffer, delimiter); n_line = 1; while (!feof(csv_f)) { SHPObject * shp; double x_pt; double y_pt; int shp_i; n_line++; fgets(sbuffer, 4000, csv_f); /* write to shape file */ x_pt = atof(delimited_column(sbuffer, delimiter, n_longitude)); y_pt = atof(delimited_column(sbuffer, delimiter, n_latitude)); #ifdef DEBUG printf("debug: sbuffer=%s", sbuffer); printf("debug: x,y = %f, %f\n", x_pt, y_pt); #endif shp = SHPCreateSimpleObject(SHPT_POINT, 1, &x_pt, &y_pt, NULL); shp_i = SHPWriteObject(shp_h, -1, shp); SHPDestroyObject(shp); /* write to dbf */ for (x = 0; x <= n_columns; x++) { char szfield[4096]; int b; strcpy(szfield, delimited_column(sbuffer, delimiter, x)); switch (columns[x].eType) { case FTInteger: b = DBFWriteIntegerAttribute(dbf_h, shp_i, x, atoi(szfield)); break; case FTDouble: b = DBFWriteDoubleAttribute(dbf_h, shp_i, x, atof(szfield)); break; case FTString: b = DBFWriteStringAttribute(dbf_h, shp_i, x, szfield); break; default: fprintf(stderr, "unexpected column type %i in column %i\n", columns[x].eType, x); } if (!b) { fprintf(stderr, "DBFWrite*Attribute failed\n"); exit (EXIT_FAILURE); } } } /* finish up */ SHPClose(shp_h); DBFClose(dbf_h); return EXIT_SUCCESS; } shapelib-1.3.0/contrib/tests/0000750042715500116100000000000011741051742015422 5ustar warmerdamengshapelib-1.3.0/contrib/tests/shpproj.sh0000750042715500116100000000136310365716743017463 0ustar warmerdameng#!/bin/sh cd tests rm test* shpcreate test point shpadd test -83.54949956 34.992401 shpadd test -83.52162155 34.99276748 shpadd test -84.01681518 34.67275985 shpadd test -84.15596023 34.64862437 shpadd test -83.61951463 34.54927047 dbfcreate test -s fd 30 dbfadd test "1" dbfadd test "2" dbfadd test "3" dbfadd test "4" dbfadd test "5" ../shpproj test test_1 -i=geographic -o="init=nad83:1002 units=us-ft" ../shpproj test_1 test_2 -o="proj=utm zone=16 units=m" ../shpproj test_2 test_3 -o=geographic shpdump test > test.out shpdump test_3 > test_3.out result=`diff test.out test_3.out` if [ -z "${result}" ]; then echo success... else echo failure... fi rm test* cd .. shapelib-1.3.0/contrib/shpwkb.c0000640042715500116100000000763506722656220015743 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * this code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * shpwkb.c - test WKB binary Input / Output * * * $Log: shpwkb.c,v $ * Revision 1.1 1999-05-26 02:29:36 candrsn * OGis Well Known Binary test program (output only) * * * */ #include "shapefil.h" #include "shpgeo.h" int main( int argc, char ** argv ) { SHPHandle old_SHP, new_SHP; DBFHandle old_DBF, new_DBF; int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart; double *padVertices, adBounds[4]; const char *pszPlus; DBFFieldType idfld_type; int idfld, nflds; char kv[257] = ""; char idfldName[120] = ""; char fldName[120] = ""; char shpFileName[120] = ""; char dbfFileName[120] = ""; char *DBFRow = NULL; int Cpan[2] = { 0,0 }; int byRing = 0; PT oCentrd, ringCentrd; SHPObject *psCShape, *cent_pt; double oArea = 0.0, oLen = 0.0; WKBStreamObj *wkbObj = NULL; FILE *wkb_file = NULL; if( argc < 3 ) { printf( "shpwkb shp_file wkb_file\n" ); exit( 1 ); } old_SHP = SHPOpen (argv[1], "rb" ); old_DBF = DBFOpen (argv[1], "rb"); if( old_SHP == NULL || old_DBF == NULL ) { printf( "Unable to open old files:%s\n", argv[1] ); exit( 1 ); } wkb_file = fopen ( argv[2], "wb"); wkbObj = calloc ( 3, sizeof (int) ); SHPGetInfo( old_SHP, &nEntities, &nShapeType, NULL, NULL ); for( i = 0; i < nEntities; i++ ) { int res ; psCShape = SHPReadObject( old_SHP, i ); if ( byRing == 1 ) { int ring, prevStart, ringDir; double ringArea; prevStart = psCShape->nVertices; for ( ring = (psCShape->nParts - 1); ring >= 0; ring-- ) { SHPObject *psO; int j, numVtx, rStart; rStart = psCShape->panPartStart[ring]; if ( ring == (psCShape->nParts -1) ) { numVtx = psCShape->nVertices - rStart; } else { numVtx = psCShape->panPartStart[ring+1] - rStart; } printf ("(shpdata) Ring(%d) (%d for %d) \n", ring, rStart, numVtx); psO = SHPClone ( psCShape, ring, ring + 1 ); SHPDestroyObject ( psO ); printf ("(shpdata) End Ring \n"); } /* (ring) [0,nParts */ } /* by ring */ printf ("gonna build a wkb \n"); res = SHPWriteOGisWKB ( wkbObj, psCShape ); printf ("gonna write a wkb that is %d bytes long \n", wkbObj->StreamPos ); fwrite ( (void*) wkbObj->wStream, 1, wkbObj->StreamPos, wkb_file ); } free ( wkbObj ); SHPClose( old_SHP ); DBFClose( old_DBF ); if ( wkb_file ) fclose ( wkb_file ); printf ("\n"); } shapelib-1.3.0/contrib/.cvsignore0000640042715500116100000000014711364056425016267 0ustar warmerdamengshpdxf dbfinfo shpcentrd shpdata shpwkb dbfcat shpinfo shpfix shpcat Shape_PointInPoly shpproj shpsort shapelib-1.3.0/contrib/shpdxf.c0000640042715500116100000002236211612707332015726 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * shp2dxf.c * * derived from a ESRI Avenue Script * and DXF specification from AutoCad 3 (yes 1984) * * modifications Carl Andrson 11/96 * modifications Carl Andrson 3/97 * * converted to C code 12/98 * * requires shapelib 1.2 * gcc shpdxf.c shpopen.o dbfopen.o -o shpdxf * */ #include #include #include "shapefil.h" #define FLOAT_PREC "%16.5f\r\n" void dxf_hdr (x1,y1,x2,y2,df) double x1,y1,x2,y2; FILE *df; { /* Create HEADER section */ fprintf( df, " 0\r\n"); fprintf( df, "SECTION\r\n"); fprintf( df, " 2\r\n" ); fprintf( df, "HEADER\r\n" ); fprintf( df, " 9\r\n" ); fprintf( df, "$EXTMAX\r\n" ); fprintf( df, " 10\r\n" ); fprintf( df, FLOAT_PREC, x2 ); fprintf( df, " 20\r\n" ); fprintf( df, FLOAT_PREC, y2 ); fprintf( df, " 9\r\n" ); fprintf( df, "$EXTMIN\r\n" ); fprintf( df, " 10\r\n" ); fprintf( df, FLOAT_PREC, x1 ); fprintf( df, " 20\r\n" ); fprintf( df, FLOAT_PREC, y1 ); fprintf( df, " 9\r\n" ); fprintf( df, "$LUPREC\r\n" ); fprintf( df, " 70\r\n" ); fprintf( df, " 14\r\n" ); fprintf( df, " 0\r\n" ); fprintf( df, "ENDSEC\r\n" ); /* ' Create TABLES section */ fprintf( df, " 0\r\n" ); fprintf( df, "SECTION\r\n" ); fprintf( df, " 2\r\n" ); fprintf( df, "TABLES\r\n" ); /* ' Table 1 - set up line type */ fprintf( df, " 0\r\n" ); fprintf( df, "TABLE\r\n" ); fprintf( df, " 2\r\n" ); fprintf( df, "LTYPE\r\n" ); fprintf( df, " 70\r\n" ); fprintf( df, "2\r\n" ); /* ' Entry 1 of Table 1 */ fprintf( df, " 0\r\n" ); fprintf( df, "LTYPE\r\n" ); fprintf( df, " 2\r\n" ); fprintf( df, "CONTINUOUS\r\n" ); fprintf( df, " 70\r\n" ); fprintf( df, "64\r\n" ); fprintf( df, " 3\r\n" ); fprintf( df, "Solid line\r\n" ); fprintf( df, " 72\r\n" ); fprintf( df, "65\r\n" ); fprintf( df, " 73\r\n" ); fprintf( df, "0\r\n" ); fprintf( df, " 40\r\n" ); fprintf( df, "0.0\r\n" ); fprintf( df, " 0\r\n" ); fprintf( df, "ENDTAB\r\n" ); /* End of TABLES section */ fprintf( df, " 0\r\n" ); fprintf( df, "ENDSEC\r\n" ); /* Create BLOCKS section */ fprintf( df, " 0\r\n" ); fprintf( df, "SECTION\r\n" ); fprintf( df, " 2\r\n" ); fprintf( df, "BLOCKS\r\n" ); fprintf( df, " 0\r\n" ); fprintf( df, "ENDSEC\r\n" ); fprintf( df, " 0\r\n" ); fprintf( df, "SECTION\r\n" ); fprintf( df, " 2\r\n" ); fprintf( df, "ENTITIES\r\n" ); } void dxf_ent_preamble (dxf_type, id, df) int dxf_type; char *id; FILE *df; { fprintf( df, " 0\r\n" ); switch (dxf_type) { case SHPT_POLYGON: case SHPT_ARC: fprintf (df, "POLYLINE\r\n"); break; default: fprintf(df, "POINT\r\n"); } fprintf( df, " 8\r\n", df); fprintf( df, "%s\r\n", id ); switch ( dxf_type ) { case SHPT_ARC: fprintf( df, " 6\r\n" ); fprintf( df, "CONTINUOUS\r\n" ); fprintf( df, " 66\r\n" ); fprintf( df, "1\r\n" ); break; case SHPT_POLYGON: fprintf( df, " 6\r\n" ); fprintf( df, "CONTINUOUS\r\n" ); fprintf( df, " 66\r\n" ); fprintf( df, "1\r\n" ); fprintf( df, " 70\r\n"); fprintf (df, "1\r\n"); default: break; } } void dxf_ent (id, x, y, z, dxf_type, df) char *id; double x,y,z; int dxf_type; FILE *df; { if ((dxf_type == SHPT_ARC) || ( dxf_type == SHPT_POLYGON)) { fprintf( df, " 0\r\n"); fprintf( df, "VERTEX\r\n"); fprintf( df, " 8\r\n"); fprintf( df, "%s\r\n", id); } fprintf( df, " 10\r\n" ); fprintf( df, FLOAT_PREC, x ); fprintf( df, " 20\r\n" ); fprintf( df, FLOAT_PREC, y ); fprintf( df, " 30\r\n" ); if ( z != 0 ) fprintf( df, FLOAT_PREC, z ); else fprintf( df, "0.0\r\n" ); } void dxf_ent_postamble (dxf_type, df) int dxf_type; FILE *df; { if ((dxf_type == SHPT_ARC) || ( dxf_type == SHPT_POLYGON)) fprintf( df, " 0\r\nSEQEND\r\n 8\r\n0\r\n", df); } int main (int argc, char **argv) { char shpFileName[80] = "", dbfFileName[80] = ""; char dxfFileName[80] = ""; char idfldName[15]; char zfldName[6] = "ELEV"; char fldName[15]; char id[255]; double elev; int parts, *panParts, nParts, nVertices; FILE *dxf; SHPHandle shp; DBFHandle dbf; DBFFieldType idfld_type; double adfBoundsMin[4], adfBoundsMax[4]; int vrtx, shp_type, shp_numrec, zfld, idfld, nflds, recNum, part; unsigned int MaxElem = -1; if ( argc < 2 ) { printf ("usage: shpdxf shapefile {idfield}\r\n"); exit (-1); } strcpy (shpFileName,argv[1]); strncpy (dbfFileName, shpFileName, strlen(shpFileName)-3); strcat (dbfFileName,"dbf"); strncpy (dxfFileName, shpFileName,strlen(shpFileName)-3); strcat( dxfFileName, "dxf"); shp = SHPOpen (shpFileName, "rb"); dbf = DBFOpen (dbfFileName, "rb"); dxf = fopen( dxfFileName, "w"); printf("Starting conversion %s(%s) -> %s\r\n", shpFileName,dbfFileName,dxfFileName); SHPGetInfo (shp, &shp_numrec, &shp_type, adfBoundsMin, adfBoundsMax ); printf ("file has %d objects\r\n", shp_numrec); dxf_hdr(adfBoundsMin[0], adfBoundsMin[1], adfBoundsMax[0], adfBoundsMax[1], dxf); /* Before proceeding, allow the user to specify the ID field to use or default to the record number.... */ if ( argc > 3 ) MaxElem = atoi(argv[3]); nflds = DBFGetFieldCount(dbf); if ( argc > 2 ) { strcpy (idfldName, argv[2]); for ( idfld=0; idfld < nflds; idfld++ ) { idfld_type = DBFGetFieldInfo( dbf, idfld, fldName, NULL, NULL); if (!strcmp (idfldName, fldName )) break; } if ( idfld >= nflds ) { printf ("Id field %s not found, using default\r\n",idfldName); idfld = -1; } else printf ("proceeding with field %s for LayerNames\r\n",fldName); } else idfld = -1; for ( zfld=0; zfld < nflds; zfld++ ) { DBFGetFieldInfo( dbf, zfld, fldName, NULL, NULL); if (!strcmp (zfldName, fldName )) break; } if ( zfld >= nflds ) zfld = -1; // printf ("proceeding with id = %d, elevation = %d\r\n",idfld, zfld); /* Proceed to process data..... */ for ( recNum = 0; (recNum < shp_numrec) && (recNum < MaxElem); recNum++) { SHPObject *shape; if ( idfld >= 0 ) switch (idfld_type) { case FTString: sprintf (id, "lvl_%s",DBFReadStringAttribute ( dbf, recNum, idfld )); break; default: sprintf(id, "%-20.0lf", DBFReadDoubleAttribute (dbf, recNum, idfld)); } else sprintf (id,"lvl_%-20d",(recNum +1 )); if ( zfld >= 0 ) elev = 0; else elev = DBFReadDoubleAttribute ( dbf, recNum, zfld ); #ifdef DEBUG printf("\r\nworking on obj %d", recNum); #endif shape = SHPReadObject( shp, recNum ); nVertices = shape->nVertices; nParts = shape->nParts; panParts = shape->panPartStart; part = 0; for (vrtx=0; vrtx < nVertices; vrtx ++ ) { #ifdef DEBUG printf("\rworking on part %d, vertex %d", part,vrtx); #endif if ( panParts[part] == vrtx ) { #ifdef DEBUG printf ("object preamble\r\n"); #endif dxf_ent_preamble (shp_type, id, dxf); } dxf_ent (id, shape->padfX[vrtx], shape->padfY[vrtx], elev, shp_type, dxf); if ((panParts[part] == (vrtx + 1))|| (vrtx == (nVertices -1)) ) { dxf_ent_postamble (shp_type, dxf); part ++; } } SHPDestroyObject( shape ); } /* close out DXF file */ fprintf( dxf, "0\r\n" ); fprintf( dxf, "ENDSEC\r\n" ); fprintf( dxf, "0\r\n" ); fprintf( dxf, "EOF\r\n" ); SHPClose (shp); DBFClose (dbf); fclose (dxf); } shapelib-1.3.0/contrib/Makefile0000640042715500116100000000355011320264642015722 0ustar warmerdameng #LINKOPT = /usr/local/lib/libdbmalloc.a #CFLAGS = -g # Endian: define either _LITTLE_ENDIAN or _BIG_ENDIAN ENDIAN = -D_LITTLE_ENDIAN CFLAGS = -g -I.. -I$(HOME)/bld/include -DPROJ4 $(ENDIAN) -DDEBUG -DDEBUG2 SHPOBJ = ../shpopen.o ../dbfopen.o ../safileio.o SHPGOBJ = ../shpopen.o ../dbfopen.o ../safileio.o shpgeo.o GEOOBJ = ./shpgeo.o -lm -L$(HOME)/bld/lib -lproj default: all all: shpdxf shpproj dbfinfo shpcentrd shpdata shpwkb dbfinfo dbfcat shpinfo shpfix shpcat Shape_PointInPoly shpsort clean: rm -f shpdxf shpproj dbfinfo shpcentrd shpdata shpwkb dbfcat dbfinfo shpinfo shpfix shpcat *.o shpgeo.o: shpgeo.c shpgeo.h $(CC) $(CFLAGS) -c shpgeo.c shpdxf: shpdxf.c $(SHPOBJ) $(CC) $(CFLAGS) shpdxf.c ${SHPOBJ} $(LINKOPT) -o shpdxf shpcentrd: shpcentrd.c $(SHPGOBJ) $(CC) $(CFLAGS) shpcentrd.c ${SHPOBJ} $(LINKOPT) $(GEOOBJ) -o shpcentrd shpdata: shpdata.c $(SHPGOBJ) $(CC) $(CFLAGS) shpdata.c ${SHPOBJ} $(LINKOPT) $(GEOOBJ) -o shpdata shpinfo: shpinfo.c $(SHPOBJ) $(CC) $(CFLAGS) shpinfo.c ${SHPOBJ} $(LINKOPT) $(GEOOBJ) -o shpinfo shpfix: shpfix.c $(SHPOBJ) $(CC) $(CFLAGS) shpfix.c ${SHPOBJ} $(LINKOPT) -o shpfix shpcat: shpcat.c $(SHPOBJ) $(CC) $(CFLAGS) shpcat.c ${SHPOBJ} $(LINKOPT) -o shpcat shpwkb: shpwkb.c $(SHPGOBJ) $(CC) $(CFLAGS) shpwkb.c ${SHPOBJ} $(LINKOPT) $(GEOOBJ) -o shpwkb shpproj: shpproj.c $(SHPGOBJ) $(CC) $(CFLAGS) shpproj.c $(SHPOBJ) $(GEOOBJ) -lm -lproj $(LINKOPT) -o shpproj shpsort: shpsort.c $(SHPOBJ) $(CC) $(CFLAGS) shpsort.c ${SHPOBJ} $(LINKOPT) -lm -o shpsort dbfinfo: dbfinfo.c $(SHPOBJ) $(CC) $(CFLAGS) dbfinfo.c $(SHPOBJ) $(LINKOPT) -o dbfinfo dbfcat: dbfcat.c $(SHPOBJ) $(CC) $(CFLAGS) dbfcat.c $(SHPOBJ) $(LINKOPT) -o dbfcat Shape_PointInPoly: Shape_PointInPoly.cpp $(SHPOBJ) $(CXX) $(CFLAGS) Shape_PointInPoly.cpp $(SHPOBJ) $(LINKOPT) \ -o Shape_PointInPoly check: testproj testproj: tests/shpproj.sh shapelib-1.3.0/contrib/shpfix.c0000640042715500116100000000712011612707332015726 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * shpfix * * * gcc -c shpfix.c shpopen.c -o shpfix * * Utility program to fix nulls and inconsistencies in Shapefiles * as happens from time to time * * Simply load and rewrite each record, parameter fixrex allow user to null * a particularly nasty record if needed * */ #include #include #include "shapefil.h" int main( int argc, char ** argv ) { SHPHandle hSHP, cSHP; int nShapeType, cShapeType, nEntities, i; double adBounds[4]; SHPObject *shape; int fix_rec; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc <= 3 ) { printf( "shpfix shpfile new_file \n" ); exit( 1 ); } fix_rec = atoi (argv[3]); fix_rec --; /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( argv[1], "rb+" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( hSHP, &nEntities, &nShapeType, NULL, NULL ); /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ cSHP = SHPCreate( argv[2], nShapeType ); if( cSHP == NULL ) { printf( "Unable to open:%s\n", argv[2] ); exit( 1 ); } SHPGetInfo( cSHP, NULL, &cShapeType, &(adBounds[0]), &(adBounds[2]) ); /* -------------------------------------------------------------------- */ /* Skim over the list of shapes, printing all the vertices. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nEntities; i++ ) { shape = SHPReadObject( hSHP, i ); if ( i == fix_rec ) { shape->nParts = 0; shape->nVertices = 0; } SHPWriteObject( cSHP, -1, shape ); SHPDestroyObject ( shape ); } SHPClose ( hSHP ); SHPClose ( cSHP ); } shapelib-1.3.0/contrib/shpproj.c0000640042715500116100000001676411612707332016130 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * requires shapelib 1.2 * gcc shpproj ../shpopen.o ../dbfopen.o shpgeo.o -lm -lproj -o shpproj * * this requires linking with the PROJ4.3 projection library available from * * ftp://kai.er.usgs.gov/ftp/PROJ.4 * * * SHPGeo must be compiled with -DPROJ4 support * * $Log: shpproj.c,v $ * Revision 1.10 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.9 2002-01-15 14:37:08 warmerda * upgrade to use proj_api.h * * Revision 1.8 2002/01/11 15:47:26 warmerda * several fixes * * Revision 1.7 2002/01/11 15:23:28 warmerda * use text mode reading and writing .prj files * * Revision 1.6 1999/05/26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * Revision 1.2 1999/05/13 19:30:52 warmerda * Removed libgen.h, added url for PROJ.4, and corrected unsafe return of * local variable in asFileName(). * */ #include #include #include #include "shapefil.h" #include "shpgeo.h" int main( int argc, char ** argv ) { SHPHandle old_SHP, new_SHP; DBFHandle old_DBF, new_DBF; int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart, j; double *padVertices, adBounds[4]; const char *pszPlus; DBFFieldType idfld_type; SHPObject *psCShape; FILE *ifp = NULL; int idfld, nflds; char kv[257] = ""; char idfldName[120] = ""; char fldName[120] = ""; char shpFileName[120] = ""; char dbfFileName[120] = ""; char prjFileName[120] = ""; char parg[80]; double apeture[4]; int inarg, outarg; char *DBFRow = NULL; /* for testing only char *in_args[] = { "init=nad83:1002", "units=us-ft" }; char *out_args[] = { "proj=utm", "zone=16", "units=m" }; */ char *in_args[16]; char *out_args[16]; int in_argc = 0 , out_argc = 0, outf_arg; char *arglst; projPJ orig_prj, new_prj; va_list myargs, moargs; if( argc < 4) { printf( "shpproj shp_file new_shp ( -i=in_proj_file | -i=\"in_params\" | -i=geographic ) ( -o=out_info_file | -o=\"out_params\" | -o=geographic ) \n" ); exit( 1 ); } old_SHP = SHPOpen( argv[1], "rb" ); old_DBF = DBFOpen( argv[1], "rb" ); if( old_SHP == NULL || old_DBF == NULL ) { printf( "Unable to open old files:%s\n", argv[1] ); exit( 1 ); } outf_arg = 2; inarg = 0; outarg = 0; for ( i = 3; i < argc; i++ ) { if ( !strncmp ("-i=", argv[i], 3 )) inarg = i; if ( !strncmp ("-o=", argv[i], 3 )) outarg = i; } /* if shapefile has a prj component then use that else try for a file then read args as list */ if( inarg == 0 ) { strcpy( prjFileName, argv[1] ); ifp = fopen( asFileName ( prjFileName, "prj" ),"rt"); } else { ifp = fopen( asFileName ( argv[inarg] + 3, "prj" ),"rt"); } i = 0; if ( ifp ) { if( inarg == 0 ) printf ("using default file proj params from <- %s\n", asFileName ( prjFileName, "prj" ) ); else printf ("using file proj params from <- %s\n", asFileName ( argv[inarg] + 3, "prj" ) ); while( fscanf( ifp, "%s", parg) != EOF ) { in_args[i] = malloc ( strlen(parg)+1 ); strcpy ( in_args[i], parg); i++; } in_argc = i; fclose (ifp); } else { if ( inarg > 0 ) { arglst = argv[inarg] + 3; j = 0; i = 0; while ( j < strlen (arglst) ) { in_argc += sscanf ( arglst + j, "%s", parg); in_args[i] = malloc( strlen (parg)+1); strcpy (in_args[i], parg); i++; j += strlen (parg) +1; if ( arglst[j] + 1 == 0 ) j = strlen (argv[inarg]); } } } i = 0; if ( outarg > 0 ) ifp = fopen( asFileName ( argv[outarg] + 3, "prj" ),"rt"); if ( ifp ) { while( fscanf( ifp, "%s", parg) != EOF ) { out_args[i] = malloc ( strlen(parg)); strcpy ( out_args[i], parg); i++; } out_argc = i; fclose (ifp); } else { if ( outarg > 0 ) { arglst = argv[outarg] + 3; j = 0; i = 0; while ( j < strlen (arglst) ) { out_argc += sscanf ( arglst + j, "%s", parg); out_args[i] = malloc( strlen (parg)+1); strcpy (out_args[i], parg); i++; j += strlen (parg) +1; if ( arglst[j] + 1 == 0 ) j = strlen (argv[outarg]); } } } if ( !strcmp( argv[inarg], "-i=geographic" )) in_argc = 0; if ( !strcmp( argv[outarg], "-o=geographic" )) out_argc = 0; orig_prj = SHPSetProjection ( in_argc, in_args ); new_prj = SHPSetProjection ( out_argc, out_args ); if ( !(( (!in_argc) || orig_prj) && ( (!out_argc) || new_prj) )) { fprintf (stderr, "unable to process projection, exiting...\n"); exit(1); } SHPGetInfo( old_SHP, &nEntities, &nShapeType, NULL, NULL); new_SHP = SHPCreate ( argv[outf_arg], nShapeType ); new_DBF = DBFCloneEmpty (old_DBF, argv[outf_arg]); if( new_SHP == NULL || new_DBF == NULL ) { printf( "Unable to create new files:%s\n", argv[outf_arg] ); exit( 1 ); } DBFRow = (char *) malloc ( (old_DBF->nRecordLength) + 15 ); for( i = 0; i < nEntities; i++ ) { int j; psCShape = SHPReadObject ( old_SHP, i ); SHPProject (psCShape, orig_prj, new_prj ); SHPWriteObject ( new_SHP, -1, psCShape ); SHPDestroyObject ( psCShape ); memcpy ( DBFRow, DBFReadTuple ( old_DBF, i ), old_DBF->nRecordLength ); DBFWriteTuple ( new_DBF, new_DBF->nRecords, DBFRow ); } SHPFreeProjection ( orig_prj ); SHPFreeProjection ( new_prj ); /* store projection params into prj file */ ifp = fopen( asFileName ( argv[outf_arg], "prj" ),"wt"); if ( ifp ) { if ( out_argc == 0 ) { fprintf( ifp, "proj=geographic\n" ); } else { for ( i = 0; i < out_argc; i++ ) fprintf( ifp, "%s\n", out_args[i]); } fclose (ifp); } SHPClose( old_SHP ); SHPClose( new_SHP ); DBFClose( old_DBF ); DBFClose( new_DBF ); printf ("\n"); } shapelib-1.3.0/contrib/shpcentrd.c0000640042715500116100000001121211612707332016414 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * this code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * shpcentrd.c - compute XY centroid for complex shapes * and create a new SHPT_PT file of then * specifically undo compound objects but not complex ones * * * $Log: shpcentrd.c,v $ * Revision 1.3 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.2 1999-05-26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * * */ /* the centroid is defined as * * Cx = sum (x dArea ) / Total Area * and * Cy = sum (y dArea ) / Total Area */ #include #include #include "shapefil.h" #include "shpgeo.h" int main( int argc, char ** argv ) { SHPHandle old_SHP, new_SHP; DBFHandle old_DBF, new_DBF; int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart; double *padVertices, adBounds[4]; const char *pszPlus; DBFFieldType idfld_type; int idfld, nflds; char kv[257] = ""; char idfldName[120] = ""; char fldName[120] = ""; char shpFileName[120] = ""; char dbfFileName[120] = ""; double apeture[4]; char *DBFRow = NULL; int Cpan[2] = { 0,0 }; int byRing = 1; PT Centrd; SHPObject *psCShape, *cent_pt; if( argc < 3 ) { printf( "shpcentrd shp_file new_shp_file\n" ); exit( 1 ); } old_SHP = SHPOpen (argv[1], "rb" ); old_DBF = DBFOpen (argv[1], "rb"); if( old_SHP == NULL || old_DBF == NULL ) { printf( "Unable to open old files:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( old_SHP, &nEntities, &nShapeType, NULL, NULL ); new_SHP = SHPCreate ( argv[2], SHPT_POINT ); new_DBF = DBFCloneEmpty (old_DBF, argv[2]); if( new_SHP == NULL || new_DBF == NULL ) { printf( "Unable to create new files:%s\n", argv[2] ); exit( 1 ); } DBFRow = (char *) malloc ( (old_DBF->nRecordLength) + 15 ); #ifdef DEBUG printf ("ShpCentrd using shpgeo \n"); #endif for( i = 0; i < nEntities; i++ ) { int res ; psCShape = SHPReadObject( old_SHP, i ); if ( byRing == 1 ) { int ring; for ( ring = 0; ring < psCShape->nParts; ring ++ ) { SHPObject *psO; psO = SHPClone ( psCShape, ring, ring + 1 ); Centrd = SHPCentrd_2d ( psO ); cent_pt = SHPCreateSimpleObject ( SHPT_POINT, 1, (double*) &(Centrd.x), (double*) &(Centrd.y), NULL ); SHPWriteObject ( new_SHP, -1, cent_pt ); memcpy ( DBFRow, DBFReadTuple ( old_DBF, i ), old_DBF->nRecordLength ); DBFWriteTuple ( new_DBF, new_DBF->nRecords, DBFRow ); SHPDestroyObject ( cent_pt ); SHPDestroyObject ( psO ); } } else { Centrd = SHPCentrd_2d ( psCShape ); cent_pt = SHPCreateSimpleObject ( SHPT_POINT, 1, (double*) &(Centrd.x), (double*) &(Centrd.y), NULL ); SHPWriteObject ( new_SHP, -1, cent_pt ); memcpy ( DBFRow, DBFReadTuple ( old_DBF, i ), old_DBF->nRecordLength ); DBFWriteTuple ( new_DBF, new_DBF->nRecords, DBFRow ); SHPDestroyObject ( cent_pt ); } } SHPClose( old_SHP ); SHPClose( new_SHP ); DBFClose( old_DBF ); DBFClose( new_DBF ); printf ("\n"); } shapelib-1.3.0/contrib/shpgeo.h0000640042715500116100000001223507421037210015714 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * shpgeo.h * * support for geometric and other additions to shapelib * * * $Log: shpgeo.h,v $ * Revision 1.3 2002-01-15 14:36:56 warmerda * upgrade to use proj_api.h * * Revision 1.2 1999/05/26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * */ /* I'm using some shorthand throughout this file * R+ is a Clockwise Ring and is the positive portion of an object * R- is a CounterClockwise Ring and is a hole in a R+ * A complex object is one having at least one R- * A compound object is one having more than one R+ * A simple object has one and only one element (R+ or R-) * * The closed ring constraint is for polygons and assumed here * Arcs or LineStrings I am calling Rings (generically open or closed) * Point types are vertices or lists of vertices but not Rings * * SHPT_POLYGON, SHPT_POLYGONZ, SHPT_POLYGONM and SHPT_MULTIPATCH * can have SHPObjects that are compound as well as complex * * SHP_POINT and its Z and M derivatives are strictly simple * MULTI_POINT, SHPT_ARC and their derivatives may be simple or compound * */ #ifndef SHPGEO_H #define SHPGEO_H #ifdef __cplusplus extern "C" { #endif #include "proj_api.h" #define SHPD_POINT 1 #define SHPD_LINE 2 #define SHPD_AREA 4 #define SHPD_Z 8 #define SHPD_MEASURE 16 /* move these into a ogis header file ogis.h */ #define OGIST_UNKNOWN 0 #define OGIST_POINT 1 #define OGIST_LINESTRING 2 #define OGIST_POLYGON 3 #define OGIST_MULTIPOINT 4 #define OGIST_MULTILINE 5 #define OGIST_MULTIPOLYGON 6 #define OGIST_GEOMCOLL 7 typedef struct { int StreamPos; int NeedSwap; char *wStream; } WKBStreamObj; typedef struct { double x; double y; } PT; typedef struct { int cParts; SHPObject *SHPObj; } SHPObjectList; #define LSB_ORDER (int) 1 extern char * asFileName ( const char *fil, char *ext ); extern int SHPProject ( SHPObject *psCShape, projPJ inproj, projPJ outproj ); extern projPJ SHPSetProjection ( int param_cnt, char **params ); extern int SHPFreeProjection ( projPJ p); extern int SHPDimension ( int SHPType ); extern double SHPArea_2d ( SHPObject *psCShape ); extern int SHPRingDir_2d ( SHPObject *psCShape, int Ring ); extern double SHPLength_2d ( SHPObject *psCShape ); extern PT SHPCentrd_2d ( SHPObject *psCShape ); extern PT SHPPointinPoly_2d ( SHPObject *psCShape ); extern PT* SHPPointsinPoly_2d ( SHPObject *psCShape ); extern int RingCentroid_2d ( int nVertices, double *a, double *b, PT *C, double *Area ); extern double RingLength_2d ( int nVertices, double *a, double *b ); extern int RingDir_2d ( int nVertices, double *a, double *b ); extern double RingArea_2d ( int nVertices, double *a, double *b ); extern SHPObject* SHPClone ( SHPObject *psCShape, int lowPart, int highPart ); extern SHPObject* SHPUnCompound ( SHPObject *psCShape, int * ringNumber ); extern SHPObject* SHPIntersect_2d ( SHPObject* a, SHPObject* b ); extern int SHPWriteOGisWKB ( WKBStreamObj *stream_obj, SHPObject *psCShape ); extern SHPObject* SHPReadOGisWKB ( WKBStreamObj *stream_obj ); int SHPWriteOGisPolygon ( WKBStreamObj *stream_obj, SHPObject *psCShape ); int SHPWriteOGisLine ( WKBStreamObj *stream_obj, SHPObject *psCShape ); int SHPWriteOGisPoint ( WKBStreamObj *stream_obj, SHPObject *psCShape ); SHPObject* SHPReadOGisPolygon ( WKBStreamObj *stream_obj ); SHPObject* SHPReadOGisLine ( WKBStreamObj *stream_obj ); SHPObject* SHPReadOGisPoint ( WKBStreamObj *stream_obj ); extern int SHPClean ( SHPObject *psCShape ); extern int SHPOGisType ( int GeomType, int toOGis); void swapD (void *so, unsigned char *in, long bytes); void swapW (void *so, unsigned char *in, long bytes); void SwapG( void *so, void *in, int this_cnt, int this_size ); #ifdef __cplusplus } #endif #endif /* ndef SHPGEO_H */ shapelib-1.3.0/contrib/shpdata.c0000640042715500116100000001022106722661337016057 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * this code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * shpdata.c - utility program for testing elements of the libraries * * * $Log: shpdata.c,v $ * Revision 1.2 1999-05-26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * * */ #include "shapefil.h" #include "shpgeo.h" int main( int argc, char ** argv ) { SHPHandle old_SHP, new_SHP; DBFHandle old_DBF, new_DBF; int nShapeType, nEntities, nVertices, nParts, *panParts, i, iPart; double *padVertices, adBounds[4]; const char *pszPlus; DBFFieldType idfld_type; int idfld, nflds; char kv[257] = ""; char idfldName[120] = ""; char fldName[120] = ""; char shpFileName[120] = ""; char dbfFileName[120] = ""; char *DBFRow = NULL; int Cpan[2] = { 0,0 }; int byRing = 1; PT oCentrd, ringCentrd; SHPObject *psCShape, *cent_pt; double oArea = 0.0, oLen = 0.0; if( argc < 2 ) { printf( "shpdata shp_file \n" ); exit( 1 ); } old_SHP = SHPOpen (argv[1], "rb" ); old_DBF = DBFOpen (argv[1], "rb"); if( old_SHP == NULL || old_DBF == NULL ) { printf( "Unable to open old files:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( old_SHP, &nEntities, &nShapeType, NULL, NULL ); for( i = 0; i < nEntities; i++ ) { int res ; psCShape = SHPReadObject( old_SHP, i ); if ( byRing == 1 ) { int ring, prevStart, ringDir; double ringArea; prevStart = psCShape->nVertices; for ( ring = (psCShape->nParts - 1); ring >= 0; ring-- ) { SHPObject *psO; int j, numVtx, rStart; rStart = psCShape->panPartStart[ring]; if ( ring == (psCShape->nParts -1) ) { numVtx = psCShape->nVertices - rStart; } else { numVtx = psCShape->panPartStart[ring+1] - rStart; } printf ("(shpdata) Ring(%d) (%d for %d) \n", ring, rStart, numVtx); psO = SHPClone ( psCShape, ring, ring + 1 ); ringDir = SHPRingDir_2d ( psO, 0 ); ringArea = RingArea_2d (psO->nVertices,(double*) psO->padfX, (double*) psO->padfY); RingCentroid_2d ( psO->nVertices, (double*) psO->padfX, (double*) psO->padfY, &ringCentrd, &ringArea); printf ("(shpdata) Ring %d, %f Area %d dir \n", ring, ringArea, ringDir ); SHPDestroyObject ( psO ); printf ("(shpdata) End Ring \n"); } /* (ring) [0,nParts */ } /* by ring */ oArea = SHPArea_2d ( psCShape ); oLen = SHPLength_2d ( psCShape ); oCentrd = SHPCentrd_2d ( psCShape ); printf ("(shpdata) Part (%d) %f Area %f length, C (%f,%f)\n", i, oArea, oLen, oCentrd.x, oCentrd.y ); } SHPClose( old_SHP ); DBFClose( old_DBF ); printf ("\n"); } shapelib-1.3.0/contrib/ShapeFileII.pas0000640042715500116100000002564107660520543017065 0ustar warmerdameng{ /****************************************************************************** * $Id: ShapeFileII.pas,v 1.3 2003-05-14 20:04:51 warmerda Exp $ * * Project: Shapelib * Purpose: Delphi Pascal interface to Shapelib. * Author: Kevin Meyer (Kevin@CyberTracker.co.za) * ****************************************************************************** * Copyright (c) 2002, Keven Meyer (Kevin@CyberTracker.co.za) * * 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: ShapeFileII.pas,v $ * Revision 1.3 2003-05-14 20:04:51 warmerda * Changed fpSHP and fpSHX to integer at suggestion of Ivan Lucena. * * Revision 1.2 2002/01/21 14:09:26 warmerda * Fixed name. * * Revision 1.1 2002/01/17 14:30:37 warmerda * New * */ } unit ShapeFileII; interface //uses { uses clause } // ; { Set compiler to pack on byte boundaries only } {$ALIGN OFF} {$OVERFLOWCHECKS OFF} {$J-} const SHPT_NULL = 0; SHPT_POINT = 1; SHPT_ARC = 3; SHPT_POLYGON = 5; SHPT_MULTIPOINT = 8; SHPT_POINTZ = 11; SHPT_ARCZ = 13; SHPT_POLYGONZ = 15; SHPT_MULTIPOINTZ = 18; SHPT_POINTM = 21; SHPT_ARCM = 23; SHPT_POLYGONM = 25; SHPT_MULTIPOINTM = 28; SHPT_MULTIPATCH = 31; XBASE_FLDHDR_SZ = 32; szAccessBRW = 'rb+'; // *********************** SHP support ************************ type SHPObject = record nSHPType, nShapeId, nParts : LongWord; panPartStart, panPartType : array of LongWord; nVertices : LongWord; padfX, padfY, padfZ, padfM : array of double; dfXMin, dfYMin, dfZMin, dfMMin : double; dfXMax, dfYMax, dfZMax, dfMMax : double; end; SHPObjectHandle = ^SHPObject; SHPBoundsArr = double; SHPInfo = record fpSHP, fpSHX : integer; nShapeType, nFileSize, nRecords, nMaxRecords : LongWord; panRecOffset, panRecSize : array of LongWord; adBoundsMin, adBoundsMax : SHPBoundsArr; bUpdated : LongWord; end; SHPHandle = ^SHPInfo; // *********************** DBF support ************************ DBFInfo = record fp : FILE; nRecords, nRecordLength, nHeaderLength, nFields : LongWord; panFieldOffset, panFieldSize, panFieldDecimals : array of LongWord; pachFieldType : LongWord; pszHeader : PChar; nCurrentRecord, bCurrentRecordModified : LongWord; pszCurrentRecord : PChar; bNoHeader, bUpdated : LongWord; end; DBFHandle = ^DBFInfo; DBFFieldType = (DBFTString, DBFTInteger, DBFTDouble, DBFTInvalid) ; // *********************** SHP func declarations ************************ {$ALIGN ON} function SHPOpen(pszShapeFile, pszAccess : PChar) : SHPHandle;cdecl; procedure SHPGetInfo(hSHP : SHPHandle; var pnEntities, pnShapeType : LongWord; var padfMinBoud, padfMaxBound : SHPBoundsArr);cdecl; procedure SHPClose(hSHP : SHPHandle);cdecl; function SHPReadObject(hSHP : SHPHandle; iShape : LongWord): SHPObjectHandle;cdecl; function SHPCreate(pszShapeFile : PChar; nShapeType : LongWord):SHPHandle;cdecl; function SHPWriteObject(hSHP : SHPHandle; iShape : LongWord; psObject : SHPObjectHandle): LongWord;cdecl; function SHPCreateSimpleObject(nSHPType, nVertices : LongWord; var padfX, padfY, padfZ : double):SHPObjectHandle;cdecl; procedure SHPDestroy(psObject : SHPObjectHandle);cdecl; procedure SHPComputeExtents(psObject : SHPObjectHandle);cdecl; function SHPCreateObject(nSHPType, iShape, nParts : LongWord; var panPartStart, panPartType : LongWord; nVertices : LongWord; var padfX, padfY, padfZ, padfM : SHPBoundsArr): SHPObjectHandle;cdecl; function SHPTypeStr(pnShapeType : LongWord): string; // *********************** DBF func declarations ************************ function DBFOpen(pszDBFFile, pszAccess : PChar): DBFHandle;cdecl; function DBFCreate(pszDBFFile : PChar): DBFHandle ;cdecl; function DBFGetFieldCount(hDBF : DBFHandle) : LongWord ;cdecl; function DBFGetRecordCount(hDBF : DBFHandle) : LongWord;cdecl; function DBFGetFieldIndex(hDBF: DBFHandle; pszFieldName : PChar): LongWord;cdecl; function DBFGetFieldInfo(hDBF : DBFHandle; iField : LongWord; pszFieldName : PChar; var pnWidth, pnDecimals : LongWord): DBFFieldType;cdecl; function DBFAddField(hDBF : DBFHandle; pszFieldName : PChar; eType : DBFFieldType; nWidth, nDecimals : LongWord): LongWord;cdecl; function DBFReadIntegerAttribute(hDBF : DBFHandle;iShape, iField : LongWord ): LongWord;cdecl; function DBFReadDoubleAttribute(hDBF : DBFHandle; iShape, iField : LongWord ):double;cdecl; function DBFReadStringAttribute(hDBF : DBFHandle; iShape, iField : LongWord ) : pchar;cdecl; function DBFIsAttributeNULL(hDBF : DBFHandle; iShape, iField : LongWord ): LongWord;cdecl; function DBFWriteIntegerAttribute(hDBF : DBFHandle;iShape, iField, nFieldValue : LongWord): LongWord;cdecl; function DBFWriteDoubleAttribute(hDBF : DBFHandle;iShape, iField : LongWord; dFieldValue : double): LongWord ;cdecl; function DBFWriteStringAttribute(hDBF : DBFHandle;iShape, iField : LongWord; pszFieldValue : PChar): LongWord ;cdecl; function DBFWriteNULLAttribute(hDBF : DBFHandle; iShape, iField : LongWord ) : LongWord;cdecl; procedure DBFClose(hDBF : DBFHandle);cdecl; function DBFGetNativeFieldType(hDBF : DBFHandle; iField : LongWord) : Char;cdecl; // *********************** SHP implementation ************************ implementation // ***************************************************************************** function SHPCreateSimpleObject(nSHPType, nVertices : LongWord; var padfX, padfY, padfZ : double):SHPObjectHandle;external 'shapelib.dll' name 'SHPCreateSimpleObject'; function SHPOpen(pszShapeFile, pszAccess : PChar) : SHPHandle; external 'shapelib.dll' name 'SHPOpen'; procedure SHPGetInfo(hSHP : SHPHandle; var pnEntities, pnShapeType : LongWord; var padfMinBoud, padfMaxBound : SHPBoundsArr);external 'shapelib.dll' name 'SHPGetInfo'; procedure SHPClose(hSHP : SHPHandle);external 'shapelib.dll' name 'SHPClose'; function SHPReadObject(hSHP : SHPHandle; iShape : LongWord) : SHPObjectHandle;external 'shapelib.dll' name 'SHPReadObject'; function SHPCreate(pszShapeFile : PChar; nShapeType : LongWord):SHPHandle;external 'shapelib.dll' name 'SHPCreate'; function SHPWriteObject(hSHP : SHPHandle; iShape : LongWord; psObject : SHPObjectHandle): LongWord;cdecl;external 'shapelib.dll' name 'SHPWriteObject'; procedure SHPDestroy(psObject : SHPObjectHandle);external 'shapelib.dll' name 'SHPDestroyObject'; procedure SHPComputeExtents(psObject : SHPObjectHandle);external 'shapelib.dll' name 'SHPComputeExtents'; function SHPCreateObject(nSHPType, iShape, nParts : LongWord; var panPartStart, panPartType : LongWord; nVertices : LongWord; var padfX, padfY, padfZ, padfM : SHPBoundsArr): SHPObjectHandle;external 'shapelib.dll' name 'SHPCreateObject'; // ***************************************************************************** function SHPTypeStr(pnShapeType : LongWord): string; begin case pnShapeType of SHPT_NULL : result := 'NULL'; SHPT_POINT : result := 'POINT'; SHPT_ARC : result := 'ARC'; SHPT_POLYGON : result := 'POLYGON'; SHPT_MULTIPOINT : result := 'MULTIPOINT'; SHPT_POINTZ : result := 'POINTZ'; SHPT_ARCZ : result := 'ARCZ'; SHPT_POLYGONZ : result := 'POLYGONZ'; SHPT_MULTIPOINTZ : result := 'MULTIPOINTZ'; SHPT_POINTM : result := 'POINTM'; SHPT_ARCM : result := 'ARCM'; SHPT_POLYGONM : result := 'POLYGONM'; SHPT_MULTIPOINTM : result := 'MULTIPOINTM'; SHPT_MULTIPATCH : result := 'MULTIPATCH'; else result := '--unknown--'; end; end; // ***************************************************************************** // ***************************************************************************** function DBFOpen(pszDBFFile, pszAccess : PChar): DBFHandle;external 'shapelib.dll'; function DBFCreate(pszDBFFile : PChar): DBFHandle ;external 'shapelib.dll'; function DBFGetFieldCount(hDBF : DBFHandle) : LongWord ;external 'shapelib.dll'; function DBFGetRecordCount(hDBF : DBFHandle) : LongWord;external 'shapelib.dll'; function DBFGetFieldIndex(hDBF: DBFHandle; pszFieldName : PChar): LongWord;external 'shapelib.dll'; function DBFGetFieldInfo(hDBF : DBFHandle; iField : LongWord; pszFieldName : PChar; var pnWidth, pnDecimals : LongWord): DBFFieldType;external 'shapelib.dll'; function DBFAddField(hDBF : DBFHandle; pszFieldName : PChar; eType : DBFFieldType; nWidth, nDecimals : LongWord): LongWord;external 'shapelib.dll'; function DBFReadIntegerAttribute(hDBF : DBFHandle;iShape, iField : LongWord ): LongWord;external 'shapelib.dll'; function DBFReadDoubleAttribute(hDBF : DBFHandle; iShape, iField : LongWord ):double;external 'shapelib.dll'; function DBFReadStringAttribute(hDBF : DBFHandle; iShape, iField : LongWord ) : pchar;external 'shapelib.dll'; function DBFIsAttributeNULL(hDBF : DBFHandle; iShape, iField : LongWord ): LongWord;external 'shapelib.dll'; function DBFWriteIntegerAttribute(hDBF : DBFHandle;iShape, iField, nFieldValue : LongWord): LongWord;external 'shapelib.dll'; function DBFWriteDoubleAttribute(hDBF : DBFHandle;iShape, iField : LongWord; dFieldValue : double): LongWord ;external 'shapelib.dll'; function DBFWriteStringAttribute(hDBF : DBFHandle;iShape, iField : LongWord; pszFieldValue : PChar): LongWord ;external 'shapelib.dll'; function DBFWriteNULLAttribute(hDBF : DBFHandle; iShape, iField : LongWord ) : LongWord;external 'shapelib.dll'; procedure DBFClose(hDBF : DBFHandle);external 'shapelib.dll'; function DBFGetNativeFieldType(hDBF : DBFHandle; iField : LongWord) : Char;external 'shapelib.dll'; // ***************************************************************************** end. shapelib-1.3.0/contrib/shpsort.c0000640042715500116100000003620110072614105016123 0ustar warmerdameng/****************************************************************************** * Copyright (c) 2004, Eric G. Miller * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * shpsort * * Rewrite a shapefile sorted by a field or by the geometry. For polygons, * sort by area, for lines sort by length and do nothing for all others. * * $Log: shpsort.c,v $ * Revision 1.3 2004-07-06 21:23:17 fwarmerdam * minor const warning fix * * Revision 1.2 2004/07/06 21:20:49 fwarmerdam * major upgrade .. sort on multiple fields * * Revision 1.4 2004/06/30 18:19:53 emiller * handle POINTZ, POINTM * * Revision 1.3 2004/06/30 17:40:32 emiller * major rewrite allows sorting on multiple fields. * * Revision 1.2 2004/06/23 23:19:58 emiller * use tuple copy, misc changes * * Revision 1.1 2004/06/23 21:38:17 emiller * Initial revision * * */ #include #include #include #include #include #include "shapefil.h" enum FieldOrderEnum {DESCENDING, ASCENDING}; enum FieldTypeEnum { FIDType = -2, SHPType = -1, StringType = FTString, LogicalType = FTLogical, IntegerType = FTInteger, DoubleType = FTDouble }; struct DataUnion { int null; union { int i; double d; char *s; } u; }; struct DataStruct { int record; struct DataUnion *value; }; /* globals used in sorting, each element could have a pointer to a single data struct, but that's still nShapes pointers more memory. Alternatively, write a custom sort rather than using library qsort. */ int nFields; int *fldIdx; int *fldOrder; int *fldType; int shpType; int nShapes; static struct DataStruct * build_index (SHPHandle shp, DBFHandle dbf); static char * dupstr (const char *); static void copy_related (const char *inName, const char *outName, const char *old_ext, const char *new_ext); static char ** split(const char *arg, const char *delim); static int compare(const void *, const void *); static double area2d_polygon (int n, double *x, double *y); static double shp_area (SHPObject *feat); static double length2d_polyline (int n, double *x, double *y); static double shp_length (SHPObject *feat); int main (int argc, char *argv[]) { SHPHandle inSHP, outSHP; DBFHandle inDBF, outDBF; int len; int i; char **fieldNames; char **strOrder = 0; struct DataStruct *index; int width; int decimals; SHPObject *feat; void *tuple; if (argc < 4) { printf("USAGE: shpsort [<(ASCENDING|DESCENDING)[;...]>]\n"); exit(EXIT_FAILURE); } inSHP = SHPOpen (argv[1], "rb"); if (!inSHP) { fputs("Couldn't open shapefile for reading!\n", stderr); exit(EXIT_FAILURE); } SHPGetInfo(inSHP, &nShapes, &shpType, NULL, NULL); /* If we can open the inSHP, open its DBF */ inDBF = DBFOpen (argv[1], "rb"); if (!inDBF) { fputs("Couldn't open dbf file for reading!\n", stderr); exit(EXIT_FAILURE); } /* Parse fields and validate existence */ fieldNames = split(argv[3], ";"); if (!fieldNames) { fputs("ERROR: parsing field names!\n", stderr); exit(EXIT_FAILURE); } for (nFields = 0; fieldNames[nFields] ; nFields++) { continue; } fldIdx = malloc(sizeof *fldIdx * nFields); if (!fldIdx) { fputs("malloc failed!\n", stderr); exit(EXIT_FAILURE); } for (i = 0; i < nFields; i++) { len = (int)strlen(fieldNames[i]); while(len > 0) { --len; fieldNames[i][len] = (char)toupper((unsigned char)fieldNames[i][len]); } fldIdx[i] = DBFGetFieldIndex(inDBF, fieldNames[i]); if (fldIdx[i] < 0) { /* try "SHAPE" */ if (strcmp(fieldNames[i], "SHAPE") == 0) { fldIdx[i] = -1; } else if (strcmp(fieldNames[i], "FID") == 0) { fldIdx[i] = -2; } else { fprintf(stderr, "ERROR: field '%s' not found!\n", fieldNames[i]); exit(EXIT_FAILURE); } } } /* set up field type array */ fldType = malloc(sizeof *fldType * nFields); if (!fldType) { fputs("malloc failed!\n", stderr); exit(EXIT_FAILURE); } for (i = 0; i < nFields; i++) { if (fldIdx[i] < 0) { fldType[i] = fldIdx[i]; } else { fldType[i] = DBFGetFieldInfo(inDBF, fldIdx[i], NULL, &width, &decimals); if (fldType[i] == FTInvalid) { fputs("Unrecognized field type in dBASE file!\n", stderr); exit(EXIT_FAILURE); } } } /* set up field order array */ fldOrder = malloc(sizeof *fldOrder * nFields); if (!fldOrder) { fputs("malloc failed!\n", stderr); exit(EXIT_FAILURE); } for (i = 0; i < nFields; i++) { /* default to ascending order */ fldOrder[i] = ASCENDING; } if (argc > 4) { strOrder = split(argv[4], ";"); if (!strOrder) { fputs("ERROR: parsing fields ordering!\n", stderr); exit(EXIT_FAILURE); } for (i = 0; i < nFields && strOrder[i]; i++) { if (strcmp(strOrder[i], "DESCENDING") == 0) { fldOrder[i] = DESCENDING; } } } /* build the index */ index = build_index (inSHP, inDBF); /* Create output shapefile */ outSHP = SHPCreate(argv[2], shpType); if (!outSHP) { fprintf(stderr, "%s:%d: couldn't create output shapefile!\n", __FILE__, __LINE__); exit(EXIT_FAILURE); } /* Create output dbf */ outDBF = DBFCloneEmpty(inDBF, argv[2]); if (!outDBF) { fprintf(stderr, "%s:%d: couldn't create output dBASE file!\n", __FILE__, __LINE__); exit(EXIT_FAILURE); } /* Copy projection file, if any */ copy_related(argv[1], argv[2], ".shp", ".prj"); /* Copy metadata file, if any */ copy_related(argv[1], argv[2], ".shp", ".shp.xml"); /* Write out sorted results */ for (i = 0; i < nShapes; i++) { feat = SHPReadObject(inSHP, index[i].record); if (SHPWriteObject(outSHP, -1, feat) < 0) { fprintf(stderr, "%s:%d: error writing shapefile!\n", __FILE__, __LINE__); exit(EXIT_FAILURE); } tuple = (void *) DBFReadTuple(inDBF, index[i].record); if (DBFWriteTuple(outDBF, i, tuple) < 0) { fprintf(stderr, "%s:%d: error writing dBASE file!\n", __FILE__, __LINE__); exit(EXIT_FAILURE); } } SHPClose(inSHP); SHPClose(outSHP); DBFClose(inDBF); DBFClose(outDBF); return EXIT_SUCCESS; } static char ** split(const char *arg, const char *delim) { char *copy = dupstr(arg); char *cptr = copy; char **result = NULL; char **tmp; int i = 0; for (cptr = strtok(copy, delim); cptr; cptr = strtok(NULL, delim)) { tmp = realloc (result, sizeof *result * (i + 1)); if (!tmp && result) { while (i > 0) { free(result[--i]); } free(result); free(copy); return NULL; } result = tmp; result[i++] = dupstr(cptr); } free(copy); if (i) { tmp = realloc(result, sizeof *result * (i + 1)); if (!tmp) { while (i > 0) { free(result[--i]); } free(result); free(copy); return NULL; } result = tmp; result[i++] = NULL; } return result; } static void copy_related (const char *inName, const char *outName, const char *old_ext, const char *new_ext) { char *in; char *out; FILE *inFile; FILE *outFile; int c; size_t name_len = strlen(inName); size_t old_len = strlen(old_ext); size_t new_len = strlen(new_ext); in = malloc(name_len - old_len + new_len + 1); strncpy(in, inName, (name_len - old_len)); strcpy(&in[(name_len - old_len)], new_ext); inFile = fopen(in, "rb"); if (!inFile) { free(in); return; } name_len = strlen(outName); out = malloc(name_len - old_len + new_len + 1); strncpy(out, outName, (name_len - old_len)); strcpy(&out[(name_len - old_len)], new_ext); outFile = fopen(out, "wb"); if (!out) { fprintf(stderr, "%s:%d: couldn't copy related file!\n", __FILE__, __LINE__); free(in); free(out); return; } while ((c = fgetc(inFile)) != EOF) { fputc(c, outFile); } fclose(inFile); fclose(outFile); free(in); free(out); } static char * dupstr (const char *src) { char *dst = malloc(strlen(src) + 1); char *cptr; if (!dst) { fprintf(stderr, "%s:%d: malloc failed!\n", __FILE__, __LINE__); exit(EXIT_FAILURE); } cptr = dst; while ((*cptr++ = *src++)) ; return dst; } #ifdef DEBUG static void PrintDataStruct (struct DataStruct *data) { int i, j; for (i = 0; i < nShapes; i++) { printf("data[%d] {\n", i); printf("\t.record = %d\n", data[i].record); for (j = 0; j < nFields; j++) { printf("\t.value[%d].null = %d\n", j, data[i].value[j].null); if (!data[i].value[j].null) { switch(fldType[j]) { case FIDType: case IntegerType: case LogicalType: printf("\t.value[%d].u.i = %d\n", j, data[i].value[j].u.i); break; case DoubleType: case SHPType: printf("\t.value[%d].u.d = %f\n", j, data[i].value[j].u.d); break; case StringType: printf("\t.value[%d].u.s = %s\n", j, data[i].value[j].u.s); break; } } } puts("}"); } } #endif static struct DataStruct * build_index (SHPHandle shp, DBFHandle dbf) { struct DataStruct *data; SHPObject *feat; int i; int j; /* make array */ data = malloc (sizeof *data * nShapes); if (!data) { fputs("malloc failed!\n", stderr); exit(EXIT_FAILURE); } /* populate array */ for (i = 0; i < nShapes; i++) { data[i].value = malloc(sizeof data[0].value[0] * nFields); if (0 == data[i].value) { fputs("malloc failed!\n", stderr); exit(EXIT_FAILURE); } data[i].record = i; for (j = 0; j < nFields; j++) { data[i].value[j].null = 0; switch (fldType[j]) { case FIDType: data[i].value[j].u.i = i; break; case SHPType: feat = SHPReadObject(shp, i); switch (feat->nSHPType) { case SHPT_NULL: fprintf(stderr, "Shape %d is a null feature!\n", i); data[i].value[j].null = 1; break; case SHPT_POINT: case SHPT_POINTZ: case SHPT_POINTM: case SHPT_MULTIPOINT: case SHPT_MULTIPOINTZ: case SHPT_MULTIPOINTM: case SHPT_MULTIPATCH: /* Y-sort bounds */ data[i].value[j].u.d = feat->dfYMax; break; case SHPT_ARC: case SHPT_ARCZ: case SHPT_ARCM: data[i].value[j].u.d = shp_length(feat); break; case SHPT_POLYGON: case SHPT_POLYGONZ: case SHPT_POLYGONM: data[i].value[j].u.d = shp_area(feat); break; default: fputs("Can't sort on Shapefile feature type!\n", stderr); exit(EXIT_FAILURE); } SHPDestroyObject(feat); break; case FTString: data[i].value[j].null = DBFIsAttributeNULL(dbf, i, fldIdx[j]); if (!data[i].value[j].null) { data[i].value[j].u.s = dupstr(DBFReadStringAttribute(dbf, i, fldIdx[j])); } break; case FTInteger: case FTLogical: data[i].value[j].null = DBFIsAttributeNULL(dbf, i, fldIdx[j]); if (!data[i].value[j].null) { data[i].value[j].u.i = DBFReadIntegerAttribute(dbf, i, fldIdx[j]); } break; case FTDouble: data[i].value[j].null = DBFIsAttributeNULL(dbf, i, fldIdx[j]); if (!data[i].value[j].null) { data[i].value[j].u.d = DBFReadDoubleAttribute(dbf, i, fldIdx[j]); } break; } } } #ifdef DEBUG PrintDataStruct(data); fputs("build_index: sorting array\n", stdout); #endif qsort (data, nShapes, sizeof data[0], compare); #ifdef DEBUG PrintDataStruct(data); fputs("build_index: returning array\n", stdout); #endif return data; } static int compare(const void *A, const void *B) { const struct DataStruct *a = A; const struct DataStruct *b = B; int i; int result = 0; for (i = 0; i < nFields; i++) { if (a->value[i].null && b->value[i].null) { continue; } if (a->value[i].null && !b->value[i].null) { return (fldOrder[i]) ? 1 : -1; } if (!a->value[i].null && b->value[i].null) { return (fldOrder[i]) ? -1 : 1; } switch (fldType[i]) { case FIDType: case IntegerType: case LogicalType: if (a->value[i].u.i < b->value[i].u.i) { return (fldOrder[i]) ? -1 : 1; } if (a->value[i].u.i > b->value[i].u.i) { return (fldOrder[i]) ? 1 : -1; } break; case DoubleType: case SHPType: if (a->value[i].u.d < b->value[i].u.d) { return (fldOrder[i]) ? -1 : 1; } if (a->value[i].u.d > b->value[i].u.d) { return (fldOrder[i]) ? 1 : -1; } break; case StringType: result = strcmp(a->value[i].u.s, b->value[i].u.s); if (result) { return (fldOrder[i]) ? result : -result; } break; default: fprintf(stderr, "compare: Program Error! Unhandled field type! fldType[%d] = %d\n", i, fldType[i]); break; } } return 0; } static double area2d_polygon (int n, double *x, double *y) { double area = 0; int i; for (i = 1; i < n; i++) { area += (x[i-1] + x[i]) * (y[i] - y[i-1]); } return area / 2.0; } static double shp_area (SHPObject *feat) { double area = 0.0; if (feat->nParts == 0) { area = area2d_polygon (feat->nVertices, feat->padfX, feat->padfY); } else { int part, n; for (part = 0; part < feat->nParts; part++) { if (part < feat->nParts - 1) { n = feat->panPartStart[part+1] - feat->panPartStart[part]; } else { n = feat->nVertices - feat->panPartStart[part]; } area += area2d_polygon (n, &(feat->padfX[feat->panPartStart[part]]), &(feat->padfY[feat->panPartStart[part]])); } } /* our area function computes in opposite direction */ return -area; } static double length2d_polyline (int n, double *x, double *y) { double length = 0.0; int i; for (i = 1; i < n; i++) { length += sqrt((x[i] - x[i-1])*(x[i] - x[i-1]) + (y[i] - y[i-1])*(y[i] - y[i-1])); } return length; } static double shp_length (SHPObject *feat) { double length = 0.0; if (feat->nParts == 0) { length = length2d_polyline(feat->nVertices, feat->padfX, feat->padfY); } else { int part, n; for (part = 0; part < feat->nParts; part++) { if (part < feat->nParts - 1) { n = feat->panPartStart[part+1] - feat->panPartStart[part]; } else { n = feat->nVertices - feat->panPartStart[part]; } length += length2d_polyline (n, &(feat->padfX[feat->panPartStart[part]]), &(feat->padfY[feat->panPartStart[part]])); } } return length; } shapelib-1.3.0/contrib/Shape_PointInPoly_README.txt0000640042715500116100000000564007777555475021442 0ustar warmerdameng=============================================================================== Project: Shape_PoinInPoly Purpose: Sample and the function for calculatin a point in a polygon (complex,compound - it doesn't matter). Can be used for labeling. Author: Copyright (c) 2004, Marko Podgorsek, d-mon@siol.net =============================================================================== Requires: shapelib 1.2 (http://shapelib.maptools.org/) Tested and created on platform: Windows 2000 Professional Visual Studio .NET 7.0 P4 2.4 GHz 1GB RAM I just found out about the ShapeLib, GDAL and OGR and I must say that they're all great projects. I belive I'll use some of those libraries in the future. Right now I'm using only shapelib. The thing that led me to the http://wwww.maptools.org was the need of finding the point in poly...but as I found out that even OGR didn't support it. So there I was. I was forced to make my own function. Well, it was fun. I learned a lot. I wrote this function for the Autodesk Autocad 2004 MPolygon, because there was no function to do this in the Object Arx SDK (the Acad programming SDK). Well, it will be in the 2005 release...but, still. There is a function in the Autodesk Map 2004 version...in the menu. Not usefull when you need the coordinates, not the point on the screen... So when the Acad version was done I was thinking of doing it on the Shape files, too. A little bit of changing the structures and variable types (so they're not using Object Arx) and I was done. And here it is....Contribution from me to the ShapeLib world :)...and maybe even OGR (a little bit of changing there). Some statistics: For about 69000 polygons in Autocad picture (.dwg files) Autodesk Map 2004 was creating centroids (the menu command) about 45s (1 scan line) My function, with 3 scan lines took about 5s. And I was drawing the dots on the picture... ------------------------------------------------------------------------------- DPoint2d CreatePointInPoly(SHPObject *psShape, int quality) The second parameter quality tell the function just how many rays shall it use to get the point. quality = 3 works very well, but anything below 5 is good. This doesn't mean that the execution will slow down, but it just finds a good point. That's all. The qality shows on the compound objects (multiple poligons with more than one exterior loop) - if not enough rays, then there may be no centroid. Or the U shaped thin polygon, only the bootom (below the y center line) is fat. Autodesk Map with one scan line will create the centroid on one of the thin parts, because it only uses the y center line. If you have more rays, one will surely pass the fat area and centroid will be created there. ------------------------------------------------------------------------------- Anyone using this function: Just send me an e-mail, so I'll see if I did anything good for the public. And you can send me e-mail with questions also. shapelib-1.3.0/contrib/shpsort.txt0000640042715500116100000000332110072613704016521 0ustar warmerdameng============================= ABOUT =========================================== The program "shpsort" is a standalone program for sorting shapefiles on one or more fields (including the pseudofield "SHAPE") and outputing the results. People may find it useful for forcing drawing order. ============================= AUTHOR ========================================== Eric G. Miller California Department of Fish and Game 2004-06-30 ============================= USAGE =========================================== shpsort {SORT_ORDER;SORT_ORDER...} ============================= DETAILS ========================================= INFILE The input shapefile OUTFILE The output shapefile SORT_FIELD Any attribute field of the shapefile, including "SHAPE" SORT_ORDER Specify "ASCENDING" or "DESCENDING" for each SORT_FIELD. This field is optional, and is assumed to be ASCENDING unless the exact word "DESCENDING" is specified (case matters). When sorting on the "SHAPE" the records are sorted as follows: * Null shapes are treated as any other null field and will sort to the top in ASCENDING mode. A warning is issued for each null shape encountered. * POINT, POINTM, POINTZ, MULTIPOINT, MULTIPOINTM, MULTIPOINTZ and MULTIPATCH are all sorted by the maximum "Y" value of their envelopes (not particularly useful). * POLYLINE, POLYLINEZ and POLYLINEM are sorted by total 2d shape length. * POLYGON, POLYGONZ and POLYGONM are sorted by the 2d shape area. Shapes are assumed to be in canonical ordering, so that the area of interior rings (if any) is subtracted from the area of exterior rings. shapelib-1.3.0/contrib/Shape_PointInPoly.cpp0000640042715500116100000001644607777555475020376 0ustar warmerdameng/****************************************************************************** * $Id: Shape_PointInPoly.cpp,v 1.1 2004-01-09 16:47:57 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Commandline program to generate points-in-polygons from a * shapefile as a shapefile. * Author: Marko Podgorsek, d-mon@siol.net * ****************************************************************************** * Copyright (c) 2004, Marko Podgorsek, d-mon@siol.net * * 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: Shape_PointInPoly.cpp,v $ * Revision 1.1 2004-01-09 16:47:57 fwarmerdam * New * */ static char rcsid[] = "$Id: Shape_PointInPoly.cpp,v 1.1 2004-01-09 16:47:57 fwarmerdam Exp $"; #include #include #include #include #define MAXINTERSECTIONPOINTS 255 enum loopDir { kExterior, kInterior, kError }; struct DPoint2d { DPoint2d() { x = y = 0.0; }; DPoint2d(double x, double y) { this->x = x; this->y = y; }; double x,y; }; struct IntersectPoint { IntersectPoint(void) { x = y = 0.0; boundry_nmb = 0; loopdirection = kError; }; double x,y; int boundry_nmb; loopDir loopdirection; }; loopDir LoopDirection(DPoint2d *vertices, int vertsize) { int i; double sum = 0.0; for(i=0;i0) return kInterior; else return kExterior; } DPoint2d CreatePointInPoly(SHPObject *psShape, int quality) { int i, j, k, end, vert, pointpos; double part, dx, xmin, xmax, ymin, ymax, y, x3, x4, y3, y4, len, maxlen = 0; DPoint2d *vertices; loopDir direction; IntersectPoint mp1, mp2, point1, point2, points[MAXINTERSECTIONPOINTS]; xmin = psShape->dfXMin; ymin = psShape->dfYMin; xmax = psShape->dfXMax; ymax = psShape->dfYMax; part = (ymax-ymin)/(quality+1); dx = xmax-xmin; for(i=0;inParts;j++) { if(j==psShape->nParts-1) end = psShape->nVertices; else end = psShape->panPartStart[j+1]; vertices = new DPoint2d [end-psShape->panPartStart[j]]; for(k=psShape->panPartStart[j],vert=0;kpadfX[k]; vertices[vert++].y = psShape->padfY[k]; } direction = LoopDirection(vertices, vert); for(k=0;k= y && y4 < y) || (y3 <= y && y4 > y)) //I check >= only once, because if it's not checked now (y3) it will be in the next iteration (which is y4 now) { point1.boundry_nmb = j; point1.loopdirection = direction; x3 = vertices[k].x; x4 = vertices[k+1].x; if(y3==y) { point1.y = y3; point1.x = x3; if(direction == kInterior) //add point 2 times if the direction is interior, so that the final count of points is even { points[pointpos++]=point1; } } else { point1.x = xmin+(((((x4-x3)*(y-y3))-((y4-y3)*(xmin-x3)))/((y4-y3)*dx))*dx); //striped down calculation of intersection of 2 lines point1.y = y; } points[pointpos++]=point1; } } delete [] vertices; } for(j=1;j0;k--) { if(points[k].x < points[k-1].x) { point1 = points[k]; points[k] = points[k-1]; points[k-1] = point1; } else { break; } } } for(j=0;j= maxlen) { maxlen = len; mp1 = point1; mp2 = point2; } } } } return DPoint2d((mp1.x+mp2.x)*0.5, (mp1.y+mp2.y)*0.5); } int main(int argc, char* argv[]) { if(argc != 3) { printf("Usage: %s shpfile_path quality\n", argv[0]); return 1; } int i, nEntities, quality; SHPHandle hSHP; SHPObject *psShape; DPoint2d pt; quality = atoi(argv[2]); hSHP = SHPOpen(argv[1], "rb"); SHPGetInfo(hSHP, &nEntities, NULL, NULL, NULL); printf("PointInPoly v1.0, by Marko Podgorsek\n----------------\n"); for( i = 0; i < nEntities; i++ ) { psShape = SHPReadObject( hSHP, i ); if(psShape->nSHPType == SHPT_POLYGON) { pt = CreatePointInPoly(psShape, quality); printf("%d: x=%f y=%f\n",i, pt.x,pt.y); } SHPDestroyObject( psShape ); } SHPClose(hSHP); return 0; } shapelib-1.3.0/contrib/dbfcat.c0000640042715500116100000001060511612707332015652 0ustar warmerdameng/* * Copyright (c) 1995 Frank Warmerdam * * This code is in the public domain. * * $Log: dbfcat.c,v $ * Revision 1.2 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.1 1999-05-26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * * Revision 1.3 1995/10/21 03:15:01 warmerda * Changed to use binary file access. * * Revision 1.2 1995/08/04 03:16:22 warmerda * Added header. * */ static char rcsid[] = "$Id: dbfcat.c,v 1.2 2011-07-24 03:17:46 fwarmerdam Exp $"; #include #include #include "shapefil.h" int main( int argc, char ** argv ) { DBFHandle hDBF; int *panWidth, i, iRecord; char szFormat[32], szField[1024]; char cTitle[32], nTitle[32]; int nWidth, nDecimals; int cnWidth, cnDecimals; DBFHandle cDBF; DBFFieldType hType,cType; int ci, ciRecord; char tfile[160]; int hflds, j, cflds; int verbose = 0; int force = 0; int mismatch = 0; int matches = 0; char fld_m[256]; int shift = 0; char type_names[4][15] = {"integer", "string", "double", "double"}; if( argc < 3 ) { printf( "dbfcat [-v] [-f] from_DBFfile to_DBFfile\n" ); exit( 1 ); } if ( strcmp ("-v", argv[1] ) == 0 ) { shift = 1; verbose = 1; } if ( strcmp ("-f", argv[1 + shift] ) == 0 ) { shift ++; force = 1; } if ( strcmp ("-v", argv[1 + shift] ) == 0 ) { shift ++; verbose = 1; } strcpy (tfile, argv[1 + shift]); strcat (tfile, ".dbf"); hDBF = DBFOpen( tfile, "rb" ); if( hDBF == NULL ) { printf( "DBFOpen(%s.dbf,\"r\") failed for From_DBF.\n", tfile ); exit( 2 ); } strcpy (tfile, argv[2 + shift]); strcat (tfile, ".dbf"); cDBF = DBFOpen( tfile, "rb+" ); if( cDBF == NULL ) { printf( "DBFOpen(%s.dbf,\"rb+\") failed for To_DBF.\n", tfile ); exit( 2 ); } if( DBFGetFieldCount(hDBF) == 0 ) { printf( "There are no fields in this table!\n" ); exit( 3 ); } hflds = DBFGetFieldCount(hDBF); cflds = DBFGetFieldCount(cDBF); matches = 0; for( i = 0; i < hflds; i++ ) { char szTitle[18]; char cname[18]; int j; hType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals ); fld_m[i] = -1; for ( j = 0; j < cflds; j ++ ) { cType = DBFGetFieldInfo( cDBF, j, cname, &cnWidth, &cnDecimals ); if ( strcmp (cname, szTitle) == 0 ) { if ( hType != cType ) { printf ("Incompatible fields %s(%s) != %s(%s),\n", type_names[hType],nTitle,type_names[cType],cTitle); mismatch = 1; } fld_m[i] = j; if ( verbose ) { printf("%s %s(%d,%d) <- %s %s(%d,%d)\n", cname, type_names[cType], cnWidth, cnDecimals, szTitle, type_names[hType], nWidth, nDecimals); } j = cflds; matches = 1; } } } if ( (matches == 0 ) && !force ) { printf ("ERROR: No field names match for tables, cannot proceed\n use -f to force processing using blank records\n"); exit(-1); } if ( mismatch && !force ) { printf ("ERROR: field type mismatch cannot proceed\n use -f to force processing using attempted conversions\n"); exit(-1); } for( iRecord = 0; iRecord < DBFGetRecordCount(hDBF); iRecord++ ) { ciRecord = DBFGetRecordCount( cDBF ); for ( i = 0; i < hflds;i ++ ) { double cf; ci = fld_m[i]; if ( ci != -1 ) { cType = DBFGetFieldInfo( cDBF, ci, cTitle, &cnWidth, &cnDecimals ); hType = DBFGetFieldInfo( hDBF, i, nTitle, &nWidth, &nDecimals ); switch( cType ) { case FTString: DBFWriteStringAttribute(cDBF, ciRecord, ci, (char *) DBFReadStringAttribute( hDBF, iRecord, i ) ); break; case FTInteger: DBFWriteIntegerAttribute(cDBF, ciRecord, ci, (int) DBFReadIntegerAttribute( hDBF, iRecord, i ) ); break; case FTDouble: /* cf = DBFReadDoubleAttribute( hDBF, iRecord, i ); printf ("%s <- %s (%f)\n", cTitle, nTitle, cf); */ DBFWriteDoubleAttribute(cDBF, ciRecord, ci, (double) DBFReadDoubleAttribute( hDBF, iRecord, i ) ); break; } } } /* fields names match */ } if ( verbose ) { printf (" %d records appended \n\n", iRecord); } DBFClose( hDBF ); DBFClose( cDBF ); return( 0 ); } shapelib-1.3.0/contrib/doc/0000750042715500116100000000000011741051742015025 5ustar warmerdamengshapelib-1.3.0/contrib/doc/shpproj.txt0000640042715500116100000000452406716432477017277 0ustar warmerdameng shpproj using the projection tools proj and invproj we have implemented a shapefile projection utility shpproj shp_file new_shp ( -i=in_proj_file | -i="in_params" | -i=geographic ) ( -o=out_info_file | -o="out_params" | -o=geographic ) INPUT Input can come from one of three sources. A projection parameter file, directly through parameters or geographic. If the shapefile has an associated prj file, name the same as the shapefile but ending in ".prj" it will be used by default ignoring all other parameters. If input is omitted it defaults to geographic, unless the default prj file exists.. OUTPUT Output can come from one of three sources. A projection parameter file, directly through parameters or geographic. If output is omitted it defaults to geographic. PROJECTION PARAMETER FILE This file MUST end with the extension ".prj". It has the form of one projection parameter per line. Parameters can be in any order. PROJECTION PARAMETERS Are the same as used by proj and invproj. use proj -lP to see available projections proj -lu to see available units proj -le to see available ellipsoid USAGE the following example projects file rowtest to row3, moving data from Stateplane NAD83 zone 1002 to utm zone 16 in meters shpproj rowtest row -i="init=nad83:1002 units=us-ft" -o="proj=utm zone=16 units=m" shpproj rowtest row3 -o="proj=utm zone=18 units=m" -i="zone=16 proj=utm units=us-ft" shpproj rowtest row3 -o="proj=utm zone=18 units=m" shpproj rowtest row3 -i=myfile.prj -o=geographic shpproj rowtest row3 -is=myfile.prj Datums Stateplane data can be accessed by the init function init=nad83:1003 which is of the form datum:FIPSzone To move from NAD27 to NAD83 or otherwise the shpproj utility moves to geographic coordinates and the back to the desired datum. proj can handle direct datum to datum conversions but it is umimplemented here. for a complete listing of FIPSZones by datum read nad/nad.lst in the PROJ4 library CAUTION It is possible to get very poor results for projection values when using coordinates VERY far away from the intended scope of the projection. An example of a poor projection choice would be to move from nad83:1002 (Georgia West) for data in California into utm. The resulting data will be much less accurate than if it had started as geographic. shapelib-1.3.0/contrib/shpgeo.c0000640042715500116100000014241711612707332015723 0ustar warmerdameng/****************************************************************************** * Copyright (c) 1999, Carl Anderson * * This code is based in part on the earlier work of Frank Warmerdam * * 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. ****************************************************************************** * * requires shapelib 1.2 * gcc shpproj shpopen.o dbfopen.o -lm -lproj -o shpproj * * this may require linking with the PROJ4 projection library available from * * http://www.remotesensing.org/proj * * use -DPROJ4 to compile in Projection support * * $Log: shpgeo.c,v $ * Revision 1.13 2011-07-24 03:17:46 fwarmerdam * include string.h and stdlib.h where needed in contrib (#2146) * * Revision 1.12 2007-09-03 23:17:46 fwarmerdam * fix SHPDimension() function * * Revision 1.11 2006/11/06 20:45:58 fwarmerdam * Fixed SHPProject. * * Revision 1.10 2006/11/06 20:44:58 fwarmerdam * SHPProject() uses pj_transform now * * Revision 1.9 2006/01/25 15:33:50 fwarmerdam * fixed ppsC assignment maptools bug 1263 * * Revision 1.8 2002/01/15 14:36:56 warmerda * upgrade to use proj_api.h * * Revision 1.7 2002/01/11 15:22:04 warmerda * fix many warnings. Lots of this code is cruft. * * Revision 1.6 2001/08/30 13:42:31 warmerda * avoid use of auto initialization of PT for VC++ * * Revision 1.5 2000/04/26 13:24:06 warmerda * made projUV handling safer * * Revision 1.4 2000/04/26 13:17:15 warmerda * check if projUV or UV * * Revision 1.3 2000/03/17 14:15:16 warmerda * Don't try to use system nan.h ... doesn't always exist. * * Revision 1.2 1999/05/26 02:56:31 candrsn * updates to shpdxf, dbfinfo, port from Shapelib 1.1.5 of dbfcat and shpinfo * */ #include #include #include "shapefil.h" #ifndef NAN #include "my_nan.h" #endif #include "shpgeo.h" /* I'm using some shorthand throughout this file * R+ is a Clockwise Ring and is the positive portion of an object * R- is a CounterClockwise Ring and is a hole in a R+ * A complex object is one having at least one R- * A compound object is one having more than one R+ * A simple object has one and only one element (R+ or R-) * * The closed ring constraint is for polygons and assumed here * Arcs or LineStrings I am calling Rings (generically open or closed) * Point types are vertices or lists of vertices but not Rings * * SHPT_POLYGON, SHPT_POLYGONZ, SHPT_POLYGONM and SHPT_MULTIPATCH * can have SHPObjects that are compound as well as complex * * SHP_POINT and its Z and M derivatives are strictly simple * MULTI_POINT, SHPT_ARC and their derivatives may be simple or compound * */ /* ************************************************************************** * asFileName * * utility function, toss part of filename after last dot * * **************************************************************************/ char * asFileName ( const char *fil, char *ext ) { char pszBasename[120]; static char pszFullname[120]; int i; /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ // pszFullname = (char*) malloc(( strlen(fil)+5 )); // pszBasename = (char *) malloc(strlen(fil)+5); strcpy( pszBasename, fil ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; /* -------------------------------------------------------------------- */ /* Note that files pulled from */ /* a PC to Unix with upper case filenames won't work! */ /* -------------------------------------------------------------------- */ // pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.%s", pszBasename, ext ); return ( pszFullname ); } /************************************************************************/ /* SfRealloc() */ /* */ /* A realloc cover function that will access a NULL pointer as */ /* a valid input. */ /************************************************************************/ /* copied directly from shpopen.c -- maybe expose this in shapefil.h */ static void * SfRealloc( void * pMem, int nNewSize ) { if( pMem == NULL ) return( (void *) malloc(nNewSize) ); else return( (void *) realloc(pMem,nNewSize) ); } /* ************************************************************************** * SHPPRoject * * Project points using projection handles, for use with PROJ4.3 * * act as a wrapper to protect against library changes in PROJ * * **************************************************************************/ int SHPProject ( SHPObject *psCShape, projPJ inproj, projPJ outproj ) { #ifdef PROJ4 int j; if ( pj_is_latlong(inproj) ) { for(j=0; j < psCShape->nVertices; j++) { psCShape->padfX[j] *= DEG_TO_RAD; psCShape->padfY[j] *= DEG_TO_RAD; } } pj_transform(inproj, outproj, psCShape->nVertices, 0, psCShape->padfX, psCShape->padfY, NULL); if ( pj_is_latlong(outproj) ) { for(j=0; j < psCShape->nVertices; j++) { psCShape->padfX[j] *= RAD_TO_DEG; psCShape->padfY[j] *= RAD_TO_DEG; } } /* Recompute new Extents of projected Object */ SHPComputeExtents ( psCShape ); #endif return ( 1 ); } /* ************************************************************************** * SHPSetProjection * * establish a projection handle for use with PROJ4.3 * * act as a wrapper to protect against library changes in PROJ * * **************************************************************************/ projPJ SHPSetProjection ( int param_cnt, char **params ) { #ifdef PROJ4 projPJ *p = NULL; if ( param_cnt > 0 && params[0] ) { p = pj_init ( param_cnt, params ); } return ( p ); #else return ( NULL ); #endif } /* ************************************************************************** * SHPFreeProjection * * release a projection handle for use with PROJ4.3 * * act as a wrapper to protect against library changes in PROJ * * **************************************************************************/ int SHPFreeProjection ( projPJ p) { #ifdef PROJ4 if ( p ) pj_free ( p ); #endif return ( 1 ); } /* ************************************************************************** * SHPOGisType * * Convert Both ways from and to OGIS Geometry Types * * **************************************************************************/ int SHPOGisType ( int GeomType, int toOGis) { if ( toOGis == 0 ) /* connect OGis -> SHP types */ switch (GeomType) { case (OGIST_POINT): return ( SHPT_POINT ); break; case (OGIST_LINESTRING): return ( SHPT_ARC ); break; case (OGIST_POLYGON): return ( SHPT_POLYGON ); break; case (OGIST_MULTIPOINT): return ( SHPT_MULTIPOINT ); break; case (OGIST_MULTILINE): return ( SHPT_ARC ); break; case (OGIST_MULTIPOLYGON): return ( SHPT_POLYGON ); break; } else /* ok so its SHP->OGis types */ switch (GeomType) { case (SHPT_POINT): return ( OGIST_POINT ); break; case (SHPT_POINTM): return ( OGIST_POINT ); break; case (SHPT_POINTZ): return ( OGIST_POINT ); break; case (SHPT_ARC): return ( OGIST_LINESTRING );break; case (SHPT_ARCZ): return ( OGIST_LINESTRING );break; case (SHPT_ARCM): return ( OGIST_LINESTRING );break; case (SHPT_POLYGON): return ( OGIST_MULTIPOLYGON );break; case (SHPT_POLYGONZ): return ( OGIST_MULTIPOLYGON );break; case (SHPT_POLYGONM): return ( OGIST_MULTIPOLYGON );break; case (SHPT_MULTIPOINT): return ( OGIST_MULTIPOINT );break; case (SHPT_MULTIPOINTZ): return ( OGIST_MULTIPOINT );break; case (SHPT_MULTIPOINTM): return ( OGIST_MULTIPOINT );break; case (SHPT_MULTIPATCH): return ( OGIST_GEOMCOLL ); break; } return 0; } /* ************************************************************************** * SHPReadSHPStream * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPReadSHPStream ( SHPObject *psCShape, char *stream_obj) { int obj_storage; int my_order, need_swap =0, GeoType ; int use_Z = 0; int use_M = 0; need_swap = stream_obj[0]; my_order = 1; my_order = ((char*) (&my_order))[0]; need_swap = need_swap & my_order; if ( need_swap ) swapW (stream_obj, (void*) &GeoType, sizeof (GeoType) ); else memcpy (stream_obj, &GeoType, sizeof (GeoType) ); if ( need_swap ) { } else { memcpy (stream_obj, &(psCShape->nSHPType), sizeof (psCShape->nSHPType) ); memcpy (stream_obj, &(psCShape->nShapeId), sizeof (psCShape->nShapeId) ); memcpy (stream_obj, &(psCShape->nVertices), sizeof (psCShape->nVertices) ); memcpy (stream_obj, &(psCShape->nParts), sizeof (psCShape->nParts) ); memcpy (stream_obj, &(psCShape->dfXMin), sizeof (psCShape->dfXMin) ); memcpy (stream_obj, &(psCShape->dfYMin), sizeof (psCShape->dfYMin) ); memcpy (stream_obj, &(psCShape->dfXMax), sizeof (psCShape->dfXMax) ); memcpy (stream_obj, &(psCShape->dfYMax), sizeof (psCShape->dfYMax) ); if ( use_Z ) { memcpy (stream_obj, &(psCShape->dfZMin), sizeof (psCShape->dfZMin) ); memcpy (stream_obj, &(psCShape->dfZMax), sizeof (psCShape->dfZMax) ); } memcpy (stream_obj, psCShape->panPartStart, psCShape->nParts * sizeof (int) ); memcpy (stream_obj, psCShape->panPartType, psCShape->nParts * sizeof (int) ); /* get X and Y coordinate arrarys */ memcpy (stream_obj, psCShape->padfX, psCShape->nVertices * 2 * sizeof (double) ); /* get Z coordinate array if used */ if ( use_Z ) memcpy (stream_obj, psCShape->padfZ, psCShape->nVertices * 2 * sizeof (double) ); /* get Measure coordinate array if used */ if ( use_M ) memcpy (stream_obj, psCShape->padfM, psCShape->nVertices * 2 * sizeof (double) ); } /* end put data without swap */ return (0); } /* ************************************************************************** * SHPWriteSHPStream * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPWriteSHPStream ( WKBStreamObj *stream_obj, SHPObject *psCShape ) { int obj_storage = 0; int need_swap = 0, my_order, GeoType; int use_Z = 0; int use_M = 0; need_swap = 1; need_swap = ((char*) (&need_swap))[0]; realloc (stream_obj, obj_storage ); if ( need_swap ) { } else { memcpy (stream_obj, psCShape, 4 * sizeof (int) ); memcpy (stream_obj, psCShape, 4 * sizeof (double) ); if ( use_Z ) memcpy (stream_obj, psCShape, 2 * sizeof (double) ); if ( use_M ) memcpy (stream_obj, psCShape, 2 * sizeof (double) ); memcpy (stream_obj, psCShape, psCShape->nParts * 2 * sizeof (int) ); memcpy (stream_obj, psCShape, psCShape->nVertices * 2 * sizeof (double) ); if ( use_Z ) memcpy (stream_obj, psCShape, psCShape->nVertices * 2 * sizeof (double) ); if ( use_M ) memcpy (stream_obj, psCShape, psCShape->nVertices * 2 * sizeof (double) ); } return (0); } /* ************************************************************************** * WKBStreamWrite * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int WKBStreamWrite ( WKBStreamObj* wso, void* this, int tcount, int tsize ) { if ( wso->NeedSwap ) SwapG ( &(wso->wStream[wso->StreamPos]), this, tcount, tsize ); else memcpy ( &(wso->wStream[wso->StreamPos]), this, tsize * tcount ); wso->StreamPos += tsize; return 0; } /* ************************************************************************** * WKBStreamRead * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int WKBStreamRead ( WKBStreamObj* wso, void* this, int tcount, int tsize ) { if ( wso->NeedSwap ) SwapG ( this, &(wso->wStream[wso->StreamPos]), tcount, tsize ); else memcpy ( this, &(wso->wStream[wso->StreamPos]), tsize * tcount ); wso->StreamPos += tsize; return 0; } /* ************************************************************************** * SHPReadOGisWKB * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ SHPObject* SHPReadOGisWKB ( WKBStreamObj *stream_obj) { SHPObject *psCShape; char WKB_order; int need_swap = 0, my_order, GeoType = 0; int use_Z = 0, use_M = 0; int nSHPType, thisDim; WKBStreamRead ( stream_obj, &WKB_order, 1, sizeof(char)); my_order = 1; my_order = ((char*) (&my_order))[0]; stream_obj->NeedSwap = !(WKB_order & my_order); /* convert OGis Types to SHP types */ nSHPType = SHPOGisType ( GeoType, 0 ); WKBStreamRead ( stream_obj, &GeoType, 1, sizeof(int)); thisDim = SHPDimension ( nSHPType ); if ( thisDim && SHPD_AREA ) { psCShape = SHPReadOGisPolygon ( stream_obj ); } else { if ( thisDim && SHPD_LINE ) { psCShape = SHPReadOGisLine ( stream_obj ); } else { if ( thisDim && SHPD_POINT ) { psCShape = SHPReadOGisPoint ( stream_obj ); } } } return (0); } /* ************************************************************************** * SHPWriteOGisWKB * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPWriteOGisWKB ( WKBStreamObj* stream_obj, SHPObject *psCShape ) { int need_swap = 0, my_order, GeoType, thisDim; int use_Z = 0, use_M = 0; char LSB = 1; /* indicate that this WKB is in LSB Order */ /* OGis WKB can handle either byte order, but if I get to choose I'd /* rather have it predicatable system-to-system */ if ( stream_obj ) { if ( stream_obj->wStream ) free ( stream_obj->wStream ); } else { stream_obj = calloc ( 3, sizeof (int ) ); } /* object size needs to be 9 bytes for the wrapper, and for each polygon */ /* another 9 bytes all plus twice the total number of vertices */ /* times the sizeof (double) and just pad with 10 more chars for fun */ stream_obj->wStream = calloc (1, (9 * (psCShape->nParts + 1)) + ( sizeof(double) * 2 * psCShape->nVertices ) + 10 ); #ifdef DEBUG2 printf (" I just allocated %d bytes to wkbObj \n", sizeof (int) + sizeof (int) + sizeof(int) + ( sizeof(int) * psCShape->nParts + 1 ) + ( sizeof(double) * 2 * psCShape->nVertices ) + 10 ); #endif my_order = 1; my_order = ((char*) (&my_order))[0]; /* Need to swap if this system is not LSB (Intel Order) */ stream_obj->NeedSwap = ( my_order != LSB ); stream_obj->StreamPos = 0; #ifdef DEBUG2 printf ("this system is (%d) LSB recorded as needSwap %d\n",my_order, stream_obj->NeedSwap); #endif WKBStreamWrite ( stream_obj, & LSB, 1, sizeof(char) ); #ifdef DEBUG2 printf ("this system in (%d) LSB \n"); #endif /* convert SHP Types to OGis types */ GeoType = SHPOGisType ( psCShape->nSHPType, 1 ); WKBStreamWrite ( stream_obj, &GeoType, 1, sizeof(int) ); thisDim = SHPDimension ( psCShape->nSHPType ); if ( thisDim && SHPD_AREA ) { SHPWriteOGisPolygon ( stream_obj, psCShape ); } else { if ( thisDim && SHPD_LINE ) { SHPWriteOGisLine ( stream_obj, psCShape ); } else { if ( thisDim && SHPD_POINT ) { SHPWriteOGisPoint ( stream_obj, psCShape ); } } } #ifdef DEBUG2 printf("(SHPWriteOGisWKB) outta here when stream pos is %d \n", stream_obj->StreamPos); #endif return (0); } /* ************************************************************************** * SHPWriteOGisPolygon * * for this pass code to more generic OGis MultiPolygon Type * later add support for OGis Polygon Type * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPWriteOGisPolygon ( WKBStreamObj *stream_obj, SHPObject *psCShape ) { SHPObject **ppsC; SHPObject *psC; int rPart, ring, rVertices, cpart, cParts, nextring, i, j; char Flag = 1; int GeoType = OGIST_POLYGON; /* cant have more than nParts complex objects in this object */ ppsC = calloc ( psCShape->nParts, sizeof(int) ); nextring = 0; cParts=0; while ( nextring >= 0 ) { ppsC[cParts] = SHPUnCompound ( psCShape, &nextring ); cParts++; } #ifdef DEBUG2 printf ("(SHPWriteOGisPolygon) Uncompounded into %d parts \n", cParts); #endif WKBStreamWrite ( stream_obj, &cParts, 1, sizeof(int) ); for ( cpart = 0; cpart < cParts; cpart++) { WKBStreamWrite ( stream_obj, & Flag, 1, sizeof(char) ); WKBStreamWrite ( stream_obj, & GeoType, 1, sizeof(int) ); psC = (SHPObject*) ppsC[cpart]; WKBStreamWrite ( stream_obj, &(psC->nParts), 1, sizeof(int) ); for ( ring = 0; (ring < (psC->nParts)) && (psC->nParts > 0); ring ++) { if ( ring < (psC->nParts-2) ) { rVertices = psC->panPartStart[ring+1] - psC->panPartStart[ring]; } else { rVertices = psC->nVertices - psC->panPartStart[ring]; } #ifdef DEBUG2 printf ("(SHPWriteOGisPolygon) scanning part %d, ring %d %d vtxs \n", cpart, ring, rVertices); #endif rPart = psC->panPartStart[ring]; WKBStreamWrite ( stream_obj, &rVertices, 1, sizeof(int) ); for ( j=rPart; j < (rPart + rVertices); j++ ) { WKBStreamWrite ( stream_obj, &(psC->padfX[j]), 1, sizeof(double) ); WKBStreamWrite ( stream_obj, &(psC->padfY[j]), 1, sizeof(double) ); } /* for each vertex */ } /* for each ring */ } /* for each complex part */ #ifdef DEBUG2 printf ("(SHPWriteOGisPolygon) outta here \n"); #endif return (1); } /* ************************************************************************** * SHPWriteOGisLine * * for this pass code to more generic OGis MultiXXXXXXX Type * later add support for OGis LineString Type * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPWriteOGisLine ( WKBStreamObj *stream_obj, SHPObject *psCShape ) { return ( SHPWriteOGisPolygon( stream_obj, psCShape )); } /* ************************************************************************** * SHPWriteOGisPoint * * for this pass code to more generic OGis MultiPoint Type * later add support for OGis Point Type * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int SHPWriteOGisPoint ( WKBStreamObj *stream_obj, SHPObject *psCShape ) { int j; WKBStreamWrite ( stream_obj, &(psCShape->nVertices), 1, sizeof(int) ); for ( j=0; j < psCShape->nVertices; j++ ) { WKBStreamWrite ( stream_obj, &(psCShape->padfX[j]), 1, sizeof(double) ); WKBStreamWrite ( stream_obj, &(psCShape->padfY[j]), 1, sizeof(double) ); } /* for each vertex */ return (1); } /* ************************************************************************** * SHPReadOGisPolygon * * for this pass code to more generic OGis MultiPolygon Type * later add support for OGis Polygon Type * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ SHPObject* SHPReadOGisPolygon ( WKBStreamObj *stream_obj ) { SHPObject **ppsC; SHPObject *psC; int rPart, ring, rVertices, cpart, cParts, nextring, i, j; int totParts, totVertices, pRings, nParts; psC = SHPCreateObject ( SHPT_POLYGON, -1, 0, NULL, NULL, 0, NULL, NULL, NULL, NULL ); /* initialize a blank SHPObject */ WKBStreamRead ( stream_obj, &cParts, 1, sizeof(char) ); totParts = cParts; totVertices = 0; SfRealloc ( psC->panPartStart, cParts * sizeof(int)); SfRealloc ( psC->panPartType, cParts * sizeof(int)); for ( cpart = 0; cpart < cParts; cpart++) { WKBStreamRead ( stream_obj, &nParts, 1, sizeof(int) ); pRings = nParts; /* pRings is the number of rings prior to the Ring loop below */ if ( nParts > 1 ) { totParts += nParts - 1; SfRealloc ( psC->panPartStart, totParts * sizeof(int)); SfRealloc ( psC->panPartType, totParts * sizeof(int)); } rPart = 0; for ( ring = 0; ring < (nParts - 1); ring ++) { WKBStreamRead ( stream_obj, &rVertices, 1, sizeof(int) ); totVertices += rVertices; psC->panPartStart[ring+pRings] = rPart; if ( ring == 0 ) { psC->panPartType[ring + pRings] = SHPP_OUTERRING; } else { psC->panPartType[ring + pRings] = SHPP_INNERRING; } SfRealloc ( psC->padfX, totVertices * sizeof (double)); SfRealloc ( psC->padfY, totVertices * sizeof (double)); for ( j=rPart; j < (rPart + rVertices); j++ ) { WKBStreamRead ( stream_obj, &(psC->padfX[j]), 1, sizeof(double) ); WKBStreamRead ( stream_obj, &(psC->padfY[j]), 1, sizeof(double) ); } /* for each vertex */ rPart += rVertices; } /* for each ring */ } /* for each complex part */ return ( psC ); } /* ************************************************************************** * SHPReadOGisLine * * for this pass code to more generic OGis MultiLineString Type * later add support for OGis LineString Type * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ SHPObject* SHPReadOGisLine ( WKBStreamObj *stream_obj ) { SHPObject **ppsC; SHPObject *psC; int rPart, ring, rVertices, cpart, cParts, nextring, i, j; int totParts, totVertices, pRings, nParts; psC = SHPCreateObject ( SHPT_ARC, -1, 0, NULL, NULL, 0, NULL, NULL, NULL, NULL ); /* initialize a blank SHPObject */ WKBStreamRead ( stream_obj, &cParts, 1, sizeof(int) ); totParts = cParts; totVertices = 0; SfRealloc ( psC->panPartStart, cParts * sizeof(int)); SfRealloc ( psC->panPartType, cParts * sizeof(int)); for ( cpart = 0; cpart < cParts; cpart++) { WKBStreamRead ( stream_obj, &nParts, 1, sizeof(int) ); pRings = totParts; /* pRings is the number of rings prior to the Ring loop below */ if ( nParts > 1 ) { totParts += nParts - 1; SfRealloc ( psC->panPartStart, totParts * sizeof(int)); SfRealloc ( psC->panPartType, totParts * sizeof(int)); } rPart = 0; for ( ring = 0; ring < (nParts - 1); ring ++) { WKBStreamRead ( stream_obj, &rVertices, 1, sizeof(int) ); totVertices += rVertices; psC->panPartStart[ring+pRings] = rPart; if ( ring == 0 ) { psC->panPartType[ring + pRings] = SHPP_OUTERRING; } else { psC->panPartType[ring + pRings] = SHPP_INNERRING; } SfRealloc ( psC->padfX, totVertices * sizeof (double)); SfRealloc ( psC->padfY, totVertices * sizeof (double)); for ( j=rPart; j < (rPart + rVertices); j++ ) { WKBStreamRead ( stream_obj, &(psC->padfX[j]), 1, sizeof(double) ); WKBStreamRead ( stream_obj, &(psC->padfY[j]), 1, sizeof(double) ); } /* for each vertex */ rPart += rVertices; } /* for each ring */ } /* for each complex part */ return ( psC ); } /* ************************************************************************** * SHPReadOGisPoint * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ SHPObject* SHPReadOGisPoint ( WKBStreamObj *stream_obj ) { SHPObject *psC; int nVertices, j; psC = SHPCreateObject ( SHPT_MULTIPOINT, -1, 0, NULL, NULL, 0, NULL, NULL, NULL, NULL ); /* initialize a blank SHPObject */ WKBStreamRead ( stream_obj, &nVertices, 1, sizeof(int) ); SfRealloc ( psC->padfX, nVertices * sizeof (double)); SfRealloc ( psC->padfY, nVertices * sizeof (double)); for ( j=0; j < nVertices; j++ ) { WKBStreamRead ( stream_obj, &(psC->padfX[j]), 1, sizeof(double) ); WKBStreamRead ( stream_obj, &(psC->padfY[j]), 1, sizeof(double) ); } /* for each vertex */ return ( psC ); } /* ************************************************************************** * RingReadOGisWKB * * this accepts OGisLineStrings which are basic building blocks * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int RingReadOgisWKB ( SHPObject *psCShape, char *stream_obj) { return 0; } /* ************************************************************************** * RingWriteOGisWKB * * this emits OGisLineStrings which are basic building blocks * * Encapsulate entire SHPObject for use with Postgresql * * **************************************************************************/ int RingWriteOgisWKB ( SHPObject *psCShape, char *stream_obj) { return 0; } /* ************************************************************************** * SHPDimension * * Return the Dimensionality of the SHPObject * a handy utility function * * **************************************************************************/ int SHPDimension ( int SHPType ) { int dimension; dimension = 0; switch ( SHPType ) { case SHPT_POINT : dimension = SHPD_POINT; break; case SHPT_ARC : dimension = SHPD_LINE; break; case SHPT_POLYGON : dimension = SHPD_AREA; break; case SHPT_MULTIPOINT : dimension = SHPD_POINT; break; case SHPT_POINTZ : dimension = SHPD_POINT | SHPD_Z; break; case SHPT_ARCZ : dimension = SHPD_LINE | SHPD_Z; break; case SHPT_POLYGONZ : dimension = SHPD_AREA | SHPD_Z; break; case SHPT_MULTIPOINTZ : dimension = SHPD_POINT | SHPD_Z; break; case SHPT_POINTM : dimension = SHPD_POINT | SHPD_MEASURE; break; case SHPT_ARCM : dimension = SHPD_LINE | SHPD_MEASURE; break; case SHPT_POLYGONM : dimension = SHPD_AREA | SHPD_MEASURE; break; case SHPT_MULTIPOINTM : dimension = SHPD_POINT | SHPD_MEASURE; break; case SHPT_MULTIPATCH : dimension = SHPD_AREA; break; } return ( dimension ); } /* ************************************************************************** * SHPPointinPoly_2d * * Return a Point inside an R+ of a potentially * complex/compound SHPObject suitable for labelling * return only one point even if if is a compound object * * reject non area SHP Types * * **************************************************************************/ PT SHPPointinPoly_2d ( SHPObject *psCShape ) { PT *sPT, rPT; if ( !(SHPDimension (psCShape->nSHPType) & SHPD_AREA) ) { rPT.x = NAN; rPT.y = NAN; return rPT; } sPT = SHPPointsinPoly_2d ( psCShape ); if ( sPT ) { rPT.x = sPT[0].x; rPT.y = sPT[0].y; } else { rPT.x = NAN; rPT.y = NAN; } return ( rPT ); } /* ************************************************************************** * SHPPointsinPoly_2d * * Return a Point inside each R+ of a potentially * complex/compound SHPObject suitable for labelling * return one point for each R+ even if it is a compound object * * reject non area SHP Types * * **************************************************************************/ PT* SHPPointsinPoly_2d ( SHPObject *psCShape ) { PT *PIP = NULL; int cRing; SHPObject *psO, *psInt, *CLine; double *CLx, *CLy; int *CLstt, *CLst, nPIP, ring, rMpart, ring_vtx, ring_nVertices; double rLen, rLenMax; if ( !(SHPDimension (psCShape->nSHPType) & SHPD_AREA) ) return ( NULL ); while ( psO = SHPUnCompound (psCShape, &cRing)) { CLx = calloc ( 4, sizeof(double)); CLy = calloc ( 4, sizeof(double)); CLst = calloc ( 2, sizeof(int)); CLstt = calloc ( 2, sizeof(int)); /* a horizontal & vertical compound line though the middle of the */ /* extents */ CLx [0] = psO->dfXMin; CLy [0] = (psO->dfYMin + psO->dfYMax ) * 0.5; CLx [1] = psO->dfXMax; CLy [1] = (psO->dfYMin + psO->dfYMax ) * 0.5; CLx [2] = (psO->dfXMin + psO->dfXMax ) * 0.5; CLy [2] = psO->dfYMin; CLx [3] = (psO->dfXMin + psO->dfXMax ) * 0.5; CLy [3] = psO->dfYMax; CLst[0] = 0; CLst[1] = 2; CLstt[0] = SHPP_RING; CLstt[1] = SHPP_RING; CLine = SHPCreateObject ( SHPT_POINT, -1, 2, CLst, CLstt, 4, CLx, CLy, NULL, NULL ); /* with the H & V centrline compound object, intersect it with the OBJ */ psInt = SHPIntersect_2d ( CLine, psO ); /* return SHP type is lowest common dimensionality of the input types */ /* find the longest linestring returned by the intersection */ ring_vtx = psInt->nVertices ; for ( ring = (psInt->nParts - 1); ring >= 0; ring-- ) { ring_nVertices = ring_vtx - psInt->panPartStart[ring]; rLen += RingLength_2d ( ring_nVertices, (double*) &(psInt->padfX [psInt->panPartStart[ring]]), (double*) &(psInt->padfY [psInt->panPartStart[ring]]) ); if ( rLen > rLenMax ) { rLenMax = rLen; rMpart = psInt->panPartStart[ring]; } ring_vtx = psInt->panPartStart[ring]; } /* add the centerpoint of the longest ARC of the intersection to the */ /* PIP list */ nPIP ++; SfRealloc ( PIP, sizeof(double) * 2 * nPIP); PIP[nPIP].x = (psInt ->padfX [rMpart] + psInt ->padfX [rMpart]) * 0.5; PIP[nPIP].y = (psInt ->padfY [rMpart] + psInt ->padfY [rMpart]) * 0.5; SHPDestroyObject ( psO ); SHPDestroyObject ( CLine ); /* does SHPCreateobject use preallocated memory or does it copy the */ /* contents. To be safe conditionally release CLx, CLy, CLst, CLstt */ if ( CLx ) free ( CLx ); if ( CLy ) free ( CLy ); if ( CLst ) free ( CLst ); if ( CLstt ) free ( CLstt ); } return ( PIP ); } /* ************************************************************************** * SHPCentrd_2d * * Return the single mathematical / geometric centroid of a potentially * complex/compound SHPObject * * reject non area SHP Types * * **************************************************************************/ PT SHPCentrd_2d ( SHPObject *psCShape ) { int ring, ringPrev, ring_nVertices, rStart; double Area, ringArea; PT ringCentrd, C; if ( !(SHPDimension (psCShape->nSHPType) & SHPD_AREA) ) { C.x = NAN; C.y = NAN; return C; } #ifdef DEBUG printf ("for Object with %d vtx, %d parts [ %d, %d] \n", psCShape->nVertices, psCShape->nParts, psCShape->panPartStart[0],psCShape->panPartStart[1]); #endif Area = 0; C.x = 0.0; C.y = 0.0; /* for each ring in compound / complex object calc the ring cntrd */ ringPrev = psCShape->nVertices; for ( ring = (psCShape->nParts - 1); ring >= 0; ring-- ) { rStart = psCShape->panPartStart[ring]; ring_nVertices = ringPrev - rStart; RingCentroid_2d ( ring_nVertices, (double*) &(psCShape->padfX [rStart]), (double*) &(psCShape->padfY [rStart]), &ringCentrd, &ringArea); #ifdef DEBUG printf ("(SHPCentrd_2d) Ring %d, vtxs %d, area: %f, ring centrd %f, %f \n", ring, ring_nVertices, ringArea, ringCentrd.x, ringCentrd.y); #endif /* use Superposition of these rings to build a composite Centroid */ /* sum the ring centrds * ringAreas, at the end divide by total area */ C.x += ringCentrd.x * ringArea; C.y += ringCentrd.y * ringArea; Area += ringArea; ringPrev = rStart; } /* hold on the division by AREA until were at the end */ C.x = C.x / Area; C.y = C.y / Area; #ifdef DEBUG printf ("SHPCentrd_2d) Overall Area: %f, Centrd %f, %f \n", Area, C.x, C.y); #endif return ( C ); } /* ************************************************************************** * RingCentroid_2d * * Return the mathematical / geometric centroid of a single closed ring * * **************************************************************************/ int RingCentroid_2d ( int nVertices, double *a, double *b, PT *C, double *Area ) { int iv,jv; int sign_x, sign_y; double dy_Area, dx_Area, Cx_accum, Cy_accum, ppx, ppy; double x_base, y_base, x, y; /* the centroid of a closed Ring is defined as * * Cx = sum (cx * dArea ) / Total Area * and * Cy = sum (cy * dArea ) / Total Area */ x_base = a[0]; y_base = b[0]; Cy_accum = 0.0; Cx_accum = 0.0; ppx = a[1] - x_base; ppy = b[1] - y_base; *Area = 0; /* Skip the closing vector */ for ( iv = 2; iv <= nVertices - 2; iv++ ) { x = a[iv] - x_base; y = b[iv] - y_base; /* calc the area and centroid of triangle built out of an arbitrary */ /* base_point on the ring and each successive pair on the ring */ /* Area of a triangle is the cross product of its defining vectors */ /* Centroid of a triangle is the average of its vertices */ dx_Area = ((x * ppy) - (y * ppx)) * 0.5; *Area += dx_Area; Cx_accum += ( ppx + x ) * dx_Area; Cy_accum += ( ppy + y ) * dx_Area; #ifdef DEBUG2 printf("(ringcentrd_2d) Pp( %f, %f), P(%f, %f)\n", ppx, ppy, x, y); printf("(ringcentrd_2d) dA: %f, sA: %f, Cx: %f, Cy: %f \n", dx_Area, *Area, Cx_accum, Cy_accum); #endif ppx = x; ppy = y; } #ifdef DEBUG2 printf("(ringcentrd_2d) Cx: %f, Cy: %f \n", ( Cx_accum / ( *Area * 3) ), ( Cy_accum / (*Area * 3) )); #endif /* adjust back to world coords */ C->x = ( Cx_accum / ( *Area * 3)) + x_base; C->y = ( Cy_accum / ( *Area * 3)) + y_base; return ( 1 ); } /* ************************************************************************** * SHPRingDir_2d * * Test Polygon for CW / CCW ( R+ / R- ) * * return 1 for R+ * return -1 for R- * return 0 for error * **************************************************************************/ int SHPRingDir_2d ( SHPObject *psCShape, int Ring ) { int i, ti, last_vtx; double tX; double *a, *b; double dx0, dx1, dy0, dy1, v1, v2 ,v3; tX = 0.0; a = psCShape->padfX; b = psCShape->padfY; if ( Ring >= psCShape->nParts ) return ( 0 ); if ( Ring >= psCShape->nParts -1 ) { last_vtx = psCShape->nVertices; } else { last_vtx = psCShape->panPartStart[Ring + 1]; } /* All vertices at the corners of the extrema (rightmost lowest, leftmost lowest, */ /* topmost rightest, ...) must be less than pi wide. If they werent they couldnt be */ /* extrema. */ /* of course the following will fail if the Extents are even a little wrong */ for ( i = psCShape->panPartStart[Ring]; i < last_vtx; i++ ) { if ( b[i] == psCShape->dfYMax && a[i] > tX ) { ti = i; } } #ifdef DEBUG2 printf ("(shpgeo:SHPRingDir) highest Rightmost Pt is vtx %d (%f, %f)\n", ti, a[ti], b[ti]); #endif /* cross product */ /* the sign of the cross product of two vectors indicates the right or left half-plane */ /* which we can use to indicate Ring Dir */ if ( ti > psCShape->panPartStart[Ring] & ti < last_vtx ) { dx0 = a[ti-1] - a[ti]; dx1 = a[ti+1] - a[ti]; dy0 = b[ti-1] - b[ti]; dy1 = b[ti+1] - b[ti]; } else /* if the tested vertex is at the origin then continue from 0 */ { dx1 = a[1] - a[0]; dx0 = a[last_vtx] - a[0]; dy1 = b[1] - b[0]; dy0 = b[last_vtx] - b[0]; } // v1 = ( (dy0 * 0) - (0 * dy1) ); // v2 = ( (0 * dx1) - (dx0 * 0) ); /* these above are always zero so why do the math */ v3 = ( (dx0 * dy1) - (dx1 * dy0) ); #ifdef DEBUG2 printf ("(shpgeo:SHPRingDir) cross product for vtx %d was %f \n", ti, v3); #endif if ( v3 > 0 ) { return (1); } else { return (-1); } } /* ************************************************************************** * SHPArea_2d * * Calculate the XY Area of Polygon ( can be compound / complex ) * * **************************************************************************/ double SHPArea_2d ( SHPObject *psCShape ) { double cArea; int ring, ring_vtx, ringDir, ring_nVertices; cArea = 0; if ( !(SHPDimension (psCShape->nSHPType) & SHPD_AREA) ) return ( -1 ); /* Walk each ring adding its signed Area, R- will return a negative */ /* area, so we don't have to test for them */ /* I just start at the last ring and work down to the first */ ring_vtx = psCShape->nVertices ; for ( ring = (psCShape->nParts - 1); ring >= 0; ring-- ) { ring_nVertices = ring_vtx - psCShape->panPartStart[ring]; #ifdef DEBUG2 printf("(shpgeo:SHPArea_2d) part %d, vtx %d \n", ring, ring_nVertices); #endif cArea += RingArea_2d ( ring_nVertices, (double*) &(psCShape->padfX [psCShape->panPartStart[ring]]), (double*) &(psCShape->padfY [psCShape->panPartStart[ring]]) ); ring_vtx = psCShape->panPartStart[ring]; } #ifdef DEBUG2 printf ("(shpgeo:SHPArea_2d) Area = %f \n", cArea); #endif /* Area is signed, negative Areas are R- */ return ( cArea ); } /* ************************************************************************** * SHPLength_2d * * Calculate the Planar ( XY ) Length of Polygon ( can be compound / complex ) * or Polyline ( can be compound ). Length on Polygon is its Perimeter * * **************************************************************************/ double SHPLength_2d ( SHPObject *psCShape ) { double Length; int i, j; double dx, dy; if ( !(SHPDimension (psCShape->nSHPType) & (SHPD_AREA || SHPD_LINE)) ) return ( (double) -1 ); Length = 0; j = 1; for ( i = 1; i < psCShape->nVertices; i++ ) { if ( psCShape->panPartStart[j] == i ) { j ++; } /* skip the moves with "pen up" from ring to ring */ else { dx = psCShape->padfX[i] - psCShape->padfX[i-1]; dy = psCShape->padfY[i] - psCShape->padfY[i-1]; Length += sqrt ( ( dx * dx ) + ( dy * dy ) ); } /* simplify this equation */ } return ( Length ); } /* ************************************************************************** * RingLength_2d * * Calculate the Planar ( XY ) Length of Polygon ( can be compound / complex ) * or Polyline ( can be compound ). Length of Polygon is its Perimeter * * **************************************************************************/ double RingLength_2d ( int nVertices, double *a, double *b ) { double Length; int i, j; double dx, dy; Length = 0; j = 1; for ( i = 1; i < nVertices; i++ ) { dx = a[i] - b[i-1]; dy = b[i] - b[i-1]; Length += sqrt ( ( dx * dx ) + ( dy * dy ) ); /* simplify this equation */ } return ( Length ); } /* ************************************************************************** * RingArea_2d * * Calculate the Planar Area of a single closed ring * * **************************************************************************/ double RingArea_2d ( int nVertices, double *a, double *b ) { int iv,jv; double ppx, ppy; static double Area; double dx_Area; double x_base, y_base, x, y; x_base = a[0]; y_base = b[0]; ppx = a[1] - x_base; ppy = b[1] - y_base; Area = 0.0; #ifdef DEBUG2 printf("(shpgeo:RingArea) %d vertices \n", nVertices); #endif for ( iv = 2; iv <= ( nVertices - 1 ); iv++ ) { x = a[iv] - x_base; y = b[iv] - y_base; /* Area of a triangle is the cross product of its defining vectors */ dx_Area = ((x * ppy) - (y * ppx)) * 0.5; Area += dx_Area; #ifdef DEBUG2 printf ("(shpgeo:RingArea) dxArea %f sArea %f for pt(%f, %f)\n", dx_Area, Area, x, y); #endif ppx = x; ppy = y; } #ifdef DEBUG2 printf ("(shpgeo:RingArea) total RingArea %f \n", Area); #endif return ( Area ); } /* ************************************************************************** * SHPUnCompound * * ESRI calls this function explode * Return a non compound ( possibly complex ) object * * ring_number is R+ number corresponding to object * * * ignore complexity in Z dimension for now * * **************************************************************************/ SHPObject* SHPUnCompound ( SHPObject *psCShape, int * ringNumber ) { int ringDir, ring, lRing; if ( (*ringNumber >= psCShape->nParts) || *ringNumber == -1 ) { *ringNumber = -1; return (NULL); } if ( *ringNumber == (psCShape->nParts - 1) ) { *ringNumber = -1; return ( SHPClone(psCShape, (psCShape->nParts - 1), -1) ); } lRing = *ringNumber; ringDir = -1; for ( ring = (lRing + 1); (ring < psCShape->nParts) && ( ringDir < 0 ); ring ++) ringDir = SHPRingDir_2d ( psCShape, ring); if ( ring == psCShape->nParts ) *ringNumber = -1; else *ringNumber = ring; /* I am strictly assuming that all R- parts of a complex object * directly follow their R+, so when we hit a new R+ its a * new part of a compound object * a SHPClean may be needed to enforce this as it is not part * of ESRI's definition of a SHPfile */ #ifdef DEBUG2 printf ("(SHPUnCompound) asked for ring %d, lastring is %d \n", lRing, ring); #endif return ( SHPClone(psCShape, lRing, ring ) ); } /* ************************************************************************** * SHPIntersect_2d * * * prototype only for now * * return object with lowest common dimensionality of objects * * **************************************************************************/ SHPObject* SHPIntersect_2d ( SHPObject* a, SHPObject* b ) { SHPObject *C; if ( (SHPDimension(a->nSHPType) && SHPD_POINT) || ( SHPDimension(b->nSHPType) && SHPD_POINT ) ) return ( NULL ); /* there is no intersect function like this for points */ C = SHPClone ( a, 0 , -1 ); return ( C); } /* ************************************************************************** * SHPClean * * Test and fix normalization problems in shapes * Different tests need to be implemented for different SHPTypes * SHPT_POLYGON check ring directions CW / CCW ( R+ / R- ) * put all R- after the R+ they are members of * i.e. each complex object is completed before the * next object is started * check for closed rings * ring must not intersect itself, even on edge * * no other types implemented yet * * not sure why but return object in place * use for object casting and object verification * **************************************************************************/ int SHPClean ( SHPObject *psCShape ) { return (0); } /* ************************************************************************** * SHPClone * * Clone a SHPObject, replicating all data * * **************************************************************************/ SHPObject* SHPClone ( SHPObject *psCShape, int lowPart, int highPart ) { SHPObject *psObject; int newParts, newVertices; #ifdef DEBUG int i; #endif if ( highPart >= psCShape->nParts || highPart == -1 ) highPart = psCShape->nParts ; #ifdef DEBUG printf (" cloning SHP (%d parts) from ring %d upto ring %d \n", psCShape->nParts, lowPart, highPart); #endif newParts = highPart - lowPart; if ( newParts == 0 ) { return ( NULL ); } psObject = (SHPObject *) calloc(1,sizeof(SHPObject)); psObject->nSHPType = psCShape->nSHPType; psObject->nShapeId = psCShape->nShapeId; psObject->nParts = newParts; if ( psCShape->padfX ) { psObject->panPartStart = (int*) calloc (newParts, sizeof (int)); memcpy ( psObject->panPartStart, psCShape->panPartStart, newParts * sizeof (int) ); } if ( psCShape->padfX ) { psObject->panPartType = (int*) calloc (newParts, sizeof (int)); memcpy ( psObject->panPartType, (int *) &(psCShape->panPartType[lowPart]), newParts * sizeof (int) ); } if ( highPart != psCShape->nParts ) { newVertices = psCShape->panPartStart[highPart] - psCShape->panPartStart[lowPart]; } else { newVertices = psCShape->nVertices - psCShape->panPartStart[lowPart]; } #ifdef DEBUG if ( highPart = psCShape->nParts ) i = psCShape->nVertices; else i = psCShape->panPartStart[highPart]; printf (" from part %d (%d) to %d (%d) is %d vertices \n", lowPart, psCShape->panPartStart[lowPart], highPart, i, newVertices); #endif psObject->nVertices = newVertices; if ( psCShape->padfX ) { psObject->padfX = (double*) calloc (newVertices, sizeof (double)); memcpy ( psObject->padfX, (double *) &(psCShape->padfX[psCShape->panPartStart[lowPart]]), newVertices * sizeof (double) ); } if ( psCShape->padfY ) { psObject->padfY = (double*) calloc (newVertices, sizeof (double)); memcpy ( psObject->padfY, (double *) &(psCShape->padfY[psCShape->panPartStart[lowPart]]), newVertices * sizeof (double) ); } if ( psCShape->padfZ ) { psObject->padfZ = (double*) calloc (newVertices, sizeof (double)); memcpy ( psObject->padfZ, (double *) &(psCShape->padfZ[psCShape->panPartStart[lowPart]]), newVertices * sizeof (double) ); } if ( psCShape->padfM ) { psObject->padfM = (double*) calloc (newVertices, sizeof (double)); memcpy ( psObject->padfM, (double *) &(psCShape->padfM[psCShape->panPartStart[lowPart]]), newVertices * sizeof (double) ); } psObject->dfXMin = psCShape->dfXMin; psObject->dfYMin = psCShape->dfYMin; psObject->dfZMin = psCShape->dfZMin; psObject->dfMMin = psCShape->dfMMin; psObject->dfXMax = psCShape->dfXMax; psObject->dfYMax = psCShape->dfYMax; psObject->dfZMax = psCShape->dfZMax; psObject->dfMMax = psCShape->dfMMax; SHPComputeExtents ( psObject ); return ( psObject ); } /************************************************************************/ /* SwapG */ /* */ /* Swap a 2, 4 or 8 byte word. */ /************************************************************************/ void SwapG( void *so, void *in, int this_cnt, int this_size ) { int i, j; unsigned char temp; /* return to a new pointer otherwise it would invalidate existing data */ /* as prevent further use of it */ for( j=0; j < this_cnt; j++ ) { for( i=0; i < this_size/2; i++ ) { ((unsigned char *) so)[i] = ((unsigned char *) in)[this_size-i-1]; ((unsigned char *) so)[this_size-i-1] = ((unsigned char *) in)[i]; } } } /* ************************************************************************** * SwapW * * change byte order on an array of 16 bit words * need to change this over to shapelib, Frank Warmerdam's functions * * **************************************************************************/ void swapW (void *so, unsigned char *in, long bytes) { int i, j; unsigned char map[4] = {3,2,1,0}; unsigned char *out; out = so; for (i=0; i <= (bytes/4); i++) for (j=0; j < 4; j++) out[(i*4)+map[j]] = in[(i*4)+j]; } /* ************************************************************************** * SwapD * * change byte order on an array of (double) 32 bit words * need to change this over to shapelib, Frank Warmerdam's functons * * **************************************************************************/ void swapD (void *so, unsigned char *in, long bytes) { int i, j; unsigned char map[8] = {7,6,5,4,3,2,1,0}; unsigned char *out; out = so; for (i=0; i <= (bytes/8); i++) for (j=0; j < 8; j++) out[(i*8)+map[j]] = in[(i*8)+j]; } shapelib-1.3.0/dbfadd.c0000640042715500116100000001073610125620777014205 0ustar warmerdameng/****************************************************************************** * $Id: dbfadd.c,v 1.9 2004-09-26 20:09:35 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for adding a record to an existing .dbf file. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: dbfadd.c,v $ * Revision 1.9 2004-09-26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.8 2004/01/09 16:39:49 fwarmerdam * include standard include files * * Revision 1.7 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.6 2001/05/31 18:15:40 warmerda * Added support for NULL fields in DBF files * * Revision 1.5 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.4 1998/12/03 16:36:06 warmerda * Added stdlib.h and math.h to get atof() prototype. * * Revision 1.3 1995/10/21 03:13:23 warmerda * Use binary mode.. * * Revision 1.2 1995/08/04 03:15:59 warmerda * Added header. * */ #include #include #include #include "shapefil.h" SHP_CVSID("$Id: dbfadd.c,v 1.9 2004-09-26 20:09:35 fwarmerdam Exp $") int main( int argc, char ** argv ) { DBFHandle hDBF; int i, iRecord; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc < 3 ) { printf( "dbfadd xbase_file field_values\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Create the database. */ /* -------------------------------------------------------------------- */ hDBF = DBFOpen( argv[1], "r+b" ); if( hDBF == NULL ) { printf( "DBFOpen(%s,\"rb+\") failed.\n", argv[1] ); exit( 2 ); } /* -------------------------------------------------------------------- */ /* Do we have the correct number of arguments? */ /* -------------------------------------------------------------------- */ if( DBFGetFieldCount( hDBF ) != argc - 2 ) { printf( "Got %d fields, but require %d\n", argc - 2, DBFGetFieldCount( hDBF ) ); exit( 3 ); } iRecord = DBFGetRecordCount( hDBF ); /* -------------------------------------------------------------------- */ /* Loop assigning the new field values. */ /* -------------------------------------------------------------------- */ for( i = 0; i < DBFGetFieldCount(hDBF); i++ ) { if( strcmp( argv[i+2], "" ) == 0 ) DBFWriteNULLAttribute(hDBF, iRecord, i ); else if( DBFGetFieldInfo( hDBF, i, NULL, NULL, NULL ) == FTString ) DBFWriteStringAttribute(hDBF, iRecord, i, argv[i+2] ); else DBFWriteDoubleAttribute(hDBF, iRecord, i, atof(argv[i+2]) ); } /* -------------------------------------------------------------------- */ /* Close and cleanup. */ /* -------------------------------------------------------------------- */ DBFClose( hDBF ); return( 0 ); } shapelib-1.3.0/stream1.out0000640042715500116100000016514407314525551014746 0ustar warmerdameng------------------------------------------------------------------------- Test 1: dump anno.shp ------------------------------------------------------------------------- Shapefile Type: Polygon # of Shapes: 201 File Bounds: ( 471276.281, 4751595.500,0,0) to ( 492683.536, 4765390.413,0,0) Shape:0 (Polygon) nVertices=5, nParts=1 Bounds:( 486019.130, 4764549.500, 0, 0) to ( 486356.183, 4765212.744, 0, 0) ( 486089.531, 4764549.500, 0, 0) Ring ( 486019.130, 4764579.128, 0, 0) ( 486285.782, 4765212.744, 0, 0) ( 486356.183, 4765183.116, 0, 0) ( 486089.531, 4764549.500, 0, 0) Shape:1 (Polygon) nVertices=5, nParts=1 Bounds:( 484948.275, 4763866.500, 0, 0) to ( 485333.012, 4764070.376, 0, 0) ( 484974.719, 4763866.500, 0, 0) Ring ( 484948.275, 4763938.159, 0, 0) ( 485306.569, 4764070.376, 0, 0) ( 485333.012, 4763998.717, 0, 0) ( 484974.719, 4763866.500, 0, 0) Shape:2 (Polygon) nVertices=5, nParts=1 Bounds:( 485577.021, 4764106.500, 0, 0) to ( 485818.355, 4764259.305, 0, 0) ( 485604.156, 4764106.500, 0, 0) Ring ( 485577.021, 4764177.900, 0, 0) ( 485791.220, 4764259.305, 0, 0) ( 485818.355, 4764187.906, 0, 0) ( 485604.156, 4764106.500, 0, 0) Shape:3 (Polygon) nVertices=5, nParts=1 Bounds:( 484861.500, 4762570.513, 0, 0) to ( 485092.062, 4763026.856, 0, 0) ( 485092.062, 4762597.000, 0, 0) Ring ( 485020.420, 4762570.513, 0, 0) ( 484861.500, 4763000.370, 0, 0) ( 484933.143, 4763026.856, 0, 0) ( 485092.062, 4762597.000, 0, 0) Shape:4 (Polygon) nVertices=5, nParts=1 Bounds:( 484452.624, 4763792.614, 0, 0) to ( 484628.031, 4764105.947, 0, 0) ( 484628.031, 4763818.500, 0, 0) Ring ( 484556.169, 4763792.614, 0, 0) ( 484452.624, 4764080.061, 0, 0) ( 484524.486, 4764105.947, 0, 0) ( 484628.031, 4763818.500, 0, 0) Shape:5 (Polygon) nVertices=5, nParts=1 Bounds:( 484355.352, 4764139.435, 0, 0) to ( 484505.344, 4764380.892, 0, 0) ( 484505.344, 4764165.500, 0, 0) Ring ( 484433.546, 4764139.435, 0, 0) ( 484355.352, 4764354.827, 0, 0) ( 484427.150, 4764380.892, 0, 0) ( 484505.344, 4764165.500, 0, 0) Shape:6 (Polygon) nVertices=9, nParts=1 Bounds:( 484548.866, 4763118.531, 0, 0) to ( 484772.062, 4763742.258, 0, 0) ( 484772.062, 4763152.000, 0, 0) Ring ( 484703.404, 4763118.531, 0, 0) ( 484605.763, 4763318.832, 0, 0) ( 484548.866, 4763471.149, 0, 0) ( 484603.088, 4763742.258, 0, 0) ( 484677.987, 4763727.278, 0, 0) ( 484628.031, 4763477.500, 0, 0) ( 484676.031, 4763349.000, 0, 0) ( 484772.062, 4763152.000, 0, 0) Shape:7 (Polygon) nVertices=5, nParts=1 Bounds:( 484671.739, 4763562.500, 0, 0) to ( 484911.415, 4763682.338, 0, 0) ( 484686.719, 4763562.500, 0, 0) Ring ( 484671.739, 4763637.399, 0, 0) ( 484896.435, 4763682.338, 0, 0) ( 484911.415, 4763607.439, 0, 0) ( 484686.719, 4763562.500, 0, 0) Shape:8 (Polygon) nVertices=5, nParts=1 Bounds:( 484930.172, 4763125.500, 0, 0) to ( 485596.342, 4763453.269, 0, 0) ( 484958.719, 4763125.500, 0, 0) Ring ( 484930.172, 4763196.347, 0, 0) ( 485567.795, 4763453.269, 0, 0) ( 485596.342, 4763382.423, 0, 0) ( 484958.719, 4763125.500, 0, 0) Shape:9 (Polygon) nVertices=5, nParts=1 Bounds:( 485102.757, 4763082.500, 0, 0) to ( 485344.154, 4763234.029, 0, 0) ( 485129.406, 4763082.500, 0, 0) Ring ( 485102.757, 4763154.083, 0, 0) ( 485317.505, 4763234.029, 0, 0) ( 485344.154, 4763162.446, 0, 0) ( 485129.406, 4763082.500, 0, 0) Shape:10 (Polygon) nVertices=5, nParts=1 Bounds:( 485368.786, 4762538.500, 0, 0) to ( 485824.016, 4762774.029, 0, 0) ( 485396.156, 4762538.500, 0, 0) Ring ( 485368.786, 4762609.810, 0, 0) ( 485796.646, 4762774.029, 0, 0) ( 485824.016, 4762702.719, 0, 0) ( 485396.156, 4762538.500, 0, 0) Shape:11 (Polygon) nVertices=5, nParts=1 Bounds:( 487002.484, 4763184.000, 0, 0) to ( 487243.960, 4763333.368, 0, 0) ( 487028.312, 4763184.000, 0, 0) Ring ( 487002.484, 4763255.883, 0, 0) ( 487218.132, 4763333.368, 0, 0) ( 487243.960, 4763261.486, 0, 0) ( 487028.312, 4763184.000, 0, 0) Shape:12 (Polygon) nVertices=5, nParts=1 Bounds:( 486733.537, 4762455.413, 0, 0) to ( 487076.312, 4763275.483, 0, 0) ( 487076.312, 4762480.000, 0, 0) Ring ( 487003.996, 4762455.413, 0, 0) ( 486733.537, 4763250.896, 0, 0) ( 486805.854, 4763275.483, 0, 0) ( 487076.312, 4762480.000, 0, 0) Shape:13 (Polygon) nVertices=5, nParts=1 Bounds:( 486440.735, 4762331.029, 0, 0) to ( 486772.281, 4763075.311, 0, 0) ( 486772.281, 4762357.000, 0, 0) Ring ( 486700.450, 4762331.029, 0, 0) ( 486440.735, 4763049.339, 0, 0) ( 486512.566, 4763075.311, 0, 0) ( 486772.281, 4762357.000, 0, 0) Shape:14 (Polygon) nVertices=5, nParts=1 Bounds:( 486383.882, 4762986.530, 0, 0) to ( 486521.594, 4763227.908, 0, 0) ( 486521.594, 4763008.000, 0, 0) Ring ( 486448.291, 4762986.530, 0, 0) ( 486383.882, 4763206.438, 0, 0) ( 486457.184, 4763227.908, 0, 0) ( 486521.594, 4763008.000, 0, 0) Shape:15 (Polygon) nVertices=9, nParts=1 Bounds:( 486360.416, 4762774.310, 0, 0) to ( 486800.882, 4763656.208, 0, 0) ( 486489.594, 4763600.000, 0, 0) Ring ( 486541.313, 4763656.208, 0, 0) ( 486762.057, 4763453.094, 0, 0) ( 486800.882, 4763266.659, 0, 0) ( 486420.883, 4762774.310, 0, 0) ( 486360.416, 4762820.979, 0, 0) ( 486718.938, 4763285.500, 0, 0) ( 486692.281, 4763413.500, 0, 0) ( 486489.594, 4763600.000, 0, 0) Shape:16 (Polygon) nVertices=5, nParts=1 Bounds:( 486682.872, 4762181.000, 0, 0) to ( 487292.496, 4762415.463, 0, 0) ( 486702.969, 4762181.000, 0, 0) Ring ( 486682.872, 4762254.691, 0, 0) ( 487272.400, 4762415.463, 0, 0) ( 487292.496, 4762341.772, 0, 0) ( 486702.969, 4762181.000, 0, 0) Shape:17 (Polygon) nVertices=5, nParts=1 Bounds:( 487480.713, 4762283.320, 0, 0) to ( 487732.406, 4762812.552, 0, 0) ( 487732.406, 4762309.000, 0, 0) Ring ( 487660.470, 4762283.320, 0, 0) ( 487480.713, 4762786.872, 0, 0) ( 487552.649, 4762812.552, 0, 0) ( 487732.406, 4762309.000, 0, 0) Shape:18 (Polygon) nVertices=5, nParts=1 Bounds:( 487069.757, 4763685.709, 0, 0) to ( 487220.344, 4763927.145, 0, 0) ( 487220.344, 4763712.000, 0, 0) Ring ( 487148.629, 4763685.709, 0, 0) ( 487069.757, 4763900.854, 0, 0) ( 487141.471, 4763927.145, 0, 0) ( 487220.344, 4763712.000, 0, 0) Shape:19 (Polygon) nVertices=9, nParts=1 Bounds:( 487854.719, 4758279.000, 0, 0) to ( 488518.085, 4758475.003, 0, 0) ( 487854.719, 4758404.000, 0, 0) Ring ( 487882.875, 4758475.003, 0, 0) ( 488183.362, 4758355.845, 0, 0) ( 488341.273, 4758360.840, 0, 0) ( 488515.420, 4758366.919, 0, 0) ( 488518.085, 4758290.583, 0, 0) ( 488343.812, 4758284.500, 0, 0) ( 488169.938, 4758279.000, 0, 0) ( 487854.719, 4758404.000, 0, 0) Shape:20 (Polygon) nVertices=5, nParts=1 Bounds:( 486300.557, 4758366.000, 0, 0) to ( 486613.245, 4758546.262, 0, 0) ( 486327.781, 4758366.000, 0, 0) Ring ( 486300.557, 4758437.366, 0, 0) ( 486586.021, 4758546.262, 0, 0) ( 486613.245, 4758474.896, 0, 0) ( 486327.781, 4758366.000, 0, 0) Shape:21 (Polygon) nVertices=5, nParts=1 Bounds:( 486709.618, 4758518.000, 0, 0) to ( 486949.999, 4758681.145, 0, 0) ( 486740.750, 4758518.000, 0, 0) Ring ( 486709.618, 4758587.750, 0, 0) ( 486918.867, 4758681.145, 0, 0) ( 486949.999, 4758611.396, 0, 0) ( 486740.750, 4758518.000, 0, 0) Shape:22 (Polygon) nVertices=5, nParts=1 Bounds:( 487325.398, 4757807.034, 0, 0) to ( 487555.844, 4758263.402, 0, 0) ( 487555.844, 4757833.500, 0, 0) Ring ( 487484.193, 4757807.034, 0, 0) ( 487325.398, 4758236.937, 0, 0) ( 487397.049, 4758263.402, 0, 0) ( 487555.844, 4757833.500, 0, 0) Shape:23 (Polygon) nVertices=5, nParts=1 Bounds:( 487255.256, 4758215.573, 0, 0) to ( 487387.406, 4758456.611, 0, 0) ( 487387.406, 4758235.000, 0, 0) Ring ( 487313.536, 4758215.573, 0, 0) ( 487255.256, 4758437.184, 0, 0) ( 487329.126, 4758456.611, 0, 0) ( 487387.406, 4758235.000, 0, 0) Shape:24 (Polygon) nVertices=5, nParts=1 Bounds:( 487248.714, 4758360.500, 0, 0) to ( 487559.687, 4758550.761, 0, 0) ( 487278.719, 4758360.500, 0, 0) Ring ( 487248.714, 4758430.742, 0, 0) ( 487529.682, 4758550.761, 0, 0) ( 487559.687, 4758480.519, 0, 0) ( 487278.719, 4758360.500, 0, 0) Shape:25 (Polygon) nVertices=5, nParts=1 Bounds:( 487573.994, 4758496.500, 0, 0) to ( 487815.502, 4758644.603, 0, 0) ( 487599.344, 4758496.500, 0, 0) Ring ( 487573.994, 4758568.553, 0, 0) ( 487790.152, 4758644.603, 0, 0) ( 487815.502, 4758572.550, 0, 0) ( 487599.344, 4758496.500, 0, 0) ------------------------------------------------------------------------- Test 2: dump brklinz.shp ------------------------------------------------------------------------- Shapefile Type: ArcZ # of Shapes: 122 File Bounds: ( 6294338.260, 1978444.010,0,0) to ( 6296321.860, 1979694.450,0,0) Shape:0 (ArcZ) nVertices=92, nParts=1 Bounds:( 6294700.210, 1978579.390, 818.64, 0) to ( 6295395.930, 1979050.330, 917.86, 0) ( 6295372.750, 1978755.830, 823.06, 0) Ring ( 6295366.170, 1978739.190, 826.58, 0) ( 6295360.400, 1978718.540, 829.2, 0) ( 6295352.620, 1978697.000, 832.22, 0) ( 6295345.960, 1978677.040, 834.64, 0) ( 6295339.690, 1978656.810, 838.51, 0) ( 6295335.040, 1978637.600, 840.94, 0) ( 6295331.080, 1978621.450, 844.48, 0) ( 6295324.350, 1978607.940, 847.04, 0) ( 6295313.370, 1978598.450, 850.38, 0) ( 6295296.780, 1978594.950, 853.27, 0) ( 6295273.800, 1978594.990, 858.06, 0) ( 6295251.750, 1978595.380, 861.53, 0) ( 6295232.340, 1978598.400, 864.22, 0) ( 6295206.740, 1978606.390, 866.38, 0) ( 6295180.610, 1978616.970, 868.15, 0) ( 6295156.350, 1978630.540, 870.65, 0) ( 6295132.270, 1978645.210, 872.02, 0) ( 6295111.070, 1978659.740, 875.17, 0) ( 6295090.030, 1978674.920, 878.84, 0) ( 6295071.060, 1978689.340, 882.06, 0) ( 6295051.900, 1978705.080, 886.98, 0) ( 6295036.460, 1978719.260, 889.66, 0) ( 6295023.620, 1978732.910, 893.53, 0) ( 6295010.450, 1978750.380, 895.24, 0) ( 6294999.910, 1978767.850, 897.47, 0) ( 6294989.810, 1978783.860, 900.29, 0) ( 6294975.040, 1978795.570, 902.45, 0) ( 6294956.300, 1978806.830, 906.32, 0) ( 6294937.260, 1978814.620, 909.21, 0) ( 6294919.240, 1978821.960, 912.88, 0) ( 6294897.040, 1978832.210, 915.04, 0) ( 6294878.070, 1978844.070, 916.49, 0) ( 6294865.010, 1978855.820, 917.34, 0) ( 6294859.560, 1978870.150, 916.81, 0) ( 6294861.520, 1978882.920, 916.62, 0) ( 6294874.640, 1978906.220, 917.86, 0) ( 6294886.980, 1978926.880, 917.6, 0) ( 6294889.630, 1978953.270, 917.54, 0) ( 6294888.520, 1978978.280, 916.88, 0) ( 6294880.350, 1978998.390, 915.96, 0) ( 6294866.540, 1979018.920, 915.57, 0) ( 6294843.270, 1979039.140, 915.57, 0) ( 6294812.250, 1979049.040, 915.96, 0) ( 6294777.640, 1979050.330, 916.75, 0) ( 6294752.060, 1979040.520, 916.68, 0) ( 6294730.990, 1979028.850, 916.62, 0) ( 6294716.690, 1979008.420, 916.62, 0) ( 6294706.050, 1978987.490, 916.95, 0) ( 6294700.210, 1978965.390, 916.95, 0) ( 6294700.520, 1978937.670, 917.01, 0) ( 6294712.060, 1978911.340, 916.95, 0) ( 6294724.820, 1978893.560, 916.62, 0) ( 6294741.630, 1978878.010, 916.36, 0) ( 6294759.360, 1978865.090, 916.36, 0) ( 6294777.650, 1978855.370, 916.22, 0) ( 6294807.570, 1978846.970, 916.36, 0) ( 6294837.640, 1978836.590, 916.55, 0) ( 6294858.650, 1978831.390, 916.29, 0) ( 6294878.860, 1978825.840, 915.37, 0) ( 6294897.630, 1978817.860, 913.67, 0) ( 6294914.550, 1978809.520, 910.78, 0) ( 6294932.380, 1978798.580, 907.17, 0) ( 6294947.360, 1978788.370, 904.42, 0) ( 6294960.500, 1978778.120, 901.86, 0) ( 6294974.780, 1978761.900, 898.78, 0) ( 6294988.510, 1978747.610, 895.7, 0) ( 6295005.230, 1978730.220, 892.81, 0) ( 6295023.560, 1978713.470, 889.34, 0) ( 6295043.310, 1978696.320, 885.07, 0) ( 6295061.830, 1978680.810, 881.47, 0) ( 6295080.970, 1978664.550, 877.79, 0) ( 6295104.570, 1978648.190, 874.58, 0) ( 6295126.310, 1978633.890, 872.09, 0) ( 6295149.840, 1978618.720, 869.6, 0) ( 6295173.840, 1978605.030, 867.37, 0) ( 6295198.110, 1978594.150, 866.12, 0) ( 6295222.830, 1978586.990, 865.2, 0) ( 6295243.030, 1978583.810, 863.5, 0) ( 6295268.110, 1978581.290, 860.35, 0) ( 6295291.530, 1978579.390, 856.48, 0) ( 6295313.200, 1978582.040, 852.42, 0) ( 6295329.170, 1978591.410, 848.81, 0) ( 6295339.780, 1978603.880, 845.07, 0) ( 6295345.640, 1978621.110, 842.12, 0) ( 6295351.070, 1978642.970, 838.32, 0) ( 6295357.250, 1978666.560, 834.77, 0) ( 6295367.290, 1978691.000, 831.89, 0) ( 6295376.030, 1978718.470, 828.09, 0) ( 6295383.930, 1978744.860, 824.35, 0) ( 6295389.990, 1978768.720, 821.33, 0) ( 6295395.930, 1978790.090, 818.64, 0) Shape:1 (ArcZ) nVertices=9, nParts=1 Bounds:( 6295218.470, 1978444.010, 864.55, 0) to ( 6295330.760, 1978581.880, 882.45, 0) ( 6295330.760, 1978444.010, 882.45, 0) Ring ( 6295306.050, 1978461.190, 880.94, 0) ( 6295280.210, 1978482.710, 878.52, 0) ( 6295258.180, 1978504.050, 875.89, 0) ( 6295239.910, 1978524.670, 871.89, 0) ( 6295225.650, 1978546.540, 869.53, 0) ( 6295218.470, 1978565.550, 866.97, 0) ( 6295223.960, 1978575.510, 865.27, 0) ( 6295230.580, 1978581.880, 864.55, 0) Shape:2 (ArcZ) nVertices=10, nParts=1 Bounds:( 6295199.220, 1978444.010, 866.32, 0) to ( 6295309.040, 1978588.800, 882.08, 0) ( 6295200.070, 1978588.800, 866.32, 0) Ring ( 6295199.220, 1978571.840, 867.24, 0) ( 6295200.770, 1978555.740, 868.88, 0) ( 6295207.890, 1978538.040, 869.86, 0) ( 6295223.020, 1978520.530, 870.84, 0) ( 6295239.450, 1978502.440, 874.06, 0) ( 6295258.050, 1978483.440, 876.48, 0) ( 6295268.990, 1978473.760, 879.17, 0) ( 6295285.710, 1978461.560, 880.55, 0) ( 6295309.040, 1978444.010, 882.08, 0) Shape:3 (ArcZ) nVertices=5, nParts=1 Bounds:( 6294340.890, 1979449.280, 1031.78, 0) to ( 6294394.080, 1979522.030, 1039.78, 0) ( 6294394.080, 1979449.280, 1039.78, 0) Ring ( 6294378.800, 1979469.230, 1038.73, 0) ( 6294364.980, 1979486.740, 1037.28, 0) ( 6294350.800, 1979504.980, 1035.12, 0) ( 6294340.890, 1979522.030, 1031.78, 0) Shape:4 (ArcZ) nVertices=6, nParts=1 Bounds:( 6294344.380, 1979583.450, 1008.04, 0) to ( 6294354.670, 1979678.070, 1023.45, 0) ( 6294344.380, 1979583.450, 1023.45, 0) Ring ( 6294348.050, 1979601.580, 1019.18, 0) ( 6294349.570, 1979621.200, 1016.5, 0) ( 6294351.990, 1979637.890, 1012.95, 0) ( 6294353.090, 1979657.140, 1011.51, 0) ( 6294354.670, 1979678.070, 1008.04, 0) Shape:5 (ArcZ) nVertices=3, nParts=1 Bounds:( 6294338.260, 1979628.600, 1008.63, 0) to ( 6294341.080, 1979674.100, 1015.71, 0) ( 6294341.080, 1979674.100, 1008.63, 0) Ring ( 6294339.460, 1979649.880, 1011.71, 0) ( 6294338.260, 1979628.600, 1015.71, 0) Shape:6 (ArcZ) nVertices=3, nParts=1 Bounds:( 6294350.160, 1979437.980, 1038.6, 0) to ( 6294379.980, 1979476.720, 1040.1, 0) ( 6294350.160, 1979476.720, 1038.6, 0) Ring ( 6294368.100, 1979454.860, 1040.1, 0) ( 6294379.980, 1979437.980, 1039.32, 0) Shape:7 (ArcZ) nVertices=39, nParts=1 Bounds:( 6295371.530, 1978758.160, 754.11, 0) to ( 6295534.560, 1979677.750, 823.3, 0) ( 6295534.560, 1979677.750, 779.95, 0) Ring ( 6295534.380, 1979648.150, 778.57, 0) ( 6295534.480, 1979605.990, 775.16, 0) ( 6295533.970, 1979577.580, 772.21, 0) ( 6295532.310, 1979547.260, 768.41, 0) ( 6295532.970, 1979521.290, 763.82, 0) ( 6295532.390, 1979496.890, 759.1, 0) ( 6295532.940, 1979474.010, 755.49, 0) ( 6295533.680, 1979452.180, 754.11, 0) ( 6295533.850, 1979434.640, 754.11, 0) ( 6295532.170, 1979409.180, 755.75, 0) ( 6295531.580, 1979384.450, 758.7, 0) ( 6295531.590, 1979356.090, 760.28, 0) ( 6295530.190, 1979325.690, 761.13, 0) ( 6295530.020, 1979291.090, 761.66, 0) ( 6295529.210, 1979259.420, 762.7, 0) ( 6295526.250, 1979221.610, 762.77, 0) ( 6295524.260, 1979187.500, 763.75, 0) ( 6295522.640, 1979155.350, 764.61, 0) ( 6295521.540, 1979123.230, 765.33, 0) ( 6295518.460, 1979096.000, 765.92, 0) ( 6295511.670, 1979081.110, 767.16, 0) ( 6295500.700, 1979064.060, 768.41, 0) ( 6295489.330, 1979049.600, 770.11, 0) ( 6295475.500, 1979033.100, 773.07, 0) ( 6295462.530, 1979018.190, 775.16, 0) ( 6295447.760, 1979001.400, 779.49, 0) ( 6295433.380, 1978984.530, 782.9, 0) ( 6295419.040, 1978965.820, 785.92, 0) ( 6295409.020, 1978946.820, 790.58, 0) ( 6295399.860, 1978923.910, 795.1, 0) ( 6295391.010, 1978894.410, 800.94, 0) ( 6295387.440, 1978875.550, 805.53, 0) ( 6295382.030, 1978849.030, 809.79, 0) ( 6295382.190, 1978828.930, 813.33, 0) ( 6295383.570, 1978809.290, 817.4, 0) ( 6295380.880, 1978789.860, 819.69, 0) ( 6295375.630, 1978771.810, 822.58, 0) ( 6295371.530, 1978758.160, 823.3, 0) Shape:8 (ArcZ) nVertices=35, nParts=1 Bounds:( 6295396.480, 1978794.780, 753.98, 0) to ( 6295549.010, 1979670.060, 818.58, 0) ( 6295396.620, 1978794.780, 818.58, 0) Ring ( 6295397.330, 1978816.670, 815.76, 0) ( 6295396.480, 1978836.150, 812.22, 0) ( 6295397.670, 1978857.110, 807.95, 0) ( 6295401.180, 1978874.720, 804.61, 0) ( 6295406.260, 1978897.320, 799.95, 0) ( 6295413.580, 1978919.930, 794.77, 0) ( 6295421.330, 1978938.190, 790.31, 0) ( 6295431.450, 1978956.590, 786.51, 0) ( 6295444.950, 1978974.360, 782.38, 0) ( 6295461.420, 1978993.620, 777.66, 0) ( 6295479.760, 1979013.510, 773.26, 0) ( 6295494.630, 1979032.330, 771.1, 0) ( 6295510.990, 1979052.120, 767.69, 0) ( 6295524.170, 1979071.090, 766.84, 0) ( 6295532.180, 1979091.890, 765.33, 0) ( 6295536.530, 1979120.830, 764.8, 0) ( 6295537.480, 1979150.200, 764.08, 0) ( 6295539.470, 1979189.490, 763.43, 0) ( 6295541.670, 1979230.490, 762.64, 0) ( 6295541.760, 1979271.330, 761.79, 0) ( 6295543.650, 1979306.300, 761.46, 0) ( 6295544.470, 1979335.540, 760.47, 0) ( 6295544.960, 1979363.490, 759.23, 0) ( 6295545.620, 1979392.020, 757.13, 0) ( 6295546.340, 1979419.430, 754.9, 0) ( 6295547.120, 1979439.940, 753.98, 0) ( 6295546.510, 1979459.150, 754.38, 0) ( 6295545.460, 1979482.710, 757.66, 0) ( 6295545.530, 1979507.330, 761.13, 0) ( 6295545.610, 1979532.470, 765.59, 0) ( 6295546.490, 1979565.520, 770.44, 0) ( 6295547.960, 1979597.100, 775.03, 0) ( 6295548.990, 1979628.040, 777.26, 0) ( 6295549.010, 1979670.060, 780.15, 0) Shape:9 (ArcZ) nVertices=45, nParts=1 Bounds:( 6295694.040, 1978444.010, 696.95, 0) to ( 6296208.790, 1979687.080, 787.43, 0) ( 6295698.400, 1979687.080, 787.43, 0) Ring ( 6295694.040, 1979670.950, 786.31, 0) ( 6295696.410, 1979650.280, 785.13, 0) ( 6295700.080, 1979634.530, 784.8, 0) ( 6295704.080, 1979620.010, 784.15, 0) ( 6295708.420, 1979601.930, 782.44, 0) ( 6295711.230, 1979584.790, 781.99, 0) ( 6295712.060, 1979564.780, 780.8, 0) ( 6295710.550, 1979537.480, 779.69, 0) ( 6295711.290, 1979508.020, 777.59, 0) ( 6295710.010, 1979477.420, 776.08, 0) ( 6295709.300, 1979442.530, 773.59, 0) ( 6295709.160, 1979413.640, 772.21, 0) ( 6295707.090, 1979372.570, 769.46, 0) ( 6295708.140, 1979336.210, 767.49, 0) ( 6295709.710, 1979297.130, 764.67, 0) ( 6295710.960, 1979272.310, 763.29, 0) ( 6295714.640, 1979241.200, 761.2, 0) ( 6295719.050, 1979211.560, 759.82, 0) ( 6295724.280, 1979179.840, 758.31, 0) ( 6295729.460, 1979152.460, 756.74, 0) ( 6295735.770, 1979126.530, 754.44, 0) ( 6295744.970, 1979095.400, 752.87, 0) ( 6295755.820, 1979063.140, 750.31, 0) ( 6295767.590, 1979028.330, 747.62, 0) ( 6295782.240, 1978993.450, 744.21, 0) ( 6295801.580, 1978952.420, 741.26, 0) ( 6295825.730, 1978905.370, 736.87, 0) ( 6295842.330, 1978877.810, 734.7, 0) ( 6295859.110, 1978851.150, 731.55, 0) ( 6295875.620, 1978827.010, 729.52, 0) ( 6295899.080, 1978794.830, 727.42, 0) ( 6295923.640, 1978763.720, 724.34, 0) ( 6295949.340, 1978734.180, 721.39, 0) ( 6295975.020, 1978704.320, 718.57, 0) ( 6296000.320, 1978677.440, 716.01, 0) ( 6296026.940, 1978648.120, 713.45, 0) ( 6296053.500, 1978617.500, 709.78, 0) ( 6296078.620, 1978589.630, 706.9, 0) ( 6296098.880, 1978566.880, 704.47, 0) ( 6296126.050, 1978537.930, 702.37, 0) ( 6296150.670, 1978507.990, 700.14, 0) ( 6296179.280, 1978476.280, 698.7, 0) ( 6296208.030, 1978444.880, 696.99, 0) ( 6296208.790, 1978444.010, 696.95, 0) Shape:10 (ArcZ) nVertices=10, nParts=1 Bounds:( 6296270.060, 1979014.970, 712.54, 0) to ( 6296315.990, 1979152.310, 725.13, 0) ( 6296306.110, 1979152.310, 725.13, 0) Ring ( 6296288.270, 1979139.690, 723.42, 0) ( 6296276.630, 1979122.410, 721.98, 0) ( 6296270.060, 1979101.470, 719.95, 0) ( 6296270.390, 1979084.580, 719.36, 0) ( 6296275.110, 1979068.970, 717.26, 0) ( 6296284.280, 1979052.820, 716.41, 0) ( 6296294.680, 1979040.410, 715.49, 0) ( 6296305.720, 1979027.370, 713.59, 0) ( 6296315.990, 1979014.970, 712.54, 0) Shape:11 (ArcZ) nVertices=18, nParts=1 Bounds:( 6296044.930, 1978451.120, 690.11, 0) to ( 6296312.920, 1978679.190, 713.72, 0) ( 6296312.920, 1978493.560, 690.11, 0) Ring ( 6296301.160, 1978479.050, 690.9, 0) ( 6296287.840, 1978464.950, 692.4, 0) ( 6296276.430, 1978454.890, 693.58, 0) ( 6296262.580, 1978451.120, 694.44, 0) ( 6296249.650, 1978452.500, 694.9, 0) ( 6296237.110, 1978461.670, 696.08, 0) ( 6296223.600, 1978477.650, 697.78, 0) ( 6296209.320, 1978493.930, 698.7, 0) ( 6296193.640, 1978511.140, 699.16, 0) ( 6296176.980, 1978529.710, 700.6, 0) ( 6296157.700, 1978550.970, 701.98, 0) ( 6296136.720, 1978574.950, 703.49, 0) ( 6296121.400, 1978591.550, 705.39, 0) ( 6296102.290, 1978613.590, 707.36, 0) ( 6296084.440, 1978634.580, 709.13, 0) ( 6296065.890, 1978654.760, 711.29, 0) ( 6296044.930, 1978679.190, 713.72, 0) Shape:12 (ArcZ) nVertices=71, nParts=1 Bounds:( 6295741.070, 1978679.190, 713.72, 0) to ( 6296321.860, 1979680.370, 813.79, 0) ( 6296044.930, 1978679.190, 713.72, 0) Ring ( 6296025.660, 1978700.780, 716.6, 0) ( 6296006.480, 1978721.510, 718.37, 0) ( 6295987.070, 1978742.720, 721, 0) ( 6295970.410, 1978761.420, 722.44, 0) ( 6295953.490, 1978780.070, 724.28, 0) ( 6295932.470, 1978805.820, 726.44, 0) ( 6295913.490, 1978830.550, 728.67, 0) ( 6295896.490, 1978855.310, 731.16, 0) ( 6295881.220, 1978878.070, 733.39, 0) ( 6295867.710, 1978899.180, 734.7, 0) ( 6295853.950, 1978923.310, 737, 0) ( 6295839.810, 1978950.030, 739.56, 0) ( 6295825.270, 1978979.390, 742.11, 0) ( 6295809.100, 1979015.600, 745.46, 0) ( 6295796.940, 1979045.170, 748.02, 0) ( 6295785.770, 1979078.900, 750.97, 0) ( 6295777.080, 1979104.550, 752.54, 0) ( 6295768.950, 1979133.460, 754.84, 0) ( 6295762.170, 1979163.090, 756.87, 0) ( 6295755.640, 1979194.930, 758.9, 0) ( 6295750.610, 1979225.390, 760.48, 0) ( 6295746.300, 1979259.750, 762.64, 0) ( 6295743.320, 1979291.750, 764.54, 0) ( 6295741.650, 1979321.060, 766.64, 0) ( 6295741.070, 1979353.790, 768.54, 0) ( 6295741.170, 1979384.450, 770.71, 0) ( 6295742.010, 1979419.210, 772.48, 0) ( 6295743.010, 1979454.740, 774.44, 0) ( 6295743.910, 1979493.310, 776.94, 0) ( 6295744.990, 1979530.290, 778.97, 0) ( 6295745.900, 1979569.120, 781.46, 0) ( 6295745.940, 1979603.910, 783.3, 0) ( 6295747.600, 1979636.660, 785.85, 0) ( 6295751.850, 1979653.260, 787.49, 0) ( 6295760.490, 1979665.820, 788.87, 0) ( 6295773.510, 1979673.830, 790.18, 0) ( 6295788.460, 1979676.100, 791.95, 0) ( 6295823.990, 1979674.960, 793.46, 0) ( 6295871.620, 1979674.070, 796.94, 0) ( 6295918.980, 1979673.120, 798.97, 0) ( 6295971.200, 1979672.130, 802.25, 0) ( 6296019.370, 1979671.600, 803.95, 0) ( 6296054.350, 1979670.030, 805.92, 0) ( 6296074.580, 1979662.250, 806.58, 0) ( 6296085.660, 1979647.700, 806.97, 0) ( 6296089.370, 1979635.300, 807.69, 0) ( 6296086.380, 1979620.160, 808.61, 0) ( 6296080.060, 1979601.690, 810.32, 0) ( 6296074.440, 1979583.990, 811.17, 0) ( 6296070.250, 1979568.770, 812.22, 0) ( 6296072.470, 1979552.830, 812.94, 0) ( 6296083.220, 1979536.790, 813.46, 0) ( 6296102.650, 1979531.410, 813.79, 0) ( 6296121.290, 1979536.450, 813.73, 0) ( 6296133.190, 1979548.520, 813.2, 0) ( 6296138.010, 1979563.380, 812.61, 0) ( 6296135.460, 1979580.580, 811.37, 0) ( 6296129.950, 1979598.850, 810.18, 0) ( 6296124.490, 1979618.170, 809.46, 0) ( 6296122.100, 1979635.880, 808.35, 0) ( 6296126.820, 1979651.410, 807.36, 0) ( 6296136.390, 1979661.360, 806.51, 0) ( 6296149.630, 1979666.080, 806.05, 0) ( 6296163.380, 1979667.880, 805.73, 0) ( 6296186.080, 1979667.460, 805.14, 0) ( 6296215.190, 1979666.580, 805, 0) ( 6296247.690, 1979667.830, 803.5, 0) ( 6296273.580, 1979670.850, 802.32, 0) ( 6296295.410, 1979674.090, 800.68, 0) ( 6296321.860, 1979680.370, 799.23, 0) Shape:13 (ArcZ) nVertices=6, nParts=1 Bounds:( 6295372.650, 1979608.700, 773.19, 0) to ( 6295470.330, 1979679.550, 780.15, 0) ( 6295372.650, 1979679.550, 780.15, 0) Ring ( 6295387.140, 1979664.770, 777.85, 0) ( 6295406.650, 1979645.400, 776.21, 0) ( 6295422.760, 1979631.580, 775.29, 0) ( 6295442.800, 1979612.190, 773.65, 0) ( 6295470.330, 1979608.700, 773.19, 0) Shape:14 (ArcZ) nVertices=7, nParts=1 Bounds:( 6295415.710, 1979491.540, 772.08, 0) to ( 6295453.550, 1979590.190, 773.85, 0) ( 6295453.550, 1979590.110, 772.09, 0) Ring ( 6295453.110, 1979590.190, 772.08, 0) ( 6295439.430, 1979579.260, 772.74, 0) ( 6295430.870, 1979552.770, 772.93, 0) ( 6295420.940, 1979527.860, 773.19, 0) ( 6295415.710, 1979510.070, 773.79, 0) ( 6295421.080, 1979491.540, 773.85, 0) Shape:15 (ArcZ) nVertices=9, nParts=1 Bounds:( 6295351.240, 1979521.410, 773, 0) to ( 6295430.330, 1979692.520, 782.11, 0) ( 6295395.270, 1979521.410, 774.51, 0) Ring ( 6295415.880, 1979549.790, 773.85, 0) ( 6295426.030, 1979579.220, 773, 0) ( 6295430.330, 1979604.610, 773.06, 0) ( 6295418.610, 1979622.140, 774.31, 0) ( 6295398.970, 1979639.020, 776.34, 0) ( 6295382.220, 1979655.690, 778.31, 0) ( 6295365.040, 1979674.420, 780.15, 0) ( 6295351.240, 1979692.520, 782.11, 0) Shape:16 (ArcZ) nVertices=28, nParts=1 Bounds:( 6294520.270, 1979256.990, 932.36, 0) to ( 6294743.290, 1979675.030, 1016.69, 0) ( 6294531.940, 1979675.030, 932.36, 0) Ring ( 6294523.870, 1979650.550, 933.54, 0) ( 6294520.270, 1979620.920, 936.75, 0) ( 6294525.030, 1979592.840, 940.29, 0) ( 6294533.880, 1979567.770, 942.98, 0) ( 6294546.040, 1979543.320, 949.28, 0) ( 6294564.140, 1979524.750, 951.64, 0) ( 6294585.590, 1979515.130, 956.36, 0) ( 6294611.810, 1979503.890, 959.38, 0) ( 6294635.130, 1979494.900, 966.2, 0) ( 6294662.590, 1979487.470, 969.41, 0) ( 6294687.540, 1979482.070, 971.77, 0) ( 6294710.180, 1979470.160, 976.75, 0) ( 6294732.150, 1979450.140, 978.53, 0) ( 6294743.290, 1979431.460, 981.94, 0) ( 6294738.700, 1979402.930, 984.69, 0) ( 6294731.290, 1979380.980, 986.79, 0) ( 6294717.670, 1979358.290, 988.3, 0) ( 6294706.340, 1979342.050, 991.38, 0) ( 6294697.140, 1979315.920, 996.76, 0) ( 6294696.360, 1979292.580, 1000.17, 0) ( 6294691.930, 1979275.010, 1002.4, 0) ( 6294681.970, 1979259.950, 1004.76, 0) ( 6294665.150, 1979256.990, 1006.53, 0) ( 6294638.580, 1979258.930, 1010.33, 0) ( 6294617.350, 1979259.730, 1012.76, 0) ( 6294592.000, 1979262.260, 1015.32, 0) ( 6294572.550, 1979262.000, 1016.69, 0) Shape:17 (ArcZ) nVertices=43, nParts=1 Bounds:( 6294466.100, 1979253.610, 930.98, 0) to ( 6294720.520, 1979678.410, 1018.46, 0) ( 6294572.550, 1979262.000, 1016.69, 0) Ring ( 6294549.640, 1979260.720, 1017.48, 0) ( 6294522.440, 1979260.520, 1017.48, 0) ( 6294472.060, 1979253.610, 1016.63, 0) ( 6294469.530, 1979302.330, 1017.15, 0) ( 6294466.100, 1979341.240, 1016.63, 0) ( 6294469.480, 1979374.290, 1016.5, 0) ( 6294506.640, 1979382.010, 1016.96, 0) ( 6294538.320, 1979377.390, 1016.89, 0) ( 6294581.400, 1979377.510, 1017.74, 0) ( 6294603.050, 1979366.770, 1017.74, 0) ( 6294597.820, 1979338.470, 1018, 0) ( 6294587.060, 1979307.490, 1018.46, 0) ( 6294579.280, 1979283.460, 1017.87, 0) ( 6294593.320, 1979278.020, 1016.36, 0) ( 6294613.160, 1979275.640, 1013.15, 0) ( 6294634.390, 1979274.630, 1009.54, 0) ( 6294650.590, 1979272.960, 1006.4, 0) ( 6294666.970, 1979274.830, 1003.77, 0) ( 6294675.710, 1979289.290, 1001.81, 0) ( 6294681.310, 1979309.230, 998.13, 0) ( 6294686.190, 1979327.900, 995.64, 0) ( 6294692.280, 1979346.960, 991.64, 0) ( 6294699.730, 1979367.200, 989.08, 0) ( 6294709.530, 1979384.310, 985.74, 0) ( 6294716.160, 1979401.370, 983.25, 0) ( 6294720.520, 1979414.810, 980.1, 0) ( 6294718.980, 1979441.480, 978, 0) ------------------------------------------------------------------------- Test 3: dump polygon.shp ------------------------------------------------------------------------- Shapefile Type: Polygon # of Shapes: 474 File Bounds: ( 471127.188, 4751545.000,0,0) to ( 489292.312, 4765610.500,0,0) Shape:0 (Polygon) nVertices=20, nParts=1 Bounds:( 479647.000, 4764856.500, 0, 0) to ( 480389.688, 4765610.500, 0, 0) ( 479819.844, 4765180.500, 0, 0) Ring ( 479690.188, 4765259.500, 0, 0) ( 479647.000, 4765369.500, 0, 0) ( 479730.375, 4765400.500, 0, 0) ( 480039.031, 4765539.500, 0, 0) ( 480035.344, 4765558.500, 0, 0) ( 480159.781, 4765610.500, 0, 0) ( 480202.281, 4765482.000, 0, 0) ( 480365.000, 4765015.500, 0, 0) ( 480389.688, 4764950.000, 0, 0) ( 480133.969, 4764856.500, 0, 0) ( 480080.281, 4764979.500, 0, 0) ( 480082.969, 4765049.500, 0, 0) ( 480088.812, 4765139.500, 0, 0) ( 480059.906, 4765239.500, 0, 0) ( 480019.719, 4765319.500, 0, 0) ( 479980.219, 4765409.500, 0, 0) ( 479909.875, 4765370.000, 0, 0) ( 479859.875, 4765270.000, 0, 0) ( 479819.844, 4765180.500, 0, 0) Shape:1 (Polygon) nVertices=20, nParts=1 Bounds:( 479014.938, 4764879.000, 0, 0) to ( 480039.031, 4765558.500, 0, 0) ( 480035.344, 4765558.500, 0, 0) Ring ( 480039.031, 4765539.500, 0, 0) ( 479730.375, 4765400.500, 0, 0) ( 479647.000, 4765369.500, 0, 0) ( 479690.188, 4765259.500, 0, 0) ( 479819.844, 4765180.500, 0, 0) ( 479779.844, 4765109.500, 0, 0) ( 479681.781, 4764940.000, 0, 0) ( 479468.000, 4764942.500, 0, 0) ( 479411.438, 4764940.500, 0, 0) ( 479353.000, 4764939.500, 0, 0) ( 479208.656, 4764882.500, 0, 0) ( 479196.812, 4764879.000, 0, 0) ( 479123.281, 4765015.000, 0, 0) ( 479046.531, 4765117.000, 0, 0) ( 479029.719, 4765110.500, 0, 0) ( 479014.938, 4765147.500, 0, 0) ( 479149.938, 4765200.500, 0, 0) ( 479639.625, 4765399.500, 0, 0) ( 480035.344, 4765558.500, 0, 0) Shape:2 (Polygon) nVertices=54, nParts=1 Bounds:( 480882.688, 4763472.500, 0, 0) to ( 484519.969, 4765410.000, 0, 0) ( 481575.000, 4764999.500, 0, 0) Ring ( 481542.312, 4765097.500, 0, 0) ( 481443.688, 4765387.500, 0, 0) ( 481499.656, 4765410.000, 0, 0) ( 481631.000, 4765031.000, 0, 0) ( 481693.312, 4764853.000, 0, 0) ( 481759.281, 4764889.500, 0, 0) ( 481860.031, 4764920.000, 0, 0) ( 482002.969, 4764910.000, 0, 0) ( 482180.094, 4764909.500, 0, 0) ( 482359.812, 4764960.000, 0, 0) ( 482510.500, 4765065.000, 0, 0) ( 482619.906, 4765080.500, 0, 0) ( 482809.500, 4765090.000, 0, 0) ( 483189.812, 4765084.500, 0, 0) ( 483330.312, 4765105.500, 0, 0) ( 483591.094, 4765260.000, 0, 0) ( 483700.500, 4765280.000, 0, 0) ( 483799.938, 4765270.000, 0, 0) ( 484039.844, 4765280.500, 0, 0) ( 484115.688, 4765300.000, 0, 0) ( 484120.625, 4765280.000, 0, 0) ( 484131.125, 4765260.000, 0, 0) ( 484167.844, 4765271.000, 0, 0) ( 484277.875, 4765015.500, 0, 0) ( 484455.062, 4764500.000, 0, 0) ( 484519.969, 4764345.000, 0, 0) ( 484482.031, 4764332.000, 0, 0) ( 483904.719, 4764113.500, 0, 0) ( 483334.844, 4763905.000, 0, 0) ( 482941.031, 4763760.500, 0, 0) ( 482590.719, 4763624.500, 0, 0) ( 482185.656, 4763472.500, 0, 0) ( 482009.844, 4763980.500, 0, 0) ( 481960.438, 4764099.500, 0, 0) ( 481767.500, 4764014.500, 0, 0) ( 480955.500, 4763700.000, 0, 0) ( 480882.688, 4763670.000, 0, 0) ( 481039.938, 4763889.500, 0, 0) ( 481130.312, 4763979.500, 0, 0) ( 481143.438, 4764010.500, 0, 0) ( 481199.844, 4764180.000, 0, 0) ( 481141.625, 4764480.500, 0, 0) ( 481140.469, 4764510.500, 0, 0) ( 481159.938, 4764580.000, 0, 0) ( 481185.500, 4764607.000, 0, 0) ( 481199.219, 4764623.500, 0, 0) ( 481209.812, 4764633.500, 0, 0) ( 481235.312, 4764650.000, 0, 0) ( 481635.969, 4764795.500, 0, 0) ( 481645.312, 4764797.500, 0, 0) ( 481629.844, 4764829.500, 0, 0) ( 481602.125, 4764915.500, 0, 0) ( 481575.000, 4764999.500, 0, 0) Shape:3 (Polygon) nVertices=29, nParts=1 Bounds:( 479117.812, 4764505.000, 0, 0) to ( 480088.812, 4765409.500, 0, 0) ( 479819.844, 4765180.500, 0, 0) Ring ( 479859.875, 4765270.000, 0, 0) ( 479909.875, 4765370.000, 0, 0) ( 479980.219, 4765409.500, 0, 0) ( 480019.719, 4765319.500, 0, 0) ( 480059.906, 4765239.500, 0, 0) ( 480088.812, 4765139.500, 0, 0) ( 480082.969, 4765049.500, 0, 0) ( 480000.281, 4765043.000, 0, 0) ( 479934.969, 4765020.000, 0, 0) ( 479895.125, 4765000.000, 0, 0) ( 479734.375, 4764865.000, 0, 0) ( 479680.281, 4764852.000, 0, 0) ( 479644.781, 4764827.500, 0, 0) ( 479637.875, 4764803.000, 0, 0) ( 479617.219, 4764760.000, 0, 0) ( 479587.281, 4764718.000, 0, 0) ( 479548.031, 4764693.500, 0, 0) ( 479504.906, 4764609.500, 0, 0) ( 479239.812, 4764505.000, 0, 0) ( 479117.812, 4764847.000, 0, 0) ( 479196.812, 4764879.000, 0, 0) ( 479208.656, 4764882.500, 0, 0) ( 479353.000, 4764939.500, 0, 0) ( 479411.438, 4764940.500, 0, 0) ( 479468.000, 4764942.500, 0, 0) ( 479681.781, 4764940.000, 0, 0) ( 479779.844, 4765109.500, 0, 0) ( 479819.844, 4765180.500, 0, 0) Shape:4 (Polygon) nVertices=22, nParts=1 Bounds:( 480537.156, 4764738.000, 0, 0) to ( 481575.000, 4765387.500, 0, 0) ( 480537.156, 4765014.000, 0, 0) Ring ( 481090.281, 4765242.000, 0, 0) ( 481443.688, 4765387.500, 0, 0) ( 481542.312, 4765097.500, 0, 0) ( 481575.000, 4764999.500, 0, 0) ( 481538.906, 4764982.500, 0, 0) ( 481509.656, 4764967.000, 0, 0) ( 481457.375, 4764937.000, 0, 0) ( 481465.906, 4764872.500, 0, 0) ( 481291.094, 4764810.000, 0, 0) ( 481281.312, 4764876.500, 0, 0) ( 481136.844, 4764994.500, 0, 0) ( 481088.188, 4764936.000, 0, 0) ( 480984.250, 4764875.000, 0, 0) ( 480930.719, 4764852.000, 0, 0) ( 480922.031, 4764850.500, 0, 0) ( 480824.969, 4764820.000, 0, 0) ( 480761.469, 4764778.000, 0, 0) ( 480701.062, 4764738.000, 0, 0) ( 480605.000, 4764835.000, 0, 0) ( 480567.969, 4764918.000, 0, 0) ( 480537.156, 4765014.000, 0, 0) Shape:5 (Polygon) nVertices=60, nParts=1 Bounds:( 484482.031, 4760649.500, 0, 0) to ( 488408.281, 4765179.000, 0, 0) ( 484482.031, 4764332.000, 0, 0) Ring ( 484519.969, 4764345.000, 0, 0) ( 484817.938, 4764465.500, 0, 0) ( 485615.406, 4764770.000, 0, 0) ( 486269.688, 4765010.000, 0, 0) ( 486320.062, 4765024.000, 0, 0) ( 486340.594, 4765040.000, 0, 0) ( 486369.844, 4765050.000, 0, 0) ( 486719.969, 4765170.000, 0, 0) ( 486738.625, 4765179.000, 0, 0) ( 486987.781, 4764497.500, 0, 0) ( 487019.875, 4764384.500, 0, 0) ( 487077.375, 4764226.500, 0, 0) ( 487120.031, 4764100.000, 0, 0) ( 487160.250, 4763998.000, 0, 0) ( 487186.812, 4763922.500, 0, 0) ( 487408.250, 4763315.500, 0, 0) ( 487608.062, 4762780.000, 0, 0) ( 487659.406, 4762650.000, 0, 0) ( 487719.406, 4762480.000, 0, 0) ( 487741.062, 4762419.500, 0, 0) ( 487747.875, 4762395.500, 0, 0) ( 487880.875, 4762032.000, 0, 0) ( 487899.438, 4761975.500, 0, 0) ( 488082.000, 4761480.000, 0, 0) ( 488408.281, 4760649.500, 0, 0) ( 488050.375, 4760824.500, 0, 0) ( 487690.906, 4760802.000, 0, 0) ( 487640.062, 4760879.500, 0, 0) ( 487594.938, 4761023.000, 0, 0) ( 487341.375, 4761776.500, 0, 0) ( 487037.125, 4761672.500, 0, 0) ( 487005.375, 4761662.500, 0, 0) ( 486788.219, 4761579.500, 0, 0) ( 486822.250, 4761492.000, 0, 0) ( 486838.312, 4761437.500, 0, 0) ( 486841.312, 4761381.000, 0, 0) ( 486850.562, 4761340.000, 0, 0) ( 486810.750, 4761335.500, 0, 0) ( 486775.438, 4761400.000, 0, 0) ( 486710.094, 4761368.000, 0, 0) ( 486606.188, 4761330.000, 0, 0) ( 486548.656, 4761488.000, 0, 0) ( 486380.656, 4761428.500, 0, 0) ( 486152.906, 4761348.000, 0, 0) ( 485900.250, 4761250.500, 0, 0) ( 485666.875, 4761156.500, 0, 0) ( 485585.875, 4761374.500, 0, 0) ( 485564.875, 4761444.500, 0, 0) ( 485496.219, 4761614.500, 0, 0) ( 485438.688, 4761760.500, 0, 0) ( 485264.969, 4762222.500, 0, 0) ( 485192.688, 4762439.000, 0, 0) ( 485175.406, 4762493.500, 0, 0) ( 484947.344, 4763100.500, 0, 0) ( 484888.000, 4763260.500, 0, 0) ( 484785.469, 4763560.500, 0, 0) ( 484760.219, 4763659.500, 0, 0) ( 484696.969, 4763734.000, 0, 0) ( 484482.031, 4764332.000, 0, 0) Shape:6 (Polygon) nVertices=26, nParts=1 Bounds:( 478315.531, 4764174.000, 0, 0) to ( 479305.875, 4765147.500, 0, 0) ( 479014.938, 4765147.500, 0, 0) Ring ( 479029.719, 4765110.500, 0, 0) ( 479117.812, 4764847.000, 0, 0) ( 479239.812, 4764505.000, 0, 0) ( 479305.875, 4764361.000, 0, 0) ( 479256.031, 4764314.500, 0, 0) ( 479220.906, 4764212.500, 0, 0) ( 479114.500, 4764174.000, 0, 0) ( 479018.281, 4764418.500, 0, 0) ( 478896.938, 4764371.000, 0, 0) ( 478748.812, 4764308.500, 0, 0) ( 478503.031, 4764218.000, 0, 0) ( 478461.750, 4764337.500, 0, 0) ( 478443.938, 4764400.500, 0, 0) ( 478447.812, 4764454.000, 0, 0) ( 478448.688, 4764531.500, 0, 0) ( 478502.188, 4764541.500, 0, 0) ( 478683.000, 4764730.500, 0, 0) ( 478621.031, 4764788.500, 0, 0) ( 478597.344, 4764766.500, 0, 0) ( 478532.500, 4764695.500, 0, 0) ( 478460.125, 4764615.000, 0, 0) ( 478408.062, 4764654.000, 0, 0) ( 478315.531, 4764876.000, 0, 0) ( 478889.250, 4765100.000, 0, 0) ( 479014.938, 4765147.500, 0, 0) Shape:7 (Polygon) nVertices=6, nParts=1 Bounds:( 479029.719, 4764847.000, 0, 0) to ( 479196.812, 4765117.000, 0, 0) ( 479029.719, 4765110.500, 0, 0) Ring ( 479046.531, 4765117.000, 0, 0) ( 479123.281, 4765015.000, 0, 0) ( 479196.812, 4764879.000, 0, 0) ( 479117.812, 4764847.000, 0, 0) ( 479029.719, 4765110.500, 0, 0) Shape:8 (Polygon) nVertices=20, nParts=1 Bounds:( 479504.906, 4764609.500, 0, 0) to ( 480133.969, 4765049.500, 0, 0) ( 480082.969, 4765049.500, 0, 0) Ring ( 480080.281, 4764979.500, 0, 0) ( 480133.969, 4764856.500, 0, 0) ( 479968.469, 4764788.000, 0, 0) ( 479750.688, 4764702.000, 0, 0) ( 479735.906, 4764752.000, 0, 0) ( 479640.094, 4764721.000, 0, 0) ( 479658.594, 4764670.000, 0, 0) ( 479504.906, 4764609.500, 0, 0) ( 479548.031, 4764693.500, 0, 0) ( 479587.281, 4764718.000, 0, 0) ( 479617.219, 4764760.000, 0, 0) ( 479637.875, 4764803.000, 0, 0) ( 479644.781, 4764827.500, 0, 0) ( 479680.281, 4764852.000, 0, 0) ( 479734.375, 4764865.000, 0, 0) ( 479895.125, 4765000.000, 0, 0) ( 479934.969, 4765020.000, 0, 0) ( 480000.281, 4765043.000, 0, 0) ( 480082.969, 4765049.500, 0, 0) Shape:9 (Polygon) nVertices=31, nParts=1 Bounds:( 479968.469, 4764183.000, 0, 0) to ( 480731.656, 4765014.000, 0, 0) ( 480389.688, 4764950.000, 0, 0) Ring ( 480537.156, 4765014.000, 0, 0) ( 480567.969, 4764918.000, 0, 0) ( 480605.000, 4764835.000, 0, 0) ( 480701.062, 4764738.000, 0, 0) ( 480710.250, 4764690.500, 0, 0) ( 480588.594, 4764740.500, 0, 0) ( 480540.719, 4764741.000, 0, 0) ( 480515.125, 4764695.000, 0, 0) ( 480731.656, 4764561.500, 0, 0) ( 480692.188, 4764453.500, 0, 0) ( 480677.844, 4764439.000, 0, 0) ( 480655.344, 4764397.500, 0, 0) ( 480584.375, 4764353.000, 0, 0) ( 480500.406, 4764326.500, 0, 0) ( 480358.531, 4764277.000, 0, 0) ( 480192.312, 4764183.000, 0, 0) ( 480157.125, 4764266.500, 0, 0) ( 480234.312, 4764304.000, 0, 0) ( 480289.125, 4764348.500, 0, 0) ( 480316.000, 4764395.000, 0, 0) ( 480343.562, 4764477.000, 0, 0) ( 480343.719, 4764532.500, 0, 0) ( 480258.031, 4764767.000, 0, 0) ( 480177.156, 4764742.000, 0, 0) ( 480093.750, 4764703.000, 0, 0) ( 480011.000, 4764674.500, 0, 0) ( 479985.062, 4764732.000, 0, 0) ( 479968.469, 4764788.000, 0, 0) ( 480133.969, 4764856.500, 0, 0) ( 480389.688, 4764950.000, 0, 0) Shape:10 (Polygon) nVertices=61, nParts=1 Bounds:( 479492.688, 4762880.500, 0, 0) to ( 481645.312, 4764999.500, 0, 0) ( 480701.062, 4764738.000, 0, 0) Ring ( 480761.469, 4764778.000, 0, 0) ( 480824.969, 4764820.000, 0, 0) ( 480922.031, 4764850.500, 0, 0) ( 480930.719, 4764852.000, 0, 0) ( 480984.250, 4764875.000, 0, 0) ( 481088.188, 4764936.000, 0, 0) ( 481136.844, 4764994.500, 0, 0) ( 481281.312, 4764876.500, 0, 0) ( 481291.094, 4764810.000, 0, 0) ( 481465.906, 4764872.500, 0, 0) ( 481457.375, 4764937.000, 0, 0) ( 481509.656, 4764967.000, 0, 0) ( 481538.906, 4764982.500, 0, 0) ( 481575.000, 4764999.500, 0, 0) ( 481602.125, 4764915.500, 0, 0) ( 481629.844, 4764829.500, 0, 0) ( 481645.312, 4764797.500, 0, 0) ( 481635.969, 4764795.500, 0, 0) ( 481235.312, 4764650.000, 0, 0) ( 481209.812, 4764633.500, 0, 0) ( 481199.219, 4764623.500, 0, 0) ( 481185.500, 4764607.000, 0, 0) ( 481159.938, 4764580.000, 0, 0) ( 481140.469, 4764510.500, 0, 0) ( 481141.625, 4764480.500, 0, 0) ( 481199.844, 4764180.000, 0, 0) ( 481143.438, 4764010.500, 0, 0) ( 481130.312, 4763979.500, 0, 0) ( 481039.938, 4763889.500, 0, 0) ( 480882.688, 4763670.000, 0, 0) ( 480826.062, 4763650.500, 0, 0) ( 480745.188, 4763628.500, 0, 0) ( 480654.438, 4763627.500, 0, 0) ( 480599.812, 4763660.000, 0, 0) ( 480281.938, 4763576.500, 0, 0) ( 480221.500, 4763533.500, 0, 0) ( 480199.688, 4763509.000, 0, 0) ( 480195.094, 4763430.000, 0, 0) ( 480273.688, 4763305.500, 0, 0) ( 480309.688, 4763063.500, 0, 0) ( 480201.844, 4762962.500, 0, 0) ( 479855.312, 4762880.500, 0, 0) ( 479848.531, 4762897.000, 0, 0) ( 479728.875, 4763217.500, 0, 0) ( 479492.688, 4763850.000, 0, 0) ( 479550.062, 4763919.500, 0, 0) ( 480120.219, 4764188.500, 0, 0) ( 480192.312, 4764183.000, 0, 0) ( 480358.531, 4764277.000, 0, 0) ( 480500.406, 4764326.500, 0, 0) ( 480584.375, 4764353.000, 0, 0) ( 480655.344, 4764397.500, 0, 0) ( 480677.844, 4764439.000, 0, 0) ( 480692.188, 4764453.500, 0, 0) ( 480731.656, 4764561.500, 0, 0) ( 480515.125, 4764695.000, 0, 0) ( 480540.719, 4764741.000, 0, 0) ( 480588.594, 4764740.500, 0, 0) ( 480710.250, 4764690.500, 0, 0) ( 480701.062, 4764738.000, 0, 0) Shape:11 (Polygon) nVertices=21, nParts=1 Bounds:( 476732.906, 4763624.500, 0, 0) to ( 478408.062, 4764876.000, 0, 0) ( 478315.531, 4764876.000, 0, 0) Ring ( 478408.062, 4764654.000, 0, 0) ( 478325.250, 4764606.500, 0, 0) ( 478220.094, 4764574.500, 0, 0) ( 478140.344, 4764511.000, 0, 0) ( 478065.062, 4764487.500, 0, 0) ( 478080.938, 4764401.500, 0, 0) ( 478110.500, 4764308.500, 0, 0) ( 478149.969, 4764212.500, 0, 0) ( 478180.219, 4764150.000, 0, 0) ( 478192.500, 4764099.500, 0, 0) ( 477893.125, 4763984.500, 0, 0) ( 477417.031, 4763800.500, 0, 0) ( 477005.594, 4763640.000, 0, 0) ( 476958.312, 4763624.500, 0, 0) ( 476947.250, 4763664.500, 0, 0) ( 476732.906, 4764243.000, 0, 0) ( 477322.375, 4764502.000, 0, 0) ( 477599.906, 4764600.000, 0, 0) ( 477949.656, 4764745.000, 0, 0) ( 478315.531, 4764876.000, 0, 0) Shape:12 (Polygon) nVertices=22, nParts=1 Bounds:( 478065.062, 4764099.500, 0, 0) to ( 478683.000, 4764788.500, 0, 0) ( 478408.062, 4764654.000, 0, 0) Ring ( 478460.125, 4764615.000, 0, 0) ( 478532.500, 4764695.500, 0, 0) ( 478597.344, 4764766.500, 0, 0) ( 478621.031, 4764788.500, 0, 0) ( 478683.000, 4764730.500, 0, 0) ( 478502.188, 4764541.500, 0, 0) ( 478448.688, 4764531.500, 0, 0) ( 478447.812, 4764454.000, 0, 0) ( 478443.938, 4764400.500, 0, 0) ( 478461.750, 4764337.500, 0, 0) ( 478503.031, 4764218.000, 0, 0) ( 478192.500, 4764099.500, 0, 0) ( 478180.219, 4764150.000, 0, 0) ( 478149.969, 4764212.500, 0, 0) ( 478110.500, 4764308.500, 0, 0) ( 478080.938, 4764401.500, 0, 0) ( 478065.062, 4764487.500, 0, 0) ( 478140.344, 4764511.000, 0, 0) ( 478220.094, 4764574.500, 0, 0) ( 478325.250, 4764606.500, 0, 0) ( 478408.062, 4764654.000, 0, 0) Shape:13 (Polygon) nVertices=27, nParts=1 Bounds:( 479239.812, 4763850.000, 0, 0) to ( 480343.719, 4764788.000, 0, 0) ( 479750.688, 4764702.000, 0, 0) Ring ( 479968.469, 4764788.000, 0, 0) ( 479985.062, 4764732.000, 0, 0) ( 480011.000, 4764674.500, 0, 0) ( 480093.750, 4764703.000, 0, 0) ( 480177.156, 4764742.000, 0, 0) ( 480258.031, 4764767.000, 0, 0) ( 480343.719, 4764532.500, 0, 0) ( 480343.562, 4764477.000, 0, 0) ( 480316.000, 4764395.000, 0, 0) ( 480289.125, 4764348.500, 0, 0) ( 480234.312, 4764304.000, 0, 0) ( 480157.125, 4764266.500, 0, 0) ( 480192.312, 4764183.000, 0, 0) ( 480120.219, 4764188.500, 0, 0) ( 479550.062, 4763919.500, 0, 0) ( 479492.688, 4763850.000, 0, 0) ( 479487.750, 4763864.500, 0, 0) ( 479442.750, 4763990.000, 0, 0) ( 479436.000, 4764023.000, 0, 0) ( 479398.938, 4764100.000, 0, 0) ( 479349.625, 4764230.000, 0, 0) ( 479305.875, 4764361.000, 0, 0) ( 479239.812, 4764505.000, 0, 0) ( 479504.906, 4764609.500, 0, 0) ( 479658.594, 4764670.000, 0, 0) ( 479750.688, 4764702.000, 0, 0) Shape:14 (Polygon) nVertices=5, nParts=1 Bounds:( 479640.094, 4764670.000, 0, 0) to ( 479750.688, 4764752.000, 0, 0) ( 479750.688, 4764702.000, 0, 0) Ring ( 479658.594, 4764670.000, 0, 0) ( 479640.094, 4764721.000, 0, 0) ( 479735.906, 4764752.000, 0, 0) ( 479750.688, 4764702.000, 0, 0) Shape:15 (Polygon) nVertices=28, nParts=1 Bounds:( 478503.031, 4763357.500, 0, 0) to ( 479349.625, 4764418.500, 0, 0) ( 479305.875, 4764361.000, 0, 0) Ring ( 479349.625, 4764230.000, 0, 0) ( 479218.156, 4764126.000, 0, 0) ( 479128.344, 4764030.500, 0, 0) ( 479103.406, 4764000.000, 0, 0) ( 479099.594, 4763977.500, 0, 0) ( 479080.812, 4763930.000, 0, 0) ( 478999.812, 4763864.500, 0, 0) ------------------------------------------------------------------------- Test 4: dump pline.dbf - uses new F field type ------------------------------------------------------------------------- Field 0: Type=Integer, Title=`FNODE_', Width=11, Decimals=0 Field 1: Type=Integer, Title=`TNODE_', Width=11, Decimals=0 Field 2: Type=Integer, Title=`LPOLY_', Width=11, Decimals=0 Field 3: Type=Integer, Title=`RPOLY_', Width=11, Decimals=0 Field 4: Type=Double, Title=`LENGTH', Width=13, Decimals=3 Field 5: Type=Integer, Title=`PLINE_', Width=11, Decimals=0 Field 6: Type=Integer, Title=`PLINE_ID', Width=11, Decimals=0 Field 7: Type=Integer, Title=`UID', Width=11, Decimals=0 Field 8: Type=Integer, Title=`GISO_TYPE_', Width=11, Decimals=0 Field 9: Type=Integer, Title=`SYMBOL', Width=6, Decimals=0 Field 10: Type=Integer, Title=`LOCK__ID', Width=11, Decimals=0 Field 11: Type=Integer, Title=`PHASE__ID', Width=6, Decimals=0 Field 12: Type=Integer, Title=`OBJECT__ID', Width=11, Decimals=0 Field 13: Type=String, Title=`TYPE', Width=50, Decimals=0 Field 14: Type=Integer, Title=`SYM_NBR', Width=6, Decimals=0 Field 15: Type=String, Title=`PHASE', Width=4, Decimals=0 Field 16: Type=String, Title=`CKT_NM', Width=30, Decimals=0 Field 17: Type=String, Title=`VOLTAGE', Width=30, Decimals=0 Field 18: Type=String, Title=`CMPN', Width=30, Decimals=0 Record: 0 FNODE_: 351 TNODE_: 352 LPOLY_: 0 RPOLY_: 0 LENGTH: 139.451 PLINE_: 1 PLINE_ID: 8588 UID: 544484 GISO_TYPE_: 13 SYMBOL: 101 LOCK__ID: 0 PHASE__ID: 0 OBJECT__ID: 131978 TYPE: Overhead Primary SYM_NBR: 101 PHASE: ABC CKT_NM: MED36 VOLTAGE: (NULL) CMPN: (NULL) Record: 1 FNODE_: 352 TNODE_: 362 LPOLY_: 0 RPOLY_: 0 LENGTH: 158.033 PLINE_: 2 PLINE_ID: 8695 UID: 544591 ------------------------------------------------------------------------- Test 5: NULL Shapes. ------------------------------------------------------------------------- Shapefile Type: Arc # of Shapes: 124 File Bounds: ( 257104.880, 5176098.606,0,0) to ( 335497.500, 5226768.100,0,0) Shape:0 (Arc) nVertices=21, nParts=1 Bounds:( 317138.450, 5176398.916, 0, 0) to ( 317325.590, 5186063.780, 0, 0) ( 317255.906, 5176398.916, 0, 0) Ring ( 317188.010, 5176506.460, 0, 0) ( 317176.920, 5176524.510, 0, 0) ( 317165.340, 5176546.850, 0, 0) ( 317157.950, 5176566.020, 0, 0) ( 317150.020, 5176587.650, 0, 0) ( 317140.130, 5176623.380, 0, 0) ( 317138.700, 5176637.220, 0, 0) ( 317138.450, 5176652.790, 0, 0) ( 317194.710, 5177654.350, 0, 0) ( 317208.900, 5178001.150, 0, 0) ( 317257.240, 5178791.400, 0, 0) ( 317233.330, 5179171.730, 0, 0) ( 317178.860, 5179593.910, 0, 0) ( 317177.430, 5180161.330, 0, 0) ( 317179.910, 5181231.060, 0, 0) ( 317191.120, 5182009.000, 0, 0) ( 317217.150, 5182812.160, 0, 0) ( 317251.760, 5184426.350, 0, 0) ( 317285.550, 5185242.720, 0, 0) ( 317325.590, 5186063.780, 0, 0) Shape:1 (Arc) nVertices=14, nParts=1 Bounds:( 327417.340, 5176119.960, 0, 0) to ( 327575.150, 5179522.550, 0, 0) ( 327417.340, 5176119.960, 0, 0) Ring ( 327472.250, 5177756.610, 0, 0) ( 327475.670, 5178507.280, 0, 0) ( 327487.420, 5179001.910, 0, 0) ( 327488.760, 5179080.090, 0, 0) ( 327485.310, 5179309.310, 0, 0) ( 327487.010, 5179328.210, 0, 0) ( 327491.800, 5179348.860, 0, 0) ( 327499.800, 5179374.940, 0, 0) ( 327512.980, 5179413.100, 0, 0) ( 327527.290, 5179446.960, 0, 0) ( 327538.870, 5179469.890, 0, 0) ( 327552.260, 5179491.550, 0, 0) ( 327575.150, 5179522.550, 0, 0) Shape:2 (Arc) nVertices=40, nParts=1 Bounds:( 326935.880, 5180924.980, 0, 0) to ( 327723.190, 5198803.660, 0, 0) ( 327370.950, 5180924.980, 0, 0) Ring ( 327410.070, 5181060.540, 0, 0) ( 327512.850, 5181435.450, 0, 0) ( 327518.640, 5181464.010, 0, 0) ( 327523.700, 5181488.920, 0, 0) ( 327524.500, 5181514.570, 0, 0) ( 327468.010, 5182633.640, 0, 0) ( 327500.040, 5183199.840, 0, 0) ( 327499.600, 5183224.920, 0, 0) ( 327484.700, 5183355.010, 0, 0) ( 327483.690, 5183400.900, 0, 0) ( 327483.840, 5183464.480, 0, 0) ( 327486.010, 5183494.980, 0, 0) ( 327571.280, 5184207.820, 0, 0) ( 327617.210, 5184599.430, 0, 0) ( 327620.420, 5184623.780, 0, 0) ( 327625.530, 5184650.530, 0, 0) ( 327698.430, 5184927.070, 0, 0) ( 327702.100, 5184946.520, 0, 0) ( 327717.940, 5185394.820, 0, 0) ( 327723.190, 5185719.320, 0, 0) ( 327719.460, 5185737.170, 0, 0) ( 327712.090, 5185755.740, 0, 0) ( 327699.840, 5185775.080, 0, 0) ( 327683.830, 5185791.480, 0, 0) ( 327665.380, 5185807.950, 0, 0) ( 327641.970, 5185822.740, 0, 0) ( 327622.280, 5185829.070, 0, 0) ( 327604.950, 5185832.940, 0, 0) ( 326937.500, 5185829.310, 0, 0) ( 326935.880, 5187515.510, 0, 0) ( 326983.050, 5189115.230, 0, 0) ( 326998.860, 5189920.820, 0, 0) ( 327060.240, 5190715.870, 0, 0) ( 327123.230, 5192332.220, 0, 0) ( 327179.920, 5193766.290, 0, 0) ( 327185.490, 5193921.940, 0, 0) ( 327204.120, 5195553.580, 0, 0) ( 327218.270, 5197179.250, 0, 0) ( 327251.330, 5198803.660, 0, 0) Shape:3 (NullShape) nVertices=0, nParts=0 Bounds:( 0.000, 0.000, 0, 0) to ( 0.000, 0.000, 0, 0) Shape:4 (NullShape) nVertices=0, nParts=0 Bounds:( 0.000, 0.000, 0, 0) to ( 0.000, 0.000, 0, 0) Shape:5 (NullShape) nVertices=0, nParts=0 Bounds:( 0.000, 0.000, 0, 0) to ( 0.000, 0.000, 0, 0) Shape:6 (Arc) nVertices=2, nParts=1 Bounds:( 327123.230, 5192296.600, 0, 0) to ( 328480.850, 5192332.220, 0, 0) ( 327123.230, 5192332.220, 0, 0) Ring ( 328480.850, 5192296.600, 0, 0) Shape:7 (Arc) nVertices=5, nParts=1 Bounds:( 329222.060, 5217943.490, 0, 0) to ( 335290.680, 5218084.780, 0, 0) ( 329222.060, 5218084.780, 0, 0) Ring ( 330442.520, 5218057.650, 0, 0) ( 332059.960, 5218033.810, 0, 0) ( 333685.820, 5218004.860, 0, 0) ( 335290.680, 5217943.490, 0, 0) Shape:8 (Arc) nVertices=65, nParts=1 Bounds:( 280048.100, 5177687.643, 0, 0) to ( 280439.410, 5182567.120, 0, 0) ( 280316.840, 5177687.643, 0, 0) Ring ( 280325.310, 5177968.830, 0, 0) ( 280324.630, 5178037.940, 0, 0) ( 280324.150, 5178059.350, 0, 0) ( 280320.130, 5178084.560, 0, 0) ( 280299.860, 5178170.250, 0, 0) ( 280288.710, 5178218.940, 0, 0) ( 280274.280, 5178283.640, 0, 0) ( 280268.000, 5178330.870, 0, 0) ( 280267.910, 5178346.760, 0, 0) ( 280270.510, 5178364.580, 0, 0) ( 280274.820, 5178382.360, 0, 0) ( 280278.440, 5178397.210, 0, 0) ( 280351.400, 5178743.800, 0, 0) ( 280369.860, 5178800.630, 0, 0) ( 280378.670, 5178826.010, 0, 0) ( 280400.350, 5178869.890, 0, 0) ( 280414.870, 5178901.180, 0, 0) ( 280427.030, 5178934.990, 0, 0) ( 280436.250, 5178971.970, 0, 0) ( 280439.410, 5178992.650, 0, 0) ( 280439.170, 5179001.630, 0, 0) ( 280437.010, 5179011.690, 0, 0) ( 280434.930, 5179016.970, 0, 0) ( 280431.870, 5179022.260, 0, 0) ( 280413.610, 5179041.850, 0, 0) ( 280410.040, 5179046.780, 0, 0) ( 280406.640, 5179052.480, 0, 0) shapelib-1.3.0/web/0000750042715500116100000000000011741051742013375 5ustar warmerdamengshapelib-1.3.0/web/.cvsignore0000640042715500116100000000001610073542061015367 0ustar warmerdamengrobots.txt dl shapelib-1.3.0/web/codepage.html0000640042715500116100000001466011552342731016043 0ustar warmerdameng This table is derived from:

http://www.autopark.ru/ASBProgrammerGuide/DBFSTRUC.HTM

ID Codepage Description
1 0x01 437 US MS-DOS
2 0x02 850 International MS-DOS
3 0x03 1252 Windows ANSI Latin I
4 0x04 10000 Standard Macintosh
8 0x08 865 Danish OEM
9 0x09 437 Dutch OEM
10 0x0A 850 Dutch OEM*
11 0x0B 437 Finnish OEM
13 0x0D 437 French OEM
14 0x0E 850 French OEM*
15 0x0F 437 German OEM
16 0x10 850 German OEM*
17 0x11 437 Italian OEM
18 0x12 850 Italian OEM*
19 0x13 932 Japanese Shift-JIS
20 0x14 850 Spanish OEM*
21 0x15 437 Swedish OEM
22 0x16 850 Swedish OEM*
23 0x17 865 Norwegian OEM
24 0x18 437 Spanish OEM
25 0x19 437 English OEM (Great Britain)
26 0x1A 850 English OEM (Great Britain)*
27 0x1B 437 English OEM (US)
28 0x1C 863 French OEM (Canada)
29 0x1D 850 French OEM*
31 0x1F 852 Czech OEM
34 0x22 852 Hungarian OEM
35 0x23 852 Polish OEM
36 0x24 860 Portuguese OEM
37 0x25 850 Portuguese OEM*
38 0x26 866 Russian OEM
55 0x37 850 English OEM (US)*
64 0x40 852 Romanian OEM
77 0x4D 936 Chinese GBK (PRC)
78 0x4E 949 Korean (ANSI/OEM)
79 0x4F 950 Chinese Big5 (Taiwan)
80 0x50 874 Thai (ANSI/OEM)
87 0x57 Current ANSI CP ANSI
88 0x58 1252 Western European ANSI
89 0x59 1252 Spanish ANSI
100 0x64 852 Eastern European MS-DOS
101 0x65 866 Russian MS-DOS
102 0x66 865 Nordic MS-DOS
103 0x67 861 Icelandic MS-DOS
104 0x68 895 Kamenicky (Czech) MS-DOS
105 0x69 620 Mazovia (Polish) MS-DOS
106 0x6A 737 Greek MS-DOS (437G)
107 0x6B 857 Turkish MS-DOS
108 0x6C 863 French-Canadian MS-DOS
120 0x78 950 Taiwan Big 5
121 0x79 949 Hangul (Wansung)
122 0x7A 936 PRC GBK
123 0x7B 932 Japanese Shift-JIS
124 0x7C 874 Thai Windows/MS–DOS
134 0x86 737 Greek OEM
135 0x87 852 Slovenian OEM
136 0x88 857 Turkish OEM
150 0x96 10007 Russian Macintosh
151 0x97 10029 Eastern European Macintosh
152 0x98 10006 Greek Macintosh
200 0xC8 1250 Eastern European Windows
201 0xC9 1251 Russian Windows
202 0xCA 1254 Turkish Windows
203 0xCB 1253 Greek Windows
204 0xCC 1257 Baltic Windows
shapelib-1.3.0/web/release.html0000640042715500116100000000642611741051717015716 0ustar warmerdameng Shapelib Release Notes

Shapelib Release Notes

To get notification of new releases of Shapelib subscribe to the project at www.freshmeat.net. This is currently the only reliable way of finding out about new releases since there is no shapelib specific mailing list.

Release 1.3.0:

  • Major rework to us application provided hooks for file io, and error reporting (SAHooks).
  • Added contrib/Shape_PointInPoly.cpp from Marko Podgorsek.
  • Added shapelib tools documentation from Eduardo Patto Kanegae.
  • Added dbf deletion support.
  • Added DBFAddNativeFieldType().
  • Added DBFDeleteField(), DBFReorderFields() and DBFAlterFields() to rework DBF schema.
  • likely a variety of other changes - it has been eight years since 1.2.10!
Release 1.2.10: Added SHPRewindObject() function, and shprewind utility program. Added FTLogical, DBFReadLogicalAttribute() and DBFWriteLogicalAttribute() (thanks to Olek Neyman).

Release 1.2.9: Good support for reading and writing NULL fields in .dbf files, good support for NULL shapes and addition of the DBFGetFieldIndex() functions (all contributed by Jim Matthews).

An upgraded shputils.c has been contributed by Bill Miller. Daniel Morissette contributed DBFGetNativeFieldType(). Better error checking for disk errors in dbfopen.c. Various other bug fixes and safety improvements.

Release 1.2.8: Added hacked libtool support (supplied by Jan) and "rpm ready" install logic.

Release 1.2.7: Fix record size (was 4 bytes too long). Modify SHPReadObject() to handle null shapes properly. Use atof() instead of sscanf(). Support .DBF as well as .dbf.

Release 1.2.6: Now available under old MIT style license, or at the users option, LGPL. Added the contrib directory of stuff from Carl Anderson and the shptree.c API for quadtree based spatial searches.

Release 1.2.5: SHPOpen() now forcably uses "rb" or "r+b" access string to avoid common mistakes on Windows. Also fixed a serious bug with .dbf files with a 'F' field type.

Release 1.2.4: DBFOpen() will now automatically translate a .shp extension to .dbf for convenience. SHPOpen() will try datasets with lower and uppercase extension. DBFAddField() now returns the field number, not TRUE/FALSE.

Release 1.2.3: Disable writing measures to multi-patches as ArcView seems to puke on them (as reported by Monika Sester). Add white space trimming, and string/numeric attribute interchangability in DBF API as suggested by Steve Lime. Dbfdump was updated to include several reporting options.

Release 1.2.2: Added proper support for multipatch (reading and writing) - this release just for testing purposes.

Release 1.2 is mostly a rewrite of the .shp/.shx access API to account for ArcView 3.x 3D shapes, and to encapsulate the shapes in a structure. Existing code using the shapefile library will require substantial changes to use release 1.2.

Release V1.1 has been built on a number of platforms, and used by a number of people successfully. V1.1 is the first release with the xBase API documentation.

shapelib-1.3.0/web/manifest.html0000640042715500116100000000515007763125111016074 0ustar warmerdameng Shapefile C Library V1.2

Shapelib Manifest

  • web/index.html: This file - general documentation on the Shapefile C Library.

  • web/shp_api.html: Documentation for the API for accessing the .shp/.shx files.

  • web/dbf_api.html: Documentation for the API for accessing the .dbf attribute files.

  • shpopen.c: C code for access to .shp/.shx vertex files.

  • dbfopen.c: C code for access to .dbf attribute file.

  • shapefil.h: Include file defining all the services of dbfopen.c and shpopen.c.

  • contrib/: A directory of "in progress" contributed programs from Carl Anderson.

  • dbfcreate.c: Simple example program for creating a new .dbf file.

  • dbfadd.c: Simple example program for adding a record to a .dbf file.

  • dbfdump.c: Simple example program for displaying the contents of a .dbf file.

  • shpcreate.c: Simple example program for creating a new .shp and .shx file.

  • shpadd.c: Simple example program for adding a shape to an existing shape file.

  • shpdump.c: Simple program for dumping all the vertices in a shapefile with an indicating of the parts.

  • shputils.c: Complex contributed program capable of clipping and appending shapefiles as well as a few other things. Type shputils after building to get a full usage message.

  • Makefile: A simple makefile to compile the library and example programs.

  • makeshape.sh: A simple script for running some of the example programs.

  • shptest.c: A simple test harnass to generate each of the supported types of shapefiles.

  • shptree.c: Implements a simple quadtree algorithm for fast spatial searches of shapefiles.

  • shptreedump.c: A simple mainly showing information on quad trees build using the quad tree api.

  • stream1.sh - A test script, which should produce stream1.out. Note this will only work if you have the example data downloaded.

  • stream1.out: Expected output of stream1.sh test script.

  • stream2.sh: A test script, which should produce stream2.out.

  • stream2.out: Expected output of stream2.sh test script.

  • pyshapelib-0.1: Prototype contributed Python bindings.

shapelib-1.3.0/web/shp_api.html0000640042715500116100000003151107455070025015712 0ustar warmerdameng .SHP File API

.SHP File API

The .SHP API uses a SHPHandle to represent an open .shp/.shx file pair. The contents of the SHPHandle are visible (see shapefile.h) but should be ignored by the application. It is intended that all information be accessed by the API functions.

Shape Types

Shapes have types associated with them. The following is a list of the different shapetypes supported by Shapefiles. At this time all shapes in a Shapefile must be of the same type (with the exception of NULL shapes).

  #define SHPT_NULL             0

  2D Shape Types (pre ArcView 3.x):

  #define SHPT_POINT		1	Points
  #define SHPT_ARC		3	Arcs (Polylines, possible in parts)
  #define SHPT_POLYGON		5	Polygons (possible in parts)
  #define SHPT_MULTIPOINT	8	MultiPoint (related points)

  3D Shape Types (may include "measure" values for vertices):

  #define SHPT_POINTZ		11	
  #define SHPT_ARCZ		13
  #define SHPT_POLYGONZ		15
  #define SHPT_MULTIPOINTZ 	18

  2D + Measure Types:

  #define SHPT_POINTM		21
  #define SHPT_ARCM		23
  #define SHPT_POLYGONM		25
  #define SHPT_MULTIPOINTM 	28

  Complex (TIN-like) with Z, and Measure:

  #define SHPT_MULTIPATCH 	31

SHPObject

An individual shape is represented by the SHPObject structure. SHPObject's created with SHPCreateObject(), SHPCreateSimpleObject(), or SHPReadObject() should be disposed of with SHPDestroyObject().

  typedef struct
  {
    int		nSHPType;	Shape Type (SHPT_* - see list above)

    int		nShapeId; 	Shape Number (-1 is unknown/unassigned)

    int		nParts;		# of Parts (0 implies single part with no info)
    int		*panPartStart;  Start Vertex of part
    int		*panPartType;	Part Type (SHPP_RING if not SHPT_MULTIPATCH)
    
    int		nVertices;	Vertex list 
    double	*padfX;		
    double	*padfY;
    double	*padfZ;		(all zero if not provided)
    double	*padfM;		(all zero if not provided)

    double	dfXMin;		Bounds in X, Y, Z and M dimensions
    double	dfYMin;
    double	dfZMin;
    double	dfMMin;

    double	dfXMax;
    double	dfYMax;
    double	dfZMax;
    double	dfMMax;
  } SHPObject;

SHPOpen()

SHPHandle SHPOpen( const char * pszShapeFile, const char * pszAccess );

  pszShapeFile:		The name of the layer to access.  This can be the
			name of either the .shp or the .shx file or can
			just be the path plus the basename of the pair.

  pszAccess:		The fopen() style access string.  At this time only
			"rb" (read-only binary) and "rb+" (read/write binary) 
		        should be used.
The SHPOpen() function should be used to establish access to the two files for accessing vertices (.shp and .shx). Note that both files have to be in the indicated directory, and must have the expected extensions in lower case. The returned SHPHandle is passed to other access functions, and SHPClose() should be invoked to recover resources, and flush changes to disk when complete.

SHPGetInfo()

void SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
                 double * padfMinBound, double * padfMaxBound );

  hSHP:			The handle previously returned by SHPOpen() 
			or SHPCreate().

  pnEntities:		A pointer to an integer into which the number of
			entities/structures should be placed.  May be NULL.

  pnShapetype:		A pointer to an integer into which the shapetype
			of this file should be placed.  Shapefiles may contain
			either SHPT_POINT, SHPT_ARC, SHPT_POLYGON or 
			SHPT_MULTIPOINT entities.  This may be NULL.

  padfMinBound:		The X, Y, Z and M minimum values will be placed into
                        this four entry array.  This may be NULL.
			
  padfMaxBound:		The X, Y, Z and M maximum values will be placed into
                        this four entry array.  This may be NULL.
The SHPGetInfo() function retrieves various information about shapefile as a whole. The bounds are read from the file header, and may be inaccurate if the file was improperly generated.

SHPReadObject()

SHPObject *SHPReadObject( SHPHandle hSHP, int iShape );

  hSHP:			The handle previously returned by SHPOpen() 
			or SHPCreate().

  iShape:		The entity number of the shape to read.  Entity 
			numbers are between 0 and nEntities-1 (as returned
			by SHPGetInfo()).
The SHPReadObject() call is used to read a single structure, or entity from the shapefile. See the definition of the SHPObject structure for detailed information on fields of a SHPObject. SHPObject's returned from SHPReadObject() should be deallocated with SHPDestroyShape(). SHPReadObject() will return NULL if an illegal iShape value is requested.

Note that the bounds placed into the SHPObject are those read from the file, and may not be correct. For points the bounds are generated from the single point since bounds aren't normally provided for point types.

Generally the shapes returned will be of the type of the file as a whole. However, any file may also contain type SHPT_NULL shapes which will have no geometry. Generally speaking applications should skip rather than preserve them, as they usually represented interactively deleted shapes.

SHPClose()

void	SHPClose( SHPHandle hSHP );

  hSHP:			The handle previously returned by SHPOpen() 
			or SHPCreate().
The SHPClose() function will close the .shp and .shx files, and flush all outstanding header information to the files. It will also recover resources associated with the handle. After this call the hSHP handle cannot be used again.

SHPCreate()

SHPHandle SHPCreate( const char * pszShapeFile, int nShapeType );

  pszShapeFile:		The name of the layer to access.  This can be the
			name of either the .shp or the .shx file or can
			just be the path plus the basename of the pair.

  nShapeType:		The type of shapes to be stored in the newly created
			file.  It may be either SHPT_POINT, SHPT_ARC, 
		        SHPT_POLYGON or SHPT_MULTIPOINT.
The SHPCreate() function will create a new .shp and .shx file of the desired type.

SHPCreateSimpleObject()

SHPObject * 
     SHPCreateSimpleObject( int nSHPType, int nVertices, 
			    double *padfX, double * padfY, double *padfZ, );

  nSHPType:		The SHPT_ type of the object to be created, such
                        as SHPT_POINT, or SHPT_POLYGON.
  
  nVertices:		The number of vertices being passed in padfX,    
                        padfY, and padfZ. 

  padfX:		An array of nVertices X coordinates of the vertices
                        for this object.

  padfY:		An array of nVertices Y coordinates of the vertices
                        for this object.

  padfZ:		An array of nVertices Z coordinates of the vertices
                        for this object.  This may be NULL in which case
		        they are all assumed to be zero.
The SHPCreateSimpleObject() allows for the convenient creation of simple objects. This is normally used so that the SHPObject can be passed to SHPWriteObject() to write it to the file. The simple object creation API assumes an M (measure) value of zero for each vertex. For complex objects (such as polygons) it is assumed that there is only one part, and that it is of the default type (SHPP_RING).

Use the SHPCreateObject() function for more sophisticated objects. The SHPDestroyObject() function should be used to free resources associated with an object allocated with SHPCreateSimpleObject().

This function computes a bounding box for the SHPObject from the given vertices.

SHPCreateObject()

SHPObject * 
     SHPCreateObject( int nSHPType, int iShape,
                      int nParts, int * panPartStart, int * panPartType,
                      int nVertices, double *padfX, double * padfY, 
                      double *padfZ, double *padfM );

  nSHPType:		The SHPT_ type of the object to be created, such
                        as SHPT_POINT, or SHPT_POLYGON.

  iShape:		The shapeid to be recorded with this shape.

  nParts:		The number of parts for this object.  If this is
                        zero for ARC, or POLYGON type objects, a single 
                        zero valued part will be created internally.
  
  panPartStart:		The list of zero based start vertices for the rings
                        (parts) in this object.  The first should always be
                        zero.  This may be NULL if nParts is 0.
  
  panPartType:		The type of each of the parts.  This is only meaningful
                        for MULTIPATCH files.  For all other cases this may
                        be NULL, and will be assumed to be SHPP_RING.
  
  nVertices:		The number of vertices being passed in padfX,    
                        padfY, and padfZ. 

  padfX:		An array of nVertices X coordinates of the vertices
                        for this object.

  padfY:		An array of nVertices Y coordinates of the vertices
                        for this object.

  padfZ:		An array of nVertices Z coordinates of the vertices
                        for this object.  This may be NULL in which case
		        they are all assumed to be zero.

  padfM:		An array of nVertices M (measure values) of the 
			vertices for this object.  This may be NULL in which 
			case they are all assumed to be zero.
The SHPCreateSimpleObject() allows for the creation of objects (shapes). This is normally used so that the SHPObject can be passed to SHPWriteObject() to write it to the file.

The SHPDestroyObject() function should be used to free resources associated with an object allocated with SHPCreateObject().

This function computes a bounding box for the SHPObject from the given vertices.

SHPComputeExtents()

void SHPComputeExtents( SHPObject * psObject );

  psObject:		An existing shape object to be updated in place.
This function will recompute the extents of this shape, replacing the existing values of the dfXMin, dfYMin, dfZMin, dfMMin, dfXMax, dfYMax, dfZMax, and dfMMax values based on the current set of vertices for the shape. This function is automatically called by SHPCreateObject() but if the vertices of an existing object are altered it should be called again to fix up the extents.

SHPWriteObject()

int SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject *psObject );

  hSHP:			The handle previously returned by SHPOpen("r+") 
			or SHPCreate().

  iShape:		The entity number of the shape to write.  A value of
		        -1 should be used for new shapes.  

  psObject:		The shape to write to the file. This should have
                        been created with SHPCreateObject(), or 
                        SHPCreateSimpleObject().
The SHPWriteObject() call is used to write a single structure, or entity to the shapefile. See the definition of the SHPObject structure for detailed information on fields of a SHPObject. The return value is the entity number of the written shape.

SHPDestroyObject()

void SHPDestroyObject( SHPObject *psObject );

  psObject:		The object to deallocate.
This function should be used to deallocate the resources associated with a SHPObject when it is no longer needed, including those created with SHPCreateSimpleObject(), SHPCreateObject() and returned from SHPReadObject().

SHPRewindObject()

int SHPRewindObject( SHPHandle hSHP, SHPObject *psObject );

  hSHP:                 The shapefile (not used at this time).
  psObject:		The object to deallocate.
This function will reverse any rings necessary in order to enforce the shapefile restrictions on the required order of inner and outer rings in the Shapefile specification. It returns TRUE if a change is made and FALSE if no change is made. Only polygon objects will be affected though any object may be passed.

shapelib-1.3.0/web/dbf_api.html0000640042715500116100000003655010357072777015676 0ustar warmerdameng Attribute (.DBF) API

Attribute (.DBF) API

The Attribute (DBF) API uses DBFHandle to represent a handle for access to one .dbf file. The contents of the DBFHandle are visible (see shapefil.h) but should be ignored by the application. It is intended that all information be accessed by API functions. Note that there should be exactly one record in the .dbf file for each shape in the .shp/.shx files. This constraint must be maintained by the application.

DBFOpen()

DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess );

  pszDBFFile:		The name of the xBase (.dbf) file to access.

  pszAccess:		The fopen() style access string.  At this time only
			"rb" (read-only binary) and "rb+" (read/write binary) 
		        should be used.
The DBFOpen() function should be used to establish access to an existing xBase format table file. The returned DBFHandle is passed to other access functions, and DBFClose() should be invoked to recover resources, and flush changes to disk when complete. The DBFCreate() function should called to create new xBase files. As a convenience, DBFOpen() can be called with the name of a .shp or .shx file, and it will figure out the name of the related .dbf file.

DBFCreate()

DBFHandle DBFCreate( const char * pszDBFFile );

  pszDBFFile:		The name of the xBase (.dbf) file to create.
The DBFCreate() function creates a new xBase format file with the given name, and returns an access handle that can be used with other DBF functions. The newly created file will have no fields, and no records. Fields should be added with DBFAddField() before any records add written.

DBFGetFieldCount()

int DBFGetFieldCount( DBFHandle hDBF );

  hDBF:		The access handle for the file to be queried, as returned
                by DBFOpen(), or DBFCreate().
The DBFGetFieldCount() function returns the number of fields currently defined for the indicated xBase file.

DBFGetRecordCount()

int DBFGetRecordCount( DBFHandle hDBF );

  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().
The DBFGetRecordCount() function returns the number of records that exist on the xBase file currently. Note that with shape files one xBase record exists for each shape in the .shp/.shx files.

DBFGetFieldIndex()

int DBFGetFieldIndex( DBFHandle hDBF, const char *pszFieldName );

  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  pszFieldName: Name of the field to search for.
Returns the index of the field matching this name, or -1 on failure. The comparison is case insensitive. However, lengths must match exactly.

DBFGetFieldInfo()

DBFFieldType DBFGetFieldInfo( DBFHandle hDBF, int iField, char * pszFieldName,
                              int * pnWidth, int * pnDecimals );

  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iField:	The field to be queried.  This should be a number between 
                0 and n-1, where n is the number fields on the file, as
                returned by DBFGetFieldCount().

  pszFieldName:	If this pointer is not NULL the name of the requested field
		will be written to this location.  The pszFieldName buffer 
                should be at least 12 character is size in order to hold
		the longest possible field name of 11 characters plus a 
                terminating zero character.

  pnWidth:	If this pointer is not NULL, the width of the requested field
		will be returned in the int pointed to by pnWidth.  This is
                the width in characters.  

  pnDecimals:	If this pointer is not NULL, the number of decimal places
                precision defined for the field will be returned.  This is
                zero for integer fields, or non-numeric fields.
The DBFGetFieldInfo() returns the type of the requested field, which is one of the DBFFieldType enumerated values. As well, the field name, and field width information can optionally be returned. The field type returned does not correspond one to one with the xBase field types. For instance the xBase field type for Date will just be returned as being FTInteger.

    typedef enum {
      FTString,			/* fixed length string field 		*/
      FTInteger,		/* numeric field with no decimals 	*/
      FTDouble,			/* numeric field with decimals 		*/
      FTLogical,		/* logical field.                       */
      FTInvalid                 /* not a recognised field type 		*/
    } DBFFieldType;

DBFAddField()

int DBFAddField( DBFHandle hDBF, const char * pszFieldName, 
                 DBFFieldType eType, int nWidth, int nDecimals );

  hDBF:		The access handle for the file to be updated, as returned by
		DBFOpen(), or DBFCreate().

  pszFieldName:	The name of the new field.  At most 11 character will be used.
                In order to use the xBase file in some packages it may be
                necessary to avoid some special characters in the field names
                such as spaces, or arithmetic operators.

  eType:	One of FTString, FTInteger or FTDouble in order to establish
                the type of the new field.  Note that some valid xBase field
                types cannot be created such as date fields.

  nWidth:	The width of the field to be created.  For FTString fields this
                establishes the maximum length of string that can be stored.
                For FTInteger this establishes the number of digits of the
                largest number that can
                be represented.  For FTDouble fields this in combination
                with the nDecimals value establish the size, and precision
                of the created field.

  nDecimals:    The number of decimal places to reserve for FTDouble fields.
                For all other field types this should be zero.  For instance
                with nWidth=7, and nDecimals=3 numbers would be formatted
                similarly to `123.456'.
The DBFAddField() function is used to add new fields to an existing xBase file opened with DBFOpen(), or created with DBFCreate(). Note that fields can only be added to xBase files with no records, though this is limitation of this API, not of the file format.

The DBFAddField() return value is the field number of the new field, or -1 if the addition of the field failed.

DBFReadIntegerAttribute()

int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadIntegerAttribute() will read the value of one field and return it as an integer. This can be used even with FTString fields, though the returned value will be zero if not interpretable as a number.

DBFReadDoubleAttribute()

double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadDoubleAttribute() will read the value of one field and return it as a double. This can be used even with FTString fields, though the returned value will be zero if not interpretable as a number.

DBFReadStringAttribute()

const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
The DBFReadStringAttribute() will read the value of one field and return it as a string. This function may be used on any field type (including FTInteger and FTDouble) and will return the string representation stored in the .dbf file. The returned pointer is to an internal buffer which is only valid untill the next DBF function call. It's contents may be copied with normal string functions such as strcpy(), or strdup(). If the TRIM_DBF_WHITESPACE macro is defined in shapefil.h (it is by default) then all leading and trailing space (ASCII 32) characters will be stripped before the string is returned.

DBFIsAttributeNULL()

int DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
  
  hDBF:		The access handle for the file to be queried, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) from which the field value
                should be read.

  iField:	The field within the selected record that should be read.
This function will return TRUE if the indicated field is NULL valued otherwise FALSE. Note that NULL fields are represented in the .dbf file as having all spaces in the field. Reading NULL fields will result in a value of 0.0 or an empty string with the other DBFRead*Attribute() functions.

DBFWriteIntegerAttribute

int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
                              int nFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  nFieldValue:	The integer value that should be written.
The DBFWriteIntegerAttribute() function is used to write a value to a numeric field (FTInteger, or FTDouble). If the write succeeds the value TRUE will be returned, otherwise FALSE will be returned. If the value is too large to fit in the field, it will be truncated and FALSE returned.

DBFWriteDoubleAttribute()

int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
                             double dFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  dFieldValue:	The floating point value that should be written.
The DBFWriteDoubleAttribute() function is used to write a value to a numeric field (FTInteger, or FTDouble). If the write succeeds the value TRUE will be returned, otherwise FALSE will be returned. If the value is too large to fit in the field, it will be truncated and FALSE returned.

DBFWriteStringAttribute()

int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
                             const char * pszFieldValue );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.

  pszFieldValue: The string to be written to the field.
The DBFWriteStringAttribute() function is used to write a value to a string field (FString). If the write succeeds the value TRUE willbe returned, otherwise FALSE will be returned. If the value is too large to fit in the field, it will be truncated and FALSE returned.

DBFWriteNULLAttribute()

int DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );

  hDBF:		The access handle for the file to be written, as returned by
		DBFOpen(), or DBFCreate().

  iShape:	The record number (shape number) to which the field value
                should be written.

  iField:	The field within the selected record that should be written.
The DBFWriteNULLAttribute() function is used to clear the indicated field to a NULL value. In the .dbf file this is represented by setting the entire field to spaces. If the write succeeds the value TRUE willbe returned, otherwise FALSE will be returned.

DBFClose()

void DBFClose( DBFHandle hDBF );

  hDBF:		The access handle for the file to be closed.
The DBFClose() function will close the indicated xBase file (opened with DBFOpen(), or DBFCreate()), flushing out all information to the file on disk, and recovering any resources associated with having the file open. The file handle (hDBF) should not be used again with the DBF API after calling DBFClose().

DBFIsRecordDeleted()

int DBFIsRecordDeleted( DBFHandle hDBF, int iShape );

  hDBF:		The access handle for the file to be checked.
  iShape:       The record index to check.
Returns TRUE (non-zero) if the record is marked for deletion, otherwise it returns FALSE.

DBFMarkRecordDeleted()

int DBFMarkRecordDeleted( DBFHandle hDBF, int iShape, int bIsDeleted );

  hDBF:		The access handle for the file.
  iShape:       The record index to update.
  bIsDeleted:   TRUE to mark record deleted, or FALSE to undelete it.
Returns TRUE on success, or FALSE on error.

DBFGetNativeFieldType()

char DBFGetNativeFieldType( DBFHandle hDBF, int iField );

  hDBF:		The access handle for the file.
  iField:       The field index to query.
  
This function returns the DBF type code of the indicated field. It will be one of:

  • 'C' (String)
  • 'D' (Date)
  • 'F' (Float)
  • 'N' (Numeric, with or without decimal)
  • 'L' (Logical)
  • 'M' (Memo: 10 digits .DBT block ptr)
  • ' ' (field out of range)
shapelib-1.3.0/web/index.html0000640042715500116100000002320011554030166015367 0ustar warmerdameng Shapefile C Library V1.2

Shapefile C Library V1.2

Purpose

The Shapefile C Library provides the ability to write simple C programs for reading, writing and updating (to a limited extent) ESRI Shapefiles, and the associated attribute file (.dbf).

Supporting Information

What is a Shapefile?

If you don't know, you probably don't need this library. The Shapefile format is a working and interchange format promulagated by ESRI for simple vector data with attributes.

An excellent white paper on the shapefile format is available from ESRI, but it is .pdf format, so you will need Adobe Acrobat to browse it.

The file format actually consists of three files.

XXX.shp - holds the actual vertices.
XXX.shx - hold index data pointing to the structures in the .shp file.
XXX.dbf - holds the attributes in xBase (dBase) format.  

Download

Source code, and some other odds and ends can be downloaded from http://download.osgeo.org/shapelib or http://shapelib.maptools.org/dl.

Shapelib is available for anonymous CVS access:

  cvs -d :pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot login
  Password: (hit enter)
  cvs -d :pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot co shapelib

Bugs, Maintainance and Support

This library is maintained by Frank Warmerdam. Please send me bug reports, patches and suggestions for the library via the maptools.org Bugzilla. Shapelib bugs can also be queried.

Shapelib is hosted at shapelib.maptools.org. A mailing list for discussion of how to use shapelib, and announcing new releases is available. To only find out about new releases of Shapelib select the "Subscribe to new releases" option from the link at Freshmeat.

Credits

I didn't start this section anywhere near soon enough, so alot of earlier contributors to Shapelib are lost in pre-history.
  • Bill Miller (NY-DOT) for shputils.c
  • Carl Anderson for the contents of the contrib directory, and the "tuple" additions to dbfopen.c.
  • Andrea Giacomelli for patches for dbfopen.c.
  • Doug Matthews for portability improvements.
  • Jan-Oliver Wagner for convincing me to make it available under LGPL, shared library support, and various other patches.
  • Dennis Christopher (of Avenza) for testing and bug fixes.
  • Miko Syrjä (of 3D-system Oy) for a record size bug fix.
  • Steven Lime and Curtis Hill for help with NULL shapes.
  • Jim Matthews for support of NULL attributes in dbf files.
  • PCI Geomatics who let me release a modified version of their shapefile code in the beginning and who hosted shapelib for years.

In Memorium

I would like to dedicate Shapelib to the memory of Sol Katz. While I never met him in person, his generous contributions to the GIS community took many forms, including free distribution of a variety of GIS translators with source. The fact that he used this Shapelib in some of his utilities, and thanked me was a great encouragement to me. I hope I can do his memory honour by trying to contribute in a similar fashion.

Portability

The Shapefile C Library should port easily to 32bit systems with ANSI C compilers. It should work on 64 bit architectures (such as the DEC AXP).

Care should also be taken to pass the binary access flag into SHPOpen() and DBFOpen() when operating on systems with special text file translation such as MSDOS.

The shputils.c module is contributed, and may not take the same approach to portability as the rest of the package.

On Linux, and most unix systems it should be possible to build and install shapefile support as a shared library using the "lib" and "lib_install" targets of the Makefile. Note that this Makefile doesn't use autoconf mechanisms and will generally require some hand tailoring for your environment.

Limitations

  • You can't modify the vertices of existing structures (though you can update the attributes of existing structures, and create new structures).

  • Not written in such a way as to be particularly fast. This is particularly true of the 1.2 API. For applications more concerned with speed it may be worth using the V1.1 API.

  • Doesn't set the last access time properly in the .dbf files.

  • There is no way to synchronize information to the file except to close it.

  • Poor error checking and reporting.

  • Not professionally supported (well it can be, if you want to pay).

  • Some aspects of xBase files not supported, though I believe they are not used by ESRI.

  • The application must keep the .dbf file in sync with the .shp/.shx files through appropriate use of the DBF and SHP APIs.

  • No support for the undocumented .sbn/.sbx spatial index files.

Other Shapefile Resources

  • Shapefile Format Specifications (pdf)

  • Xbase (.dbf) File Format Description.

  • Language ID / Code Page mappings

  • Shapelib is used within the multiformat OGR library. If you are looking for a high level C++ library with support for many geospatial vector formats you might want to check it out.

  • Ari Jolma has produced an initial perl binding on top of shapelib, which can be found at CPAN as Geo::ShapeFile under the Geo module.

  • Bernhard Herzog has produced python bindings for Shapelib with SWIG, available at http://ftp.intevation.de/users/bh/pyshapelib. A new version not using swig is available as part of Thuban.

  • Delphi bindings for Shapelib courtesy of Alexander Weidauer.

  • Miguel Filgueiras has implemented Tcl bindings for Shapelib as part of GPSMan.

  • David Gancarz has implemented a Microsoft .NET wrapper for Shapelib. An example of using shapelib with VB6 is also icluded in the .NET wrapper project file.

  • Andrey Hristov (php at hristov dot com) has developed a PHP extension based on Shapelib. It can be found in CVS at http://cvs.php.net/pecl/shp.

  • Toyoda Eizi has developed Ruby bindings found at http://sourceforge.net/projects/ruby-shapelib.

  • Davide Cesari has developed FORTRAN bindings that can be found at http://www.webalice.it/o.drofa/davide/shapelib-fortran.
  • Jan-Oliver Wagner has implemented a commandline program (gen2shp) for producing shapefiles from Arc/Info Generate format ASCII files. He maintains a web page for his work.

  • Tom Russo has implemented a shpcs2cs program, which reprojects shapefiles using arguments similar to the PROJ.4 cs2cs program including datum conversion. Use as an alternate to the contrib/shpproj which doesn't do datums. It is available at the bottom of Tom's Xastir Shapefile Resources page.

  • Andrew Williamson's Useful Scripts and Stuff page for ArcView, which includes ShapeChecker.

  • The University of Bonn sf4java project apparently includes Java classes for reading Shapefiles.

  • The ShapeIO2 Visual Basic libraries may be of interest to those wanting VB access to Shapefiles. Also available locally.

  • The ShapeFile Read/Write OCX is another option for Visual Basic programmers.

  • Isovist Analyst is a sort-of-free isovist generating extension for ArcView using shapelib.

  • shpdiff utility by Bryce Nesbitt.

  • Aequometer: a program for MS Excel to calculate the area of polygons and export as shapefiles.

shapelib-1.3.0/web/shapelib-tools.html0000640042715500116100000003120310023626744017212 0ustar warmerdameng ShapeLib Tools - User Guide

ShapeLib Tools - User Guide

ShapeLib is maintained by Frank Warmerdam
This guide was created by Eduardo Patto Kanegae < eduardo~at~consultoria~dot~eti~dot~br >

dbfcreate

Purpose: creates a new and empty .dbf file.
Usage: dbfcreate xbase_file [[-s field_name width],[-n field_name width decimals]]...
  • xbase_file: the name of xBase file to be created. Doesn't need the extension.
  • -s field_name width: creates a string field with name field_name and size width.
  • -n field_name width decimals: creates a numeric field with name field_name, width of width and with decimals places sized by decimals.
Example
$ dbfcreate testbase -s NAME 20, -n AREA 9 3, -n VALUE 9 2
# this will create a file named testbase.dbf with 3 fields: NAME ( string (20)), AREA ( float (9,3)) and VALUE ( float (9,2))

dbfadd

Purpose: adds a record into an existing .dbf file.
Usage: dbfadd xbase_file field_values
  • xbase_file: the name of an existing xBase file.
  • field_values: list of values to be inserted into the xBase file. You must specify a number of values equal to the number of fields the xBase file has. The order of values must also reflect the order of fields inside xBase file.
Example
$ dbfadd testbase.dbf REGION1 25.656 150.22
# assuming that testbase.dbf has 3 fields( NAME, AREA and VALUE), this command line will insert a new record into testbase.dbf with the value "REGION1" for NAME, '25.656' for AREA and '150.22' for VALUE field.

dbfdump

Purpose: dumps the content of a xBase file to the terminal.
Usage: dbfdump [-h] [-r] [-m] xbase_file
  • -h: output header info( field descriptions).
  • -r: output raw field info, numeric values not reformatted.
  • -m: output one line per field.
  • xbase_file: the name of an existing xBase file.
Example
$ dbfdump -h testbase.dbf
# assuming that testbase.dbf has 1 record( inserted by previous example using 'dbfadd'), this command line will produce the following output:
Field 0: Type=String, Title=`NAME', Width=20, Decimals=0
Field 1: Type=Double, Title=`AREA', Width=9, Decimals=3
Field 2: Type=Double, Title=`VALUE', Width=9, Decimals=2
NAME AREA VALUE
REGION1 25.656 150.22


shpcreate

Purpose: creates a new and empty shapefile.
Usage: shpcreate shp_file [point|arc|polygon|multipoint]
  • shp_file: the name of shapefile to be created. Doesn't need the extension.
  • point/arc/polygon/multipoint: the type of shapefile that you wish to create. You must specify a valid option.
Example
$ shpcreate testpolygon polygon
# this will create a point shapefile named testpolygon( in fact testpolygon.shp and testpolygon.shx will be created).

shpadd

Purpose: adds a shape into an existing shapefile.
Usage: shpadd shp_file [[x y] [+]]*
  • shp_file: the name of an existing shapefile.
  • x1 y1 x2 y2 ... xn yn: the set of x,y coordinates that describes the shape that you wish to add. Note that you must specify the correct number of parameters for a given type of shapefile. e.g.: for point shapefiles you have to pass 1 pair of XY coordinates and for a polygon shapefile you should pass at least 4 pairs of XY coordinates( where the first and the last point must have the same coordinates).
Example
$ shpadd testpolygon 100000 7000000 250000 6500000 200000 6000000 100000 7000000
# assuming that testpolygon is a polygon shapefile, this command line will insert a new shape( a triangle) into testpolygon with the following XY coordinates:
vertice 0: 100000 7000000 ( this will also be the vertice where the shape starts and ends)
vertice 1: 250000 6500000
vertice 2: 200000 6000000
vertice 3: 100000 7000000

shpdump

Purpose: dumps content of shapefile showing information like shape type, file extents, total of objects and vertices coordinates.
Usage: shpdump [-validate] shp_file
  • -validate: count the number of objects that has invalid ring orderings.
  • shp_file: the name of an existing shapefile.
Example
$ shpdump testpolygon
# assuming that testpolygon is an existing shapefile previously created, this command line will output the following result:
Shapefile Type: Polygon   # of Shapes: 1

File Bounds: (  100000.000, 6000000.000,0,0)
         to  (  250000.000, 7000000.000,0,0)

Shape:0 (Polygon)  nVertices=4, nParts=1
  Bounds:(  100000.000, 6000000.000, 0, 0)
      to (  250000.000, 7000000.000, 0, 0)
     (  100000.000, 7000000.000, 0, 0) Ring
     (  250000.000, 6500000.000, 0, 0)
     (  200000.000, 6000000.000, 0, 0)
     (  100000.000, 7000000.000, 0, 0)

shprewind

Purpose: validates and resets the winding order of rings in polygon geometries to match the ordering required by shapefile specification. This is usefull for shapefiles having troubles when checked with a 'shpdump -validate'.
Usage: shprewind in_shp_file out_shp_file
  • in_shp_file: the name of an existing shapefile.
  • out_shp_file: the name of the new fixed shapefile that will be created.
Example
$ shprewind badshapefile newshapefile

dbfinfo

Purpose: displays basic information for a given xBase file, like number of columns, number of records and type of each column.
Usage: dbfinfo xbase_file
  • xbase_file: the name of an existing xBase file.
Example
$ dbfinfo testbase
Info for testbase.dbf
3 Columns,  1 Records in file
           NAME          string  (20,0)
           AREA           float  (9,3)
          VALUE           float  (9,2)


dbfcat

Purpose: appends the records of a source xBase file into a destiny xBase file. Both files must have the same number of fields.
Usage: dbfcat [-v] [-f] from_DBFfile to_DBFfile
  • -v: verbose mode.
  • -f: forces data convertion if data field types is not the same at both files or if is there any null value into from_DBFfile.
  • from_DBFfile: source xBase file.
  • to_DBFfile: destiny xBase file.
Example
$ dbfcat -v testbase1 testbase2

shpinfo

Purpose: displays basic information for a given shapefile, like shapefile type, number of objects and its extents.
Usage: shpinfo shp_file
  • shp_file: the name of an existing shapefile.
Example
$ shpinfo testpolygon
Info for testpolygon
Polygon(5), 1 Records in file
File Bounds: (         100000,        6000000)
        (         250000,        7000000)

shpcat

Purpose: appends the content of a source shapefile into a destiny shapefile. Both files must be the same shapefile type.
Usage: shpcat from_shpfile to_shpfile
  • from_shpfile: source shapefile
  • to_shpfile: destiny shapefile
Example
$ shpcat shapefile1 shapefile2

shpcentrd

Purpose: computes XY centroid for polygon shapefiles.
Usage: shpcentrd shp_file new_shp_file
  • shp_file: the name of an existing polygon shapefile.
  • new_shp_file: the name of the point shapefile that will created.
Example
$ shpcentrd apolygonfile pointcentrd

shpdxf

Purpose: creates a DXF file from an existing shapefile.
Usage: shpdxf shapefile {idfield}
  • shapefile: the name of an existing shapefile.
  • idfield: explain
Example
$ shpdxf testshapefile IDFIELD
# explain the command

shpfix

Purpose: Utility program to fix nulls and inconsistencies in Shapefiles as happens from time to time.
Usage: shpfix shpfile new_file <Record# to Blank>
  • shpfile: input file
  • new_file: output file
Example
$ shpfix broken fixed

shpproj

Purpose: Reproject Shapefiles using PROJ.4
Usage: shpproj shp_file new_shp ( -i=in_proj_file | -i="in_params" | -i=geographic ) ( -o=out_info_file | -o="out_params" | -o=geographic )
  • param1: explain
  • param2: explain

INPUT
Input can come from one of three sources. A projection parameter file, directly through parameters or geographic. If the shapefile has an associated prj file, name the same as the shapefile but ending in ".prj" it will be used by default ignoring all other parameters. If input is omitted it defaults to geographic, unless the default prj file exists.

OUTPUT
Output can come from one of three sources. A projection parameter file, directly through parameters or geographic. If output is omitted it defaults to geographic.

PROJECTION PARAMETER FILE
This file MUST end with the extension ".prj". It has the form of one projection parameter per line. Parameters can be in any order. The projection parameters are those used to define a PROJ.4 projection.

PROJECTION PARAMETERS
Are the same as used by proj and invproj.

  use      proj -lP   to see available projections
	   proj -lu   to see available units
	   proj -le   to see available ellipsoid
Or visit the PROJ.4 web page at http://www.remotesensing.org/proj for more details.

Example
the following example projects file rowtest to row3, moving data from Stateplane NAD83 zone 1002 to utm zone 16 in meters

 
shpproj rowtest row -i="init=nad83:1002 units=us-ft" -o="proj=utm zone=16 units=m"

shpproj rowtest row3 -o="proj=utm zone=18 units=m" -i="zone=16 proj=utm units=us-ft"

shpproj rowtest row3 -o="proj=utm zone=18 units=m" 

shpproj rowtest row3 -i=myfile.prj -o=geographic
shpproj rowtest row3 -is=myfile.prj

shapelib-1.3.0/web/license.html0000640042715500116100000000661707763125304015725 0ustar warmerdameng Shapelib License

License

The source for the Shapefile C Library is (c) 1998 Frank Warmerdam, and released under the following conditions. The intent is that anyone can do anything with the code, but that I do not assume any liability, nor express any warranty for this code.

As of Shapelib 1.2.6 the core portions of the library are made available under two possible licenses. The licensee can choose to use the code under either the Library GNU Public License (LGPL) described in LICENSE.LGPL or under the following MIT style license. Any files in the Shapelib distribution without explicit copyright license terms (such as this documentation, the Makefile and so forth) should be considered to have the following licensing terms. Some auxilary portions of Shapelib, notably some of the components in the contrib directory come under slightly different license restrictions. Check the source files that you are actually using for conditions.

Default License Terms

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.

Shapelib Modifications

I am pleased to receive bug fixes, and improvements for Shapelib. Unless the submissions indicate otherwise I will assume that changes submitted to me remain under the the above "dual license" terms. If changes are made to the library with the intention that those changes should be protected by the LGPL then I should be informed upon submission. Note that I will not generally incorporate changes into the core of Shapelib that are protected under the LGPL as this would effectively limit the whole file and distribution to LGPL terms.

Opting for LGPL

For licensee's opting to use Shapelib under LGPL as opposed to the MIT Style license above, and wishing to redistribute the software based on Shapelib, I would ask that all "dual license" modules be updated to indicate that only the LGPL (and not the MIT Style license) applies. This action represents opting for the LGPL, and thereafter LGPL terms apply to any redistribution and modification of the affected modules.

shapelib-1.3.0/LICENSE.LGPL0000640042715500116100000006126307010562702014370 0ustar warmerdameng GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! shapelib-1.3.0/shptest.c0000640042715500116100000002306710125620777014474 0ustar warmerdameng/****************************************************************************** * $Id: shptest.c,v 1.7 2004-09-26 20:09:35 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Application for generating sample Shapefiles of various types. * Used by the stream2.sh test script. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shptest.c,v $ * Revision 1.7 2004-09-26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.6 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.5 2001/06/22 02:18:20 warmerda * Added null shape support * * Revision 1.4 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.3 1999/11/05 14:12:05 warmerda * updated license terms * * Revision 1.2 1998/12/16 05:15:20 warmerda * Added support for writing multipatch. * * Revision 1.1 1998/11/09 20:18:42 warmerda * Initial revision * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: shptest.c,v 1.7 2004-09-26 20:09:35 fwarmerdam Exp $") /************************************************************************/ /* Test_WritePoints() */ /* */ /* Write a small point file. */ /************************************************************************/ static void Test_WritePoints( int nSHPType, const char *pszFilename ) { SHPHandle hSHPHandle; SHPObject *psShape; double x, y, z, m; hSHPHandle = SHPCreate( pszFilename, nSHPType ); x = 1.0; y = 2.0; z = 3.0; m = 4.0; psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL, 1, &x, &y, &z, &m ); SHPWriteObject( hSHPHandle, -1, psShape ); SHPDestroyObject( psShape ); x = 10.0; y = 20.0; z = 30.0; m = 40.0; psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL, 1, &x, &y, &z, &m ); SHPWriteObject( hSHPHandle, -1, psShape ); SHPDestroyObject( psShape ); SHPClose( hSHPHandle ); } /************************************************************************/ /* Test_WriteMultiPoints() */ /* */ /* Write a small multipoint file. */ /************************************************************************/ static void Test_WriteMultiPoints( int nSHPType, const char *pszFilename ) { SHPHandle hSHPHandle; SHPObject *psShape; double x[4], y[4], z[4], m[4]; int i, iShape; hSHPHandle = SHPCreate( pszFilename, nSHPType ); for( iShape = 0; iShape < 3; iShape++ ) { for( i = 0; i < 4; i++ ) { x[i] = iShape * 10 + i + 1.15; y[i] = iShape * 10 + i + 2.25; z[i] = iShape * 10 + i + 3.35; m[i] = iShape * 10 + i + 4.45; } psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL, 4, x, y, z, m ); SHPWriteObject( hSHPHandle, -1, psShape ); SHPDestroyObject( psShape ); } SHPClose( hSHPHandle ); } /************************************************************************/ /* Test_WriteArcPoly() */ /* */ /* Write a small arc or polygon file. */ /************************************************************************/ static void Test_WriteArcPoly( int nSHPType, const char *pszFilename ) { SHPHandle hSHPHandle; SHPObject *psShape; double x[100], y[100], z[100], m[100]; int anPartStart[100]; int anPartType[100], *panPartType; int i, iShape; hSHPHandle = SHPCreate( pszFilename, nSHPType ); if( nSHPType == SHPT_MULTIPATCH ) panPartType = anPartType; else panPartType = NULL; for( iShape = 0; iShape < 3; iShape++ ) { x[0] = 1.0; y[0] = 1.0+iShape*3; x[1] = 2.0; y[1] = 1.0+iShape*3; x[2] = 2.0; y[2] = 2.0+iShape*3; x[3] = 1.0; y[3] = 2.0+iShape*3; x[4] = 1.0; y[4] = 1.0+iShape*3; for( i = 0; i < 5; i++ ) { z[i] = iShape * 10 + i + 3.35; m[i] = iShape * 10 + i + 4.45; } psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL, 5, x, y, z, m ); SHPWriteObject( hSHPHandle, -1, psShape ); SHPDestroyObject( psShape ); } /* -------------------------------------------------------------------- */ /* Do a multi part polygon (shape). We close it, and have two */ /* inner rings. */ /* -------------------------------------------------------------------- */ x[0] = 0.0; y[0] = 0.0; x[1] = 0; y[1] = 100; x[2] = 100; y[2] = 100; x[3] = 100; y[3] = 0; x[4] = 0; y[4] = 0; x[5] = 10; y[5] = 20; x[6] = 30; y[6] = 20; x[7] = 30; y[7] = 40; x[8] = 10; y[8] = 40; x[9] = 10; y[9] = 20; x[10] = 60; y[10] = 20; x[11] = 90; y[11] = 20; x[12] = 90; y[12] = 40; x[13] = 60; y[13] = 40; x[14] = 60; y[14] = 20; for( i = 0; i < 15; i++ ) { z[i] = i; m[i] = i*2; } anPartStart[0] = 0; anPartStart[1] = 5; anPartStart[2] = 10; anPartType[0] = SHPP_RING; anPartType[1] = SHPP_INNERRING; anPartType[2] = SHPP_INNERRING; psShape = SHPCreateObject( nSHPType, -1, 3, anPartStart, panPartType, 15, x, y, z, m ); SHPWriteObject( hSHPHandle, -1, psShape ); SHPDestroyObject( psShape ); SHPClose( hSHPHandle ); } /************************************************************************/ /* main() */ /************************************************************************/ int main( int argc, char ** argv ) { /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 2 ) { printf( "shptest test_number\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Figure out which test to run. */ /* -------------------------------------------------------------------- */ if( atoi(argv[1]) == 0 ) Test_WritePoints( SHPT_NULL, "test0.shp" ); else if( atoi(argv[1]) == 1 ) Test_WritePoints( SHPT_POINT, "test1.shp" ); else if( atoi(argv[1]) == 2 ) Test_WritePoints( SHPT_POINTZ, "test2.shp" ); else if( atoi(argv[1]) == 3 ) Test_WritePoints( SHPT_POINTM, "test3.shp" ); else if( atoi(argv[1]) == 4 ) Test_WriteMultiPoints( SHPT_MULTIPOINT, "test4.shp" ); else if( atoi(argv[1]) == 5 ) Test_WriteMultiPoints( SHPT_MULTIPOINTZ, "test5.shp" ); else if( atoi(argv[1]) == 6 ) Test_WriteMultiPoints( SHPT_MULTIPOINTM, "test6.shp" ); else if( atoi(argv[1]) == 7 ) Test_WriteArcPoly( SHPT_ARC, "test7.shp" ); else if( atoi(argv[1]) == 8 ) Test_WriteArcPoly( SHPT_ARCZ, "test8.shp" ); else if( atoi(argv[1]) == 9 ) Test_WriteArcPoly( SHPT_ARCM, "test9.shp" ); else if( atoi(argv[1]) == 10 ) Test_WriteArcPoly( SHPT_POLYGON, "test10.shp" ); else if( atoi(argv[1]) == 11 ) Test_WriteArcPoly( SHPT_POLYGONZ, "test11.shp" ); else if( atoi(argv[1]) == 12 ) Test_WriteArcPoly( SHPT_POLYGONM, "test12.shp" ); else if( atoi(argv[1]) == 13 ) Test_WriteArcPoly( SHPT_MULTIPATCH, "test13.shp" ); else { printf( "Test `%s' not recognised.\n", argv[1] ); exit( 10 ); } #ifdef USE_DBMALLOC malloc_dump(2); #endif exit( 0 ); } shapelib-1.3.0/stream1.sh0000750042715500116100000000231107064435245014537 0ustar warmerdameng#!/bin/sh EG_DATA=/u/www/projects/shapelib/eg_data echo ------------------------------------------------------------------------- echo Test 1: dump anno.shp echo ------------------------------------------------------------------------- ./shpdump $EG_DATA/anno.shp | head -250 echo ------------------------------------------------------------------------- echo Test 2: dump brklinz.shp echo ------------------------------------------------------------------------- ./shpdump $EG_DATA/brklinz.shp | head -500 echo ------------------------------------------------------------------------- echo Test 3: dump polygon.shp echo ------------------------------------------------------------------------- ./shpdump $EG_DATA/polygon.shp | head -500 echo ------------------------------------------------------------------------- echo Test 4: dump pline.dbf - uses new F field type echo ------------------------------------------------------------------------- ./dbfdump -m -h $EG_DATA/pline.dbf | head -50 echo ------------------------------------------------------------------------- echo Test 5: NULL Shapes. echo ------------------------------------------------------------------------- ./shpdump $EG_DATA/csah.dbf | head -150 shapelib-1.3.0/.cvsignore0000640042715500116100000000016211671226417014625 0ustar warmerdamengdbfadd dbfcreate dbfdump shpadd shpcreate shpdump shprewind shptreedump shptest *.dll *.lib *.exp *.la *.lo .libs shapelib-1.3.0/README0000750042715500116100000000152011612720132013472 0ustar warmerdameng Please read shapelib.html. Building on Unix ---------------- 1) Edit Makefile, and set CFLAGS, and CC macros as required for the target system. Often the defaults will work fine. 2) type "make" The result should be: Core shapelib support. shpopen.o dbfopen.o safileio.o shptree.o libshp.a Utility/demonstration programs: shpcreate, shpdump, shpadd, dbfcreate, dbfdump, dbfadd, shptreedump 3) To test type: make test 4) To libshp.a and the test binaries in /usr/local: make install Building on Windows ------------------- If you have run the VC++ VCVARS32.BAT, you should be able to type the following in a command window to build the code and executables: C:> nmake /f makefile.vc Otherwise create your own VC++ project. There aren't many files to deal with here! shapelib-1.3.0/shprewind.c0000640042715500116100000001010010125620777014765 0ustar warmerdameng/****************************************************************************** * $Id: shprewind.c,v 1.4 2004-09-26 20:09:35 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Utility to validate and reset the winding order of rings in * polygon geometries to match the ordering required by spec. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2002, 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: shprewind.c,v $ * Revision 1.4 2004-09-26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.3 2004/01/09 16:39:49 fwarmerdam * include standard include files * * Revision 1.2 2002/04/10 17:23:11 warmerda * copy from source to destination now * * Revision 1.1 2002/04/10 16:56:36 warmerda * New * */ #include #include #include "shapefil.h" int main( int argc, char ** argv ) { SHPHandle hSHP, hSHPOut; int nShapeType, nEntities, i, nInvalidCount=0; double adfMinBound[4], adfMaxBound[4]; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 3 ) { printf( "shprewind in_shp_file out_shp_file\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( argv[1], "rb" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", argv[1] ); exit( 1 ); } SHPGetInfo( hSHP, &nEntities, &nShapeType, adfMinBound, adfMaxBound ); /* -------------------------------------------------------------------- */ /* Create output shapefile. */ /* -------------------------------------------------------------------- */ hSHPOut = SHPCreate( argv[2], nShapeType ); if( hSHPOut == NULL ) { printf( "Unable to create:%s\n", argv[2] ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Skim over the list of shapes, printing all the vertices. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nEntities; i++ ) { SHPObject *psShape; psShape = SHPReadObject( hSHP, i ); if( SHPRewindObject( hSHP, psShape ) ) nInvalidCount++; SHPWriteObject( hSHPOut, -1, psShape ); SHPDestroyObject( psShape ); } SHPClose( hSHP ); SHPClose( hSHPOut ); printf( "%d objects rewound.\n", nInvalidCount ); exit( 0 ); } shapelib-1.3.0/stream2.sh0000750042715500116100000000042607314525505014542 0ustar warmerdameng#!/bin/sh for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13; do echo ----------------------------------------------------------------------- echo Test 2/$i echo ----------------------------------------------------------------------- ./shptest $i ./shpdump test${i}.shp done shapelib-1.3.0/makeshape.sh0000750042715500116100000000103511364056264015121 0ustar warmerdameng#!/bin/sh # # Use example programs to create a very simple dataset that # should display in ARCView II. # ./shpcreate test polygon ./dbfcreate test.dbf -s Description 30 -n TestInt 6 0 -n TestDouble 16 5 ./shpadd test 0 0 100 0 100 100 0 100 0 0 + 20 20 20 30 30 30 20 20 ./dbfadd test.dbf "Square with triangle missing" 1.5 2.5 ./shpadd test 150 150 160 150 180 170 150 150 ./dbfadd test.dbf "Smaller triangle" 100 1000.25 ./shpadd test 150 150 160 150 180 170 150 150 ./dbfadd test.dbf "" "" "" ./shpdump test.shp ./dbfdump test.dbf shapelib-1.3.0/shputils.c0000640042715500116100000012026610730307433014645 0ustar warmerdameng/****************************************************************************** * $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 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= 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= '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 {ALL}"); puts( "USAGE: shputils " ); puts( " { }" ); puts( " { }" ); puts( " { }" ); puts( " { }" ); puts( " { }" ); 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 ); } shapelib-1.3.0/Makefile0000640042715500116100000000555111612720132014260 0ustar warmerdameng PREFIX = /usr/local CFLAGS = -g -Wall -fPIC #CFLAGS = -g -DUSE_CPL #CC = g++ LIBOBJ = shpopen.o dbfopen.o safileio.o shptree.o SHPBIN = shpcreate shpadd shpdump shprewind dbfcreate dbfadd dbfdump \ shptreedump default: all all: $(SHPBIN) shptest lib shpopen.o: shpopen.c shapefil.h $(CC) $(CFLAGS) -c shpopen.c shptree.o: shptree.c shapefil.h $(CC) $(CFLAGS) -c shptree.c dbfopen.o: dbfopen.c shapefil.h $(CC) $(CFLAGS) -c dbfopen.c safileio.o: safileio.c shapefil.h $(CC) $(CFLAGS) -c safileio.c shpcreate: shpcreate.c shpopen.o safileio.o $(CC) $(CFLAGS) shpcreate.c shpopen.o safileio.o $(LINKOPT) -o shpcreate shpadd: shpadd.c shpopen.o safileio.o $(CC) $(CFLAGS) shpadd.c shpopen.o safileio.o $(LINKOPT) -o shpadd shpdump: shpdump.c shpopen.o safileio.o $(CC) $(CFLAGS) shpdump.c shpopen.o safileio.o $(LINKOPT) -o shpdump shprewind: shprewind.c shpopen.o safileio.o $(CC) $(CFLAGS) shprewind.c shpopen.o safileio.o $(LINKOPT) -o shprewind dbfcreate: dbfcreate.c dbfopen.o safileio.o $(CC) $(CFLAGS) dbfcreate.c dbfopen.o safileio.o $(LINKOPT) -o dbfcreate dbfadd: dbfadd.c dbfopen.o safileio.o $(CC) $(CFLAGS) dbfadd.c dbfopen.o safileio.o $(LINKOPT) -o dbfadd dbfdump: dbfdump.c dbfopen.o safileio.o $(CC) $(CFLAGS) dbfdump.c dbfopen.o safileio.o $(LINKOPT) -o dbfdump shptest: shptest.c shpopen.o safileio.o $(CC) $(CFLAGS) shptest.c shpopen.o safileio.o $(LINKOPT) -o shptest shputils: shputils.c shpopen.o safileio.o dbfopen.o $(CC) $(CFLAGS) shputils.c shpopen.o safileio.o dbfopen.o $(LINKOPT) -o shputils shptreedump: shptreedump.c shptree.o shpopen.o safileio.o $(CC) $(CFLAGS) shptreedump.c shptree.o shpopen.o safileio.o $(LINKOPT) \ -o shptreedump clean: rm -f *.o shptest $(SHPBIN) libshp.a test: test2 test3 # # Note this stream only works if example data is accessable. # Fetch ftp://gdal.velocet.ca/pub/outgoing/shape_eg_data.zip # test1: @./stream1.sh > s1.out @if test "`diff s1.out stream1.out`" = '' ; then \ echo "******* Stream 1 Succeeded *********"; \ rm s1.out; \ else \ echo "******* Stream 1 Failed *********"; \ diff s1.out stream1.out; \ fi test2: @./stream2.sh > s2.out @if test "`diff s2.out stream2.out`" = '' ; then \ echo "******* Stream 2 Succeeded *********"; \ rm s2.out; \ rm test*.s??; \ else \ echo "******* Stream 2 Failed *********"; \ diff s2.out stream2.out; \ fi test3: @./makeshape.sh > s3.out @if test "`diff s3.out stream3.out`" = '' ; then \ echo "******* Stream 3 Succeeded *********"; \ rm s3.out; \ rm test.*; \ else \ echo "******* Stream 3 Failed *********"; \ diff s3.out stream3.out; \ fi lib: libshp.a libshp.a: $(LIBOBJ) ar r libshp.a $(LIBOBJ) lib_install: libshp.a cp libshp.a $(PREFIX)/lib cp shapefil.h $(PREFIX)/include bin_install: $(SHPBIN) cp $(SHPBIN) $(PREFIX)/bin install: lib_install bin_install shapelib-1.3.0/stream3.out0000640042715500116100000000161611612705752014740 0ustar warmerdamengShapefile Type: Polygon # of Shapes: 3 File Bounds: (0,0,0,0) to (180,170,0,0) Shape:0 (Polygon) nVertices=9, nParts=2 Bounds:(0,0, 0) to (100,100, 0) (0,0, 0) Ring (100,0, 0) (100,100, 0) (0,100, 0) (0,0, 0) + (20,20, 0) Ring (20,30, 0) (30,30, 0) (20,20, 0) Shape:1 (Polygon) nVertices=4, nParts=1 Bounds:(150,150, 0) to (180,170, 0) (150,150, 0) Ring (160,150, 0) (180,170, 0) (150,150, 0) Shape:2 (Polygon) nVertices=4, nParts=1 Bounds:(150,150, 0) to (180,170, 0) (150,150, 0) Ring (160,150, 0) (180,170, 0) (150,150, 0) Descriptio TestInt TestDouble Square with triangle missing 1 2.50000 Smaller triangle 100 1000.25000 (NULL) (NULL) (NULL) shapelib-1.3.0/safileio.c0000640042715500116100000002271610743461572014577 0ustar warmerdameng/****************************************************************************** * $Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $ * * Project: Shapelib * Purpose: Default implementation of file io based on stdio. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2007, 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: safileio.c,v $ * Revision 1.4 2008-01-16 20:05:14 bram * Add file hooks that accept UTF-8 encoded filenames on some platforms. Use SASetupUtf8Hooks * tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability. Currently, this * is only available on the Windows platform that decodes the UTF-8 filenames to wide * character strings and feeds them to _wfopen and _wremove. * * Revision 1.3 2007/12/18 18:28:11 bram * - create hook for client specific atof (bugzilla ticket 1615) * - check for NULL handle before closing cpCPG file, and close after reading. * * Revision 1.2 2007/12/15 20:25:30 bram * dbfopen.c now reads the Code Page information from the DBF file, and exports * this information as a string through the DBFGetCodePage function. This is * either the number from the LDID header field ("LDID/") or as the * content of an accompanying .CPG file. When creating a DBF file, the code can * be set using DBFCreateEx. * * Revision 1.1 2007/12/06 06:56:41 fwarmerdam * new * */ #include "shapefil.h" #include #include #include #include #include #include SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $"); #ifdef SHPAPI_UTF8_HOOKS # ifdef SHPAPI_WINDOWS # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include # pragma comment(lib, "kernel32.lib") # endif #endif /************************************************************************/ /* SADFOpen() */ /************************************************************************/ SAFile SADFOpen( const char *pszFilename, const char *pszAccess ) { return (SAFile) fopen( pszFilename, pszAccess ); } /************************************************************************/ /* SADFRead() */ /************************************************************************/ SAOffset SADFRead( void *p, SAOffset size, SAOffset nmemb, SAFile file ) { return (SAOffset) fread( p, (size_t) size, (size_t) nmemb, (FILE *) file ); } /************************************************************************/ /* SADFWrite() */ /************************************************************************/ SAOffset SADFWrite( void *p, SAOffset size, SAOffset nmemb, SAFile file ) { return (SAOffset) fwrite( p, (size_t) size, (size_t) nmemb, (FILE *) file ); } /************************************************************************/ /* SADFSeek() */ /************************************************************************/ SAOffset SADFSeek( SAFile file, SAOffset offset, int whence ) { return (SAOffset) fseek( (FILE *) file, (long) offset, whence ); } /************************************************************************/ /* SADFTell() */ /************************************************************************/ SAOffset SADFTell( SAFile file ) { return (SAOffset) ftell( (FILE *) file ); } /************************************************************************/ /* SADFFlush() */ /************************************************************************/ int SADFFlush( SAFile file ) { return fflush( (FILE *) file ); } /************************************************************************/ /* SADFClose() */ /************************************************************************/ int SADFClose( SAFile file ) { return fclose( (FILE *) file ); } /************************************************************************/ /* SADFClose() */ /************************************************************************/ int SADRemove( const char *filename ) { return remove( filename ); } /************************************************************************/ /* SADError() */ /************************************************************************/ void SADError( const char *message ) { fprintf( stderr, "%s\n", message ); } /************************************************************************/ /* SASetupDefaultHooks() */ /************************************************************************/ void SASetupDefaultHooks( SAHooks *psHooks ) { psHooks->FOpen = SADFOpen; psHooks->FRead = SADFRead; psHooks->FWrite = SADFWrite; psHooks->FSeek = SADFSeek; psHooks->FTell = SADFTell; psHooks->FFlush = SADFFlush; psHooks->FClose = SADFClose; psHooks->Remove = SADRemove; psHooks->Error = SADError; psHooks->Atof = atof; } #ifdef SHPAPI_WINDOWS /************************************************************************/ /* Utf8ToWideChar */ /************************************************************************/ const wchar_t* Utf8ToWideChar( const char *pszFilename ) { int nMulti, nWide; wchar_t *pwszFileName; nMulti = strlen(pszFilename) + 1; nWide = MultiByteToWideChar( CP_UTF8, 0, pszFilename, nMulti, 0, 0); if( nWide == 0 ) { return NULL; } pwszFileName = (wchar_t*) malloc(nWide * sizeof(wchar_t)); if ( pwszFileName == NULL ) { return NULL; } if( MultiByteToWideChar( CP_UTF8, 0, pszFilename, nMulti, pwszFileName, nWide ) == 0 ) { free( pwszFileName ); return NULL; } return pwszFileName; } /************************************************************************/ /* SAUtf8WFOpen */ /************************************************************************/ SAFile SAUtf8WFOpen( const char *pszFilename, const char *pszAccess ) { SAFile file = NULL; const wchar_t *pwszFileName, *pwszAccess; pwszFileName = Utf8ToWideChar( pszFilename ); pwszAccess = Utf8ToWideChar( pszAccess ); if( pwszFileName != NULL && pwszFileName != NULL) { file = (SAFile) _wfopen( pwszFileName, pwszAccess ); } free ((wchar_t*) pwszFileName); free ((wchar_t*) pwszAccess); return file; } /************************************************************************/ /* SAUtf8WRemove() */ /************************************************************************/ int SAUtf8WRemove( const char *pszFilename ) { const wchar_t *pwszFileName = Utf8ToWideChar( pszFilename ); int rc = -1; if( pwszFileName != NULL ) { rc = _wremove( pwszFileName ); } free ((wchar_t*) pwszFileName); return rc; } #endif #ifdef SHPAPI_UTF8_HOOKS /************************************************************************/ /* SASetupUtf8Hooks() */ /************************************************************************/ void SASetupUtf8Hooks( SAHooks *psHooks ) { #ifdef SHPAPI_WINDOWS psHooks->FOpen = SAUtf8WFOpen; psHooks->Remove = SAUtf8WRemove; #else # error "no implementations of UTF-8 hooks available for this platform" #endif psHooks->FRead = SADFRead; psHooks->FWrite = SADFWrite; psHooks->FSeek = SADFSeek; psHooks->FTell = SADFTell; psHooks->FFlush = SADFFlush; psHooks->FClose = SADFClose; psHooks->Error = SADError; psHooks->Atof = atof; } #endif shapelib-1.3.0/shpcreate.c0000640042715500116100000001155010735746775014770 0ustar warmerdameng/****************************************************************************** * $Id: shpcreate.c,v 1.8 2007-12-30 16:57:33 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for creating a new shapefile. * Author: Frank Warmerdam, warmerdm@pobox.com * ****************************************************************************** * 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: shpcreate.c,v $ * Revision 1.8 2007-12-30 16:57:33 fwarmerdam * add support for z and m * * Revision 1.7 2004/09/26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.6 2004/01/09 16:39:49 fwarmerdam * include standard include files * * Revision 1.5 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.4 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.3 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.2 1995/08/04 03:16:43 warmerda * Added header. * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: shpcreate.c,v 1.8 2007-12-30 16:57:33 fwarmerdam Exp $") int main( int argc, char ** argv ) { SHPHandle hSHP; int nShapeType; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 3 ) { printf( "shpcreate shp_file [point/arc/polygon/multipoint][/m/z]\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Figure out the shape type. */ /* -------------------------------------------------------------------- */ if( strcmp(argv[2],"POINT") == 0 || strcmp(argv[2],"point") == 0 ) nShapeType = SHPT_POINT; else if( strcmp(argv[2],"ARC") == 0 || strcmp(argv[2],"arc") == 0 ) nShapeType = SHPT_ARC; else if( strcmp(argv[2],"POLYGON") == 0 || strcmp(argv[2],"polygon") == 0 ) nShapeType = SHPT_POLYGON; else if( strcmp(argv[2],"MULTIPOINT")==0 ||strcmp(argv[2],"multipoint")==0) nShapeType = SHPT_MULTIPOINT; else if( strcmp(argv[2],"POINTZ") == 0 || strcmp(argv[2],"pointz") == 0 ) nShapeType = SHPT_POINTZ; else if( strcmp(argv[2],"ARCZ") == 0 || strcmp(argv[2],"arcz") == 0 ) nShapeType = SHPT_ARCZ; else if( strcmp(argv[2],"POLYGONZ") == 0 || strcmp(argv[2],"polygonz") == 0) nShapeType = SHPT_POLYGONZ; else if( strcmp(argv[2],"MULTIPOINTZ") == 0 || strcmp(argv[2],"multipointz") == 0) nShapeType = SHPT_MULTIPOINTZ; else if( strcmp(argv[2],"POINTM") == 0 || strcmp(argv[2],"pointm") == 0 ) nShapeType = SHPT_POINTM; else if( strcmp(argv[2],"ARCM") == 0 || strcmp(argv[2],"arcm") == 0 ) nShapeType = SHPT_ARCM; else if( strcmp(argv[2],"POLYGONM") == 0 || strcmp(argv[2],"polygonm") == 0) nShapeType = SHPT_POLYGONM; else if( strcmp(argv[2],"MULTIPOINTM") == 0 || strcmp(argv[2],"multipointm") == 0 ) nShapeType = SHPT_MULTIPOINTM; else { printf( "Shape Type `%s' not recognised.\n", argv[2] ); exit( 2 ); } /* -------------------------------------------------------------------- */ /* Create the requested layer. */ /* -------------------------------------------------------------------- */ hSHP = SHPCreate( argv[1], nShapeType ); if( hSHP == NULL ) { printf( "Unable to create:%s\n", argv[1] ); exit( 3 ); } SHPClose( hSHP ); return 0; } shapelib-1.3.0/shpdump.c0000640042715500116100000002145211612705752014455 0ustar warmerdameng/****************************************************************************** * $Id: shpdump.c,v 1.18 2011-07-24 03:05:14 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for dumping contents of a shapefile to * the terminal in human readable form. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shpdump.c,v $ * Revision 1.18 2011-07-24 03:05:14 fwarmerdam * use %.15g for formatting coordiantes in shpdump * * Revision 1.17 2010-07-01 07:33:04 fwarmerdam * do not crash in shpdump if null object returned * * Revision 1.16 2010-07-01 07:27:13 fwarmerdam * white space formatting adjustments * * Revision 1.15 2006-01-26 15:07:32 fwarmerdam * add bMeasureIsUsed flag from Craig Bruce: Bug 1249 * * Revision 1.14 2005/02/11 17:17:46 fwarmerdam * added panPartStart[0] validation * * Revision 1.13 2004/09/26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.12 2004/01/27 18:05:35 fwarmerdam * Added the -ho (header only) switch. * * Revision 1.11 2004/01/09 16:39:49 fwarmerdam * include standard include files * * Revision 1.10 2002/04/10 16:59:29 warmerda * added -validate switch * * Revision 1.9 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.8 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.7 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.6 1998/12/03 15:48:48 warmerda * Added report of shapefile type, and total number of shapes. * * Revision 1.5 1998/11/09 20:57:36 warmerda * use SHPObject. * * Revision 1.4 1995/10/21 03:14:49 warmerda * Changed to use binary file access. * * Revision 1.3 1995/08/23 02:25:25 warmerda * Added support for bounds. * * Revision 1.2 1995/08/04 03:18:11 warmerda * Added header. * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: shpdump.c,v 1.18 2011-07-24 03:05:14 fwarmerdam Exp $") int main( int argc, char ** argv ) { SHPHandle hSHP; int nShapeType, nEntities, i, iPart, bValidate = 0,nInvalidCount=0; int bHeaderOnly = 0; const char *pszPlus; double adfMinBound[4], adfMaxBound[4]; if( argc > 1 && strcmp(argv[1],"-validate") == 0 ) { bValidate = 1; argv++; argc--; } if( argc > 1 && strcmp(argv[1],"-ho") == 0 ) { bHeaderOnly = 1; argv++; argc--; } /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc != 2 ) { printf( "shpdump [-validate] [-ho] shp_file\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( argv[1], "rb" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", argv[1] ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Print out the file bounds. */ /* -------------------------------------------------------------------- */ SHPGetInfo( hSHP, &nEntities, &nShapeType, adfMinBound, adfMaxBound ); printf( "Shapefile Type: %s # of Shapes: %d\n\n", SHPTypeName( nShapeType ), nEntities ); printf( "File Bounds: (%.15g,%.15g,%.15g,%.15g)\n" " to (%.15g,%.15g,%.15g,%.15g)\n", adfMinBound[0], adfMinBound[1], adfMinBound[2], adfMinBound[3], adfMaxBound[0], adfMaxBound[1], adfMaxBound[2], adfMaxBound[3] ); /* -------------------------------------------------------------------- */ /* Skim over the list of shapes, printing all the vertices. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nEntities && !bHeaderOnly; i++ ) { int j; SHPObject *psShape; psShape = SHPReadObject( hSHP, i ); if( psShape == NULL ) { fprintf( stderr, "Unable to read shape %d, terminating object reading.\n", i ); break; } if( psShape->bMeasureIsUsed ) printf( "\nShape:%d (%s) nVertices=%d, nParts=%d\n" " Bounds:(%.15g,%.15g, %.15g, %.15g)\n" " to (%.15g,%.15g, %.15g, %.15g)\n", i, SHPTypeName(psShape->nSHPType), psShape->nVertices, psShape->nParts, psShape->dfXMin, psShape->dfYMin, psShape->dfZMin, psShape->dfMMin, psShape->dfXMax, psShape->dfYMax, psShape->dfZMax, psShape->dfMMax ); else printf( "\nShape:%d (%s) nVertices=%d, nParts=%d\n" " Bounds:(%.15g,%.15g, %.15g)\n" " to (%.15g,%.15g, %.15g)\n", i, SHPTypeName(psShape->nSHPType), psShape->nVertices, psShape->nParts, psShape->dfXMin, psShape->dfYMin, psShape->dfZMin, psShape->dfXMax, psShape->dfYMax, psShape->dfZMax ); if( psShape->nParts > 0 && psShape->panPartStart[0] != 0 ) { fprintf( stderr, "panPartStart[0] = %d, not zero as expected.\n", psShape->panPartStart[0] ); } for( j = 0, iPart = 1; j < psShape->nVertices; j++ ) { const char *pszPartType = ""; if( j == 0 && psShape->nParts > 0 ) pszPartType = SHPPartTypeName( psShape->panPartType[0] ); if( iPart < psShape->nParts && psShape->panPartStart[iPart] == j ) { pszPartType = SHPPartTypeName( psShape->panPartType[iPart] ); iPart++; pszPlus = "+"; } else pszPlus = " "; if( psShape->bMeasureIsUsed ) printf(" %s (%.15g,%.15g, %.15g, %.15g) %s \n", pszPlus, psShape->padfX[j], psShape->padfY[j], psShape->padfZ[j], psShape->padfM[j], pszPartType ); else printf(" %s (%.15g,%.15g, %.15g) %s \n", pszPlus, psShape->padfX[j], psShape->padfY[j], psShape->padfZ[j], pszPartType ); } if( bValidate ) { int nAltered = SHPRewindObject( hSHP, psShape ); if( nAltered > 0 ) { printf( " %d rings wound in the wrong direction.\n", nAltered ); nInvalidCount++; } } SHPDestroyObject( psShape ); } SHPClose( hSHP ); if( bValidate ) { printf( "%d object has invalid ring orderings.\n", nInvalidCount ); } #ifdef USE_DBMALLOC malloc_dump(2); #endif exit( 0 ); } shapelib-1.3.0/dbfdump.c0000640042715500116100000002370110444644614014416 0ustar warmerdameng/****************************************************************************** * $Id: dbfdump.c,v 1.12 2006-06-17 00:15:08 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for dumping .dbf files to the terminal. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: dbfdump.c,v $ * Revision 1.12 2006-06-17 00:15:08 fwarmerdam * Free panWidth for better memory testing. * * Revision 1.11 2006/02/15 01:11:27 fwarmerdam * added reporting of native type * * Revision 1.10 2004/09/26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.9 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.8 2001/05/31 18:15:40 warmerda * Added support for NULL fields in DBF files * * Revision 1.7 2000/09/20 13:13:55 warmerda * added break after default: * * Revision 1.6 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.5 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.4 1998/12/31 15:30:13 warmerda * Added -m, -r, and -h commandline options. * * Revision 1.3 1995/10/21 03:15:01 warmerda * Changed to use binary file access. * * Revision 1.2 1995/08/04 03:16:22 warmerda * Added header. * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: dbfdump.c,v 1.12 2006-06-17 00:15:08 fwarmerdam Exp $") int main( int argc, char ** argv ) { DBFHandle hDBF; int *panWidth, i, iRecord; char szFormat[32], *pszFilename = NULL; int nWidth, nDecimals; int bHeader = 0; int bRaw = 0; int bMultiLine = 0; char szTitle[12]; /* -------------------------------------------------------------------- */ /* Handle arguments. */ /* -------------------------------------------------------------------- */ for( i = 1; i < argc; i++ ) { if( strcmp(argv[i],"-h") == 0 ) bHeader = 1; else if( strcmp(argv[i],"-r") == 0 ) bRaw = 1; else if( strcmp(argv[i],"-m") == 0 ) bMultiLine = 1; else pszFilename = argv[i]; } /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( pszFilename == NULL ) { printf( "dbfdump [-h] [-r] [-m] xbase_file\n" ); printf( " -h: Write header info (field descriptions)\n" ); printf( " -r: Write raw field info, numeric values not reformatted\n" ); printf( " -m: Multiline, one line per field.\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Open the file. */ /* -------------------------------------------------------------------- */ hDBF = DBFOpen( pszFilename, "rb" ); if( hDBF == NULL ) { printf( "DBFOpen(%s,\"r\") failed.\n", argv[1] ); exit( 2 ); } /* -------------------------------------------------------------------- */ /* If there is no data in this file let the user know. */ /* -------------------------------------------------------------------- */ if( DBFGetFieldCount(hDBF) == 0 ) { printf( "There are no fields in this table!\n" ); exit( 3 ); } /* -------------------------------------------------------------------- */ /* Dump header definitions. */ /* -------------------------------------------------------------------- */ if( bHeader ) { for( i = 0; i < DBFGetFieldCount(hDBF); i++ ) { DBFFieldType eType; const char *pszTypeName; char chNativeType; chNativeType = DBFGetNativeFieldType( hDBF, i ); eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals ); if( eType == FTString ) pszTypeName = "String"; else if( eType == FTInteger ) pszTypeName = "Integer"; else if( eType == FTDouble ) pszTypeName = "Double"; else if( eType == FTInvalid ) pszTypeName = "Invalid"; printf( "Field %d: Type=%c/%s, Title=`%s', Width=%d, Decimals=%d\n", i, chNativeType, pszTypeName, szTitle, nWidth, nDecimals ); } } /* -------------------------------------------------------------------- */ /* Compute offsets to use when printing each of the field */ /* values. We make each field as wide as the field title+1, or */ /* the field value + 1. */ /* -------------------------------------------------------------------- */ panWidth = (int *) malloc( DBFGetFieldCount( hDBF ) * sizeof(int) ); for( i = 0; i < DBFGetFieldCount(hDBF) && !bMultiLine; i++ ) { DBFFieldType eType; eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals ); if( (int) strlen(szTitle) > nWidth ) panWidth[i] = strlen(szTitle); else panWidth[i] = nWidth; if( eType == FTString ) sprintf( szFormat, "%%-%ds ", panWidth[i] ); else sprintf( szFormat, "%%%ds ", panWidth[i] ); printf( szFormat, szTitle ); } printf( "\n" ); /* -------------------------------------------------------------------- */ /* Read all the records */ /* -------------------------------------------------------------------- */ for( iRecord = 0; iRecord < DBFGetRecordCount(hDBF); iRecord++ ) { if( bMultiLine ) printf( "Record: %d\n", iRecord ); for( i = 0; i < DBFGetFieldCount(hDBF); i++ ) { DBFFieldType eType; eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals ); if( bMultiLine ) { printf( "%s: ", szTitle ); } /* -------------------------------------------------------------------- */ /* Print the record according to the type and formatting */ /* information implicit in the DBF field description. */ /* -------------------------------------------------------------------- */ if( !bRaw ) { if( DBFIsAttributeNULL( hDBF, iRecord, i ) ) { if( eType == FTString ) sprintf( szFormat, "%%-%ds", nWidth ); else sprintf( szFormat, "%%%ds", nWidth ); printf( szFormat, "(NULL)" ); } else { switch( eType ) { case FTString: sprintf( szFormat, "%%-%ds", nWidth ); printf( szFormat, DBFReadStringAttribute( hDBF, iRecord, i ) ); break; case FTInteger: sprintf( szFormat, "%%%dd", nWidth ); printf( szFormat, DBFReadIntegerAttribute( hDBF, iRecord, i ) ); break; case FTDouble: sprintf( szFormat, "%%%d.%dlf", nWidth, nDecimals ); printf( szFormat, DBFReadDoubleAttribute( hDBF, iRecord, i ) ); break; default: break; } } } /* -------------------------------------------------------------------- */ /* Just dump in raw form (as formatted in the file). */ /* -------------------------------------------------------------------- */ else { sprintf( szFormat, "%%-%ds", nWidth ); printf( szFormat, DBFReadStringAttribute( hDBF, iRecord, i ) ); } /* -------------------------------------------------------------------- */ /* Write out any extra spaces required to pad out the field */ /* width. */ /* -------------------------------------------------------------------- */ if( !bMultiLine ) { sprintf( szFormat, "%%%ds", panWidth[i] - nWidth + 1 ); printf( szFormat, "" ); } if( bMultiLine ) printf( "\n" ); fflush( stdout ); } printf( "\n" ); } DBFClose( hDBF ); free( panWidth ); return( 0 ); } shapelib-1.3.0/ChangeLog0000640042715500116100000003401111710611206014363 0ustar warmerdameng2012-01-27 Frank Warmerdam * shptree.c: optimize quadtree generation (gdal #4472) 2012-01-24 Frank Warmerdam * shpopen.c: fix memory leaks on failure to open .shp file. 2011-12-11 Frank Warmerdam * shptree.c,h: Use SAHooks for .qix access (gdal #3365) 2011-09-14 Frank Warmerdam * shpopen.c: fix missing cast (#2344) 2011-07-24 * shpopen.c, dbfopen.c, shptree.c, shapefil.h: Minimize use of CPL services in favor of SAHooks.Error(). * Makefile: Remove all the shared library building stuff, it is just too half assed, and results in all sorts of bug reports and complaints. Instead just install a static libshp.a. 2011-07-23 * Makefile: build shpdumptree as part of all target (#1648). * shpopen.c: fix memory leaks in error cases (#2061) * contrib/*.c: Include stdlib.h and strings.h (#2146) * shpdump.c: change to use %.15g for coordinate reporting. (#2277) 2011-05-13 Frank Warmerdam * dbfopen.c, shapelib.h: Add functions to reorder and alter field definitions. DBFReorderFields() and DBFAlterFields(). 2011-05-07 Frank Warmerdam * dbfopen.c: Ensure pending record is flushed when adding a native field (gdal #4073). 2011-04-16 Frank Warmerdam * shapefil.h: avoid warnings with SHP_CVSID on gcc. 2010-12-06 Frank Warmerdam * dbfopen.c: fix read past end of init data fetching code page http://bugzilla.maptools.org/show_bug.cgi?id=2276 2010-07-01 Frank Warmerdam * shpopen.c: do not error out on a shape with zero vertices. * shpdump.c: do not crash if null shape returned by read object. 2010-06-29 Frank Warmerdam * shptree.c: fix sign of Z and M comparisons in SHPCheckObjectContained. (http://bugzilla.maptools.org/show_bug.cgi?id=2223) 2010-01-28 Frank Warmerdam * shpopen.c/shapefil.h: Handle the .shp file length limits more gracefully. (http://trac.osgeo.org/gdal/ticket/3236) * shpopen.c: Improve the numerical accurancy of algorithms in SHPRewind() (http://trac.osgeo.org/gdal/ticket/3363). 2010-01-16 Frank Warmerdam * shpopen.c: support passing in zero/nulls to create an empty SHPObject: http://bugzilla.maptools.org/show_bug.cgi?id=2148 2009-10-29 Frank Warmerdam * dbfopen.c: avoid crash risk for truncated files. http://trac.osgeo.org/gdal/ticket/3093 2009-09-17 Bram de Greve * shpopen.c: on Win32, define snprintf as alias to _snprintf 2008-11-12 Frank Warmerdam * shptree.c: improve safety in face of buggy .shp file. http://trac.osgeo.org/gdal/ticket/2610 * dbfopen.c: DBFCreateField() can now also operate on files with records, c/o Martin Dobias. https://trac.osgeo.org/gdal/ticket/2672 2008-11-11 Frank Warmerdam * dbfopen.c: Introduce DBFDeleteField() function from Martin Dobias. http://trac.osgeo.org/gdal/ticket/2671 2008-03-14 Frank Warmerdam * Correct crash on buggy geometries (Even Rouault). http://trac.osgeo.org/gdal/ticket/2218 2008-01-16 Bram de Greve * shapefil.h, safileio.c: add file hooks that accept UTF-8 encoded filenames on some platforms. Use SASetupUtf8Hooks to setup the hooks and check SHPAPI_UTF8_HOOKS for its availability. Currently, this is only available on the Windows platform that decodes the UTF-8 filenames to wide character strings and feed them to _wfopen and _wremove. 2008-01-10 Frank Warmerdam * shapefil.h: Avoid _ prefix on #defines. http://bugzilla.maptools.org/show_bug.cgi?id=1840 2008-01-03 Bram de Greve * dbfopen.c: in DBFCreate, use default code page LDID/87 (= 0x57, ANSI) instead of LDID/3. This seems to be the same as what ESRI would be doing by default. 2007-12-30 Frank Warmerdam * shpadd.c/shpcreate.c: Add support for z and m files. * Massive overhaul to use hooks for file io, etc. 2007-12-18 Bram de Greve * dbfopen.c/shapefil.h/safileio.c: create hook for client specific atof http://bugzilla.maptools.org/show_bug.cgi?id=1615 * dbfopen.c: check for NULL handle before closing cpCPG file, and close after reading. 2007-12-15 Bram de Greve * dbfopen.c/shapefil.h/safileio.c: read the Code Page information from the DBF file, and exports this information as a string through the DBFGetCodePage function. This is either the number from the LDID header field ("LDID/") or as the content of an accompanying .CPG file. When creating a DBF file, the code can be set using DBFCreateEx. 2007-12-12 Bram de Greve * dbfopen.c: check for NULL handle in DBFClose. 2007-11-21 Frank Warmerdam * shpopen.c/shapefil.h: Don't keep .shx file open in read-only mode. http://trac.osgeo.org/gdal/ticket/1956 2007-11-14 Frank Warmerdam * shpopen.c: checks after mallocs to detect for corrupted/voluntary broken shapefiles. http://trac.osgeo.org/gdal/ticket/1991 2007-09-03 Frank Warmerdam * shpgeo.c: Fixed SHPDimension() (missing breaks) in shpgeo.c. Fix contributed by Andrea Peri. * dbfopen.c: Move the static dDoubleField return buffer into DBFInfo structure to avoid multithreaded risks. * dbfopen.c: Simplify DBFReadTuple() to avoid use of static tuple. Note that this means DBFReadTuple() results are only valid till the next record is read for any reason. 2007-06-21 Frank Warmerdam * shpopen.c: Fix for SHPRewind() for "contact at one vertex" cases in rings. http://trac.osgeo.org/gdal/ticket/976 2006-11-06 Frank Warmerdam * contrib/shpgeo.c: Modified SHPProject to use pj_transform() so it works for datums and stuff. Submitted by Steffen Macke. 2006-09-04 Frank Warmerdam * shpeopen.c: (MLoskot) Added stronger test of Shapefile reading failures, e.g. truncated files. The problem was discovered by Tim Sutton and reported here: https://svn.qgis.org/trac/ticket/200 2006-06-17 Frank Warmerdam * dbfopen.c: use calloc() for DBFInfo in DBFCreate() to ensure all fields initialized to zero if not otherwise mentioned. * dbfopen.c: Don't allow creation of string fields with width larger than 255 per http://bugzilla.maptools.org/show_bug.cgi?id=1434 2006-06-16 Frank Warmerdam * dbfopen.c: Don't treat decimals value as high order field length for strings, as it causes serious bugs in some cases such as http://bugzilla.remotesensing.org/show_bug.cgi?id=1202 * dbfopen.c: Made static field buffer in DBFReadAttribute() into a field in the DBFInfo structure to avoid multi-threading problems. 2006-03-29 Frank Warmerdam * dbfopen.c: Fixed bug in DBFCloneEmpty() (treating pachFieldType as an array of int). 2006-02-08 Frank Warmerdam * dbfopen.c: Changed to put spaces into string fields that are NULL as per http://bugzilla.maptools.org/show_bug.cgi?id=316. 2006-01-26 Frank Warmerdam * shpopen.c, shapefil.h, shpdump.c: Added bMeasureIsUsed support as per http://bugzilla.maptools.org/show_bug.cgi?id=1249 2006-01-04 Frank Warmerdam * dbfopen.c/shapefil.h: Added functions to check if dbf record is deleted, and to mark it as deleted. 2005-02-11 Frank Warmerdam * shpopen.c: Check panPartStart[0] is 0 in SHPCreateObject(). * Fixed bug 305 in DBFCloneEmpty() - header length problem. * Make the pszStringField buffer for DBFReadAttribute() static char [256] as per bug 306. 2004-09-15 Frank Warmerdam * dbfopen.c: treat all blanks as NULL in DBFIsAttributeNULL(). 2004-06-23 Frank Warmerdam * contrib/shpsort.c: added new contribute program from Eric Miller. 2003-04-07 Frank Warmerdam * Issue 1.2.10 Release. 2003-03-10 Frank Warmerdam * dbfopen.c: modified DBFWriteAttribute call so that it returns FALSE if it has to truncate the input value. 2003-01-28 Frank Warmerdam * shptree.c: avoid build warnings. 2002-05-07 Frank Warmerdam * dbfopen.c: Added DBFWriteAttributeDirectly() from the AVCE00 distribution to simplify AVC integration in GDAL. * shptree.c: added use of qsort() in place of bubble sort as submitted by Bernhard Herzog. 2002-04-10 Frank Warmerdam * shpopen.c: Added SHPRewindObject() to correct ring winding. * shprewind.c: New utility program. 2002-03-12 Frank Warmerdam * shapelib.def: added DBFWriteNULLAttribute. 2002-01-17 Frank Warmerdam * contrib/ShapeFileII.pas: Contributed Delphi Pascal interface to Shapelib. 2002-01-15 Frank Warmerdam * shapelib.h: Added support for SHAPELIB_DLLEXPORT macro, and write up material attempting to explain the use of SHPAPI_CALL macros. * dbfopen.c: Compute nHeaderLength in DBFCloneEmpty() instead of copying it from the source file so we don't have quirks when copying from files with extra bytes of spacers in the header that don't themselves get copied properly. 2001-12-07 Frank Warmerdam * shpopen.c: Fix fclose() of SHX file if SHX file fails to open. Should be closing SHP file. Reported by Ben Discoe. 2001-11-28 Frank Warmerdam * dbfopen.c: two fixes for compiler warnings as suggested by Richard Hash. 2001-11-01 Frank Warmerdam * shpopen.c/shapefil.h: Move record buffer into SHPInfo so that different threads can safely access separate files. Other threading issues may remain. 2001-08-28 Frank Warmerdam * Issue Shapelib 1.2.9 * shputils.c: DBFAddField() call should check for -1 return value for failure. 2001-07-03 Frank Warmerdam * shpopen.c: cleanup better if SHX missing, provided by Riccardo Cohen. 2001-06-21 Frank Warmerdam * dbfopen.c: Fixed NULL support with patches from Jim Matthews. * shpopen.c: Be more careful of establishing initial file bounds in face of possible NULL shapes. 2001-06-01 Frank Warmerdam * dbfopen.c: ensure binary mode open. 2001-05-31 Frank Warmerdam * shpopen.c: Add support for writing null shapes. * dbfopen.c: added DBFGetFieldIndex(), contributed by Jim Matthews. * dbfopen.c/shapefil.h/dbf_api.h: added support for NULL fields in .dbf files. 2001-05-28 Frank Warmerdam * shpopen.c: add some checking on the record count to ensure it is reasonable. 2001-05-23 Frank Warmerdam * shapefile.h, shpopen.c, dbfopen.c, shptree.c: added the SHPAPI_CALL macro to allow compilation with _stdcall conventions. 2001-02-06 Frank Warmerdam * Fixed a few memory leaks when SHPOpen() fails. 2000-12-05 Frank Warmerdam * Fix from Craig Bruce (Cubewerx) for DBFReadAttribute() for the white space trimming code to avoid reading outside allocated memory. 2000-11-02 Frank Warmerdam * Checked in upgraded shputils.c from Bill Miller. 2000-10-05 Frank Warmerdam * Fixed DBFWriteAttribute() to ensure we can't overwrite the end of the szSField buffer even if the width is set large. Bug report by Kirk Benell . 2000-09-25 Frank Warmerdam * Added DBFGetNativeFieldType() (contributed by Daniel) to dbfopen.c. 2000-07-18 Frank Warmerdam * added better enforcement of -1 for append in SHPWriteObject(). 2000-07-07 Frank Warmerdam * Added stdlib.h and string.h where needed, and removed lots of unused variables, mainly from example mainlines at the suggestion of Bill Hughes. 2000-05-24 Frank Warmerdam * Added logic to shpadd to grow vertex lists at the suggestion of Santiago Nullo . 2000-05-23 Frank Warmerdam * Added checks in dbfopen.c on return result of fseek() and fread(). * Avoid crashing in DBReadIntegerAttribute() or DBFReadDoubleAttribte() if the field or record are out of range. 2000-03-28 Frank Warmerdam * Release as 1.2.8. * Incorporated a -version-info fix and added mkinstalldirs from Jan. 2000-03-17 Frank Warmerdam * Added shared library hack to Makefile. * Fixed up test scripts to look in ./ for executables. Wed Feb 16 11:20:29 2000 Frank Warmerdam * Release 1.2.7. * Modified SHPReadObject() so that will return NULL (type 0) shapes in a sort of sensible way. Wed Dec 15 08:49:53 1999 Frank Warmerdam * Fixed record size written at beginning of records in .shp file. It was 4 bytes to long (thanks to Mikko Syrja of 3D-system Oy) * Use atof() instead of sscanf() in dbfopen.c, and add stdlib.h. Mon Dec 13 12:29:01 1999 Frank Warmerdam * Added support for uppercase .DBF extention c/o Dennis Christopher Fri Nov 5 09:12:31 1999 Frank Warmerdam * Updated license headers to include the option of use of the code under the LGPL. 1999-09-15 * Added shapelib.dll target to makefile.vc. Mon May 10 23:19:42 1999 Frank Warmerdam * Added candrsn's improvements to extension handling in dbfopen.c * Added ``raw tuple'' api to dbfopen.c, still not in dbf_api.html. From candrsn. Tue May 4 11:04:31 1999 Frank Warmerdam * Prepare 1.2.5 release. * Added support for 'F' fields. shapelib-1.3.0/shptree.c0000640042715500116100000012756111710611206014444 0ustar warmerdameng/****************************************************************************** * $Id: shptree.c,v 1.17 2012-01-27 21:09:26 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Implementation of quadtree building and searching functions. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shptree.c,v $ * Revision 1.17 2012-01-27 21:09:26 fwarmerdam * optimize .qix output (gdal #4472) * * Revision 1.16 2011-12-11 22:26:46 fwarmerdam * upgrade .qix access code to use SAHooks (gdal #3365) * * Revision 1.15 2011-07-24 05:59:25 fwarmerdam * minimize use of CPLError in favor of SAHooks.Error() * * Revision 1.14 2010-08-27 23:43:27 fwarmerdam * add SHPAPI_CALL attribute in code * * Revision 1.13 2010-06-29 05:50:15 fwarmerdam * fix sign of Z/M comparisons in SHPCheckObjectContained (#2223) * * Revision 1.12 2008-11-12 15:39:50 fwarmerdam * improve safety in face of buggy .shp file. * * Revision 1.11 2007/10/27 03:31:14 fwarmerdam * limit default depth of tree to 12 levels (gdal ticket #1594) * * Revision 1.10 2005/01/03 22:30:13 fwarmerdam * added support for saved quadtrees * * Revision 1.9 2003/01/28 15:53:41 warmerda * Avoid build warnings. * * Revision 1.8 2002/05/07 13:07:45 warmerda * use qsort() - patch from Bernhard Herzog * * Revision 1.7 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.6 2001/05/23 13:36:52 warmerda * added use of SHPAPI_CALL * * Revision 1.5 1999/11/05 14:12:05 warmerda * updated license terms * * Revision 1.4 1999/06/02 18:24:21 warmerda * added trimming code * * Revision 1.3 1999/06/02 17:56:12 warmerda * added quad'' subnode support for trees * * Revision 1.2 1999/05/18 19:11:11 warmerda * Added example searching capability * * Revision 1.1 1999/05/18 17:49:20 warmerda * New * */ #include "shapefil.h" #include #include #include #include #ifdef USE_CPL #include "cpl_error.h" #endif SHP_CVSID("$Id: shptree.c,v 1.17 2012-01-27 21:09:26 fwarmerdam Exp $") #ifndef TRUE # define TRUE 1 # define FALSE 0 #endif static int bBigEndian = 0; /* -------------------------------------------------------------------- */ /* If the following is 0.5, nodes will be split in half. If it */ /* is 0.6 then each subnode will contain 60% of the parent */ /* node, with 20% representing overlap. This can be help to */ /* prevent small objects on a boundary from shifting too high */ /* up the tree. */ /* -------------------------------------------------------------------- */ #define SHP_SPLIT_RATIO 0.55 /************************************************************************/ /* SfRealloc() */ /* */ /* A realloc cover function that will access a NULL pointer as */ /* a valid input. */ /************************************************************************/ static void * SfRealloc( void * pMem, int nNewSize ) { if( pMem == NULL ) return( (void *) malloc(nNewSize) ); else return( (void *) realloc(pMem,nNewSize) ); } /************************************************************************/ /* SHPTreeNodeInit() */ /* */ /* Initialize a tree node. */ /************************************************************************/ static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin, double * padfBoundsMax ) { SHPTreeNode *psTreeNode; psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode)); if( NULL == psTreeNode ) return NULL; psTreeNode->nShapeCount = 0; psTreeNode->panShapeIds = NULL; psTreeNode->papsShapeObj = NULL; psTreeNode->nSubNodes = 0; if( padfBoundsMin != NULL ) memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 ); if( padfBoundsMax != NULL ) memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 ); return psTreeNode; } /************************************************************************/ /* SHPCreateTree() */ /************************************************************************/ SHPTree SHPAPI_CALL1(*) SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth, double *padfBoundsMin, double *padfBoundsMax ) { SHPTree *psTree; if( padfBoundsMin == NULL && hSHP == NULL ) return NULL; /* -------------------------------------------------------------------- */ /* Allocate the tree object */ /* -------------------------------------------------------------------- */ psTree = (SHPTree *) malloc(sizeof(SHPTree)); if( NULL == psTree ) { return NULL; } psTree->hSHP = hSHP; psTree->nMaxDepth = nMaxDepth; psTree->nDimension = nDimension; psTree->nTotalCount = 0; /* -------------------------------------------------------------------- */ /* If no max depth was defined, try to select a reasonable one */ /* that implies approximately 8 shapes per node. */ /* -------------------------------------------------------------------- */ if( psTree->nMaxDepth == 0 && hSHP != NULL ) { int nMaxNodeCount = 1; int nShapeCount; SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL ); while( nMaxNodeCount*4 < nShapeCount ) { psTree->nMaxDepth += 1; nMaxNodeCount = nMaxNodeCount * 2; } #ifdef USE_CPL CPLDebug( "Shape", "Estimated spatial index tree depth: %d", psTree->nMaxDepth ); #endif /* NOTE: Due to problems with memory allocation for deep trees, * automatically estimated depth is limited up to 12 levels. * See Ticket #1594 for detailed discussion. */ if( psTree->nMaxDepth > MAX_DEFAULT_TREE_DEPTH ) { psTree->nMaxDepth = MAX_DEFAULT_TREE_DEPTH; #ifdef USE_CPL CPLDebug( "Shape", "Falling back to max number of allowed index tree levels (%d).", MAX_DEFAULT_TREE_DEPTH ); #endif } } /* -------------------------------------------------------------------- */ /* Allocate the root node. */ /* -------------------------------------------------------------------- */ psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax ); if( NULL == psTree->psRoot ) { return NULL; } /* -------------------------------------------------------------------- */ /* Assign the bounds to the root node. If none are passed in, */ /* use the bounds of the provided file otherwise the create */ /* function will have already set the bounds. */ /* -------------------------------------------------------------------- */ assert( NULL != psTree ); assert( NULL != psTree->psRoot ); if( padfBoundsMin == NULL ) { SHPGetInfo( hSHP, NULL, NULL, psTree->psRoot->adfBoundsMin, psTree->psRoot->adfBoundsMax ); } /* -------------------------------------------------------------------- */ /* If we have a file, insert all it's shapes into the tree. */ /* -------------------------------------------------------------------- */ if( hSHP != NULL ) { int iShape, nShapeCount; SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL ); for( iShape = 0; iShape < nShapeCount; iShape++ ) { SHPObject *psShape; psShape = SHPReadObject( hSHP, iShape ); if( psShape != NULL ) { SHPTreeAddShapeId( psTree, psShape ); SHPDestroyObject( psShape ); } } } return psTree; } /************************************************************************/ /* SHPDestroyTreeNode() */ /************************************************************************/ static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode ) { int i; assert( NULL != psTreeNode ); for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( psTreeNode->apsSubNode[i] != NULL ) SHPDestroyTreeNode( psTreeNode->apsSubNode[i] ); } if( psTreeNode->panShapeIds != NULL ) free( psTreeNode->panShapeIds ); if( psTreeNode->papsShapeObj != NULL ) { for( i = 0; i < psTreeNode->nShapeCount; i++ ) { if( psTreeNode->papsShapeObj[i] != NULL ) SHPDestroyObject( psTreeNode->papsShapeObj[i] ); } free( psTreeNode->papsShapeObj ); } free( psTreeNode ); } /************************************************************************/ /* SHPDestroyTree() */ /************************************************************************/ void SHPAPI_CALL SHPDestroyTree( SHPTree * psTree ) { SHPDestroyTreeNode( psTree->psRoot ); free( psTree ); } /************************************************************************/ /* SHPCheckBoundsOverlap() */ /* */ /* Do the given boxes overlap at all? */ /************************************************************************/ int SHPAPI_CALL SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max, double * padfBox2Min, double * padfBox2Max, int nDimension ) { int iDim; for( iDim = 0; iDim < nDimension; iDim++ ) { if( padfBox2Max[iDim] < padfBox1Min[iDim] ) return FALSE; if( padfBox1Max[iDim] < padfBox2Min[iDim] ) return FALSE; } return TRUE; } /************************************************************************/ /* SHPCheckObjectContained() */ /* */ /* Does the given shape fit within the indicated extents? */ /************************************************************************/ static int SHPCheckObjectContained( SHPObject * psObject, int nDimension, double * padfBoundsMin, double * padfBoundsMax ) { if( psObject->dfXMin < padfBoundsMin[0] || psObject->dfXMax > padfBoundsMax[0] ) return FALSE; if( psObject->dfYMin < padfBoundsMin[1] || psObject->dfYMax > padfBoundsMax[1] ) return FALSE; if( nDimension == 2 ) return TRUE; if( psObject->dfZMin < padfBoundsMin[2] || psObject->dfZMax > padfBoundsMax[2] ) return FALSE; if( nDimension == 3 ) return TRUE; if( psObject->dfMMin < padfBoundsMin[3] || psObject->dfMMax > padfBoundsMax[3] ) return FALSE; return TRUE; } /************************************************************************/ /* SHPTreeSplitBounds() */ /* */ /* Split a region into two subregion evenly, cutting along the */ /* longest dimension. */ /************************************************************************/ void SHPAPI_CALL SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn, double *padfBoundsMin1, double * padfBoundsMax1, double *padfBoundsMin2, double * padfBoundsMax2 ) { /* -------------------------------------------------------------------- */ /* The output bounds will be very similar to the input bounds, */ /* so just copy over to start. */ /* -------------------------------------------------------------------- */ memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 ); memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 ); memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 ); memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 ); /* -------------------------------------------------------------------- */ /* Split in X direction. */ /* -------------------------------------------------------------------- */ if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0]) > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) ) { double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0]; padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO; padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO; } /* -------------------------------------------------------------------- */ /* Otherwise split in Y direction. */ /* -------------------------------------------------------------------- */ else { double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1]; padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO; padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO; } } /************************************************************************/ /* SHPTreeNodeAddShapeId() */ /************************************************************************/ static int SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject, int nMaxDepth, int nDimension ) { int i; /* -------------------------------------------------------------------- */ /* If there are subnodes, then consider wiether this object */ /* will fit in them. */ /* -------------------------------------------------------------------- */ if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 ) { for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( SHPCheckObjectContained(psObject, nDimension, psTreeNode->apsSubNode[i]->adfBoundsMin, psTreeNode->apsSubNode[i]->adfBoundsMax)) { return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i], psObject, nMaxDepth-1, nDimension ); } } } /* -------------------------------------------------------------------- */ /* Otherwise, consider creating four subnodes if could fit into */ /* them, and adding to the appropriate subnode. */ /* -------------------------------------------------------------------- */ #if MAX_SUBNODE == 4 else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 ) { double adfBoundsMinH1[4], adfBoundsMaxH1[4]; double adfBoundsMinH2[4], adfBoundsMaxH2[4]; double adfBoundsMin1[4], adfBoundsMax1[4]; double adfBoundsMin2[4], adfBoundsMax2[4]; double adfBoundsMin3[4], adfBoundsMax3[4]; double adfBoundsMin4[4], adfBoundsMax4[4]; SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax, adfBoundsMinH1, adfBoundsMaxH1, adfBoundsMinH2, adfBoundsMaxH2 ); SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1, adfBoundsMin1, adfBoundsMax1, adfBoundsMin2, adfBoundsMax2 ); SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2, adfBoundsMin3, adfBoundsMax3, adfBoundsMin4, adfBoundsMax4 ); if( SHPCheckObjectContained(psObject, nDimension, adfBoundsMin1, adfBoundsMax1) || SHPCheckObjectContained(psObject, nDimension, adfBoundsMin2, adfBoundsMax2) || SHPCheckObjectContained(psObject, nDimension, adfBoundsMin3, adfBoundsMax3) || SHPCheckObjectContained(psObject, nDimension, adfBoundsMin4, adfBoundsMax4) ) { psTreeNode->nSubNodes = 4; psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, adfBoundsMax1 ); psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, adfBoundsMax2 ); psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3, adfBoundsMax3 ); psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4, adfBoundsMax4 ); /* recurse back on this node now that it has subnodes */ return( SHPTreeNodeAddShapeId( psTreeNode, psObject, nMaxDepth, nDimension ) ); } } #endif /* MAX_SUBNODE == 4 */ /* -------------------------------------------------------------------- */ /* Otherwise, consider creating two subnodes if could fit into */ /* them, and adding to the appropriate subnode. */ /* -------------------------------------------------------------------- */ #if MAX_SUBNODE == 2 else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 ) { double adfBoundsMin1[4], adfBoundsMax1[4]; double adfBoundsMin2[4], adfBoundsMax2[4]; SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax, adfBoundsMin1, adfBoundsMax1, adfBoundsMin2, adfBoundsMax2 ); if( SHPCheckObjectContained(psObject, nDimension, adfBoundsMin1, adfBoundsMax1)) { psTreeNode->nSubNodes = 2; psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, adfBoundsMax1 ); psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, adfBoundsMax2 ); return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject, nMaxDepth - 1, nDimension ) ); } else if( SHPCheckObjectContained(psObject, nDimension, adfBoundsMin2, adfBoundsMax2) ) { psTreeNode->nSubNodes = 2; psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1, adfBoundsMax1 ); psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2, adfBoundsMax2 ); return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject, nMaxDepth - 1, nDimension ) ); } } #endif /* MAX_SUBNODE == 2 */ /* -------------------------------------------------------------------- */ /* If none of that worked, just add it to this nodes list. */ /* -------------------------------------------------------------------- */ psTreeNode->nShapeCount++; psTreeNode->panShapeIds = (int *) SfRealloc( psTreeNode->panShapeIds, sizeof(int) * psTreeNode->nShapeCount ); psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId; if( psTreeNode->papsShapeObj != NULL ) { psTreeNode->papsShapeObj = (SHPObject **) SfRealloc( psTreeNode->papsShapeObj, sizeof(void *) * psTreeNode->nShapeCount ); psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL; } return TRUE; } /************************************************************************/ /* SHPTreeAddShapeId() */ /* */ /* Add a shape to the tree, but don't keep a pointer to the */ /* object data, just keep the shapeid. */ /************************************************************************/ int SHPAPI_CALL SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject ) { psTree->nTotalCount++; return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject, psTree->nMaxDepth, psTree->nDimension ) ); } /************************************************************************/ /* SHPTreeCollectShapesIds() */ /* */ /* Work function implementing SHPTreeFindLikelyShapes() on a */ /* tree node by tree node basis. */ /************************************************************************/ void SHPAPI_CALL SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode, double * padfBoundsMin, double * padfBoundsMax, int * pnShapeCount, int * pnMaxShapes, int ** ppanShapeList ) { int i; /* -------------------------------------------------------------------- */ /* Does this node overlap the area of interest at all? If not, */ /* return without adding to the list at all. */ /* -------------------------------------------------------------------- */ if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax, padfBoundsMin, padfBoundsMax, hTree->nDimension ) ) return; /* -------------------------------------------------------------------- */ /* Grow the list to hold the shapes on this node. */ /* -------------------------------------------------------------------- */ if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes ) { *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20; *ppanShapeList = (int *) SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes); } /* -------------------------------------------------------------------- */ /* Add the local nodes shapeids to the list. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nShapeCount; i++ ) { (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i]; } /* -------------------------------------------------------------------- */ /* Recurse to subnodes if they exist. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( psTreeNode->apsSubNode[i] != NULL ) SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i], padfBoundsMin, padfBoundsMax, pnShapeCount, pnMaxShapes, ppanShapeList ); } } /************************************************************************/ /* SHPTreeFindLikelyShapes() */ /* */ /* Find all shapes within tree nodes for which the tree node */ /* bounding box overlaps the search box. The return value is */ /* an array of shapeids terminated by a -1. The shapeids will */ /* be in order, as hopefully this will result in faster (more */ /* sequential) reading from the file. */ /************************************************************************/ /* helper for qsort */ static int compare_ints( const void * a, const void * b) { return (*(int*)a) - (*(int*)b); } int SHPAPI_CALL1(*) SHPTreeFindLikelyShapes( SHPTree * hTree, double * padfBoundsMin, double * padfBoundsMax, int * pnShapeCount ) { int *panShapeList=NULL, nMaxShapes = 0; /* -------------------------------------------------------------------- */ /* Perform the search by recursive descent. */ /* -------------------------------------------------------------------- */ *pnShapeCount = 0; SHPTreeCollectShapeIds( hTree, hTree->psRoot, padfBoundsMin, padfBoundsMax, pnShapeCount, &nMaxShapes, &panShapeList ); /* -------------------------------------------------------------------- */ /* Sort the id array */ /* -------------------------------------------------------------------- */ qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints); return panShapeList; } /************************************************************************/ /* SHPTreeNodeTrim() */ /* */ /* This is the recurve version of SHPTreeTrimExtraNodes() that */ /* walks the tree cleaning it up. */ /************************************************************************/ static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode ) { int i; /* -------------------------------------------------------------------- */ /* Trim subtrees, and free subnodes that come back empty. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) ) { SHPDestroyTreeNode( psTreeNode->apsSubNode[i] ); psTreeNode->apsSubNode[i] = psTreeNode->apsSubNode[psTreeNode->nSubNodes-1]; psTreeNode->nSubNodes--; i--; /* process the new occupant of this subnode entry */ } } /* -------------------------------------------------------------------- */ /* If the current node has 1 subnode and no shapes, promote that */ /* subnode to the current node position. */ /* -------------------------------------------------------------------- */ if( psTreeNode->nSubNodes == 1 && psTreeNode->nShapeCount == 0) { SHPTreeNode* psSubNode = psTreeNode->apsSubNode[0]; memcpy(psTreeNode->adfBoundsMin, psSubNode->adfBoundsMin, sizeof(psSubNode->adfBoundsMin)); memcpy(psTreeNode->adfBoundsMax, psSubNode->adfBoundsMax, sizeof(psSubNode->adfBoundsMax)); psTreeNode->nShapeCount = psSubNode->nShapeCount; assert(psTreeNode->panShapeIds == NULL); psTreeNode->panShapeIds = psSubNode->panShapeIds; assert(psTreeNode->papsShapeObj == NULL); psTreeNode->papsShapeObj = psSubNode->papsShapeObj; psTreeNode->nSubNodes = psSubNode->nSubNodes; for( i = 0; i < psSubNode->nSubNodes; i++ ) psTreeNode->apsSubNode[i] = psSubNode->apsSubNode[i]; free(psSubNode); } /* -------------------------------------------------------------------- */ /* We should be trimmed if we have no subnodes, and no shapes. */ /* -------------------------------------------------------------------- */ return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 ); } /************************************************************************/ /* SHPTreeTrimExtraNodes() */ /* */ /* Trim empty nodes from the tree. Note that we never trim an */ /* empty root node. */ /************************************************************************/ void SHPAPI_CALL SHPTreeTrimExtraNodes( SHPTree * hTree ) { SHPTreeNodeTrim( hTree->psRoot ); } /************************************************************************/ /* SwapWord() */ /* */ /* Swap a 2, 4 or 8 byte word. */ /************************************************************************/ static void SwapWord( int length, void * wordP ) { int i; unsigned char temp; for( i=0; i < length/2; i++ ) { temp = ((unsigned char *) wordP)[i]; ((unsigned char *)wordP)[i] = ((unsigned char *) wordP)[length-i-1]; ((unsigned char *) wordP)[length-i-1] = temp; } } struct SHPDiskTreeInfo { SAHooks sHooks; SAFile fpQIX; }; /************************************************************************/ /* SHPOpenDiskTree() */ /************************************************************************/ SHPTreeDiskHandle SHPOpenDiskTree( const char* pszQIXFilename, SAHooks *psHooks ) { SHPTreeDiskHandle hDiskTree; hDiskTree = (SHPTreeDiskHandle) calloc(sizeof(struct SHPDiskTreeInfo),1); if (psHooks == NULL) SASetupDefaultHooks( &(hDiskTree->sHooks) ); else memcpy( &(hDiskTree->sHooks), psHooks, sizeof(SAHooks) ); hDiskTree->fpQIX = hDiskTree->sHooks.FOpen(pszQIXFilename, "rb"); if (hDiskTree->fpQIX == NULL) { free(hDiskTree); return NULL; } return hDiskTree; } /***********************************************************************/ /* SHPCloseDiskTree() */ /************************************************************************/ void SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree ) { if (hDiskTree == NULL) return; hDiskTree->sHooks.FClose(hDiskTree->fpQIX); free(hDiskTree); } /************************************************************************/ /* SHPSearchDiskTreeNode() */ /************************************************************************/ static int SHPSearchDiskTreeNode( SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax, int **ppanResultBuffer, int *pnBufferMax, int *pnResultCount, int bNeedSwap ) { int i; int offset; int numshapes, numsubnodes; double adfNodeBoundsMin[2], adfNodeBoundsMax[2]; /* -------------------------------------------------------------------- */ /* Read and unswap first part of node info. */ /* -------------------------------------------------------------------- */ hDiskTree->sHooks.FRead( &offset, 4, 1, hDiskTree->fpQIX ); if ( bNeedSwap ) SwapWord ( 4, &offset ); hDiskTree->sHooks.FRead( adfNodeBoundsMin, sizeof(double), 2, hDiskTree->fpQIX ); hDiskTree->sHooks.FRead( adfNodeBoundsMax, sizeof(double), 2, hDiskTree->fpQIX ); if ( bNeedSwap ) { SwapWord( 8, adfNodeBoundsMin + 0 ); SwapWord( 8, adfNodeBoundsMin + 1 ); SwapWord( 8, adfNodeBoundsMax + 0 ); SwapWord( 8, adfNodeBoundsMax + 1 ); } hDiskTree->sHooks.FRead( &numshapes, 4, 1, hDiskTree->fpQIX ); if ( bNeedSwap ) SwapWord ( 4, &numshapes ); /* -------------------------------------------------------------------- */ /* If we don't overlap this node at all, we can just fseek() */ /* pass this node info and all subnodes. */ /* -------------------------------------------------------------------- */ if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax, padfBoundsMin, padfBoundsMax, 2 ) ) { offset += numshapes*sizeof(int) + sizeof(int); hDiskTree->sHooks.FSeek(hDiskTree->fpQIX, offset, SEEK_CUR); return TRUE; } /* -------------------------------------------------------------------- */ /* Add all the shapeids at this node to our list. */ /* -------------------------------------------------------------------- */ if(numshapes > 0) { if( *pnResultCount + numshapes > *pnBufferMax ) { *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25); *ppanResultBuffer = (int *) SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) ); } hDiskTree->sHooks.FRead( *ppanResultBuffer + *pnResultCount, sizeof(int), numshapes, hDiskTree->fpQIX ); if (bNeedSwap ) { for( i=0; isHooks.FRead( &numsubnodes, 4, 1, hDiskTree->fpQIX ); if ( bNeedSwap ) SwapWord ( 4, &numsubnodes ); for(i=0; isHooks.FSeek( hDiskTree->fpQIX, 0, SEEK_SET ); hDiskTree->sHooks.FRead( abyBuf, 16, 1, hDiskTree->fpQIX ); if( memcmp( abyBuf, "SQT", 3 ) != 0 ) return NULL; if( (abyBuf[3] == 2 && bBigEndian) || (abyBuf[3] == 1 && !bBigEndian) ) bNeedSwap = FALSE; else bNeedSwap = TRUE; /* -------------------------------------------------------------------- */ /* Search through root node and it's decendents. */ /* -------------------------------------------------------------------- */ if( !SHPSearchDiskTreeNode( hDiskTree, padfBoundsMin, padfBoundsMax, &panResultBuffer, &nBufferMax, pnShapeCount, bNeedSwap ) ) { if( panResultBuffer != NULL ) free( panResultBuffer ); *pnShapeCount = 0; return NULL; } /* -------------------------------------------------------------------- */ /* Sort the id array */ /* -------------------------------------------------------------------- */ qsort(panResultBuffer, *pnShapeCount, sizeof(int), compare_ints); return panResultBuffer; } /************************************************************************/ /* SHPGetSubNodeOffset() */ /* */ /* Determine how big all the subnodes of this node (and their */ /* children) will be. This will allow disk based searchers to */ /* seek past them all efficiently. */ /************************************************************************/ static int SHPGetSubNodeOffset( SHPTreeNode *node) { int i; long offset=0; for(i=0; inSubNodes; i++ ) { if(node->apsSubNode[i]) { offset += 4*sizeof(double) + (node->apsSubNode[i]->nShapeCount+3)*sizeof(int); offset += SHPGetSubNodeOffset(node->apsSubNode[i]); } } return(offset); } /************************************************************************/ /* SHPWriteTreeNode() */ /************************************************************************/ static void SHPWriteTreeNode( SAFile fp, SHPTreeNode *node, SAHooks* psHooks) { int i,j; int offset; unsigned char *pabyRec = NULL; assert( NULL != node ); offset = SHPGetSubNodeOffset(node); pabyRec = (unsigned char *) malloc(sizeof(double) * 4 + (3 * sizeof(int)) + (node->nShapeCount * sizeof(int)) ); if( NULL == pabyRec ) { #ifdef USE_CPL CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure"); #endif assert( 0 ); return; } memcpy( pabyRec, &offset, 4); /* minx, miny, maxx, maxy */ memcpy( pabyRec+ 4, node->adfBoundsMin+0, sizeof(double) ); memcpy( pabyRec+12, node->adfBoundsMin+1, sizeof(double) ); memcpy( pabyRec+20, node->adfBoundsMax+0, sizeof(double) ); memcpy( pabyRec+28, node->adfBoundsMax+1, sizeof(double) ); memcpy( pabyRec+36, &node->nShapeCount, 4); j = node->nShapeCount * sizeof(int); memcpy( pabyRec+40, node->panShapeIds, j); memcpy( pabyRec+j+40, &node->nSubNodes, 4); psHooks->FWrite( pabyRec, 44+j, 1, fp ); free (pabyRec); for(i=0; inSubNodes; i++ ) { if(node->apsSubNode[i]) SHPWriteTreeNode( fp, node->apsSubNode[i], psHooks); } } /************************************************************************/ /* SHPWriteTree() */ /************************************************************************/ int SHPAPI_CALL SHPWriteTree(SHPTree *tree, const char *filename ) { SAHooks sHooks; SASetupDefaultHooks( &sHooks ); return SHPWriteTreeLL(tree, filename, &sHooks); } /************************************************************************/ /* SHPWriteTreeLL() */ /************************************************************************/ int SHPWriteTreeLL(SHPTree *tree, const char *filename, SAHooks* psHooks ) { char signature[4] = "SQT"; int i; char abyBuf[32]; SAFile fp; SAHooks sHooks; if (psHooks == NULL) { SASetupDefaultHooks( &sHooks ); psHooks = &sHooks; } /* -------------------------------------------------------------------- */ /* Open the output file. */ /* -------------------------------------------------------------------- */ fp = psHooks->FOpen(filename, "wb"); if( fp == NULL ) { return FALSE; } /* -------------------------------------------------------------------- */ /* Establish the byte order on this machine. */ /* -------------------------------------------------------------------- */ i = 1; if( *((unsigned char *) &i) == 1 ) bBigEndian = FALSE; else bBigEndian = TRUE; /* -------------------------------------------------------------------- */ /* Write the header. */ /* -------------------------------------------------------------------- */ memcpy( abyBuf+0, signature, 3 ); if( bBigEndian ) abyBuf[3] = 2; /* New MSB */ else abyBuf[3] = 1; /* New LSB */ abyBuf[4] = 1; /* version */ abyBuf[5] = 0; /* next 3 reserved */ abyBuf[6] = 0; abyBuf[7] = 0; psHooks->FWrite( abyBuf, 8, 1, fp ); psHooks->FWrite( &(tree->nTotalCount), 4, 1, fp ); /* write maxdepth */ psHooks->FWrite( &(tree->nMaxDepth), 4, 1, fp ); /* -------------------------------------------------------------------- */ /* Write all the nodes "in order". */ /* -------------------------------------------------------------------- */ SHPWriteTreeNode( fp, tree->psRoot, psHooks ); psHooks->FClose( fp ); return TRUE; } shapelib-1.3.0/mkrelease.sh0000750042715500116100000000221511250246176015131 0ustar warmerdameng#!/bin/sh # # mkrelease.sh - prepares Shapelib source distribution package # if [ $# -lt 1 ] ; then echo "Usage: mkrelease.sh " echo " - version number used in name of generated archive." echo echo "Example: mkrelease 1.3.0beta1" exit fi # # Processing script input arguments # VERSION=$1 # # Checkout Shapelib sources from the repository # echo "* Downloading Shapelib sources from CVS..." rm -rf dist_wrk mkdir dist_wrk cd dist_wrk cvs -d :pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot export -D now shapelib if [ \! -d shapelib ] ; then echo "checkout reported an error ..." echo "perhaps you need to do:" echo "cvs -d :pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot login" cd .. rm -rf dist_wrk exit fi # # Make distribution packages # echo "* Making distribution packages..." mv shapelib shapelib-${VERSION} rm -f ../shapelib-${VERSION}.tar.gz ../shapelib-${VERSION}.zip tar cf ../shapelib-${VERSION}.tar shapelib-${VERSION} gzip -9 ../shapelib-${VERSION}.tar zip -r ../shapelib-${VERSION}.zip shapelib-${VERSION} echo "* Cleaning..." cd .. rm -rf dist_wrk echo "*** The End ***" shapelib-1.3.0/HOWTO-RELEASE0000640042715500116100000000057111250246520014520 0ustar warmerdameng Producing Shapelib Releases =========================== 1) Update web/release.html with change notes on the new release and commit. 2) Build the release files. ./mkrelease.sh 1.3.0 3) Upload: scp shapelib-1.3.0{.tar.gz,.zip} warmerdam@upload.osgeo.org:/osgeo/download/shapelib ... add upload notes to maptools.org ... 4) Announce on shapelib mailing list. shapelib-1.3.0/dbfopen.c0000640042715500116100000023260511612732275014416 0ustar warmerdameng/****************************************************************************** * $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Implementation of .dbf access API documented in dbf_api.html. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: dbfopen.c,v $ * Revision 1.89 2011-07-24 05:59:25 fwarmerdam * minimize use of CPLError in favor of SAHooks.Error() * * Revision 1.88 2011-05-13 17:35:17 fwarmerdam * added DBFReorderFields() and DBFAlterFields() functions (from Even) * * Revision 1.87 2011-05-07 22:41:02 fwarmerdam * ensure pending record is flushed when adding a native field (GDAL #4073) * * Revision 1.86 2011-04-17 15:15:29 fwarmerdam * Removed unused variable. * * Revision 1.85 2010-12-06 16:09:34 fwarmerdam * fix buffer read overrun fetching code page (bug 2276) * * Revision 1.84 2009-10-29 19:59:48 fwarmerdam * avoid crash on truncated header (gdal #3093) * * Revision 1.83 2008/11/12 14:28:15 fwarmerdam * DBFCreateField() now works on files with records * * Revision 1.82 2008/11/11 17:47:09 fwarmerdam * added DBFDeleteField() function * * Revision 1.81 2008/01/03 17:48:13 bram * in DBFCreate, use default code page LDID/87 (= 0x57, ANSI) * instead of LDID/3. This seems to be the same as what ESRI * would be doing by default. * * Revision 1.80 2007/12/30 14:36:39 fwarmerdam * avoid syntax issue with last comment. * * Revision 1.79 2007/12/30 14:35:48 fwarmerdam * Avoid char* / unsigned char* warnings. * * Revision 1.78 2007/12/18 18:28:07 bram * - create hook for client specific atof (bugzilla ticket 1615) * - check for NULL handle before closing cpCPG file, and close after reading. * * Revision 1.77 2007/12/15 20:25:21 bram * dbfopen.c now reads the Code Page information from the DBF file, and exports * this information as a string through the DBFGetCodePage function. This is * either the number from the LDID header field ("LDID/") or as the * content of an accompanying .CPG file. When creating a DBF file, the code can * be set using DBFCreateEx. * * Revision 1.76 2007/12/12 22:21:32 bram * DBFClose: check for NULL psDBF handle before trying to close it. * * Revision 1.75 2007/12/06 13:58:19 fwarmerdam * make sure file offset calculations are done in as SAOffset * * Revision 1.74 2007/12/06 07:00:25 fwarmerdam * dbfopen now using SAHooks for fileio * * Revision 1.73 2007/09/03 19:48:11 fwarmerdam * move DBFReadAttribute() static dDoubleField into dbfinfo * * Revision 1.72 2007/09/03 19:34:06 fwarmerdam * Avoid use of static tuple buffer in DBFReadTuple() * * Revision 1.71 2006/06/22 14:37:18 fwarmerdam * avoid memory leak if dbfopen fread fails * * Revision 1.70 2006/06/17 17:47:05 fwarmerdam * use calloc() for dbfinfo in DBFCreate * * Revision 1.69 2006/06/17 15:34:32 fwarmerdam * disallow creating fields wider than 255 * * Revision 1.68 2006/06/17 15:12:40 fwarmerdam * Fixed C++ style comments. * * Revision 1.67 2006/06/17 00:24:53 fwarmerdam * Don't treat non-zero decimals values as high order byte for length * for strings. It causes serious corruption for some files. * http://bugzilla.remotesensing.org/show_bug.cgi?id=1202 * * Revision 1.66 2006/03/29 18:26:20 fwarmerdam * fixed bug with size of pachfieldtype in dbfcloneempty * * Revision 1.65 2006/02/15 01:14:30 fwarmerdam * added DBFAddNativeFieldType * * Revision 1.64 2006/02/09 00:29:04 fwarmerdam * Changed to put spaces into string fields that are NULL as * per http://bugzilla.maptools.org/show_bug.cgi?id=316. * * Revision 1.63 2006/01/25 15:35:43 fwarmerdam * check success on DBFFlushRecord * * Revision 1.62 2006/01/10 16:28:03 fwarmerdam * Fixed typo in CPLError. * * Revision 1.61 2006/01/10 16:26:29 fwarmerdam * Push loading record buffer into DBFLoadRecord. * Implement CPL error reporting if USE_CPL defined. * * Revision 1.60 2006/01/05 01:27:27 fwarmerdam * added dbf deletion mark/fetch * * Revision 1.59 2005/03/14 15:20:28 fwarmerdam * Fixed last change. * * Revision 1.58 2005/03/14 15:18:54 fwarmerdam * Treat very wide fields with no decimals as double. This is * more than 32bit integer fields. * * Revision 1.57 2005/02/10 20:16:54 fwarmerdam * Make the pszStringField buffer for DBFReadAttribute() static char [256] * as per bug 306. * * Revision 1.56 2005/02/10 20:07:56 fwarmerdam * Fixed bug 305 in DBFCloneEmpty() - header length problem. * * Revision 1.55 2004/09/26 20:23:46 fwarmerdam * avoid warnings with rcsid and signed/unsigned stuff * * Revision 1.54 2004/09/15 16:26:10 fwarmerdam * Treat all blank numeric fields as null too. */ #include "shapefil.h" #include #include #include #include SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $") #ifndef FALSE # define FALSE 0 # define TRUE 1 #endif /************************************************************************/ /* SfRealloc() */ /* */ /* A realloc cover function that will access a NULL pointer as */ /* a valid input. */ /************************************************************************/ static void * SfRealloc( void * pMem, int nNewSize ) { if( pMem == NULL ) return( (void *) malloc(nNewSize) ); else return( (void *) realloc(pMem,nNewSize) ); } /************************************************************************/ /* DBFWriteHeader() */ /* */ /* This is called to write out the file header, and field */ /* descriptions before writing any actual data records. This */ /* also computes all the DBFDataSet field offset/size/decimals */ /* and so forth values. */ /************************************************************************/ static void DBFWriteHeader(DBFHandle psDBF) { unsigned char abyHeader[XBASE_FLDHDR_SZ]; int i; if( !psDBF->bNoHeader ) return; psDBF->bNoHeader = FALSE; /* -------------------------------------------------------------------- */ /* Initialize the file header information. */ /* -------------------------------------------------------------------- */ for( i = 0; i < XBASE_FLDHDR_SZ; i++ ) abyHeader[i] = 0; abyHeader[0] = 0x03; /* memo field? - just copying */ /* write out a dummy date */ abyHeader[1] = 95; /* YY */ abyHeader[2] = 7; /* MM */ abyHeader[3] = 26; /* DD */ /* record count preset at zero */ abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256); abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256); abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256); abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256); abyHeader[29] = (unsigned char) (psDBF->iLanguageDriver); /* -------------------------------------------------------------------- */ /* Write the initial 32 byte file header, and all the field */ /* descriptions. */ /* -------------------------------------------------------------------- */ psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp ); psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields, psDBF->fp ); /* -------------------------------------------------------------------- */ /* Write out the newline character if there is room for it. */ /* -------------------------------------------------------------------- */ if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 ) { char cNewline; cNewline = 0x0d; psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp ); } } /************************************************************************/ /* DBFFlushRecord() */ /* */ /* Write out the current record if there is one. */ /************************************************************************/ static int DBFFlushRecord( DBFHandle psDBF ) { SAOffset nRecordOffset; if( psDBF->bCurrentRecordModified && psDBF->nCurrentRecord > -1 ) { psDBF->bCurrentRecordModified = FALSE; nRecordOffset = psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord + psDBF->nHeaderLength; if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0 || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) { char szMessage[128]; sprintf( szMessage, "Failure writing DBF record %d.", psDBF->nCurrentRecord ); psDBF->sHooks.Error( szMessage ); return FALSE; } } return TRUE; } /************************************************************************/ /* DBFLoadRecord() */ /************************************************************************/ static int DBFLoadRecord( DBFHandle psDBF, int iRecord ) { if( psDBF->nCurrentRecord != iRecord ) { SAOffset nRecordOffset; if( !DBFFlushRecord( psDBF ) ) return FALSE; nRecordOffset = psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 ) { char szMessage[128]; sprintf( szMessage, "fseek(%ld) failed on DBF file.\n", (long) nRecordOffset ); psDBF->sHooks.Error( szMessage ); return FALSE; } if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ) != 1 ) { char szMessage[128]; sprintf( szMessage, "fread(%d) failed on DBF file.\n", psDBF->nRecordLength ); psDBF->sHooks.Error( szMessage ); return FALSE; } psDBF->nCurrentRecord = iRecord; } return TRUE; } /************************************************************************/ /* DBFUpdateHeader() */ /************************************************************************/ void SHPAPI_CALL DBFUpdateHeader( DBFHandle psDBF ) { unsigned char abyFileHeader[32]; if( psDBF->bNoHeader ) DBFWriteHeader( psDBF ); DBFFlushRecord( psDBF ); psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp ); abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256); abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256); abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256); abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256); psDBF->sHooks.FSeek( psDBF->fp, 0, 0 ); psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp ); psDBF->sHooks.FFlush( psDBF->fp ); } /************************************************************************/ /* DBFOpen() */ /* */ /* Open a .dbf file. */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFOpen( const char * pszFilename, const char * pszAccess ) { SAHooks sHooks; SASetupDefaultHooks( &sHooks ); return DBFOpenLL( pszFilename, pszAccess, &sHooks ); } /************************************************************************/ /* DBFOpen() */ /* */ /* Open a .dbf file. */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks ) { DBFHandle psDBF; SAFile pfCPG; unsigned char *pabyBuf; int nFields, nHeadLen, iField, i; char *pszBasename, *pszFullname; int nBufSize = 500; /* -------------------------------------------------------------------- */ /* We only allow the access strings "rb" and "r+". */ /* -------------------------------------------------------------------- */ if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0 && strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0 && strcmp(pszAccess,"r+b") != 0 ) return( NULL ); if( strcmp(pszAccess,"r") == 0 ) pszAccess = "rb"; if( strcmp(pszAccess,"r+") == 0 ) pszAccess = "rb+"; /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszFilename)+5); strcpy( pszBasename, pszFilename ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.dbf", pszBasename ); psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) ); psDBF->fp = psHooks->FOpen( pszFullname, pszAccess ); memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); if( psDBF->fp == NULL ) { sprintf( pszFullname, "%s.DBF", pszBasename ); psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess ); } sprintf( pszFullname, "%s.cpg", pszBasename ); pfCPG = psHooks->FOpen( pszFullname, "r" ); if( pfCPG == NULL ) { sprintf( pszFullname, "%s.CPG", pszBasename ); pfCPG = psHooks->FOpen( pszFullname, "r" ); } free( pszBasename ); free( pszFullname ); if( psDBF->fp == NULL ) { free( psDBF ); if( pfCPG ) psHooks->FClose( pfCPG ); return( NULL ); } psDBF->bNoHeader = FALSE; psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; /* -------------------------------------------------------------------- */ /* Read Table Header info */ /* -------------------------------------------------------------------- */ pabyBuf = (unsigned char *) malloc(nBufSize); if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 ) { psDBF->sHooks.FClose( psDBF->fp ); if( pfCPG ) psDBF->sHooks.FClose( pfCPG ); free( pabyBuf ); free( psDBF ); return NULL; } psDBF->nRecords = pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256; psDBF->iLanguageDriver = pabyBuf[29]; if (nHeadLen < 32) { psDBF->sHooks.FClose( psDBF->fp ); if( pfCPG ) psDBF->sHooks.FClose( pfCPG ); free( pabyBuf ); free( psDBF ); return NULL; } psDBF->nFields = nFields = (nHeadLen - 32) / 32; psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength); /* -------------------------------------------------------------------- */ /* Figure out the code page from the LDID and CPG */ /* -------------------------------------------------------------------- */ psDBF->pszCodePage = NULL; if( pfCPG ) { size_t n; memset( pabyBuf, 0, nBufSize); psDBF->sHooks.FRead( pabyBuf, nBufSize - 1, 1, pfCPG ); n = strcspn( (char *) pabyBuf, "\n\r" ); if( n > 0 ) { pabyBuf[n] = '\0'; psDBF->pszCodePage = (char *) malloc(n + 1); memcpy( psDBF->pszCodePage, pabyBuf, n + 1 ); } psDBF->sHooks.FClose( pfCPG ); } if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 ) { sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver ); psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1); strcpy( psDBF->pszCodePage, (char *) pabyBuf ); } /* -------------------------------------------------------------------- */ /* Read in Field Definitions */ /* -------------------------------------------------------------------- */ pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen); psDBF->pszHeader = (char *) pabyBuf; psDBF->sHooks.FSeek( psDBF->fp, 32, 0 ); if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) { psDBF->sHooks.FClose( psDBF->fp ); free( pabyBuf ); free( psDBF->pszCurrentRecord ); free( psDBF ); return NULL; } psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); psDBF->panFieldDecimals = (int *) malloc(sizeof(int) * nFields); psDBF->pachFieldType = (char *) malloc(sizeof(char) * nFields); for( iField = 0; iField < nFields; iField++ ) { unsigned char *pabyFInfo; pabyFInfo = pabyBuf+iField*32; if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' ) { psDBF->panFieldSize[iField] = pabyFInfo[16]; psDBF->panFieldDecimals[iField] = pabyFInfo[17]; } else { psDBF->panFieldSize[iField] = pabyFInfo[16]; psDBF->panFieldDecimals[iField] = 0; /* ** The following seemed to be used sometimes to handle files with long ** string fields, but in other cases (such as bug 1202) the decimals field ** just seems to indicate some sort of preferred formatting, not very ** wide fields. So I have disabled this code. FrankW. psDBF->panFieldSize[iField] = pabyFInfo[16] + pabyFInfo[17]*256; psDBF->panFieldDecimals[iField] = 0; */ } psDBF->pachFieldType[iField] = (char) pabyFInfo[11]; if( iField == 0 ) psDBF->panFieldOffset[iField] = 1; else psDBF->panFieldOffset[iField] = psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1]; } return( psDBF ); } /************************************************************************/ /* DBFClose() */ /************************************************************************/ void SHPAPI_CALL DBFClose(DBFHandle psDBF) { if( psDBF == NULL ) return; /* -------------------------------------------------------------------- */ /* Write out header if not already written. */ /* -------------------------------------------------------------------- */ if( psDBF->bNoHeader ) DBFWriteHeader( psDBF ); DBFFlushRecord( psDBF ); /* -------------------------------------------------------------------- */ /* Update last access date, and number of records if we have */ /* write access. */ /* -------------------------------------------------------------------- */ if( psDBF->bUpdated ) DBFUpdateHeader( psDBF ); /* -------------------------------------------------------------------- */ /* Close, and free resources. */ /* -------------------------------------------------------------------- */ psDBF->sHooks.FClose( psDBF->fp ); if( psDBF->panFieldOffset != NULL ) { free( psDBF->panFieldOffset ); free( psDBF->panFieldSize ); free( psDBF->panFieldDecimals ); free( psDBF->pachFieldType ); } if( psDBF->pszWorkField != NULL ) free( psDBF->pszWorkField ); free( psDBF->pszHeader ); free( psDBF->pszCurrentRecord ); free( psDBF->pszCodePage ); free( psDBF ); } /************************************************************************/ /* DBFCreate() */ /* */ /* Create a new .dbf file with default code page LDID/87 (0x57) */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFCreate( const char * pszFilename ) { return DBFCreateEx( pszFilename, "LDID/87" ); // 0x57 } /************************************************************************/ /* DBFCreateEx() */ /* */ /* Create a new .dbf file. */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFCreateEx( const char * pszFilename, const char* pszCodePage ) { SAHooks sHooks; SASetupDefaultHooks( &sHooks ); return DBFCreateLL( pszFilename, pszCodePage , &sHooks ); } /************************************************************************/ /* DBFCreate() */ /* */ /* Create a new .dbf file. */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHooks ) { DBFHandle psDBF; SAFile fp; char *pszFullname, *pszBasename; int i, ldid = -1; char chZero = '\0'; /* -------------------------------------------------------------------- */ /* Compute the base (layer) name. If there is any extension */ /* on the passed in filename we will strip it off. */ /* -------------------------------------------------------------------- */ pszBasename = (char *) malloc(strlen(pszFilename)+5); strcpy( pszBasename, pszFilename ); for( i = strlen(pszBasename)-1; i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' && pszBasename[i] != '\\'; i-- ) {} if( pszBasename[i] == '.' ) pszBasename[i] = '\0'; pszFullname = (char *) malloc(strlen(pszBasename) + 5); sprintf( pszFullname, "%s.dbf", pszBasename ); /* -------------------------------------------------------------------- */ /* Create the file. */ /* -------------------------------------------------------------------- */ fp = psHooks->FOpen( pszFullname, "wb" ); if( fp == NULL ) return( NULL ); psHooks->FWrite( &chZero, 1, 1, fp ); psHooks->FClose( fp ); fp = psHooks->FOpen( pszFullname, "rb+" ); if( fp == NULL ) return( NULL ); sprintf( pszFullname, "%s.cpg", pszBasename ); if( pszCodePage != NULL ) { if( strncmp( pszCodePage, "LDID/", 5 ) == 0 ) { ldid = atoi( pszCodePage + 5 ); if( ldid > 255 ) ldid = -1; // don't use 0 to indicate out of range as LDID/0 is a valid one } if( ldid < 0 ) { SAFile fpCPG = psHooks->FOpen( pszFullname, "w" ); psHooks->FWrite( (char*) pszCodePage, strlen(pszCodePage), 1, fpCPG ); psHooks->FClose( fpCPG ); } } if( pszCodePage == NULL || ldid >= 0 ) { psHooks->Remove( pszFullname ); } free( pszBasename ); free( pszFullname ); /* -------------------------------------------------------------------- */ /* Create the info structure. */ /* -------------------------------------------------------------------- */ psDBF = (DBFHandle) calloc(1,sizeof(DBFInfo)); memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) ); psDBF->fp = fp; psDBF->nRecords = 0; psDBF->nFields = 0; psDBF->nRecordLength = 1; psDBF->nHeaderLength = 33; psDBF->panFieldOffset = NULL; psDBF->panFieldSize = NULL; psDBF->panFieldDecimals = NULL; psDBF->pachFieldType = NULL; psDBF->pszHeader = NULL; psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; psDBF->pszCurrentRecord = NULL; psDBF->bNoHeader = TRUE; psDBF->iLanguageDriver = ldid > 0 ? ldid : 0; psDBF->pszCodePage = NULL; if( pszCodePage ) { psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 ); strcpy( psDBF->pszCodePage, pszCodePage ); } return( psDBF ); } /************************************************************************/ /* DBFAddField() */ /* */ /* Add a field to a newly created .dbf or to an existing one */ /************************************************************************/ int SHPAPI_CALL DBFAddField(DBFHandle psDBF, const char * pszFieldName, DBFFieldType eType, int nWidth, int nDecimals ) { char chNativeType = 'C'; if( eType == FTLogical ) chNativeType = 'L'; else if( eType == FTString ) chNativeType = 'C'; else chNativeType = 'N'; return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType, nWidth, nDecimals ); } /************************************************************************/ /* DBFGetNullCharacter() */ /************************************************************************/ static char DBFGetNullCharacter(char chType) { switch (chType) { case 'N': case 'F': return '*'; case 'D': return '0'; case 'L': return '?'; default: return ' '; } } /************************************************************************/ /* DBFAddField() */ /* */ /* Add a field to a newly created .dbf file before any records */ /* are written. */ /************************************************************************/ int SHPAPI_CALL DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName, char chType, int nWidth, int nDecimals ) { char *pszFInfo; int i; int nOldRecordLength, nOldHeaderLength; char *pszRecord; char chFieldFill; SAOffset nRecordOffset; /* make sure that everything is written in .dbf */ if( !DBFFlushRecord( psDBF ) ) return -1; /* -------------------------------------------------------------------- */ /* Do some checking to ensure we can add records to this file. */ /* -------------------------------------------------------------------- */ if( nWidth < 1 ) return -1; if( nWidth > 255 ) nWidth = 255; nOldRecordLength = psDBF->nRecordLength; nOldHeaderLength = psDBF->nHeaderLength; /* -------------------------------------------------------------------- */ /* SfRealloc all the arrays larger to hold the additional field */ /* information. */ /* -------------------------------------------------------------------- */ psDBF->nFields++; psDBF->panFieldOffset = (int *) SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); psDBF->panFieldSize = (int *) SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); psDBF->panFieldDecimals = (int *) SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); psDBF->pachFieldType = (char *) SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); /* -------------------------------------------------------------------- */ /* Assign the new field information fields. */ /* -------------------------------------------------------------------- */ psDBF->panFieldOffset[psDBF->nFields-1] = psDBF->nRecordLength; psDBF->nRecordLength += nWidth; psDBF->panFieldSize[psDBF->nFields-1] = nWidth; psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; psDBF->pachFieldType[psDBF->nFields-1] = chType; /* -------------------------------------------------------------------- */ /* Extend the required header information. */ /* -------------------------------------------------------------------- */ psDBF->nHeaderLength += 32; psDBF->bUpdated = FALSE; psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1); for( i = 0; i < 32; i++ ) pszFInfo[i] = '\0'; if( (int) strlen(pszFieldName) < 10 ) strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); else strncpy( pszFInfo, pszFieldName, 10); pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1]; if( chType == 'C' ) { pszFInfo[16] = (unsigned char) (nWidth % 256); pszFInfo[17] = (unsigned char) (nWidth / 256); } else { pszFInfo[16] = (unsigned char) nWidth; pszFInfo[17] = (unsigned char) nDecimals; } /* -------------------------------------------------------------------- */ /* Make the current record buffer appropriately larger. */ /* -------------------------------------------------------------------- */ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength); /* we're done if dealing with new .dbf */ if( psDBF->bNoHeader ) return( psDBF->nFields - 1 ); /* -------------------------------------------------------------------- */ /* For existing .dbf file, shift records */ /* -------------------------------------------------------------------- */ /* alloc record */ pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength); chFieldFill = DBFGetNullCharacter(chType); for (i = psDBF->nRecords-1; i >= 0; --i) { nRecordOffset = nOldRecordLength * (SAOffset) i + nOldHeaderLength; /* load record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); /* set new field's value to NULL */ memset(pszRecord + nOldRecordLength, chFieldFill, nWidth); nRecordOffset = psDBF->nRecordLength * (SAOffset) i + psDBF->nHeaderLength; /* move record to the new place*/ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp ); } /* free record */ free(pszRecord); /* force update of header with new header, record length and new field */ psDBF->bNoHeader = TRUE; DBFUpdateHeader( psDBF ); psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; return( psDBF->nFields-1 ); } /************************************************************************/ /* DBFReadAttribute() */ /* */ /* Read one of the attribute fields of a record. */ /************************************************************************/ static void *DBFReadAttribute(DBFHandle psDBF, int hEntity, int iField, char chReqType ) { unsigned char *pabyRec; void *pReturnField = NULL; /* -------------------------------------------------------------------- */ /* Verify selection. */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity >= psDBF->nRecords ) return( NULL ); if( iField < 0 || iField >= psDBF->nFields ) return( NULL ); /* -------------------------------------------------------------------- */ /* Have we read the record? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, hEntity ) ) return NULL; pabyRec = (unsigned char *) psDBF->pszCurrentRecord; /* -------------------------------------------------------------------- */ /* Ensure we have room to extract the target field. */ /* -------------------------------------------------------------------- */ if( psDBF->panFieldSize[iField] >= psDBF->nWorkFieldLength ) { psDBF->nWorkFieldLength = psDBF->panFieldSize[iField] + 100; if( psDBF->pszWorkField == NULL ) psDBF->pszWorkField = (char *) malloc(psDBF->nWorkFieldLength); else psDBF->pszWorkField = (char *) realloc(psDBF->pszWorkField, psDBF->nWorkFieldLength); } /* -------------------------------------------------------------------- */ /* Extract the requested field. */ /* -------------------------------------------------------------------- */ strncpy( psDBF->pszWorkField, ((const char *) pabyRec) + psDBF->panFieldOffset[iField], psDBF->panFieldSize[iField] ); psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0'; pReturnField = psDBF->pszWorkField; /* -------------------------------------------------------------------- */ /* Decode the field. */ /* -------------------------------------------------------------------- */ if( chReqType == 'N' ) { psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField); pReturnField = &(psDBF->dfDoubleField); } /* -------------------------------------------------------------------- */ /* Should we trim white space off the string attribute value? */ /* -------------------------------------------------------------------- */ #ifdef TRIM_DBF_WHITESPACE else { char *pchSrc, *pchDst; pchDst = pchSrc = psDBF->pszWorkField; while( *pchSrc == ' ' ) pchSrc++; while( *pchSrc != '\0' ) *(pchDst++) = *(pchSrc++); *pchDst = '\0'; while( pchDst != psDBF->pszWorkField && *(--pchDst) == ' ' ) *pchDst = '\0'; } #endif return( pReturnField ); } /************************************************************************/ /* DBFReadIntAttribute() */ /* */ /* Read an integer attribute. */ /************************************************************************/ int SHPAPI_CALL DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField ) { double *pdValue; pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); if( pdValue == NULL ) return 0; else return( (int) *pdValue ); } /************************************************************************/ /* DBFReadDoubleAttribute() */ /* */ /* Read a double attribute. */ /************************************************************************/ double SHPAPI_CALL DBFReadDoubleAttribute( DBFHandle psDBF, int iRecord, int iField ) { double *pdValue; pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' ); if( pdValue == NULL ) return 0.0; else return( *pdValue ); } /************************************************************************/ /* DBFReadStringAttribute() */ /* */ /* Read a string attribute. */ /************************************************************************/ const char SHPAPI_CALL1(*) DBFReadStringAttribute( DBFHandle psDBF, int iRecord, int iField ) { return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'C' ) ); } /************************************************************************/ /* DBFReadLogicalAttribute() */ /* */ /* Read a logical attribute. */ /************************************************************************/ const char SHPAPI_CALL1(*) DBFReadLogicalAttribute( DBFHandle psDBF, int iRecord, int iField ) { return( (const char *) DBFReadAttribute( psDBF, iRecord, iField, 'L' ) ); } /************************************************************************/ /* DBFIsValueNULL() */ /* */ /* Return TRUE if the passed string is NULL. */ /************************************************************************/ static int DBFIsValueNULL( char chType, const char* pszValue ) { int i; if( pszValue == NULL ) return TRUE; switch(chType) { case 'N': case 'F': /* ** We accept all asterisks or all blanks as NULL ** though according to the spec I think it should be all ** asterisks. */ if( pszValue[0] == '*' ) return TRUE; for( i = 0; pszValue[i] != '\0'; i++ ) { if( pszValue[i] != ' ' ) return FALSE; } return TRUE; case 'D': /* NULL date fields have value "00000000" */ return strncmp(pszValue,"00000000",8) == 0; case 'L': /* NULL boolean fields have value "?" */ return pszValue[0] == '?'; default: /* empty string fields are considered NULL */ return strlen(pszValue) == 0; } } /************************************************************************/ /* DBFIsAttributeNULL() */ /* */ /* Return TRUE if value for field is NULL. */ /* */ /* Contributed by Jim Matthews. */ /************************************************************************/ int SHPAPI_CALL DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) { const char *pszValue; pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); if( pszValue == NULL ) return TRUE; return DBFIsValueNULL( psDBF->pachFieldType[iField], pszValue ); } /************************************************************************/ /* DBFGetFieldCount() */ /* */ /* Return the number of fields in this table. */ /************************************************************************/ int SHPAPI_CALL DBFGetFieldCount( DBFHandle psDBF ) { return( psDBF->nFields ); } /************************************************************************/ /* DBFGetRecordCount() */ /* */ /* Return the number of records in this table. */ /************************************************************************/ int SHPAPI_CALL DBFGetRecordCount( DBFHandle psDBF ) { return( psDBF->nRecords ); } /************************************************************************/ /* DBFGetFieldInfo() */ /* */ /* Return any requested information about the field. */ /************************************************************************/ DBFFieldType SHPAPI_CALL DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals ) { if( iField < 0 || iField >= psDBF->nFields ) return( FTInvalid ); if( pnWidth != NULL ) *pnWidth = psDBF->panFieldSize[iField]; if( pnDecimals != NULL ) *pnDecimals = psDBF->panFieldDecimals[iField]; if( pszFieldName != NULL ) { int i; strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 ); pszFieldName[11] = '\0'; for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- ) pszFieldName[i] = '\0'; } if ( psDBF->pachFieldType[iField] == 'L' ) return( FTLogical); else if( psDBF->pachFieldType[iField] == 'N' || psDBF->pachFieldType[iField] == 'F' ) { if( psDBF->panFieldDecimals[iField] > 0 || psDBF->panFieldSize[iField] > 10 ) return( FTDouble ); else return( FTInteger ); } else { return( FTString ); } } /************************************************************************/ /* DBFWriteAttribute() */ /* */ /* Write an attribute record to the file. */ /************************************************************************/ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void * pValue ) { int i, j, nRetResult = TRUE; unsigned char *pabyRec; char szSField[400], szFormat[20]; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { if( !DBFFlushRecord( psDBF ) ) return FALSE; psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, hEntity ) ) return FALSE; pabyRec = (unsigned char *) psDBF->pszCurrentRecord; psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; /* -------------------------------------------------------------------- */ /* Translate NULL value to valid DBF file representation. */ /* */ /* Contributed by Jim Matthews. */ /* -------------------------------------------------------------------- */ if( pValue == NULL ) { memset( (char *) (pabyRec+psDBF->panFieldOffset[iField]), DBFGetNullCharacter(psDBF->pachFieldType[iField]), psDBF->panFieldSize[iField] ); return TRUE; } /* -------------------------------------------------------------------- */ /* Assign all the record fields. */ /* -------------------------------------------------------------------- */ switch( psDBF->pachFieldType[iField] ) { case 'D': case 'N': case 'F': if( psDBF->panFieldDecimals[iField] == 0 ) { int nWidth = psDBF->panFieldSize[iField]; if( (int) sizeof(szSField)-2 < nWidth ) nWidth = sizeof(szSField)-2; sprintf( szFormat, "%%%dd", nWidth ); sprintf(szSField, szFormat, (int) *((double *) pValue) ); if( (int)strlen(szSField) > psDBF->panFieldSize[iField] ) { szSField[psDBF->panFieldSize[iField]] = '\0'; nRetResult = FALSE; } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), szSField, strlen(szSField) ); } else { int nWidth = psDBF->panFieldSize[iField]; if( (int) sizeof(szSField)-2 < nWidth ) nWidth = sizeof(szSField)-2; sprintf( szFormat, "%%%d.%df", nWidth, psDBF->panFieldDecimals[iField] ); sprintf(szSField, szFormat, *((double *) pValue) ); if( (int) strlen(szSField) > psDBF->panFieldSize[iField] ) { szSField[psDBF->panFieldSize[iField]] = '\0'; nRetResult = FALSE; } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), szSField, strlen(szSField) ); } break; case 'L': if (psDBF->panFieldSize[iField] >= 1 && (*(char*)pValue == 'F' || *(char*)pValue == 'T')) *(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue; break; default: if( (int) strlen((char *) pValue) > psDBF->panFieldSize[iField] ) { j = psDBF->panFieldSize[iField]; nRetResult = FALSE; } else { memset( pabyRec+psDBF->panFieldOffset[iField], ' ', psDBF->panFieldSize[iField] ); j = strlen((char *) pValue); } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), (char *) pValue, j ); break; } return( nRetResult ); } /************************************************************************/ /* DBFWriteAttributeDirectly() */ /* */ /* Write an attribute record to the file, but without any */ /* reformatting based on type. The provided buffer is written */ /* as is to the field position in the record. */ /************************************************************************/ int SHPAPI_CALL DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, void * pValue ) { int i, j; unsigned char *pabyRec; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { if( !DBFFlushRecord( psDBF ) ) return FALSE; psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, hEntity ) ) return FALSE; pabyRec = (unsigned char *) psDBF->pszCurrentRecord; /* -------------------------------------------------------------------- */ /* Assign all the record fields. */ /* -------------------------------------------------------------------- */ if( (int)strlen((char *) pValue) > psDBF->panFieldSize[iField] ) j = psDBF->panFieldSize[iField]; else { memset( pabyRec+psDBF->panFieldOffset[iField], ' ', psDBF->panFieldSize[iField] ); j = strlen((char *) pValue); } strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]), (char *) pValue, j ); psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; return( TRUE ); } /************************************************************************/ /* DBFWriteDoubleAttribute() */ /* */ /* Write a double attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteDoubleAttribute( DBFHandle psDBF, int iRecord, int iField, double dValue ) { return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); } /************************************************************************/ /* DBFWriteIntegerAttribute() */ /* */ /* Write a integer attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteIntegerAttribute( DBFHandle psDBF, int iRecord, int iField, int nValue ) { double dValue = nValue; return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) &dValue ) ); } /************************************************************************/ /* DBFWriteStringAttribute() */ /* */ /* Write a string attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteStringAttribute( DBFHandle psDBF, int iRecord, int iField, const char * pszValue ) { return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) pszValue ) ); } /************************************************************************/ /* DBFWriteNULLAttribute() */ /* */ /* Write a string attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteNULLAttribute( DBFHandle psDBF, int iRecord, int iField ) { return( DBFWriteAttribute( psDBF, iRecord, iField, NULL ) ); } /************************************************************************/ /* DBFWriteLogicalAttribute() */ /* */ /* Write a logical attribute. */ /************************************************************************/ int SHPAPI_CALL DBFWriteLogicalAttribute( DBFHandle psDBF, int iRecord, int iField, const char lValue) { return( DBFWriteAttribute( psDBF, iRecord, iField, (void *) (&lValue) ) ); } /************************************************************************/ /* DBFWriteTuple() */ /* */ /* Write an attribute record to the file. */ /************************************************************************/ int SHPAPI_CALL DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple ) { int i; unsigned char *pabyRec; /* -------------------------------------------------------------------- */ /* Is this a valid record? */ /* -------------------------------------------------------------------- */ if( hEntity < 0 || hEntity > psDBF->nRecords ) return( FALSE ); if( psDBF->bNoHeader ) DBFWriteHeader(psDBF); /* -------------------------------------------------------------------- */ /* Is this a brand new record? */ /* -------------------------------------------------------------------- */ if( hEntity == psDBF->nRecords ) { if( !DBFFlushRecord( psDBF ) ) return FALSE; psDBF->nRecords++; for( i = 0; i < psDBF->nRecordLength; i++ ) psDBF->pszCurrentRecord[i] = ' '; psDBF->nCurrentRecord = hEntity; } /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, hEntity ) ) return FALSE; pabyRec = (unsigned char *) psDBF->pszCurrentRecord; memcpy ( pabyRec, pRawTuple, psDBF->nRecordLength ); psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; return( TRUE ); } /************************************************************************/ /* DBFReadTuple() */ /* */ /* Read a complete record. Note that the result is only valid */ /* till the next record read for any reason. */ /************************************************************************/ const char SHPAPI_CALL1(*) DBFReadTuple(DBFHandle psDBF, int hEntity ) { if( hEntity < 0 || hEntity >= psDBF->nRecords ) return( NULL ); if( !DBFLoadRecord( psDBF, hEntity ) ) return NULL; return (const char *) psDBF->pszCurrentRecord; } /************************************************************************/ /* DBFCloneEmpty() */ /* */ /* Read one of the attribute fields of a record. */ /************************************************************************/ DBFHandle SHPAPI_CALL DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) { DBFHandle newDBF; newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage ); if ( newDBF == NULL ) return ( NULL ); newDBF->nFields = psDBF->nFields; newDBF->nRecordLength = psDBF->nRecordLength; newDBF->nHeaderLength = psDBF->nHeaderLength; newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength ); memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength ); newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); newDBF->pachFieldType = (char *) malloc ( sizeof(char) * psDBF->nFields ); memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(char)*psDBF->nFields ); newDBF->bNoHeader = TRUE; newDBF->bUpdated = TRUE; DBFWriteHeader ( newDBF ); DBFClose ( newDBF ); newDBF = DBFOpen ( pszFilename, "rb+" ); return ( newDBF ); } /************************************************************************/ /* DBFGetNativeFieldType() */ /* */ /* Return the DBase field type for the specified field. */ /* */ /* Value can be one of: 'C' (String), 'D' (Date), 'F' (Float), */ /* 'N' (Numeric, with or without decimal), */ /* 'L' (Logical), */ /* 'M' (Memo: 10 digits .DBT block ptr) */ /************************************************************************/ char SHPAPI_CALL DBFGetNativeFieldType( DBFHandle psDBF, int iField ) { if( iField >=0 && iField < psDBF->nFields ) return psDBF->pachFieldType[iField]; return ' '; } /************************************************************************/ /* str_to_upper() */ /************************************************************************/ static void str_to_upper (char *string) { int len; short i = -1; len = strlen (string); while (++i < len) if (isalpha(string[i]) && islower(string[i])) string[i] = (char) toupper ((int)string[i]); } /************************************************************************/ /* DBFGetFieldIndex() */ /* */ /* Get the index number for a field in a .dbf file. */ /* */ /* Contributed by Jim Matthews. */ /************************************************************************/ int SHPAPI_CALL DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) { char name[12], name1[12], name2[12]; int i; strncpy(name1, pszFieldName,11); name1[11] = '\0'; str_to_upper(name1); for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) { DBFGetFieldInfo( psDBF, i, name, NULL, NULL ); strncpy(name2,name,11); str_to_upper(name2); if(!strncmp(name1,name2,10)) return(i); } return(-1); } /************************************************************************/ /* DBFIsRecordDeleted() */ /* */ /* Returns TRUE if the indicated record is deleted, otherwise */ /* it returns FALSE. */ /************************************************************************/ int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape ) { /* -------------------------------------------------------------------- */ /* Verify selection. */ /* -------------------------------------------------------------------- */ if( iShape < 0 || iShape >= psDBF->nRecords ) return TRUE; /* -------------------------------------------------------------------- */ /* Have we read the record? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, iShape ) ) return FALSE; /* -------------------------------------------------------------------- */ /* '*' means deleted. */ /* -------------------------------------------------------------------- */ return psDBF->pszCurrentRecord[0] == '*'; } /************************************************************************/ /* DBFMarkRecordDeleted() */ /************************************************************************/ int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape, int bIsDeleted ) { char chNewFlag; /* -------------------------------------------------------------------- */ /* Verify selection. */ /* -------------------------------------------------------------------- */ if( iShape < 0 || iShape >= psDBF->nRecords ) return FALSE; /* -------------------------------------------------------------------- */ /* Is this an existing record, but different than the last one */ /* we accessed? */ /* -------------------------------------------------------------------- */ if( !DBFLoadRecord( psDBF, iShape ) ) return FALSE; /* -------------------------------------------------------------------- */ /* Assign value, marking record as dirty if it changes. */ /* -------------------------------------------------------------------- */ if( bIsDeleted ) chNewFlag = '*'; else chNewFlag = ' '; if( psDBF->pszCurrentRecord[0] != chNewFlag ) { psDBF->bCurrentRecordModified = TRUE; psDBF->bUpdated = TRUE; psDBF->pszCurrentRecord[0] = chNewFlag; } return TRUE; } /************************************************************************/ /* DBFGetCodePage */ /************************************************************************/ const char SHPAPI_CALL1(*) DBFGetCodePage(DBFHandle psDBF ) { if( psDBF == NULL ) return NULL; return psDBF->pszCodePage; } /************************************************************************/ /* DBFDeleteField() */ /* */ /* Remove a field from a .dbf file */ /************************************************************************/ int SHPAPI_CALL DBFDeleteField(DBFHandle psDBF, int iField) { int nOldRecordLength, nOldHeaderLength; int nDeletedFieldOffset, nDeletedFieldSize; SAOffset nRecordOffset; char* pszRecord; int i, iRecord; if (iField < 0 || iField >= psDBF->nFields) return FALSE; /* make sure that everything is written in .dbf */ if( !DBFFlushRecord( psDBF ) ) return FALSE; /* get information about field to be deleted */ nOldRecordLength = psDBF->nRecordLength; nOldHeaderLength = psDBF->nHeaderLength; nDeletedFieldOffset = psDBF->panFieldOffset[iField]; nDeletedFieldSize = psDBF->panFieldSize[iField]; /* update fields info */ for (i = iField + 1; i < psDBF->nFields; i++) { psDBF->panFieldOffset[i-1] = psDBF->panFieldOffset[i] - nDeletedFieldSize; psDBF->panFieldSize[i-1] = psDBF->panFieldSize[i]; psDBF->panFieldDecimals[i-1] = psDBF->panFieldDecimals[i]; psDBF->pachFieldType[i-1] = psDBF->pachFieldType[i]; } /* resize fields arrays */ psDBF->nFields--; psDBF->panFieldOffset = (int *) SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); psDBF->panFieldSize = (int *) SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); psDBF->panFieldDecimals = (int *) SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); psDBF->pachFieldType = (char *) SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields ); /* update header information */ psDBF->nHeaderLength -= 32; psDBF->nRecordLength -= nDeletedFieldSize; /* overwrite field information in header */ memmove(psDBF->pszHeader + iField*32, psDBF->pszHeader + (iField+1)*32, sizeof(char) * (psDBF->nFields - iField)*32); psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32); /* update size of current record appropriately */ psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength); /* we're done if we're dealing with not yet created .dbf */ if ( psDBF->bNoHeader && psDBF->nRecords == 0 ) return TRUE; /* force update of header with new header and record length */ psDBF->bNoHeader = TRUE; DBFUpdateHeader( psDBF ); /* alloc record */ pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength); /* shift records to their new positions */ for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++) { nRecordOffset = nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength; /* load record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); nRecordOffset = psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* move record in two steps */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FWrite( pszRecord, nDeletedFieldOffset, 1, psDBF->fp ); psDBF->sHooks.FWrite( pszRecord + nDeletedFieldOffset + nDeletedFieldSize, nOldRecordLength - nDeletedFieldOffset - nDeletedFieldSize, 1, psDBF->fp ); } /* TODO: truncate file */ /* free record */ free(pszRecord); psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; return TRUE; } /************************************************************************/ /* DBFReorderFields() */ /* */ /* Reorder the fields of a .dbf file */ /* */ /* panMap must be exactly psDBF->nFields long and be a permutation */ /* of [0, psDBF->nFields-1]. This assumption will not be asserted in the*/ /* code of DBFReorderFields. */ /************************************************************************/ int SHPAPI_CALL DBFReorderFields( DBFHandle psDBF, int* panMap ) { SAOffset nRecordOffset; int i, iRecord; int *panFieldOffsetNew; int *panFieldSizeNew; int *panFieldDecimalsNew; char *pachFieldTypeNew; char *pszHeaderNew; char *pszRecord; char *pszRecordNew; if ( psDBF->nFields == 0 ) return TRUE; /* make sure that everything is written in .dbf */ if( !DBFFlushRecord( psDBF ) ) return FALSE; panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields); panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields); panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields); pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields); pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields); /* shuffle fields definitions */ for(i=0; i < psDBF->nFields; i++) { panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]]; panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]]; pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]]; memcpy(pszHeaderNew + i * 32, psDBF->pszHeader + panMap[i] * 32, 32); } panFieldOffsetNew[0] = 1; for(i=1; i < psDBF->nFields; i++) { panFieldOffsetNew[i] = panFieldOffsetNew[i - 1] + panFieldSizeNew[i - 1]; } free(psDBF->pszHeader); psDBF->pszHeader = pszHeaderNew; /* we're done if we're dealing with not yet created .dbf */ if ( !(psDBF->bNoHeader && psDBF->nRecords == 0) ) { /* force update of header with new header and record length */ psDBF->bNoHeader = TRUE; DBFUpdateHeader( psDBF ); /* alloc record */ pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength); pszRecordNew = (char *) malloc(sizeof(char) * psDBF->nRecordLength); /* shuffle fields in records */ for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++) { nRecordOffset = psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* load record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FRead( pszRecord, psDBF->nRecordLength, 1, psDBF->fp ); pszRecordNew[0] = pszRecord[0]; for(i=0; i < psDBF->nFields; i++) { memcpy(pszRecordNew + panFieldOffsetNew[i], pszRecord + psDBF->panFieldOffset[panMap[i]], psDBF->panFieldSize[panMap[i]]); } /* write record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FWrite( pszRecordNew, psDBF->nRecordLength, 1, psDBF->fp ); } /* free record */ free(pszRecord); free(pszRecordNew); } free(psDBF->panFieldOffset); free(psDBF->panFieldSize); free(psDBF->panFieldDecimals); free(psDBF->pachFieldType); psDBF->panFieldOffset = panFieldOffsetNew; psDBF->panFieldSize = panFieldSizeNew; psDBF->panFieldDecimals =panFieldDecimalsNew; psDBF->pachFieldType = pachFieldTypeNew; psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; return TRUE; } /************************************************************************/ /* DBFAlterFieldDefn() */ /* */ /* Alter a field definition in a .dbf file */ /************************************************************************/ int SHPAPI_CALL DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName, char chType, int nWidth, int nDecimals ) { int i; int iRecord; int nOffset; int nOldWidth; int nOldRecordLength; int nRecordOffset; char* pszFInfo; char chOldType; int bIsNULL; char chFieldFill; if (iField < 0 || iField >= psDBF->nFields) return FALSE; /* make sure that everything is written in .dbf */ if( !DBFFlushRecord( psDBF ) ) return FALSE; chFieldFill = DBFGetNullCharacter(chType); chOldType = psDBF->pachFieldType[iField]; nOffset = psDBF->panFieldOffset[iField]; nOldWidth = psDBF->panFieldSize[iField]; nOldRecordLength = psDBF->nRecordLength; /* -------------------------------------------------------------------- */ /* Do some checking to ensure we can add records to this file. */ /* -------------------------------------------------------------------- */ if( nWidth < 1 ) return -1; if( nWidth > 255 ) nWidth = 255; /* -------------------------------------------------------------------- */ /* Assign the new field information fields. */ /* -------------------------------------------------------------------- */ psDBF->panFieldSize[iField] = nWidth; psDBF->panFieldDecimals[iField] = nDecimals; psDBF->pachFieldType[iField] = chType; /* -------------------------------------------------------------------- */ /* Update the header information. */ /* -------------------------------------------------------------------- */ pszFInfo = psDBF->pszHeader + 32 * iField; for( i = 0; i < 32; i++ ) pszFInfo[i] = '\0'; if( (int) strlen(pszFieldName) < 10 ) strncpy( pszFInfo, pszFieldName, strlen(pszFieldName)); else strncpy( pszFInfo, pszFieldName, 10); pszFInfo[11] = psDBF->pachFieldType[iField]; if( chType == 'C' ) { pszFInfo[16] = (unsigned char) (nWidth % 256); pszFInfo[17] = (unsigned char) (nWidth / 256); } else { pszFInfo[16] = (unsigned char) nWidth; pszFInfo[17] = (unsigned char) nDecimals; } /* -------------------------------------------------------------------- */ /* Update offsets */ /* -------------------------------------------------------------------- */ if (nWidth != nOldWidth) { for (i = iField + 1; i < psDBF->nFields; i++) psDBF->panFieldOffset[i] += nWidth - nOldWidth; psDBF->nRecordLength += nWidth - nOldWidth; psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord, psDBF->nRecordLength); } /* we're done if we're dealing with not yet created .dbf */ if ( psDBF->bNoHeader && psDBF->nRecords == 0 ) return TRUE; /* force update of header with new header and record length */ psDBF->bNoHeader = TRUE; DBFUpdateHeader( psDBF ); if (nWidth < nOldWidth || (nWidth == nOldWidth && chType != chOldType)) { char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength); char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1)); pszOldField[nOldWidth] = 0; /* move records to their new positions */ for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++) { nRecordOffset = nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* load record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); memcpy(pszOldField, pszRecord + nOffset, nOldWidth); bIsNULL = DBFIsValueNULL( chOldType, pszOldField ); if (nWidth != nOldWidth) { if ((chOldType == 'N' || chOldType == 'F') && pszOldField[0] == ' ') { /* Strip leading spaces when truncating a numeric field */ memmove( pszRecord + nOffset, pszRecord + nOffset + nOldWidth - nWidth, nWidth ); } if (nOffset + nOldWidth < nOldRecordLength) { memmove( pszRecord + nOffset + nWidth, pszRecord + nOffset + nOldWidth, nOldRecordLength - (nOffset + nOldWidth)); } } /* Convert null value to the appropriate value of the new type */ if (bIsNULL) { memset( pszRecord + nOffset, chFieldFill, nWidth); } nRecordOffset = psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* write record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp ); } free(pszRecord); free(pszOldField); } else if (nWidth > nOldWidth) { char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength); char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1)); pszOldField[nOldWidth] = 0; /* move records to their new positions */ for (iRecord = psDBF->nRecords - 1; iRecord >= 0; iRecord--) { nRecordOffset = nOldRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* load record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp ); memcpy(pszOldField, pszRecord + nOffset, nOldWidth); bIsNULL = DBFIsValueNULL( chOldType, pszOldField ); if (nOffset + nOldWidth < nOldRecordLength) { memmove( pszRecord + nOffset + nWidth, pszRecord + nOffset + nOldWidth, nOldRecordLength - (nOffset + nOldWidth)); } /* Convert null value to the appropriate value of the new type */ if (bIsNULL) { memset( pszRecord + nOffset, chFieldFill, nWidth); } else { if ((chOldType == 'N' || chOldType == 'F')) { /* Add leading spaces when expanding a numeric field */ memmove( pszRecord + nOffset + nWidth - nOldWidth, pszRecord + nOffset, nOldWidth ); memset( pszRecord + nOffset, ' ', nWidth - nOldWidth ); } else { /* Add trailing spaces */ memset(pszRecord + nOffset + nOldWidth, ' ', nWidth - nOldWidth); } } nRecordOffset = psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength; /* write record */ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ); psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp ); } free(pszRecord); free(pszOldField); } psDBF->nCurrentRecord = -1; psDBF->bCurrentRecordModified = FALSE; return TRUE; } shapelib-1.3.0/README.tree0000640042715500116100000001547006720341344014447 0ustar warmerdamengVenkat, I have completed the planned Shapefile quadtree mechanism. The additions to the traditional Shapelib are found in shptree.c (functions supporting quad tree searching and query). There are also some new prototypes for the tree stuff in shapefil.h ... including some prototypes for functions you don't require and hence that I haven't implemented at this time. I have also prepared a demonstration program using the API. That is the ``shpdumptree'' program, with the source code in shpdumptree.c. The shpdumptree program has two functions. One is to dump an ASCII rendering of the internal quadtree, and the other is example use of a quad tree searching function. Dumping the Tree ---------------- The tree dumping is done as shown below. The "-maxdepth" commandline switch can be used to control the maximum depth, otherwise it internally computes a ``reasonable depth'' to use based on the number of structures in the shapefile. warmerda@gdal[207]% shptreedump -maxdepth 6 eg_data/polygon.shp ( SHPTreeNode Min = (471127.19,4751545.00) Max = (489292.31,4765610.50) Shapes(0): ( SHPTreeNode Min = (471127.19,4751545.00) Max = (481118.01,4765610.50) Shapes(0): ( SHPTreeNode Min = (471127.19,4751545.00) Max = (481118.01,4759281.03) Shapes(0): ( SHPTreeNode Min = (471127.19,4751545.00) Max = (476622.14,4759281.03) Shapes(0): ( SHPTreeNode Min = (471127.19,4751545.00) Max = (476622.14,4755799.81) Shapes(0): ( SHPTreeNode Min = (471127.19,4751545.00) Max = (474149.41,4755799.81) Shapes(6): 395 397 402 404 405 422 ) ( SHPTreeNode Min = (473599.92,4751545.00) Max = (476622.14,4755799.81) Shapes(10): 392 394 403 413 414 417 426 433 434 447 ) ) ... A structure like the following represents one node in the tree. In this case it cover the region of 473599.92 < X < 476622.14,and 4751545.0 < Y < 4755799.81. There are ten shapes within this region who's shapeids are 392, 394 ... 447. This node has no children nodes. ( SHPTreeNode Min = (473599.92,4751545.00) Max = (476622.14,4755799.81) Shapes(10): 392 394 403 413 414 417 426 433 434 447 ) The heirarchy of indentation is intended to show the parent, child relationship between nodes, with the tree being deeper the further to the right you go. The `-v' flag to the program can be used to expand the report to include the full information about shapes, not just their shapeid. This can result in a report looking more like this: ... ( SHPTreeNode Min = (478095.78,4751545.00) Max = (481118.01,4755799.81) Shapes(3): ( Shape ShapeId = 448 Min = (479988.09,4753300.00) Max = (480705.59,4754236.50) Vertex[0] = (480136.59,4754174.50) Vertex[1] = (480229.97,4754182.00) Vertex[2] = (480370.09,4754200.50) Vertex[3] = (480695.12,4754236.50) Vertex[4] = (480687.97,4754129.50) Vertex[5] = (480650.47,4754075.50) Vertex[6] = (480520.62,4753948.00) Vertex[7] = (480490.00,4753900.00) Vertex[8] = (480499.78,4753840.50) Vertex[9] = (480500.97,4753820.50) Vertex[10] = (480534.75,4753660.50) Vertex[11] = (480560.00,4753565.00) Vertex[12] = (480574.91,4753550.50) ... While it is possible to part the output of the shptreedump program, and insert it into your database, my intention was that the shptreedump program would serve as an example of how to pre-order traversal of the quad tree, and collect the information you will need to insert into your database. I would then expect you to write a new program based on shptreedump that calls a C API for your database to insert objects instead of printing them out. Alternatively there may be an ASCII format for loading tables that you could modify the program to output. Searching --------- The other thing that you can do with the shptreedump program is to perform a search on the quadtree. For instance the following shows searching on a small region. % shptreedump -search 471127 4751545 476622 4759281 eg_data/polygon.shp Shape 17: not in area of interest, but fetched. Shape 31: not in area of interest, but fetched. Shape 52: not in area of interest, but fetched. Shape 76: not in area of interest, but fetched. Shape 82: not in area of interest, but fetched. Shape 104: not in area of interest, but fetched. Shape 124: not in area of interest, but fetched. Shape 134: not in area of interest, but fetched. Shape 139: not in area of interest, but fetched. Shape 154: not in area of interest, but fetched. Shape 175: not in area of interest, but fetched. Shape 177: not in area of interest, but fetched. Shape 185: not in area of interest, but fetched. Shape 192: not in area of interest, but fetched. Shape 196: appears to be in area of interest. .... I have included this capability (and the SHPTreeFindLikelyShapes() function) so that you can see a working example of how to search this quad tree. Note that searching is a multi-stage affair. First a pass is made over the quadtree, collecting the shapeids of all shapes contained in a quadtree node for which the bounding rectangle overlaps the search rectangle. This is all accomplished by SHPTreeFindLikelyShapes() in shptree.c. The second phase is to fetch the actual shapes, and verify if their bounding box falls within the area of interest. This is necessary because the shape will tend to have a significantly smaller bounding rectangle than the tree node in which it is found. This can result ``false positives'' on the first phase search, as indicated by teh ``not in area of interest, but fetched'' messages above. This stage is done in the SHPTreeNodeSearchAndDump() function in shptreedump.c. A possible third phase is to verify that the actualy line segments in the shape actually cross the area of interest. I don't both with this as it is complicated, and assuming that the drawing engine takes care of clipping it is quite a bit easier to let it fall through. Building -------- I have added a makefile.vc to the shapelib distribution. After you have unpacked the shapefile you should have a shapelib subdirectory. If you cd to that directory, and enter ``nmake -f makefile.vc'' in a DOS window you should be able to build everything with VC++ (assuming it is properly installed and in your path). You can also create a project in VC just including the files shpopen.c, shptree.c and shptreedump.c, building as a Win32 console application. For your convenience I am including prebuild .obj files, and .exe files in the distribution. shapelib-1.3.0/shpadd.c0000640042715500116100000001625111407747220014237 0ustar warmerdameng/****************************************************************************** * $Id: shpadd.c,v 1.16 2010-06-21 20:41:52 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for adding a shape to a shapefile. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shpadd.c,v $ * Revision 1.16 2010-06-21 20:41:52 fwarmerdam * reformat white space * * Revision 1.15 2007-12-30 16:57:32 fwarmerdam * add support for z and m * * Revision 1.14 2004/09/26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.13 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.12 2001/05/31 19:35:29 warmerda * added support for writing null shapes * * Revision 1.11 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.10 2000/05/24 15:09:22 warmerda * Added logic to graw vertex lists of needed. * * Revision 1.9 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.8 1998/12/03 16:36:26 warmerda * Use r+b rather than rb+ for binary access. * * Revision 1.7 1998/11/09 20:57:04 warmerda * Fixed SHPGetInfo() call. * * Revision 1.6 1998/11/09 20:19:16 warmerda * Changed to use SHPObject based API. * * Revision 1.5 1997/03/06 14:05:02 warmerda * fixed typo. * * Revision 1.4 1997/03/06 14:01:16 warmerda * added memory allocation checking, and free()s. * * Revision 1.3 1995/10/21 03:14:37 warmerda * Changed to use binary file access * * Revision 1.2 1995/08/04 03:18:01 warmerda * Added header. * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: shpadd.c,v 1.16 2010-06-21 20:41:52 fwarmerdam Exp $") int main( int argc, char ** argv ) { SHPHandle hSHP; int nShapeType, nVertices, nParts, *panParts, i, nVMax; double *padfX, *padfY, *padfZ = NULL, *padfM = NULL; SHPObject *psObject; const char *tuple = ""; const char *filename; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc < 2 ) { printf( "shpadd shp_file [[x y] [+]]*\n" ); printf( " or\n" ); printf( "shpadd shp_file -m [[x y m] [+]]*\n" ); printf( " or\n" ); printf( "shpadd shp_file -z [[x y z] [+]]*\n" ); printf( " or\n" ); printf( "shpadd shp_file -zm [[x y z m] [+]]*\n" ); exit( 1 ); } filename = argv[1]; argv++; argc--; /* -------------------------------------------------------------------- */ /* Check for tuple description options. */ /* -------------------------------------------------------------------- */ if( argc > 1 && (strcmp(argv[1],"-z") == 0 || strcmp(argv[1],"-m") == 0 || strcmp(argv[1],"-zm") == 0) ) { tuple = argv[1] + 1; argv++; argc--; } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( filename, "r+b" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", filename ); exit( 1 ); } SHPGetInfo( hSHP, NULL, &nShapeType, NULL, NULL ); if( argc == 1 ) nShapeType = SHPT_NULL; /* -------------------------------------------------------------------- */ /* Build a vertex/part list from the command line arguments. */ /* -------------------------------------------------------------------- */ nVMax = 1000; padfX = (double *) malloc(sizeof(double) * nVMax); padfY = (double *) malloc(sizeof(double) * nVMax); if( strchr(tuple,'z') ) padfZ = (double *) malloc(sizeof(double) * nVMax); if( strchr(tuple,'m') ) padfM = (double *) malloc(sizeof(double) * nVMax); nVertices = 0; if( (panParts = (int *) malloc(sizeof(int) * 1000 )) == NULL ) { printf( "Out of memory\n" ); exit( 1 ); } nParts = 1; panParts[0] = 0; for( i = 1; i < argc; ) { if( argv[i][0] == '+' ) { panParts[nParts++] = nVertices; i++; } else if( i < argc-1-strlen(tuple) ) { if( nVertices == nVMax ) { nVMax = nVMax * 2; padfX = (double *) realloc(padfX,sizeof(double)*nVMax); padfY = (double *) realloc(padfY,sizeof(double)*nVMax); if( padfZ ) padfZ = (double *) realloc(padfZ,sizeof(double)*nVMax); if( padfM ) padfM = (double *) realloc(padfM,sizeof(double)*nVMax); } sscanf( argv[i++], "%lg", padfX+nVertices ); sscanf( argv[i++], "%lg", padfY+nVertices ); if( padfZ ) sscanf( argv[i++], "%lg", padfZ+nVertices ); if( padfM ) sscanf( argv[i++], "%lg", padfM+nVertices ); nVertices += 1; } } /* -------------------------------------------------------------------- */ /* Write the new entity to the shape file. */ /* -------------------------------------------------------------------- */ psObject = SHPCreateObject( nShapeType, -1, nParts, panParts, NULL, nVertices, padfX, padfY, padfZ, padfM ); SHPWriteObject( hSHP, -1, psObject ); SHPDestroyObject( psObject ); SHPClose( hSHP ); free( panParts ); free( padfX ); free( padfY ); free( padfZ ); free( padfM ); return 0; } shapelib-1.3.0/stream2.out0000640042715500116100000003176211612705752014744 0ustar warmerdameng----------------------------------------------------------------------- Test 2/0 ----------------------------------------------------------------------- Shapefile Type: NullShape # of Shapes: 2 File Bounds: (0,0,0,0) to (10,20,0,0) Shape:0 (NullShape) nVertices=0, nParts=0 Bounds:(0,0, 0) to (0,0, 0) Shape:1 (NullShape) nVertices=0, nParts=0 Bounds:(0,0, 0) to (0,0, 0) ----------------------------------------------------------------------- Test 2/1 ----------------------------------------------------------------------- Shapefile Type: Point # of Shapes: 2 File Bounds: (1,2,0,0) to (10,20,0,0) Shape:0 (Point) nVertices=1, nParts=0 Bounds:(1,2, 0) to (1,2, 0) (1,2, 0) Shape:1 (Point) nVertices=1, nParts=0 Bounds:(10,20, 0) to (10,20, 0) (10,20, 0) ----------------------------------------------------------------------- Test 2/2 ----------------------------------------------------------------------- Shapefile Type: PointZ # of Shapes: 2 File Bounds: (1,2,3,4) to (10,20,30,40) Shape:0 (PointZ) nVertices=1, nParts=0 Bounds:(1,2, 3, 4) to (1,2, 3, 4) (1,2, 3, 4) Shape:1 (PointZ) nVertices=1, nParts=0 Bounds:(10,20, 30, 40) to (10,20, 30, 40) (10,20, 30, 40) ----------------------------------------------------------------------- Test 2/3 ----------------------------------------------------------------------- Shapefile Type: PointM # of Shapes: 2 File Bounds: (1,2,0,4) to (10,20,0,40) Shape:0 (PointM) nVertices=1, nParts=0 Bounds:(1,2, 0, 4) to (1,2, 0, 4) (1,2, 0, 4) Shape:1 (PointM) nVertices=1, nParts=0 Bounds:(10,20, 0, 40) to (10,20, 0, 40) (10,20, 0, 40) ----------------------------------------------------------------------- Test 2/4 ----------------------------------------------------------------------- Shapefile Type: MultiPoint # of Shapes: 3 File Bounds: (1.15,2.25,0,0) to (24.15,25.25,0,0) Shape:0 (MultiPoint) nVertices=4, nParts=0 Bounds:(1.15,2.25, 0) to (4.15,5.25, 0) (1.15,2.25, 0) (2.15,3.25, 0) (3.15,4.25, 0) (4.15,5.25, 0) Shape:1 (MultiPoint) nVertices=4, nParts=0 Bounds:(11.15,12.25, 0) to (14.15,15.25, 0) (11.15,12.25, 0) (12.15,13.25, 0) (13.15,14.25, 0) (14.15,15.25, 0) Shape:2 (MultiPoint) nVertices=4, nParts=0 Bounds:(21.15,22.25, 0) to (24.15,25.25, 0) (21.15,22.25, 0) (22.15,23.25, 0) (23.15,24.25, 0) (24.15,25.25, 0) ----------------------------------------------------------------------- Test 2/5 ----------------------------------------------------------------------- Shapefile Type: MultiPointZ # of Shapes: 3 File Bounds: (1.15,2.25,3.35,4.45) to (24.15,25.25,26.35,27.45) Shape:0 (MultiPointZ) nVertices=4, nParts=0 Bounds:(1.15,2.25, 3.35, 4.45) to (4.15,5.25, 6.35, 7.45) (1.15,2.25, 3.35, 4.45) (2.15,3.25, 4.35, 5.45) (3.15,4.25, 5.35, 6.45) (4.15,5.25, 6.35, 7.45) Shape:1 (MultiPointZ) nVertices=4, nParts=0 Bounds:(11.15,12.25, 13.35, 14.45) to (14.15,15.25, 16.35, 17.45) (11.15,12.25, 13.35, 14.45) (12.15,13.25, 14.35, 15.45) (13.15,14.25, 15.35, 16.45) (14.15,15.25, 16.35, 17.45) Shape:2 (MultiPointZ) nVertices=4, nParts=0 Bounds:(21.15,22.25, 23.35, 24.45) to (24.15,25.25, 26.35, 27.45) (21.15,22.25, 23.35, 24.45) (22.15,23.25, 24.35, 25.45) (23.15,24.25, 25.35, 26.45) (24.15,25.25, 26.35, 27.45) ----------------------------------------------------------------------- Test 2/6 ----------------------------------------------------------------------- Shapefile Type: MultiPointM # of Shapes: 3 File Bounds: (1.15,2.25,0,4.45) to (24.15,25.25,0,27.45) Shape:0 (MultiPointM) nVertices=4, nParts=0 Bounds:(1.15,2.25, 0, 4.45) to (4.15,5.25, 0, 7.45) (1.15,2.25, 0, 4.45) (2.15,3.25, 0, 5.45) (3.15,4.25, 0, 6.45) (4.15,5.25, 0, 7.45) Shape:1 (MultiPointM) nVertices=4, nParts=0 Bounds:(11.15,12.25, 0, 14.45) to (14.15,15.25, 0, 17.45) (11.15,12.25, 0, 14.45) (12.15,13.25, 0, 15.45) (13.15,14.25, 0, 16.45) (14.15,15.25, 0, 17.45) Shape:2 (MultiPointM) nVertices=4, nParts=0 Bounds:(21.15,22.25, 0, 24.45) to (24.15,25.25, 0, 27.45) (21.15,22.25, 0, 24.45) (22.15,23.25, 0, 25.45) (23.15,24.25, 0, 26.45) (24.15,25.25, 0, 27.45) ----------------------------------------------------------------------- Test 2/7 ----------------------------------------------------------------------- Shapefile Type: Arc # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,0,0) Shape:0 (Arc) nVertices=5, nParts=1 Bounds:(1,1, 0) to (2,2, 0) (1,1, 0) Ring (2,1, 0) (2,2, 0) (1,2, 0) (1,1, 0) Shape:1 (Arc) nVertices=5, nParts=1 Bounds:(1,4, 0) to (2,5, 0) (1,4, 0) Ring (2,4, 0) (2,5, 0) (1,5, 0) (1,4, 0) Shape:2 (Arc) nVertices=5, nParts=1 Bounds:(1,7, 0) to (2,8, 0) (1,7, 0) Ring (2,7, 0) (2,8, 0) (1,8, 0) (1,7, 0) Shape:3 (Arc) nVertices=15, nParts=3 Bounds:(0,0, 0) to (100,100, 0) (0,0, 0) Ring (0,100, 0) (100,100, 0) (100,0, 0) (0,0, 0) + (10,20, 0) Ring (30,20, 0) (30,40, 0) (10,40, 0) (10,20, 0) + (60,20, 0) Ring (90,20, 0) (90,40, 0) (60,40, 0) (60,20, 0) ----------------------------------------------------------------------- Test 2/8 ----------------------------------------------------------------------- Shapefile Type: ArcZ # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,27.35,28.45) Shape:0 (ArcZ) nVertices=5, nParts=1 Bounds:(1,1, 3.35, 4.45) to (2,2, 7.35, 8.45) (1,1, 3.35, 4.45) Ring (2,1, 4.35, 5.45) (2,2, 5.35, 6.45) (1,2, 6.35, 7.45) (1,1, 7.35, 8.45) Shape:1 (ArcZ) nVertices=5, nParts=1 Bounds:(1,4, 13.35, 14.45) to (2,5, 17.35, 18.45) (1,4, 13.35, 14.45) Ring (2,4, 14.35, 15.45) (2,5, 15.35, 16.45) (1,5, 16.35, 17.45) (1,4, 17.35, 18.45) Shape:2 (ArcZ) nVertices=5, nParts=1 Bounds:(1,7, 23.35, 24.45) to (2,8, 27.35, 28.45) (1,7, 23.35, 24.45) Ring (2,7, 24.35, 25.45) (2,8, 25.35, 26.45) (1,8, 26.35, 27.45) (1,7, 27.35, 28.45) Shape:3 (ArcZ) nVertices=15, nParts=3 Bounds:(0,0, 0, 0) to (100,100, 14, 28) (0,0, 0, 0) Ring (0,100, 1, 2) (100,100, 2, 4) (100,0, 3, 6) (0,0, 4, 8) + (10,20, 5, 10) Ring (30,20, 6, 12) (30,40, 7, 14) (10,40, 8, 16) (10,20, 9, 18) + (60,20, 10, 20) Ring (90,20, 11, 22) (90,40, 12, 24) (60,40, 13, 26) (60,20, 14, 28) ----------------------------------------------------------------------- Test 2/9 ----------------------------------------------------------------------- Shapefile Type: ArcM # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,0,28.45) Shape:0 (ArcM) nVertices=5, nParts=1 Bounds:(1,1, 0, 4.45) to (2,2, 0, 8.45) (1,1, 0, 4.45) Ring (2,1, 0, 5.45) (2,2, 0, 6.45) (1,2, 0, 7.45) (1,1, 0, 8.45) Shape:1 (ArcM) nVertices=5, nParts=1 Bounds:(1,4, 0, 14.45) to (2,5, 0, 18.45) (1,4, 0, 14.45) Ring (2,4, 0, 15.45) (2,5, 0, 16.45) (1,5, 0, 17.45) (1,4, 0, 18.45) Shape:2 (ArcM) nVertices=5, nParts=1 Bounds:(1,7, 0, 24.45) to (2,8, 0, 28.45) (1,7, 0, 24.45) Ring (2,7, 0, 25.45) (2,8, 0, 26.45) (1,8, 0, 27.45) (1,7, 0, 28.45) Shape:3 (ArcM) nVertices=15, nParts=3 Bounds:(0,0, 0, 0) to (100,100, 0, 28) (0,0, 0, 0) Ring (0,100, 0, 2) (100,100, 0, 4) (100,0, 0, 6) (0,0, 0, 8) + (10,20, 0, 10) Ring (30,20, 0, 12) (30,40, 0, 14) (10,40, 0, 16) (10,20, 0, 18) + (60,20, 0, 20) Ring (90,20, 0, 22) (90,40, 0, 24) (60,40, 0, 26) (60,20, 0, 28) ----------------------------------------------------------------------- Test 2/10 ----------------------------------------------------------------------- Shapefile Type: Polygon # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,0,0) Shape:0 (Polygon) nVertices=5, nParts=1 Bounds:(1,1, 0) to (2,2, 0) (1,1, 0) Ring (2,1, 0) (2,2, 0) (1,2, 0) (1,1, 0) Shape:1 (Polygon) nVertices=5, nParts=1 Bounds:(1,4, 0) to (2,5, 0) (1,4, 0) Ring (2,4, 0) (2,5, 0) (1,5, 0) (1,4, 0) Shape:2 (Polygon) nVertices=5, nParts=1 Bounds:(1,7, 0) to (2,8, 0) (1,7, 0) Ring (2,7, 0) (2,8, 0) (1,8, 0) (1,7, 0) Shape:3 (Polygon) nVertices=15, nParts=3 Bounds:(0,0, 0) to (100,100, 0) (0,0, 0) Ring (0,100, 0) (100,100, 0) (100,0, 0) (0,0, 0) + (10,20, 0) Ring (30,20, 0) (30,40, 0) (10,40, 0) (10,20, 0) + (60,20, 0) Ring (90,20, 0) (90,40, 0) (60,40, 0) (60,20, 0) ----------------------------------------------------------------------- Test 2/11 ----------------------------------------------------------------------- Shapefile Type: PolygonZ # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,27.35,28.45) Shape:0 (PolygonZ) nVertices=5, nParts=1 Bounds:(1,1, 3.35, 4.45) to (2,2, 7.35, 8.45) (1,1, 3.35, 4.45) Ring (2,1, 4.35, 5.45) (2,2, 5.35, 6.45) (1,2, 6.35, 7.45) (1,1, 7.35, 8.45) Shape:1 (PolygonZ) nVertices=5, nParts=1 Bounds:(1,4, 13.35, 14.45) to (2,5, 17.35, 18.45) (1,4, 13.35, 14.45) Ring (2,4, 14.35, 15.45) (2,5, 15.35, 16.45) (1,5, 16.35, 17.45) (1,4, 17.35, 18.45) Shape:2 (PolygonZ) nVertices=5, nParts=1 Bounds:(1,7, 23.35, 24.45) to (2,8, 27.35, 28.45) (1,7, 23.35, 24.45) Ring (2,7, 24.35, 25.45) (2,8, 25.35, 26.45) (1,8, 26.35, 27.45) (1,7, 27.35, 28.45) Shape:3 (PolygonZ) nVertices=15, nParts=3 Bounds:(0,0, 0, 0) to (100,100, 14, 28) (0,0, 0, 0) Ring (0,100, 1, 2) (100,100, 2, 4) (100,0, 3, 6) (0,0, 4, 8) + (10,20, 5, 10) Ring (30,20, 6, 12) (30,40, 7, 14) (10,40, 8, 16) (10,20, 9, 18) + (60,20, 10, 20) Ring (90,20, 11, 22) (90,40, 12, 24) (60,40, 13, 26) (60,20, 14, 28) ----------------------------------------------------------------------- Test 2/12 ----------------------------------------------------------------------- Shapefile Type: PolygonM # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,0,28.45) Shape:0 (PolygonM) nVertices=5, nParts=1 Bounds:(1,1, 0, 4.45) to (2,2, 0, 8.45) (1,1, 0, 4.45) Ring (2,1, 0, 5.45) (2,2, 0, 6.45) (1,2, 0, 7.45) (1,1, 0, 8.45) Shape:1 (PolygonM) nVertices=5, nParts=1 Bounds:(1,4, 0, 14.45) to (2,5, 0, 18.45) (1,4, 0, 14.45) Ring (2,4, 0, 15.45) (2,5, 0, 16.45) (1,5, 0, 17.45) (1,4, 0, 18.45) Shape:2 (PolygonM) nVertices=5, nParts=1 Bounds:(1,7, 0, 24.45) to (2,8, 0, 28.45) (1,7, 0, 24.45) Ring (2,7, 0, 25.45) (2,8, 0, 26.45) (1,8, 0, 27.45) (1,7, 0, 28.45) Shape:3 (PolygonM) nVertices=15, nParts=3 Bounds:(0,0, 0, 0) to (100,100, 0, 28) (0,0, 0, 0) Ring (0,100, 0, 2) (100,100, 0, 4) (100,0, 0, 6) (0,0, 0, 8) + (10,20, 0, 10) Ring (30,20, 0, 12) (30,40, 0, 14) (10,40, 0, 16) (10,20, 0, 18) + (60,20, 0, 20) Ring (90,20, 0, 22) (90,40, 0, 24) (60,40, 0, 26) (60,20, 0, 28) ----------------------------------------------------------------------- Test 2/13 ----------------------------------------------------------------------- Shapefile Type: MultiPatch # of Shapes: 4 File Bounds: (0,0,0,0) to (100,100,27.35,28.45) Shape:0 (MultiPatch) nVertices=5, nParts=1 Bounds:(1,1, 3.35) to (2,2, 7.35) (1,1, 3.35) Ring (2,1, 4.35) (2,2, 5.35) (1,2, 6.35) (1,1, 7.35) Shape:1 (MultiPatch) nVertices=5, nParts=1 Bounds:(1,4, 13.35) to (2,5, 17.35) (1,4, 13.35) Ring (2,4, 14.35) (2,5, 15.35) (1,5, 16.35) (1,4, 17.35) Shape:2 (MultiPatch) nVertices=5, nParts=1 Bounds:(1,7, 23.35) to (2,8, 27.35) (1,7, 23.35) Ring (2,7, 24.35) (2,8, 25.35) (1,8, 26.35) (1,7, 27.35) Shape:3 (MultiPatch) nVertices=15, nParts=3 Bounds:(0,0, 0) to (100,100, 14) (0,0, 0) Ring (0,100, 1) (100,100, 2) (100,0, 3) (0,0, 4) + (10,20, 5) InnerRing (30,20, 6) (30,40, 7) (10,40, 8) (10,20, 9) + (60,20, 10) InnerRing (90,20, 11) (90,40, 12) (60,40, 13) (60,20, 14) shapelib-1.3.0/shptreedump.c0000640042715500116100000003725710166343565015352 0ustar warmerdameng/****************************************************************************** * $Id: shptreedump.c,v 1.8 2005-01-03 22:30:13 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Mainline for creating and dumping an ASCII representation of * a quadtree. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: shptreedump.c,v $ * Revision 1.8 2005-01-03 22:30:13 fwarmerdam * added support for saved quadtrees * * Revision 1.7 2002/04/10 16:59:12 warmerda * fixed email * * Revision 1.6 1999/11/05 14:12:05 warmerda * updated license terms * * Revision 1.5 1999/06/02 18:24:21 warmerda * added trimming code * * Revision 1.4 1999/06/02 17:56:12 warmerda * added quad'' subnode support for trees * * Revision 1.3 1999/05/18 19:13:13 warmerda * Use fabs() instead of abs(). * * Revision 1.2 1999/05/18 19:11:11 warmerda * Added example searching capability * * Revision 1.1 1999/05/18 17:49:20 warmerda * New * */ #include "shapefil.h" #include #include #include #include SHP_CVSID("$Id: shptreedump.c,v 1.8 2005-01-03 22:30:13 fwarmerdam Exp $") static void SHPTreeNodeDump( SHPTree *, SHPTreeNode *, const char *, int ); static void SHPTreeNodeSearchAndDump( SHPTree *, double *, double * ); /************************************************************************/ /* Usage() */ /************************************************************************/ static void Usage() { printf( "shptreedump [-maxdepth n] [-search xmin ymin xmax ymax]\n" " [-v] [-o indexfilename] [-i indexfilename]\n" " shp_file\n" ); exit( 1 ); } /************************************************************************/ /* main() */ /************************************************************************/ int main( int argc, char ** argv ) { SHPHandle hSHP; SHPTree *psTree; int nExpandShapes = 0; int nMaxDepth = 0; int bDoSearch = 0; double adfSearchMin[4], adfSearchMax[4]; const char *pszOutputIndexFilename = NULL; const char *pszInputIndexFilename = NULL; const char *pszTargetFile = NULL; /* -------------------------------------------------------------------- */ /* Consume flags. */ /* -------------------------------------------------------------------- */ while( argc > 1 ) { if( strcmp(argv[1],"-v") == 0 ) { nExpandShapes = 1; argv++; argc--; } else if( strcmp(argv[1],"-maxdepth") == 0 && argc > 2 ) { nMaxDepth = atoi(argv[2]); argv += 2; argc -= 2; } else if( strcmp(argv[1],"-o") == 0 && argc > 2 ) { pszOutputIndexFilename = argv[2]; argv += 2; argc -= 2; } else if( strcmp(argv[1],"-i") == 0 && argc > 2 ) { pszInputIndexFilename = argv[2]; argv += 2; argc -= 2; } else if( strcmp(argv[1],"-search") == 0 && argc > 5 ) { bDoSearch = 1; adfSearchMin[0] = atof(argv[2]); adfSearchMin[1] = atof(argv[3]); adfSearchMax[0] = atof(argv[4]); adfSearchMax[1] = atof(argv[5]); adfSearchMin[2] = adfSearchMax[2] = 0.0; adfSearchMin[3] = adfSearchMax[3] = 0.0; if( adfSearchMin[0] > adfSearchMax[0] || adfSearchMin[1] > adfSearchMax[1] ) { printf( "Min greater than max in search criteria.\n" ); Usage(); } argv += 5; argc -= 5; } else if( pszTargetFile == NULL ) { pszTargetFile = argv[1]; argv++; argc--; } else { printf( "Unrecognised argument: %s\n", argv[1] ); Usage(); } } /* -------------------------------------------------------------------- */ /* Do a search with an existing index file? */ /* -------------------------------------------------------------------- */ if( bDoSearch && pszInputIndexFilename != NULL ) { FILE *fp = fopen( pszInputIndexFilename, "rb" ); int *panResult, nResultCount = 0, iResult; if( fp == NULL ) { perror( pszInputIndexFilename ); exit( 1 ); } panResult = SHPSearchDiskTree( fp, adfSearchMin, adfSearchMax, &nResultCount ); printf( "Result: " ); for( iResult = 0; iResult < nResultCount; iResult++ ) printf( "%d ", panResult[iResult] ); printf( "\n" ); free( panResult ); fclose( fp ); exit( 0 ); } /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( pszTargetFile == NULL ) { Usage(); } /* -------------------------------------------------------------------- */ /* Open the passed shapefile. */ /* -------------------------------------------------------------------- */ hSHP = SHPOpen( pszTargetFile, "rb" ); if( hSHP == NULL ) { printf( "Unable to open:%s\n", pszTargetFile ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Build a quadtree structure for this file. */ /* -------------------------------------------------------------------- */ psTree = SHPCreateTree( hSHP, 2, nMaxDepth, NULL, NULL ); /* -------------------------------------------------------------------- */ /* Trim unused nodes from the tree. */ /* -------------------------------------------------------------------- */ SHPTreeTrimExtraNodes( psTree ); /* -------------------------------------------------------------------- */ /* Dump tree to .qix file. */ /* -------------------------------------------------------------------- */ if( pszOutputIndexFilename != NULL ) { SHPWriteTree( psTree, pszOutputIndexFilename ); } /* -------------------------------------------------------------------- */ /* Dump tree by recursive descent. */ /* -------------------------------------------------------------------- */ else if( !bDoSearch ) SHPTreeNodeDump( psTree, psTree->psRoot, "", nExpandShapes ); /* -------------------------------------------------------------------- */ /* or do a search instead. */ /* -------------------------------------------------------------------- */ else SHPTreeNodeSearchAndDump( psTree, adfSearchMin, adfSearchMax ); /* -------------------------------------------------------------------- */ /* cleanup */ /* -------------------------------------------------------------------- */ SHPDestroyTree( psTree ); SHPClose( hSHP ); #ifdef USE_DBMALLOC malloc_dump(2); #endif exit( 0 ); } /************************************************************************/ /* EmitCoordinate() */ /************************************************************************/ static void EmitCoordinate( double * padfCoord, int nDimension ) { const char *pszFormat; if( fabs(padfCoord[0]) < 180 && fabs(padfCoord[1]) < 180 ) pszFormat = "%.9f"; else pszFormat = "%.2f"; printf( pszFormat, padfCoord[0] ); printf( "," ); printf( pszFormat, padfCoord[1] ); if( nDimension > 2 ) { printf( "," ); printf( pszFormat, padfCoord[2] ); } if( nDimension > 3 ) { printf( "," ); printf( pszFormat, padfCoord[3] ); } } /************************************************************************/ /* EmitShape() */ /************************************************************************/ static void EmitShape( SHPObject * psObject, const char * pszPrefix, int nDimension ) { int i; printf( "%s( Shape\n", pszPrefix ); printf( "%s ShapeId = %d\n", pszPrefix, psObject->nShapeId ); printf( "%s Min = (", pszPrefix ); EmitCoordinate( &(psObject->dfXMin), nDimension ); printf( ")\n" ); printf( "%s Max = (", pszPrefix ); EmitCoordinate( &(psObject->dfXMax), nDimension ); printf( ")\n" ); for( i = 0; i < psObject->nVertices; i++ ) { double adfVertex[4]; printf( "%s Vertex[%d] = (", pszPrefix, i ); adfVertex[0] = psObject->padfX[i]; adfVertex[1] = psObject->padfY[i]; adfVertex[2] = psObject->padfZ[i]; adfVertex[3] = psObject->padfM[i]; EmitCoordinate( adfVertex, nDimension ); printf( ")\n" ); } printf( "%s)\n", pszPrefix ); } /************************************************************************/ /* SHPTreeNodeDump() */ /* */ /* Dump a tree node in a readable form. */ /************************************************************************/ static void SHPTreeNodeDump( SHPTree * psTree, SHPTreeNode * psTreeNode, const char * pszPrefix, int nExpandShapes ) { char szNextPrefix[150]; int i; strcpy( szNextPrefix, pszPrefix ); if( strlen(pszPrefix) < sizeof(szNextPrefix) - 3 ) strcat( szNextPrefix, " " ); printf( "%s( SHPTreeNode\n", pszPrefix ); /* -------------------------------------------------------------------- */ /* Emit the bounds. */ /* -------------------------------------------------------------------- */ printf( "%s Min = (", pszPrefix ); EmitCoordinate( psTreeNode->adfBoundsMin, psTree->nDimension ); printf( ")\n" ); printf( "%s Max = (", pszPrefix ); EmitCoordinate( psTreeNode->adfBoundsMax, psTree->nDimension ); printf( ")\n" ); /* -------------------------------------------------------------------- */ /* Emit the list of shapes on this node. */ /* -------------------------------------------------------------------- */ if( nExpandShapes ) { printf( "%s Shapes(%d):\n", pszPrefix, psTreeNode->nShapeCount ); for( i = 0; i < psTreeNode->nShapeCount; i++ ) { SHPObject *psObject; psObject = SHPReadObject( psTree->hSHP, psTreeNode->panShapeIds[i] ); assert( psObject != NULL ); if( psObject != NULL ) { EmitShape( psObject, szNextPrefix, psTree->nDimension ); } SHPDestroyObject( psObject ); } } else { printf( "%s Shapes(%d): ", pszPrefix, psTreeNode->nShapeCount ); for( i = 0; i < psTreeNode->nShapeCount; i++ ) { printf( "%d ", psTreeNode->panShapeIds[i] ); } printf( "\n" ); } /* -------------------------------------------------------------------- */ /* Emit subnodes. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( psTreeNode->apsSubNode[i] != NULL ) SHPTreeNodeDump( psTree, psTreeNode->apsSubNode[i], szNextPrefix, nExpandShapes ); } printf( "%s)\n", pszPrefix ); return; } /************************************************************************/ /* SHPTreeNodeSearchAndDump() */ /************************************************************************/ static void SHPTreeNodeSearchAndDump( SHPTree * hTree, double *padfBoundsMin, double *padfBoundsMax ) { int *panHits, nShapeCount, i; /* -------------------------------------------------------------------- */ /* Perform the search for likely candidates. These are shapes */ /* that fall into a tree node whose bounding box intersects our */ /* area of interest. */ /* -------------------------------------------------------------------- */ panHits = SHPTreeFindLikelyShapes( hTree, padfBoundsMin, padfBoundsMax, &nShapeCount ); /* -------------------------------------------------------------------- */ /* Read all of these shapes, and establish whether the shape's */ /* bounding box actually intersects the area of interest. Note */ /* that the bounding box could intersect the area of interest, */ /* and the shape itself still not cross it but we don't try to */ /* address that here. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nShapeCount; i++ ) { SHPObject *psObject; psObject = SHPReadObject( hTree->hSHP, panHits[i] ); if( psObject == NULL ) continue; if( !SHPCheckBoundsOverlap( padfBoundsMin, padfBoundsMax, &(psObject->dfXMin), &(psObject->dfXMax), hTree->nDimension ) ) { printf( "Shape %d: not in area of interest, but fetched.\n", panHits[i] ); } else { printf( "Shape %d: appears to be in area of interest.\n", panHits[i] ); } SHPDestroyObject( psObject ); } if( nShapeCount == 0 ) printf( "No shapes found in search.\n" ); } shapelib-1.3.0/shapelib.def0000640042715500116100000000152110357072777015104 0ustar warmerdamengLIBRARY shapelib EXPORTS SHPOpen SHPCreate SHPGetInfo SHPReadObject SHPWriteObject SHPDestroyObject SHPComputeExtents SHPCreateObject SHPCreateSimpleObject SHPClose SHPWriteHeader SHPTypeName SHPPartTypeName SHPCreateTree SHPDestroyTree SHPTreeAddShapeId SHPTreeTrimExtraNodes SHPTreeFindLikelyShapes SHPCheckBoundsOverlap DBFOpen DBFCreate DBFGetFieldCount DBFGetRecordCount DBFAddField DBFGetFieldInfo DBFReadIntegerAttribute DBFReadDoubleAttribute DBFReadStringAttribute DBFWriteIntegerAttribute DBFWriteDoubleAttribute DBFWriteStringAttribute DBFReadTuple DBFWriteTuple DBFCloneEmpty DBFClose DBFWriteNULLAttribute DBFGetFieldIndex DBFIsAttributeNULL DBFWriteLogicalAttribute DBFReadLogicalAttribute DBFUpdateHeader DBFGetNativeFieldType SHPRewindObject DBFIsRecordDeleted DBFMarkRecordDeleted shapelib-1.3.0/mkdist.sh0000750042715500116100000000123710770506436014463 0ustar warmerdameng#!/bin/sh if [ $# -lt 1 ] ; then echo "Usage: mkdist.sh " echo " - version number used in name of generated archive." echo "Example: mkdist.sh 1.1.4" exit fi VERSION=$1 rm -rf dist_wrk mkdir dist_wrk cd dist_wrk REP=:pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot if cvs -d $REP co shapelib ; then echo checkout succeeds. else cvs -d $REP login cvs -d $REP co shapelib fi if [ ! -d shapelib ] ; then exit 1 fi mv shapelib shapelib-$VERSION find . -name CVS -type d -exec echo rm -rf {} \; tar czvf ../shapelib-$VERSION.tar.gz shapelib-$VERSION zip -r ../shapelib-$VERSION.zip shapelib-$VERSION cd .. rm -rf dist_wrk shapelib-1.3.0/dbfcreate.c0000640042715500116100000001012710125620777014712 0ustar warmerdameng/****************************************************************************** * $Id: dbfcreate.c,v 1.7 2004-09-26 20:09:35 fwarmerdam Exp $ * * Project: Shapelib * Purpose: Sample application for creating a new .dbf file. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * 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: dbfcreate.c,v $ * Revision 1.7 2004-09-26 20:09:35 fwarmerdam * avoid rcsid warnings * * Revision 1.6 2002/01/15 14:36:07 warmerda * updated email address * * Revision 1.5 2000/07/07 13:39:45 warmerda * removed unused variables, and added system include files * * Revision 1.4 1999/11/05 14:12:04 warmerda * updated license terms * * Revision 1.3 1999/04/01 18:47:44 warmerda * Fixed DBFAddField() call convention. * * Revision 1.2 1995/08/04 03:17:11 warmerda * Added header. * */ #include #include #include "shapefil.h" SHP_CVSID("$Id: dbfcreate.c,v 1.7 2004-09-26 20:09:35 fwarmerdam Exp $") int main( int argc, char ** argv ) { DBFHandle hDBF; int i; /* -------------------------------------------------------------------- */ /* Display a usage message. */ /* -------------------------------------------------------------------- */ if( argc < 2 ) { printf( "dbfcreate xbase_file [[-s field_name width],[-n field_name width decimals]]...\n" ); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Create the database. */ /* -------------------------------------------------------------------- */ hDBF = DBFCreate( argv[1] ); if( hDBF == NULL ) { printf( "DBFCreate(%s) failed.\n", argv[1] ); exit( 2 ); } /* -------------------------------------------------------------------- */ /* Loop over the field definitions adding new fields. */ /* -------------------------------------------------------------------- */ for( i = 2; i < argc; i++ ) { if( strcmp(argv[i],"-s") == 0 && i < argc-2 ) { if( DBFAddField( hDBF, argv[i+1], FTString, atoi(argv[i+2]), 0 ) == -1 ) { printf( "DBFAddField(%s,FTString,%d,0) failed.\n", argv[i+1], atoi(argv[i+2]) ); exit( 4 ); } i = i + 2; } else if( strcmp(argv[i],"-n") == 0 && i < argc-3 ) { if( DBFAddField( hDBF, argv[i+1], FTDouble, atoi(argv[i+2]), atoi(argv[i+3]) ) == -1 ) { printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n", argv[i+1], atoi(argv[i+2]), atoi(argv[i+3]) ); exit( 4 ); } i = i + 3; } else { printf( "Argument incomplete, or unrecognised:%s\n", argv[i] ); exit( 3 ); } } DBFClose( hDBF ); return( 0 ); }