using System;
using GeoAPI.Geometries;
namespace GisSharpBlog.NetTopologySuite.Geometries
{
///
/// Defines a rectangular 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.
/// Note that Envelopes support infinite or half-infinite regions, by using the values of
/// Double.PositiveInfinity and Double.NegativeInfinity.
/// When Envelope objects are created or initialized,
/// the supplies extent values are automatically sorted into the correct order.
///
[Serializable]
public class Envelope : IEnvelope
{
/*
* the minimum x-coordinate
*/
/*
* the maximum x-coordinate
*/
/*
* the minimum y-coordinate
*/
/*
* the maximum y-coordinate
*/
///
/// Creates a null Envelope.
///
public Envelope()
{
Init();
}
///
/// Creates an Envelope for a region defined by maximum and minimum values.
///
/// The first x-value.
/// The second x-value.
/// The first y-value.
/// The second y-value.
public Envelope(double x1, double x2, double y1, double y2)
{
Init(x1, x2, y1, y2);
}
///
/// Creates an Envelope for a region defined by two Coordinates.
///
/// The first Coordinate.
/// The second Coordinate.
public Envelope(ICoordinate p1, ICoordinate p2)
{
Init(p1, p2);
}
///
/// Creates an Envelope for a region defined by a single Coordinate.
///
/// The Coordinate.
public Envelope(ICoordinate p)
{
Init(p);
}
///
/// Create an Envelope from an existing Envelope.
///
/// The Envelope to initialize from.
public Envelope(IEnvelope env)
{
Init(env);
}
///
/// Returns true if this Envelope is a "null" envelope.
///
///
/// true if this Envelope is uninitialized
/// or is the envelope of the empty point.
///
public bool IsNull
{
get
{
return MaxX < MinX;
}
}
///
/// Returns the difference between the maximum and minimum x values.
///
/// max x - min x, or 0 if this is a null Envelope.
public double Width
{
get
{
if (IsNull)
{
return 0;
}
return MaxX - MinX;
}
}
///
/// Returns the difference between the maximum and minimum y values.
///
/// max y - min y, or 0 if this is a null Envelope.
public double Height
{
get
{
if (IsNull)
{
return 0;
}
return MaxY - MinY;
}
}
///
/// Returns the Envelopes minimum x-value. min x > max x
/// indicates that this is a null Envelope.
///
/// The minimum x-coordinate.
public double MinX { get; private set; }
///
/// Returns the Envelopes maximum x-value. min x > max x
/// indicates that this is a null Envelope.
///
/// The maximum x-coordinate.
public double MaxX { get; private set; }
///
/// Returns the Envelopes minimum y-value. min y > max y
/// indicates that this is a null Envelope.
///
/// The minimum y-coordinate.
public double MinY { get; private set; }
///
/// Returns the Envelopes maximum y-value. min y > max y
/// indicates that this is a null Envelope.
///
/// The maximum y-coordinate.
public double MaxY { get; private set; }
///
/// Computes the coordinate of the centre of this envelope (as long as it is non-null).
///
///
/// The centre coordinate of this envelope,
/// or null if the envelope is null.
/// .
public ICoordinate Centre
{
get
{
if (IsNull)
{
return null;
}
return new Coordinate((MinX + MaxX)/2.0, (MinY + MaxY)/2.0);
}
}
/* BEGIN ADDED BY MPAUL42: monoGIS team */
///
/// Returns the area of the envelope.
///
public double Area
{
get
{
double area = 1;
area = area*(MaxX - MinX);
area = area*(MaxY - MinY);
return area;
}
}
///
/// Test the point q to see whether it intersects the Envelope
/// defined by p1-p2.
///
/// One extremal point of the envelope.
/// Another extremal point of the envelope.
/// Point to test for intersection.
/// true if q intersects the envelope p1-p2.
public static bool Intersects(ICoordinate p1, ICoordinate p2, ICoordinate q)
{
if (((q.X >= (p1.X < p2.X ? p1.X : p2.X)) && (q.X <= (p1.X > p2.X ? p1.X : p2.X))) &&
((q.Y >= (p1.Y < p2.Y ? p1.Y : p2.Y)) && (q.Y <= (p1.Y > p2.Y ? p1.Y : p2.Y))))
{
return true;
}
return false;
}
///
/// Test the envelope defined by p1-p2 for intersection
/// with the envelope defined by q1-q2
///
/// One extremal point of the envelope Point.
/// Another extremal point of the envelope Point.
/// One extremal point of the envelope Q.
/// Another extremal point of the envelope Q.
/// true if Q intersects Point
public static bool Intersects(ICoordinate p1, ICoordinate p2, ICoordinate q1, ICoordinate q2)
{
double minq = Math.Min(q1.X, q2.X);
double maxq = Math.Max(q1.X, q2.X);
double minp = Math.Min(p1.X, p2.X);
double maxp = Math.Max(p1.X, p2.X);
if (minp > maxq)
{
return false;
}
if (maxp < minq)
{
return false;
}
minq = Math.Min(q1.Y, q2.Y);
maxq = Math.Max(q1.Y, q2.Y);
minp = Math.Min(p1.Y, p2.Y);
maxp = Math.Max(p1.Y, p2.Y);
if (minp > maxq)
{
return false;
}
if (maxp < minq)
{
return false;
}
return true;
}
///
///
///
///
///
///
public static bool operator ==(Envelope obj1, Envelope obj2)
{
return Equals(obj1, obj2);
}
///
///
///
///
///
///
public static bool operator !=(Envelope obj1, Envelope obj2)
{
return !(obj1 == obj2);
}
///
/// Creates a deep copy of the current envelope.
///
///
public IEnvelope Clone()
{
return new Envelope(MinX, MaxX, MinY, MaxY);
}
///
///
///
///
///
public override bool Equals(object other)
{
if (other == null)
{
return false;
}
if (!(other is Envelope))
{
return false;
}
return Equals((IEnvelope) other);
}
///
///
///
public override int GetHashCode()
{
int result = 17;
result = 37*result + GetHashCode(MinX);
result = 37*result + GetHashCode(MaxX);
result = 37*result + GetHashCode(MinY);
result = 37*result + GetHashCode(MaxY);
return result;
}
///
///
///
///
public override string ToString()
{
return "Env[" + MinX + " : " + MaxX + ", " + MinY + " : " + MaxY + "]";
}
///
/// Initialize to a null Envelope.
///
public void Init()
{
SetToNull();
}
///
/// Initialize an Envelope for a region defined by maximum and minimum values.
///
/// The first x-value.
/// The second x-value.
/// The first y-value.
/// The second y-value.
public 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;
}
}
///
/// Initialize an Envelope for a region defined by two Coordinates.
///
/// The first Coordinate.
/// The second Coordinate.
public void Init(ICoordinate p1, ICoordinate p2)
{
Init(p1.X, p2.X, p1.Y, p2.Y);
}
///
/// Initialize an Envelope for a region defined by a single Coordinate.
///
/// The Coordinate.
public void Init(ICoordinate p)
{
Init(p.X, p.X, p.Y, p.Y);
}
///
/// Initialize an Envelope from an existing Envelope.
///
/// The Envelope to initialize from.
public void Init(IEnvelope env)
{
MinX = env.MinX;
MaxX = env.MaxX;
MinY = env.MinY;
MaxY = env.MaxY;
}
///
/// Makes this Envelope a "null" envelope..
///
public void SetToNull()
{
MinX = 0;
MaxX = -1;
MinY = 0;
MaxY = -1;
}
///
/// Expands this envelope by a given distance in all directions.
/// Both positive and negative distances are supported.
///
/// The distance to expand the envelope.
public void ExpandBy(double distance)
{
ExpandBy(distance, distance);
}
///
/// Expands this envelope by a given distance in all directions.
/// Both positive and negative distances are supported.
///
/// The distance to expand the envelope along the the X axis.
/// The distance to expand the envelope along the the Y axis.
public void ExpandBy(double deltaX, double deltaY)
{
if (IsNull)
{
return;
}
MinX -= deltaX;
MaxX += deltaX;
MinY -= deltaY;
MaxY += deltaY;
// check for envelope disappearing
if (MinX > MaxX || MinY > MaxY)
{
SetToNull();
}
}
///
/// Enlarges the boundary of the Envelope so that it contains (p).
/// Does nothing if (p) is already on or within the boundaries.
///
/// The Coordinate.
public void ExpandToInclude(ICoordinate p)
{
ExpandToInclude(p.X, p.Y);
}
///
/// Enlarges the boundary of the Envelope so that it contains
/// (x,y). Does nothing if (x,y) is already on or within the boundaries.
///
/// The value to lower the minimum x to or to raise the maximum x to.
/// The value to lower the minimum y to or to raise the maximum y to.
public 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;
}
}
}
///
/// Enlarges the boundary of the Envelope so that it contains
/// other. Does nothing if other is wholly on or
/// within the boundaries.
///
/// the Envelope to merge with.
public void ExpandToInclude(IEnvelope other)
{
if (other == null || other.IsNull)
{
return;
}
if (IsNull)
{
MinX = other.MinX;
MaxX = other.MaxX;
MinY = other.MinY;
MaxY = other.MaxY;
}
else
{
if (other.MinX < MinX)
{
MinX = other.MinX;
}
if (other.MaxX > MaxX)
{
MaxX = other.MaxX;
}
if (other.MinY < MinY)
{
MinY = other.MinY;
}
if (other.MaxY > MaxY)
{
MaxY = other.MaxY;
}
}
}
///
/// Translates this envelope by given amounts in the X and Y direction.
///
/// The amount to translate along the X axis.
/// The amount to translate along the Y axis.
public void Translate(double transX, double transY)
{
if (IsNull)
{
return;
}
Init(MinX + transX, MaxX + transX, MinY + transY, MaxY + transY);
}
///
///
///
///
///
public IEnvelope Intersection(IEnvelope env)
{
if (IsNull || env.IsNull || !Intersects(env))
{
return new Envelope();
}
return new Envelope(Math.Max(MinX, env.MinX),
Math.Min(MaxX, env.MaxX),
Math.Max(MinY, env.MinY),
Math.Min(MaxY, env.MaxY));
}
///
/// Check if the region defined by other
/// overlaps (intersects) the region of this Envelope.
///
/// the Envelope which this Envelope is
/// being checked for overlapping.
///
///
/// true if the Envelopes overlap.
///
public bool Intersects(IEnvelope other)
{
if (IsNull || other.IsNull)
{
return false;
}
return !(other.MinX > MaxX || other.MaxX < MinX || other.MinY > MaxY || other.MaxY < MinY);
}
///
/// Use Intersects instead. In the future, Overlaps may be
/// changed to be a true overlap check; that is, whether the intersection is
/// two-dimensional.
///
///
///
[Obsolete("Use Intersects instead")]
public bool Overlaps(IEnvelope other)
{
return Intersects(other);
}
///
/// Use Intersects instead.
///
///
///
[Obsolete("Use Intersects instead")]
public bool Overlaps(ICoordinate p)
{
return Intersects(p);
}
///
/// Use Intersects instead.
///
///
///
///
[Obsolete("Use Intersects instead")]
public bool Overlaps(double x, double y)
{
return Intersects(x, y);
}
///
/// Check if the point p overlaps (lies inside) the region of this Envelope.
///
/// the Coordinate to be tested.
/// true if the point overlaps this Envelope.
public bool Intersects(ICoordinate p)
{
return Intersects(p.X, p.Y);
}
///
/// Check if the point (x, y) overlaps (lies inside) the region of this Envelope.
///
/// the x-ordinate of the point.
/// the y-ordinate of the point.
/// true if the point overlaps this Envelope.
public bool Intersects(double x, double y)
{
return !(x > MaxX || x < MinX || y > MaxY || y < MinY);
}
///
/// Returns true if the given point lies in or on the envelope.
///
/// the point which this Envelope is
/// being checked for containing.
///
/// true if the point lies in the interior or
/// on the boundary of this Envelope.
///
public bool Contains(ICoordinate p)
{
return Contains(p.X, p.Y);
}
///
/// Returns true if the given point lies in or on the envelope.
///
/// the x-coordinate of the point which this Envelope is
/// being checked for containing.
/// the y-coordinate of the point which this Envelope is
/// being checked for containing.
/// true if (x, y) lies in the interior or
/// on the boundary of this Envelope.
public bool Contains(double x, double y)
{
return x >= MinX && x <= MaxX && y >= MinY && y <= MaxY;
}
///
/// Returns true if the Envelope other
/// lies wholely inside this Envelope (inclusive of the boundary).
///
/// the Envelope which this Envelope is being checked for containing.
/// true if other is contained in this Envelope.
public bool Contains(IEnvelope other)
{
if (IsNull || other.IsNull)
{
return false;
}
return other.MinX >= MinX && other.MaxX <= MaxX &&
other.MinY >= MinY && other.MaxY <= MaxY;
}
///
/// 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.
///
/// The distance between this and another Envelope.
public double Distance(IEnvelope env)
{
if (Intersects(env))
{
return 0;
}
double dx = 0.0;
if (MaxX < env.MinX)
{
dx = env.MinX - MaxX;
}
if (MinX > env.MaxX)
{
dx = MinX - env.MaxX;
}
double dy = 0.0;
if (MaxY < env.MinY)
{
dy = env.MinY - MaxY;
}
if (MinY > env.MaxY)
{
dy = MinY - env.MaxY;
}
// if either is zero, the envelopes overlap either vertically or horizontally
if (dx == 0.0)
{
return dy;
}
if (dy == 0.0)
{
return dx;
}
return Math.Sqrt(dx*dx + dy*dy);
}
///
///
///
///
///
public bool Equals(IEnvelope other)
{
if (IsNull)
{
return other.IsNull;
}
if (other == null)
{
return false;
}
return MaxX == other.MaxX && MaxY == other.MaxY &&
MinX == other.MinX && MinY == other.MinY;
}
///
///
///
///
///
public int CompareTo(object other)
{
return CompareTo((IEnvelope) other);
}
///
///
///
///
///
public int CompareTo(IEnvelope other)
{
if (IsNull && other.IsNull)
{
return 0;
}
else if (!IsNull && other.IsNull)
{
return 1;
}
else if (IsNull && !other.IsNull)
{
return -1;
}
if (Area > other.Area)
{
return 1;
}
if (Area < other.Area)
{
return -1;
}
return 0;
}
///
/// Creates a new object that is a copy of the current instance.
///
/// A new object that is a copy of this instance.
object ICloneable.Clone()
{
return Clone();
}
///
/// Calculates the union of the current box and the given point.
///
public IEnvelope Union(IPoint point)
{
return Union(point.Coordinate);
}
///
/// Calculates the union of the current box and the given coordinate.
///
public IEnvelope Union(ICoordinate coord)
{
Envelope env = (Envelope) Clone();
env.ExpandToInclude(coord);
return env;
}
///
/// Calculates the union of the current box and the given box.
///
public IEnvelope Union(IEnvelope box)
{
if (box.IsNull)
{
return this;
}
if (IsNull)
{
return box;
}
return new Envelope(Math.Min(MinX, box.MinX),
Math.Max(MaxX, box.MaxX),
Math.Min(MinY, box.MinY),
Math.Max(MaxY, box.MaxY));
}
///
/// Moves the envelope to the indicated coordinate.
///
/// The new centre coordinate.
public void SetCentre(ICoordinate centre)
{
SetCentre(centre, Width, Height);
}
///
/// Moves the envelope to the indicated point.
///
/// The new centre point.
public void SetCentre(IPoint centre)
{
SetCentre(centre.Coordinate, Width, Height);
}
///
/// Resizes the envelope to the indicated point.
///
/// The new width.
/// The new height.
public void SetCentre(double width, double height)
{
SetCentre(Centre, width, height);
}
///
/// Moves and resizes the current envelope.
///
/// The new centre point.
/// The new width.
/// The new height.
public void SetCentre(IPoint centre, double width, double height)
{
SetCentre(centre.Coordinate, width, height);
}
///
/// Moves and resizes the current envelope.
///
/// The new centre coordinate.
/// The new width.
/// The new height.
public void SetCentre(ICoordinate centre, double width, double height)
{
MinX = centre.X - (width/2);
MaxX = centre.X + (width/2);
MinY = centre.Y - (height/2);
MaxY = centre.Y + (height/2);
}
///
/// Zoom the box.
/// Possible values are e.g. 50 (to zoom in a 50%) or -50 (to zoom out a 50%).
///
///
/// Negative do Envelope smaller.
/// Positive do Envelope bigger.
///
///
/// perCent = -50 compact the envelope a 50% (make it smaller).
/// perCent = 200 enlarge envelope by 2.
///
public void Zoom(double perCent)
{
double w = (Width*perCent/100);
double h = (Height*perCent/100);
SetCentre(w, h);
}
///
/// Return HashCode.
///
/// Value from HashCode computation.
private static int GetHashCode(double value)
{
long f = BitConverter.DoubleToInt64Bits(value);
return (int) (f ^ (f >> 32));
}
/* END ADDED BY MPAUL42: monoGIS team */
}
}