void GeoDataPlacemark::unpack( QDataStream& stream ) { detach(); p()->m_geometry->setParent( this ); GeoDataFeature::unpack( stream ); stream >> p()->m_countrycode; stream >> p()->m_area; stream >> p()->m_population; int geometryId; stream >> geometryId; switch( geometryId ) { case InvalidGeometryId: break; case GeoDataPointId: { GeoDataPoint* point = new GeoDataPoint; point->unpack( stream ); delete p()->m_geometry; p()->m_geometry = point; } break; case GeoDataLineStringId: { GeoDataLineString* lineString = new GeoDataLineString; lineString->unpack( stream ); delete p()->m_geometry; p()->m_geometry = lineString; } break; case GeoDataLinearRingId: { GeoDataLinearRing* linearRing = new GeoDataLinearRing; linearRing->unpack( stream ); delete p()->m_geometry; p()->m_geometry = linearRing; } break; case GeoDataPolygonId: { GeoDataPolygon* polygon = new GeoDataPolygon; polygon->unpack( stream ); delete p()->m_geometry; p()->m_geometry = polygon; } break; case GeoDataMultiGeometryId: { GeoDataMultiGeometry* multiGeometry = new GeoDataMultiGeometry; multiGeometry->unpack( stream ); delete p()->m_geometry; p()->m_geometry = multiGeometry; } break; case GeoDataModelId: break; default: break; }; }
void GeoDataMultiGeometry::unpack( QDataStream& stream ) { detach(); GeoDataGeometry::unpack( stream ); int size = 0; stream >> size; for( int i = 0; i < size; i++ ) { int geometryId; stream >> geometryId; switch( geometryId ) { case InvalidGeometryId: break; case GeoDataPointId: { GeoDataPoint *point = new GeoDataPoint; point->unpack( stream ); p()->m_vector.append( point ); } break; case GeoDataLineStringId: { GeoDataLineString *lineString = new GeoDataLineString; lineString->unpack( stream ); p()->m_vector.append( lineString ); } break; case GeoDataLinearRingId: { GeoDataLinearRing *linearRing = new GeoDataLinearRing; linearRing->unpack( stream ); p()->m_vector.append( linearRing ); } break; case GeoDataPolygonId: { GeoDataPolygon *polygon = new GeoDataPolygon; polygon->unpack( stream ); p()->m_vector.append( polygon ); } break; case GeoDataMultiGeometryId: { GeoDataMultiGeometry *multiGeometry = new GeoDataMultiGeometry; multiGeometry->unpack( stream ); p()->m_vector.append( multiGeometry ); } break; case GeoDataModelId: break; default: break; }; } }
void MonavMap::parseBoundingBox( const QFileInfo &file ) { GeoDataLineString points; bool tooLarge = false; QFile input( file.absoluteFilePath() ); if ( input.open( QFile::ReadOnly ) ) { GeoDataParser parser( GeoData_KML ); if ( !parser.read( &input ) ) { mDebug() << "Could not parse file: " << parser.errorString(); return; } GeoDocument *doc = parser.releaseDocument(); input.close(); GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( doc ); QVector<GeoDataPlacemark*> placemarks = document->placemarkList(); if ( placemarks.size() == 1 ) { GeoDataPlacemark* placemark = placemarks.first(); m_name = placemark->name(); m_version = placemark->extendedData().value( "version" ).value().toString(); m_date = placemark->extendedData().value( "date" ).value().toString(); m_transport = placemark->extendedData().value( "transport" ).value().toString(); m_payload = placemark->extendedData().value( "payload" ).value().toString(); GeoDataMultiGeometry* geometry = dynamic_cast<GeoDataMultiGeometry*>( placemark->geometry() ); if ( geometry->size() > 1500 ) { tooLarge = true; } for ( int i = 0; geometry && i < geometry->size(); ++i ) { GeoDataLinearRing* poly = dynamic_cast<GeoDataLinearRing*>( geometry->child( i ) ); if ( poly ) { for ( int j = 0; j < poly->size(); ++j ) { points << poly->at( j ); } m_tiles.push_back( *poly ); } if ( poly->size() > 1500 ) { tooLarge = true; } } } else { mDebug() << "File " << file.absoluteFilePath() << " does not contain one placemark, but " << placemarks.size(); } delete doc; } m_boundingBox = points.latLonAltBox(); if ( tooLarge ) { // The bounding box polygon is rather complicated, therefore not allowing a quick check // and also occupying memory. Discard the polygon and only store the rectangular bounding // box. Only happens for non-simplified bounding box polygons. mDebug() << "Discarding too large bounding box poylgon for " << file.absoluteFilePath() << ". Please check for a map update."; m_tiles.clear(); } }
void EditPolygonDialog::handleItemMoving( GeoDataPlacemark *item ) { if( item == d->m_placemark ) { d->m_nodeModel->clear(); if( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { GeoDataPolygon *polygon = static_cast<GeoDataPolygon*>( d->m_placemark->geometry() ); GeoDataLinearRing outerBoundary = polygon->outerBoundary(); for( int i = 0; i < outerBoundary.size(); ++i ) { d->m_nodeModel->addNode( outerBoundary.at( i ) ); } } } }
void GeoDataPolygon::pack( QDataStream& stream ) const { GeoDataObject::pack( stream ); p()->outer.pack( stream ); stream << p()->inner.size(); stream << (qint32)(p()->m_tessellationFlags); for( QVector<GeoDataLinearRing>::const_iterator iterator = p()->inner.constBegin(); iterator != p()->inner.constEnd(); ++iterator ) { mDebug() << "innerRing: size" << p()->inner.size(); GeoDataLinearRing linearRing = ( *iterator ); linearRing.pack( stream ); } }
void GeoDataPolygon::unpack( QDataStream& stream ) { detach(); GeoDataObject::unpack( stream ); p()->outer.unpack( stream ); qint32 size; qint32 tessellationFlags; stream >> size; stream >> tessellationFlags; p()->m_tessellationFlags = (TessellationFlags)(tessellationFlags); for(qint32 i = 0; i < size; i++ ) { GeoDataLinearRing linearRing; linearRing.unpack( stream ); p()->inner.append( linearRing ); } }
bool JsonParser::read( QIODevice* device ) { // Assert previous document got released. delete m_document; m_document = new GeoDataDocument; Q_ASSERT( m_document ); // Read file data QJsonParseError error; const QJsonDocument jsonDoc = QJsonDocument::fromJson(device->readAll(), &error); if (jsonDoc.isNull()) { qDebug() << "Error parsing GeoJSON : " << error.errorString(); return false; } // Start parsing const QJsonValue featuresValue = jsonDoc.object().value(QStringLiteral("features")); // In GeoJSON format, geometries are stored in features, so we iterate on features if (featuresValue.isArray()) { const QJsonArray featureArray = featuresValue.toArray(); // Parse each feature for (int featureIndex = 0; featureIndex < featureArray.size(); ++featureIndex) { const QJsonObject featureObject = featureArray[featureIndex].toObject(); // Check if the feature contains a geometry const QJsonValue geometryValue = featureObject.value(QStringLiteral("geometry")); if (geometryValue.isObject()) { const QJsonObject geometryObject = geometryValue.toObject(); // Variables for creating the geometry QList<GeoDataGeometry*> geometryList; QList<GeoDataPlacemark*> placemarkList; // Create the different geometry types const QString geometryType = geometryObject.value(QStringLiteral("type")).toString().toUpper(); if (geometryType == QLatin1String("POLYGON")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); GeoDataPolygon * geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); // Coordinates first array will be the outer boundary, if there are more // positions those will be inner holes for (int ringIndex = 0 ; ringIndex < coordinateArray.size(); ++ringIndex) { const QJsonArray ringArray = coordinateArray[ringIndex].toArray(); GeoDataLinearRing linearRing; for (int coordinatePairIndex = 0; coordinatePairIndex < ringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = ringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); linearRing.append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } // Outer ring if (ringIndex == 0) { geom->setOuterBoundary( linearRing ); } // Inner holes else { geom->appendInnerBoundary( linearRing ); } } geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTIPOLYGON")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int polygonIndex = 0; polygonIndex < coordinateArray.size(); ++polygonIndex) { const QJsonArray polygonArray = coordinateArray[polygonIndex].toArray(); GeoDataPolygon * geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); // Coordinates first array will be the outer boundary, if there are more // positions those will be inner holes for (int ringIndex = 0 ; ringIndex < polygonArray.size(); ++ringIndex) { const QJsonArray ringArray = polygonArray[ringIndex].toArray(); GeoDataLinearRing linearRing; for (int coordinatePairIndex = 0; coordinatePairIndex < ringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = ringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); linearRing.append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } // Outer ring if (ringIndex == 0) { geom->setOuterBoundary( linearRing ); } // Inner holes else { geom->appendInnerBoundary( linearRing ); } } geometryList.append( geom ); } } } else if (geometryType == QLatin1String("LINESTRING")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); GeoDataLineString * geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); for (int coordinatePairIndex = 0; coordinatePairIndex < coordinateArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = coordinateArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTILINESTRING")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int lineStringIndex = 0; lineStringIndex < coordinateArray.size(); ++lineStringIndex) { const QJsonArray lineStringArray = coordinateArray[lineStringIndex].toArray(); GeoDataLineString * geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); for (int coordinatePairIndex = 0; coordinatePairIndex < lineStringArray.size(); ++coordinatePairIndex) { const QJsonArray coordinatePairArray = lineStringArray[coordinatePairIndex].toArray(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->append( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); } geometryList.append( geom ); } } } else if (geometryType == QLatin1String("POINT")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinatePairArray = coordinatesValue.toArray(); GeoDataPoint * geom = new GeoDataPoint(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->setCoordinates( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); geometryList.append( geom ); } } else if (geometryType == QLatin1String("MULTIPOINT")) { // Check first that there are coordinates const QJsonValue coordinatesValue = geometryObject.value(QStringLiteral("coordinates")); if (coordinatesValue.isArray()) { const QJsonArray coordinateArray = coordinatesValue.toArray(); for (int pointIndex = 0; pointIndex < coordinateArray.size(); ++pointIndex) { const QJsonArray coordinatePairArray = coordinateArray[pointIndex].toArray(); GeoDataPoint * geom = new GeoDataPoint(); const qreal longitude = coordinatePairArray.at(0).toDouble(); const qreal latitude = coordinatePairArray.at(1).toDouble(); geom->setCoordinates( GeoDataCoordinates( longitude , latitude , 0 , GeoDataCoordinates::Degree ) ); geometryList.append( geom ); } } } // Parse the features properties const QJsonValue propertiesValue = featureObject.value(QStringLiteral("properties")); if (!geometryList.isEmpty() && propertiesValue.isObject()) { const QJsonObject propertiesObject = propertiesValue.toObject(); // First create a placemark for each geometry, there could be multi geometries // that are translated into more than one geometry/placemark for ( int numberGeometries = 0 ; numberGeometries < geometryList.length() ; numberGeometries++ ) { GeoDataPlacemark * placemark = new GeoDataPlacemark(); placemarkList.append( placemark ); } OsmPlacemarkData osmData; QJsonObject::ConstIterator it = propertiesObject.begin(); const QJsonObject::ConstIterator end = propertiesObject.end(); for ( ; it != end; ++it) { if (it.value().isObject() || it.value().isArray()) { qDebug() << "Skipping property, values of type arrays and objects not supported:" << it.key(); continue; } // pass value through QVariant to also get bool & numbers osmData.addTag(it.key(), it.value().toVariant().toString()); } // If the property read, is the features name const auto tagIter = osmData.findTag(QStringLiteral("name")); if (tagIter != osmData.tagsEnd()) { const QString& name = tagIter.value(); for (int pl = 0 ; pl < placemarkList.length(); ++pl) { placemarkList.at(pl)->setName(name); } } const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData); if (category != GeoDataPlacemark::None) { // Add the visual category to all the placemarks for (int pl = 0 ; pl < placemarkList.length(); ++pl) { placemarkList.at(pl)->setVisualCategory(category); placemarkList.at(pl)->setOsmData(osmData); } } } // Add the geometry to the document if ( geometryList.length() == placemarkList.length() ) { while( placemarkList.length() > 0 ) { GeoDataPlacemark * placemark = placemarkList.last(); placemarkList.pop_back(); GeoDataGeometry * geom = geometryList.last(); geometryList.pop_back(); placemark->setGeometry( geom ); placemark->setVisible( true ); m_document->append( placemark ); } } // If geometries or placemarks missing inside the lists, delete them qDeleteAll( geometryList.begin(), geometryList.end() ); geometryList.clear(); qDeleteAll( placemarkList.begin(), placemarkList.end() ); placemarkList.clear(); } } } return true; }
GeoDataDocument *ShpRunner::parseFile(const QString &fileName, DocumentRole role, QString &error) { QFileInfo fileinfo( fileName ); if (fileinfo.suffix().compare(QLatin1String("shp"), Qt::CaseInsensitive) != 0) { error = QStringLiteral("File %1 does not have a shp suffix").arg(fileName); mDebug() << error; return nullptr; } SHPHandle handle = SHPOpen( fileName.toStdString().c_str(), "rb" ); if ( !handle ) { error = QStringLiteral("Failed to read %1").arg(fileName); mDebug() << error; return nullptr; } int entities; int shapeType; SHPGetInfo( handle, &entities, &shapeType, NULL, NULL ); mDebug() << " SHP info " << entities << " Entities " << shapeType << " Shape Type "; DBFHandle dbfhandle; dbfhandle = DBFOpen( fileName.toStdString().c_str(), "rb"); int nameField = DBFGetFieldIndex( dbfhandle, "Name" ); int noteField = DBFGetFieldIndex( dbfhandle, "Note" ); int mapColorField = DBFGetFieldIndex( dbfhandle, "mapcolor13" ); GeoDataDocument *document = new GeoDataDocument; document->setDocumentRole( role ); if ( mapColorField != -1 ) { GeoDataSchema schema; schema.setId(QStringLiteral("default")); GeoDataSimpleField simpleField; simpleField.setName(QStringLiteral("mapcolor13")); simpleField.setType( GeoDataSimpleField::Double ); schema.addSimpleField( simpleField ); document->addSchema( schema ); } for ( int i=0; i< entities; ++i ) { GeoDataPlacemark *placemark = 0; placemark = new GeoDataPlacemark; document->append( placemark ); SHPObject *shape = SHPReadObject( handle, i ); if (nameField != -1) { const char* info = DBFReadStringAttribute( dbfhandle, i, nameField ); // TODO: defaults to utf-8 encoding, but could be also something else, optionally noted in a .cpg file placemark->setName( info ); mDebug() << "name " << placemark->name(); } if (noteField != -1) { const char* note = DBFReadStringAttribute( dbfhandle, i, noteField ); // TODO: defaults to utf-8 encoding, see comment for name placemark->setDescription( note ); mDebug() << "desc " << placemark->description(); } double mapColor = DBFReadDoubleAttribute( dbfhandle, i, mapColorField ); if ( mapColor ) { GeoDataStyle::Ptr style(new GeoDataStyle); if ( mapColor >= 0 && mapColor <=255 ) { quint8 colorIndex = quint8( mapColor ); style->polyStyle().setColorIndex( colorIndex ); } else { quint8 colorIndex = 0; // mapColor is undefined in this case style->polyStyle().setColorIndex( colorIndex ); } placemark->setStyle( style ); } switch ( shapeType ) { case SHPT_POINT: { GeoDataPoint *point = new GeoDataPoint( *shape->padfX, *shape->padfY, 0, GeoDataCoordinates::Degree ); placemark->setGeometry( point ); mDebug() << "point " << placemark->name(); break; } case SHPT_MULTIPOINT: { GeoDataMultiGeometry *geom = new GeoDataMultiGeometry; for( int j=0; j<shape->nVertices; ++j ) { geom->append( new GeoDataPoint( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ) ); } placemark->setGeometry( geom ); mDebug() << "multipoint " << placemark->name(); break; } case SHPT_ARC: { if ( shape->nParts != 1 ) { GeoDataMultiGeometry *geom = new GeoDataMultiGeometry; for( int j=0; j<shape->nParts; ++j ) { GeoDataLineString *line = new GeoDataLineString; int itEnd = (j + 1 < shape->nParts) ? shape->panPartStart[j+1] : shape->nVertices; for( int k=shape->panPartStart[j]; k<itEnd; ++k ) { line->append( GeoDataCoordinates( shape->padfX[k], shape->padfY[k], 0, GeoDataCoordinates::Degree ) ); } geom->append( line ); } placemark->setGeometry( geom ); mDebug() << "arc " << placemark->name() << " " << shape->nParts; } else { GeoDataLineString *line = new GeoDataLineString; for( int j=0; j<shape->nVertices; ++j ) { line->append( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ); } placemark->setGeometry( line ); mDebug() << "arc " << placemark->name() << " " << shape->nParts; } break; } case SHPT_POLYGON: { if ( shape->nParts != 1 ) { bool isRingClockwise = false; GeoDataMultiGeometry *multigeom = new GeoDataMultiGeometry; GeoDataPolygon *poly = 0; int polygonCount = 0; for( int j=0; j<shape->nParts; ++j ) { GeoDataLinearRing ring; int itStart = shape->panPartStart[j]; int itEnd = (j + 1 < shape->nParts) ? shape->panPartStart[j+1] : shape->nVertices; for( int k = itStart; k<itEnd; ++k ) { ring.append( GeoDataCoordinates( shape->padfX[k], shape->padfY[k], 0, GeoDataCoordinates::Degree ) ); } isRingClockwise = ring.isClockwise(); if ( j == 0 || isRingClockwise ) { poly = new GeoDataPolygon; ++polygonCount; poly->setOuterBoundary( ring ); if ( polygonCount > 1 ) { multigeom->append( poly ); } } else { poly->appendInnerBoundary( ring ); } } if ( polygonCount > 1 ) { placemark->setGeometry( multigeom ); } else { placemark->setGeometry( poly ); delete multigeom; multigeom = 0; } mDebug() << "donut " << placemark->name() << " " << shape->nParts; } else { GeoDataPolygon *poly = new GeoDataPolygon; GeoDataLinearRing ring; for( int j=0; j<shape->nVertices; ++j ) { ring.append( GeoDataCoordinates( shape->padfX[j], shape->padfY[j], 0, GeoDataCoordinates::Degree ) ); } poly->setOuterBoundary( ring ); placemark->setGeometry( poly ); mDebug() << "poly " << placemark->name() << " " << shape->nParts; } break; } } } SHPClose( handle ); DBFClose( dbfhandle ); if ( document->size() ) { document->setFileName( fileName ); return document; } else { delete document; return nullptr; } }
bool JsonParser::read( QIODevice* device ) { // Assert previous document got released. delete m_document; m_document = new GeoDataDocument; Q_ASSERT( m_document ); // Fixes for test parsing device->seek(21); // Strip off 'onKothicDataRespone(' QString temp = QString::fromUtf8( device->readAll() ); int midIndex = temp.size(); int rightIndex = midIndex; for ( int i=0; i<4; ++i ) { rightIndex = midIndex; midIndex = temp.lastIndexOf( ',', midIndex-1 ); if ( i==1 ) { QString name = temp.mid( midIndex-1 ); name.remove( name.size()-2,2 ); m_document->setName( "Kothic " + name ); } } QString stream = temp.mid(0, midIndex); stream.prepend('('); stream.append("})"); bool hasGranularity = false; int const granularity = temp.mid(midIndex+15, rightIndex-midIndex-16).toInt( &hasGranularity ); if (!hasGranularity) { mDebug() << "Cannot parse json file (failed to parse granularity) " << temp; return false; } /** THIS IS A TEST PARSER FOR KOTHIK's JSON FORMAT **/ m_data = m_engine.evaluate( stream ); if (m_engine.hasUncaughtException()) { mDebug() << "Cannot parse json file: " << m_engine.uncaughtException().toString(); return false; } // Start parsing GeoDataPlacemark *placemark; GeoDataFeature::GeoDataVisualCategory category; // Bounding box coordinates float east; float south; float west; float north; // Global data (even if it is at the end of the json response // it is possible to read it now) if ( m_data.property( "bbox" ).isArray() ){ QStringList coors = m_data.property( "bbox" ).toString().split( QLatin1Char( ',' ) ); // Load the bounding box coordinates west = coors.at(0).toFloat(); east = coors.at(2).toFloat(); south = coors.at(1).toFloat(); north = coors.at(3).toFloat(); } else{ mDebug() << "Cannot parse bbox"; return false; } // All downloaded placemarks will be features, so we should iterate // on features QScriptValue const features = m_data.property( "features" ); if (features.isArray()){ QScriptValueIterator iterator( features ); // Add items to the list while ( iterator.hasNext() ) { iterator.next(); GeoDataGeometry * geom; placemark = new GeoDataPlacemark(); QString const typeProperty = iterator.value().property( "type" ).toString(); if ( typeProperty == "Polygon" ){ geom = new GeoDataPolygon( RespectLatitudeCircle | Tessellate ); } else if ( typeProperty == "LineString" ){ geom = new GeoDataLineString( RespectLatitudeCircle | Tessellate ); } else if ( typeProperty == "Point" ){ geom = new GeoDataPoint(); } else geom = 0; QScriptValueIterator it (iterator.value().property( "properties" )); bool propertiesCorrect = false; // Parsing properties while ( it.hasNext() && geom != 0 ) { it.next(); if ( it.name() == "name" ){ placemark->setName( it.value().toString() ); }else if ( !propertiesCorrect ){ category = GeoDataFeature::OsmVisualCategory( it.name() + '=' + it.value().toString() ); if (category != 0){ placemark->setVisualCategory( category ); propertiesCorrect = true; } } } // Parsing coordinates QScriptValue const coordinatesProperty = iterator.value().property( "coordinates" ); if ( coordinatesProperty.isArray() ){ QScriptValueIterator it ( coordinatesProperty ); while ( it.hasNext() ) { it.next(); QStringList coors = it.value().toString().split( QLatin1Char( ',' ) ); for (int x = 0; x < coors.size()-1 && coors.size()>1 ;){ float auxX = ( coors.at(x++).toFloat() / granularity)*(east-west) + west; float auxY = ( coors.at(x++).toFloat() / granularity)*(north-south) + south; QString const typeProperty = iterator.value().property( "type" ).toString(); if (typeProperty == "Polygon"){ GeoDataLinearRing ring = ((GeoDataPolygon*)geom)->outerBoundary(); ring.append( GeoDataCoordinates(auxX, auxY,0, GeoDataCoordinates::Degree ) ); // FIXME appending to the ring could be done more efficiently ((GeoDataPolygon*)geom)->setOuterBoundary(ring); } else if (typeProperty == "LineString"){ ((GeoDataLineString*) geom)->append( GeoDataCoordinates(auxX, auxY,0, GeoDataCoordinates::Degree ) ); } else if (typeProperty == "Point"){ ((GeoDataPoint*) geom)->setCoordinates( GeoDataCoordinates(auxX,auxY,0, GeoDataCoordinates::Degree ) ); } } } } if ( propertiesCorrect && geom != 0 ){ placemark->setGeometry( geom ); placemark->setVisible( true ); m_document->append( placemark ); } } } return true; }
void MeasureToolPlugin::drawSegments( GeoPainter* painter ) { for ( int segmentIndex = 0; segmentIndex < m_measureLineString.size() - 1; ++segmentIndex ) { GeoDataLineString segment( Tessellate ); segment << m_measureLineString[segmentIndex] ; segment << m_measureLineString[segmentIndex + 1]; QPen shadowPen( Oxygen::aluminumGray5 ); shadowPen.setWidthF(4.0); painter->setPen( shadowPen ); painter->drawPolyline( segment ); QString infoString; if ( (m_paintMode == Polygon && m_showDistanceLabel) || (m_paintMode == Circular && m_showRadius) ) { const qreal segmentLength = segment.length( marbleModel()->planet()->radius() ); m_radius = segmentLength; infoString = meterToPreferredUnit(segmentLength); } if ( m_showBearingLabel && m_paintMode != Circular ) { GeoDataCoordinates coordinates = segment.first(); qreal bearing = coordinates.bearing( segment.last(), GeoDataCoordinates::Degree ); if ( bearing < 0 ) { bearing += 360; } QString bearingString = QString::fromUtf8( "%1°" ).arg( bearing, 0, 'f', 2 ); if ( !infoString.isEmpty() ) { infoString.append( "\n" ); } infoString.append( bearingString ); } if ( m_showBearingChangeLabel && segmentIndex != 0 ) { GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex]; qreal currentBearing = currentCoordinates.bearing(m_measureLineString[segmentIndex+1]); qreal previousBearing = currentCoordinates.bearing( m_measureLineString[segmentIndex-1]); GeoDataLinearRing ring; painter->setPen( Qt::NoPen ); painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) ); if (currentBearing < previousBearing) currentBearing += 2 * M_PI; ring << currentCoordinates; qreal angleLength = qAbs(m_latLonAltBox.north() - m_latLonAltBox.south()) / 20; qreal iterBearing = previousBearing; while ( iterBearing < currentBearing ) { ring << currentCoordinates.moveByBearing( iterBearing, angleLength );; iterBearing += 0.1; } ring << currentCoordinates.moveByBearing( currentBearing, angleLength );; painter->drawPolygon( ring ); qreal currentBearingChange = (currentBearing - previousBearing) * RAD2DEG; if (currentBearingChange < 0) currentBearingChange += 360; QString bearingChangedString = QString::fromUtf8( "%1°" ).arg( currentBearingChange, 0, 'f', 2 ); painter->setPen( Qt::black ); GeoDataCoordinates textPosition = ring.latLonAltBox().center(); qreal deltaEast = ring.latLonAltBox().east() - currentCoordinates.longitude(); qreal deltaWest = currentCoordinates.longitude() - ring.latLonAltBox().west(); if (deltaEast > deltaWest) { textPosition.setLongitude(currentCoordinates.longitude() + deltaEast / 2); } else { textPosition.setLongitude(currentCoordinates.longitude() - deltaWest); } painter->drawText(textPosition, bearingChangedString ); } // Drawing ellipse around 1st point towards the 2nd if ( m_paintMode == Circular ) { GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex]; GeoDataLinearRing ring; // planetRadius - planet radius // d - distance between points // S - area of the painted circle qreal planetRadius = marbleModel()->planet()->radius(); qreal d = m_measureLineString.length(1); m_circularArea = 2 * M_PI * planetRadius * planetRadius * (1 - qCos(d)); qreal iterBearing = 0; while ( iterBearing < 2 * M_PI ) { ring << currentCoordinates.moveByBearing(iterBearing, d); iterBearing += 0.1; } painter->setPen( Qt::NoPen ); painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) ); painter->drawPolygon(ring); if ( m_showCircularArea ) { painter->setPen(Qt::white); GeoDataCoordinates textPosition = ring.latLonAltBox().center(); QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(m_circularArea, true)); QFontMetrics fontMetrics = painter->fontMetrics(); QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText); painter->drawText(textPosition, areaText, -boundingRect.width()/2, -boundingRect.height()*1.5, boundingRect.width(), boundingRect.height(), QTextOption(Qt::AlignCenter)); } if ( m_showCircumference ) { painter->setPen(Qt::white); GeoDataCoordinates textPosition = ring.latLonAltBox().center(); m_circumference = 2 * M_PI * planetRadius * qSin(d); QString circumferenceText = tr("Circumference:\n%1").arg(meterToPreferredUnit(m_circumference)); QFontMetrics fontMetrics = painter->fontMetrics(); QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter, circumferenceText); painter->drawText(textPosition, circumferenceText, -boundingRect.width()/2, boundingRect.height(), boundingRect.width(), boundingRect.height(), QTextOption(Qt::AlignCenter)); } } if ( !infoString.isEmpty() ) { QPen linePen; // have three alternating colors for the segments switch ( segmentIndex % 3 ) { case 0: linePen.setColor( Oxygen::brickRed4 ); break; case 1: linePen.setColor( Oxygen::forestGreen4 ); break; case 2: linePen.setColor( Oxygen::skyBlue4 ); break; } linePen.setWidthF(2.0); painter->setPen( linePen ); painter->drawPolyline( segment, infoString, LineCenter ); } } if (m_paintMode == Polygon && m_measureLineString.size() > 2) { GeoDataLinearRing measureRing = m_measureLineString; if (m_showPolygonArea || m_showPerimeter) { painter->setPen( Qt::NoPen ); painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) ); painter->drawPolygon(measureRing); QPen shadowPen( Oxygen::aluminumGray5 ); shadowPen.setStyle(Qt::DashLine); shadowPen.setWidthF(3.0); painter->setPen( shadowPen ); painter->drawPolyline(GeoDataLineString( Tessellate ) << m_measureLineString.first() << m_measureLineString.last()); } if (m_showPolygonArea) { qreal theta1 = 0.0; qreal n = m_measureLineString.size(); for (int segmentIndex = 1; segmentIndex < m_measureLineString.size()-1; segmentIndex++) { GeoDataCoordinates current = m_measureLineString[segmentIndex]; qreal prevBearing = current.bearing(m_measureLineString[segmentIndex-1]); qreal nextBearing = current.bearing(m_measureLineString[segmentIndex+1]); if (nextBearing < prevBearing) nextBearing += 2 * M_PI; qreal angle = nextBearing - prevBearing; theta1 += angle; } // Traversing first vertex GeoDataCoordinates current = m_measureLineString[0]; qreal prevBearing = current.bearing(m_measureLineString[n-1]); qreal nextBearing = current.bearing(m_measureLineString[1]); if (nextBearing < prevBearing) nextBearing += 2 * M_PI; qreal angle = nextBearing - prevBearing; theta1 += angle; // And the last one current = m_measureLineString[n-1]; prevBearing = current.bearing(m_measureLineString[n-2]); nextBearing = current.bearing(m_measureLineString[0]); if (nextBearing < prevBearing) nextBearing += 2 * M_PI; angle = nextBearing - prevBearing; theta1 += angle; qreal theta2 = 2 * M_PI * n - theta1; // theta = smaller of theta1 and theta2 qreal theta = (theta1 < theta2) ? theta1 : theta2; qreal planetRadius = marbleModel()->planet()->radius(); qreal S = qAbs((theta - (n-2) * M_PI) * planetRadius * planetRadius); m_polygonArea = S; painter->setPen(Qt::white); GeoDataCoordinates textPosition = measureRing.latLonAltBox().center(); QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(S, true)); QFontMetrics fontMetrics = painter->fontMetrics(); QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText); painter->drawText(textPosition, areaText, -boundingRect.width()/2, -(boundingRect.height()+fontMetrics.height()*0.25), boundingRect.width(), boundingRect.height(), QTextOption(Qt::AlignCenter)); } if (m_showPerimeter) { painter->setPen(Qt::white); GeoDataCoordinates textPosition = measureRing.latLonAltBox().center(); qreal P = measureRing.length(marbleModel()->planet()->radius()); m_perimeter = P; QString perimeterText = tr("Perimeter:\n%1").arg(meterToPreferredUnit(P)); QFontMetrics fontMetrics = painter->fontMetrics(); QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter, perimeterText); painter->drawText(textPosition, perimeterText, -boundingRect.width()/2, 0, boundingRect.width(), boundingRect.height(), QTextOption(Qt::AlignCenter)); } } }
void CountryByShape::postQuestion( QObject *gameObject ) { //Find a random placemark Q_ASSERT_X( d->m_countryNames, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryNames is NULL" ); QVector<GeoDataPlacemark*> countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); bool found = false; GeoDataPlacemark *placemark =0; GeoDataPoint *point = 0; GeoDataCoordinates coord; GeoDataLatLonAltBox box; QVariantList answerOptions; while ( !found ) { int randomIndex = qrand()%countryPlacemarks.size(); placemark = countryPlacemarks[randomIndex]; point = dynamic_cast<GeoDataPoint*>( placemark->geometry() ); coord = point->coordinates(); if ( point ) { /** * Find the country geometry and fetch corresponding * GeoDataLatLonAltBox to zoom in to that country so that * it fills the viewport. */ Q_ASSERT_X( d->m_countryBoundaries, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryBoundaries is NULL" ); QVector<GeoDataFeature*>::Iterator i = d->m_countryBoundaries->begin(); QVector<GeoDataFeature*>::Iterator const end = d->m_countryBoundaries->end(); for ( ; i != end; ++i ) { GeoDataPlacemark *country = static_cast<GeoDataPlacemark*>( *i ); GeoDataPolygon *polygon = dynamic_cast<GeoDataPolygon*>( country->geometry() ); GeoDataLinearRing *linearring = dynamic_cast<GeoDataLinearRing*>( country->geometry() ); GeoDataMultiGeometry *multigeom = dynamic_cast<GeoDataMultiGeometry*>( country->geometry() ); if ( polygon && polygon->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = polygon->latLonAltBox(); found = true; break; } if ( linearring && linearring->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = linearring->latLonAltBox(); found = true; break; } if ( multigeom ) { QVector<GeoDataGeometry*>::Iterator iter = multigeom->begin(); QVector<GeoDataGeometry*>::Iterator const end = multigeom->end(); for ( ; iter != end; ++iter ) { GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( *iter ); if ( poly && poly->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = poly->latLonAltBox(); found = true; break; } } } if ( found ) { break; } } } } d->m_marbleWidget->setHighlightEnabled( true ); emit announceHighlight( coord.longitude(GeoDataCoordinates::Degree), coord.latitude(GeoDataCoordinates::Degree), GeoDataCoordinates::Degree ); /** * Now disable the highlight feature so that * the user click doesn't disturbe the highlight * we did to ask question. */ d->m_marbleWidget->setHighlightEnabled( false ); d->m_marbleWidget->centerOn( box, true ); answerOptions << placemark->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name(); // Randomize options in list answerOptions for ( int i = 0; i < answerOptions.size(); ++i ) { QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() ); answerOptions.append( option ); } if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "countryByShapeQuestion", Q_ARG(QVariant, QVariant(answerOptions)), Q_ARG(QVariant, QVariant(placemark->name())) ); } }
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 ); } } } }
void EclipsesItem::calculate() { int np, kp, j; double lat1, lng1, lat2, lng2, lat3, lng3, lat4, lng4; double ltf[60], lnf[60]; m_ecl->putEclSelect( m_index ); // FIXME: set observer location m_ecl->getMaxPos( lat1, lng1 ); m_ecl->setLocalPos( lat1, lng1, 0 ); // eclipse's maximum location m_maxLocation = GeoDataCoordinates( lng1, lat1, 0., GeoDataCoordinates::Degree ); // calculate central line np = m_ecl->eclPltCentral( true, lat1, lng1 ); kp = np; m_centralLine.clear(); m_centralLine << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); if( np > 3 ) { // central eclipse while( np > 3 ) { np = m_ecl->eclPltCentral( false, lat1, lng1 ); if( np > 3 ) { m_centralLine << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } } // calculate umbra np = kp; m_umbra.clear(); if( np > 3 ) { // total or annual eclipse // northern /southern boundaries of umbra np = m_ecl->centralBound( true, lat1, lng1, lat2, lng2 ); GeoDataLinearRing lowerUmbra( Tessellate ), upperUmbra( Tessellate ); lowerUmbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); upperUmbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); while( np > 0 ) { np = m_ecl->centralBound( false, lat1, lng1, lat2, lng2 ); if( lat1 <= 90. ) { lowerUmbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } if( lat1 <= 90. ) { upperUmbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng2, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat2, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } GeoDataLinearRing invertedUpperUmbra( Tessellate ); QVector<GeoDataCoordinates>::const_iterator iter = upperUmbra.constEnd() - 1; for( ; iter != upperUmbra.constBegin(); --iter ) { invertedUpperUmbra << *iter; } invertedUpperUmbra << upperUmbra.first(); upperUmbra = invertedUpperUmbra; m_umbra << lowerUmbra << upperUmbra; } // shadow cones m_shadowConeUmbra.clear(); m_shadowConePenumbra.clear(); m_shadowCone60MagPenumbra.clear(); m_ecl->getLocalMax( lat2, lat3, lat4 ); m_ecl->getShadowCone( lat2, true, 40, ltf, lnf ); for( j = 0; j < 40; ++j ) { if( ltf[j] < 100. ) { m_shadowConeUmbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lnf[j], GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(ltf[j], GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } m_ecl->setPenumbraAngle( 1., 0 ); m_ecl->getShadowCone( lat2, false, 60, ltf, lnf ); for( j = 0; j < 60; ++j ) { if( ltf[j] < 100. ) { m_shadowConePenumbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lnf[j], GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(ltf[j], GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } m_ecl->setPenumbraAngle( 0.6, 1 ); m_ecl->getShadowCone( lat2, false, 60, ltf, lnf ); for( j = 0; j < 60; ++j ) { if( ltf[j] < 100. ) { m_shadowCone60MagPenumbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lnf[j], GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(ltf[j], GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } m_ecl->setPenumbraAngle( 1., 0 ); // eclipse boundaries m_southernPenumbra.clear(); m_northernPenumbra.clear(); np = m_ecl->GNSBound( true, true, lat1, lng2 ); while( np > 0 ) { np = m_ecl->GNSBound( false, true, lat1, lng1 ); if( ( np > 0 ) && ( lat1 <= 90. ) ) { m_southernPenumbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } np = m_ecl->GNSBound( true, false, lat1, lng1 ); while( np > 0 ) { np = m_ecl->GNSBound( false, false, lat1, lng1 ); if( ( np > 0 ) && ( lat1 <= 90. ) ) { m_northernPenumbra << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } } // sunrise / sunset boundaries QList<GeoDataLinearRing*> sunBoundaries; np = m_ecl->GRSBound( true, lat1, lng1, lat3, lng3 ); GeoDataLinearRing *lowerBoundary = new GeoDataLinearRing( Tessellate ); *lowerBoundary << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng1, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat1, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); GeoDataLinearRing *upperBoundary = new GeoDataLinearRing( Tessellate ); *upperBoundary << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng3, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat3, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); m_sunBoundaries.clear(); while ( np > 0 ) { np = m_ecl->GRSBound( false, lat2, lng2, lat4, lng4 ); bool pline = fabs( lng1 - lng2 ) < 10.; // during partial eclipses, the Rise/Set // lines switch at one stage. // This will prevent an ugly line between // the switch points. If there is a // longitude jump then add the current // section to our sun boundaries collection // and start a new section if ( !pline && !lowerBoundary->isEmpty() ) { sunBoundaries.prepend( lowerBoundary ); lowerBoundary = new GeoDataLinearRing( Tessellate ); } if ( ( np > 0 ) && ( lat2 <= 90. ) && ( lat1 <= 90. ) ) { *lowerBoundary << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng2, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat2, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } pline = fabs( lng3 - lng4 ) < 10.; // during partial eclipses, the Rise/Set lines // switch at one stage. // This will prevent an ugly line between the // switch points. If there is a longitude jump // then add the current section to our sun // boundaries collection and start a new section if ( !pline && !upperBoundary->isEmpty() ) { sunBoundaries.prepend( upperBoundary ); upperBoundary = new GeoDataLinearRing( Tessellate ); } if ( pline && ( np > 0 ) && ( lat4 <= 90. ) && ( lat3 <= 90. ) ) { *upperBoundary << GeoDataCoordinates( GeoDataCoordinates::normalizeLon(lng4, GeoDataCoordinates::Degree), GeoDataCoordinates::normalizeLat(lat4, GeoDataCoordinates::Degree), 0., GeoDataCoordinates::Degree ); } lng1 = lng2; lat1 = lat2; lng3 = lng4; lat3 = lat4; } if ( !lowerBoundary->isEmpty() ) { sunBoundaries.prepend(lowerBoundary); } else { delete lowerBoundary; } if ( !upperBoundary->isEmpty() ) { sunBoundaries.prepend(upperBoundary); } else { delete upperBoundary; } for ( int result = 0; result < 2; ++result ) { GeoDataLinearRing sunBoundary( Tessellate ); sunBoundary = *sunBoundaries.last(); sunBoundaries.pop_back(); while ( sunBoundaries.size() > 0) { int closestSection = -1; // TODO: Now that MableMath is not public anymore we need a // GeoDataCoordinates::distance() method in Marble. GeoDataLineString ruler; ruler << sunBoundary.last() << sunBoundary.first(); qreal closestDistance = ruler.length( 1 ); int closestEnd = 0; // 0 = start of section, 1 = end of section // Look for a section that is closest to our sunBoundary section. for ( int it = 0; it < sunBoundaries.size(); ++it ) { GeoDataLineString distanceStartSection; distanceStartSection << sunBoundary.last() << sunBoundaries.at( it )->first(); GeoDataLineString distanceEndSection; distanceEndSection << sunBoundary.last() << sunBoundaries.at( it )->last(); if ( distanceStartSection.length( 1 ) < closestDistance ) { closestDistance = distanceStartSection.length( 1 ); closestSection = it; closestEnd = 0; } if ( distanceEndSection.length(1) < closestDistance ) { closestDistance = distanceEndSection.length( 1 ); closestSection = it; closestEnd = 1; } } if ( closestSection == -1 ) { // There is no other section that is closer to the end of // our sunBoundary section than the startpoint of our // sunBoundary itself break; } else { // We now concatenate the closest section to the sunBoundary. // First we might have to invert it so that we concatenate // the right end if ( closestEnd == 1 ) { // TODO: replace this with a GeoDataLinearRing::invert() // method that needs to be added to Marble ... GeoDataLinearRing * invertedBoundary = new GeoDataLinearRing( Tessellate ); QVector<GeoDataCoordinates>::const_iterator iter = sunBoundaries.at( closestSection )->constEnd(); --iter; for( ; iter != sunBoundaries.at( closestSection )->constBegin(); --iter ) { *invertedBoundary << *iter; } *invertedBoundary << sunBoundaries.at( closestSection )->first(); delete sunBoundaries[closestSection]; sunBoundaries[closestSection] = invertedBoundary; } sunBoundary << *sunBoundaries[closestSection]; // Now remove the section that we've just added from the list delete sunBoundaries[closestSection]; sunBoundaries.removeAt( closestSection ); } } m_sunBoundaries << sunBoundary; if ( sunBoundaries.size() == 0 ) break; } m_calculationsNeedUpdate = false; }