[Marble-commits] KDE/kdeedu/marble

Thibaut Gridel tgridel at free.fr
Sun Jul 18 23:49:56 CEST 2010


SVN commit 1151349 by tgridel:

LatLonBox: fixes
- isEmpty shows if the box is uninitialised
- center() should return 0,0 if box is not initialised
- center() should normalize longitude result
- united returns the bounding box of this and the given one

- MultiGeometry uses |= to get the bounding box of all its geometries

at last, testing in TestGeoData.

 M  +3 -1      src/lib/geodata/data/GeoDataLatLonAltBox.cpp  
 M  +68 -6     src/lib/geodata/data/GeoDataLatLonBox.cpp  
 M  +14 -1     src/lib/geodata/data/GeoDataLatLonBox.h  
 M  +9 -2      src/lib/geodata/data/GeoDataMultiGeometry.cpp  
 M  +163 -0    tests/TestGeoData.cpp  


--- trunk/KDE/kdeedu/marble/src/lib/geodata/data/GeoDataLatLonAltBox.cpp #1151348:1151349
@@ -140,8 +140,10 @@
 
 GeoDataCoordinates GeoDataLatLonAltBox::center() const
 {
+    if ( isEmpty() )
+        return GeoDataCoordinates();
     if( crossesDateLine() )
-        return GeoDataCoordinates( east() + 2 * M_PI - (east() + 2 * M_PI - west()) / 2,
+        return GeoDataCoordinates( GeoDataCoordinates::normalizeLon(east() + 2 * M_PI - (east() + 2 * M_PI - west()) / 2),
                                 north() - (north() - south()) / 2, 
                                 d->m_maxAltitude - (d->m_maxAltitude - d->m_minAltitude) / 2);
     else
--- trunk/KDE/kdeedu/marble/src/lib/geodata/data/GeoDataLatLonBox.cpp #1151348:1151349
@@ -268,8 +268,11 @@
 
 GeoDataCoordinates GeoDataLatLonBox::center() const
 {
+    if( isEmpty() )
+        return GeoDataCoordinates();
+
     if( crossesDateLine() )
-        return GeoDataCoordinates( east() + 2 * M_PI - (east() + 2 * M_PI - west()) / 2,
+        return GeoDataCoordinates( GeoDataCoordinates::normalizeLon( east() + 2 * M_PI - ( east() + 2 * M_PI - west() ) / 2 ) ,
                                 north() - (north() - south()) / 2 );
     else
         return GeoDataCoordinates( east() - (east() - west()) / 2,
@@ -447,6 +450,59 @@
     return false;
 }
 
+GeoDataLatLonBox GeoDataLatLonBox::united( const GeoDataLatLonBox& other ) const
+{
+    GeoDataLatLonBox result;
+
+    // use the position of the centers of the boxes to determine the "smallest"
+    // box (i.e. should the total box go through IDL or not). this
+    // determination does not depend on one box or the other crossing IDL too
+    GeoDataCoordinates c1 = center();
+    GeoDataCoordinates c2 = other.center();
+
+    // do latitude first, quite simple
+    result.setNorth(qMax( d->m_north, other.north() ) );
+    result.setSouth( qMin( d->m_south, other.south() ) );
+
+    qreal w1 = d->m_west;
+    qreal w2 = other.west();
+    qreal e1 = d->m_east;
+    qreal e2 = other.east();
+
+    bool idl1 = crossesDateLine();
+    bool idl2 = other.crossesDateLine();
+
+    if ( idl1 ) {
+        w1 += 2* M_PI;
+        e1 += 2* M_PI;
+    }
+    if ( idl2 ) {
+        w2 += 2* M_PI;
+        e2 += 2* M_PI;
+    }
+
+    // in the usual case, we take the maximum of east bounds, and
+    // the minimum of west bounds. The exceptions are:
+    // - centers of boxes are more than 180 apart
+    //    (so the smallest box should go around the IDL)
+    //
+    // - 1 but not 2 boxes are crossing IDL
+    if ( fabs( c2.longitude()-c1.longitude() ) > M_PI
+         || ( idl1 ^ idl2 ) ) {
+        // exceptions, we go the unusual way:
+        // min of east, max of west
+        result.setEast( qMin( e1, e2 ) );
+        result.setWest( qMax( w1, w2 ) );
+    }
+    else {
+        // normal case, max of east, min of west
+        result.setEast( qMax( e1, e2 ) );
+        result.setWest( qMin( w1, w2 ) );
+    }
+    return result;
+}
+
+
 QString GeoDataLatLonBox::toString( GeoDataCoordinates::Unit unit ) const
 {
     switch( unit ){
@@ -473,12 +529,14 @@
     return *this;
 }
 
-GeoDataLatLonBox& GeoDataLatLonBox::operator+=( const GeoDataLatLonBox& other )
+GeoDataLatLonBox GeoDataLatLonBox::operator|( const GeoDataLatLonBox& other ) const
 {
-    d->m_north = qMax(d->m_north, other.north());
-    d->m_south = qMin(d->m_south, other.south());
-    d->m_east = qMax(d->m_east, other.east());
-    d->m_west = qMin(d->m_west, other.west());
+    return united( other );
+}
+
+GeoDataLatLonBox& GeoDataLatLonBox::operator|=( const GeoDataLatLonBox& other )
+{
+    *this = united( other );
     return *this;
 }
 
@@ -628,4 +686,8 @@
     return false;
 }
 
+bool GeoDataLatLonBox::isEmpty() const
+{
+    return *this == GeoDataLatLonBox();
 }
+}
--- trunk/KDE/kdeedu/marble/src/lib/geodata/data/GeoDataLatLonBox.h #1151348:1151349
@@ -140,6 +140,11 @@
     virtual bool intersects( const GeoDataLatLonBox & ) const;
 
     /**
+     * @brief Returns the bounding LatLonBox of this box with the given one.
+     */
+    GeoDataLatLonBox united( const GeoDataLatLonBox& other) const;
+
+    /**
      * @brief Create the smallest bounding box from a line string.
      * @return the smallest bounding box that contains the linestring.
      */
@@ -157,10 +162,18 @@
     virtual bool isNull() const;
 
     /**
+     * @brief Indicates whether the bounding box is not initialised (and contains all).
+     * @return Return value is true if bounding box is not initialised.
+     */
+    virtual bool isEmpty() const;
+
+    GeoDataLatLonBox operator|( const GeoDataLatLonBox& other ) const;
+
+    /**
      * @brief Unites this bounding box with the given one.
      * @return Returns a reference to self.
      */
-    GeoDataLatLonBox& operator +=( const GeoDataLatLonBox& other) ;
+    GeoDataLatLonBox& operator |=( const GeoDataLatLonBox& other) ;
 
     /// Serialize the contents of the feature to @p stream.
     virtual void pack( QDataStream& stream ) const;
--- trunk/KDE/kdeedu/marble/src/lib/geodata/data/GeoDataMultiGeometry.cpp #1151348:1151349
@@ -53,10 +53,17 @@
     QVector<GeoDataGeometry*>::const_iterator it = p()->m_vector.constBegin();
     QVector<GeoDataGeometry*>::const_iterator end = p()->m_vector.constEnd();
 
-    GeoDataLatLonAltBox box( (*it)->latLonAltBox() );
+    GeoDataLatLonAltBox box;
     for (; it != end; ++it) {
-        box += (*it)->latLonAltBox();
+        if ( !(*it)->latLonAltBox().isEmpty() ) {
+            if ( box.isEmpty() ) {
+                box = (*it)->latLonAltBox();
     }
+            else {
+                box |= (*it)->latLonAltBox();
+            }
+        }
+    }
     return box;
 }
 
--- trunk/KDE/kdeedu/marble/tests/TestGeoData.cpp #1151348:1151349
@@ -17,6 +17,7 @@
 #include "GeoDataCoordinates.h"
 #include "GeoDataLatLonAltBox.h"
 #include "GeoDataTypes.h"
+#include "MarbleDebug.h"
 
 namespace Marble
 {
@@ -34,6 +35,10 @@
     
     void latLonAltBoxIntersects_data();
     void latLonAltBoxIntersects();
+    void latLonBoxCenter_data();
+    void latLonBoxCenter();
+    void latLonBoxUnited_data();
+    void latLonBoxUnited();
 };
 
 /// test the nodeType function through various construction tests
@@ -238,8 +243,166 @@
     QCOMPARE( box1.intersects( box2 ), intersects );
 }
 
+void TestGeoData::latLonBoxCenter_data()
+{
+    QTest::addColumn<qreal>( "boxnorth" );
+    QTest::addColumn<qreal>( "boxsouth" );
+    QTest::addColumn<qreal>( "boxwest" );
+    QTest::addColumn<qreal>( "boxeast" );
+    QTest::addColumn<qreal>( "centerlat" );
+    QTest::addColumn<qreal>( "centerlon" );
+
+    QTest::newRow( "N-E" ) << 60.0 << 40.0 << 10.0 << 30.0
+                          << 50.0 << 20.0;
+
+    QTest::newRow( "N-GW" ) << 60.0 << 40.0 << -30.0 << 10.0
+                          << 50.0 << -10.0;
+
+    QTest::newRow( "N-W" ) << 60.0 << 40.0 << -30.0 << -10.0
+                          << 50.0 << -20.0;
+
+    QTest::newRow( "NS-W" ) << 30.0 << -30.0 << -30.0 << -10.0
+                           << 0.0  << -20.0;
+
+    QTest::newRow( "N-IDL" ) << 30.0 << -30.0 << 170.0 << -150.0
+                            << 0.0  << -170.0;
 }
 
+void TestGeoData::latLonBoxCenter()
+{
+    QFETCH( qreal, boxnorth );
+    QFETCH( qreal, boxsouth );
+    QFETCH( qreal, boxwest );
+    QFETCH( qreal, boxeast );
+    QFETCH( qreal, centerlat );
+    QFETCH( qreal, centerlon );
+
+    MarbleDebug::enable = true;
+
+    GeoDataLatLonAltBox box;
+    box.setNorth( boxnorth, GeoDataCoordinates::Degree );
+    box.setSouth( boxsouth, GeoDataCoordinates::Degree );
+    box.setWest( boxwest, GeoDataCoordinates::Degree );
+    box.setEast( boxeast, GeoDataCoordinates::Degree );
+
+    GeoDataCoordinates center = box.center();
+    QCOMPARE( center.latitude(GeoDataCoordinates::Degree), centerlat );
+    QCOMPARE( center.longitude(GeoDataCoordinates::Degree), centerlon );
+}
+
+void TestGeoData::latLonBoxUnited_data()
+{
+    QTest::addColumn<qreal>( "box1north" );
+    QTest::addColumn<qreal>( "box1south" );
+    QTest::addColumn<qreal>( "box1west" );
+    QTest::addColumn<qreal>( "box1east" );
+    QTest::addColumn<qreal>( "box2north" );
+    QTest::addColumn<qreal>( "box2south" );
+    QTest::addColumn<qreal>( "box2west" );
+    QTest::addColumn<qreal>( "box2east" );
+    QTest::addColumn<qreal>( "box3north" );
+    QTest::addColumn<qreal>( "box3south" );
+    QTest::addColumn<qreal>( "box3west" );
+    QTest::addColumn<qreal>( "box3east" );
+
+    QTest::newRow( "same" ) << 56.0 << 40.0 << 0.0 << 11.0
+                            << 56.0 << 40.0 << 0.0 << 11.0
+                            << 56.0 << 40.0 << 0.0 << 11.0;
+
+    // 2 boxes in West, result stays west
+    QTest::newRow( "bigWest" ) << 30.0 << -30.0 << -30.0 << -10.0   // -20
+                               << 30.0 << -30.0 << -170.0 << -150.0 // -160
+                               << 30.0 << -30.0 << -170.0 << -10.0;
+
+    // 2 boxes each side of greenwich, result crosses greenwich
+    QTest::newRow( "aroundGreenwich" ) << 30.0 << -30.0 << -30.0 << -10.0 // -20
+                                 << 30.0 << -30.0 << 10.0 << 30.0         // -160
+                                 << 30.0 << -30.0 << -30.0 << 30.0;
+
+    // 2 boxes crossing greenwich, result crosses greenwich
+    QTest::newRow( "aroundGreenwich" ) << 30.0 << -30.0 << -30.0 << 10.0  // -20
+                                 << 30.0 << -30.0 << -10.0 << 30.0        // 20
+                                 << 30.0 << -30.0 << -30.0 << 30.0;
+
+    // 2 boxes each side of IDL, result crosses IDL as smaller box
+    QTest::newRow( "aroundIDL" ) << 30.0 << -30.0 << -170.0 << -150.0     // -160
+                                 << 30.0 << -30.0 << 150.0 << 170.0       // 160
+                                 << 30.0 << -30.0 << 150.0 << -150.0;
+
+    // reciprocical, so independent of side
+    QTest::newRow( "aroundIDL2" ) << 30.0 << -30.0 << 150.0 << 170.0     // 160
+                                  << 30.0 << -30.0 << -170.0 << -150.0   // -160
+                                  << 30.0 << -30.0 << 150.0 << -150.0;
+
+    // 1 box crossing IDL, the 2 centers are close together, result crosses IDL
+    QTest::newRow( "crossingIDLclose" ) << 30.0 << -30.0 << -150.0 << -130.0  // -140
+                                        << 30.0 << -30.0 << 170.0 << -150.0   // -170
+                                        << 30.0 << -30.0 << 170.0 << -130.0;
+
+    // reciprocical
+    QTest::newRow( "crossingIDLclose2" ) << 30.0 << -30.0 << 170.0 << -160.0   // -175
+                                         << 30.0 << -30.0 << -150.0 << -140.0  // -145
+                                         << 30.0 << -30.0 << 170.0 << -140.0;
+
+    // 1 box crossing IDL, the 2 centers are across IDL, result crosses IDL
+    QTest::newRow( "crossingIDLfar" ) << 30.0 << -30.0 << -170.0 << -150.0    // -160
+                                      << 30.0 << -30.0 << 150.0 << -170.0          // 170
+                                      << 30.0 << -30.0 << 150.0 << -150.0;
+
+    // reciprocical
+    QTest::newRow( "crossingIDLfar2" ) << 30.0 << -30.0 << 150.0 << -170.0          // 170
+                                       << 30.0 << -30.0 << -170.0 << -150.0    // -160
+                                       << 30.0 << -30.0 << 150.0 << -150.0;
+
+    // 2 box crossing IDL, the 2 centers are close together, result crosses IDL
+    QTest::newRow( "crossingsIDLclose" ) << 30.0 << -30.0 << 160.0 << -140.0   // -170
+                                        << 30.0 << -30.0 << 170.0 << -160.0   // -175
+                                        << 30.0 << -30.0 << 160.0 << -140.0;
+
+    // 2 box crossing IDL, the 2 centers are across IDL, result crosses IDL
+    QTest::newRow( "crossingsIDLfar" ) << 30.0 << -30.0 << -170.0 << -150.0    // -160
+                                      << 30.0 << -30.0 << 150.0 << -170.0     // 170
+                                      << 30.0 << -30.0 << 150.0 << -150.0;
+
+}
+
+void TestGeoData::latLonBoxUnited()
+{
+    QFETCH( qreal, box1north );
+    QFETCH( qreal, box1south );
+    QFETCH( qreal, box1west );
+    QFETCH( qreal, box1east );
+    QFETCH( qreal, box2north );
+    QFETCH( qreal, box2south );
+    QFETCH( qreal, box2west );
+    QFETCH( qreal, box2east );
+    QFETCH( qreal, box3north );
+    QFETCH( qreal, box3south );
+    QFETCH( qreal, box3west );
+    QFETCH( qreal, box3east );
+
+    MarbleDebug::enable = true;
+
+    GeoDataLatLonAltBox box1;
+    GeoDataLatLonAltBox box2;
+    GeoDataLatLonAltBox box3;
+    box1.setNorth( box1north, GeoDataCoordinates::Degree );
+    box1.setSouth( box1south, GeoDataCoordinates::Degree );
+    box1.setWest( box1west, GeoDataCoordinates::Degree );
+    box1.setEast( box1east, GeoDataCoordinates::Degree );
+    box2.setNorth( box2north, GeoDataCoordinates::Degree );
+    box2.setSouth( box2south, GeoDataCoordinates::Degree );
+    box2.setWest( box2west, GeoDataCoordinates::Degree );
+    box2.setEast( box2east, GeoDataCoordinates::Degree );
+    box3 = box1 | box2;
+    QCOMPARE( box3.north( GeoDataCoordinates::Degree ), box3north );
+    QCOMPARE( box3.south( GeoDataCoordinates::Degree ), box3south );
+    QCOMPARE( box3.west( GeoDataCoordinates::Degree ), box3west );
+    QCOMPARE( box3.east( GeoDataCoordinates::Degree ), box3east );
+}
+
+}
+
 QTEST_MAIN( Marble::TestGeoData )
 
 #include "TestGeoData.moc"


More information about the Marble-commits mailing list