Opened 16 years ago
Closed 16 years ago
#2174 closed defect (fixed)
Problem with RingExtent::calculate in shape2ogr.cpp
Reported by: | bpeschel | Owned by: | Even Rouault |
---|---|---|---|
Priority: | normal | Milestone: | 1.6.0 |
Component: | default | Version: | unspecified |
Severity: | normal | Keywords: | |
Cc: | warmerdam |
Description
I am using code from shape2ogr.cpp to determine outer/inner rings and their association. The method RingExtent::calculate() is used to find the max and min of the object. This is used later to check if the inner rings are contained by the inner.
However, the code has a bug in it:
void RingExtent::calculate( int ringParts, double *ringX, double *ringY ) { empty = ringParts <= 0; if ( !empty ) { xMin = xMax = *ringX; yMin = yMax = *ringY; while( --ringParts > 0 ) { if ( xMin > *ringX ) xMin = *ringX; else if ( xMax < *ringX ) xMax = *ringX; if ( yMin > *ringY ) yMin = *ringY; else if ( yMax < *ringY ) yMax = *ringY; ++ringX; ++ringY; } } }
The problem is in the while loop. Because SHPReadOGRObject() calls this by:
int start = 0; int end = 0; RingStartEnd ( psShape, iRing, &start, &end ); extents[ iRing ].calculate( end-start, psShape->padfX + start, psShape->padfY + start );
So, if the ring has 4 points (causing 5 in the shape file because the first and last must be repeated), start would be 0 and end would be 4. So, the loop will evaluate points 0, 1, and 2 skipping the fourth point. If that point happens to be a max or min, the later calculations will not be correct.
It appears this can be fixed by changing
while( --ringParts > 0 )
to
while( ringParts-- > 0 )
at least in my limited testing.
If I can attach a file after submission, I will attach a shapefile set that proves this.
Attachments (1)
Change History (5)
by , 16 years ago
Attachment: | 1000308y.zip added |
---|
comment:1 by , 16 years ago
I share bpeschel's analysis. My suggestion for a fix would be to increment ringX and ringY before the loop. bpeschel's fix would work too, but would go on doing an extra first loop that does nothing.
void RingExtent::calculate( int ringParts, double *ringX, double *ringY ) { empty = ringParts <= 0; if ( !empty ) { xMin = xMax = *ringX; yMin = yMax = *ringY; ++ringX; // FIX ++ringY; // FIX while( --ringParts > 0 ) { if ( xMin > *ringX ) xMin = *ringX; else if ( xMax < *ringX ) xMax = *ringX; if ( yMin > *ringY ) yMin = *ringY; else if ( yMax < *ringY ) yMax = *ringY; ++ringX; ++ringY; } } }
I also want to outline that since my fix for bug #1217, RingExtent::calculate is not called anymore in trunk (since r13551) and in branches/1.5 (since r13553). The old code that classified multipolygons is still there, but it's dead.
comment:2 by , 16 years ago
Owner: | changed from | to
---|
comment:3 by , 16 years ago
Cc: | added |
---|
comment:4 by , 16 years ago
Milestone: | → 1.6.0 |
---|---|
Resolution: | → fixed |
Status: | new → closed |
The problem manifests in the second ring of shape 3 and the ring in shape 4