/// <summary> /// Enlarges the boundary of the <c>Envelope</c> so that it contains (p). /// Does nothing if (p) is already on or within the boundaries. /// This executes to the minimum of dimensions between p and this envelope. /// </summary> /// <param name="self">The first envelope (this object when extending)</param> /// <param name="p">The Coordinate.</param> public static void ExpandToInclude(this IEnvelope self, Coordinate p) { if (self == null) { return; } if (self.IsNull) { self.Init(p, p); return; } int numDimensions = Math.Min(self.NumOrdinates, p.NumOrdinates); Coordinate min = self.Minimum; Coordinate max = self.Maximum; for (int i = 0; i < numDimensions; i++) { if (p[i] < min[i]) { min[i] = p[i]; } if (p[i] > max[i]) { max[i] = p[i]; } } self.Init(min, max); // this is to ensure we don't break the min/max relationships. }
/// <summary> /// Translates the envelope by given amounts up to the minimum dimension between /// the envelope and the shift coordinate. (e.g., A 2D envelope will only /// be shifted in 2 dimensions because it has no Z, while a 2D coordinate /// can only shift a cube based on the X and Y positions, leaving the Z /// info alone. /// </summary> /// <param name="self">The IEnvelope to use with this method</param> /// <param name="shift"></param> /// <remarks>This does nothing to a "NULL" envelope</remarks> public static void Translate(this IEnvelope self, Coordinate shift) { if (self == null) { return; } if (self.IsNull) { return; } if (shift == null) { return; } Coordinate min = self.Minimum; Coordinate max = self.Maximum; int numDimensions = Math.Min(self.NumOrdinates, shift.NumOrdinates); for (int i = 0; i < numDimensions; i++) { min[i] += shift[i]; max[i] += shift[i]; } self.Init(min, max); }
/// <summary> /// /// </summary> /// <param name="level"></param> /// <param name="itemEnv"></param> private void ComputeKey(int level, IEnvelope itemEnv) { double quadSize = DoubleBits.PowerOf2(level); pt.X = Math.Floor(itemEnv.MinX / quadSize) * quadSize; pt.Y = Math.Floor(itemEnv.MinY / quadSize) * quadSize; env.Init(pt.X, pt.X + quadSize, pt.Y, pt.Y + quadSize); }
/// <summary> /// The two dimensional overload for consistency with other code. /// Despite the names, this will force the smallest X coordinate given /// to become maxX. /// </summary> /// <param name="self">The IEnvelope to use with this method</param> /// <param name="minX">An X coordinate</param> /// <param name="minY">A Y coordinate</param> /// <param name="maxX">Another X coordinate</param> /// <param name="maxY">Another Y coordinate</param> public static void SetExtents(this IEnvelope self, double minX, double minY, double maxX, double maxY) { if (self == null) { return; } Coordinate min = new Coordinate(minX, minY); Coordinate max = new Coordinate(maxX, maxY); self.Init(min, max); }
/// <summary> /// /// </summary> /// <param name="start0"></param> /// <param name="end0"></param> /// <param name="mce"></param> /// <param name="start1"></param> /// <param name="end1"></param> /// <param name="ei"></param> private void ComputeIntersectsForChain(int start0, int end0, MonotoneChainEdge mce, int start1, int end1, SegmentIntersector ei) { ICoordinate p00 = pts[start0]; ICoordinate p01 = pts[end0]; ICoordinate p10 = mce.pts[start1]; ICoordinate p11 = mce.pts[end1]; // terminating condition for the recursion if (end0 - start0 == 1 && end1 - start1 == 1) { ei.AddIntersections(e, start0, mce.e, start1); return; } // nothing to do if the envelopes of these chains don't overlap env1.Init(p00, p01); env2.Init(p10, p11); if (!env1.Intersects(env2)) { return; } // the chains overlap, so split each in half and iterate (binary search) int mid0 = (start0 + end0) / 2; int mid1 = (start1 + end1) / 2; // check terminating conditions before recursing if (start0 < mid0) { if (start1 < mid1) { ComputeIntersectsForChain(start0, mid0, mce, start1, mid1, ei); } if (mid1 < end1) { ComputeIntersectsForChain(start0, mid0, mce, mid1, end1, ei); } } if (mid0 < end0) { if (start1 < mid1) { ComputeIntersectsForChain(mid0, end0, mce, start1, mid1, ei); } if (mid1 < end1) { ComputeIntersectsForChain(mid0, end0, mce, mid1, end1, ei); } } }
/// <summary> /// Enlarges the boundary of the <c>Envelope</c> so that it contains /// <c>other</c>. Does nothing if <c>other</c> is wholly on or /// within the boundaries. /// </summary> /// <param name="self">The first envelope (this object when extending)</param> /// <param name="other">the <c>Envelope</c> to merge with.</param> public static void ExpandToInclude(this IEnvelope self, IEnvelope other) { if (self == null) { return; } if (other == null) { return; } if (other.IsNull) { return; } if (self.IsNull) { self.Init(other.Minimum, other.Maximum); return; } int numDimensions = Math.Min(self.NumOrdinates, other.NumOrdinates); Coordinate min = self.Minimum; Coordinate max = self.Maximum; for (int i = 0; i < numDimensions; i++) { if (other.Minimum[i] < min[i]) { min[i] = other.Minimum[i]; } if (other.Maximum[i] > max[i]) { max[i] = other.Maximum[i]; } } self.Init(min, max); // re-initialize to prevent sign errors and indicate a change. }
/// <summary> /// Uses the dimensions of the specified distances coordinate to /// specify the amount to expand the envelopes in each ordinate. /// This will apply the method to the minimum dimensions between /// the distances coordinate and this envelope. (eg. A 2D /// distances coordinate will not affect Z values in the envelope). /// </summary> /// <param name="self">The first envelope (this object when extending)</param> /// <param name="distances">The distance to expand the envelope.</param> public static void ExpandBy(this IEnvelope self, Coordinate distances) { if (self == null) { return; } int numDimensions = Math.Min(self.NumOrdinates, distances.NumOrdinates); Coordinate min = self.Minimum; Coordinate max = self.Maximum; for (int i = 0; i < numDimensions; i++) { min[i] -= distances[i]; max[i] += distances[i]; } self.Init(min, max); // this is important in case negative values are used, and // the maximum is now the minimum etc. }
/// <summary> /// This handles setting the center and scale in N dimensions. The size is equivalent to the /// span in each dimension, while the center is the central position in each dimension. The /// envelope will have values in each dimension where either the existing envelope or both the /// specified center and size values have been specified. If only the existing envelope /// and a size is specified for dimension 3, for example, the existing center will be used. /// </summary> /// <param name="self">The envelope to modify</param> /// <param name="center">The center position. This can also be null.</param> /// <param name="size">The size (or span) in each dimension. This can also be null.</param> public static void SetCenter(this IEnvelope self, Coordinate center, Coordinate size) { int centerDimensions = 0; int sizeDimensions = 0; if (self == null) { return; } if (center != null) { centerDimensions = center.NumOrdinates; } if (size != null) { sizeDimensions = size.NumOrdinates; } int numDimensionsCenterAndSize = Math.Min(centerDimensions, sizeDimensions); int numDimensions = Math.Max(self.NumOrdinates, numDimensionsCenterAndSize); Coordinate min = new Coordinate(); Coordinate max = new Coordinate(); for (int i = 0; i < numDimensions; i++) { if (centerDimensions > i && sizeDimensions > i) { // we have completely new information for this dimension if (center != null) { if (size != null) { min[i] = center[i] - size[i] / 2; max[i] = center[i] + size[i] / 2; } } } if (centerDimensions <= i && sizeDimensions <= i) { // we have no new information at all, so just use the existing envelope min[i] = self.Minimum[i]; max[i] = self.Maximum[i]; } if (centerDimensions > i && sizeDimensions <= i) { // We have a center specified in this dimension, but not a size, so keep the old size double oldSize = self.Maximum[i] - self.Minimum[i]; if (center != null) { min[i] = center[i] - oldSize / 2; max[i] = center[i] + oldSize / 2; } } if (centerDimensions <= i && sizeDimensions > i) { // We have a size specified in this dimension, but not any center information, so use the old center. double oldCenter = (self.Minimum[i] + self.Maximum[i]) / 2; if (size != null) { min[i] = oldCenter - size[i]; max[i] = oldCenter + size[i]; } } } self.Init(min, max); }