From 5487e7e639b6870b42a1700ce4b4cc87858daaae Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 1 Dec 2003 20:52:00 +0000 Subject: [PATCH] shapelib put in sync with gdal cvs git-svn-id: http://svn.osgeo.org/postgis/trunk@398 b70326c6-7e19-0410-871a-916f4a2858ee --- loader/dbfopen.c | 308 ++++++++++++++++++++++++++++++++++++-------- loader/shapefil.h | 96 ++++++++++++-- loader/shpopen.c | 320 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 593 insertions(+), 131 deletions(-) diff --git a/loader/dbfopen.c b/loader/dbfopen.c index 93eb1a5a3..280fa01c8 100644 --- a/loader/dbfopen.c +++ b/loader/dbfopen.c @@ -3,7 +3,7 @@ * * Project: Shapelib * Purpose: Implementation of .dbf access API documented in dbf_api.html. - * Author: Frank Warmerdam, warmerda@home.com + * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam @@ -34,17 +34,53 @@ ****************************************************************************** * * $Log$ - * Revision 1.5 2002/10/17 17:06:39 chodgson - * fixed the last compile warning on solaris/gcc + * Revision 1.6 2003/12/01 20:52:00 strk + * shapelib put in sync with gdal cvs * - * Revision 1.4 2002/10/17 16:45:04 chodgson - * - cleaned up all the compiler warnings - * - for getopt.c, this involved moving the line: - * extern char *getenv(const char *name); - * outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments? + * Revision 1.52 2003/07/08 15:20:03 warmerda + * avoid warnings about downcasting to unsigned char * - * Revision 1.3 2002/05/04 22:44:04 pramsey - * Update shapelib references to 1.2.9. + * Revision 1.51 2003/07/08 13:50:15 warmerda + * DBFIsAttributeNULL check for pszValue==NULL - bug 360 + * + * Revision 1.50 2003/04/21 18:58:25 warmerda + * ensure current record is flushed at same time as header is updated + * + * Revision 1.49 2003/04/21 18:30:37 warmerda + * added header write/update public methods + * + * Revision 1.48 2003/03/10 14:51:27 warmerda + * DBFWrite* calls now return FALSE if they have to truncate + * + * Revision 1.47 2002/11/20 03:32:22 warmerda + * Ensure field name in DBFGetFieldIndex() is properly terminated. + * + * Revision 1.46 2002/10/09 13:10:21 warmerda + * Added check that width is positive. + * + * Revision 1.45 2002/09/29 00:00:08 warmerda + * added FTLogical and logical attribute read/write calls + * + * Revision 1.44 2002/05/07 13:46:11 warmerda + * Added DBFWriteAttributeDirectly(). + * + * Revision 1.43 2002/02/13 19:39:21 warmerda + * Fix casting issues in DBFCloneEmpty(). + * + * Revision 1.42 2002/01/15 14:36:07 warmerda + * updated email address + * + * Revision 1.41 2002/01/15 14:31:49 warmerda + * compute rather than copying nHeaderLength in DBFCloneEmpty() + * + * Revision 1.40 2002/01/09 04:32:35 warmerda + * fixed to read correct amount of header + * + * Revision 1.39 2001/12/11 22:41:03 warmerda + * improve io related error checking when reading header + * + * Revision 1.38 2001/11/28 16:07:31 warmerda + * Cleanup to avoid compiler warnings as suggested by Richard Hash. * * Revision 1.37 2001/07/04 05:18:09 warmerda * do last fix properly @@ -161,6 +197,9 @@ * Added header. */ +static char rcsid[] = + "$Id$"; + #include "shapefil.h" #include @@ -220,13 +259,18 @@ static void DBFWriteHeader(DBFHandle psDBF) abyHeader[0] = 0x03; /* memo field? - just copying */ - /* date updated on close, record count preset at zero */ + /* write out a dummy date */ + abyHeader[1] = 95; /* YY */ + abyHeader[2] = 7; /* MM */ + abyHeader[3] = 26; /* DD */ - abyHeader[8] = psDBF->nHeaderLength % 256; - abyHeader[9] = psDBF->nHeaderLength / 256; + /* record count preset at zero */ + + abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256); + abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256); - abyHeader[10] = psDBF->nRecordLength % 256; - abyHeader[11] = psDBF->nRecordLength / 256; + abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256); + abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256); /* -------------------------------------------------------------------- */ /* Write the initial 32 byte file header, and all the field */ @@ -271,6 +315,35 @@ static void DBFFlushRecord( DBFHandle psDBF ) } } +/************************************************************************/ +/* DBFUpdateHeader() */ +/************************************************************************/ + +void SHPAPI_CALL +DBFUpdateHeader( DBFHandle psDBF ) + +{ + unsigned char abyFileHeader[32]; + + if( psDBF->bNoHeader ) + DBFWriteHeader( psDBF ); + + DBFFlushRecord( psDBF ); + + fseek( psDBF->fp, 0, 0 ); + 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); + + fseek( psDBF->fp, 0, 0 ); + fwrite( abyFileHeader, 32, 1, psDBF->fp ); + + fflush( psDBF->fp ); +} + /************************************************************************/ /* DBFOpen() */ /* */ @@ -283,7 +356,7 @@ DBFOpen( const char * pszFilename, const char * pszAccess ) { DBFHandle psDBF; unsigned char *pabyBuf; - int nFields, nRecords, nHeadLen, nRecLen, iField, i; + int nFields, nHeadLen, nRecLen, iField, i; char *pszBasename, *pszFullname; /* -------------------------------------------------------------------- */ @@ -343,9 +416,15 @@ DBFOpen( const char * pszFilename, const char * pszAccess ) /* Read Table Header info */ /* -------------------------------------------------------------------- */ pabyBuf = (unsigned char *) malloc(500); - fread( pabyBuf, 32, 1, psDBF->fp ); + if( fread( pabyBuf, 32, 1, psDBF->fp ) != 1 ) + { + fclose( psDBF->fp ); + free( pabyBuf ); + free( psDBF ); + return NULL; + } - psDBF->nRecords = nRecords = + psDBF->nRecords = pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256; psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256; @@ -363,7 +442,13 @@ DBFOpen( const char * pszFilename, const char * pszAccess ) psDBF->pszHeader = (char *) pabyBuf; fseek( psDBF->fp, 32, 0 ); - fread( pabyBuf, nHeadLen, 1, psDBF->fp ); + if( fread( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 ) + { + fclose( psDBF->fp ); + free( pabyBuf ); + free( psDBF ); + return NULL; + } psDBF->panFieldOffset = (int *) malloc(sizeof(int) * nFields); psDBF->panFieldSize = (int *) malloc(sizeof(int) * nFields); @@ -418,24 +503,7 @@ DBFClose(DBFHandle psDBF) /* write access. */ /* -------------------------------------------------------------------- */ if( psDBF->bUpdated ) - { - unsigned char abyFileHeader[32]; - - fseek( psDBF->fp, 0, 0 ); - fread( abyFileHeader, 32, 1, psDBF->fp ); - - abyFileHeader[1] = 95; /* YY */ - abyFileHeader[2] = 7; /* MM */ - abyFileHeader[3] = 26; /* DD */ - - abyFileHeader[4] = psDBF->nRecords % 256; - abyFileHeader[5] = (psDBF->nRecords/256) % 256; - abyFileHeader[6] = (psDBF->nRecords/(256*256)) % 256; - abyFileHeader[7] = (psDBF->nRecords/(256*256*256)) % 256; - - fseek( psDBF->fp, 0, 0 ); - fwrite( abyFileHeader, 32, 1, psDBF->fp ); - } + DBFUpdateHeader( psDBF ); /* -------------------------------------------------------------------- */ /* Close, and free resources. */ @@ -565,6 +633,9 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName, if( eType != FTDouble && nDecimals != 0 ) return( -1 ); + if( nWidth < 1 ) + return -1; + /* -------------------------------------------------------------------- */ /* SfRealloc all the arrays larger to hold the additional field */ /* information. */ @@ -591,7 +662,9 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName, psDBF->panFieldSize[psDBF->nFields-1] = nWidth; psDBF->panFieldDecimals[psDBF->nFields-1] = nDecimals; - if( eType == FTString ) + if( eType == FTLogical ) + psDBF->pachFieldType[psDBF->nFields-1] = 'L'; + else if( eType == FTString ) psDBF->pachFieldType[psDBF->nFields-1] = 'C'; else psDBF->pachFieldType[psDBF->nFields-1] = 'N'; @@ -618,13 +691,13 @@ DBFAddField(DBFHandle psDBF, const char * pszFieldName, if( eType == FTString ) { - pszFInfo[16] = nWidth % 256; - pszFInfo[17] = nWidth / 256; + pszFInfo[16] = (unsigned char) (nWidth % 256); + pszFInfo[17] = (unsigned char) (nWidth / 256); } else { - pszFInfo[16] = nWidth; - pszFInfo[17] = nDecimals; + pszFInfo[16] = (unsigned char) nWidth; + pszFInfo[17] = (unsigned char) nDecimals; } /* -------------------------------------------------------------------- */ @@ -796,6 +869,19 @@ 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' ) ); +} + /************************************************************************/ /* DBFIsAttributeNULL() */ /* */ @@ -812,6 +898,9 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) pszValue = DBFReadStringAttribute( psDBF, iRecord, iField ); + if( pszValue == NULL ) + return TRUE; + switch(psDBF->pachFieldType[iField]) { case 'N': @@ -831,7 +920,6 @@ DBFIsAttributeNULL( DBFHandle psDBF, int iRecord, int iField ) /* empty string fields are considered NULL */ return strlen(pszValue) == 0; } - return FALSE; } /************************************************************************/ @@ -890,9 +978,12 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, pszFieldName[i] = '\0'; } - if( psDBF->pachFieldType[iField] == 'N' - || psDBF->pachFieldType[iField] == 'F' - || psDBF->pachFieldType[iField] == 'D' ) + if ( psDBF->pachFieldType[iField] == 'L' ) + return( FTLogical); + + else if( psDBF->pachFieldType[iField] == 'N' + || psDBF->pachFieldType[iField] == 'F' + || psDBF->pachFieldType[iField] == 'D' ) { if( psDBF->panFieldDecimals[iField] > 0 ) return( FTDouble ); @@ -915,7 +1006,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, void * pValue ) { - int nRecordOffset, i, j; + int nRecordOffset, i, j, nRetResult = TRUE; unsigned char *pabyRec; char szSField[400], szFormat[20]; @@ -1018,7 +1109,10 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, 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) ); @@ -1034,15 +1128,27 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, 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], ' ', @@ -1055,6 +1161,83 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField, 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 DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField, + void * pValue ) + +{ + int nRecordOffset, 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 ) + { + DBFFlushRecord( psDBF ); + + 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( psDBF->nCurrentRecord != hEntity ) + { + DBFFlushRecord( psDBF ); + + nRecordOffset = psDBF->nRecordLength * hEntity + psDBF->nHeaderLength; + + fseek( psDBF->fp, nRecordOffset, 0 ); + fread( psDBF->pszCurrentRecord, psDBF->nRecordLength, 1, psDBF->fp ); + + psDBF->nCurrentRecord = hEntity; + } + + 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 ); } @@ -1115,6 +1298,20 @@ 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() */ /* */ @@ -1237,20 +1434,20 @@ DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename ) newDBF = DBFCreate ( pszFilename ); if ( newDBF == NULL ) return ( NULL ); - newDBF->pszHeader = (void *) malloc ( 32 * psDBF->nFields ); + newDBF->pszHeader = (char *) malloc ( 32 * psDBF->nFields ); memcpy ( newDBF->pszHeader, psDBF->pszHeader, 32 * psDBF->nFields ); newDBF->nFields = psDBF->nFields; newDBF->nRecordLength = psDBF->nRecordLength; - newDBF->nHeaderLength = psDBF->nHeaderLength; + newDBF->nHeaderLength = 32 * (psDBF->nFields+1); - newDBF->panFieldOffset = (void *) malloc ( sizeof(int) * psDBF->nFields ); + newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields ); - newDBF->panFieldSize = (void *) malloc ( sizeof(int) * psDBF->nFields ); + newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields ); - newDBF->panFieldDecimals = (void *) malloc ( sizeof(int) * psDBF->nFields ); + newDBF->panFieldDecimals = (int *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->panFieldDecimals, psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields ); - newDBF->pachFieldType = (void *) malloc ( sizeof(int) * psDBF->nFields ); + newDBF->pachFieldType = (char *) malloc ( sizeof(int) * psDBF->nFields ); memcpy ( newDBF->pachFieldType, psDBF->pachFieldType, sizeof(int) * psDBF->nFields ); newDBF->bNoHeader = TRUE; @@ -1297,8 +1494,8 @@ static void str_to_upper (char *string) len = strlen (string); while (++i < len) - if (isalpha((unsigned)string[i]) && islower((unsigned)string[i])) - string[i] = toupper ((int)string[i]); + if (isalpha(string[i]) && islower(string[i])) + string[i] = (char) toupper ((int)string[i]); } /************************************************************************/ @@ -1317,6 +1514,7 @@ DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName) int i; strncpy(name1, pszFieldName,11); + name1[11] = '\0'; str_to_upper(name1); for( i = 0; i < DBFGetFieldCount(psDBF); i++ ) diff --git a/loader/shapefil.h b/loader/shapefil.h index bca89b3e1..741c826d8 100644 --- a/loader/shapefil.h +++ b/loader/shapefil.h @@ -6,7 +6,7 @@ * * Project: Shapelib * Purpose: Primary include file for Shapelib. - * Author: Frank Warmerdam, warmerda@home.com + * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1999, Frank Warmerdam @@ -37,8 +37,29 @@ ****************************************************************************** * * $Log$ - * Revision 1.3 2002/05/04 22:44:04 pramsey - * Update shapelib references to 1.2.9. + * Revision 1.4 2003/12/01 20:52:00 strk + * shapelib put in sync with gdal cvs + * + * 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 + * + * Revision 1.21 2001/11/01 16:29:55 warmerda + * move pabyRec into SHPInfo for thread safety * * Revision 1.20 2001/07/20 13:06:02 warmerda * fixed SHPAPI attribute for SHPTreeFindLikelyShapes @@ -109,12 +130,6 @@ extern "C" { #endif -#ifndef SHPAPI_CALL -#define SHPAPI_CALL -#endif - -#define SHPAPI_CALL1(x) * SHPAPI_CALL - /************************************************************************/ /* Configuration options. */ /************************************************************************/ @@ -132,6 +147,48 @@ extern "C" { /* -------------------------------------------------------------------- */ #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 +# define SHPAPI_CALL +#endif + +#ifndef SHPAPI_CALL1 +# define SHPAPI_CALL1(x) x SHPAPI_CALL +#endif + /************************************************************************/ /* SHP Support. */ /************************************************************************/ @@ -153,6 +210,9 @@ typedef struct double adBoundsMax[4]; int bUpdated; + + unsigned char *pabyRec; + int nBufSize; } SHPInfo; typedef SHPInfo * SHPHandle; @@ -248,8 +308,11 @@ SHPObject SHPAPI_CALL1(*) SHPCreateSimpleObject( int nSHPType, int nVertices, double * padfX, double * padfY, double * padfZ ); -void SHPAPI_CALL - SHPClose( SHPHandle hSHP ); +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 ); @@ -352,6 +415,7 @@ typedef enum { FTString, FTInteger, FTDouble, + FTLogical, FTInvalid } DBFFieldType; @@ -383,6 +447,8 @@ 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 ); @@ -398,6 +464,12 @@ int SHPAPI_CALL 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 @@ -408,6 +480,8 @@ DBFHandle SHPAPI_CALL void SHPAPI_CALL DBFClose( DBFHandle hDBF ); +void SHPAPI_CALL + DBFUpdateHeader( DBFHandle hDBF ); char SHPAPI_CALL DBFGetNativeFieldType( DBFHandle hDBF, int iField ); diff --git a/loader/shpopen.c b/loader/shpopen.c index 4af4ce0c0..599ccaf89 100644 --- a/loader/shpopen.c +++ b/loader/shpopen.c @@ -34,14 +34,38 @@ ****************************************************************************** * * $Log$ - * Revision 1.4 2002/10/17 16:45:04 chodgson - * - cleaned up all the compiler warnings - * - for getopt.c, this involved moving the line: - * extern char *getenv(const char *name); - * outside of the two nested #ifdefs that it was inside, as it is always required (the code that calls it isn't inside any #ifdefs) Perhaps this may break compilation in non-linux/gnu environments? + * Revision 1.5 2003/12/01 20:52:00 strk + * shapelib put in sync with gdal cvs * - * Revision 1.3 2002/05/04 22:44:04 pramsey - * Update shapelib references to 1.2.9. + * 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. @@ -149,6 +173,9 @@ * */ +static char rcsid[] = + "$Id$"; + #include "shapefil.h" #include @@ -177,8 +204,6 @@ typedef int int32; #endif static int bBigEndian; -static uchar *pabyRec = NULL; -static int nBufSize = 0; /************************************************************************/ @@ -224,7 +249,7 @@ static void * SfRealloc( void * pMem, int nNewSize ) /* contents of the index (.shx) file. */ /************************************************************************/ -static void SHPWriteHeader( SHPHandle psSHP ) +void SHPWriteHeader( SHPHandle psSHP ) { uchar abyHeader[100]; @@ -318,6 +343,12 @@ static void SHPWriteHeader( SHPHandle psSHP ) fwrite( panSHX, sizeof(int32) * 2, psSHP->nRecords, psSHP->fpSHX ); free( panSHX ); + +/* -------------------------------------------------------------------- */ +/* Flush to disk. */ +/* -------------------------------------------------------------------- */ + fflush( psSHP->fpSHP ); + fflush( psSHP->fpSHX ); } /************************************************************************/ @@ -361,7 +392,7 @@ SHPOpen( const char * pszLayer, const char * pszAccess ) /* -------------------------------------------------------------------- */ /* Initialize the info structure. */ /* -------------------------------------------------------------------- */ - psSHP = (SHPHandle) malloc(sizeof(SHPInfo)); + psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1); psSHP->bUpdated = FALSE; @@ -410,7 +441,7 @@ SHPOpen( const char * pszLayer, const char * pszAccess ) if( psSHP->fpSHX == NULL ) { - fclose( psSHP->fpSHX ); + fclose( psSHP->fpSHP ); free( psSHP ); free( pszBasename ); free( pszFullname ); @@ -547,9 +578,7 @@ SHPClose(SHPHandle psSHP ) /* Update the header if we have modified anything. */ /* -------------------------------------------------------------------- */ if( psSHP->bUpdated ) - { SHPWriteHeader( psSHP ); - } /* -------------------------------------------------------------------- */ /* Free all resources, and close files. */ @@ -560,14 +589,12 @@ SHPClose(SHPHandle psSHP ) fclose( psSHP->fpSHX ); fclose( psSHP->fpSHP ); - free( psSHP ); - - if( pabyRec != NULL ) + if( psSHP->pabyRec != NULL ) { - free( pabyRec ); - pabyRec = NULL; - nBufSize = 0; + free( psSHP->pabyRec ); } + + free( psSHP ); } /************************************************************************/ @@ -906,7 +933,7 @@ int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) { - int nRecordOffset, i, nRecordSize; + int nRecordOffset, i, nRecordSize=0; uchar *pabyRec; int32 i32; @@ -1233,13 +1260,22 @@ SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject ) if( psSHP->adBoundsMin[0] == 0.0 && psSHP->adBoundsMax[0] == 0.0 && psSHP->adBoundsMin[1] == 0.0 - && psSHP->adBoundsMax[1] == 0.0 - && psObject->nSHPType != SHPT_NULL ) + && psSHP->adBoundsMax[1] == 0.0 ) { - 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]; + 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++ ) @@ -1279,17 +1315,17 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ /* Ensure our record buffer is large enough. */ /* -------------------------------------------------------------------- */ - if( psSHP->panRecSize[hEntity]+8 > nBufSize ) + if( psSHP->panRecSize[hEntity]+8 > psSHP->nBufSize ) { - nBufSize = psSHP->panRecSize[hEntity]+8; - pabyRec = (uchar *) SfRealloc(pabyRec,nBufSize); + psSHP->nBufSize = psSHP->panRecSize[hEntity]+8; + psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,psSHP->nBufSize); } /* -------------------------------------------------------------------- */ /* Read the record. */ /* -------------------------------------------------------------------- */ fseek( psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0 ); - fread( pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP ); + fread( psSHP->pabyRec, psSHP->panRecSize[hEntity]+8, 1, psSHP->fpSHP ); /* -------------------------------------------------------------------- */ /* Allocate and minimally initialize the object. */ @@ -1297,7 +1333,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) psShape = (SHPObject *) calloc(1,sizeof(SHPObject)); psShape->nShapeId = hEntity; - memcpy( &psShape->nSHPType, pabyRec + 8, 4 ); + memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 ); if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) ); /* ==================================================================== */ @@ -1316,10 +1352,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ - memcpy( &(psShape->dfXMin), pabyRec + 8 + 4, 8 ); - memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 ); - memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 ); - memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 ); + 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) ); @@ -1330,8 +1366,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* Extract part/point count, and build vertex and part arrays */ /* to proper size. */ /* -------------------------------------------------------------------- */ - memcpy( &nPoints, pabyRec + 40 + 8, 4 ); - memcpy( &nParts, pabyRec + 36 + 8, 4 ); + memcpy( &nPoints, psSHP->pabyRec + 40 + 8, 4 ); + memcpy( &nParts, psSHP->pabyRec + 36 + 8, 4 ); if( bBigEndian ) SwapWord( 4, &nPoints ); if( bBigEndian ) SwapWord( 4, &nParts ); @@ -1352,7 +1388,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ /* Copy out the part array from the record. */ /* -------------------------------------------------------------------- */ - memcpy( psShape->panPartStart, pabyRec + 44 + 8, 4 * nParts ); + memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts ); for( i = 0; i < nParts; i++ ) { if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i ); @@ -1365,7 +1401,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_MULTIPATCH ) { - memcpy( psShape->panPartType, pabyRec + nOffset, 4*nParts ); + memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts ); for( i = 0; i < nParts; i++ ) { if( bBigEndian ) SwapWord( 4, psShape->panPartType+i ); @@ -1380,11 +1416,11 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { memcpy(psShape->padfX + i, - pabyRec + nOffset + i * 16, + psSHP->pabyRec + nOffset + i * 16, 8 ); memcpy(psShape->padfY + i, - pabyRec + nOffset + i * 16 + 8, + psSHP->pabyRec + nOffset + i * 16 + 8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfX + i ); @@ -1400,8 +1436,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) || psShape->nSHPType == SHPT_ARCZ || psShape->nSHPType == SHPT_MULTIPATCH ) { - memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 ); + 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) ); @@ -1409,7 +1445,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfZ + i, - pabyRec + nOffset + 16 + i*8, 8 ); + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); } @@ -1424,8 +1460,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) { - memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 ); + 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) ); @@ -1433,7 +1469,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfM + i, - pabyRec + nOffset + 16 + i*8, 8 ); + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); } } @@ -1450,7 +1486,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) int32 nPoints; int i, nOffset; - memcpy( &nPoints, pabyRec + 44, 4 ); + memcpy( &nPoints, psSHP->pabyRec + 44, 4 ); if( bBigEndian ) SwapWord( 4, &nPoints ); psShape->nVertices = nPoints; @@ -1461,8 +1497,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { - memcpy(psShape->padfX+i, pabyRec + 48 + 16 * i, 8 ); - memcpy(psShape->padfY+i, pabyRec + 48 + 16 * i + 8, 8 ); + 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 ); @@ -1473,10 +1509,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ /* Get the X/Y bounds. */ /* -------------------------------------------------------------------- */ - memcpy( &(psShape->dfXMin), pabyRec + 8 + 4, 8 ); - memcpy( &(psShape->dfYMin), pabyRec + 8 + 12, 8 ); - memcpy( &(psShape->dfXMax), pabyRec + 8 + 20, 8 ); - memcpy( &(psShape->dfYMax), pabyRec + 8 + 28, 8 ); + 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) ); @@ -1488,8 +1524,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_MULTIPOINTZ ) { - memcpy( &(psShape->dfZMin), pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfZMax), pabyRec + nOffset + 8, 8 ); + 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) ); @@ -1497,7 +1533,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfZ + i, - pabyRec + nOffset + 16 + i*8, 8 ); + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ + i ); } @@ -1512,8 +1548,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 16 + 8*nPoints ) { - memcpy( &(psShape->dfMMin), pabyRec + nOffset, 8 ); - memcpy( &(psShape->dfMMax), pabyRec + nOffset + 8, 8 ); + 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) ); @@ -1521,7 +1557,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) for( i = 0; i < nPoints; i++ ) { memcpy( psShape->padfM + i, - pabyRec + nOffset + 16 + i*8, 8 ); + psSHP->pabyRec + nOffset + 16 + i*8, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM + i ); } } @@ -1542,8 +1578,8 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) psShape->padfZ = (double *) calloc(1,sizeof(double)); psShape->padfM = (double *) calloc(1,sizeof(double)); - memcpy( psShape->padfX, pabyRec + 12, 8 ); - memcpy( psShape->padfY, pabyRec + 20, 8 ); + 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 ); @@ -1555,7 +1591,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psShape->nSHPType == SHPT_POINTZ ) { - memcpy( psShape->padfZ, pabyRec + nOffset, 8 ); + memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfZ ); @@ -1570,7 +1606,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity ) /* -------------------------------------------------------------------- */ if( psSHP->panRecSize[hEntity]+8 >= nOffset + 8 ) { - memcpy( psShape->padfM, pabyRec + nOffset, 8 ); + memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 ); if( bBigEndian ) SwapWord( 8, psShape->padfM ); } @@ -1705,3 +1741,157 @@ SHPDestroyObject( SHPObject * psShape ) 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. */ +/* -------------------------------------------------------------------- */ + dfTestX = psObject->padfX[psObject->panPartStart[iOpRing]]; + dfTestY = psObject->padfY[psObject->panPartStart[iOpRing]]; + + 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; + + if( (psObject->padfY[iEdge+nVertStart] < dfTestY + && psObject->padfY[iNext+nVertStart] >= dfTestY) + || (psObject->padfY[iNext+nVertStart] < dfTestY + && psObject->padfY[iEdge+nVertStart] >= dfTestY) ) + { + if( 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]) < dfTestX ) + bInner = !bInner; + } + } + } + +/* -------------------------------------------------------------------- */ +/* 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]; + + dfSum = 0.0; + for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ ) + { + dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1] + - psObject->padfY[iVert] * psObject->padfX[iVert+1]; + } + + dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart] + - psObject->padfY[iVert] * psObject->padfX[nVertStart]; + +/* -------------------------------------------------------------------- */ +/* 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; +} -- 2.40.0