///<summary> /// Initializes the points. ///</summary> /// <param name="p0">1st coordinate</param> /// <param name="p1">2nd coordinate</param> public void Initialize(Coordinate p0, Coordinate p1) { _pt[0].CoordinateValue = p0; _pt[1].CoordinateValue = p1; _distance = p0.Distance(p1); _isNull = false; }
/// <summary> /// Computes the inCircle test using distance from the circumcentre. /// Uses standard double-precision arithmetic. /// </summary> /// <remarks> /// In general this doesn't /// appear to be any more robust than the standard calculation. However, there /// is at least one case where the test point is far enough from the /// circumcircle that this test gives the correct answer. /// <pre> /// LINESTRING (1507029.9878 518325.7547, 1507022.1120341457 518332.8225183258, /// 1507029.9833 518325.7458, 1507029.9896965567 518325.744909031) /// </pre> /// </remarks> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <param name="p">The point to test</param> /// <returns>The area of a triangle defined by the points a, b and c</returns> public static bool IsInCircleCC(Coordinate a, Coordinate b, Coordinate c, Coordinate p) { Coordinate cc = Triangle.Circumcentre(a, b, c); double ccRadius = a.Distance(cc); double pRadiusDiff = p.Distance(cc) - ccRadius; return pRadiusDiff <= 0; }
/// <summary> /// /// </summary> /// <param name="point"></param> private void Add(Coordinate point) { double dist = point.Distance(_centroid); if (dist < _minDistance) { _interiorPoint = new Coordinate(point); _minDistance = dist; } }
private void checkWithinCircle(Coordinate[] pts, Coordinate centre, double radius, double tolerance) { for (int i = 0; i < pts.Length; i++) { Coordinate p = pts[i]; double ptRadius = centre.Distance(p); double error = ptRadius - radius; Assert.LessOrEqual(error, tolerance); } }
/// <summary> /// Tests whether the given point is redundant /// relative to the previous /// point in the list (up to tolerance). /// </summary> /// <param name="pt"></param> /// <returns>true if the point is redundant</returns> private bool IsRedundant(Coordinate pt) { if (_ptList.Count < 1) return false; var lastPt = _ptList[_ptList.Count - 1]; double ptDist = pt.Distance(lastPt); if (ptDist < _minimimVertexDistance) return true; return false; }
///<summary> /// Tests whether the given point duplicates the previous point in the list (up to tolerance) ///</summary> /// <param name="pt">The point to test</param> /// <returns>true if the point duplicates the previous point</returns> private bool IsDuplicate(Coordinate pt) { if (_ptList.Count < 1) return false; var lastPt = _ptList[_ptList.Count - 1]; var ptDist = pt.Distance(lastPt); if (ptDist < _minimimVertexDistance) return true; return false; }
public static double Distance(Coordinate p0, Coordinate p1) { // default to 2D distance if either Z is not set if (Double.IsNaN(p0.Z) || Double.IsNaN(p1.Z)) return p0.Distance(p1); var dx = p0.X - p1.X; var dy = p0.Y - p1.Y; var dz = p0.Z - p1.Z; return Math.Sqrt(dx * dx + dy * dy + dz * dz); }
public void SetMaximum(Coordinate p0, Coordinate p1) { if (_isNull) { Initialize(p0, p1); return; } double dist = p0.Distance(p1); if (dist > _distance) Initialize(p0, p1, dist); }
private void Densify(Coordinate p0, Coordinate p1, double segLength) { double origLen = p1.Distance(p0); int nPtsToAdd = (int)Math.Floor(origLen / segLength); double delx = p1.X - p0.X; double dely = p1.Y - p0.Y; double segLenFrac = segLength / origLen; for (int i = 0; i <= nPtsToAdd; i++) { double addedPtFrac = i * segLenFrac; Coordinate pt = new Coordinate(p0.X + addedPtFrac * delx, p0.Y + addedPtFrac * dely); newCoords.Add(pt, false); } newCoords.Add(new Coordinate(p1), false); }
/// <summary> /// Creates an AffineTransformation defined by a pair of control vectors. A /// control vector consists of a source point and a destination point, which is /// the image of the source point under the desired transformation. The /// computed transformation is a combination of one or more of a uniform scale, /// a rotation, and a translation (i.e. there is no shear component and no /// reflection) /// </summary> /// <param name="src0"></param> /// <param name="src1"></param> /// <param name="dest0"></param> /// <param name="dest1"></param> /// <returns>The computed transformation</returns> /// <returns><c>null</c> if the control vectors do not determine a well-defined transformation</returns> public static AffineTransformation CreateFromControlVectors(Coordinate src0, Coordinate src1, Coordinate dest0, Coordinate dest1) { Coordinate rotPt = new Coordinate(dest1.X - dest0.X, dest1.Y - dest0.Y); double ang = AngleUtility.AngleBetweenOriented(src1, src0, rotPt); double srcDist = src1.Distance(src0); double destDist = dest1.Distance(dest0); if (srcDist == 0.0) return null; double scale = destDist / srcDist; AffineTransformation trans = AffineTransformation.TranslationInstance( -src0.X, -src0.Y); trans.Rotate(ang); trans.Scale(scale, scale); trans.Translate(dest0.X, dest0.Y); return trans; }
/// <summary> /// Computes the closest points on a line segment. /// </summary> /// <param name="line"></param> /// <returns> /// A pair of Coordinates which are the closest points on the line segments. /// </returns> public virtual Coordinate[] ClosestPoints(ILineSegmentBase line) { LineSegment myLine = new LineSegment(line); // test for intersection Coordinate intPt = Intersection(line); if (intPt != null) return new[] { intPt, intPt }; /* * if no intersection closest pair contains at least one endpoint. * Test each endpoint in turn. */ Coordinate[] closestPt = new Coordinate[2]; Coordinate close00 = new Coordinate(ClosestPoint(line.P0)); double minDistance = close00.Distance(line.P0); closestPt[0] = close00; closestPt[1] = new Coordinate(line.P0); Coordinate close01 = new Coordinate(ClosestPoint(line.P1)); double dist = close01.Distance(line.P1); if (dist < minDistance) { minDistance = dist; closestPt[0] = close01; closestPt[1] = new Coordinate(line.P1); } Coordinate close10 = new Coordinate(myLine.ClosestPoint(P0)); dist = close10.Distance(P0); if (dist < minDistance) { minDistance = dist; closestPt[0] = new Coordinate(P0); closestPt[1] = close10; } Coordinate close11 = new Coordinate(myLine.ClosestPoint(P1)); dist = close11.Distance(P1); if (dist < minDistance) { closestPt[0] = new Coordinate(P1); closestPt[1] = close11; } return closestPt; }
/// <summary> /// Computes the distance from a point p to a line segment AB. /// Note: NON-ROBUST! /// </summary> /// <param name="p">The point to compute the distance for.</param> /// <param name="A">One point of the line.</param> /// <param name="B">Another point of the line (must be different to A).</param> /// <returns> The distance from p to line segment AB.</returns> public static double DistancePointLine(Coordinate p, Coordinate A, Coordinate B) { // if start = end, then just compute distance to one of the endpoints if (A.X == B.X && A.Y == B.Y) return p.Distance(A); // otherwise use comp.graphics.algorithms Frequently Asked Questions method /*(1) AC dot AB r = --------- ||AB||^2 r has the following meaning: r=0 Point = A r=1 Point = B r<0 Point is on the backward extension of AB r>1 Point is on the forward extension of AB 0<r<1 Point is interior to AB */ var len2 = ((B.X - A.X)*(B.X - A.X) + (B.Y - A.Y)*(B.Y - A.Y)); var r = ((p.X - A.X)*(B.X - A.X) + (p.Y - A.Y)*(B.Y - A.Y))/len2; if (r <= 0.0) return p.Distance(A); if (r >= 1.0) return p.Distance(B); /*(2) (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------- Curve^2 Then the distance from C to Point = |s|*Curve. This is the same calculation as {@link #distancePointLinePerpendicular}. Unrolled here for performance. */ var s = ((A.Y - p.Y)*(B.X - A.X) - (A.X - p.X)*(B.Y - A.Y))/len2; return Math.Abs(s) * Math.Sqrt(len2); }
/// <summary> /// Computes the distance from a point to a sequence of line segments. /// </summary> /// <param name="p">A point</param> /// <param name="line">A sequence of contiguous line segments defined by their vertices</param> /// <returns>The minimum distance between the point and the line segments</returns> /// <exception cref="ArgumentException">If there are too few points to make up a line (at least one?)</exception> public static double DistancePointLine(Coordinate p, Coordinate[] line) { if (line.Length == 0) throw new ArgumentException("Line array must contain at least one vertex"); // this handles the case of length = 1 double minDistance = p.Distance(line[0]); for (int i = 0; i < line.Length - 1; i++) { double dist = CGAlgorithms.DistancePointLine(p, line[i], line[i + 1]); if (dist < minDistance) { minDistance = dist; } } return minDistance; }
/// <summary> /// /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="tolerance"></param> /// <returns></returns> protected virtual bool Equal(Coordinate a, Coordinate b, double tolerance) { if (tolerance == 0) return a.Equals(b); return a.Distance(b) <= tolerance; }
public bool Equals(Coordinate p0, Coordinate p1, double distanceTolerance) { return p0.Distance(p1) <= distanceTolerance; }
/// <summary> /// Checks if the computed value for isInCircle is correct, using /// double-double precision arithmetic. /// </summary> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <param name="p">The point to test</param> private static void CheckRobustInCircle(Coordinate a, Coordinate b, Coordinate c, Coordinate p) { bool nonRobustInCircle = IsInCircleNonRobust(a, b, c, p); bool isInCircleDD = IsInCircleDDSlow(a, b, c, p); bool isInCircleCC = IsInCircleCC(a, b, c, p); Coordinate circumCentre = Triangle.Circumcentre(a, b, c); #if !PCL // ReSharper disable RedundantStringFormatCall // String.Format needed to build 2.0 release! Debug.WriteLine(String.Format("p radius diff a = {0}", Math.Abs(p.Distance(circumCentre) - a.Distance(circumCentre))/a.Distance(circumCentre))); if (nonRobustInCircle != isInCircleDD || nonRobustInCircle != isInCircleCC) { Debug.WriteLine(String.Format("inCircle robustness failure (double result = {0}, DD result = {1}, CC result = {2})", nonRobustInCircle, isInCircleDD, isInCircleCC)); Debug.WriteLine(WKTWriter.ToLineString(new CoordinateArraySequence(new[] { a, b, c, p }))); Debug.WriteLine(String.Format("Circumcentre = {0} radius = {1}", WKTWriter.ToPoint(circumCentre), a.Distance(circumCentre))); Debug.WriteLine(String.Format("p radius diff a = {0}", Math.Abs(p.Distance(circumCentre)/a.Distance(circumCentre) - 1))); Debug.WriteLine(String.Format("p radius diff b = {0}", Math.Abs(p.Distance(circumCentre)/b.Distance(circumCentre) - 1))); Debug.WriteLine(String.Format("p radius diff c = {0}", Math.Abs(p.Distance(circumCentre)/c.Distance(circumCentre) - 1))); Debug.WriteLine(""); } // ReSharper restore RedundantStringFormatCall #endif }
/// <summary> /// Computes the distance from a point p to a line segment AB. /// Note: NON-ROBUST! /// </summary> /// <param name="p">The point to compute the distance for.</param> /// <param name="A">One point of the line.</param> /// <param name="B">Another point of the line (must be different to A).</param> /// <returns> The distance from p to line segment AB.</returns> public static double DistancePointLine(Coordinate p, Coordinate A, Coordinate B) { // if start == end, then use pt distance if (A.Equals(B)) return p.Distance(A); // otherwise use comp.graphics.algorithms Frequently Asked Questions method /*(1) AC dot AB r = --------- ||AB||^2 r has the following meaning: r=0 Point = A r=1 Point = B r<0 Point is on the backward extension of AB r>1 Point is on the forward extension of AB 0<r<1 Point is interior to AB */ double r = ( (p.X - A.X) * (B.X - A.X) + (p.Y - A.Y) * (B.Y - A.Y) ) / ( (B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y) ); if (r <= 0.0) return p.Distance(A); if (r >= 1.0) return p.Distance(B); /*(2) (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------- Curve^2 Then the distance from C to Point = |s|*Curve. */ double s = ( (A.Y - p.Y) * (B.X - A.X) - (A.X - p.X) * (B.Y - A.Y) ) / ( (B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y) ); return Math.Abs(s) * Math.Sqrt(((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y))); }
///<summary>Computes the point at which the bisector of the angle ABC cuts the segment AC.</summary> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <returns>The angle bisector cut point</returns> public static Coordinate AngleBisector(Coordinate a, Coordinate b, Coordinate c) { /* * Uses the fact that the lengths of the parts of the split segment * are proportional to the lengths of the adjacent triangle sides */ double len0 = b.Distance(a); double len2 = b.Distance(c); double frac = len0 / (len0 + len2); double dx = c.X - a.X; double dy = c.Y - a.Y; Coordinate splitPt = new Coordinate(a.X + frac * dx, a.Y + frac * dy); return splitPt; }
/// <summary> /// Given the specified test point, this checks each segment, and will /// return the closest point on the specified segment. /// </summary> /// <param name="testPoint">The point to test.</param> /// <returns></returns> public override Coordinate ClosestPoint(Coordinate testPoint) { // For a point outside the polygon, it must be closer to the shell than // any holes. Coordinate closest = null; double dist = double.MaxValue; foreach (IGeometry geometry in Geometries) { Coordinate temp = geometry.ClosestPoint(testPoint); double tempDist = testPoint.Distance(temp); if (tempDist >= dist) continue; dist = tempDist; closest = temp; } return closest; }
/// <summary> /// Creates an AffineTransformation defined by a maping between two baselines. /// The computed transformation consists of: /// <list type="Bullet"> /// <item>a translation from the start point of the source baseline to the start point of the destination baseline,</item> /// <item>a rotation through the angle between the baselines about the destination start point,</item> /// <item>and a scaling equal to the ratio of the baseline lengths.</item> /// </list> /// If the source baseline has zero length, an identity transformation is returned. /// </summary> /// <param name="src0">The start point of the source baseline</param> /// <param name="src1">The end point of the source baseline</param> /// <param name="dest0">The start point of the destination baseline</param> /// <param name="dest1">The end point of the destination baseline</param> /// <returns></returns> public static AffineTransformation CreateFromBaseLines( Coordinate src0, Coordinate src1, Coordinate dest0, Coordinate dest1) { Coordinate rotPt = new Coordinate(src0.X + dest1.X - dest0.X, src0.Y + dest1.Y - dest0.Y); double ang = AngleUtility.AngleBetweenOriented(src1, src0, rotPt); double srcDist = src1.Distance(src0); double destDist = dest1.Distance(dest0); // return identity if transformation would be degenerate if (srcDist == 0.0) return new AffineTransformation(); double scale = destDist / srcDist; AffineTransformation trans = AffineTransformation.TranslationInstance( -src0.X, -src0.Y); trans.Rotate(ang); trans.Scale(scale, scale); trans.Translate(dest0.X, dest0.Y); return trans; }
private void CheckVertexDistance(Coordinate vertex) { double vertexDist = vertex.Distance(_queryPt); if (vertexDist > 0) { _smc.UpdateClearance(vertexDist, _queryPt, vertex); } }
/// <summary> /// /// </summary> /// <param name="pt"></param> /// <param name="snapPts"></param> /// <returns></returns> private Coordinate FindSnapForVertex(Coordinate pt, Coordinate[] snapPts) { foreach (Coordinate coord in snapPts) { // if point is already equal to a src pt, don't snap if (pt.Equals2D(coord)) return null; if (pt.Distance(coord) < _snapTolerance) return coord; } return null; }
private void DoMinimumBoundingCircleTest(String wkt, String expectedWKT, Coordinate expectedCentre, double expectedRadius) { MinimumBoundingCircle mbc = new MinimumBoundingCircle(reader.Read(wkt)); Coordinate[] exPts = mbc.GetExtremalPoints(); IGeometry actual = geometryFactory.CreateMultiPoint(exPts); double actualRadius = mbc.GetRadius(); Coordinate actualCentre = mbc.GetCentre(); Console.WriteLine(" Centre = " + actualCentre + " Radius = " + actualRadius); IGeometry expected = reader.Read(expectedWKT); bool isEqual = actual.Equals(expected); // need this hack because apparently equals does not work for MULTIPOINT EMPTY if (actual.IsEmpty && expected.IsEmpty) isEqual = true; if (!isEqual) { Console.WriteLine("Actual = " + actual + ", Expected = " + expected); } Assert.IsTrue(isEqual); if (expectedCentre != null) { Assert.IsTrue(expectedCentre.Distance(actualCentre) < TOLERANCE); } if (expectedRadius >= 0) { Assert.IsTrue(Math.Abs(expectedRadius - actualRadius) < TOLERANCE); } }
/// <summary> /// The original algorithm simply allows edges that have one defined point and /// another "NAN" point. Simply excluding the not a number coordinates fails /// to preserve the known direction of the ray. We only need to extend this /// long enough to encounter the bounding box, not infinity. /// </summary> /// <param name="graph">The VoronoiGraph with the edge list</param> /// <param name="bounds">The polygon bounding the datapoints</param> private static void HandleBoundaries(VoronoiGraph graph, IEnvelope bounds) { List<ILineString> boundSegments = new List<ILineString>(); List<VoronoiEdge> unboundEdges = new List<VoronoiEdge>(); // Identify bound edges for intersection testing foreach (VoronoiEdge edge in graph.Edges) { if(edge.VVertexA.ContainsNan() || edge.VVertexB.ContainsNan()) { unboundEdges.Add(edge); continue; } boundSegments.Add(new LineString(new List<Coordinate>{edge.VVertexA.ToCoordinate(), edge.VVertexB.ToCoordinate()})); } // calculate a length to extend a ray to look for intersections IEnvelope env = bounds; double h = env.Height; double w = env.Width; double len = Math.Sqrt(w * w + h * h); // len is now long enough to pass entirely through the dataset no matter where it starts foreach (VoronoiEdge edge in unboundEdges) { // the unbound line passes thorugh start Coordinate start = (edge.VVertexB.ContainsNan()) ? edge.VVertexA.ToCoordinate() : edge.VVertexB.ToCoordinate(); // the unbound line should have a direction normal to the line joining the left and right source points double dx = edge.LeftData.X - edge.RightData.X; double dy = edge.LeftData.Y - edge.RightData.Y; double l = Math.Sqrt(dx*dx + dy*dy); // the slope of the bisector between left and right double sx = -dy/l; double sy = dx/l; Coordinate center = bounds.Center(); if((start.X > center.X && start.Y > center.Y) || (start.X < center.X && start.Y < center.Y)) { sx = dy/l; sy = -dx/l; } Coordinate end1 = new Coordinate(start.X + len*sx, start.Y + len * sy); Coordinate end2 = new Coordinate(start.X - sx * len, start.Y - sy * len); Coordinate end = (end1.Distance(center) < end2.Distance(center)) ? end2 : end1; if(bounds.Contains(end)) { end = new Coordinate(start.X - sx * len, start.Y - sy * len); } if (edge.VVertexA.ContainsNan()) { edge.VVertexA = new Vector2(end.ToArray()); } else { edge.VVertexB = new Vector2(end.ToArray()); } } }
/// <summary> /// Given the specified test point, this checks each segment, and will /// return the closest point on the specified segment. /// </summary> /// <param name="testPoint">The point to test.</param> /// <returns></returns> public override Coordinate ClosestPoint(Coordinate testPoint) { Coordinate closest = Coordinate; double dist = double.MaxValue; for (int i = 0; i < _points.Count - 1; i++) { LineSegment s = new LineSegment(_points[i], _points[i + 1]); Coordinate temp = s.ClosestPoint(testPoint); double tempDist = testPoint.Distance(temp); if (tempDist < dist) { dist = tempDist; closest = temp; } } return closest; }
/// <summary> /// Checks if the computed value for isInCircle is correct, using /// double-double precision arithmetic. /// </summary> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <param name="p">The point to test</param> private static void CheckRobustInCircle(Coordinate a, Coordinate b, Coordinate c, Coordinate p) { bool nonRobustInCircle = IsInCircleNonRobust(a, b, c, p); bool isInCircleDD = IsInCircleDDSlow(a, b, c, p); bool isInCircleCC = IsInCircleCC(a, b, c, p); Coordinate circumCentre = Triangle.Circumcentre(a, b, c); System.Diagnostics.Debug.WriteLine("p radius diff a = " + Math.Abs(p.Distance(circumCentre) - a.Distance(circumCentre)) /a.Distance(circumCentre)); if (nonRobustInCircle != isInCircleDD || nonRobustInCircle != isInCircleCC) { System.Diagnostics.Debug.WriteLine("inCircle robustness failure (double result = " + nonRobustInCircle + ", DD result = " + isInCircleDD + ", CC result = " + isInCircleCC + ")"); System.Diagnostics.Debug.WriteLine(WKTWriter.ToLineString(new CoordinateArraySequence(new[] { a, b, c, p }))); System.Diagnostics.Debug.WriteLine("Circumcentre = " + WKTWriter.ToPoint(circumCentre) + " radius = " + a.Distance(circumCentre)); System.Diagnostics.Debug.WriteLine("p radius diff a = " + Math.Abs(p.Distance(circumCentre)/a.Distance(circumCentre) - 1)); System.Diagnostics.Debug.WriteLine("p radius diff b = " + Math.Abs(p.Distance(circumCentre)/b.Distance(circumCentre) - 1)); System.Diagnostics.Debug.WriteLine("p radius diff c = " + Math.Abs(p.Distance(circumCentre)/c.Distance(circumCentre) - 1)); System.Diagnostics.Debug.WriteLine(""); } }
///<summary>Computes the length of the longest side of a triangle</summary> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <returns>The length of the longest side of the triangle</returns> public static double LongestSideLength(Coordinate a, Coordinate b, Coordinate c) { // ReSharper disable InconsistentNaming double lenAB = a.Distance(b); double lenBC = b.Distance(c); double lenCA = c.Distance(a); // ReSharper restore InconsistentNaming double maxLen = lenAB; if (lenBC > maxLen) maxLen = lenBC; if (lenCA > maxLen) maxLen = lenCA; return maxLen; }
/// <summary> /// Given the specified test point, this checks each segment, and will /// return the closest point on the specified segment. /// </summary> /// <param name="testPoint">The point to test.</param> /// <returns></returns> public override Coordinate ClosestPoint(Coordinate testPoint) { // For a point outside the polygon, it must be closer to the shell than // any holes. if (Intersects(new Point(testPoint)) == false) { return _shell.ClosestPoint(testPoint); } Coordinate closest = _shell.ClosestPoint(testPoint); double dist = testPoint.Distance(closest); foreach (ILinearRing ring in Holes) { Coordinate temp = ring.ClosestPoint(testPoint); double tempDist = testPoint.Distance(temp); if (tempDist >= dist) continue; dist = tempDist; closest = temp; } return closest; }
// public static final String DEBUG_SEG_SPLIT = "C:\\proj\\CWB\\test\\segSplit.jml"; /// <summary> /// Given a set of points stored in the kd-tree and a line segment defined by /// two points in this set, finds a <see cref="Coordinate"/> in the circumcircle of /// the line segment, if one exists. This is called the Gabriel point - if none /// exists then the segment is said to have the Gabriel condition. Uses the /// heuristic of finding the non-Gabriel point closest to the midpoint of the /// segment. /// </summary> /// <param name="seg">the line segment</param> /// <returns> /// A point which is non-Gabriel, /// or null if no point is non-Gabriel /// </returns> private Coordinate FindNonGabrielPoint(Segment seg) { Coordinate p = seg.Start; Coordinate q = seg.End; // Find the mid point on the line and compute the radius of enclosing circle Coordinate midPt = new Coordinate((p.X + q.X) / 2.0, (p.Y + q.Y) / 2.0); double segRadius = p.Distance(midPt); // compute envelope of circumcircle Envelope env = new Envelope(midPt); env.ExpandBy(segRadius); // Find all points in envelope ICollection<KdNode<Vertex>> result = _kdt.Query(env); // For each point found, test if it falls strictly in the circle // find closest point Coordinate closestNonGabriel = null; double minDist = Double.MaxValue; foreach (KdNode<Vertex> nextNode in result) { Coordinate testPt = nextNode.Coordinate; // ignore segment endpoints if (testPt.Equals2D(p) || testPt.Equals2D(q)) continue; double testRadius = midPt.Distance(testPt); if (testRadius < segRadius) { // double testDist = seg.distance(testPt); double testDist = testRadius; if (closestNonGabriel == null || testDist < minDist) { closestNonGabriel = testPt; minDist = testDist; } } } return closestNonGabriel; }
///<summary> /// Computes the incentre of a triangle. ///</summary> /// <remarks> /// The <c>InCentre</c> of a triangle is the point which is equidistant /// from the sides of the triangle. /// It is also the point at which the bisectors of the triangle's angles meet. /// It is the centre of the triangle's <c>InCircle</c>, which is the unique circle /// that is tangent to each of the triangle's three sides. /// </remarks> /// <param name="a">A vertex of the triangle</param> /// <param name="b">A vertex of the triangle</param> /// <param name="c">A vertex of the triangle</param> /// <returns>The point which is the incentre of the triangle</returns> public static Coordinate InCentre(Coordinate a, Coordinate b, Coordinate c) { // the lengths of the sides, labelled by their opposite vertex double len0 = b.Distance(c); double len1 = a.Distance(c); double len2 = a.Distance(b); double circum = len0 + len1 + len2; double inCentreX = (len0 * a.X + len1 * b.X + len2 * c.X) / circum; double inCentreY = (len0 * a.Y + len1 * b.Y + len2 * c.Y) / circum; return new Coordinate(inCentreX, inCentreY); }