예제 #1
0
        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);
             //         }
        }
예제 #2
0
        /// <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");
            }
        }
예제 #3
0
        public List <BvhILS2> FindPotentiallyIntersectingLeaves(IntLineSegment2 seg)
        {
            var res = new List <BvhILS2>();

            FindPotentiallyIntersectingLeavesInternal(ref seg, res);
            return(res);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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 });
        }
예제 #6
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);
        }
예제 #7
0
 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);
     }
 }
예제 #8
0
        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);
        }
예제 #9
0
 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
      };
 }
예제 #10
0
        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));
        }
예제 #11
0
 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);
 }
예제 #12
0
 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);
 }
예제 #13
0
        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));
                }
예제 #14
0
        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);
        }
예제 #15
0
 private static IntLineSegment3 ToILS3(IntLineSegment2 p) => new IntLineSegment3(ToIV3(p.First), ToIV3(p.Second));
예제 #16
0
        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);
                        }
                    }
                });
            }
        }
예제 #17
0
 public bool TryIntersect(IntLineSegment2 segment, out DoubleVector2 p)
 {
     return(TryIntersect(ref segment, out p));
 }
예제 #18
0
 public bool Intersects(IntLineSegment2 segment)
 {
     return(Intersects(ref segment));
 }
예제 #19
0
        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));
        }
예제 #20
0
        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
                        };
                    }
                }
예제 #21
0
        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();
            }
        }
예제 #22
0
 public bool ContainsOrIntersects(IntLineSegment2 segment)
 {
     return(ContainsOrIntersects(ref segment));
 }
예제 #23
0
 public bool FullyContains(ref IntLineSegment2 segment)
 {
     return(Contains(segment.First) && Contains(segment.Second));
 }
예제 #24
0
        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);
        }
예제 #25
0
 private static void H(ref IntLineSegment2 seg, PolyNode polyNode, ref IntLineSegment2 contourSegment, List<(PolyNode, double)> localBreakpoints)
예제 #26
0
 public static void DrawLine(this IDebugCanvas canvas, IntLineSegment2 segment, StrokeStyle strokeStyle)
 {
     canvas.DrawLine(ToDV3(segment.First), ToDV3(segment.Second), strokeStyle);
 }