Ticket #2147 (closed defect: fixed)
S-57 ENC coast lines, depth contours etc. imported incorrectly in OGR S57Reader
| Reported by: | Tom1 | Owned by: | warmerdam |
|---|---|---|---|
| Priority: | normal | Milestone: | 1.7.3 |
| Component: | OGR_SF | Version: | 1.5.0 |
| Severity: | normal | Keywords: | s57 |
| Cc: |
Description
S-57 reader in OGR incorrectly concatenates multi-part coast lines, depth contours, etc. found in S-57 ENC data. The problem is that features consisting of multiple polyline geometries are presented as one OGRLineString simply chaining the separate edges. This causes errors in ENC cell boundaries where e.g. coast line of an island cross the edge multiple times. (The coast line takes shortcuts to be continuous where it actually should be absent.) The fix involves creating a OGRMultiLineString geometry for such features that have multiple separate OGRLineString geometries embedded.
In the following source, there are added/removed tags for the changes required to released 1.5.0 source code.
Finally, here's the fixed source for S57Reader::AssembleLineGeometry?:
/************************************************************************/
/* AssembleLineGeometry() */
/************************************************************************/
void S57Reader::AssembleLineGeometry( DDFRecord * poFRecord,
OGRFeature * poFeature )
{
DDFField *poFSPT;
int nEdgeCount;
// OGRLineString *poLine = new OGRLineString(); // removed
/* -------------------------------------------------------------------- */
/* Find the FSPT field. */
/* -------------------------------------------------------------------- */
poFSPT = poFRecord->FindField( "FSPT" );
if( poFSPT == NULL )
return;
nEdgeCount = poFSPT->GetRepeatCount();
OGRMultiLineString *poMultiLine =0; // added
if(nEdgeCount>1) poMultiLine = new OGRMultiLineString(); // added
/* ==================================================================== */
/* Loop collecting edges. */
/* ==================================================================== */
for( int iEdge = 0; iEdge < nEdgeCount; iEdge++ )
{
DDFRecord *poSRecord;
int nRCID;
/* -------------------------------------------------------------------- */
/* Find the spatial record for this edge. */
/* -------------------------------------------------------------------- */
nRCID = ParseName( poFSPT, iEdge );
poSRecord = oVE_Index.FindRecord( nRCID );
if( poSRecord == NULL )
{
CPLError( CE_Warning, CPLE_AppDefined,
"Couldn't find spatial record %d.\n"
"Feature OBJL=%s, RCID=%d may have corrupt or"
"missing geometry.",
nRCID,
poFeature->GetDefnRef()->GetName(),
poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
continue;
}
/* -------------------------------------------------------------------- */
/* Establish the number of vertices, and whether we need to */
/* reverse or not. */
/* -------------------------------------------------------------------- */
int nVCount;
int nStart, nEnd, nInc;
DDFField *poSG2D = poSRecord->FindField( "SG2D" );
DDFField *poAR2D = poSRecord->FindField( "AR2D" );
DDFSubfieldDefn *poXCOO=NULL, *poYCOO=NULL;
if( poSG2D == NULL && poAR2D != NULL )
poSG2D = poAR2D;
if( poSG2D != NULL )
{
poXCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("XCOO");
poYCOO = poSG2D->GetFieldDefn()->FindSubfieldDefn("YCOO");
nVCount = poSG2D->GetRepeatCount();
}
else
nVCount = 0;
if( poFRecord->GetIntSubfield( "FSPT", 0, "ORNT", iEdge ) == 2 )
{
nStart = nVCount-1;
nEnd = 0;
nInc = -1;
}
else
{
nStart = 0;
nEnd = nVCount-1;
nInc = 1;
}
/* -------------------------------------------------------------------- */
/* Add the start node, if this is the first edge. */
/* -------------------------------------------------------------------- */
OGRLineString *poLine = new OGRLineString(); // added
// if( iEdge == 0 ) // removed
// { // removed
int nVC_RCID;
double dfX, dfY;
if( nInc == 1 )
nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 0 );
else
nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 1 );
if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
poLine->addPoint( dfX, dfY );
else
CPLError( CE_Warning, CPLE_AppDefined,
"Unable to fetch start node RCID%d.\n"
"Feature OBJL=%s, RCID=%d may have corrupt or"
" missing geometry.",
nVC_RCID,
poFeature->GetDefnRef()->GetName(),
poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
// } // removed
/* -------------------------------------------------------------------- */
/* Collect the vertices. */
/* -------------------------------------------------------------------- */
int nVBase = poLine->getNumPoints();
poLine->setNumPoints( nVCount+nVBase );
for( int i = nStart; i != nEnd+nInc; i += nInc )
{
double dfX, dfY;
const char *pachData;
int nBytesRemaining;
pachData = poSG2D->GetSubfieldData(poXCOO,&nBytesRemaining,i);
dfX = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
/ (double) nCOMF;
pachData = poSG2D->GetSubfieldData(poYCOO,&nBytesRemaining,i);
dfY = poXCOO->ExtractIntData(pachData,nBytesRemaining,NULL)
/ (double) nCOMF;
poLine->setPoint( nVBase++, dfX, dfY );
}
/* -------------------------------------------------------------------- */
/* Add the end node. */
/* -------------------------------------------------------------------- */
{
int nVC_RCID;
double dfX, dfY;
if( nInc == 1 )
nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 1 );
else
nVC_RCID = ParseName( poSRecord->FindField( "VRPT" ), 0 );
if( FetchPoint( RCNM_VC, nVC_RCID, &dfX, &dfY ) )
poLine->addPoint( dfX, dfY );
else
CPLError( CE_Warning, CPLE_AppDefined,
"Unable to fetch end node RCID=%d.\n"
"Feature OBJL=%s, RCID=%d may have corrupt or"
" missing geometry.",
nVC_RCID,
poFeature->GetDefnRef()->GetName(),
poFRecord->GetIntSubfield( "FRID", 0, "RCID", 0 ) );
}
// } // removed
if( poLine->getNumPoints() >= 2 ){
// poFeature->SetGeometryDirectly( poLine ); // removed
if(poMultiLine) poMultiLine->addGeometryDirectly( poLine ); // added
else poFeature->SetGeometryDirectly( poLine ); // added
}
else
delete poLine;
} // added
if(poMultiLine) poFeature->SetGeometryDirectly( poMultiLine );// added
}

