void GeoDataLineStringPrivate::optimize (GeoDataLineString& lineString) const { QVector<GeoDataCoordinates>::iterator itCoords = lineString.begin(); QVector<GeoDataCoordinates>::const_iterator itEnd = lineString.constEnd(); if (lineString.size() < 2) return; // Calculate the least non-zero detail-level by checking the bounding box int startLevel = levelForResolution( ( lineString.latLonAltBox().width() + lineString.latLonAltBox().height() ) / 2 ); int currentLevel = startLevel; int maxLevel = startLevel; GeoDataCoordinates currentCoords; lineString.first().setDetail(startLevel); // Iterate through the linestring to assign different detail levels to the nodes. // In general the first and last node should have the start level assigned as // a detail level. // Starting from the first node the algorithm picks those nodes which // have a distance from each other that is just above the resolution that is // associated with the start level (which we use as a "current level"). // Each of those nodes get the current level assigned as the detail level. // After iterating through the linestring we increment the current level value // and starting again with the first node we assign detail values in a similar way // to the remaining nodes which have no final detail level assigned yet. // We do as many iterations through the lineString as needed and bump up the // current level until all nodes have a non-zero detail level assigned. while ( currentLevel < 16 && currentLevel <= maxLevel + 1 ) { itCoords = lineString.begin(); currentCoords = *itCoords; ++itCoords; for( ; itCoords != itEnd; ++itCoords) { if (itCoords->detail() != 0 && itCoords->detail() < currentLevel) continue; if ( currentLevel == startLevel && (itCoords->longitude() == -M_PI || itCoords->longitude() == M_PI || itCoords->latitude() < -89 * DEG2RAD || itCoords->latitude() > 89 * DEG2RAD)) { itCoords->setDetail(startLevel); currentCoords = *itCoords; maxLevel = currentLevel; continue; } if (distanceSphere( currentCoords, *itCoords ) < resolutionForLevel(currentLevel + 1)) { itCoords->setDetail(currentLevel + 1); } else { itCoords->setDetail(currentLevel); currentCoords = *itCoords; maxLevel = currentLevel; } } ++currentLevel; } lineString.last().setDetail(startLevel); }
int main(int argc, char** argv) { QApplication app(argc,argv); qDebug( " Syntax: pnt2svg [-i shp-sourcefile -o pn2-targetfile]" ); QString inputFilename; int inputIndex = app.arguments().indexOf( "-i" ); if ( inputIndex > 0 && inputIndex + 1 < argc ) inputFilename = app.arguments().at( inputIndex + 1 ); QString outputFilename = "output.pn2"; int outputIndex = app.arguments().indexOf("-o"); if ( outputIndex > 0 && outputIndex + 1 < argc ) outputFilename = app.arguments().at( outputIndex + 1 ); MarbleModel *model = new MarbleModel; ParsingRunnerManager* manager = new ParsingRunnerManager( model->pluginManager() ); GeoDataDocument* document = manager->openFile( inputFilename ); QFile file( outputFilename ); file.open( QIODevice::WriteOnly ); QDataStream stream( &file ); quint8 fileHeaderVersion; quint32 fileHeaderPolygons; fileHeaderVersion = 1; fileHeaderPolygons = 0; // This variable counts the number of polygons inside the document QVector<GeoDataFeature*>::Iterator i = document->begin(); QVector<GeoDataFeature*>::Iterator const end = document->end(); for (; i != end; ++i) { GeoDataPlacemark* placemark = static_cast<GeoDataPlacemark*>( *i ); // Types of placemarks GeoDataPolygon* polygon = dynamic_cast<GeoDataPolygon*>( placemark->geometry() ); GeoDataLineString* linestring = dynamic_cast<GeoDataLineString*>( placemark->geometry() ); GeoDataMultiGeometry* multigeom = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() ); if ( polygon ) { fileHeaderPolygons += 1 + polygon->innerBoundaries().size(); // outer boundary + number of inner boundaries of the polygon } if ( linestring ) { ++fileHeaderPolygons; } if ( multigeom ) { fileHeaderPolygons += multigeom->size(); // number of polygons inside the multigeometry } } stream << fileHeaderVersion << fileHeaderPolygons; i = document->begin(); quint32 polyCurrentID = 0; quint32 polyParentNodes; quint8 polyFlag; for ( ; i != end; ++i ) { GeoDataPlacemark* placemark = static_cast<GeoDataPlacemark*>( *i ); // Types of placemarks GeoDataPolygon* polygon = dynamic_cast<GeoDataPolygon*>( placemark->geometry() ); GeoDataLineString* linestring = dynamic_cast<GeoDataLineString*>( placemark->geometry() ); GeoDataMultiGeometry* multigeom = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() ); if ( polygon ) { // Outer boundary ++polyCurrentID; QVector<GeoDataCoordinates>::Iterator jBegin = polygon->outerBoundary().begin(); QVector<GeoDataCoordinates>::Iterator jEnd = polygon->outerBoundary().end(); polyParentNodes = getParentNodes( jBegin, jEnd ); polyFlag = OUTERBOUNDARY; stream << polyCurrentID << polyParentNodes << polyFlag; printAllNodes( jBegin, jEnd, stream ); // Inner boundaries QVector<GeoDataLinearRing>::Iterator inner = polygon->innerBoundaries().begin(); QVector<GeoDataLinearRing>::Iterator innerEnd = polygon->innerBoundaries().end(); for ( ; inner != innerEnd; ++inner ) { GeoDataLinearRing linearring = static_cast<GeoDataLinearRing>( *inner ); ++polyCurrentID; jBegin = linearring.begin(); jEnd = linearring.end(); polyParentNodes = getParentNodes( jBegin, jEnd ); polyFlag = INNERBOUNDARY; stream << polyCurrentID << polyParentNodes << polyFlag; printAllNodes( jBegin, jEnd, stream ); } } if ( linestring ) { ++polyCurrentID; QVector<GeoDataCoordinates>::Iterator jBegin = linestring->begin(); QVector<GeoDataCoordinates>::Iterator jEnd = linestring->end(); polyParentNodes = getParentNodes( jBegin, jEnd ); if ( linestring->isClosed() ) polyFlag = LINEARRING; else polyFlag = LINESTRING; stream << polyCurrentID << polyParentNodes << polyFlag; printAllNodes( jBegin, jEnd, stream ); } if ( multigeom ) { QVector<GeoDataGeometry*>::Iterator multi = multigeom->begin(); QVector<GeoDataGeometry*>::Iterator multiEnd = multigeom->end(); for ( ; multi != multiEnd; ++multi ) { GeoDataLineString* currLineString = dynamic_cast<GeoDataLineString*>( *multi ); ++polyCurrentID; QVector<GeoDataCoordinates>::Iterator jBegin = currLineString->begin(); QVector<GeoDataCoordinates>::Iterator jEnd = currLineString->end(); polyParentNodes = getParentNodes( jBegin, jEnd ); if ( currLineString->isClosed() ) polyFlag = LINEARRING; else polyFlag = LINESTRING; stream << polyCurrentID << polyParentNodes << polyFlag; printAllNodes( jBegin, jEnd, stream ); } } } }