public static void general_intersections() { var line = new Line2(new Point2(2, 1), new Vector2(2, 1)); line.Intersects(new Point2(-2, -1)).Should().BeTrue(); line.Intersects(new Point2(0, 0)).Should().BeTrue(); line.Intersects(new Point2(1, 0.5)).Should().BeTrue(); line.Intersects(new Point2(2, 1)).Should().BeTrue(); line.Intersects(new Point2(4, 2)).Should().BeTrue(); line.Intersects(new Point2(1, 2)).Should().BeFalse(); }
public static void line_ray_basic_intersection_testing() { var a = new Line2(new Point2(3, 3), new Vector2(1, 1)); var b = new Ray2(new Point2(0, 1), new Vector2(0, 1)); var c = new Ray2(new Point2(2, 2), new Vector2(-1, -1)); var d = new Ray2(new Point2(2, 3), new Vector2(-1, -1)); a.Intersects(b.GetReverse()).Should().BeTrue(); a.Intersects(c).Should().BeTrue(); a.Intersects(c.GetReverse()).Should().BeTrue(); a.Intersects(b).Should().BeFalse(); a.Intersects(d).Should().BeFalse(); a.Intersects(d.GetReverse()).Should().BeFalse(); }
public static void line_line_basic_intersection_testing() { var a = new Line2(new Point2(3, 3), new Vector2(1, 1)); var b = new Line2(new Point2(0, 1), new Vector2(0, 1)); var c = new Line2(new Point2(2, 2), new Vector2(-1, -1)); var d = new Line2(new Point2(2, 3), new Vector2(-1, -1)); var e = new Line2(new Point2(2, 3), new Vector2(-2, -2)); var f = new Line2(new Point2(2, 3), new Vector2(0.5, 0.5)); a.Intersects(a).Should().BeTrue(); a.Intersects(b).Should().BeTrue(); a.Intersects(c).Should().BeTrue(); a.Intersects(d).Should().BeFalse(); a.Intersects(e).Should().BeFalse(); a.Intersects(f).Should().BeFalse(); }
private Circle2 FitCirleToThreePoints(IVector2 p1, IVector2 p2, IVector2 p3) { try { double x1 = (p1.X + p2.X) / 2.0; double y1 = (p1.Y + p2.Y) / 2.0; double dy1 = p2.X - p1.X; double dx1 = -1 * (p2.Y - p1.Y); double x2 = (p3.X + p2.X) / 2.0; double y2 = (p3.Y + p2.Y) / 2.0; double dy2 = p3.X - p2.X; double dx2 = -1 * (p3.Y - p2.Y); var line1 = new Line2(new Vector2(x1, y1), new Vector2(x1 + dx1, y1 + dy1)); var line2 = new Line2(new Vector2(x2, y2), new Vector2(x2 + dx2, y2 + dy2)); var intersection = line1.Intersects(line2); if (!(intersection.Intersects)) { throw new Exception("Points are colinear, Couldn't find arc"); } else { var center = new Vector2(intersection.Point.X, intersection.Point.Y); var dx = center.X - p1.X; var dy = center.Y - p1.Y; var r = Math.Sqrt(dx * dx + dy * dy); if (double.IsNaN(center.X) || double.IsNaN(center.Y) || double.IsNaN(r)) { throw new ArgumentException("Unable to calculate center or radius of fitting circle"); } return(new Circle2(center, r)); } } catch (Exception) { throw; } }
/// <summary> /// Draws the area between two curves using the provided color. /// </summary> /// <param name="curves">Curves to draw within the currently set range.</param> /// <param name="color">Color to draw the area with.</param> private void DrawCurveRange(EdAnimationCurve[] curves, Color color) { float range = GetRange(true); if (curves.Length != 2 || curves[0] == null || curves[1] == null) { return; } KeyFrame[][] keyframes = { curves[0].KeyFrames, curves[1].KeyFrames }; if (keyframes[0].Length <= 0 || keyframes[1].Length <= 0) { return; } int numSamples = (drawableWidth + LINE_SPLIT_WIDTH - 1) / LINE_SPLIT_WIDTH; float timePerSample = range / numSamples; float time = rangeOffset; float lengthPerPixel = rangeLength / drawableWidth; time -= lengthPerPixel * PADDING; int[] keyframeIndices = { 0, 0 }; // Find first valid keyframe indices for (int curveIdx = 0; curveIdx < 2; curveIdx++) { keyframeIndices[curveIdx] = keyframes[curveIdx].Length; for (int i = 0; i < keyframes[curveIdx].Length; i++) { if (keyframes[curveIdx][i].time > time) { keyframeIndices[curveIdx] = i; } } } List <float> times = new List <float>(); List <float>[] points = { new List <float>(), new List <float>() }; // Determine start points for (int curveIdx = 0; curveIdx < 2; curveIdx++) { float value = curves[curveIdx].Evaluate(time, false); points[curveIdx].Add(value); } times.Add(time); float rangeEnd = rangeOffset + range; while (time < rangeEnd) { float nextTime = time + timePerSample; bool hasStep = false; // Determine time to sample at. Use fixed increments unless there's a step keyframe within our increment in // which case we use its time so we can evaluate it directly for (int curveIdx = 0; curveIdx < 2; curveIdx++) { int keyframeIdx = keyframeIndices[curveIdx]; if (keyframeIdx < keyframes[curveIdx].Length) { KeyFrame keyframe = keyframes[curveIdx][keyframeIdx]; bool isStep = keyframe.inTangent == float.PositiveInfinity || keyframe.outTangent == float.PositiveInfinity; if (isStep && keyframe.time <= nextTime) { nextTime = Math.Min(nextTime, keyframe.time); hasStep = true; } } } // Evaluate if (hasStep) { for (int curveIdx = 0; curveIdx < 2; curveIdx++) { int keyframeIdx = keyframeIndices[curveIdx]; if (keyframeIdx < keyframes[curveIdx].Length) { KeyFrame keyframe = keyframes[curveIdx][keyframeIdx]; if (MathEx.ApproxEquals(keyframe.time, nextTime)) { if (keyframeIdx > 0) { KeyFrame prevKeyframe = keyframes[curveIdx][keyframeIdx - 1]; points[curveIdx].Add(prevKeyframe.value); } else { points[curveIdx].Add(keyframe.value); } points[curveIdx].Add(keyframe.value); } else { // The other curve has step but this one doesn't, we just insert the same value twice float value = curves[curveIdx].Evaluate(nextTime, false); points[curveIdx].Add(value); points[curveIdx].Add(value); } times.Add(nextTime); times.Add(nextTime); } } } else { for (int curveIdx = 0; curveIdx < 2; curveIdx++) { points[curveIdx].Add(curves[curveIdx].Evaluate(nextTime, false)); } times.Add(nextTime); } // Advance keyframe indices for (int curveIdx = 0; curveIdx < 2; curveIdx++) { int keyframeIdx = keyframeIndices[curveIdx]; while (keyframeIdx < keyframes[curveIdx].Length) { KeyFrame keyframe = keyframes[curveIdx][keyframeIdx]; if (keyframe.time > nextTime) { break; } keyframeIdx = ++keyframeIndices[curveIdx]; } } time = nextTime; } // End points for (int curveIdx = 0; curveIdx < 2; curveIdx++) { float value = curves[curveIdx].Evaluate(rangeEnd, false); points[curveIdx].Add(value); } times.Add(rangeEnd); int numQuads = times.Count - 1; List <Vector2I> vertices = new List <Vector2I>(); for (int i = 0; i < numQuads; i++) { int idxLeft = points[0][i] < points[1][i] ? 0 : 1; int idxRight = points[0][i + 1] < points[1][i + 1] ? 0 : 1; Vector2[] left = { new Vector2(times[i], points[0][i]), new Vector2(times[i], points[1][i]) }; Vector2[] right = { new Vector2(times[i + 1], points[0][i + 1]), new Vector2(times[i + 1], points[1][i + 1]) }; if (idxLeft == idxRight) { int idxA = idxLeft; int idxB = (idxLeft + 1) % 2; vertices.Add(CurveToPixelSpace(left[idxB])); vertices.Add(CurveToPixelSpace(right[idxB])); vertices.Add(CurveToPixelSpace(left[idxA])); vertices.Add(CurveToPixelSpace(right[idxB])); vertices.Add(CurveToPixelSpace(right[idxA])); vertices.Add(CurveToPixelSpace(left[idxA])); } // Lines intersects, can't represent them with a single quad else if (idxLeft != idxRight) { int idxA = idxLeft; int idxB = (idxLeft + 1) % 2; Line2 lineA = new Line2(left[idxB], right[idxA] - left[idxB]); Line2 lineB = new Line2(left[idxA], right[idxB] - left[idxA]); if (lineA.Intersects(lineB, out var t)) { Vector2 intersection = left[idxB] + t * (right[idxA] - left[idxB]); vertices.Add(CurveToPixelSpace(left[idxB])); vertices.Add(CurveToPixelSpace(intersection)); vertices.Add(CurveToPixelSpace(left[idxA])); vertices.Add(CurveToPixelSpace(intersection)); vertices.Add(CurveToPixelSpace(right[idxB])); vertices.Add(CurveToPixelSpace(right[idxA])); } } } canvas.DrawTriangleList(vertices.ToArray(), color, 129); }
private static List <Triangle> Cut(Triangle tri, Line3 line) { // Create coordinate system Vec3 norm = tri.Normal; Vec3 xaxis = tri.Edge13.Normalized; Vec3 yaxis = Vec3.Cross(norm, xaxis); // Convert to 2d space Vec2 v1 = Vec2.Zero; // Consider point 0 the origin Vec2 v2 = Collapse(tri.Item2 - tri.Item1, xaxis, yaxis); // Relative position of Item2 Vec2 v3 = Collapse(tri.Item3 - tri.Item1, xaxis, yaxis); // Relative position of Item3 Vec2 ls = Collapse(line.Item1 - tri.Item1, xaxis, yaxis); Vec2 le = Collapse(line.Item2 - tri.Item1, xaxis, yaxis); Line2 l12 = new Line2(v1, v2); Line2 l13 = new Line2(v1, v3); Line2 l23 = new Line2(v2, v3); Line2 cut = new Line2(ls, le); // Perform intersection test double k12, k13, k23; double c12, c13, c23; bool i12 = l12.Intersects(cut, out c12, out k12); bool i13 = l13.Intersects(cut, out c13, out k13); bool i23 = l23.Intersects(cut, out c23, out k23); // Check cases List <Triangle> tris = new List <Triangle>(); // Corner - Edge intersection (3 cases) if (IsCorner(c12, c13) && IsEdge(c23)) { // Crossing from corner 1 to edge 2->3 Vec3 midpoint = Vec3.Lerp(tri.Item2, tri.Item3, c23); tris.Add(new Triangle(tri.Item1, tri.Item2, midpoint)); tris.Add(new Triangle(tri.Item1, midpoint, tri.Item3)); return(tris); } else if (IsCorner(c13, c23) && IsEdge(c12)) { // Crossing from corner 3 to edge 1->2 Vec3 midpoint = Vec3.Lerp(tri.Item1, tri.Item2, c12); tris.Add(new Triangle(tri.Item1, midpoint, tri.Item3)); tris.Add(new Triangle(midpoint, tri.Item2, tri.Item3)); return(tris); } else if (IsCorner(c12, c23) && IsEdge(c13)) { // Crossing from corner 2 to edge 1->3 Vec3 midpoint = Vec3.Lerp(tri.Item1, tri.Item3, c13); tris.Add(new Triangle(tri.Item1, tri.Item2, midpoint)); tris.Add(new Triangle(midpoint, tri.Item2, tri.Item3)); return(tris); } // Edge - Edge intersection (3 cases) else if (IsEdge(c12) && IsEdge(c23)) { // Collision crossing 1->2, 2->3 Vec3 m1 = Vec3.Lerp(tri.Item1, tri.Item2, c12); Vec3 m2 = Vec3.Lerp(tri.Item2, tri.Item3, c23); Vec3 mid = (tri.Item1 + tri.Item3) / 2; tris.Add(new Triangle(tri.Item1, m1, mid)); tris.Add(new Triangle(m1, m2, mid)); tris.Add(new Triangle(mid, m2, tri.Item3)); tris.Add(new Triangle(m1, tri.Item2, m2)); return(tris); } else if (IsEdge(c12) && IsEdge(c13)) { // Collision crossing 1->3, 1->2 Vec3 m1 = Vec3.Lerp(tri.Item1, tri.Item2, c12); Vec3 m2 = Vec3.Lerp(tri.Item1, tri.Item3, c13); Vec3 mid = (tri.Item2 + tri.Item3) / 2; tris.Add(new Triangle(m1, tri.Item2, mid)); tris.Add(new Triangle(m1, mid, m2)); tris.Add(new Triangle(m2, mid, tri.Item3)); tris.Add(new Triangle(tri.Item1, m1, m2)); return(tris); } else if (IsEdge(c13) && IsEdge(c23)) { // Collision crossing 1->3, 2->3 Vec3 m1 = Vec3.Lerp(tri.Item1, tri.Item3, c13); Vec3 m2 = Vec3.Lerp(tri.Item2, tri.Item3, c23); Vec3 mid = (tri.Item1 + tri.Item2) / 2; tris.Add(new Triangle(mid, tri.Item2, m2)); tris.Add(new Triangle(mid, m2, m1)); tris.Add(new Triangle(tri.Item1, mid, m1)); tris.Add(new Triangle(m1, m2, tri.Item3)); return(tris); } // No intersection (1 case) else { tris.Add(tri); return(tris); } }