BoundingBox.cs
上传用户:sex100000
上传日期:2013-11-09
资源大小:1377k
文件大小:16k
源码类别:

GIS编程

开发平台:

C#

  1. // Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
  2. //
  3. // This file is part of SharpMap.
  4. // SharpMap is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. // 
  9. // SharpMap is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU Lesser General Public License for more details.
  13. // You should have received a copy of the GNU Lesser General Public License
  14. // along with SharpMap; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Collections.ObjectModel;
  19. using System.Text;
  20. namespace SharpMap.Geometries
  21. {
  22. /// <summary>
  23. /// Bounding box type with double precision
  24. /// </summary>
  25. /// <remarks>
  26. /// The Bounding Box represents a box whose sides are parallel to the two axes of the coordinate system.
  27. /// </remarks>
  28. [Serializable]
  29. public class BoundingBox : IEquatable<BoundingBox>
  30. {
  31. /// <summary>
  32. /// Initializes a bounding box
  33. /// </summary>
  34. /// <remarks>
  35. /// In case min values are larger than max values, the parameters will be swapped to ensure correct min/max boundary
  36. /// </remarks>
  37. /// <param name="minX">left</param>
  38. /// <param name="minY">bottom</param>
  39. /// <param name="maxX">right</param>
  40. /// <param name="maxY">top</param>
  41. public BoundingBox(double minX, double minY, double maxX, double maxY)
  42. {
  43. _Min = new Point(minX, minY);
  44. _Max = new Point(maxX, maxY);
  45. CheckMinMax();
  46. }
  47. /// <summary>
  48. /// Initializes a bounding box
  49. /// </summary>
  50. /// <param name="lowerLeft">Lower left corner</param>
  51. /// <param name="upperRight">Upper right corner</param>
  52. public BoundingBox(Geometries.Point lowerLeft, Geometries.Point upperRight)
  53. : this(lowerLeft.X, lowerLeft.Y, upperRight.X, upperRight.Y)
  54. {
  55. }
  56. /// <summary>
  57. /// Initializes a new Bounding Box based on the bounds from a set of geometries
  58. /// </summary>
  59. /// <param name="objects">list of objects</param>
  60. public BoundingBox(Collection<SharpMap.Geometries.Geometry> objects)
  61. {
  62. if (objects == null || objects.Count == 0)
  63. {
  64. _Min = null;
  65. _Max = null;
  66. return;
  67. }
  68. _Min = objects[0].GetBoundingBox().Min.Clone();
  69. _Max = objects[0].GetBoundingBox().Max.Clone();
  70. CheckMinMax();
  71. for (int i = 1; i < objects.Count; i++)
  72. {
  73. BoundingBox box = objects[i].GetBoundingBox();
  74. _Min.X = Math.Min(box.Min.X, this.Min.X);
  75. _Min.Y = Math.Min(box.Min.Y, this.Min.Y);
  76. _Max.X = Math.Max(box.Max.X, this.Max.X);
  77. _Max.Y = Math.Max(box.Max.Y, this.Max.Y);
  78. }
  79. }
  80. /// <summary>
  81. /// Initializes a new Bounding Box based on the bounds from a set of bounding boxes
  82. /// </summary>
  83. /// <param name="objects">list of objects</param>
  84. public BoundingBox(Collection<SharpMap.Geometries.BoundingBox> objects)
  85. {
  86. if (objects.Count == 0) { _Max = null; _Min = null; }
  87. else
  88. {
  89. _Min = objects[0].Min.Clone();
  90. _Max = objects[0].Max.Clone();
  91. for (int i = 1; i < objects.Count; i++)
  92. {
  93. _Min.X = Math.Min(objects[i].Min.X, this.Min.X);
  94. _Min.Y = Math.Min(objects[i].Min.Y, this.Min.Y);
  95. _Max.X = Math.Max(objects[i].Max.X, this.Max.X);
  96. _Max.Y = Math.Max(objects[i].Max.Y, this.Max.Y);
  97. }
  98. }
  99. }
  100. private Point _Min;
  101. /// <summary>
  102. /// Gets or sets the lower left corner.
  103. /// </summary>
  104. public SharpMap.Geometries.Point Min
  105. {
  106. get { return _Min; }
  107. set { _Min = value; }
  108. }
  109. private SharpMap.Geometries.Point _Max;
  110. /// <summary>
  111. /// Gets or sets the upper right corner.
  112. /// </summary>
  113. public SharpMap.Geometries.Point Max
  114. {
  115. get { return _Max; }
  116. set { _Max = value; }
  117. }
  118. /// <summary>
  119. /// Gets the left boundary
  120. /// </summary>
  121. public Double Left
  122. {
  123. get { return _Min.X; }
  124. }
  125. /// <summary>
  126. /// Gets the right boundary
  127. /// </summary>
  128. public Double Right
  129. {
  130. get { return _Max.X; }
  131. }
  132. /// <summary>
  133. /// Gets the top boundary
  134. /// </summary>
  135. public Double Top
  136. {
  137. get { return _Max.Y; }
  138. }
  139. /// <summary>
  140. /// Gets the bottom boundary
  141. /// </summary>
  142. public Double Bottom
  143. {
  144. get { return _Min.Y; }
  145. }
  146. /// <summary>
  147. /// Returns the width of the bounding box
  148. /// </summary>
  149. /// <returns>Width of boundingbox</returns>
  150. public double Width
  151. {
  152. get { return Math.Abs(_Max.X - _Min.X); }
  153. }
  154. /// <summary>
  155. /// Returns the height of the bounding box
  156. /// </summary>
  157. /// <returns>Height of boundingbox</returns>
  158. public double Height
  159. {
  160. get { return Math.Abs(_Max.Y - _Min.Y); }
  161. }
  162. /// <summary>
  163. /// Moves/translates the <see cref="BoundingBox"/> along the the specified vector
  164. /// </summary>
  165. /// <param name="vector">Offset vector</param>
  166. public void Offset(Point vector)
  167. {
  168. _Min += vector;
  169. _Max += vector;
  170. }
  171. /// <summary>
  172. /// Checks whether min values are actually smaller than max values and in that case swaps them.
  173. /// </summary>
  174. /// <returns>true if the bounding was changed</returns>
  175. public bool CheckMinMax()
  176. {
  177. bool wasSwapped = false;
  178. if (_Min.X > _Max.X)
  179. {
  180. double tmp = _Min.X;
  181. _Min.X = _Max.X;
  182. _Max.X = tmp;
  183. wasSwapped = true;
  184. }
  185. if (_Min.Y > _Max.Y)
  186. {
  187. double tmp = _Min.Y;
  188. _Min.Y = _Max.Y;
  189. _Max.Y = tmp;
  190. wasSwapped = true;
  191. }
  192. return wasSwapped;
  193. }
  194. /// <summary>
  195. /// Determines whether the boundingbox intersects another boundingbox
  196. /// </summary>
  197. /// <param name="box"></param>
  198. /// <returns></returns>
  199. public bool Intersects(BoundingBox box)
  200. {
  201. return !(box.Min.X > this.Max.X ||
  202.  box.Max.X < this.Min.X ||
  203.  box.Min.Y > this.Max.Y ||
  204.  box.Max.Y < this.Min.Y);
  205. }
  206. /// <summary>
  207. /// Returns true if this <see cref="BoundingBox"/> intersects the geometry
  208. /// </summary>
  209. /// <param name="g">Geometry</param>
  210. /// <returns>True if intersects</returns>
  211. public bool Intersects(Geometry g)
  212. {
  213. return this.Touches(g);
  214. }
  215. /// <summary>
  216. /// Returns true if this instance touches the <see cref="BoundingBox"/>
  217. /// </summary>
  218. /// <param name="r"><see cref="BoundingBox"/></param>
  219. /// <returns>True it touches</returns>
  220. public bool Touches(BoundingBox r)
  221. {
  222. for (uint cIndex = 0; cIndex < 2; cIndex++)
  223. {
  224. if ((Min[cIndex] > r.Min[cIndex] && Min[cIndex] < r.Min[cIndex]) ||
  225. (Max[cIndex] > r.Max[cIndex] && Max[cIndex] < r.Max[cIndex]))
  226. return true;
  227. }
  228. return false;
  229. }
  230. /// <summary>
  231. /// Returns true if this <see cref="BoundingBox"/> touches the geometry
  232. /// </summary>
  233. /// <param name="s">Geometry</param>
  234. /// <returns>True if touches</returns>
  235. public bool Touches(Geometry s)
  236. {
  237. if (s is Point) return Touches(s as Point);
  238. throw new NotImplementedException("Touches: Not implemented on this geometry type");
  239. }
  240. /// <summary>
  241. /// Returns true if this instance contains the <see cref="BoundingBox"/>
  242. /// </summary>
  243. /// <param name="r"><see cref="BoundingBox"/></param>
  244. /// <returns>True it contains</returns>
  245. public bool Contains(BoundingBox r)
  246. {
  247. for (uint cIndex = 0; cIndex < 2; cIndex++)
  248. if (Min[cIndex] > r.Min[cIndex] || Max[cIndex] < r.Max[cIndex]) return false;
  249. return true;
  250. }
  251. /// <summary>
  252. /// Returns true if this instance contains the geometry
  253. /// </summary>
  254. /// <param name="s"><see cref="BoundingBox"/></param>
  255. /// <returns>True it contains</returns>
  256. public bool Contains(Geometry s)
  257. {
  258. if (s is Point) return Contains(s as Point);
  259. throw new NotImplementedException("Contains: Not implemented on these geometries");
  260. }
  261. /// <summary>
  262. /// Returns true if this instance touches the <see cref="Point"/>
  263. /// </summary>
  264. /// <param name="p">Geometry</param>
  265. /// <returns>True if touches</returns>
  266. public bool Touches(Point p)
  267. {
  268. for (uint cIndex = 0; cIndex < 2; cIndex++)
  269. {
  270. if ((Min[cIndex] > p[cIndex] && Min[cIndex] < p[cIndex]) ||
  271. (Max[cIndex] > p[cIndex] && Max[cIndex] < p[cIndex]))
  272. return true;
  273. }
  274. return false;
  275. }
  276. /// <summary>
  277. /// Returns the area of the BoundingBox
  278. /// </summary>
  279. /// <returns>Area of box</returns>
  280. public double GetArea()
  281. {
  282. return Width * Height;
  283. }
  284. /// <summary>
  285. /// Gets the intersecting area between two boundingboxes
  286. /// </summary>
  287. /// <param name="r">BoundingBox</param>
  288. /// <returns>Area</returns>
  289. public double GetIntersectingArea(BoundingBox r)
  290. {
  291. uint cIndex;
  292. for (cIndex = 0; cIndex < 2; cIndex++)
  293. if (Min[cIndex] > r.Max[cIndex] || Max[cIndex] < r.Min[cIndex]) return 0.0;
  294. double ret = 1.0;
  295. double f1, f2;
  296. for (cIndex = 0; cIndex < 2; cIndex++)
  297. {
  298. f1 = Math.Max(Min[cIndex], r.Min[cIndex]);
  299. f2 = Math.Min(Max[cIndex], r.Max[cIndex]);
  300. ret *= f2 - f1;
  301. }
  302. return ret;
  303. }
  304. /// <summary>
  305. /// Computes the joined boundingbox of this instance and another boundingbox
  306. /// </summary>
  307. /// <param name="box">Boundingbox to join with</param>
  308. /// <returns>Boundingbox containing both boundingboxes</returns>
  309. public BoundingBox Join(BoundingBox box)
  310. {
  311. if (box == null)
  312. return this.Clone();
  313. else
  314. return new BoundingBox(Math.Min(this.Min.X, box.Min.X), Math.Min(this.Min.Y, box.Min.Y),
  315.    Math.Max(this.Max.X, box.Max.X), Math.Max(this.Max.Y, box.Max.Y));
  316. }
  317. /// <summary>
  318. /// Computes the joined boundingbox of two boundingboxes
  319. /// </summary>
  320. /// <param name="box1"></param>
  321. /// <param name="box2"></param>
  322. /// <returns></returns>
  323. public static BoundingBox Join(BoundingBox box1, BoundingBox box2)
  324. {
  325. if (box1 == null && box2 == null)
  326. return null;
  327. else if (box1 == null)
  328. return box2.Clone();
  329. else
  330. return box1.Join(box2);
  331. }
  332. /// <summary>
  333. /// Computes the joined <see cref="BoundingBox"/> of an array of boundingboxes.
  334. /// </summary>
  335. /// <param name="boxes">Boxes to join</param>
  336. /// <returns>Combined BoundingBox</returns>
  337. public static BoundingBox Join(BoundingBox[] boxes)
  338. {
  339. if (boxes == null) return null;
  340. if (boxes.Length == 1) return boxes[0];
  341. BoundingBox box = boxes[0].Clone();
  342. for (int i = 1; i < boxes.Length; i++)
  343. box = box.Join(boxes[i]);
  344. return box;
  345. }
  346. /// <summary>
  347. /// Increases the size of the boundingbox by the givent amount in all directions
  348. /// </summary>
  349. /// <param name="amount">Amount to grow in all directions</param>
  350. public BoundingBox Grow(double amount)
  351. {
  352. BoundingBox box = this.Clone();
  353. box.Min.X -= amount;
  354. box.Min.Y -= amount;
  355. box.Max.X += amount;
  356. box.Max.Y += amount;
  357. box.CheckMinMax();
  358. return box;
  359. }
  360. /// <summary>
  361. /// Increases the size of the boundingbox by the givent amount in horizontal and vertical directions
  362. /// </summary>
  363. /// <param name="amountInX">Amount to grow in horizontal direction</param>
  364. /// <param name="amountInY">Amount to grow in vertical direction</param>
  365. public BoundingBox Grow(double amountInX, double amountInY)
  366. {
  367. BoundingBox box = this.Clone();
  368. box.Min.X -= amountInX;
  369. box.Min.Y -= amountInY;
  370. box.Max.X += amountInX;
  371. box.Max.Y += amountInY;
  372. box.CheckMinMax();
  373. return box;
  374. }
  375. /// <summary>
  376. /// Checks whether a point lies within the bounding box
  377. /// </summary>
  378. /// <param name="p">Point</param>
  379. /// <returns>true if point is within</returns>
  380. public bool Contains(Point p)
  381. {
  382. if (this.Max.X < p.X)
  383. return false;
  384. if (this.Min.X > p.X)
  385. return false;
  386. if (this.Max.Y < p.Y)
  387. return false;
  388. if (this.Min.Y > p.Y)
  389. return false;
  390. return true;
  391. }
  392. /// <summary> 
  393. /// Computes the minimum distance between this and another <see cref="BoundingBox"/>.
  394. /// The distance between overlapping bounding boxes is 0.  Otherwise, the
  395. /// distance is the Euclidean distance between the closest points.
  396. /// </summary>
  397. /// <param name="box">Box to calculate distance to</param>
  398. /// <returns>The distance between this and another <see cref="BoundingBox"/>.</returns>
  399. public virtual double Distance(BoundingBox box)
  400. {
  401. double ret = 0.0;
  402. for (uint cIndex = 0; cIndex < 2; cIndex++)
  403. {
  404. double x = 0.0;
  405. if (box.Max[cIndex] < Min[cIndex]) x = Math.Abs(box.Max[cIndex] - Min[cIndex]);
  406. else if (Max[cIndex] < box.Min[cIndex]) x = Math.Abs(box.Min[cIndex] - Max[cIndex]);
  407. ret += x * x;
  408. }
  409. return Math.Sqrt(ret);
  410. }
  411. /// <summary>
  412. /// Computes the minimum distance between this BoundingBox and a <see cref="Point"/>
  413. /// </summary>
  414. /// <param name="p"><see cref="Point"/> to calculate distance to.</param>
  415. /// <returns>Minimum distance.</returns>
  416. public virtual double Distance(Point p)
  417. {
  418. double ret = 0.0;
  419. for (uint cIndex = 0; cIndex < 2; cIndex++)
  420. {
  421. if (p[cIndex] < Min[cIndex]) ret += Math.Pow(Min[cIndex] - p[cIndex], 2.0);
  422. else if (p[cIndex] > Max[cIndex]) ret += Math.Pow(p[cIndex] - Max[cIndex], 2.0);
  423. }
  424. return Math.Sqrt(ret);
  425. }
  426. /// <summary>
  427. /// Intersection scalar (used for weighting in building the tree) 
  428. /// </summary>
  429. public uint LongestAxis
  430. {
  431. get
  432. {
  433. SharpMap.Geometries.Point boxdim = this.Max - this.Min;
  434. uint la = 0; // longest axis
  435. double lav = 0; // longest axis length
  436. // for each dimension  
  437. for (uint ii = 0; ii < 2; ii++)
  438. {
  439. // check if its longer
  440. if (boxdim[ii] > lav)
  441. {
  442. // store it if it is
  443. la = ii;
  444. lav = boxdim[ii];
  445. }
  446. }
  447. return la;
  448. }
  449. }
  450. /// <summary>
  451. /// Returns the center of the bounding box
  452. /// </summary>
  453. public Point GetCentroid()
  454. {
  455. return (this._Min + this._Max) * .5f;
  456. }
  457. /// <summary>
  458. /// Creates a copy of the BoundingBox
  459. /// </summary>
  460. /// <returns></returns>
  461. public BoundingBox Clone()
  462. {
  463. return new BoundingBox(this._Min.X, this._Min.Y, this._Max.X, this._Max.Y);
  464. }
  465. /// <summary>
  466. /// Returns a string representation of the boundingbox as LowerLeft + UpperRight formatted as "MinX,MinY MaxX,MaxY"
  467. /// </summary>
  468. /// <returns>MinX,MinY MaxX,MaxY</returns>
  469. public override string ToString()
  470. {
  471. return String.Format(SharpMap.Map.numberFormat_EnUS, "{0},{1} {2},{3}", this.Min.X, this.Min.Y, this.Max.X, this.Max.Y);
  472. }
  473. #region IEquatable<BoundingBox> Members
  474. /// <summary>
  475. /// Indicates whether the current object is equal to another object of the same type.
  476. /// </summary>
  477. /// <param name="obj"></param>
  478. /// <returns></returns>
  479. public override bool Equals(object obj)
  480. {
  481. BoundingBox box = obj as BoundingBox;
  482. if (obj == null) return false;
  483. else return Equals(box);
  484. }
  485. /// <summary>
  486. /// Returns a hash code for the specified object
  487. /// </summary>
  488. /// <returns>A hash code for the specified object</returns>
  489. public override int GetHashCode()
  490. {
  491. return Min.GetHashCode() ^ Max.GetHashCode();
  492. }
  493. /// <summary>
  494. /// Checks whether the values of this instance is equal to the values of another instance.
  495. /// </summary>
  496. /// <param name="other"><see cref="BoundingBox"/> to compare to.</param>
  497. /// <returns>True if equal</returns>
  498. public bool Equals(BoundingBox other)
  499. {
  500. if (other == null) return false;
  501. return this.Left == other.Left && this.Right == other.Right && this.Top == other.Top && this.Bottom == other.Bottom;
  502. }
  503. #endregion
  504. }
  505. }