EVOLUTION-MANAGER
Edit File: ogrpcidsklayer.cpp
/****************************************************************************** * * Project: PCIDSK Translator * Purpose: Implements OGRPCIDSKLayer class. * Author: Frank Warmerdam <warmerdam@pobox.com> * ****************************************************************************** * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com> * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org> * * 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. ****************************************************************************/ #include "pcidskdataset2.h" #include <algorithm> CPL_CVSID("$Id: ogrpcidsklayer.cpp 36353 2016-11-20 22:37:22Z rouault $"); /************************************************************************/ /* OGRPCIDSKLayer() */ /************************************************************************/ OGRPCIDSKLayer::OGRPCIDSKLayer( PCIDSK::PCIDSKSegment *poSegIn, PCIDSK::PCIDSKVectorSegment * poVecSegIn, bool bUpdate ) { poSRS = NULL; bUpdateAccess = bUpdate; poSeg = poSegIn; poVecSeg = poVecSegIn; poFeatureDefn = new OGRFeatureDefn( poSeg->GetName().c_str() ); SetDescription( poFeatureDefn->GetName() ); poFeatureDefn->Reference(); hLastShapeId = PCIDSK::NullShapeId; /* -------------------------------------------------------------------- */ /* Attempt to assign a geometry type. */ /* -------------------------------------------------------------------- */ try { std::string osLayerType = poSeg->GetMetadataValue( "LAYER_TYPE" ); if( osLayerType == "WHOLE_POLYGONS" ) poFeatureDefn->SetGeomType( wkbPolygon25D ); else if( osLayerType == "ARCS" || osLayerType == "TOPO_ARCS" ) poFeatureDefn->SetGeomType( wkbLineString25D ); else if( osLayerType == "POINTS" || osLayerType == "TOPO_NODES" ) poFeatureDefn->SetGeomType( wkbPoint25D ); else if( osLayerType == "TABLE" ) poFeatureDefn->SetGeomType( wkbNone ); } catch(...) {} /* -------------------------------------------------------------------- */ /* Build field definitions. */ /* -------------------------------------------------------------------- */ try { iRingStartField = -1; for( int iField = 0; iField < poVecSeg->GetFieldCount(); iField++ ) { OGRFieldDefn oField( poVecSeg->GetFieldName(iField).c_str(), OFTString); switch( poVecSeg->GetFieldType(iField) ) { case PCIDSK::FieldTypeFloat: case PCIDSK::FieldTypeDouble: oField.SetType( OFTReal ); break; case PCIDSK::FieldTypeInteger: oField.SetType( OFTInteger ); break; case PCIDSK::FieldTypeString: oField.SetType( OFTString ); break; case PCIDSK::FieldTypeCountedInt: oField.SetType( OFTIntegerList ); break; default: CPLAssert( false ); break; } // we ought to try and extract some width/precision information // from the format string at some point. // If the last field is named RingStart we treat it specially. if( EQUAL(oField.GetNameRef(),"RingStart") && oField.GetType() == OFTIntegerList && iField == poVecSeg->GetFieldCount()-1 ) iRingStartField = iField; else poFeatureDefn->AddFieldDefn( &oField ); } /* -------------------------------------------------------------------- */ /* Look for a coordinate system. */ /* -------------------------------------------------------------------- */ CPLString osGeosys; const char *pszUnits = NULL; std::vector<double> adfParameters; adfParameters = poVecSeg->GetProjection( osGeosys ); if( static_cast<PCIDSK::UnitCode>( static_cast<int>( adfParameters[16] ) ) == PCIDSK::UNIT_DEGREE ) pszUnits = "DEGREE"; else if( static_cast<PCIDSK::UnitCode>( static_cast<int>( adfParameters[16] )) == PCIDSK::UNIT_METER ) pszUnits = "METER"; else if( static_cast<PCIDSK::UnitCode>( static_cast<int>( adfParameters[16] ) ) == PCIDSK::UNIT_US_FOOT ) pszUnits = "FOOT"; else if( static_cast<PCIDSK::UnitCode>( static_cast<int>( adfParameters[16] ) ) == PCIDSK::UNIT_INTL_FOOT ) pszUnits = "INTL FOOT"; poSRS = new OGRSpatialReference(); if( poSRS->importFromPCI( osGeosys, pszUnits, &(adfParameters[0]) ) != OGRERR_NONE ) { delete poSRS; poSRS = NULL; } } /* -------------------------------------------------------------------- */ /* Trap pcidsk exceptions. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() ); } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." ); } if( poFeatureDefn->GetGeomFieldCount() > 0 ) poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); } /************************************************************************/ /* ~OGRPCIDSKLayer() */ /************************************************************************/ OGRPCIDSKLayer::~OGRPCIDSKLayer() { if( m_nFeaturesRead > 0 ) { CPLDebug( "PCIDSK", "%d features read on layer '%s'.", static_cast<int>( m_nFeaturesRead ), poFeatureDefn->GetName() ); } poFeatureDefn->Release(); if (poSRS) poSRS->Release(); } /************************************************************************/ /* ResetReading() */ /************************************************************************/ void OGRPCIDSKLayer::ResetReading() { hLastShapeId = PCIDSK::NullShapeId; } /************************************************************************/ /* GetNextFeature() */ /************************************************************************/ OGRFeature *OGRPCIDSKLayer::GetNextFeature() { OGRFeature *poFeature = NULL; /* -------------------------------------------------------------------- */ /* Read features till we find one that satisfies our current */ /* spatial criteria. */ /* -------------------------------------------------------------------- */ while( true ) { poFeature = GetNextUnfilteredFeature(); if( poFeature == NULL ) break; if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) break; delete poFeature; } return poFeature; } /************************************************************************/ /* GetNextUnfilteredFeature() */ /************************************************************************/ OGRFeature *OGRPCIDSKLayer::GetNextUnfilteredFeature() { try { /* -------------------------------------------------------------------- */ /* Get the next shapeid. */ /* -------------------------------------------------------------------- */ if( hLastShapeId == PCIDSK::NullShapeId ) hLastShapeId = poVecSeg->FindFirst(); else hLastShapeId = poVecSeg->FindNext( hLastShapeId ); if( hLastShapeId == PCIDSK::NullShapeId ) return NULL; return GetFeature( hLastShapeId ); } catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "PCIDSK Exception while iterating features.\n%s", ex.what() ); return NULL; } } /************************************************************************/ /* GetFeature() */ /************************************************************************/ OGRFeature *OGRPCIDSKLayer::GetFeature( GIntBig nFID ) { /* -------------------------------------------------------------------- */ /* Create the OGR feature. */ /* -------------------------------------------------------------------- */ OGRFeature *poFeature = new OGRFeature( poFeatureDefn ); poFeature->SetFID( static_cast<int>( nFID ) ); /* -------------------------------------------------------------------- */ /* Set attributes for any indicated attribute records. */ /* -------------------------------------------------------------------- */ try { std::vector<PCIDSK::ShapeField> aoFields; poVecSeg->GetFields( static_cast<int>( nFID ), aoFields ); for( unsigned int i=0; i < aoFields.size(); i++ ) { if( static_cast<int>( i ) == iRingStartField ) continue; switch( aoFields[i].GetType() ) { case PCIDSK::FieldTypeNone: // null field value. break; case PCIDSK::FieldTypeInteger: poFeature->SetField( i, aoFields[i].GetValueInteger() ); break; case PCIDSK::FieldTypeFloat: poFeature->SetField( i, aoFields[i].GetValueFloat() ); break; case PCIDSK::FieldTypeDouble: poFeature->SetField( i, aoFields[i].GetValueDouble() ); break; case PCIDSK::FieldTypeString: poFeature->SetField( i, aoFields[i].GetValueString().c_str() ); break; case PCIDSK::FieldTypeCountedInt: std::vector<PCIDSK::int32> list = aoFields[i].GetValueCountedInt(); poFeature->SetField( i, static_cast<int>(list.size()), &(list[0]) ); break; } } /* -------------------------------------------------------------------- */ /* Translate the geometry. */ /* -------------------------------------------------------------------- */ std::vector<PCIDSK::ShapeVertex> aoVertices; poVecSeg->GetVertices( static_cast<int>( nFID ), aoVertices ); /* -------------------------------------------------------------------- */ /* Point */ /* -------------------------------------------------------------------- */ if( poFeatureDefn->GetGeomType() == wkbPoint25D || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown && aoVertices.size() == 1) ) { if( aoVertices.size() == 1 ) { OGRPoint* poPoint = new OGRPoint( aoVertices[0].x, aoVertices[0].y, aoVertices[0].z ); if (poSRS) poPoint->assignSpatialReference(poSRS); poFeature->SetGeometryDirectly(poPoint); } else { // report issue? } } /* -------------------------------------------------------------------- */ /* LineString */ /* -------------------------------------------------------------------- */ else if( poFeatureDefn->GetGeomType() == wkbLineString25D || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown && aoVertices.size() > 1) ) { // We should likely be applying ringstart to break things into // a multilinestring in some cases. if( aoVertices.size() > 1 ) { OGRLineString *poLS = new OGRLineString(); poLS->setNumPoints( static_cast<int>(aoVertices.size()) ); for( unsigned int i = 0; i < aoVertices.size(); i++ ) poLS->setPoint( i, aoVertices[i].x, aoVertices[i].y, aoVertices[i].z ); if (poSRS) poLS->assignSpatialReference(poSRS); poFeature->SetGeometryDirectly( poLS ); } else { // report issue? } } /* -------------------------------------------------------------------- */ /* Polygon - Currently we have no way to recognise if we are */ /* dealing with a multipolygon when we have more than one */ /* ring. Also, PCIDSK allows the rings to be in arbitrary */ /* order, not necessarily outside first which we are not yet */ /* ready to address in the following code. */ /* -------------------------------------------------------------------- */ else if( poFeatureDefn->GetGeomType() == wkbPolygon25D ) { std::vector<PCIDSK::int32> anRingStart; OGRPolygon *poPoly = new OGRPolygon(); if( iRingStartField != -1 ) anRingStart = aoFields[iRingStartField].GetValueCountedInt(); for( unsigned int iRing = 0; iRing < anRingStart.size()+1; iRing++ ) { int iStartVertex; if( iRing == 0 ) iStartVertex = 0; else iStartVertex = anRingStart[iRing-1]; int iEndVertex; if( iRing == anRingStart.size() ) iEndVertex = static_cast<int>(aoVertices.size()) - 1; else iEndVertex = anRingStart[iRing] - 1; int iVertex; OGRLinearRing *poRing = new OGRLinearRing(); poRing->setNumPoints( iEndVertex - iStartVertex + 1 ); for( iVertex = iStartVertex; iVertex <= iEndVertex; iVertex++ ) { poRing->setPoint( iVertex - iStartVertex, aoVertices[iVertex].x, aoVertices[iVertex].y, aoVertices[iVertex].z ); } poPoly->addRingDirectly( poRing ); } if (poSRS) poPoly->assignSpatialReference(poSRS); poFeature->SetGeometryDirectly( poPoly ); } } /* -------------------------------------------------------------------- */ /* Trap exceptions and report as CPL errors. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { delete poFeature; CPLError( CE_Failure, CPLE_AppDefined, "%s", ex.what() ); return NULL; } catch(...) { delete poFeature; CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped." ); return NULL; } m_nFeaturesRead++; return poFeature; } /************************************************************************/ /* TestCapability() */ /************************************************************************/ int OGRPCIDSKLayer::TestCapability( const char * pszCap ) { if( EQUAL(pszCap,OLCRandomRead) ) return TRUE; else if( EQUAL(pszCap,OLCFastFeatureCount) ) return m_poFilterGeom == NULL && m_poAttrQuery == NULL; else if( EQUAL(pszCap,OLCSequentialWrite) || EQUAL(pszCap,OLCRandomWrite) ) return bUpdateAccess; else if( EQUAL(pszCap,OLCDeleteFeature) ) return bUpdateAccess; else if( EQUAL(pszCap,OLCCreateField) ) return bUpdateAccess; return FALSE; } /************************************************************************/ /* GetFeatureCount() */ /************************************************************************/ GIntBig OGRPCIDSKLayer::GetFeatureCount( int bForce ) { if( m_poFilterGeom != NULL || m_poAttrQuery != NULL ) return OGRLayer::GetFeatureCount( bForce ); try { return poVecSeg->GetShapeCount(); } catch(...) { return 0; } } /************************************************************************/ /* GetExtent() */ /************************************************************************/ OGRErr OGRPCIDSKLayer::GetExtent (OGREnvelope *psExtent, int bForce) { if( !bForce ) return OGRERR_FAILURE; /* -------------------------------------------------------------------- */ /* Loop over all features, but just read the geometry. This is */ /* a fair amount quicker than actually processing all the */ /* attributes, forming features and then examining the */ /* geometries as the default implementation would do. */ /* -------------------------------------------------------------------- */ try { bool bHaveExtent = false; std::vector<PCIDSK::ShapeVertex> asVertices; for( PCIDSK::ShapeIterator oIt = poVecSeg->begin(); oIt != poVecSeg->end(); oIt++ ) { poVecSeg->GetVertices( *oIt, asVertices ); for( unsigned int i = 0; i < asVertices.size(); i++ ) { if( !bHaveExtent ) { psExtent->MinX = asVertices[i].x; psExtent->MaxX = asVertices[i].x; psExtent->MinY = asVertices[i].y; psExtent->MaxY = asVertices[i].y; bHaveExtent = true; } else { psExtent->MinX = std::min(psExtent->MinX, asVertices[i].x); psExtent->MaxX = std::max(psExtent->MaxX, asVertices[i].x); psExtent->MinY = std::min(psExtent->MinY, asVertices[i].y); psExtent->MaxY = std::max(psExtent->MaxY, asVertices[i].y); } } } if( bHaveExtent ) return OGRERR_NONE; return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Trap pcidsk exceptions. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() ); return OGRERR_FAILURE; } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." ); return OGRERR_FAILURE; } } /************************************************************************/ /* DeleteFeature() */ /************************************************************************/ OGRErr OGRPCIDSKLayer::DeleteFeature( GIntBig nFID ) { try { poVecSeg->DeleteShape( (PCIDSK::ShapeId) nFID ); return OGRERR_NONE; } /* -------------------------------------------------------------------- */ /* Trap exceptions and report as CPL errors. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", ex.what() ); return OGRERR_FAILURE; } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped." ); return OGRERR_FAILURE; } } /************************************************************************/ /* ICreateFeature() */ /************************************************************************/ OGRErr OGRPCIDSKLayer::ICreateFeature( OGRFeature *poFeature ) { try { PCIDSK::ShapeId id = poVecSeg->CreateShape( (PCIDSK::ShapeId) poFeature->GetFID() ); poFeature->SetFID( (long) id ); return SetFeature( poFeature ); } /* -------------------------------------------------------------------- */ /* Trap exceptions and report as CPL errors. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", ex.what() ); return OGRERR_FAILURE; } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped." ); return OGRERR_FAILURE; } } /************************************************************************/ /* ISetFeature() */ /************************************************************************/ OGRErr OGRPCIDSKLayer::ISetFeature( OGRFeature *poFeature ) { PCIDSK::ShapeId id = (PCIDSK::ShapeId) poFeature->GetFID(); /* -------------------------------------------------------------------- */ /* Translate attribute fields. */ /* -------------------------------------------------------------------- */ try { std::vector<PCIDSK::ShapeField> aoPCIFields; aoPCIFields.resize(poVecSeg->GetFieldCount()); for( int iPCI = 0; iPCI < poVecSeg->GetFieldCount(); iPCI++ ) { int iOGR = poFeatureDefn->GetFieldIndex( poVecSeg->GetFieldName(iPCI).c_str() ); if( iOGR == -1 ) continue; switch( poVecSeg->GetFieldType(iPCI) ) { case PCIDSK::FieldTypeInteger: aoPCIFields[iPCI].SetValue( poFeature->GetFieldAsInteger( iOGR ) ); break; case PCIDSK::FieldTypeFloat: aoPCIFields[iPCI].SetValue( static_cast<float>( poFeature->GetFieldAsDouble( iOGR ) ) ); break; case PCIDSK::FieldTypeDouble: aoPCIFields[iPCI].SetValue( static_cast<double>( poFeature->GetFieldAsDouble( iOGR ) ) ); break; case PCIDSK::FieldTypeString: aoPCIFields[iPCI].SetValue( poFeature->GetFieldAsString( iOGR ) ); break; case PCIDSK::FieldTypeCountedInt: { int nCount; const int *panList = poFeature->GetFieldAsIntegerList( iOGR, &nCount ); std::vector<PCIDSK::int32> anList; anList.resize( nCount ); memcpy( &(anList[0]), panList, 4 * anList.size() ); aoPCIFields[iPCI].SetValue( anList ); } break; default: CPLAssert( false ); break; } } if( poVecSeg->GetFieldCount() > 0 ) poVecSeg->SetFields( id, aoPCIFields ); /* -------------------------------------------------------------------- */ /* Translate the geometry. */ /* -------------------------------------------------------------------- */ std::vector<PCIDSK::ShapeVertex> aoVertices; OGRGeometry *poGeometry = poFeature->GetGeometryRef(); if( poGeometry == NULL ) { // TODO: What? Is this really a NOP? } else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint ) { OGRPoint *poPoint = reinterpret_cast<OGRPoint *>( poGeometry ); aoVertices.resize(1); aoVertices[0].x = poPoint->getX(); aoVertices[0].y = poPoint->getY(); aoVertices[0].z = poPoint->getZ(); } else if( wkbFlatten(poGeometry->getGeometryType()) == wkbLineString ) { OGRLineString *poLS = reinterpret_cast<OGRLineString *>( poGeometry ); unsigned int i; aoVertices.resize(poLS->getNumPoints()); for( i = 0; i < aoVertices.size(); i++ ) { aoVertices[i].x = poLS->getX(i); aoVertices[i].y = poLS->getY(i); aoVertices[i].z = poLS->getZ(i); } } else { CPLDebug( "PCIDSK", "Unsupported geometry type in SetFeature(): %s", poGeometry->getGeometryName() ); } poVecSeg->SetVertices( id, aoVertices ); } /* try */ /* -------------------------------------------------------------------- */ /* Trap exceptions and report as CPL errors. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", ex.what() ); return OGRERR_FAILURE; } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped." ); return OGRERR_FAILURE; } return OGRERR_NONE; } /************************************************************************/ /* CreateField() */ /************************************************************************/ OGRErr OGRPCIDSKLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK ) { try { if( poFieldDefn->GetType() == OFTInteger ) { poVecSeg->AddField( poFieldDefn->GetNameRef(), PCIDSK::FieldTypeInteger, "", "" ); poFeatureDefn->AddFieldDefn( poFieldDefn ); } else if( poFieldDefn->GetType() == OFTReal ) { poVecSeg->AddField( poFieldDefn->GetNameRef(), PCIDSK::FieldTypeDouble, "", "" ); poFeatureDefn->AddFieldDefn( poFieldDefn ); } else if( poFieldDefn->GetType() == OFTString ) { poVecSeg->AddField( poFieldDefn->GetNameRef(), PCIDSK::FieldTypeString, "", "" ); poFeatureDefn->AddFieldDefn( poFieldDefn ); } else if( poFieldDefn->GetType() == OFTIntegerList ) { poVecSeg->AddField( poFieldDefn->GetNameRef(), PCIDSK::FieldTypeCountedInt, "", "" ); poFeatureDefn->AddFieldDefn( poFieldDefn ); } else if( bApproxOK ) { // Fallback to treating everything else as a string field. OGRFieldDefn oModFieldDefn(poFieldDefn); oModFieldDefn.SetType( OFTString ); poVecSeg->AddField( poFieldDefn->GetNameRef(), PCIDSK::FieldTypeString, "", "" ); poFeatureDefn->AddFieldDefn( &oModFieldDefn ); } else { CPLError( CE_Failure, CPLE_AppDefined, "Attempt to create field '%s' of unsupported data type.", poFieldDefn->GetNameRef() ); } } /* -------------------------------------------------------------------- */ /* Trap exceptions and report as CPL errors. */ /* -------------------------------------------------------------------- */ catch( const PCIDSK::PCIDSKException& ex ) { CPLError( CE_Failure, CPLE_AppDefined, "%s", ex.what() ); return OGRERR_FAILURE; } catch(...) { CPLError( CE_Failure, CPLE_AppDefined, "Non-PCIDSK exception trapped." ); return OGRERR_FAILURE; } return OGRERR_NONE; }