827 lines
23 KiB
C
827 lines
23 KiB
C
|
/**********************************************************************
|
||
|
*
|
||
|
* GEOS - Geometry Engine Open Source
|
||
|
* http://geos.osgeo.org
|
||
|
*
|
||
|
* Copyright (C) 2006 Refractions Research Inc.
|
||
|
*
|
||
|
* This is free software; you can redistribute and/or modify it under
|
||
|
* the terms of the GNU Lesser General Public Licence as published
|
||
|
* by the Free Software Foundation.
|
||
|
* See the COPYING file for more information.
|
||
|
*
|
||
|
**********************************************************************
|
||
|
*
|
||
|
* Last port: geom/Envelope.java rev 1.46 (JTS-1.10)
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
|
||
|
#include <geos/export.h>
|
||
|
#include <geos/geom/Coordinate.h>
|
||
|
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
#include <ostream> // for operator<<
|
||
|
#include <memory>
|
||
|
#include <cassert>
|
||
|
#include <algorithm>
|
||
|
|
||
|
namespace geos {
|
||
|
namespace geom { // geos::geom
|
||
|
|
||
|
class Envelope;
|
||
|
|
||
|
/// Output operator
|
||
|
GEOS_DLL std::ostream& operator<< (std::ostream& os, const Envelope& o);
|
||
|
|
||
|
class Coordinate;
|
||
|
|
||
|
/**
|
||
|
* \class Envelope geom.h geos.h
|
||
|
*
|
||
|
* \brief
|
||
|
* An Envelope defines a rectangulare region of the 2D coordinate plane.
|
||
|
*
|
||
|
* It is often used to represent the bounding box of a Geometry,
|
||
|
* e.g. the minimum and maximum x and y values of the Coordinates.
|
||
|
*
|
||
|
* Envelopes allow null values, which are represented with NaN values for ordinates.
|
||
|
* Envelopes support infinite or half-infinite regions, by using
|
||
|
* the values of `Double_POSITIVE_INFINITY` and `Double_NEGATIVE_INFINITY`.
|
||
|
*
|
||
|
* When Envelope objects are created or initialized, the supplies extent
|
||
|
* values are automatically sorted into the correct order.
|
||
|
*
|
||
|
*/
|
||
|
class GEOS_DLL Envelope {
|
||
|
|
||
|
public:
|
||
|
|
||
|
friend std::ostream& operator<< (std::ostream& os, const Envelope& o);
|
||
|
|
||
|
typedef std::unique_ptr<Envelope> Ptr;
|
||
|
|
||
|
/** \brief
|
||
|
* Creates a null Envelope.
|
||
|
*/
|
||
|
Envelope()
|
||
|
: minx(DoubleNotANumber)
|
||
|
, maxx(DoubleNotANumber)
|
||
|
, miny(DoubleNotANumber)
|
||
|
, maxy(DoubleNotANumber)
|
||
|
{};
|
||
|
|
||
|
/** \brief
|
||
|
* Creates an Envelope for a region defined by maximum and minimum values.
|
||
|
*
|
||
|
* @param x1 the first x-value
|
||
|
* @param x2 the second x-value
|
||
|
* @param y1 the first y-value
|
||
|
* @param y2 the second y-value
|
||
|
*/
|
||
|
Envelope(double x1, double x2, double y1, double y2)
|
||
|
{
|
||
|
init(x1, x2, y1, y2);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Creates an Envelope for a region defined by two Coordinates.
|
||
|
*
|
||
|
* @param p1 the first Coordinate
|
||
|
* @param p2 the second Coordinate
|
||
|
*/
|
||
|
Envelope(const CoordinateXY& p1, const CoordinateXY& p2)
|
||
|
{
|
||
|
init(p1, p2);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Creates an Envelope for a region defined by a single Coordinate.
|
||
|
*
|
||
|
* @param p the Coordinate
|
||
|
*/
|
||
|
explicit Envelope(const CoordinateXY& p)
|
||
|
: minx(p.x)
|
||
|
, maxx(p.x)
|
||
|
, miny(p.y)
|
||
|
, maxy(p.y)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Create an Envelope from an Envelope string representation produced
|
||
|
* by Envelope::toString()
|
||
|
*/
|
||
|
explicit Envelope(const std::string& str);
|
||
|
|
||
|
/** \brief
|
||
|
* Test the point `q` to see whether it intersects the Envelope
|
||
|
* defined by `p1-p2`.
|
||
|
*
|
||
|
* @param p1 one extremal point of the envelope
|
||
|
* @param p2 another extremal point of the envelope
|
||
|
* @param q the point to test for intersection
|
||
|
* @return `true` if q intersects the envelope p1-p2
|
||
|
*/
|
||
|
static bool intersects(const CoordinateXY& p1, const CoordinateXY& p2,
|
||
|
const CoordinateXY& q);
|
||
|
|
||
|
/** \brief
|
||
|
* Test the envelope defined by `p1-p2` for intersection
|
||
|
* with the envelope defined by `q1-q2`.
|
||
|
*
|
||
|
* @param p1 one extremal point of the envelope P
|
||
|
* @param p2 another extremal point of the envelope P
|
||
|
* @param q1 one extremal point of the envelope Q
|
||
|
* @param q2 another extremal point of the envelope Q
|
||
|
*
|
||
|
* @return `true` if Q intersects P
|
||
|
*/
|
||
|
static bool intersects(
|
||
|
const CoordinateXY& p1, const CoordinateXY& p2,
|
||
|
const CoordinateXY& q1, const CoordinateXY& q2)
|
||
|
{
|
||
|
double minq = std::min(q1.x, q2.x);
|
||
|
double maxq = std::max(q1.x, q2.x);
|
||
|
double minp = std::min(p1.x, p2.x);
|
||
|
double maxp = std::max(p1.x, p2.x);
|
||
|
if(minp > maxq) {
|
||
|
return false;
|
||
|
}
|
||
|
if(maxp < minq) {
|
||
|
return false;
|
||
|
}
|
||
|
minq = std::min(q1.y, q2.y);
|
||
|
maxq = std::max(q1.y, q2.y);
|
||
|
minp = std::min(p1.y, p2.y);
|
||
|
maxp = std::max(p1.y, p2.y);
|
||
|
if(minp > maxq) {
|
||
|
return false;
|
||
|
}
|
||
|
if(maxp < minq) {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Check if the extent defined by two extremal points intersects
|
||
|
* the extent of this Envelope.
|
||
|
*
|
||
|
* @param a a point
|
||
|
* @param b another point
|
||
|
* @return `true` if the extents intersect
|
||
|
*/
|
||
|
bool intersects(const CoordinateXY& a, const CoordinateXY& b) const;
|
||
|
|
||
|
/** \brief
|
||
|
* Initialize to a null Envelope.
|
||
|
*/
|
||
|
void init()
|
||
|
{
|
||
|
setToNull();
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Initialize an Envelope for a region defined by maximum and minimum values.
|
||
|
*
|
||
|
* @param x1 the first x-value
|
||
|
* @param x2 the second x-value
|
||
|
* @param y1 the first y-value
|
||
|
* @param y2 the second y-value
|
||
|
*/
|
||
|
void init(double x1, double x2, double y1, double y2)
|
||
|
{
|
||
|
if(x1 < x2) {
|
||
|
minx = x1;
|
||
|
maxx = x2;
|
||
|
}
|
||
|
else {
|
||
|
minx = x2;
|
||
|
maxx = x1;
|
||
|
}
|
||
|
if(y1 < y2) {
|
||
|
miny = y1;
|
||
|
maxy = y2;
|
||
|
}
|
||
|
else {
|
||
|
miny = y2;
|
||
|
maxy = y1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Initialize an Envelope to a region defined by two Coordinates.
|
||
|
*
|
||
|
* @param p1 the first Coordinate
|
||
|
* @param p2 the second Coordinate
|
||
|
*/
|
||
|
void init(const CoordinateXY& p1, const CoordinateXY& p2)
|
||
|
{
|
||
|
init(p1.x, p2.x, p1.y, p2.y);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Initialize an Envelope to a region defined by a single Coordinate.
|
||
|
*
|
||
|
* @param p the Coordinate
|
||
|
*/
|
||
|
void init(const CoordinateXY& p)
|
||
|
{
|
||
|
init(p.x, p.x, p.y, p.y);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Makes this `Envelope` a "null" envelope, that is, the envelope
|
||
|
* of the empty geometry.
|
||
|
*/
|
||
|
void setToNull()
|
||
|
{
|
||
|
minx = maxx = miny = maxy = DoubleNotANumber;
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Returns `true` if this Envelope is a "null" envelope.
|
||
|
*
|
||
|
* @return `true` if this Envelope is uninitialized or is the
|
||
|
* envelope of the empty geometry.
|
||
|
*/
|
||
|
bool isNull(void) const
|
||
|
{
|
||
|
return std::isnan(maxx);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the difference between the maximum and minimum x values.
|
||
|
*
|
||
|
* @return `max x - min x`, or 0 if this is a null Envelope
|
||
|
*/
|
||
|
double getWidth() const
|
||
|
{
|
||
|
if(isNull()) {
|
||
|
return 0;
|
||
|
}
|
||
|
return maxx - minx;
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the difference between the maximum and minimum y values.
|
||
|
*
|
||
|
* @return `max y - min y`, or 0 if this is a null Envelope
|
||
|
*/
|
||
|
double getHeight() const
|
||
|
{
|
||
|
if(isNull()) {
|
||
|
return 0;
|
||
|
}
|
||
|
return maxy - miny;
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Gets the area of this envelope.
|
||
|
*
|
||
|
* @return the area of the envelope
|
||
|
* @return 0.0 if the envelope is null
|
||
|
*/
|
||
|
double
|
||
|
getArea() const
|
||
|
{
|
||
|
return getWidth() * getHeight();
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Returns true if this Envelope covers a finite region
|
||
|
*/
|
||
|
bool
|
||
|
isFinite() const
|
||
|
{
|
||
|
return std::isfinite(getArea());
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the Envelope maximum y-value.
|
||
|
* Null envelopes do not have maximum values.
|
||
|
*/
|
||
|
double getMaxY() const
|
||
|
{
|
||
|
assert(!isNull());
|
||
|
return maxy;
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the Envelope maximum x-value.
|
||
|
* Null envelopes do not have maximum values.
|
||
|
*/
|
||
|
double getMaxX() const
|
||
|
{
|
||
|
assert(!isNull());
|
||
|
return maxx;
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the Envelope minimum y-value.
|
||
|
* Null envelopes do not have maximum values.
|
||
|
*/
|
||
|
double getMinY() const
|
||
|
{
|
||
|
assert(!isNull());
|
||
|
return miny;
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Returns the Envelope minimum x-value.
|
||
|
* Null envelopes do not have maximum values.
|
||
|
*/
|
||
|
double getMinX() const
|
||
|
{
|
||
|
assert(!isNull());
|
||
|
return minx;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Gets the length of the diameter (diagonal) of the envelope.
|
||
|
*
|
||
|
* @return the diameter length
|
||
|
*/
|
||
|
double getDiameter() const
|
||
|
{
|
||
|
if (isNull()) {
|
||
|
return 0.0;
|
||
|
}
|
||
|
double w = getWidth();
|
||
|
double h = getHeight();
|
||
|
return std::sqrt(w*w + h*h);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the coordinate of the centre of this envelope
|
||
|
* (as long as it is non-null).
|
||
|
*
|
||
|
* @param centre The coordinate to write results into
|
||
|
* @return `false` if the center could not be found (null envelope).
|
||
|
*/
|
||
|
bool centre(CoordinateXY& centre) const;
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the intersection of two [Envelopes](@ref Envelope).
|
||
|
*
|
||
|
* @param env the envelope to intersect with
|
||
|
* @param result the envelope representing the intersection of
|
||
|
* the envelopes (this will be the null envelope
|
||
|
* if either argument is null, or they do not intersect)
|
||
|
* @return false if no intersection is found
|
||
|
*/
|
||
|
bool intersection(const Envelope& env, Envelope& result) const;
|
||
|
|
||
|
/** \brief
|
||
|
* Translates this envelope by given amounts in the X and Y direction.
|
||
|
*
|
||
|
* @param transX the amount to translate along the X axis
|
||
|
* @param transY the amount to translate along the Y axis
|
||
|
*/
|
||
|
void translate(double transX, double transY);
|
||
|
|
||
|
/** \brief
|
||
|
* Expands this envelope by a given distance in all directions.
|
||
|
* Both positive and negative distances are supported.
|
||
|
*
|
||
|
* @param deltaX the distance to expand the envelope along the X axis
|
||
|
* @param deltaY the distance to expand the envelope along the Y axis
|
||
|
*/
|
||
|
void expandBy(double deltaX, double deltaY);
|
||
|
|
||
|
/** \brief
|
||
|
* Expands this envelope by a given distance in all directions.
|
||
|
*
|
||
|
* Both positive and negative distances are supported.
|
||
|
*
|
||
|
* @param p_distance the distance to expand the envelope
|
||
|
*/
|
||
|
void
|
||
|
expandBy(double p_distance)
|
||
|
{
|
||
|
expandBy(p_distance, p_distance);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Enlarges the boundary of the Envelope so that it contains p. Does
|
||
|
* nothing if p is already on or within the boundaries.
|
||
|
*
|
||
|
* @param p the Coordinate to include
|
||
|
*/
|
||
|
void expandToInclude(const CoordinateXY& p)
|
||
|
{
|
||
|
expandToInclude(p.x, p.y);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Enlarges the boundary of the Envelope so that it contains (x,y).
|
||
|
*
|
||
|
* Does nothing if (x,y) is already on or within the boundaries.
|
||
|
*
|
||
|
* @param x the value to lower the minimum x
|
||
|
* to or to raise the maximum x to
|
||
|
* @param y the value to lower the minimum y
|
||
|
* to or to raise the maximum y to
|
||
|
*/
|
||
|
void expandToInclude(double x, double y)
|
||
|
{
|
||
|
if(isNull()) {
|
||
|
minx = x;
|
||
|
maxx = x;
|
||
|
miny = y;
|
||
|
maxy = y;
|
||
|
}
|
||
|
else {
|
||
|
if(x < minx) {
|
||
|
minx = x;
|
||
|
}
|
||
|
if(x > maxx) {
|
||
|
maxx = x;
|
||
|
}
|
||
|
if(y < miny) {
|
||
|
miny = y;
|
||
|
}
|
||
|
if(y > maxy) {
|
||
|
maxy = y;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Enlarges the boundary of the Envelope so that it contains `other`.
|
||
|
*
|
||
|
* Does nothing if other is wholly on or within the boundaries.
|
||
|
*
|
||
|
* @param other the Envelope to merge with
|
||
|
*/
|
||
|
void expandToInclude(const Envelope* other)
|
||
|
{
|
||
|
if(isNull()) {
|
||
|
minx = other->minx;
|
||
|
maxx = other->maxx;
|
||
|
miny = other->miny;
|
||
|
maxy = other->maxy;
|
||
|
}
|
||
|
else {
|
||
|
if(std::isless(other->minx, minx)) {
|
||
|
minx = other->minx;
|
||
|
}
|
||
|
if(std::isgreater(other->maxx, maxx)) {
|
||
|
maxx = other->maxx;
|
||
|
}
|
||
|
if(std::isless(other->miny, miny)) {
|
||
|
miny = other->miny;
|
||
|
}
|
||
|
if(std::isgreater(other->maxy, maxy)) {
|
||
|
maxy = other->maxy;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void expandToInclude(const Envelope& other)
|
||
|
{
|
||
|
return expandToInclude(&other);
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Tests if the Envelope `other` lies wholly inside this Envelope
|
||
|
* (inclusive of the boundary).
|
||
|
*
|
||
|
* Note that this is **not** the same definition as the SFS `contains`,
|
||
|
* which would exclude the envelope boundary.
|
||
|
*
|
||
|
* @param other the Envelope to check
|
||
|
* @return `true` if `other` is contained in this Envelope
|
||
|
*
|
||
|
* @see covers(Envelope)
|
||
|
*/
|
||
|
bool
|
||
|
contains(const Envelope& other) const
|
||
|
{
|
||
|
return covers(other);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
contains(const Envelope* other) const
|
||
|
{
|
||
|
return contains(*other);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Returns `true` if the given point lies in or on the envelope.
|
||
|
*
|
||
|
* @param p the point which this Envelope is being checked for containing
|
||
|
* @return `true` if the point lies in the interior or on the boundary
|
||
|
* of this Envelope.
|
||
|
*/
|
||
|
bool
|
||
|
contains(const CoordinateXY& p) const
|
||
|
{
|
||
|
return covers(p.x, p.y);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Returns `true` if the given point lies in or on the envelope.
|
||
|
*
|
||
|
* @param x the x-coordinate of the point which this Envelope is
|
||
|
* being checked for containing
|
||
|
* @param y the y-coordinate of the point which this Envelope is being
|
||
|
* checked for containing
|
||
|
* @return `true` if `(x, y)` lies in the interior or on the boundary
|
||
|
* of this Envelope.
|
||
|
*/
|
||
|
bool
|
||
|
contains(double x, double y) const
|
||
|
{
|
||
|
return covers(x, y);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Check if the point p intersects (lies inside) the region of this Envelope.
|
||
|
*
|
||
|
* @param other the Coordinate to be tested
|
||
|
* @return true if the point intersects this Envelope
|
||
|
*/
|
||
|
bool intersects(const CoordinateXY& other) const
|
||
|
{
|
||
|
return (std::islessequal(other.x, maxx) && std::isgreaterequal(other.x, minx) &&
|
||
|
std::islessequal(other.y, maxy) && std::isgreaterequal(other.y, miny));
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Check if the point (x, y) intersects (lies inside) the region of this Envelope.
|
||
|
*
|
||
|
* @param x the x-ordinate of the point
|
||
|
* @param y the y-ordinate of the point
|
||
|
* @return `true` if the point intersects this Envelope
|
||
|
*/
|
||
|
bool intersects(double x, double y) const
|
||
|
{
|
||
|
return std::islessequal(x, maxx) &&
|
||
|
std::isgreaterequal(x, minx) &&
|
||
|
std::islessequal(y, maxy) &&
|
||
|
std::isgreaterequal(y, miny);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Check if the region defined by other Envelope intersects the region of this Envelope.
|
||
|
*
|
||
|
* @param other the Envelope which this Envelope is being checked for intersection
|
||
|
* @return true if the Envelopes intersects
|
||
|
*/
|
||
|
bool intersects(const Envelope* other) const
|
||
|
{
|
||
|
return std::islessequal(other->minx, maxx) &&
|
||
|
std::isgreaterequal(other->maxx, minx) &&
|
||
|
std::islessequal(other->miny, maxy) &&
|
||
|
std::isgreaterequal(other->maxy, miny);
|
||
|
}
|
||
|
|
||
|
bool intersects(const Envelope& other) const
|
||
|
{
|
||
|
return intersects(&other);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Tests if the region defined by other
|
||
|
* is disjoint from the region of this Envelope
|
||
|
*
|
||
|
* @param other the Envelope being checked for disjointness
|
||
|
* @return true if the Envelopes are disjoint
|
||
|
*/
|
||
|
bool disjoint(const Envelope& other) const
|
||
|
{
|
||
|
return !intersects(other);
|
||
|
}
|
||
|
|
||
|
bool disjoint(const Envelope* other) const
|
||
|
{
|
||
|
return !intersects(other);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Tests if the given point lies in or on the envelope.
|
||
|
*
|
||
|
* @param x the x-coordinate of the point which this Envelope is being checked for containing
|
||
|
* @param y the y-coordinate of the point which this Envelope is being checked for containing
|
||
|
* @return `true` if `(x, y)` lies in the interior or on the boundary of this Envelope.
|
||
|
*/
|
||
|
bool covers(double x, double y) const {
|
||
|
return std::isgreaterequal(x, minx) &&
|
||
|
std::islessequal(x, maxx) &&
|
||
|
std::isgreaterequal(y, miny) &&
|
||
|
std::islessequal(y, maxy);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Tests if the given point lies in or on the envelope.
|
||
|
*
|
||
|
* @param p the point which this Envelope is being checked for containing
|
||
|
* @return `true` if the point lies in the interior or on the boundary of this Envelope.
|
||
|
*/
|
||
|
bool covers(const CoordinateXY* p) const
|
||
|
{
|
||
|
return covers(p->x, p->y);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Tests if the Envelope `other` lies wholly inside this Envelope (inclusive of the boundary).
|
||
|
*
|
||
|
* @param other the Envelope to check
|
||
|
* @return true if this Envelope covers the `other`
|
||
|
*/
|
||
|
bool covers(const Envelope& other) const;
|
||
|
|
||
|
bool
|
||
|
covers(const Envelope* other) const
|
||
|
{
|
||
|
return covers(*other);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** \brief
|
||
|
* Returns `true` if the Envelope `other` spatially equals this Envelope.
|
||
|
*
|
||
|
* @param other the Envelope which this Envelope is being checked for equality
|
||
|
* @return `true` if this and `other` Envelope objects are spatially equal
|
||
|
*/
|
||
|
bool equals(const Envelope* other) const;
|
||
|
|
||
|
/**
|
||
|
* Returns `true` if all the extents of the Envelope are finite and defined (not NaN)
|
||
|
*
|
||
|
* @return `true` if envelope has only finite/valid extents, `false` otherwise
|
||
|
*/
|
||
|
bool isfinite() const;
|
||
|
|
||
|
/** \brief
|
||
|
* Returns a `string` of the form `Env[minx:maxx,miny:maxy]`.
|
||
|
*
|
||
|
* @return a `string` of the form `Env[minx:maxx,miny:maxy]`
|
||
|
*/
|
||
|
std::string toString() const;
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the distance between this and another Envelope.
|
||
|
*
|
||
|
* The distance between overlapping Envelopes is 0. Otherwise, the
|
||
|
* distance is the Euclidean distance between the closest points.
|
||
|
*/
|
||
|
double distance(const Envelope& env) const
|
||
|
{
|
||
|
return std::sqrt(distanceSquared(env));
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the maximum distance between points in this and another Envelope.
|
||
|
*/
|
||
|
double maxDistance(const Envelope& other) const
|
||
|
{
|
||
|
Coordinate p(std::min(minx, other.minx), std::min(miny, other.miny));
|
||
|
Coordinate q(std::max(maxx, other.maxx), std::max(maxy, other.maxy));
|
||
|
return p.distance(q);
|
||
|
}
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the square of the distance between this and another Envelope.
|
||
|
*
|
||
|
* The distance between overlapping Envelopes is 0. Otherwise, the
|
||
|
* distance is the Euclidean distance between the closest points.
|
||
|
*/
|
||
|
double distanceSquared(const Envelope& env) const
|
||
|
{
|
||
|
double dx = std::max(0.0,
|
||
|
std::max(maxx, env.maxx) - std::min(minx, env.minx) - (maxx - minx) -
|
||
|
(env.maxx - env.minx));
|
||
|
double dy = std::max(0.0,
|
||
|
std::max(maxy, env.maxy) - std::min(miny, env.miny) - (maxy - miny) -
|
||
|
(env.maxy - env.miny));
|
||
|
|
||
|
return dx * dx + dy * dy;
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the distance between one Coordinate and an Envelope
|
||
|
* defined by two other Coordinates. The order of the Coordinates
|
||
|
* used to define the envelope is not significant.
|
||
|
*
|
||
|
* @param c the coordinate to from which distance should be found
|
||
|
* @param p0 first coordinate defining an envelope
|
||
|
* @param p1 second coordinate defining an envelope.
|
||
|
*/
|
||
|
static double distanceToCoordinate(
|
||
|
const CoordinateXY& c,
|
||
|
const CoordinateXY& p0,
|
||
|
const CoordinateXY& p1)
|
||
|
{
|
||
|
return std::sqrt(distanceSquaredToCoordinate(c, p0, p1));
|
||
|
};
|
||
|
|
||
|
/** \brief
|
||
|
* Computes the squared distance between one Coordinate and an Envelope
|
||
|
* defined by two other Coordinates. The order of the Coordinates
|
||
|
* used to define the envelope is not significant.
|
||
|
*
|
||
|
* @param c the coordinate to from which distance should be found
|
||
|
* @param p0 first coordinate defining an envelope
|
||
|
* @param p1 second coordinate defining an envelope.
|
||
|
*/
|
||
|
static double distanceSquaredToCoordinate(
|
||
|
const CoordinateXY& c,
|
||
|
const CoordinateXY& p0,
|
||
|
const CoordinateXY& p1)
|
||
|
{
|
||
|
double xa = c.x - p0.x;
|
||
|
double xb = c.x - p1.x;
|
||
|
double ya = c.y - p0.y;
|
||
|
double yb = c.y - p1.y;
|
||
|
|
||
|
// If sign of a and b are not the same, then Envelope spans c and distance is zero.
|
||
|
double dx = (std::signbit(xa) == std::signbit(xb)) * std::min(std::abs(xa), std::abs(xb));
|
||
|
double dy = (std::signbit(ya) == std::signbit(yb)) * std::min(std::abs(ya), std::abs(yb));
|
||
|
|
||
|
return dx*dx + dy*dy;
|
||
|
}
|
||
|
|
||
|
std::size_t hashCode() const
|
||
|
{
|
||
|
auto hash = std::hash<double>{};
|
||
|
|
||
|
//Algorithm from Effective Java by Joshua Bloch [Jon Aquino]
|
||
|
std::size_t result = 17;
|
||
|
result = 37 * result + hash(minx);
|
||
|
result = 37 * result + hash(maxx);
|
||
|
result = 37 * result + hash(miny);
|
||
|
result = 37 * result + hash(maxy);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
struct GEOS_DLL HashCode
|
||
|
{
|
||
|
std::size_t operator()(const Envelope& e) const
|
||
|
{
|
||
|
return e.hashCode();
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/// Checks if two Envelopes are equal (2D only check)
|
||
|
// GEOS_DLL bool operator==(const Envelope& a, const Envelope& b);
|
||
|
GEOS_DLL friend bool
|
||
|
operator==(const Envelope& a, const Envelope& b)
|
||
|
{
|
||
|
return a.equals(&b);
|
||
|
}
|
||
|
|
||
|
// GEOS_DLL bool operator!=(const Envelope& a, const Envelope& b);
|
||
|
GEOS_DLL friend bool
|
||
|
operator!=(const Envelope& a, const Envelope& b)
|
||
|
{
|
||
|
return !(a == b);
|
||
|
}
|
||
|
|
||
|
/// Strict weak ordering operator for Envelope
|
||
|
/// This is the C++ equivalent of JTS's compareTo
|
||
|
GEOS_DLL friend bool
|
||
|
operator< (const Envelope& a, const Envelope& b);
|
||
|
|
||
|
private:
|
||
|
|
||
|
/** \brief
|
||
|
* Splits a string into parts based on the supplied delimiters.
|
||
|
*
|
||
|
* This is a generic function that really belongs in a utility
|
||
|
* file somewhere
|
||
|
*/
|
||
|
static std::vector<std::string> split(const std::string& str,
|
||
|
const std::string& delimiters = " ");
|
||
|
|
||
|
static double distance(double x0, double y0, double x1, double y1)
|
||
|
{
|
||
|
double dx = x1 - x0;
|
||
|
double dy = y1 - y0;
|
||
|
return std::sqrt(dx * dx + dy * dy);
|
||
|
}
|
||
|
|
||
|
/// the minimum x-coordinate
|
||
|
double minx;
|
||
|
|
||
|
/// the maximum x-coordinate
|
||
|
double maxx;
|
||
|
|
||
|
/// the minimum y-coordinate
|
||
|
double miny;
|
||
|
|
||
|
/// the maximum y-coordinate
|
||
|
double maxy;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
} // namespace geos::geom
|
||
|
} // namespace geos
|