private static void RenderVisualizationFrame() { var segments = Util.Generate(200, RandomSegment); // var quad = new[] { new IntVector2(100, 100), new IntVector2(200, 200), new IntVector2(300, 300), new IntVector2(400, 400) }; var quad = Util.Generate(4, RandomPoint); var hull = GeometryOperations.ConvexHull4(quad[0], quad[1], quad[2], quad[3]); var canvas = host.CreateAndAddCanvas(frameCounter++); canvas.BatchDraw(() => { foreach (var(x, y) in quad.Zip(quad.RotateLeft())) { canvas.DrawLine(x, y, StrokeStyle.BlackHairLineDashed5); } foreach (var(x, y) in hull.Zip(hull.RotateLeft())) { canvas.DrawLine(x, y, StrokeStyle.BlackHairLineSolid); } foreach (var p in hull) { canvas.DrawPoint(p, StrokeStyle.RedThick5Solid); } foreach (var s in segments) { canvas.DrawLine(s.First, s.Second, GeometryOperations.SegmentIntersectsConvexPolygonInterior(s, hull) ? StrokeStyle.LimeHairLineDashed5 : StrokeStyle.RedHairLineDashed5); } }); }
// Todo: Can we support DV2s? public int[] AddMany(DoubleLineSegment2 edgeSegment, IntVector2[] points) { Interlocked.Increment(ref AddManyInvocationCount); // return points.Map(p => 0); var segmentSeeingWaypoints = landPolyNode.ComputeSegmentSeeingWaypoints(edgeSegment); // It's safe to assume <some> point in points will be new, so preprocess which segments are betwen us and other edge segments var barriers = landPolyNode.FindContourAndChildHoleBarriers(); Dictionary <DoubleLineSegment2, IntLineSegment2[]> barriersBySegment = indicesBySegment.Map((s, _) => { Interlocked.Increment(ref AddManyConvexHullsComputed); var hull = GeometryOperations.ConvexHull4(s.First, s.Second, edgeSegment.First, edgeSegment.Second); return(barriers.Where(b => { var barrierDv2 = new DoubleLineSegment2(b.First.ToDoubleVector2(), b.Second.ToDoubleVector2()); return GeometryOperations.SegmentIntersectsConvexPolygonInterior(barrierDv2, hull); }).ToArray()); }); return(indicesBySegment[edgeSegment] = points.Map(p => { if (TryAdd(p, out var cpi)) { Interlocked.Increment(ref CrossoverPointsAdded); segmentByCrossoverPoint[p] = edgeSegment; } return cpi; })); bool TryAdd(IntVector2 crossoverPoint, out int crossoverPointIndex) { if (!crossoverPoints.TryAdd(crossoverPoint, out crossoverPointIndex)) { return(false); } var(visibleWaypointLinks, visibleWaypointLinksLength, optimalLinkToWaypoints, optimalLinkToCrossovers) = FindOptimalLinksToCrossovers(crossoverPoint, segmentSeeingWaypoints, barriersBySegment); // visibleWaypointLinksByCrossoverPointIndex.Add(visibleWaypointLinks); optimalLinkToWaypointsByCrossoverPointIndex.Add(optimalLinkToWaypoints); optimalLinkToOtherCrossoversByCrossoverPointIndex.Add(optimalLinkToCrossovers); Trace.Assert(optimalLinkToOtherCrossoversByCrossoverPointIndex.Count == optimalLinkToCrossovers.Count); for (var otherCpi = 0; otherCpi < crossoverPoints.Count - 1; otherCpi++) { var linkToOther = optimalLinkToCrossovers[otherCpi]; var linkFromOther = linkToOther.PriorIndex < 0 ? new PathLink { PriorIndex = linkToOther.PriorIndex, TotalCost = linkToOther.TotalCost } : new PathLink { PriorIndex = optimalLinkToWaypointsByCrossoverPointIndex[otherCpi][linkToOther.PriorIndex].PriorIndex, TotalCost = linkToOther.TotalCost }; optimalLinkToOtherCrossoversByCrossoverPointIndex[otherCpi].Add(linkFromOther); } return(true); } }
private static void Benchmark() { var segments = Util.Generate(100000, RandomSegment); var quad = Util.Generate(4, RandomPoint); var hull = GeometryOperations.ConvexHull(quad); var sw = new Stopwatch(); sw.Start(); const int niters = 100; for (var i = 0; i < niters; i++) { for (var j = 0; j < segments.Length; j++) { GeometryOperations.SegmentIntersectsConvexPolygonInterior(segments[j], hull); } } Console.WriteLine(sw.Elapsed.TotalMilliseconds / niters); }