Skip to content

Commit

Permalink
GDAL contour: fix incorrect oriented contour lines in some rare cases…
Browse files Browse the repository at this point in the history
… (patch by schmitzu, fixes OSGeo#6563)

git-svn-id: https://svn.osgeo.org/gdal/trunk@34471 f0d54148-0727-0410-94bb-9a71ac55c965
  • Loading branch information
rouault committed Jun 30, 2016
1 parent 22e1522 commit 22919bf
Showing 1 changed file with 152 additions and 65 deletions.
217 changes: 152 additions & 65 deletions gdal/alg/contour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class GDALContourItem
double dfXEnd, double dfYEnd, int bLeftHigh );
void MakeRoomFor( int );
int Merge( GDALContourItem * );
double DistanceSqr(double x0, double y0, double x1, double y1);
int MergeCase( double ax0, double ay0, double ax1, double ay1,
double bx0, double by0, double bx1, double by1);
void PrepareEjection();
};

Expand Down Expand Up @@ -1226,106 +1229,190 @@ int GDALContourItem::AddSegment( double dfXStart, double dfYStart,
return FALSE;
}

/************************************************************************/
/* DistanceSqr() */
/************************************************************************/

double GDALContourItem::DistanceSqr(
double x0, double y0, double x1, double y1
)
{
// --------------------------------------------------------------------
// Coumpute the square of the euclidian distance between
// (x0;y0)-(x1;y1)
// --------------------------------------------------------------------
double dx = x0 - x1;
double dy = y0 - y1;

return (dx*dx + dy*dy);
}

/************************************************************************/
/* MergeCase() */
/************************************************************************/

int GDALContourItem::MergeCase(
double ax0, double ay0, double ax1, double ay1,
double bx0, double by0, double bx1, double by1
)
{
double dd;

// --------------------------------------------------------------------
// Try to find a match case between line ends
// Calculate all possible distances and choose the closest
// if less than JOIN_DIST
// --------------------------------------------------------------------

// avoid sqrt()
const double jds = JOIN_DIST * JOIN_DIST;

// case 1 e-b
int cs = 1;
double dmin = DistanceSqr (ax1, ay1, bx0, by0);

// case 2 b-e
dd = DistanceSqr (ax0, ay0, bx1, by1);
if (dd < dmin)
{
dmin = dd;
cs = 2;
}

// case 3 e-e
dd = DistanceSqr (ax1, ay1, bx1, by1);
if (dd < dmin)
{
dmin = dd;
cs = 3;
}

// case 4 b-b
dd = DistanceSqr (ax0, ay0, bx0, by0);
if (dd < dmin)
{
dmin = dd;
cs = 4;
}

if (dmin > jds)
cs = 0;

return cs;
}

/************************************************************************/
/* Merge() */
/************************************************************************/

int GDALContourItem::Merge( GDALContourItem *poOther )

