Beispiel #1
0
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;
        };
    }
}
Beispiel #3
0
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();
    }
}
Beispiel #4
0
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 ) );
            }
        }
    }
}
Beispiel #5
0
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 );
    }
}
Beispiel #6
0
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 );
    }
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
    }
}
Beispiel #9
0
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));
        }
    }
}
Beispiel #11
0
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())) );
    }
}
Beispiel #12
0
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 );
            }
            
        }
    }

}
Beispiel #13
0
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;
}