public static IEnumerable<(PolyNode, double)> X(IntLineSegment2 seg, LocalGeometryView lgv) { var punchedLand = lgv.PunchedLand; punchedLand.AssertIsContourlessRootHolePunchResult(); var allBreakpoints = new SortedList<double, List<(PolyNode, double)>>(); foreach (var polyNode in punchedLand.EnumerateLandNodes()) { XVisitLandPolyNode(seg, polyNode, allBreakpoints); } var res = new List<(PolyNode, double)>(); foreach (var x in allBreakpoints.Values) { res.AddRange(x); } // allBreakpoints.SelectMany(kvp => kvp.Value.Item2.Select(t => (kvp.Value.Item1, t))).ToList(); return res; // // TODO: Fix this hack. Eventually. Maybe never. Possibly. // // // Trace.Assert(breakpoints.Count % 2 == 0); // return breakpoints.Select(kvp => (kvp.Value, kvp.Key)); // // var it = breakpoints.GetEnumerator(); // while (it.MoveNext()) { // var bp0 = it.Current; // Trace.Assert(it.MoveNext()); // var bp1 = it.Current; // yield return (landPolyNodeBoundedByPolyNodeContour[bp0.Value], bp0.Key, bp1.Key); // } }
/// <summary> /// A line segment S is contained within a polynode P if it is contained in /// P's contour (no points are outside contour) and none of P's child contours. /// /// Note: Given a triangle-shaped land node. A line segment containing one of its edges /// (or a segment contained within that edge) would normally be counted as a part of the /// interior. For simplicity reasons, this is the case here; however, a sub-segment of /// that edge will not be counted as a part of the interior. We don't handle the sub-segment /// case because that'd be done imprecisely anyway (we're dealing with int line segments) /// </summary> public static bool SegmentInLandPolygonNonrecursive(this PolyNode landNode, IntLineSegment2 query) { var segmentContainment = landNode.SegmentInPolygon(query); switch (segmentContainment) { case PolygonContainmentResult.OutsidePolygon: case PolygonContainmentResult.IntersectsPolygon: return(false); case PolygonContainmentResult.OnPolygon: return(true); case PolygonContainmentResult.InPolygon: foreach (var child in landNode.Childs) { var childContainment = child.SegmentInPolygon(query); if (childContainment == PolygonContainmentResult.OutsidePolygon || childContainment == PolygonContainmentResult.OnPolygon) { continue; } return(false); } return(true); default: throw new Exception("Invalid State"); } }
public List <BvhILS2> FindPotentiallyIntersectingLeaves(IntLineSegment2 seg) { var res = new List <BvhILS2>(); FindPotentiallyIntersectingLeavesInternal(ref seg, res); return(res); }
public void C() { var localGeometryView = BuildLgv(SectorMetadataPresets.Blank2D, 14, BuildRectangleHole(-664, 133, 174, 188)); var seg = new IntLineSegment2(new IntVector2(0, 600), new IntVector2(0, 800)); DebugRenderLocalGeometryView(localGeometryView, seg); var results = PortalSectorEdgeDescription.X(seg, localGeometryView).ToArray(); Assert.Equal(2, results.Length); }
public void F() { var localGeometryView = BuildLgv( SectorMetadataPresets.HashCircle2, 0 ); var seg = new IntLineSegment2(new IntVector2(-2, 620), new IntVector2(-2, 780)); var results = PortalSectorEdgeDescription.X(seg, localGeometryView).ToArray(); DebugRenderLocalGeometryView(localGeometryView, seg); Assert.Equal(results.Map(x => x.Item2), new[] { 0.0, 1.0 }); }
public void D() { var localGeometryView = BuildLgv( SectorMetadataPresets.Blank2D, 14, BuildRectangleHole(-517, 107, 5, 5, 4607552631852924299), BuildRectangleHole(-506, 100, 6, 7, 4613867344244209246), BuildRectangleHole(-505, 136, 6, 7, 4615794974257582119) ); var seg = new IntLineSegment2(new IntVector2(0, 600), new IntVector2(0, 800)); var results = PortalSectorEdgeDescription.X(seg, localGeometryView).ToArray(); DebugRenderLocalGeometryView(localGeometryView, seg); Assert.Equal(2, results.Length); }
private void FindPotentiallyIntersectingLeavesInternal(ref IntLineSegment2 seg, List <BvhILS2> results) { if (!Bounds.ContainsOrIntersects(ref seg)) { return; } if (First != null) { First.FindPotentiallyIntersectingLeavesInternal(ref seg, results); Second.FindPotentiallyIntersectingLeavesInternal(ref seg, results); } else { results.Add(this); } }
private static (DoubleVector2, IntLineSegment2[]) RandomInput() { var segments = new IntLineSegment2[1000]; for (var i = 0; i < segments.Length; i++) { var s = RandomSegment(); if (segments.Take(i).Any(s.Intersects)) { continue; } segments[i] = s; } var p = RandomPoint(); return(p.ToDoubleVector2(), segments); }
public static PortalSectorEdgeDescription Build( SectorNodeDescription source, SectorNodeDescription destination, IntLineSegment2 sourceSegment, Clockness sourceInClockness, IntLineSegment2 destinationSegment, Clockness destinationInClockness ) { return new PortalSectorEdgeDescription { Source = source, Destination = destination, SourceSegment = sourceSegment, SourceInClockness = sourceInClockness, DestinationSegment = destinationSegment, DestinationInClockness = destinationInClockness }; }
public bool ContainsOrIntersects(ref IntLineSegment2 segment) { var tl = GeometryOperations.Clockness(segment.X1, segment.Y1, segment.X2, segment.Y2, Left, Top); var tr = GeometryOperations.Clockness(segment.X1, segment.Y1, segment.X2, segment.Y2, Right, Top); var bl = GeometryOperations.Clockness(segment.X1, segment.Y1, segment.X2, segment.Y2, Left, Bottom); var br = GeometryOperations.Clockness(segment.X1, segment.Y1, segment.X2, segment.Y2, Right, Bottom); // If all on same side (and assuming assume not all collinear), then not intersecting! if (tl == tr && tr == bl && bl == br && br != Clockness.Neither) { return(false); } // Some point (or cross-sectional segment!) of rect intersects with line formed by segment return((segment.X1 >= Left || segment.X2 >= Left) && (segment.X1 <= Right || segment.X2 <= Right) && (segment.Y1 >= Top || segment.Y2 >= Top) && (segment.Y1 <= Bottom || segment.Y2 <= Bottom)); }
public bool Intersects(ref IntLineSegment2 segment) { if (!Bounds.ContainsOrIntersects(ref segment)) { return(false); } if (First != null) { return(First.Intersects(ref segment) || Second.Intersects(ref segment)); } for (var i = SegmentsStartIndexInclusive; i < SegmentsEndIndexExclusive; i++) { if (Segments[i].Intersects(ref segment)) { return(true); } } return(false); }
public bool TryIntersect(ref IntLineSegment2 segment, out DoubleVector2 p) { if (!Bounds.ContainsOrIntersects(ref segment)) { p = default(DoubleVector2); return(false); } if (First != null) { return(First.TryIntersect(ref segment, out p) || Second.TryIntersect(ref segment, out p)); } for (var i = SegmentsStartIndexInclusive; i < SegmentsEndIndexExclusive; i++) { if (GeometryOperations.TryFindSegmentSegmentIntersection(ref Segments[i], ref segment, out p)) { return(true); } } p = default(DoubleVector2); return(false); }
public static void LoadMeshAsMap(this TerrainService terrainService, string objPath, DoubleVector3 meshOffset, DoubleVector3 worldOffset, int scaling = 50000) { Environment.CurrentDirectory = @"V:\my-repositories\miyu\derp\OpenMOBA.DevTool\bin\Debug\net461"; var lines = File.ReadLines(objPath); var verts = new List <DoubleVector3>(); var previousEdges = new Dictionary <(int, int), (SectorNodeDescription, IntLineSegment2)>(); void Herp(SectorNodeDescription node, int a, int b, IntLineSegment2 seg) { if (a > b) { (a, b) = (b, a); // a < b seg = new IntLineSegment2(seg.Second, seg.First); } if (previousEdges.TryGetValue((a, b), out var prev)) { var(prevNode, prevSeg) = prev; throw new NotImplementedException("Need clockness"); //terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build(node, prevNode, seg, prevSeg)); //terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build(prevNode, node, prevSeg, seg)); }
private LocalGeometryView BuildLgv(TerrainStaticMetadata mapStaticMetadata, double holeDilationRadius, params IHoleStaticMetadata[] holeMetadatas) { var store = new SectorGraphDescriptionStore(); var terrainService = new TerrainService(store, new TerrainSnapshotCompiler(store)); var sector = terrainService.CreateSectorNodeDescription(mapStaticMetadata); sector.WorldTransform = Matrix4x4.Multiply(Matrix4x4.CreateScale(1), Matrix4x4.CreateTranslation(-500, -500, 0)); terrainService.AddSectorNodeDescription(sector); var left2 = new IntLineSegment2(new IntVector2(0, 600), new IntVector2(0, 800)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build(sector, sector, left2, left2)); foreach (var holeMetadata in holeMetadatas) { var terrainHole = terrainService.CreateHoleDescription(holeMetadata); terrainService.AddTemporaryHoleDescription(terrainHole); } var terrainOverlayNetwork = terrainService.CompileSnapshot().OverlayNetworkManager.CompileTerrainOverlayNetwork(holeDilationRadius); return(terrainOverlayNetwork.TerrainNodes.First().LocalGeometryView); }
private static IntLineSegment3 ToILS3(IntLineSegment2 p) => new IntLineSegment3(ToIV3(p.First), ToIV3(p.Second));
public static void Main(string[] args) { var sectorGraphDescriptionStore = new SectorGraphDescriptionStore(); var snapshotCompiler = new TerrainSnapshotCompiler(sectorGraphDescriptionStore); var terrainService = new TerrainService(sectorGraphDescriptionStore, snapshotCompiler); // Add test sectors var leftSnd = terrainService.CreateSectorNodeDescription(SectorMetadataPresets.HashCircle2); // leftSnd.EnableDebugHighlight = true; leftSnd.WorldTransform = Matrix4x4.CreateScale(1000.0f / 60000.0f) * Matrix4x4.CreateTranslation(-1000, 0, 0); terrainService.AddSectorNodeDescription(leftSnd); var centerSnd = terrainService.CreateSectorNodeDescription(SectorMetadataPresets.Blank2D); centerSnd.EnableDebugHighlight = true; centerSnd.WorldTransform = Matrix4x4.CreateScale(1000.0f / 60000.0f); terrainService.AddSectorNodeDescription(centerSnd); /*+ [0] {(-30000, -18000)} OpenMOBA.Geometry.IntVector2 + [1] {(-30000, -6000)} OpenMOBA.Geometry.IntVector2 + [2] {(-6000, -6000)} OpenMOBA.Geometry.IntVector2 + [3] {(-6000, -18000)} OpenMOBA.Geometry.IntVector2 + [4] {(-30000, -18000)} OpenMOBA.Geometry.IntVector2 */ var rightSnd = terrainService.CreateSectorNodeDescription(SectorMetadataPresets.HashCircle2); rightSnd.WorldTransform = Matrix4x4.CreateScale(1000.0f / 60000.0f) * Matrix4x4.CreateTranslation(1000, 0, 0); terrainService.AddSectorNodeDescription(rightSnd); // edges between test sectors var rightTopSegment = new IntLineSegment2(new IntVector2(30000, 6000), new IntVector2(30000, 18000)); var leftTopSegment = new IntLineSegment2(new IntVector2(-30000, 6000), new IntVector2(-30000, 18000)); var rightBottomSegment = new IntLineSegment2(new IntVector2(30000, -18000), new IntVector2(30000, -6000)); var leftBottomSegment = new IntLineSegment2(new IntVector2(-30000, -18000), new IntVector2(-30000, -6000)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( leftSnd, centerSnd, rightTopSegment, leftTopSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( centerSnd, leftSnd, leftTopSegment, rightTopSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( leftSnd, centerSnd, rightBottomSegment, leftBottomSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( centerSnd, leftSnd, leftBottomSegment, rightBottomSegment)); // terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( centerSnd, rightSnd, rightTopSegment, leftTopSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( rightSnd, centerSnd, leftTopSegment, rightTopSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( centerSnd, rightSnd, rightBottomSegment, leftBottomSegment)); terrainService.AddSectorEdgeDescription(PortalSectorEdgeDescription.Build( rightSnd, centerSnd, leftBottomSegment, rightBottomSegment)); // add some obstacles // terrainService.AddTemporaryHoleDescription(terrainService.CreateHoleDescription( // HoleStaticMetadata.CreateRectangleHoleMetadata(-500, 250, 60, 60, 0))); // terrainService.AddTemporaryHoleDescription(terrainService.CreateHoleDescription( // HoleStaticMetadata.CreateRectangleHoleMetadata(0, 130, 60, 60, 0))); for (var i = 0; i < 100; i++) { break; terrainService.AddTemporaryHoleDescription(terrainService.CreateHoleDescription( HoleStaticMetadata.CreateRectangleHoleMetadata( random.Next(-1500, 1500), random.Next(-500, 500), random.Next(10, 50), random.Next(10, 50), random.NextDouble() * Math.PI * 2))); } var terrainSnapshot = terrainService.CompileSnapshot(); var overlayNetwork = terrainSnapshot.OverlayNetworkManager.CompileTerrainOverlayNetwork(30); for (var i = 0; i < 360; i += 10) { var canvas = host.CreateAndAddCanvas(i); canvas.BatchDraw(() => { foreach (var terrainNode in overlayNetwork.TerrainNodes) { canvas.Transform = terrainNode.SectorNodeDescription.WorldTransform; canvas.DrawPolyNode(terrainNode.LandPolyNode, StrokeStyle.BlackHairLineSolid, StrokeStyle.DarkRedHairLineSolid); } foreach (var terrainNode in overlayNetwork.TerrainNodes) { canvas.Transform = terrainNode.SectorNodeDescription.WorldTransform; foreach (var outboundEdgeGroup in terrainNode.OutboundEdgeGroups) { foreach (var outboundEdge in outboundEdgeGroup.Value) { Console.WriteLine(outboundEdge.EdgeJob.SourceSegment); canvas.DrawLine(outboundEdge.EdgeJob.SourceSegment, StrokeStyle.CyanThick3Solid); } } } foreach (var terrainNode in overlayNetwork.TerrainNodes) { canvas.Transform = terrainNode.SectorNodeDescription.WorldTransform; foreach (var hole in terrainNode.LocalGeometryView.Job.DynamicHoles) { var(holeIncludedContours, holeExcludedContours) = hole.Value; canvas.DrawPolygonContours(holeIncludedContours, StrokeStyle.RedHairLineSolid); canvas.DrawPolygonContours(holeExcludedContours, StrokeStyle.OrangeHairLineSolid); } } int asdfa = -1; foreach (var terrainNode in overlayNetwork.TerrainNodes) { asdfa++; canvas.Transform = terrainNode.SectorNodeDescription.WorldTransform; if (terrainNode.SectorNodeDescription.EnableDebugHighlight) { var visibilityPolygonOrigin = IntVector2.FromRadiusAngle(50 * 60, i * Math.PI / 180) + new IntVector2(0, 0); canvas.DrawCrossSectorVisibilityPolygon(terrainNode, visibilityPolygonOrigin); } } }); } }
public bool TryIntersect(IntLineSegment2 segment, out DoubleVector2 p) { return(TryIntersect(ref segment, out p)); }
public bool Intersects(IntLineSegment2 segment) { return(Intersects(ref segment)); }
public static BvhILS2 Build(IEnumerable <IntLineSegment2> segmentEnumerable) { var inputSegments = segmentEnumerable.ToArray(); var inputSegmentMidpoints = inputSegments.Map(s => s.ComputeMidpoint()); var segmentIndices = Util.Generate(inputSegments.Length, i => i); var xComparer = Comparer <int> .Create((a, b) => inputSegmentMidpoints[a].X.CompareTo(inputSegmentMidpoints[b].X)); var yComparer = Comparer <int> .Create((a, b) => inputSegmentMidpoints[a].Y.CompareTo(inputSegmentMidpoints[b].Y)); var outputSegments = new IntLineSegment2[inputSegments.Length]; IntRect2 BoundingSegments(int startIndexInclusive, int endIndexExclusive) { cInt minX = cInt.MaxValue, minY = cInt.MaxValue, maxX = cInt.MinValue, maxY = cInt.MinValue; for (var i = startIndexInclusive; i < endIndexExclusive; i++) { if (inputSegments[segmentIndices[i]].First.X < minX) { minX = inputSegments[segmentIndices[i]].First.X; } if (inputSegments[segmentIndices[i]].Second.X < minX) { minX = inputSegments[segmentIndices[i]].Second.X; } if (inputSegments[segmentIndices[i]].First.Y < minY) { minY = inputSegments[segmentIndices[i]].First.Y; } if (inputSegments[segmentIndices[i]].Second.Y < minY) { minY = inputSegments[segmentIndices[i]].Second.Y; } if (maxX < inputSegments[segmentIndices[i]].First.X) { maxX = inputSegments[segmentIndices[i]].First.X; } if (maxX < inputSegments[segmentIndices[i]].Second.X) { maxX = inputSegments[segmentIndices[i]].Second.X; } if (maxY < inputSegments[segmentIndices[i]].First.Y) { maxY = inputSegments[segmentIndices[i]].First.Y; } if (maxY < inputSegments[segmentIndices[i]].Second.Y) { maxY = inputSegments[segmentIndices[i]].Second.Y; } } // ir2 is inclusive return(new IntRect2 { Left = minX, Top = minY, Right = maxX, Bottom = maxY }); } BvhILS2 BuildInternal(int startInclusive, int endExclusive, bool splitXElseY) { if (endExclusive - startInclusive < 16) { for (var i = startInclusive; i < endExclusive; i++) { outputSegments[i] = inputSegments[segmentIndices[i]]; } return(new BvhILS2(null, null, outputSegments, startInclusive, endExclusive, BoundingSegments(startInclusive, endExclusive))); } Array.Sort(segmentIndices, startInclusive, endExclusive - startInclusive, splitXElseY ? xComparer : yComparer); int midpoint = (startInclusive + endExclusive) / 2; var first = BuildInternal(startInclusive, midpoint, !splitXElseY); var second = BuildInternal(midpoint, endExclusive, !splitXElseY); var bounds = IntRect2.BoundingRectangles(first.Bounds, second.Bounds); return(new BvhILS2(first, second, outputSegments, startInclusive, endExclusive, bounds)); } return(BuildInternal(0, inputSegments.Length, true)); }
FindOptimalLinksToCrossovers( IntVector2 p, int[] candidateWaypoints = null, IReadOnlyDictionary <DoubleLineSegment2, IntLineSegment2[]> candidateBarriersByDestinationSegment = null ) { Interlocked.Increment(ref FindOptimalLinksToCrossoversInvocationCount); //var links = new List<PathLink>(128); //links.Resize(crossoverPoints.Count); //return (new PathLink[0], 0, new PathLink[waypoints.Length], links); int visibleWaypointLinksLength; PathLink[] optimalLinkToWaypoints; var visibleWaypointLinks = FindVisibleWaypointLinks(p, candidateWaypoints, out visibleWaypointLinksLength, out optimalLinkToWaypoints); // Cost from p to other crossoverPoints... var optimalLinkToCrossovers = new ExposedArrayList <PathLink>(Math.Max(128, crossoverPoints.Count)); optimalLinkToCrossovers.size = crossoverPoints.Count; void ProcessCpi(int cpi, IntLineSegment2[] candidateBarriers) { // for bench optimalLinkToCrossovers[cpi] = new PathLink { PriorIndex = PathLink.ErrorInvalidIndex, TotalCost = float.PositiveInfinity }; return; Interlocked.Increment(ref ProcessCpiInvocationCount); bool isDirectPath; if (p == crossoverPoints[cpi]) { isDirectPath = true; // degenerate segment } else if (candidateBarriers == null) { // Console.WriteLine($"Try intersect {cpi}: {p} to {crossoverPoints[cpi]}"); var isDirectPath1 = !landPolyNode.FindContourAndChildHoleBarriersBvh().Intersects(new IntLineSegment2(p, crossoverPoints[cpi])); // var isDirectPath2 = landPolyNode.SegmentInLandPolygonNonrecursive(p, crossoverPoints[cpi]); // Console.WriteLine($" => res {isDirectPath1} vs {isDirectPath2}"); isDirectPath = isDirectPath1; } else { // below is equivalent to (and shaved off 22% execution time relative to): // isDirectPath = candidateBarriers.None(new ILS2(p, crossoverPoints[cpi]).Intersects) isDirectPath = true; //var seg = new IntLineSegment2(p, crossoverPoints[cpi]); for (var bi = 0; bi < candidateBarriers.Length && isDirectPath; bi++) { Interlocked.Increment(ref ProcessCpiInvocation_CandidateBarrierIntersectCount); if (IntLineSegment2.Intersects( p.X, p.Y, crossoverPoints[cpi].X, crossoverPoints[cpi].Y, candidateBarriers[bi].X1, candidateBarriers[bi].Y1, candidateBarriers[bi].X2, candidateBarriers[bi].Y2)) { isDirectPath = false; } //if (seg.Intersects(ref candidateBarriers[bi])) isDirectPath = false; } } if (isDirectPath) { Interlocked.Increment(ref ProcessCpiInvocation_DirectCount); var totalCost = p.To(crossoverPoints[cpi]).Norm2F(); Trace.Assert(!float.IsNaN(totalCost)); optimalLinkToCrossovers[cpi] = new PathLink { PriorIndex = PathLink.DirectPathIndex, TotalCost = totalCost }; } else { Interlocked.Increment(ref ProcessCpiInvocation_IndirectCount); var otherOptimalLinkByWaypointIndex = optimalLinkToWaypointsByCrossoverPointIndex[cpi]; //-- // Below is equivalent to (and shaved off 14% execution time relative to): // visibleWaypointLinks.MinBy(cpwl => cpwl.TotalCost + otherOptimalLinkByWaypointIndex[cpwl.PriorIndex].TotalCost); var optimalLinkToOtherCrossoverPointIndex = -1; var optimalLinkToOtherCrossoverPointCost = float.PositiveInfinity; for (var vwli = 0; vwli < visibleWaypointLinksLength; vwli++) { ref var vwl = ref visibleWaypointLinks[vwli]; var cost = vwl.TotalCost + otherOptimalLinkByWaypointIndex[vwl.PriorIndex].TotalCost; if (cost < optimalLinkToOtherCrossoverPointCost) { optimalLinkToOtherCrossoverPointIndex = vwli; optimalLinkToOtherCrossoverPointCost = cost; } } if (optimalLinkToOtherCrossoverPointIndex == -1) { // Todo: This shouldn't happen! optimalLinkToCrossovers[cpi] = new PathLink { PriorIndex = PathLink.ErrorInvalidIndex, TotalCost = float.PositiveInfinity }; } else { ref var optimalLinkToOtherCrossoverPoint = ref visibleWaypointLinks[optimalLinkToOtherCrossoverPointIndex]; //-- var optimalLinkFromOtherCrossoverPoint = otherOptimalLinkByWaypointIndex[optimalLinkToOtherCrossoverPoint.PriorIndex]; var totalCost = optimalLinkToOtherCrossoverPoint.TotalCost + optimalLinkFromOtherCrossoverPoint.TotalCost; Trace.Assert(!float.IsNaN(totalCost)); optimalLinkToCrossovers[cpi] = new PathLink { PriorIndex = optimalLinkToOtherCrossoverPoint.PriorIndex, TotalCost = totalCost }; } }
private static void Step(GraphicsLoop graphicsLoop, Game game, InputSomethingOSDJFH input, Scene scene) { var expectedTicks = (int)(graphicsLoop.Statistics.FrameTime.TotalSeconds * 60); while (game.GameTimeService.Ticks < expectedTicks) { game.Tick(); } var viewProj = ComputeProjViewMatrix(graphicsLoop.Form.ClientSize); viewProj.Transpose(); var ray = Ray.GetPickRay(input.X, input.Y, new ViewportF(0, 0, 1280, 720, 1.0f, 100.0f), viewProj); var terrainOverlayNetwork = game.TerrainService.CompileSnapshot().OverlayNetworkManager.CompileTerrainOverlayNetwork(0); // rmb moves if (input.IsMouseDown(MouseButtons.Right)) { foreach (var node in terrainOverlayNetwork.TerrainNodes) { var origin = node.SectorNodeDescription.LocalToWorld(DoubleVector2.Zero); var normal = node.SectorNodeDescription.LocalToWorldNormal(DoubleVector3.UnitZ); var plane = new SDXPlane(ToSharpDX(origin), ToSharpDX(normal)); if (!plane.Intersects(ref ray, out SDXVector3 intersection)) { continue; } var intersectionLocal = node.SectorNodeDescription.WorldToLocal(intersection.ToOpenMoba()); if (!node.LandPolyNode.PointInLandPolygonNonrecursive(intersectionLocal.XY.LossyToIntVector2())) { continue; } // recompute intersectionWorld because floating point error in raycast logic var intersectionWorld = node.SectorNodeDescription.LocalToWorld(intersectionLocal.XY); game.MovementSystemService.Pathfind(player, intersectionWorld); } } // lazaars if (input.IsKeyDown(Keys.Q)) { foreach (var node in terrainOverlayNetwork.TerrainNodes) { var origin = node.SectorNodeDescription.LocalToWorld(DoubleVector2.Zero); var normal = node.SectorNodeDescription.LocalToWorldNormal(DoubleVector3.UnitZ); var plane = new SDXPlane(ToSharpDX(origin), ToSharpDX(normal)); if (!plane.Intersects(ref ray, out SDXVector3 intersection)) { continue; } var intersectionLocal = node.SectorNodeDescription.WorldToLocal(intersection.ToOpenMoba()); if (!node.SectorNodeDescription.StaticMetadata.LocalBoundary.Contains(new SDPoint((int)intersectionLocal.X, (int)intersectionLocal.Y))) { continue; } if (!node.LandPolyNode.PointInLandPolygonNonrecursive(player.MovementComponent.LocalPositionIv2)) { continue; } // recompute intersectionWorld because floating point error in raycast logic var intersectionWorld = node.SectorNodeDescription.LocalToWorld(intersectionLocal.XY); var barriersBvh = node.LandPolyNode.FindContourAndChildHoleBarriersBvh(); var q = new IntLineSegment2(player.MovementComponent.LocalPositionIv2, intersectionLocal.XY.LossyToIntVector2()); debugCanvas.Transform = node.SectorNodeDescription.WorldTransform; debugCanvas.DrawLine(q, StrokeStyle.RedHairLineSolid); foreach (var seg in barriersBvh.Segments) { debugCanvas.DrawLine(seg, StrokeStyle.RedThick5Solid); } var intersectingLeaves = barriersBvh.FindPotentiallyIntersectingLeaves(q); var tFar = 1.0; foreach (var bvhNode in intersectingLeaves) { for (var i = bvhNode.SegmentsStartIndexInclusive; i < bvhNode.SegmentsEndIndexExclusive; i++) { if (GeometryOperations.TryFindNonoverlappingSegmentSegmentIntersectionT(ref q, ref bvhNode.Segments[i], out var t)) { Console.WriteLine(t); tFar = Math.Min(tFar, t); } } } debugCanvas.Transform = Matrix4x4.Identity; debugCanvas.DrawLine(player.MovementComponent.WorldPosition, node.SectorNodeDescription.LocalToWorld(q.PointAt(tFar)), StrokeStyle.LimeThick5Solid); } } // i love rocks var rocksExisting = new List <Entity>(); foreach (var rock in rocks) { var distance = rock.MovementComponent.WorldPosition.To(player.MovementComponent.WorldPosition).Norm2D(); if (distance > player.MovementComponent.ComputedRadius) { rocksExisting.Add(rock); continue; } game.EntityService.RemoveEntity(rock); } rocks = rocksExisting; // W draws walls if (input.IsKeyJustDown(Keys.W)) { foreach (var node in terrainOverlayNetwork.TerrainNodes) { var origin = node.SectorNodeDescription.LocalToWorld(DoubleVector2.Zero); var normal = node.SectorNodeDescription.LocalToWorldNormal(DoubleVector3.UnitZ); var plane = new SDXPlane(ToSharpDX(origin), ToSharpDX(normal)); if (!plane.Intersects(ref ray, out SDXVector3 intersection)) { continue; } var intersectionLocal = node.SectorNodeDescription.WorldToLocal(intersection.ToOpenMoba()); if (!node.SectorNodeDescription.StaticMetadata.LocalBoundary.Contains(new SDPoint((int)intersectionLocal.X, (int)intersectionLocal.Y))) { continue; } // recompute intersectionWorld because floating point error in raycast logic var intersectionWorld = node.SectorNodeDescription.LocalToWorld(intersectionLocal.XY); fred.Add(intersectionWorld.XY.LossyToIntVector2()); // todo: we really need to iterate over LGVs rather than tnodes break; } } if (input.IsKeyJustDown(Keys.E)) { if (fred.Count > 0) { fred.RemoveAt(fred.Count - 1); } } if (input.IsKeyJustDown(Keys.R) && fred.Count >= 2) { var polyTree = PolylineOperations.ExtrudePolygon(fred, 10); var boundsLower = fred.Aggregate(new IntVector2(int.MaxValue, int.MaxValue), (a, b) => new IntVector2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y))); var boundsUpper = fred.Aggregate(new IntVector2(int.MinValue, int.MinValue), (a, b) => new IntVector2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y))); var bounds = new SDRectangle(boundsLower.X, boundsLower.Y, boundsUpper.X - boundsLower.X, boundsUpper.Y - boundsLower.Y); var holeStaticMetadata = new PrismHoleStaticMetadata( bounds, new[] { new Polygon2(polyTree.Childs[0].Contour) }, polyTree.Childs[0].Childs.Map(c => new Polygon2(((IEnumerable <IntVector2>)c.Contour).Reverse().ToList()))); var terrainHole = game.TerrainService.CreateHoleDescription(holeStaticMetadata); game.TerrainService.AddTemporaryHoleDescription(terrainHole); if (!input.IsKeyDown(Keys.ShiftKey)) { var removeEvent = game.CreateRemoveTemporaryHoleEvent(new GameTime(game.GameTimeService.Now.Ticks + 90), terrainHole); game.GameEventQueueService.AddGameEvent(removeEvent); } fred.Clear(); } }
public bool ContainsOrIntersects(IntLineSegment2 segment) { return(ContainsOrIntersects(ref segment)); }
public bool FullyContains(ref IntLineSegment2 segment) { return(Contains(segment.First) && Contains(segment.Second)); }
private static MultiValueDictionary <TerrainOverlayNetworkNode, IntLineSegment2> FindVisibleCrossoverSegmentsByNeighborAndClearLocalAt( IDebugCanvas canvas, TerrainOverlayNetworkNode terrainNode, VisibilityPolygon visibilityPolygon, IntVector2 visibilityPolygonOrigin, HashSet <TerrainOverlayNetworkNode> visited = null) { var visibleCrossoverSegmentsByNeighbor = MultiValueDictionary <TerrainOverlayNetworkNode, IntLineSegment2> .Create(() => new HashSet <IntLineSegment2>()); foreach (var outboundEdgeGroup in terrainNode.OutboundEdgeGroups) { var otherTerrainNode = outboundEdgeGroup.Key; if (visited?.Contains(otherTerrainNode) ?? false) { continue; } foreach (var outboundEdge in outboundEdgeGroup.Value) { var ranges = visibilityPolygon.Get(); (IntLineSegment2, bool) FlipMaybeSorta(IntLineSegment2 x) => GeometryOperations.Clockness(visibilityPolygonOrigin, x.First, x.Second) == Clockness.CounterClockwise ? (new IntLineSegment2(x.Second, x.First), true) : (x, false); var(localCrossoverSegment, lcsFlipped) = FlipMaybeSorta(outboundEdge.EdgeJob.EdgeDescription.SourceSegment); var(remoteCrossoverSegment, rcsFlipped) = FlipMaybeSorta(outboundEdge.EdgeJob.EdgeDescription.DestinationSegment); // todo: clamp visibleStartT, visibleEndT to account for agent radius eroding crossover segmetmentnt var rangeIndexIntervals = visibilityPolygon.RangeStab(localCrossoverSegment); var locallyClearedSegments = new List <IntLineSegment2>(); foreach (var(startIndexInclusive, endIndexInclusive) in rangeIndexIntervals) { for (var i = startIndexInclusive; i <= endIndexInclusive; i++) { if (ranges[i].Id == VisibilityPolygon.RANGE_ID_INFINITELY_FAR || ranges[i].Id == VisibilityPolygon.RANGE_ID_INFINITESIMALLY_NEAR) { continue; } var seg = ranges[i].Segment; var rstart = DoubleVector2.FromRadiusAngle(100, ranges[i].ThetaStart) * 100; var rend = DoubleVector2.FromRadiusAngle(100, ranges[i].ThetaEnd) * 100; double visibleStartT, visibleEndT; if (!GeometryOperations.TryFindNonoverlappingLineLineIntersectionT(localCrossoverSegment.First.ToDoubleVector2(), localCrossoverSegment.Second.ToDoubleVector2(), visibilityPolygonOrigin.ToDoubleVector2(), visibilityPolygonOrigin.ToDoubleVector2() + rstart, out visibleStartT) || !GeometryOperations.TryFindNonoverlappingLineLineIntersectionT(localCrossoverSegment.First.ToDoubleVector2(), localCrossoverSegment.Second.ToDoubleVector2(), visibilityPolygonOrigin.ToDoubleVector2(), visibilityPolygonOrigin.ToDoubleVector2() + rend, out visibleEndT)) { // wtf? Console.WriteLine("???"); continue; } // Todo: I don't actually understand why visibleEndT > 1 is a thing? // t values are for parameterization of crossover line segment, so must be within [0, 1] if ((visibleStartT < 0 && visibleEndT < 0) || (visibleStartT > 1 && visibleEndT > 1)) { continue; } visibleStartT = Math.Min(1.0, Math.Max(0.0, visibleStartT)); visibleEndT = Math.Min(1.0, Math.Max(0.0, visibleEndT)); if (visibilityPolygon.SegmentComparer.Compare(localCrossoverSegment, seg) < 0) { var localVisibleStart = localCrossoverSegment.PointAt(visibleStartT).LossyToIntVector2(); var localVisibleEnd = localCrossoverSegment.PointAt(visibleEndT).LossyToIntVector2(); var remoteVisibleStart = remoteCrossoverSegment.PointAt(lcsFlipped == rcsFlipped ? visibleStartT : 1.0 - visibleStartT).LossyToIntVector2(); var remoteVisibleEnd = remoteCrossoverSegment.PointAt(lcsFlipped == rcsFlipped ? visibleEndT : 1.0 - visibleEndT).LossyToIntVector2(); if (localVisibleStart == localVisibleEnd) { continue; } if (remoteVisibleStart == remoteVisibleEnd) { continue; } var locallyClearedSegment = new IntLineSegment2(localVisibleStart, localVisibleEnd); locallyClearedSegments.Add(locallyClearedSegment); visibleCrossoverSegmentsByNeighbor.Add(otherTerrainNode, new IntLineSegment2(remoteVisibleStart, remoteVisibleEnd)); } } } foreach (var locallyClearedSegment in locallyClearedSegments) { visibilityPolygon.ClearBefore(locallyClearedSegment); } } } return(visibleCrossoverSegmentsByNeighbor); }
private static void H(ref IntLineSegment2 seg, PolyNode polyNode, ref IntLineSegment2 contourSegment, List<(PolyNode, double)> localBreakpoints)
public static void DrawLine(this IDebugCanvas canvas, IntLineSegment2 segment, StrokeStyle strokeStyle) { canvas.DrawLine(ToDV3(segment.First), ToDV3(segment.Second), strokeStyle); }