{
int rc = FALSE;
int i;

if( poOther->dfLevel != dfLevel )
return FALSE;

/* -------------------------------------------------------------------- */
/* Try to matching up with one of the ends, and insert. */
/* -------------------------------------------------------------------- */
if( fabs(padfX[nPoints-1]-poOther->padfX[0]) < JOIN_DIST
&& fabs(padfY[nPoints-1]-poOther->padfY[0]) < JOIN_DIST )

int mc = MergeCase (
padfX[0], padfY[0],
padfX[nPoints-1], padfY[nPoints-1],
poOther->padfX[0], poOther->padfY[0],
poOther->padfX[poOther->nPoints-1], poOther->padfY[poOther->nPoints-1]
);

switch (mc)
{
MakeRoomFor( nPoints + poOther->nPoints - 1 );
case 0:
break;

memcpy( padfX + nPoints, poOther->padfX + 1,
sizeof(double) * (poOther->nPoints-1) );
memcpy( padfY + nPoints, poOther->padfY + 1,
sizeof(double) * (poOther->nPoints-1) );
nPoints += poOther->nPoints - 1;
case 1: // case 1 e-b
MakeRoomFor( nPoints + poOther->nPoints - 1 );

bRecentlyAccessed = TRUE;
memcpy( padfX + nPoints, poOther->padfX + 1,
sizeof(double) * (poOther->nPoints-1) );
memcpy( padfY + nPoints, poOther->padfY + 1,
sizeof(double) * (poOther->nPoints-1) );
nPoints += poOther->nPoints - 1;

dfTailX = padfX[nPoints-1];
bRecentlyAccessed = TRUE;

return TRUE;
}
else if( fabs(padfX[0]-poOther->padfX[poOther->nPoints-1]) < JOIN_DIST
&& fabs(padfY[0]-poOther->padfY[poOther->nPoints-1]) < JOIN_DIST )
{
MakeRoomFor( nPoints + poOther->nPoints - 1 );

memmove( padfX + poOther->nPoints - 1, padfX,
sizeof(double) * nPoints );
memmove( padfY + poOther->nPoints - 1, padfY,
sizeof(double) * nPoints );
memcpy( padfX, poOther->padfX,
sizeof(double) * (poOther->nPoints-1) );
memcpy( padfY, poOther->padfY,
sizeof(double) * (poOther->nPoints-1) );
nPoints += poOther->nPoints - 1;
dfTailX = padfX[nPoints-1];

bRecentlyAccessed = TRUE;
rc = TRUE;
break;

dfTailX = padfX[nPoints-1];
case 2: // case 2 b-e
MakeRoomFor( nPoints + poOther->nPoints - 1 );

return TRUE;
}
else if( fabs(padfX[nPoints-1]-poOther->padfX[poOther->nPoints-1]) < JOIN_DIST
&& fabs(padfY[nPoints-1]-poOther->padfY[poOther->nPoints-1]) < JOIN_DIST )
{
int i;
memmove( padfX + poOther->nPoints - 1, padfX,
sizeof(double) * nPoints );
memmove( padfY + poOther->nPoints - 1, padfY,
sizeof(double) * nPoints );
memcpy( padfX, poOther->padfX,
sizeof(double) * (poOther->nPoints-1) );
memcpy( padfY, poOther->padfY,
sizeof(double) * (poOther->nPoints-1) );
nPoints += poOther->nPoints - 1;

MakeRoomFor( nPoints + poOther->nPoints - 1 );
bRecentlyAccessed = TRUE;

for( i = 0; i < poOther->nPoints-1; i++ )
{
padfX[i+nPoints] = poOther->padfX[poOther->nPoints-i-2];
padfY[i+nPoints] = poOther->padfY[poOther->nPoints-i-2];
}
dfTailX = padfX[nPoints-1];

nPoints += poOther->nPoints - 1;
rc = TRUE;
break;

bRecentlyAccessed = TRUE;
case 3: // case 3 e-e
MakeRoomFor( nPoints + poOther->nPoints - 1 );

dfTailX = padfX[nPoints-1];
for( i = 0; i < poOther->nPoints-1; i++ )
{
padfX[i+nPoints] = poOther->padfX[poOther->nPoints-i-2];
padfY[i+nPoints] = poOther->padfY[poOther->nPoints-i-2];
}

return TRUE;
}
else if( fabs(padfX[0]-poOther->padfX[0]) < JOIN_DIST
&& fabs(padfY[0]-poOther->padfY[0]) < JOIN_DIST )
{
int i;
nPoints += poOther->nPoints - 1;

MakeRoomFor( nPoints + poOther->nPoints - 1 );
bRecentlyAccessed = TRUE;

memmove( padfX + poOther->nPoints - 1, padfX,
sizeof(double) * nPoints );
memmove( padfY + poOther->nPoints - 1, padfY,
sizeof(double) * nPoints );
dfTailX = padfX[nPoints-1];

for( i = 0; i < poOther->nPoints-1; i++ )
{
padfX[i] = poOther->padfX[poOther->nPoints - i - 1];
padfY[i] = poOther->padfY[poOther->nPoints - i - 1];
}
rc = TRUE;
break;

nPoints += poOther->nPoints - 1;
case 4: // case 3 b-b
MakeRoomFor( nPoints + poOther->nPoints - 1 );

bRecentlyAccessed = TRUE;
memmove( padfX + poOther->nPoints - 1, padfX,
sizeof(double) * nPoints );
memmove( padfY + poOther->nPoints - 1, padfY,
sizeof(double) * nPoints );

dfTailX = padfX[nPoints-1];
for( i = 0; i < poOther->nPoints-1; i++ )
{
padfX[i] = poOther->padfX[poOther->nPoints - i - 1];
padfY[i] = poOther->padfY[poOther->nPoints - i - 1];
}

return TRUE;
nPoints += poOther->nPoints - 1;

bRecentlyAccessed = TRUE;

dfTailX = padfX[nPoints-1];

rc = TRUE;
break;

default:
CPLAssert(FALSE);
break;
}
else
return FALSE;

return rc;
}

/************************************************************************/
Expand Down

0 comments on commit 22919bf

Please sign in to comment.