QGIS/src/core/qgsrectangle.cpp
jef 92bb2a3117 [FEATURE] multi-layer identify
git-svn-id: http://svn.osgeo.org/qgis/trunk@11572 c8812cc2-4d05-0410-92ff-de0c093fc19c
2009-09-05 19:49:47 +00:00

331 lines
8.7 KiB
C++

/***************************************************************************
qgsrectangle.cpp - description
-------------------
begin : Sat Jun 22 2002
copyright : (C) 2002 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/* $Id$ */
#include <algorithm>
#include <cmath>
#include <limits>
#include <QString>
#include <QTextStream>
#include "qgspoint.h"
#include "qgsrectangle.h"
#include "qgslogger.h"
QgsRectangle::QgsRectangle( double newxmin, double newymin, double newxmax, double newymax )
: xmin( newxmin ), ymin( newymin ), xmax( newxmax ), ymax( newymax )
{
normalize();
}
QgsRectangle::QgsRectangle( QgsPoint const & p1, QgsPoint const & p2 )
{
set( p1, p2 );
}
QgsRectangle::QgsRectangle( const QgsRectangle &r )
{
xmin = r.xMinimum();
ymin = r.yMinimum();
xmax = r.xMaximum();
ymax = r.yMaximum();
}
void QgsRectangle::set( const QgsPoint& p1, const QgsPoint& p2 )
{
xmin = p1.x();
xmax = p2.x();
ymin = p1.y();
ymax = p2.y();
normalize();
}
void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ )
{
xmin = xmin_;
ymin = ymin_;
xmax = xmax_;
ymax = ymax_;
normalize();
}
void QgsRectangle::normalize()
{
if ( xmin > xmax )
{
std::swap( xmin, xmax );
}
if ( ymin > ymax )
{
std::swap( ymin, ymax );
}
} // QgsRectangle::normalize()
void QgsRectangle::setMinimal()
{
xmin = std::numeric_limits<double>::max();
ymin = std::numeric_limits<double>::max();
xmax = -std::numeric_limits<double>::max();
ymax = -std::numeric_limits<double>::max();
}
void QgsRectangle::scale( double scaleFactor, const QgsPoint * cp )
{
// scale from the center
double centerX, centerY;
if ( cp )
{
centerX = cp->x();
centerY = cp->y();
}
else
{
centerX = xmin + width() / 2;
centerY = ymin + height() / 2;
}
double newWidth = width() * scaleFactor;
double newHeight = height() * scaleFactor;
xmin = centerX - newWidth / 2.0;
xmax = centerX + newWidth / 2.0;
ymin = centerY - newHeight / 2.0;
ymax = centerY + newHeight / 2.0;
}
void QgsRectangle::expand( double scaleFactor, const QgsPoint * cp )
{
// scale from the center
double centerX, centerY;
if ( cp )
{
centerX = cp->x();
centerY = cp->y();
}
else
{
centerX = xmin + width() / 2;
centerY = ymin + height() / 2;
}
double newWidth = width() * scaleFactor;
double newHeight = height() * scaleFactor;
xmin = centerX - newWidth;
xmax = centerX + newWidth;
ymin = centerY - newHeight;
ymax = centerY + newHeight;
}
QgsRectangle QgsRectangle::intersect( const QgsRectangle * rect ) const
{
QgsRectangle intersection = QgsRectangle();
//If they don't actually intersect an empty QgsRectangle should be returned
if ( !rect || !intersects( *rect ) )
{
return intersection;
}
intersection.setXMinimum( xmin > rect->xMinimum() ? xmin : rect->xMinimum() );
intersection.setXMaximum( xmax < rect->xMaximum() ? xmax : rect->xMaximum() );
intersection.setYMinimum( ymin > rect->yMinimum() ? ymin : rect->yMinimum() );
intersection.setYMaximum( ymax < rect->yMaximum() ? ymax : rect->yMaximum() );
return intersection;
}
bool QgsRectangle::intersects( const QgsRectangle& rect ) const
{
double x1 = ( xmin > rect.xmin ? xmin : rect.xmin );
double x2 = ( xmax < rect.xmax ? xmax : rect.xmax );
if ( x1 > x2 ) return FALSE;
double y1 = ( ymin > rect.ymin ? ymin : rect.ymin );
double y2 = ( ymax < rect.ymax ? ymax : rect.ymax );
if ( y1 > y2 ) return FALSE;
return TRUE;
}
bool QgsRectangle::contains( const QgsRectangle& rect ) const
{
return ( rect.xmin >= xmin && rect.xmax <= xmax && rect.ymin >= ymin && rect.ymax <= ymax );
}
bool QgsRectangle::contains( const QgsPoint &p ) const
{
return xmin <= p.x() && p.x() <= xmax &&
ymin <= p.y() && p.y() <= ymax;
}
void QgsRectangle::combineExtentWith( QgsRectangle * rect )
{
xmin = (( xmin < rect->xMinimum() ) ? xmin : rect->xMinimum() );
xmax = (( xmax > rect->xMaximum() ) ? xmax : rect->xMaximum() );
ymin = (( ymin < rect->yMinimum() ) ? ymin : rect->yMinimum() );
ymax = (( ymax > rect->yMaximum() ) ? ymax : rect->yMaximum() );
}
void QgsRectangle::combineExtentWith( double x, double y )
{
xmin = (( xmin < x ) ? xmin : x );
xmax = (( xmax > x ) ? xmax : x );
ymin = (( ymin < y ) ? ymin : y );
ymax = (( ymax > y ) ? ymax : y );
}
bool QgsRectangle::isEmpty() const
{
if ( xmax <= xmin || ymax <= ymin )
{
return TRUE;
}
else
{
return FALSE;
}
}
QString QgsRectangle::asWktCoordinates() const
{
QString rep =
QString::number( xmin, 'f', 16 ) + " " +
QString::number( ymin, 'f', 16 ) + ", " +
QString::number( xmax, 'f', 16 ) + " " +
QString::number( ymax, 'f', 16 );
return rep;
}
// Return a string representation of the rectangle with automatic or high precision
QString QgsRectangle::toString( bool automaticPrecision ) const
{
if ( automaticPrecision )
{
int precision = 0;
if (( width() < 1 || height() < 1 ) && ( width() > 0 && height() > 0 ) )
{
precision = static_cast<int>( ceil( -1.0 * log10( std::min( width(), height() ) ) ) ) + 1;
// sanity check
if ( precision > 20 )
precision = 20;
}
return toString( precision );
}
else
return toString( 16 );
}
// overloaded version of above fn to allow precision to be set
// Return a string representation of the rectangle with high precision
QString QgsRectangle::toString( int thePrecision ) const
{
QString rep = QString::number( xmin, 'f', thePrecision ) +
QString( "," ) +
QString::number( ymin, 'f', thePrecision ) +
QString( " : " ) +
QString::number( xmax, 'f', thePrecision ) +
QString( "," ) +
QString::number( ymax, 'f', thePrecision ) ;
#ifdef QGISDEBUG
// QgsDebugMsg(QString("Extents : %1").arg(rep));
#endif
return rep;
}
// Return the rectangle as a set of polygon coordinates
QString QgsRectangle::asPolygon() const
{
// QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
// xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
QString rep;
QTextStream foo( &rep );
foo.setRealNumberPrecision( 8 );
foo.setRealNumberNotation( QTextStream::FixedNotation );
// NOTE: a polygon isn't a polygon unless its closed. In the case of
// a rectangle, that means 5 points (last == first)
foo << xmin << " " << ymin << ", "
<< xmin << " " << ymax << ", "
<< xmax << " " << ymax << ", "
<< xmax << " " << ymin << ", "
<< xmin << " " << ymin;
return rep;
} // QgsRectangle::asPolygon() const
bool QgsRectangle::operator==( const QgsRectangle & r1 ) const
{
return ( r1.xMaximum() == xMaximum() &&
r1.xMinimum() == xMinimum() &&
r1.yMaximum() == yMaximum() &&
r1.yMinimum() == yMinimum() );
}
bool QgsRectangle::operator!=( const QgsRectangle & r1 ) const
{
return ( ! operator==( r1 ) );
}
QgsRectangle & QgsRectangle::operator=( const QgsRectangle & r )
{
if ( &r != this )
{
xmax = r.xMaximum();
xmin = r.xMinimum();
ymax = r.yMaximum();
ymin = r.yMinimum();
}
return *this;
}
void QgsRectangle::unionRect( const QgsRectangle& r )
{
if ( r.xMinimum() < xMinimum() ) setXMinimum( r.xMinimum() );
if ( r.xMaximum() > xMaximum() ) setXMaximum( r.xMaximum() );
if ( r.yMinimum() < yMinimum() ) setYMinimum( r.yMinimum() );
if ( r.yMaximum() > yMaximum() ) setYMaximum( r.yMaximum() );
}
bool QgsRectangle::isFinite() const
{
if ( std::numeric_limits<double>::has_infinity )
{
if ( xmin == std::numeric_limits<double>::infinity() ||
xmax == std::numeric_limits<double>::infinity() ||
ymin == std::numeric_limits<double>::infinity() ||
ymax == std::numeric_limits<double>::infinity() )
return false;
}
// By design, if a variable is nan, it won't equal itself, so that's
// how we test for nan
if ( xmin != xmin || xmax != xmax || ymin != ymin || ymax != ymax )
return false;
return true;
}