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
{
///
/// 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;
}
/*
* the minimum x-coordinate
*/
private double minx;
/*
* the maximum x-coordinate
*/
private double maxx;
/*
* the minimum y-coordinate
*/
private double miny;
/*
* the maximum y-coordinate
*/
private double maxy;
///
/// 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);
}
///
/// 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)
{
this.minx = env.MinX;
this.maxx = env.MaxX;
this.miny = env.MinY;
this.maxy = env.MaxY;
}
///
/// Makes this Envelope a "null" envelope..
///
public void SetToNull()
{
minx = 0;
maxx = -1;
miny = 0;
maxy = -1;
}
///
/// 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
{
return minx;
}
}
///
/// 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
{
return maxx;
}
}
///
/// 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
{
return miny;
}
}
///
/// 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
{
return maxy;
}
}
///
/// 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);
}
///
/// 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);
}
}
///
///
///
///
///
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 override bool Equals(object other)
{
if (other == null)
return false;
if (!(other is Envelope))
return false;
return Equals((IEnvelope) other);
}
///
///
///
///
///
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;
}
///
///
///
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;
}
///
/// Return HashCode.
///
/// Value from HashCode computation.
private static int GetHashCode(double value)
{
long f = BitConverter.DoubleToInt64Bits(value);
return (int) (f ^ (f >> 32));
}
///
///
///
///
///
///
public static bool operator ==(Envelope obj1, Envelope obj2)
{
return Equals(obj1, obj2);
}
///
///
///
///
///
///
public static bool operator !=(Envelope obj1, Envelope obj2)
{
return !(obj1 == obj2);
}
///
///
///
///
public override string ToString()
{
return "Env[" + minx + " : " + maxx + ", " + miny + " : " + maxy + "]";
}
///
/// 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();
}
/* 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;
}
}
///
/// Creates a deep copy of the current envelope.
///
///
public IEnvelope Clone()
{
return new Envelope(minx, maxx, miny, maxy);
}
///
/// 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) this.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 (this.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 = (this.Width * perCent / 100);
double h = (this.Height * perCent / 100);
SetCentre(w, h);
}
/* END ADDED BY MPAUL42: monoGIS team */
}
}