OGRBoolean OGRCompoundCurvePointIterator::getNextPoint( OGRPoint* p ) { if( iCurCurve == poCC->getNumCurves() ) return FALSE; if( poCurveIter == NULL ) poCurveIter = poCC->getCurve(0)->getPointIterator(); if( !poCurveIter->getNextPoint(p) ) { iCurCurve++; if( iCurCurve == poCC->getNumCurves() ) return FALSE; delete poCurveIter; poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator(); // Skip first point. return poCurveIter->getNextPoint(p) && poCurveIter->getNextPoint(p); } return TRUE; }
static int OGR2GML3GeometryAppend( const OGRGeometry *poGeometry, const OGRSpatialReference* poParentSRS, char **ppszText, int *pnLength, int *pnMaxLength, int bIsSubGeometry, int bLongSRS, int bLineStringAsCurve, const char* pszGMLId, int nSRSDimensionLocFlags, int bForceLineStringAsLinearRing ) { /* -------------------------------------------------------------------- */ /* Check for Spatial Reference System attached to given geometry */ /* -------------------------------------------------------------------- */ // Buffer for srsName, srsDimension and gml:id attributes (srsName="..." gml:id="...") char szAttributes[256]; int nAttrsLength = 0; szAttributes[0] = 0; const OGRSpatialReference* poSRS = NULL; if (poParentSRS) poSRS = poParentSRS; else poParentSRS = poSRS = poGeometry->getSpatialReference(); int bCoordSwap = FALSE; if( NULL != poSRS ) { const char* pszAuthName = NULL; const char* pszAuthCode = NULL; const char* pszTarget = NULL; if (poSRS->IsProjected()) pszTarget = "PROJCS"; else pszTarget = "GEOGCS"; pszAuthName = poSRS->GetAuthorityName( pszTarget ); if( NULL != pszAuthName ) { if( EQUAL( pszAuthName, "EPSG" ) ) { pszAuthCode = poSRS->GetAuthorityCode( pszTarget ); if( NULL != pszAuthCode && strlen(pszAuthCode) < 10 ) { if (bLongSRS && !(((OGRSpatialReference*)poSRS)->EPSGTreatsAsLatLong() || ((OGRSpatialReference*)poSRS)->EPSGTreatsAsNorthingEasting())) { OGRSpatialReference oSRS; if (oSRS.importFromEPSGA(atoi(pszAuthCode)) == OGRERR_NONE) { if (oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting()) bCoordSwap = TRUE; } } if (!bIsSubGeometry) { if (bLongSRS) { snprintf( szAttributes, sizeof(szAttributes), " srsName=\"urn:ogc:def:crs:%s::%s\"", pszAuthName, pszAuthCode ); } else { snprintf( szAttributes, sizeof(szAttributes), " srsName=\"%s:%s\"", pszAuthName, pszAuthCode ); } nAttrsLength = strlen(szAttributes); } } } } } if( (nSRSDimensionLocFlags & SRSDIM_LOC_GEOMETRY) != 0 && wkbHasZ(poGeometry->getGeometryType()) ) { strcat(szAttributes, " srsDimension=\"3\""); nAttrsLength = strlen(szAttributes); nSRSDimensionLocFlags &= ~SRSDIM_LOC_GEOMETRY; } if (pszGMLId != NULL && nAttrsLength + 9 + strlen(pszGMLId) + 1 < sizeof(szAttributes)) { strcat(szAttributes, " gml:id=\""); strcat(szAttributes, pszGMLId); strcat(szAttributes, "\""); nAttrsLength = strlen(szAttributes); } OGRwkbGeometryType eType = poGeometry->getGeometryType(); OGRwkbGeometryType eFType = wkbFlatten(eType); /* -------------------------------------------------------------------- */ /* 2D Point */ /* -------------------------------------------------------------------- */ if( eType == wkbPoint ) { char szCoordinate[256]; OGRPoint *poPoint = (OGRPoint *) poGeometry; if (bCoordSwap) OGRMakeWktCoordinate( szCoordinate, poPoint->getY(), poPoint->getX(), 0.0, 2 ); else OGRMakeWktCoordinate( szCoordinate, poPoint->getX(), poPoint->getY(), 0.0, 2 ); _GrowBuffer( *pnLength + strlen(szCoordinate) + 60 + nAttrsLength, ppszText, pnMaxLength ); sprintf( *ppszText + *pnLength, "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>", szAttributes, szCoordinate ); *pnLength += strlen( *ppszText + *pnLength ); } /* -------------------------------------------------------------------- */ /* 3D Point */ /* -------------------------------------------------------------------- */ else if( eType == wkbPoint25D ) { char szCoordinate[256]; OGRPoint *poPoint = (OGRPoint *) poGeometry; if (bCoordSwap) OGRMakeWktCoordinate( szCoordinate, poPoint->getY(), poPoint->getX(), poPoint->getZ(), 3 ); else OGRMakeWktCoordinate( szCoordinate, poPoint->getX(), poPoint->getY(), poPoint->getZ(), 3 ); _GrowBuffer( *pnLength + strlen(szCoordinate) + 70 + nAttrsLength, ppszText, pnMaxLength ); sprintf( *ppszText + *pnLength, "<gml:Point%s><gml:pos>%s</gml:pos></gml:Point>", szAttributes, szCoordinate ); *pnLength += strlen( *ppszText + *pnLength ); } /* -------------------------------------------------------------------- */ /* LineString and LinearRing */ /* -------------------------------------------------------------------- */ else if( eFType == wkbLineString ) { int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING") || bForceLineStringAsLinearRing; if (!bRing && bLineStringAsCurve) { AppendString( ppszText, pnLength, pnMaxLength, "<gml:Curve" ); AppendString( ppszText, pnLength, pnMaxLength, szAttributes ); AppendString( ppszText, pnLength, pnMaxLength, "><gml:segments><gml:LineStringSegment>" ); AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap, ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags ); AppendString( ppszText, pnLength, pnMaxLength, "</gml:LineStringSegment></gml:segments></gml:Curve>" ); } else { // Buffer for tag name + srsName attribute if set const size_t nLineTagLength = 16; char* pszLineTagName = NULL; pszLineTagName = (char *) CPLMalloc( nLineTagLength + nAttrsLength + 1 ); if( bRing ) { /* LinearRing isn't supposed to have srsName attribute according to GML3 SF-0 */ AppendString( ppszText, pnLength, pnMaxLength, "<gml:LinearRing>" ); } else { sprintf( pszLineTagName, "<gml:LineString%s>", szAttributes ); AppendString( ppszText, pnLength, pnMaxLength, pszLineTagName ); } // FREE TAG BUFFER CPLFree( pszLineTagName ); AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap, ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags ); if( bRing ) AppendString( ppszText, pnLength, pnMaxLength, "</gml:LinearRing>" ); else AppendString( ppszText, pnLength, pnMaxLength, "</gml:LineString>" ); } } /* -------------------------------------------------------------------- */ /* ArcString or Circle */ /* -------------------------------------------------------------------- */ else if( eFType == wkbCircularString ) { AppendString( ppszText, pnLength, pnMaxLength, "<gml:Curve" ); AppendString( ppszText, pnLength, pnMaxLength, szAttributes ); OGRSimpleCurve* poSC = (OGRSimpleCurve *) poGeometry; /* SQL MM has a unique type for arc and circle, GML not */ if( poSC->getNumPoints() == 3 && poSC->getX(0) == poSC->getX(2) && poSC->getY(0) == poSC->getY(2) ) { double dfMidX = (poSC->getX(0) + poSC->getX(1)) / 2; double dfMidY = (poSC->getY(0) + poSC->getY(1)) / 2; double dfDirX = (poSC->getX(1) - poSC->getX(0)) / 2; double dfDirY = (poSC->getY(1) - poSC->getY(0)) / 2; double dfNormX = -dfDirY; double dfNormY = dfDirX; double dfNewX = dfMidX + dfNormX; double dfNewY = dfMidY + dfNormY; OGRLineString* poLS = new OGRLineString(); OGRPoint p; poSC->getPoint(0, &p); poLS->addPoint(&p); poSC->getPoint(1, &p); if( poSC->getCoordinateDimension() == 3 ) poLS->addPoint(dfNewX, dfNewY, p.getZ()); else poLS->addPoint(dfNewX, dfNewY); poLS->addPoint(&p); AppendString( ppszText, pnLength, pnMaxLength, "><gml:segments><gml:Circle>" ); AppendGML3CoordinateList( poLS, bCoordSwap, ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags ); AppendString( ppszText, pnLength, pnMaxLength, "</gml:Circle></gml:segments></gml:Curve>" ); delete poLS; } else { AppendString( ppszText, pnLength, pnMaxLength, "><gml:segments><gml:ArcString>" ); AppendGML3CoordinateList( poSC, bCoordSwap, ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags ); AppendString( ppszText, pnLength, pnMaxLength, "</gml:ArcString></gml:segments></gml:Curve>" ); } } /* -------------------------------------------------------------------- */ /* CompositeCurve */ /* -------------------------------------------------------------------- */ else if( eFType == wkbCompoundCurve ) { AppendString( ppszText, pnLength, pnMaxLength, "<gml:CompositeCurve" ); AppendString( ppszText, pnLength, pnMaxLength, szAttributes ); AppendString( ppszText, pnLength, pnMaxLength,">"); OGRCompoundCurve* poCC = (OGRCompoundCurve*)poGeometry; for(int i=0;i<poCC->getNumCurves();i++) { AppendString( ppszText, pnLength, pnMaxLength, "<gml:curveMember>" ); if( !OGR2GML3GeometryAppend( poCC->getCurve(i), poSRS, ppszText, pnLength, pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve, NULL, nSRSDimensionLocFlags, FALSE) ) return FALSE; AppendString( ppszText, pnLength, pnMaxLength, "</gml:curveMember>" ); } AppendString( ppszText, pnLength, pnMaxLength, "</gml:CompositeCurve>" ); } /* -------------------------------------------------------------------- */ /* Polygon */ /* -------------------------------------------------------------------- */ else if( eFType == wkbPolygon || eFType == wkbCurvePolygon ) { OGRCurvePolygon *poCP = (OGRCurvePolygon *) poGeometry; // Buffer for polygon tag name + srsName attribute if set const size_t nPolyTagLength = 13; char* pszPolyTagName = NULL; pszPolyTagName = (char *) CPLMalloc( nPolyTagLength + nAttrsLength + 1 ); // Compose Polygon tag with or without srsName attribute sprintf( pszPolyTagName, "<gml:Polygon%s>", szAttributes ); AppendString( ppszText, pnLength, pnMaxLength, pszPolyTagName ); // FREE TAG BUFFER CPLFree( pszPolyTagName ); // Don't add srsName to polygon rings if( poCP->getExteriorRingCurve() != NULL ) { AppendString( ppszText, pnLength, pnMaxLength, "<gml:exterior>" ); if( !OGR2GML3GeometryAppend( poCP->getExteriorRingCurve(), poSRS, ppszText, pnLength, pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve, NULL, nSRSDimensionLocFlags, TRUE) ) { return FALSE; } AppendString( ppszText, pnLength, pnMaxLength, "</gml:exterior>" ); } for( int iRing = 0; iRing < poCP->getNumInteriorRings(); iRing++ ) { OGRCurve *poRing = poCP->getInteriorRingCurve(iRing); AppendString( ppszText, pnLength, pnMaxLength, "<gml:interior>" ); if( !OGR2GML3GeometryAppend( poRing, poSRS, ppszText, pnLength, pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve, NULL, nSRSDimensionLocFlags, TRUE) ) return FALSE; AppendString( ppszText, pnLength, pnMaxLength, "</gml:interior>" ); } AppendString( ppszText, pnLength, pnMaxLength, "</gml:Polygon>" ); } /* -------------------------------------------------------------------- */ /* MultiSurface, MultiCurve, MultiPoint, MultiGeometry */ /* -------------------------------------------------------------------- */ else if( eFType == wkbMultiPolygon || eFType == wkbMultiSurface || eFType == wkbMultiLineString || eFType == wkbMultiCurve || eFType == wkbMultiPoint || eFType == wkbGeometryCollection ) { OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry; int iMember; const char *pszElemClose = NULL; const char *pszMemberElem = NULL; // Buffer for opening tag + srsName attribute char* pszElemOpen = NULL; if( eFType == wkbMultiPolygon || eFType == wkbMultiSurface ) { pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 ); sprintf( pszElemOpen, "MultiSurface%s>", szAttributes ); pszElemClose = "MultiSurface>"; pszMemberElem = "surfaceMember>"; } else if( eFType == wkbMultiLineString || eFType == wkbMultiCurve ) { pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 ); sprintf( pszElemOpen, "MultiCurve%s>", szAttributes ); pszElemClose = "MultiCurve>"; pszMemberElem = "curveMember>"; } else if( eFType == wkbMultiPoint ) { pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 ); sprintf( pszElemOpen, "MultiPoint%s>", szAttributes ); pszElemClose = "MultiPoint>"; pszMemberElem = "pointMember>"; } else { pszElemOpen = (char *) CPLMalloc( 19 + nAttrsLength + 1 ); sprintf( pszElemOpen, "MultiGeometry%s>", szAttributes ); pszElemClose = "MultiGeometry>"; pszMemberElem = "geometryMember>"; } AppendString( ppszText, pnLength, pnMaxLength, "<gml:" ); AppendString( ppszText, pnLength, pnMaxLength, pszElemOpen ); for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++) { OGRGeometry *poMember = poGC->getGeometryRef( iMember ); AppendString( ppszText, pnLength, pnMaxLength, "<gml:" ); AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem ); char* pszGMLIdSub = NULL; if (pszGMLId != NULL) pszGMLIdSub = CPLStrdup(CPLSPrintf("%s.%d", pszGMLId, iMember)); if( !OGR2GML3GeometryAppend( poMember, poSRS, ppszText, pnLength, pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve, pszGMLIdSub, nSRSDimensionLocFlags, FALSE ) ) { CPLFree(pszGMLIdSub); return FALSE; } CPLFree(pszGMLIdSub); AppendString( ppszText, pnLength, pnMaxLength, "</gml:" ); AppendString( ppszText, pnLength, pnMaxLength, pszMemberElem ); } AppendString( ppszText, pnLength, pnMaxLength, "</gml:" ); AppendString( ppszText, pnLength, pnMaxLength, pszElemClose ); // FREE TAG BUFFER CPLFree( pszElemOpen ); } else { CPLError(CE_Failure, CPLE_NotSupported, "Unsupported geometry type %s", OGRGeometryTypeToName(eType)); return FALSE; } return TRUE; }
void OGRILI1Layer::JoinSurfaceLayer( OGRILI1Layer* poSurfaceLineLayer, int nSurfaceFieldIndex ) { CPLDebug( "OGR_ILI", "Joining surface layer %s with geometries", GetLayerDefn()->GetName()); OGRwkbGeometryType geomType = GetLayerDefn()->GetGeomFieldDefn(nSurfaceFieldIndex)->GetType(); std::map<OGRFeature*, std::vector<OGRCurve*> > oMapFeatureToGeomSet; poSurfaceLineLayer->ResetReading(); // First map: for each target curvepolygon, find all belonging curves while (OGRFeature *linefeature = poSurfaceLineLayer->GetNextFeatureRef()) { //OBJE entries with same _RefTID are polygon rings of same feature OGRFeature *feature = nullptr; if (poFeatureDefn->GetFieldDefn(0)->GetType() == OFTString) { feature = GetFeatureRef(linefeature->GetFieldAsString(1)); } else { GIntBig reftid = linefeature->GetFieldAsInteger64(1); feature = GetFeatureRef(reftid); } if (feature) { OGRGeometry* poGeom = linefeature->GetGeomFieldRef(0); OGRMultiCurve *curves = dynamic_cast<OGRMultiCurve *>(poGeom); if( curves ) { for (auto&& curve: curves ) { if( !curve->IsEmpty() ) oMapFeatureToGeomSet[feature].push_back(curve); } } } else { CPLError( CE_Warning, CPLE_AppDefined, "Couldn't join feature FID " CPL_FRMT_GIB, linefeature->GetFieldAsInteger64(1) ); } } // Now for each target polygon, assemble the curves together. std::map<OGRFeature*, std::vector<OGRCurve*> >::const_iterator oIter = oMapFeatureToGeomSet.begin(); for( ; oIter != oMapFeatureToGeomSet.end(); ++oIter ) { OGRFeature* feature = oIter->first; std::vector<OGRCurve*> oCurves = oIter->second; std::vector<OGRCurve*> oSetDestCurves; double dfLargestArea = 0.0; OGRCurve* poLargestCurve = nullptr; while( true ) { std::vector<OGRCurve*>::iterator oIterCurves = oCurves.begin(); if( oIterCurves == oCurves.end() ) break; OGRPoint endPointCC; OGRCompoundCurve* poCC = new OGRCompoundCurve(); bool bFirst = true; while( true ) { bool bNewCurveAdded = false; const double dfEps = 1e-14; for(oIterCurves = oCurves.begin(); oIterCurves != oCurves.end(); ++oIterCurves ) { OGRCurve* curve = *oIterCurves; OGRPoint startPoint; OGRPoint endPoint; curve->StartPoint(&startPoint); curve->EndPoint(&endPoint); if( bFirst || (fabs(startPoint.getX() - endPointCC.getX()) < dfEps && fabs(startPoint.getY() - endPointCC.getY()) < dfEps) ) { bFirst = false; curve->EndPoint(&endPointCC); const OGRwkbGeometryType eCurveType = wkbFlatten(curve->getGeometryType()); if( eCurveType == wkbCompoundCurve ) { OGRCompoundCurve* poCCSub = curve->toCompoundCurve(); for( auto&& subCurve: poCCSub ) { poCC->addCurve(subCurve); } } else { poCC->addCurve( curve ); } oCurves.erase( oIterCurves ); bNewCurveAdded = true; break; } else if( fabs(endPoint.getX() - endPointCC.getX()) < dfEps && fabs(endPoint.getY() - endPointCC.getY()) < dfEps ) { curve->StartPoint(&endPointCC); const OGRwkbGeometryType eCurveType = wkbFlatten(curve->getGeometryType()); if( eCurveType == wkbLineString || eCurveType == wkbCircularString ) { OGRSimpleCurve* poSC = curve->clone()->toSimpleCurve(); poSC->reversePoints(); poCC->addCurveDirectly( poSC ); } else if( eCurveType == wkbCompoundCurve ) { // Reverse the order of the elements of the // compound curve OGRCompoundCurve* poCCSub = curve->toCompoundCurve(); for( int i=poCCSub->getNumCurves()-1; i >= 0; --i ) { OGRSimpleCurve* poSC = poCCSub->getCurve(i)-> clone()->toSimpleCurve(); poSC->reversePoints(); poCC->addCurveDirectly(poSC); } } oCurves.erase( oIterCurves ); bNewCurveAdded = true; break; } } if( !bNewCurveAdded || oCurves.empty() || poCC->get_IsClosed() ) break; } if( !poCC->get_IsClosed() ) { char* pszJSon = poCC->exportToJson(); CPLError(CE_Warning, CPLE_AppDefined, "A ring %s for feature " CPL_FRMT_GIB " in layer %s " "was not closed. Dropping it", pszJSon, feature->GetFID(), GetName()); delete poCC; CPLFree(pszJSon); } else { double dfArea = poCC->get_Area(); if( dfArea >= dfLargestArea ) { dfLargestArea = dfArea; poLargestCurve = poCC; } oSetDestCurves.push_back(poCC); } } // Now build the final polygon by first inserting the largest ring. OGRCurvePolygon *poPoly = (geomType == wkbPolygon) ? new OGRPolygon() : new OGRCurvePolygon(); if( poLargestCurve ) { std::vector<OGRCurve*>::iterator oIterCurves = oSetDestCurves.begin(); for( ; oIterCurves != oSetDestCurves.end(); ++oIterCurves ) { OGRCurve* poCurve = *oIterCurves; if( poCurve == poLargestCurve ) { oSetDestCurves.erase( oIterCurves ); break; } } if (geomType == wkbPolygon) { poLargestCurve = OGRCurve::CastToLinearRing(poLargestCurve); } OGRErr error = poPoly->addRingDirectly(poLargestCurve); if (error != OGRERR_NONE) { char* pszJSon = poLargestCurve->exportToJson(); CPLError(CE_Warning, CPLE_AppDefined, "Cannot add ring %s to feature " CPL_FRMT_GIB " in layer %s", pszJSon, feature->GetFID(), GetName() ); CPLFree(pszJSon); } oIterCurves = oSetDestCurves.begin(); for( ; oIterCurves != oSetDestCurves.end(); ++oIterCurves ) { OGRCurve* poCurve = *oIterCurves; if (geomType == wkbPolygon) { poCurve = OGRCurve::CastToLinearRing(poCurve); } error = poPoly->addRingDirectly(poCurve); if (error != OGRERR_NONE) { char* pszJSon = poCurve->exportToJson(); CPLError(CE_Warning, CPLE_AppDefined, "Cannot add ring %s to feature " CPL_FRMT_GIB " in layer %s", pszJSon, feature->GetFID(), GetName() ); CPLFree(pszJSon); } } } feature->SetGeomFieldDirectly(nSurfaceFieldIndex, poPoly); } ResetReading(); }