[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