OGRGeometryCollection* make() { OGRGeometryCollection* poCollection = new OGRGeometryCollection(); poCollection->addGeometryDirectly(make<OGRPoint>()); poCollection->addGeometryDirectly(make<OGRLinearRing>()); return poCollection; }
OGRGeometry* OGRGeometryCollection::getCurveGeometry( const char* const* papszOptions) const { OGRGeometryCollection* poGC = OGRGeometryFactory::createGeometry( OGR_GT_GetCurve(getGeometryType()))->toGeometryCollection(); if( poGC == nullptr ) return nullptr; poGC->assignSpatialReference( getSpatialReference() ); bool bHasCurveGeometry = false; for( int iGeom = 0; iGeom < nGeomCount; iGeom++ ) { OGRGeometry* poSubGeom = papoGeoms[iGeom]->getCurveGeometry(papszOptions); if( poSubGeom->hasCurveGeometry() ) bHasCurveGeometry = true; poGC->addGeometryDirectly( poSubGeom ); } if( !bHasCurveGeometry ) { delete poGC; return clone(); } return poGC; }
int OGRDB2GeometryValidator::ValidatePolygon(OGRPolygon* poGeom) { int i,j; OGRLinearRing* poRing = poGeom->getExteriorRing(); OGRGeometry* poInteriorRing; if (poRing == NULL) return FALSE; OGRGeometryCollection* poGeometries = NULL; if (!ValidateLinearRing(poRing)) { if (poGeom->getNumInteriorRings() > 0) { poGeometries = new OGRGeometryCollection(); poGeometries->addGeometryDirectly(poValidGeometry); } } for (i = 0; i < poGeom->getNumInteriorRings(); i++) { poInteriorRing = poGeom->getInteriorRing(i); if (!ValidateLinearRing((OGRLinearRing*)poInteriorRing)) { if (!poGeometries) { poGeometries = new OGRGeometryCollection(); poGeometries->addGeometry(poRing); for (j = 0; j < i; j++) poGeometries->addGeometry(poGeom->getInteriorRing(j)); } poGeometries->addGeometry(poValidGeometry); continue; } if (poGeometries) poGeometries->addGeometry(poInteriorRing); } if (poGeometries) { if (poValidGeometry) delete poValidGeometry; poValidGeometry = poGeometries; } return (poValidGeometry == NULL); }
OGRGeometry* OGRGeometryCollection::getLinearGeometry(double dfMaxAngleStepSizeDegrees, const char* const* papszOptions) const { OGRGeometryCollection* poGC = (OGRGeometryCollection*) OGRGeometryFactory::createGeometry(OGR_GT_GetLinear(getGeometryType())); if( poGC == NULL ) return NULL; poGC->assignSpatialReference( getSpatialReference() ); for( int iGeom = 0; iGeom < nGeomCount; iGeom++ ) { OGRGeometry* poSubGeom = papoGeoms[iGeom]->getLinearGeometry(dfMaxAngleStepSizeDegrees, papszOptions); poGC->addGeometryDirectly( poSubGeom ); } return poGC; }
OGRGeometryCollection* OGRMSSQLGeometryParser::ReadGeometryCollection(int iShape) { int i; OGRGeometryCollection* poGeomColl = new OGRGeometryCollection(); OGRGeometry* poGeom; for (i = iShape + 1; i < nNumShapes; i++) { poGeom = NULL; if (ParentOffset(i) == (unsigned int)iShape) { switch (ShapeType(i)) { case ST_POINT: poGeom = ReadPoint(i); break; case ST_LINESTRING: poGeom = ReadLineString(i); break; case ST_POLYGON: poGeom = ReadPolygon(i); break; case ST_MULTIPOINT: poGeom = ReadMultiPoint(i); break; case ST_MULTILINESTRING: poGeom = ReadMultiLineString(i); break; case ST_MULTIPOLYGON: poGeom = ReadMultiPolygon(i); break; case ST_GEOMETRYCOLLECTION: poGeom = ReadGeometryCollection(i); break; } } if ( poGeom ) poGeomColl->addGeometryDirectly( poGeom ); } return poGeomColl; }
OGRGeometry* GML_BuildOGRGeometryFromList(const CPLXMLNode* const * papsGeometry, int bTryToMakeMultipolygons, int bInvertAxisOrderIfLatLong, const char* pszDefaultSRSName, int bConsiderEPSGAsURN, int bGetSecondaryGeometryOption, void* hCacheSRS, int bFaceHoleNegative) { OGRGeometry* poGeom = NULL; int i; OGRGeometryCollection* poCollection = NULL; for(i=0;papsGeometry[i] != NULL;i++) { OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i], bGetSecondaryGeometryOption, 0, 0, FALSE, TRUE, bFaceHoleNegative ); if (poSubGeom) { if (poGeom == NULL) poGeom = poSubGeom; else { if (poCollection == NULL) { if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = new OGRMultiPolygon(); poGeomColl->addGeometryDirectly(poGeom); poGeomColl->addGeometryDirectly(poSubGeom); poGeom = poGeomColl; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; poGeomColl->addGeometryDirectly(poSubGeom); } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbMultiPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; OGRGeometryCollection* poGeomColl2 = (OGRGeometryCollection* )poSubGeom; int nCount = poGeomColl2->getNumGeometries(); int i; for(i=0;i<nCount;i++) { poGeomColl->addGeometry(poGeomColl2->getGeometryRef(i)); } delete poSubGeom; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) { delete poGeom; delete poSubGeom; return GML_BuildOGRGeometryFromList(papsGeometry, FALSE, bInvertAxisOrderIfLatLong, pszDefaultSRSName, bConsiderEPSGAsURN, bGetSecondaryGeometryOption, hCacheSRS); } else { poCollection = new OGRGeometryCollection(); poCollection->addGeometryDirectly(poGeom); poGeom = poCollection; } } if (poCollection != NULL) { poCollection->addGeometryDirectly(poSubGeom); } } } } if( poGeom == NULL ) return NULL; std::string osWork; const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, bConsiderEPSGAsURN); const char* pszNameLookup = pszSRSName; if( pszNameLookup == NULL ) pszNameLookup = pszDefaultSRSName; if (pszNameLookup != NULL) { SRSCache* poSRSCache = (SRSCache*)hCacheSRS; SRSDesc& oSRSDesc = poSRSCache->Get(pszNameLookup); poGeom->assignSpatialReference(oSRSDesc.poSRS); if (oSRSDesc.bAxisInvert && bInvertAxisOrderIfLatLong) poGeom->swapXY(); } return poGeom; }
OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type) { OGRGeometryCollection *gm = new OGRGeometryCollection(); DOMElement *childElem = elem; while (childElem != NULL) { char* pszTagName = XMLString::transcode(childElem->getTagName()); switch (type) { case ILI2_COORD_TYPE : if (cmpStr(ILI2_COORD, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getPoint(childElem); } break; case ILI2_ARC_TYPE : // is it possible here? It have to be a ARC or COORD before (getPreviousSibling) if (cmpStr(ILI2_ARC, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getArc(childElem); } break; case ILI2_POLYLINE_TYPE : if (cmpStr(ILI2_POLYLINE, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getLineString(childElem, FALSE); } break; case ILI2_BOUNDARY_TYPE : if (cmpStr(ILI2_BOUNDARY, pszTagName) == 0) { delete gm; XMLString::release(&pszTagName); return getLineString(childElem, FALSE); } break; case ILI2_AREA_TYPE : if ((cmpStr(ILI2_AREA, pszTagName) == 0) || (cmpStr(ILI2_SURFACE, pszTagName) == 0)) { delete gm; XMLString::release(&pszTagName); return getPolygon(childElem); } break; default : if (type >= ILI2_GEOMCOLL_TYPE) { int subType = getGeometryTypeOfElem(childElem); //???? gm->addGeometryDirectly(getGeometry(childElem, subType)); } break; } XMLString::release(&pszTagName); // GEOMCOLL childElem = (DOMElement *)childElem->getNextSibling(); } return gm; }
OGRErr OGRCreateFromGeomedia( GByte *pabyGeom, OGRGeometry **ppoGeom, int nBytes ) { *ppoGeom = NULL; if( nBytes < 16 ) return OGRERR_FAILURE; if( !(pabyGeom[1] == 0xFF && pabyGeom[2] == 0xD2 && pabyGeom[3] == 0x0F) ) return OGRERR_FAILURE; int nGeomType = pabyGeom[0]; pabyGeom += 16; nBytes -= 16; if( nGeomType == GEOMEDIA_POINT || nGeomType == GEOMEDIA_ORIENTED_POINT ) { if (nBytes < 3 * 8) return OGRERR_FAILURE; double dfX, dfY, dfZ; memcpy(&dfX, pabyGeom, 8); CPL_LSBPTR64(&dfX); memcpy(&dfY, pabyGeom + 8, 8); CPL_LSBPTR64(&dfY); memcpy(&dfZ, pabyGeom + 16, 8); CPL_LSBPTR64(&dfZ); *ppoGeom = new OGRPoint( dfX, dfY, dfZ ); return OGRERR_NONE; } else if ( nGeomType == GEOMEDIA_POLYLINE ) { if (nBytes < 4) return OGRERR_FAILURE; int nPoints; memcpy(&nPoints, pabyGeom, 4); CPL_LSBPTR32(&nPoints); pabyGeom += 4; nBytes -= 4; if (nPoints < 0 || nPoints > INT_MAX / 24 || nBytes < nPoints * 24) return OGRERR_FAILURE; OGRLineString* poLS = new OGRLineString(); poLS->setNumPoints(nPoints); int i; for(i=0;i<nPoints;i++) { double dfX, dfY, dfZ; memcpy(&dfX, pabyGeom, 8); CPL_LSBPTR64(&dfX); memcpy(&dfY, pabyGeom + 8, 8); CPL_LSBPTR64(&dfY); memcpy(&dfZ, pabyGeom + 16, 8); CPL_LSBPTR64(&dfZ); poLS->setPoint(i, dfX, dfY, dfZ); pabyGeom += 24; } *ppoGeom = poLS; return OGRERR_NONE; } else if ( nGeomType == GEOMEDIA_POLYGON ) { if (nBytes < 4) return OGRERR_FAILURE; int nPoints; memcpy(&nPoints, pabyGeom, 4); CPL_LSBPTR32(&nPoints); pabyGeom += 4; nBytes -= 4; if (nPoints < 0 || nPoints > INT_MAX / 24 || nBytes < nPoints * 24) return OGRERR_FAILURE; OGRLinearRing* poRing = new OGRLinearRing(); poRing->setNumPoints(nPoints); int i; for(i=0;i<nPoints;i++) { double dfX, dfY, dfZ; memcpy(&dfX, pabyGeom, 8); CPL_LSBPTR64(&dfX); memcpy(&dfY, pabyGeom + 8, 8); CPL_LSBPTR64(&dfY); memcpy(&dfZ, pabyGeom + 16, 8); CPL_LSBPTR64(&dfZ); poRing->setPoint(i, dfX, dfY, dfZ); pabyGeom += 24; } OGRPolygon* poPoly = new OGRPolygon(); poPoly->addRingDirectly(poRing); *ppoGeom = poPoly; return OGRERR_NONE; } else if ( nGeomType == GEOMEDIA_BOUNDARY ) { if (nBytes < 4) return OGRERR_FAILURE; int nExteriorSize; memcpy(&nExteriorSize, pabyGeom, 4); CPL_LSBPTR32(&nExteriorSize); pabyGeom += 4; nBytes -= 4; if (nBytes < nExteriorSize) return OGRERR_FAILURE; OGRGeometry* poExteriorGeom = NULL; if (OGRCreateFromGeomedia( pabyGeom, &poExteriorGeom, nExteriorSize ) != OGRERR_NONE) return OGRERR_FAILURE; if ( wkbFlatten( poExteriorGeom->getGeometryType() ) != wkbPolygon ) { delete poExteriorGeom; return OGRERR_FAILURE; } pabyGeom += nExteriorSize; nBytes -= nExteriorSize; if (nBytes < 4) { delete poExteriorGeom; return OGRERR_FAILURE; } int nInteriorSize; memcpy(&nInteriorSize, pabyGeom, 4); CPL_LSBPTR32(&nInteriorSize); pabyGeom += 4; nBytes -= 4; if (nBytes < nInteriorSize) { delete poExteriorGeom; return OGRERR_FAILURE; } OGRGeometry* poInteriorGeom = NULL; if (OGRCreateFromGeomedia( pabyGeom, &poInteriorGeom, nInteriorSize ) != OGRERR_NONE) { delete poExteriorGeom; return OGRERR_FAILURE; } OGRwkbGeometryType interiorGeomType = wkbFlatten( poInteriorGeom->getGeometryType() ); if ( interiorGeomType == wkbPolygon ) { ((OGRPolygon*)poExteriorGeom)->addRing(((OGRPolygon*)poInteriorGeom)->getExteriorRing()); } else if ( interiorGeomType == wkbMultiPolygon ) { int numGeom = ((OGRMultiPolygon*)poInteriorGeom)->getNumGeometries(); for ( int i = 0; i < numGeom; ++i ) { OGRPolygon* poInteriorPolygon = (OGRPolygon*)((OGRMultiPolygon*)poInteriorGeom)->getGeometryRef(i); ((OGRPolygon*)poExteriorGeom)->addRing( poInteriorPolygon->getExteriorRing() ); } } else { delete poExteriorGeom; delete poInteriorGeom; return OGRERR_FAILURE; } delete poInteriorGeom; *ppoGeom = poExteriorGeom; return OGRERR_NONE; } else if ( nGeomType == GEOMEDIA_COLLECTION || nGeomType == GEOMEDIA_MULTILINE || nGeomType == GEOMEDIA_MULTIPOLYGON ) { if (nBytes < 4) return OGRERR_FAILURE; int i; int nParts; memcpy(&nParts, pabyGeom, 4); CPL_LSBPTR32(&nParts); pabyGeom += 4; nBytes -= 4; if (nParts < 0 || nParts > INT_MAX / (4 + 16) || nBytes < nParts * (4 + 16)) return OGRERR_FAILURE; /* Can this collection be considered as a multipolyline or multipolygon ? */ if ( nGeomType == GEOMEDIA_COLLECTION ) { GByte* pabyGeomBackup = pabyGeom; int nBytesBackup = nBytes; int bAllPolyline = TRUE; int bAllPolygon = TRUE; for(i=0;i<nParts;i++) { if (nBytes < 4) return OGRERR_FAILURE; int nSubBytes; memcpy(&nSubBytes, pabyGeom, 4); CPL_LSBPTR32(&nSubBytes); if (nSubBytes < 0) { return OGRERR_FAILURE; } pabyGeom += 4; nBytes -= 4; if (nBytes < nSubBytes) { return OGRERR_FAILURE; } if( nSubBytes < 16 ) return OGRERR_FAILURE; if( !(pabyGeom[1] == 0xFF && pabyGeom[2] == 0xD2 && pabyGeom[3] == 0x0F) ) return OGRERR_FAILURE; int nSubGeomType = pabyGeom[0]; if ( nSubGeomType != GEOMEDIA_POLYLINE ) bAllPolyline = FALSE; if ( nSubGeomType != GEOMEDIA_POLYGON ) bAllPolygon = FALSE; pabyGeom += nSubBytes; nBytes -= nSubBytes; } pabyGeom = pabyGeomBackup; nBytes = nBytesBackup; if (bAllPolyline) nGeomType = GEOMEDIA_MULTILINE; else if (bAllPolygon) nGeomType = GEOMEDIA_MULTIPOLYGON; } OGRGeometryCollection* poColl = (nGeomType == GEOMEDIA_MULTILINE) ? new OGRMultiLineString() : (nGeomType == GEOMEDIA_MULTIPOLYGON) ? new OGRMultiPolygon() : new OGRGeometryCollection(); for(i=0;i<nParts;i++) { if (nBytes < 4) return OGRERR_FAILURE; int nSubBytes; memcpy(&nSubBytes, pabyGeom, 4); CPL_LSBPTR32(&nSubBytes); if (nSubBytes < 0) { delete poColl; return OGRERR_FAILURE; } pabyGeom += 4; nBytes -= 4; if (nBytes < nSubBytes) { delete poColl; return OGRERR_FAILURE; } OGRGeometry* poSubGeom = NULL; if (OGRCreateFromGeomedia( pabyGeom, &poSubGeom, nSubBytes ) == OGRERR_NONE) { if (wkbFlatten(poColl->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbLineString) { OGRPolygon* poPoly = new OGRPolygon(); OGRLinearRing* poRing = new OGRLinearRing(); poRing->addSubLineString((OGRLineString*)poSubGeom); poPoly->addRingDirectly(poRing); delete poSubGeom; poSubGeom = poPoly; } if (poColl->addGeometryDirectly(poSubGeom) != OGRERR_NONE) { //printf("%d %d\n", poColl->getGeometryType() & ~wkb25DBit, poSubGeom->getGeometryType() & ~wkb25DBit); delete poSubGeom; } } pabyGeom += nSubBytes; nBytes -= nSubBytes; } *ppoGeom = poColl; return OGRERR_NONE; } else { CPLDebug("GEOMEDIA", "Unhandled type %d", nGeomType); } return OGRERR_FAILURE; }
OGRGeometry* GML_BuildOGRGeometryFromList(const CPLXMLNode* const * papsGeometry, int bTryToMakeMultipolygons, int bInvertAxisOrderIfLatLong, const char* pszDefaultSRSName, int bConsiderEPSGAsURN, int bGetSecondaryGeometryOption, void* hCacheSRS) { OGRGeometry* poGeom = NULL; int i; OGRGeometryCollection* poCollection = NULL; for(i=0;papsGeometry[i] != NULL;i++) { OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i], bGetSecondaryGeometryOption ); if (poSubGeom) { if (poGeom == NULL) poGeom = poSubGeom; else { if (poCollection == NULL) { if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = new OGRMultiPolygon(); poGeomColl->addGeometryDirectly(poGeom); poGeomColl->addGeometryDirectly(poSubGeom); poGeom = poGeomColl; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; poGeomColl->addGeometryDirectly(poSubGeom); } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbMultiPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; OGRGeometryCollection* poGeomColl2 = (OGRGeometryCollection* )poSubGeom; int nCount = poGeomColl2->getNumGeometries(); int i; for(i=0;i<nCount;i++) { poGeomColl->addGeometry(poGeomColl2->getGeometryRef(i)); } delete poSubGeom; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) { delete poGeom; delete poSubGeom; return GML_BuildOGRGeometryFromList(papsGeometry, FALSE, bInvertAxisOrderIfLatLong, pszDefaultSRSName, bConsiderEPSGAsURN, bGetSecondaryGeometryOption, hCacheSRS); } else { poCollection = new OGRGeometryCollection(); poCollection->addGeometryDirectly(poGeom); poGeom = poCollection; } } if (poCollection != NULL) { poCollection->addGeometryDirectly(poSubGeom); } } } } if ( poGeom != NULL && bInvertAxisOrderIfLatLong ) { std::string osWork; const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry, osWork, bConsiderEPSGAsURN); const char* pszNameLookup = pszSRSName ? pszSRSName : pszDefaultSRSName; if (pszNameLookup != NULL) { SRSCache* poSRSCache = (SRSCache*)hCacheSRS; int bSwap; if (strcmp(poSRSCache->osLastSRSName.c_str(), pszNameLookup) == 0) { bSwap = poSRSCache->bAxisInvertLastSRSName; } else { bSwap = GML_IsSRSLatLongOrder(pszNameLookup); poSRSCache->osLastSRSName = pszNameLookup; poSRSCache->bAxisInvertLastSRSName= bSwap; } if (bSwap) poGeom->swapXY(); } } return poGeom; }
void OGRDXFDataSource::ReadBlocksSection() { char szLineBuf[257]; int nCode; OGRDXFLayer *poReaderLayer = (OGRDXFLayer *) GetLayerByName( "Entities" ); iEntitiesSectionOffset = oReader.iSrcBufferFileOffset + oReader.iSrcBufferOffset; while( (nCode = ReadValue( szLineBuf, sizeof(szLineBuf) )) > -1 && !EQUAL(szLineBuf,"ENDSEC") ) { // We are only interested in extracting blocks. if( nCode != 0 || !EQUAL(szLineBuf,"BLOCK") ) continue; // Process contents of BLOCK definition till we find the // first entity. CPLString osBlockName; while( (nCode = ReadValue( szLineBuf,sizeof(szLineBuf) )) > 0 ) { if( nCode == 2 ) osBlockName = szLineBuf; // anything else we want? } if( EQUAL(szLineBuf,"ENDBLK") ) continue; UnreadValue(); // Now we will process entities till we run out at the ENDBLK code. // we aggregate the geometries of the features into a multi-geometry, // but throw away other stuff attached to the features. OGRFeature *poFeature; OGRGeometryCollection *poColl = new OGRGeometryCollection(); std::vector<OGRFeature*> apoFeatures; while( (poFeature = poReaderLayer->GetNextUnfilteredFeature()) != NULL ) { if( poFeature->GetStyleString() != NULL && strstr(poFeature->GetStyleString(),"LABEL") != NULL ) { apoFeatures.push_back( poFeature ); } else { poColl->addGeometryDirectly( poFeature->StealGeometry() ); delete poFeature; } } if( poColl->getNumGeometries() == 0 ) delete poColl; else oBlockMap[osBlockName].poGeometry = SimplifyBlockGeometry(poColl); if( apoFeatures.size() > 0 ) oBlockMap[osBlockName].apoFeatures = apoFeatures; } CPLDebug( "DXF", "Read %d blocks with meaningful geometry.", (int) oBlockMap.size() ); }
OGRGeometry* GML_BuildOGRGeometryFromList(char** papszGeometryList, int bTryToMakeMultipolygons, int bInvertAxisOrderIfLatLong, const char* pszDefaultSRSName) { OGRGeometry* poGeom = NULL; if( papszGeometryList != NULL ) { char** papszIter = papszGeometryList; OGRGeometryCollection* poCollection = NULL; while(*papszIter) { OGRGeometry* poSubGeom = OGRGeometryFactory::createFromGML( *papszIter ); if (poSubGeom) { if (poGeom == NULL) poGeom = poSubGeom; else { if (poCollection == NULL) { if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = new OGRMultiPolygon(); poGeomColl->addGeometryDirectly(poGeom); poGeomColl->addGeometryDirectly(poSubGeom); poGeom = poGeomColl; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; poGeomColl->addGeometryDirectly(poSubGeom); } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon && wkbFlatten(poSubGeom->getGeometryType()) == wkbMultiPolygon) { OGRGeometryCollection* poGeomColl = (OGRGeometryCollection* )poGeom; OGRGeometryCollection* poGeomColl2 = (OGRGeometryCollection* )poSubGeom; int nCount = poGeomColl2->getNumGeometries(); int i; for(i=0;i<nCount;i++) { poGeomColl->addGeometry(poGeomColl2->getGeometryRef(i)); } delete poSubGeom; } else if (bTryToMakeMultipolygons && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) { delete poGeom; delete poSubGeom; return GML_BuildOGRGeometryFromList(papszGeometryList, FALSE, bInvertAxisOrderIfLatLong, pszDefaultSRSName); } else { poCollection = new OGRGeometryCollection(); poCollection->addGeometryDirectly(poGeom); poGeom = poCollection; } } if (poCollection != NULL) { poCollection->addGeometryDirectly(poSubGeom); } } } papszIter ++; } } if (bInvertAxisOrderIfLatLong) { char* pszSRSName = GML_ExtractSrsNameFromGeometry(papszGeometryList); if (GML_IsSRSLatLongOrder(pszSRSName ? pszSRSName : pszDefaultSRSName)) poGeom->swapXY(); CPLFree(pszSRSName); } return poGeom; }
static OGRGeometry *kml2geom_rec ( GeometryPtr poKmlGeometry, OGRSpatialReference *poOgrSRS) { /***** ogr geom vars *****/ OGRPoint *poOgrPoint; OGRLineString *poOgrLineString; OGRLinearRing *poOgrLinearRing; OGRPolygon *poOgrPolygon; OGRGeometryCollection *poOgrMultiGeometry; OGRGeometry *poOgrGeometry = NULL; OGRGeometry *poOgrTmpGeometry = NULL; /***** libkml geom vars *****/ CoordinatesPtr poKmlCoordinates; PointPtr poKmlPoint; LineStringPtr poKmlLineString; LinearRingPtr poKmlLinearRing; OuterBoundaryIsPtr poKmlOuterRing; InnerBoundaryIsPtr poKmlInnerRing; PolygonPtr poKmlPolygon; MultiGeometryPtr poKmlMultiGeometry; GxTrackPtr poKmlGxTrack; GxMultiTrackPtr poKmlGxMultiTrack; GeometryPtr poKmlTmpGeometry; Vec3 oKmlVec; size_t nRings, nCoords, nGeom, i; switch ( poKmlGeometry->Type ( ) ) { case kmldom::Type_Point: poKmlPoint = AsPoint ( poKmlGeometry ); if ( poKmlPoint->has_coordinates ( ) ) { poKmlCoordinates = poKmlPoint->get_coordinates ( ); nCoords = poKmlCoordinates->get_coordinates_array_size ( ); if (nCoords > 0) { oKmlVec = poKmlCoordinates->get_coordinates_array_at ( 0 ); if ( oKmlVec.has_altitude ( ) ) poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ), oKmlVec.get_altitude ( ) ); else poOgrPoint = new OGRPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ) ); poOgrGeometry = poOgrPoint; } else { poOgrGeometry = new OGRPoint(); } } else { poOgrGeometry = new OGRPoint(); } break; case kmldom::Type_LineString: poKmlLineString = AsLineString ( poKmlGeometry ); poOgrLineString = new OGRLineString ( ); if ( poKmlLineString->has_coordinates ( ) ) { poKmlCoordinates = poKmlLineString->get_coordinates ( ); nCoords = poKmlCoordinates->get_coordinates_array_size ( ); for ( i = 0; i < nCoords; i++ ) { oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i ); if ( oKmlVec.has_altitude ( ) ) poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ), oKmlVec.get_altitude ( ) ); else poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ) ); } } poOgrGeometry = poOgrLineString; break; case kmldom::Type_LinearRing: poKmlLinearRing = AsLinearRing ( poKmlGeometry ); poOgrLinearRing = new OGRLinearRing ( ); if ( poKmlLinearRing->has_coordinates ( ) ) { poKmlCoordinates = poKmlLinearRing->get_coordinates ( ); nCoords = poKmlCoordinates->get_coordinates_array_size ( ); for ( i = 0; i < nCoords; i++ ) { oKmlVec = poKmlCoordinates->get_coordinates_array_at ( i ); if ( oKmlVec.has_altitude ( ) ) poOgrLinearRing-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ), oKmlVec.get_altitude ( ) ); else poOgrLinearRing-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ) ); } } poOgrGeometry = poOgrLinearRing; break; case kmldom::Type_Polygon: poKmlPolygon = AsPolygon ( poKmlGeometry ); poOgrPolygon = new OGRPolygon ( ); if ( poKmlPolygon->has_outerboundaryis ( ) ) { poKmlOuterRing = poKmlPolygon->get_outerboundaryis ( ); poKmlLinearRing = poKmlOuterRing->get_linearring ( ); if (poKmlLinearRing) { poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS ); poOgrPolygon-> addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry ); } } nRings = poKmlPolygon->get_innerboundaryis_array_size ( ); for ( i = 0; i < nRings; i++ ) { poKmlInnerRing = poKmlPolygon->get_innerboundaryis_array_at ( i ); poKmlLinearRing = poKmlInnerRing->get_linearring ( ); if (poKmlLinearRing) { poOgrTmpGeometry = kml2geom_rec ( poKmlLinearRing, poOgrSRS ); poOgrPolygon-> addRingDirectly ( ( OGRLinearRing * ) poOgrTmpGeometry ); } } poOgrGeometry = poOgrPolygon; break; case kmldom::Type_MultiGeometry: { poKmlMultiGeometry = AsMultiGeometry ( poKmlGeometry ); nGeom = poKmlMultiGeometry->get_geometry_array_size ( ); // Detect subgeometry type to instantiate appropriate // multi geometry type. kmldom::KmlDomType type = kmldom::Type_Unknown; for ( i = 0; i < nGeom; i++ ) { poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i ); if (type == kmldom::Type_Unknown) type = poKmlTmpGeometry->Type(); else if (type != poKmlTmpGeometry->Type()) { type = kmldom::Type_Unknown; break; } } if (type == kmldom::Type_Point) poOgrMultiGeometry = new OGRMultiPoint(); else if (type == kmldom::Type_LineString) poOgrMultiGeometry = new OGRMultiLineString(); else if (type == kmldom::Type_Polygon) poOgrMultiGeometry = new OGRMultiPolygon(); else poOgrMultiGeometry = new OGRGeometryCollection (); for ( i = 0; i < nGeom; i++ ) { poKmlTmpGeometry = poKmlMultiGeometry->get_geometry_array_at ( i ); poOgrTmpGeometry = kml2geom_rec ( poKmlTmpGeometry, poOgrSRS ); poOgrMultiGeometry->addGeometryDirectly ( poOgrTmpGeometry ); } poOgrGeometry = poOgrMultiGeometry; break; } case kmldom::Type_GxTrack: poKmlGxTrack = AsGxTrack ( poKmlGeometry ); nCoords = poKmlGxTrack->get_gx_coord_array_size(); poOgrLineString = new OGRLineString ( ); for ( i = 0; i < nCoords; i++ ) { oKmlVec = poKmlGxTrack->get_gx_coord_array_at ( i ); if ( oKmlVec.has_altitude ( ) ) poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ), oKmlVec.get_altitude ( ) ); else poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ) ); } poOgrGeometry = poOgrLineString; break; case kmldom::Type_GxMultiTrack: { poKmlGxMultiTrack = AsGxMultiTrack ( poKmlGeometry ); nGeom = poKmlGxMultiTrack->get_gx_track_array_size ( ); poOgrMultiGeometry = new OGRMultiLineString(); for( size_t j = 0; j < nGeom; j++ ) { poKmlGxTrack = poKmlGxMultiTrack->get_gx_track_array_at ( j ); nCoords = poKmlGxTrack->get_gx_coord_array_size(); poOgrLineString = new OGRLineString ( ); for ( i = 0; i < nCoords; i++ ) { oKmlVec = poKmlGxTrack->get_gx_coord_array_at ( i ); if ( oKmlVec.has_altitude ( ) ) poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ), oKmlVec.get_altitude ( ) ); else poOgrLineString-> addPoint ( oKmlVec.get_longitude ( ), oKmlVec.get_latitude ( ) ); } poOgrMultiGeometry->addGeometryDirectly(poOgrLineString); } poOgrGeometry = poOgrMultiGeometry; break; } default: break; } if (poOgrGeometry) poOgrGeometry->assignSpatialReference(poOgrSRS); return poOgrGeometry; }
static OGRGeometry* ParseKMLGeometry(/* const */ CPLXMLNode* psXML) { OGRGeometry* poGeom = nullptr; const char* pszGeomType = psXML->pszValue; if (strcmp(pszGeomType, "Point") == 0) { const char* pszCoordinates = CPLGetXMLValue(psXML, "coordinates", nullptr); if (pszCoordinates) { char** papszTokens = CSLTokenizeString2(pszCoordinates, ",", 0); if (CSLCount(papszTokens) == 2) poGeom = new OGRPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1])); else if (CSLCount(papszTokens) == 3) poGeom = new OGRPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1]), CPLAtof(papszTokens[2])); CSLDestroy(papszTokens); } } else if (strcmp(pszGeomType, "LineString") == 0) { const char* pszCoordinates = CPLGetXMLValue(psXML, "coordinates", nullptr); if (pszCoordinates) { OGRLineString* poLS = new OGRLineString(); ParseLineString(poLS, pszCoordinates); poGeom = poLS; } } else if (strcmp(pszGeomType, "Polygon") == 0) { OGRPolygon* poPoly = nullptr; CPLXMLNode* psOuterBoundary = CPLGetXMLNode(psXML, "outerBoundaryIs"); if (psOuterBoundary) { CPLXMLNode* psLinearRing = CPLGetXMLNode(psOuterBoundary, "LinearRing"); const char* pszCoordinates = CPLGetXMLValue( psLinearRing ? psLinearRing : psOuterBoundary, "coordinates", nullptr); if (pszCoordinates) { OGRLinearRing* poLS = new OGRLinearRing(); ParseLineString(poLS, pszCoordinates); poPoly = new OGRPolygon(); poPoly->addRingDirectly(poLS); poGeom = poPoly; } if (poPoly) { CPLXMLNode* psIter = psXML->psChild; while(psIter) { if (psIter->eType == CXT_Element && strcmp(psIter->pszValue, "innerBoundaryIs") == 0) { psLinearRing = CPLGetXMLNode(psIter, "LinearRing"); pszCoordinates = CPLGetXMLValue( psLinearRing ? psLinearRing : psIter, "coordinates", nullptr); if (pszCoordinates) { OGRLinearRing* poLS = new OGRLinearRing(); ParseLineString(poLS, pszCoordinates); poPoly->addRingDirectly(poLS); } } psIter = psIter->psNext; } } } } else if (strcmp(pszGeomType, "MultiGeometry") == 0) { CPLXMLNode* psIter = nullptr; OGRwkbGeometryType eType = wkbUnknown; for(psIter = psXML->psChild; psIter; psIter = psIter->psNext) { if (psIter->eType == CXT_Element) { OGRwkbGeometryType eNewType = wkbUnknown; if (strcmp(psIter->pszValue, "Point") == 0) { eNewType = wkbPoint; } else if (strcmp(psIter->pszValue, "LineString") == 0) { eNewType = wkbLineString; } else if (strcmp(psIter->pszValue, "Polygon") == 0) { eNewType = wkbPolygon; } else break; if (eType == wkbUnknown) eType = eNewType; else if (eType != eNewType) break; } } OGRGeometryCollection* poColl = nullptr; if (psIter != nullptr) poColl = new OGRGeometryCollection(); else if (eType == wkbPoint) poColl = new OGRMultiPoint(); else if (eType == wkbLineString) poColl = new OGRMultiLineString(); else if (eType == wkbPolygon) poColl = new OGRMultiPolygon(); else { CPLAssert(false); } for(psIter = psXML->psChild; psIter; psIter = psIter->psNext) { if (psIter->eType == CXT_Element) { OGRGeometry* poSubGeom = ParseKMLGeometry(psIter); if (poSubGeom) poColl->addGeometryDirectly(poSubGeom); } } poGeom = poColl; } return poGeom; }
static OGRGeometry *GML2OGRGeometry_XMLNode( CPLXMLNode *psNode ) { const char *pszBaseGeometry = BareGMLElement( psNode->pszValue ); /* -------------------------------------------------------------------- */ /* Polygon */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"Polygon") ) { CPLXMLNode *psChild; OGRPolygon *poPolygon = new OGRPolygon(); OGRLinearRing *poRing; // Find outer ring. psChild = FindBareXMLChild( psNode, "outerBoundaryIs" ); if( psChild == NULL || psChild->psChild == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Missing outerBoundaryIs property on Polygon." ); delete poPolygon; return NULL; } // Translate outer ring and add to polygon. poRing = (OGRLinearRing *) GML2OGRGeometry_XMLNode( psChild->psChild ); if( poRing == NULL ) { delete poPolygon; return NULL; } if( !EQUAL(poRing->getGeometryName(),"LINEARRING") ) { CPLError( CE_Failure, CPLE_AppDefined, "Got %.500s geometry as outerBoundaryIs instead of LINEARRING.", poRing->getGeometryName() ); delete poPolygon; delete poRing; return NULL; } poPolygon->addRingDirectly( poRing ); // Find all inner rings for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext ) { if( psChild->eType == CXT_Element && EQUAL(BareGMLElement(psChild->pszValue),"innerBoundaryIs") ) { poRing = (OGRLinearRing *) GML2OGRGeometry_XMLNode( psChild->psChild ); if( !EQUAL(poRing->getGeometryName(),"LINEARRING") ) { CPLError( CE_Failure, CPLE_AppDefined, "Got %.500s geometry as innerBoundaryIs instead of LINEARRING.", poRing->getGeometryName() ); delete poPolygon; delete poRing; return NULL; } poPolygon->addRingDirectly( poRing ); } } return poPolygon; } /* -------------------------------------------------------------------- */ /* LinearRing */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"LinearRing") ) { OGRLinearRing *poLinearRing = new OGRLinearRing(); if( !ParseGMLCoordinates( psNode, poLinearRing ) ) { delete poLinearRing; return NULL; } return poLinearRing; } /* -------------------------------------------------------------------- */ /* LineString */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"LineString") ) { OGRLineString *poLine = new OGRLineString(); if( !ParseGMLCoordinates( psNode, poLine ) ) { delete poLine; return NULL; } return poLine; } /* -------------------------------------------------------------------- */ /* PointType */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"PointType") || EQUAL(pszBaseGeometry,"Point") ) { OGRPoint *poPoint = new OGRPoint(); if( !ParseGMLCoordinates( psNode, poPoint ) ) { delete poPoint; return NULL; } return poPoint; } /* -------------------------------------------------------------------- */ /* Box */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"BoxType") || EQUAL(pszBaseGeometry,"Box") ) { OGRLineString oPoints; if( !ParseGMLCoordinates( psNode, &oPoints ) ) return NULL; if( oPoints.getNumPoints() < 2 ) return NULL; OGRLinearRing *poBoxRing = new OGRLinearRing(); OGRPolygon *poBoxPoly = new OGRPolygon(); poBoxRing->setNumPoints( 5 ); poBoxRing->setPoint( 0, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) ); poBoxRing->setPoint( 1, oPoints.getX(1), oPoints.getY(0), oPoints.getZ(0) ); poBoxRing->setPoint( 2, oPoints.getX(1), oPoints.getY(1), oPoints.getZ(1) ); poBoxRing->setPoint( 3, oPoints.getX(0), oPoints.getY(1), oPoints.getZ(0) ); poBoxRing->setPoint( 4, oPoints.getX(0), oPoints.getY(0), oPoints.getZ(0) ); poBoxPoly->addRingDirectly( poBoxRing ); return poBoxPoly; } /* -------------------------------------------------------------------- */ /* MultiPolygon */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"MultiPolygon") ) { CPLXMLNode *psChild; OGRMultiPolygon *poMPoly = new OGRMultiPolygon(); // Find all inner rings for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext ) { if( psChild->eType == CXT_Element && EQUAL(BareGMLElement(psChild->pszValue),"polygonMember") ) { OGRPolygon *poPolygon; poPolygon = (OGRPolygon *) GML2OGRGeometry_XMLNode( psChild->psChild ); if( poPolygon == NULL ) { delete poMPoly; return NULL; } if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") ) { CPLError( CE_Failure, CPLE_AppDefined, "Got %.500s geometry as polygonMember instead of MULTIPOLYGON.", poPolygon->getGeometryName() ); delete poPolygon; delete poMPoly; return NULL; } poMPoly->addGeometryDirectly( poPolygon ); } } return poMPoly; } /* -------------------------------------------------------------------- */ /* MultiPoint */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"MultiPoint") ) { CPLXMLNode *psChild; OGRMultiPoint *poMP = new OGRMultiPoint(); // collect points. for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext ) { if( psChild->eType == CXT_Element && EQUAL(BareGMLElement(psChild->pszValue),"pointMember") ) { OGRPoint *poPoint; poPoint = (OGRPoint *) GML2OGRGeometry_XMLNode( psChild->psChild ); if( poPoint == NULL || wkbFlatten(poPoint->getGeometryType()) != wkbPoint ) { CPLError( CE_Failure, CPLE_AppDefined, "Got %.500s geometry as pointMember instead of MULTIPOINT", poPoint ? poPoint->getGeometryName() : "NULL" ); delete poPoint; delete poMP; return NULL; } poMP->addGeometryDirectly( poPoint ); } } return poMP; } /* -------------------------------------------------------------------- */ /* MultiLineString */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"MultiLineString") ) { CPLXMLNode *psChild; OGRMultiLineString *poMP = new OGRMultiLineString(); // collect lines for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext ) { if( psChild->eType == CXT_Element && EQUAL(BareGMLElement(psChild->pszValue),"lineStringMember") ) { OGRGeometry *poGeom; poGeom = GML2OGRGeometry_XMLNode( psChild->psChild ); if( poGeom == NULL || wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) { CPLError( CE_Failure, CPLE_AppDefined, "Got %.500s geometry as Member instead of LINESTRING.", poGeom ? poGeom->getGeometryName() : "NULL" ); delete poGeom; delete poMP; return NULL; } poMP->addGeometryDirectly( poGeom ); } } return poMP; } /* -------------------------------------------------------------------- */ /* GeometryCollection */ /* -------------------------------------------------------------------- */ if( EQUAL(pszBaseGeometry,"GeometryCollection") ) { CPLXMLNode *psChild; OGRGeometryCollection *poGC = new OGRGeometryCollection(); // collect geoms for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext ) { if( psChild->eType == CXT_Element && EQUAL(BareGMLElement(psChild->pszValue),"geometryMember") ) { OGRGeometry *poGeom; poGeom = GML2OGRGeometry_XMLNode( psChild->psChild ); if( poGeom == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Failed to get geometry in geometryMember" ); delete poGeom; delete poGC; return NULL; } poGC->addGeometryDirectly( poGeom ); } } return poGC; } CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised geometry type <%.500s>.", pszBaseGeometry ); return NULL; }
void OGRDWGDataSource::ReadBlocksSection() { OGRDWGLayer *poReaderLayer = (OGRDWGLayer *) GetLayerByName( "Entities" ); int bMergeBlockGeometries = CSLTestBoolean( CPLGetConfigOption( "DWG_MERGE_BLOCK_GEOMETRIES", "TRUE" ) ); /* -------------------------------------------------------------------- */ /* Loop over all the block tables, skipping *Model_Space which */ /* we assume is primary entities. */ /* -------------------------------------------------------------------- */ OdDbBlockTableRecordPtr poModelSpace, poBlock; OdDbBlockTablePtr pTable = GetDB()->getBlockTableId().safeOpenObject(); OdDbSymbolTableIteratorPtr pBlkIter = pTable->newIterator(); for (pBlkIter->start(); ! pBlkIter->done(); pBlkIter->step()) { poBlock = pBlkIter->getRecordId().safeOpenObject(); CPLString osBlockName = (const char *) poBlock->getName(); if( EQUAL(osBlockName,"*Model_Space") ) { poModelSpace = poBlock; continue; } poReaderLayer->SetBlockTable( poBlock ); // Now we will process entities till we run out. // We aggregate the geometries of the features into a multi-geometry, // but throw away other stuff attached to the features. OGRFeature *poFeature; OGRGeometryCollection *poColl = new OGRGeometryCollection(); std::vector<OGRFeature*> apoFeatures; while( (poFeature = poReaderLayer->GetNextUnfilteredFeature()) != NULL ) { if( (poFeature->GetStyleString() != NULL && strstr(poFeature->GetStyleString(),"LABEL") != NULL) || !bMergeBlockGeometries ) { apoFeatures.push_back( poFeature ); } else { poColl->addGeometryDirectly( poFeature->StealGeometry() ); delete poFeature; } } if( poColl->getNumGeometries() == 0 ) delete poColl; else oBlockMap[osBlockName].poGeometry = SimplifyBlockGeometry(poColl); if( apoFeatures.size() > 0 ) oBlockMap[osBlockName].apoFeatures = apoFeatures; } CPLDebug( "DWG", "Read %d blocks with meaningful geometry.", (int) oBlockMap.size() ); poReaderLayer->SetBlockTable( poModelSpace ); }