/// <summary> /// Find the point of intersection of an arc and a line /// </summary> /// <param name="other">The line to find intersection with</param> /// <returns>[x, y] if applicable; [] otherwise</returns> private double[] ArcLineIntersection(LineSegment other) { double x1, x2, x3, y1, y2, y3, a, b, c, det, u, t; int numof_int = 0; x1 = (double)other.StartPoint.X; y1 = (double)other.StartPoint.Y; x2 = (double)other.EndPoint.X; y2 = (double)other.EndPoint.Y; x3 = (double)centerPoint.X; y3 = (double)centerPoint.Y; a = Math.Pow(x2 - x1, 2.0) + Math.Pow(y2 - y1, 2.0); b = 2 * ((x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3)); c = Math.Pow(x3, 2.0) + Math.Pow(y3, 2.0) + Math.Pow(x1, 2.0) + Math.Pow(y1, 2.0) - 2 * (x3 * x1 + y3 * y1) - Math.Pow(radius, 2.0); if (a == 0.0) { return(new double[0]); } det = Math.Pow(b, 2.0) - 4 * a * c; if (det < 0.0) { return(new double[0]); //no intersection } else if (det == 0.0) //one intersection { u = (-b) / 2.0 / a; if (u > (1 + INTERSECTION_TOLERANCE_PERCENTAGE) || u < (0 - INTERSECTION_TOLERANCE_PERCENTAGE)) { return(new double[0]); } float x = (float)(x1 + u * (x2 - x1)); float y = (float)(y1 + u * (y2 - y1)); double[] intPt = new double[] { x, y }; double theta = Math.Atan2(intPt[1] - centerPoint.Y, intPt[0] - centerPoint.X) * 180 / Math.PI; double endAngle = startAngle + sweepAngle; if (sweepAngle > 0) { t = (theta - startAngle) / (endAngle - startAngle); } else { t = -(theta - startAngle) / (endAngle - startAngle); } } else //two intersections { u = (-b - Math.Sqrt(det)) / 2.0 / a; if (!(u > (1 + INTERSECTION_TOLERANCE_PERCENTAGE) || u < (0 - INTERSECTION_TOLERANCE_PERCENTAGE))) { //intP1.x = x1 + u * (x2 - x1); //intP1.y = y1 + u * (y2 - y1); numof_int++; } u = (-b + Math.Sqrt(det)) / 2.0 / a; if (!(u > (1 + INTERSECTION_TOLERANCE_PERCENTAGE) || u < (0 - INTERSECTION_TOLERANCE_PERCENTAGE))) { //intP2.x = x1 + u * (x2 - x1); //intP2.y = y1 + u * (y2 - y1); numof_int++; //if (numof_int == 1) intP1 = intP2; } } return(new double[2]); }
private double[] lineIntersects(LineSegment other) { return(lineIntersects(other, 0.0d)); }
/// <summary> /// Near-intersection /// </summary> /// <param name="other"></param> /// <returns></returns> public double[] nearIntersection(LineSegment other) { return(lineIntersects(other, 25)); }
/// <summary> /// Takes a wire and returns the shape that is closest to the end of the wire /// along the line shooting off of the end. /// </summary> /// <param name="beginning">Which end we're looking at.</param> /// <param name="wire">The wire we're considering.</param> /// <param name="sketch">The sketch providing the context for the wire.</param> /// <returns>The shape that's closest to the tip of the wire.</returns> private Sketch.Shape findClosest(bool beginning, Sketch.Substroke wire, Sketch.Sketch sketch) { List <Sketch.Substroke> intersects = new List <Sketch.Substroke>(); // One method of removing hooks (in situations where the substroke loops around to // get closer to its endpoint. List <Sketch.Point> points = Featurefy.Compute.DeHook(wire).PointsL; points.Sort(); if (!beginning) { points.Reverse(); } // First we will generate the line segments shooting off the endpoints of the wires. Sketch.LineSegment segment1; int count = 20; if (points.Count < 2 * count) { segment1 = new Sketch.LineSegment(points[0], points[points.Count - 1]); } else { segment1 = new Sketch.LineSegment(points.GetRange(0, count).ToArray()); } Sketch.Substroke closestSubstroke = null; Sketch.Substroke closestLinestroke = null; double closestSubstrokeDistance = Double.PositiveInfinity; double closestLineDistance = Double.PositiveInfinity; // Now, consider every substroke in the sketch. foreach (Sketch.Substroke substroke in sketch.SubstrokesL) { if (substroke.Id != wire.Id) { // We want this stroke if it is close to the line shooting out of the end of the wire // Or if it is close enough to the endpoint. foreach (Sketch.Point point in substroke.Points) { double linedistance = point.distance(segment1.getClosestPointOnLine(point)); double pointdistance = point.distance(points[0]); if (pointdistance < closestSubstrokeDistance) { closestSubstrokeDistance = point.distance(points[0]); closestSubstroke = substroke; } if (2 * linedistance + pointdistance < closestLineDistance) { // We want to make sure it's on the correct side of the line. Sketch.Point linepoint = segment1.getClosestPointOnLine(point); if ((segment1.StartPoint.X < segment1.EndPoint.X && linepoint.X < segment1.StartPoint.X) || (segment1.StartPoint.X > segment1.EndPoint.X && linepoint.X > segment1.StartPoint.X)) { closestLineDistance = 2 * linedistance + pointdistance; closestLinestroke = substroke; } } } } } // Returning the right substroke: double thresholdLineDistance = 50.0; // MAGIC NUMBER! A somewhat arbitrary number pulled out of the air. double thresholdSubstrokeDistance = 20.0; // MAGIC NUMBER! A somewhat arbitrary number pulled out of the air. // The threshold is stricter on substrokes that are nearby but // are not in the right direction // Substrokes that are close to the projected line get priority. if ((closestLineDistance < thresholdLineDistance) && (closestLinestroke != null) && (closestLinestroke.ParentShape != null)) { return(closestLinestroke.ParentShape); } // If the Linestroke wasn't good enough, try the closest substroke. else if ((closestSubstrokeDistance < thresholdSubstrokeDistance) && (closestSubstroke != null) && (closestSubstroke.ParentShape != null)) { return(closestSubstroke.ParentShape); } // We get here if none of the substrokes were close enough else { return(null); } //// Now we need to decide whether we want the closest substroke, or the one closest to the line... //if (closestLineDistance / 5 > closestSubstrokeDistance) // if (closestSubstroke == null) // return null; // else // return closestSubstroke.ParentShapes[0]; //else // if (closestLinestroke == null) // return null; // else // return closestLinestroke.ParentShapes[0]; }