EVOLUTION-MANAGER
Edit File: ogrgeoconceptlayer.cpp
/****************************************************************************** * $Id: ogrgeoconceptlayer.cpp * * Project: OpenGIS Simple Features Reference Implementation * Purpose: Implements OGRGeoconceptLayer class. * Author: Didier Richard, didier.richard@ign.fr * Language: C++ * ****************************************************************************** * Copyright (c) 2007, Geoconcept and IGN * Copyright (c) 2008, 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 "ogrgeoconceptlayer.h" #include "cpl_conv.h" #include "cpl_string.h" CPL_CVSID("$Id: ogrgeoconceptlayer.cpp 00000 2007-11-03 16:08:14Z drichard $"); /************************************************************************/ /* OGRGeoconceptLayer() */ /************************************************************************/ OGRGeoconceptLayer::OGRGeoconceptLayer() { _poFeatureDefn = NULL; _gcFeature = NULL; } /************************************************************************/ /* ~OGRGeoconceptLayer() */ /************************************************************************/ OGRGeoconceptLayer::~OGRGeoconceptLayer() { CPLDebug( "GEOCONCEPT", "%ld features on layer %s.", GetSubTypeNbFeatures_GCIO(_gcFeature), _poFeatureDefn->GetName()); if( _poFeatureDefn ) { _poFeatureDefn->Release(); } _gcFeature= NULL; /* deleted when OGCGeoconceptDatasource destroyed */ } /************************************************************************/ /* Open() */ /************************************************************************/ OGRErr OGRGeoconceptLayer::Open( GCSubType* Subclass ) { _gcFeature= Subclass; if( GetSubTypeFeatureDefn_GCIO(_gcFeature) ) { _poFeatureDefn = (OGRFeatureDefn *)GetSubTypeFeatureDefn_GCIO(_gcFeature); _poFeatureDefn->Reference(); } else { char pszln[512]; int n, i; snprintf(pszln, 511, "%s.%s", GetSubTypeName_GCIO(_gcFeature), GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature))); pszln[511]='\0'; _poFeatureDefn = new OGRFeatureDefn(pszln); _poFeatureDefn->Reference(); _poFeatureDefn->SetGeomType(wkbUnknown); if( (n= CountSubTypeFields_GCIO(_gcFeature))>0 ) { GCField* aField= NULL; OGRFieldType oft; for( i= 0; i<n; i++ ) { if( (aField= GetSubTypeField_GCIO(_gcFeature,i)) ) { if( IsPrivateField_GCIO(aField) ) continue; switch(GetFieldKind_GCIO(aField)) { case vIntFld_GCIO : case vPositionFld_GCIO : oft= OFTInteger; break; case vRealFld_GCIO : case vLengthFld_GCIO : case vAreaFld_GCIO : oft= OFTReal; break; case vDateFld_GCIO : oft= OFTDate; break; case vTimeFld_GCIO : oft= OFTTime; break; case vMemoFld_GCIO : case vChoiceFld_GCIO : case vInterFld_GCIO : default : oft= OFTString; break; } OGRFieldDefn ofd(GetFieldName_GCIO(aField), oft); _poFeatureDefn->AddFieldDefn(&ofd); } } } SetSubTypeFeatureDefn_GCIO(_gcFeature, (OGRFeatureDefnH) _poFeatureDefn); _poFeatureDefn->Reference(); } return OGRERR_NONE; } /************************************************************************/ /* ResetReading() */ /************************************************************************/ void OGRGeoconceptLayer::ResetReading() { Rewind_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature),_gcFeature); } /************************************************************************/ /* GetNextFeature() */ /************************************************************************/ OGRFeature *OGRGeoconceptLayer::GetNextFeature() { OGRFeature* poFeature = NULL; for( ;; ) { if( !(poFeature= (OGRFeature*)ReadNextFeature_GCIO(_gcFeature)) ) { /* * As several features are embed in the Geoconcept file, * when reaching the end of the feature type, resetting * the reader would allow reading other features : * ogrinfo -ro export.gxt FT1 FT2 ... * will be all features for all features types ! */ Rewind_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature),NULL); break; } if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) { break; } delete poFeature; } CPLDebug( "GEOCONCEPT", "FID : %ld\n" "%s : %s", poFeature? poFeature->GetFID():-1L, poFeature && poFeature->GetFieldCount()>0? poFeature->GetFieldDefnRef(0)->GetNameRef():"-", poFeature && poFeature->GetFieldCount()>0? poFeature->GetFieldAsString(0):""); return poFeature; } /************************************************************************/ /* OGRGeoconceptLayer_GetCompatibleFieldName() */ /************************************************************************/ static char* OGRGeoconceptLayer_GetCompatibleFieldName(const char* pszName) { char* pszCompatibleName = CPLStrdup(pszName); int i; for(i=0;pszCompatibleName[i] != 0;i++) { if (pszCompatibleName[i] == ' ') pszCompatibleName[i] = '_'; } return pszCompatibleName; } /************************************************************************/ /* CreateFeature() */ /************************************************************************/ OGRErr OGRGeoconceptLayer::CreateFeature( OGRFeature* poFeature ) { OGRwkbGeometryType eGt; OGRGeometry* poGeom; int nextField, iGeom, nbGeom, isSingle; poGeom= poFeature->GetGeometryRef(); if (poGeom == NULL) { CPLError( CE_Warning, CPLE_NotSupported, "NULL geometry not supported in Geoconcept, feature skipped.\n"); return OGRERR_NONE; } eGt= poGeom->getGeometryType(); switch( eGt ) { case wkbPoint : case wkbPoint25D : case wkbMultiPoint : case wkbMultiPoint25D : if( GetSubTypeKind_GCIO(_gcFeature)==vUnknownItemType_GCIO ) { SetSubTypeKind_GCIO(_gcFeature,vPoint_GCIO); } else if( GetSubTypeKind_GCIO(_gcFeature)!=vPoint_GCIO ) { CPLError( CE_Failure, CPLE_NotSupported, "Can't write non ponctual feature in a ponctual Geoconcept layer %s.\n", _poFeatureDefn->GetName()); return OGRERR_FAILURE; } break; case wkbLineString : case wkbLineString25D : case wkbMultiLineString : case wkbMultiLineString25D : if( GetSubTypeKind_GCIO(_gcFeature)==vUnknownItemType_GCIO ) { SetSubTypeKind_GCIO(_gcFeature,vLine_GCIO); } else if( GetSubTypeKind_GCIO(_gcFeature)!=vLine_GCIO ) { CPLError( CE_Failure, CPLE_NotSupported, "Can't write non linear feature in a linear Geoconcept layer %s.\n", _poFeatureDefn->GetName()); return OGRERR_FAILURE; } break; case wkbPolygon : case wkbPolygon25D : case wkbMultiPolygon : case wkbMultiPolygon25D : if( GetSubTypeKind_GCIO(_gcFeature)==vUnknownItemType_GCIO ) { SetSubTypeKind_GCIO(_gcFeature,vPoly_GCIO); } else if( GetSubTypeKind_GCIO(_gcFeature)!=vPoly_GCIO ) { CPLError( CE_Failure, CPLE_NotSupported, "Can't write non polygonal feature in a polygonal Geoconcept layer %s.\n", _poFeatureDefn->GetName()); return OGRERR_FAILURE; } break; case wkbUnknown : case wkbGeometryCollection : case wkbGeometryCollection25D : case wkbNone : case wkbLinearRing : default : CPLError( CE_Warning, CPLE_AppDefined, "Geometry type %s not supported in Geoconcept, feature skipped.\n", OGRGeometryTypeToName(eGt) ); return OGRERR_NONE; } if( GetSubTypeDim_GCIO(_gcFeature)==vUnknown3D_GCIO ) { if( poGeom->getCoordinateDimension()==3 ) { SetSubTypeDim_GCIO(_gcFeature,v3D_GCIO); } else { SetSubTypeDim_GCIO(_gcFeature,v2D_GCIO); } } switch( eGt ) { case wkbPoint : case wkbPoint25D : nbGeom= 1; isSingle= TRUE; break; case wkbMultiPoint : case wkbMultiPoint25D : nbGeom= ((OGRGeometryCollection*)poGeom)->getNumGeometries(); isSingle= FALSE; break; case wkbLineString : case wkbLineString25D : nbGeom= 1; isSingle= TRUE; break; case wkbMultiLineString : case wkbMultiLineString25D : nbGeom= ((OGRGeometryCollection*)poGeom)->getNumGeometries(); isSingle= FALSE; break; case wkbPolygon : case wkbPolygon25D : nbGeom= 1; isSingle= TRUE; break; case wkbMultiPolygon : case wkbMultiPolygon25D : nbGeom= ((OGRGeometryCollection*)poGeom)->getNumGeometries(); isSingle= FALSE; break; case wkbUnknown : case wkbGeometryCollection : case wkbGeometryCollection25D : case wkbNone : case wkbLinearRing : default : nbGeom= 0; isSingle= FALSE; break; } /* 1st feature, let's write header : */ if( GetGCMode_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)) == vWriteAccess_GCIO && GetFeatureCount(TRUE) == 0 ) if( WriteHeader_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature))==NULL ) { return OGRERR_FAILURE; } if( nbGeom>0 ) { for( iGeom= 0; iGeom<nbGeom; iGeom++ ) { nextField= StartWritingFeature_GCIO(_gcFeature, isSingle? poFeature->GetFID():OGRNullFID); while (nextField!=WRITECOMPLETED_GCIO) { if( nextField==WRITEERROR_GCIO ) { return OGRERR_FAILURE; } if( nextField==GEOMETRYEXPECTED_GCIO ) { OGRGeometry* poGeomPart= isSingle? poGeom:((OGRGeometryCollection*)poGeom)->getGeometryRef(iGeom); nextField= WriteFeatureGeometry_GCIO(_gcFeature, (OGRGeometryH)poGeomPart); } else { int iF, nF; OGRFieldDefn *poField; GCField* theField= GetSubTypeField_GCIO(_gcFeature,nextField); /* for each field, find out its mapping ... */ if( (nF= poFeature->GetFieldCount())>0 ) { for( iF= 0; iF<nF; iF++ ) { poField= poFeature->GetFieldDefnRef(iF); char* pszName = OGRGeoconceptLayer_GetCompatibleFieldName(poField->GetNameRef()); if( EQUAL(pszName, GetFieldName_GCIO(theField)) ) { CPLFree(pszName); nextField= WriteFeatureFieldAsString_GCIO(_gcFeature, nextField, poFeature->IsFieldSet(iF)? poFeature->GetFieldAsString(iF) : NULL); break; } CPLFree(pszName); } if( iF==nF ) { CPLError( CE_Failure, CPLE_AppDefined, "Can't find a field attached to %s on Geoconcept layer %s.\n", GetFieldName_GCIO(theField), _poFeatureDefn->GetName()); return OGRERR_FAILURE; } } else { nextField= WRITECOMPLETED_GCIO; } } } StopWritingFeature_GCIO(_gcFeature); } } return OGRERR_NONE; } /************************************************************************/ /* GetSpatialRef() */ /************************************************************************/ OGRSpatialReference *OGRGeoconceptLayer::GetSpatialRef() { GCExportFileH* hGXT= GetSubTypeGCHandle_GCIO(_gcFeature); if( !hGXT ) return NULL; GCExportFileMetadata* Meta= GetGCMeta_GCIO(hGXT); if( !Meta ) return NULL; return (OGRSpatialReference*)GetMetaSRS_GCIO(Meta); } /************************************************************************/ /* GetFeatureCount() */ /* */ /* If a spatial filter is in effect, we turn control over to */ /* the generic counter. Otherwise we return the total count. */ /************************************************************************/ int OGRGeoconceptLayer::GetFeatureCount( int bForce ) { if( m_poFilterGeom != NULL || m_poAttrQuery != NULL ) return OGRLayer::GetFeatureCount( bForce ); else return GetSubTypeNbFeatures_GCIO(_gcFeature); } /************************************************************************/ /* GetExtent() */ /************************************************************************/ OGRErr OGRGeoconceptLayer::GetExtent( OGREnvelope* psExtent, CPL_UNUSED int bForce ) { GCExtent* theExtent; theExtent= GetSubTypeExtent_GCIO( _gcFeature ); psExtent->MinX= GetExtentULAbscissa_GCIO(theExtent); psExtent->MinY= GetExtentLROrdinate_GCIO(theExtent); psExtent->MaxX= GetExtentLRAbscissa_GCIO(theExtent); psExtent->MaxY= GetExtentULOrdinate_GCIO(theExtent); return OGRERR_NONE; } /************************************************************************/ /* TestCapability() */ /************************************************************************/ int OGRGeoconceptLayer::TestCapability( const char* pszCap ) { if( EQUAL(pszCap,OLCRandomRead) ) return FALSE; // the GetFeature() method does not work for this layer. TODO else if( EQUAL(pszCap,OLCSequentialWrite) ) return TRUE; // the CreateFeature() method works for this layer. else if( EQUAL(pszCap,OLCRandomWrite) ) return FALSE; // the SetFeature() method is not operational on this layer. else if( EQUAL(pszCap,OLCFastSpatialFilter) ) return FALSE; // this layer does not implement spatial filtering efficiently. else if( EQUAL(pszCap,OLCFastFeatureCount) ) return FALSE; // this layer can not return a feature count efficiently. FIXME else if( EQUAL(pszCap,OLCFastGetExtent) ) return FALSE; // this layer can not return its data extent efficiently. FIXME else if( EQUAL(pszCap,OLCFastSetNextByIndex) ) return FALSE; // this layer can not perform the SetNextByIndex() call efficiently. else if( EQUAL(pszCap,OLCDeleteFeature) ) return FALSE; else if( EQUAL(pszCap,OLCCreateField) ) return TRUE; else return FALSE; } /************************************************************************/ /* CreateField() */ /************************************************************************/ OGRErr OGRGeoconceptLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK ) { if( GetGCMode_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature))==vReadAccess_GCIO ) { CPLError( CE_Failure, CPLE_NotSupported, "Can't create fields on a read-only Geoconcept layer.\n"); return OGRERR_FAILURE; } /* -------------------------------------------------------------------- */ /* Add field to layer */ /* -------------------------------------------------------------------- */ { /* check whether field exists ... */ GCField* theField; char* pszName = OGRGeoconceptLayer_GetCompatibleFieldName(poField->GetNameRef()); if( !(theField= FindFeatureField_GCIO(_gcFeature,pszName)) ) { if( GetFeatureCount(TRUE) > 0 ) { CPLError( CE_Failure, CPLE_NotSupported, "Can't create field '%s' on existing Geoconcept layer '%s.%s'.\n", pszName, GetSubTypeName_GCIO(_gcFeature), GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature)) ); CPLFree(pszName); return OGRERR_FAILURE; } if( GetSubTypeNbFields_GCIO(_gcFeature)==-1) SetSubTypeNbFields_GCIO(_gcFeature, 0L); if( !(theField= AddSubTypeField_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature), GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature)), GetSubTypeName_GCIO(_gcFeature), FindFeatureFieldIndex_GCIO(_gcFeature,kNbFields_GCIO) +GetSubTypeNbFields_GCIO(_gcFeature)+1L, pszName, GetSubTypeNbFields_GCIO(_gcFeature)-999L, vUnknownItemType_GCIO, NULL, NULL)) ) { CPLError( CE_Failure, CPLE_AppDefined, "Field '%s' could not be created for Feature %s.%s.\n", pszName, GetSubTypeName_GCIO(_gcFeature), GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature)) ); CPLFree(pszName); return OGRERR_FAILURE; } SetSubTypeNbFields_GCIO(_gcFeature, GetSubTypeNbFields_GCIO(_gcFeature)+1L); _poFeatureDefn->AddFieldDefn(poField); } else { if( _poFeatureDefn->GetFieldIndex(GetFieldName_GCIO(theField))==-1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Field %s not found for Feature %s.%s.\n", GetFieldName_GCIO(theField), GetSubTypeName_GCIO(_gcFeature), GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature)) ); CPLFree(pszName); return OGRERR_FAILURE; } } CPLFree(pszName); pszName = NULL; /* check/update type ? */ if( GetFieldKind_GCIO(theField)==vUnknownItemType_GCIO ) { switch(poField->GetType()) { case OFTInteger : SetFieldKind_GCIO(theField,vIntFld_GCIO); break; case OFTReal : SetFieldKind_GCIO(theField,vRealFld_GCIO); break; case OFTDate : SetFieldKind_GCIO(theField,vDateFld_GCIO); break; case OFTTime : case OFTDateTime : SetFieldKind_GCIO(theField,vTimeFld_GCIO); break; case OFTString : SetFieldKind_GCIO(theField,vMemoFld_GCIO); break; case OFTIntegerList : case OFTRealList : case OFTStringList : case OFTBinary : default : CPLError( CE_Failure, CPLE_NotSupported, "Can't create fields of type %s on Geoconcept feature %s.\n", OGRFieldDefn::GetFieldTypeName(poField->GetType()), _poFeatureDefn->GetName() ); return OGRERR_FAILURE; } } } return OGRERR_NONE; } /************************************************************************/ /* SyncToDisk() */ /************************************************************************/ OGRErr OGRGeoconceptLayer::SyncToDisk() { FFlush_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)); return OGRERR_NONE; } /************************************************************************/ /* SetSpatialRef() */ /************************************************************************/ void OGRGeoconceptLayer::SetSpatialRef( OGRSpatialReference *poSpatialRef ) { GCSysCoord* os, *ns; OGRSpatialReference* poSRS= GetSpatialRef(); GCExportFileH* hGXT; GCExportFileMetadata* Meta; /*----------------------------------------------------------------- * Keep a copy of the OGRSpatialReference... * Note: we have to take the reference count into account... *----------------------------------------------------------------*/ if( poSRS && poSRS->Dereference() == 0) delete poSRS; if( !poSpatialRef ) return; poSRS= poSpatialRef->Clone(); if( !(hGXT= GetSubTypeGCHandle_GCIO(_gcFeature)) ) return; if( !(Meta= GetGCMeta_GCIO(hGXT)) ) return; os= GetMetaSysCoord_GCIO(Meta); ns= OGRSpatialReference2SysCoord_GCSRS((OGRSpatialReferenceH)poSRS); if( os && ns && GetSysCoordSystemID_GCSRS(os)!=-1 && ( GetSysCoordSystemID_GCSRS(os)!=GetSysCoordSystemID_GCSRS(ns) || GetSysCoordTimeZone_GCSRS(os)!=GetSysCoordTimeZone_GCSRS(ns) ) ) { CPLError( CE_Warning, CPLE_AppDefined, "Can't change SRS on Geoconcept layers.\n" ); return; } if( os ) DestroySysCoord_GCSRS(&os); SetMetaSysCoord_GCIO(Meta, ns); SetMetaSRS_GCIO(Meta, (OGRSpatialReferenceH)poSRS); return; }