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); // } }
public TerrainOverlayNetworkNode(SectorNodeDescription sectorNodeDescription, LocalGeometryView localGeometryView, PolyNode landPolyNode) { SectorNodeDescription = sectorNodeDescription; LocalGeometryView = localGeometryView; LandPolyNode = landPolyNode; CrossoverPointManager = new PolyNodeCrossoverPointManager(landPolyNode); }
public static void DrawWallPushGrid(this IDebugCanvas canvas, LocalGeometryView lgv, double holeDilationRadius, double xlow = -50, double xhigh = 1100, double xstep = 100, double ylow = -50, double yhigh = 1100, double ystep = 100) { for (double x = xlow; x < xhigh; x += xstep) { for (double y = ylow; y < yhigh; y += ystep) { throw new NotImplementedException(); // var query = new DoubleVector2(x, y); // DoubleVector2 nearestLandPoint; // var isInHole = lgv.FindNearestLandPointAndIsInHole(query, out nearestLandPoint); // canvas.DrawPoint(new DoubleVector3(query), isInHole ? InHoleStrokeStyle : InLandStrokeStyle); // if (isInHole) { // canvas.DrawLine(new DoubleVector3(query), new DoubleVector3(nearestLandPoint), NearestLandStrokeStyle); // } } } }
// public static bool TryFindSector(this TerrainSnapshot terrainSnapshot, IntVector3 queryWorld, out SectorSnapshot result) { // return TryFindSector(terrainSnapshot, queryWorld.ToDoubleVector3(), out result); // } // public static bool TryFindSector(this TerrainSnapshot terrainSnapshot, DoubleVector3 queryWorld, out SectorSnapshot result) { // return terrainSnapshot.SectorSnapshots.TryFindFirst(sectorSnapshot => { // var queryLocal = sectorSnapshot.WorldToLocal(queryWorld); // var localBoundary = sectorSnapshot.StaticMetadata.LocalBoundary; // return localBoundary.X <= queryLocal.X && queryLocal.X <= localBoundary.Right && // localBoundary.Y <= queryLocal.Y && queryLocal.Y <= localBoundary.Bottom; // }, out result); // } // public static bool IsInHole(this SectorSnapshotGeometryContext sectorSnapshotGeometryContext, IntVector3 query) { // var punchedLandPolytree = sectorSnapshotGeometryContext.PunchedLand; // punchedLandPolytree.AssertIsContourlessRootHolePunchResult(); // // PolyNode pickedNode; // bool isHole; // punchedLandPolytree.PickDeepestPolynode(query.XY, out pickedNode, out isHole); // // return isHole; // } /// <summary> /// Note: Containment definition varies by hole vs terrain: Containment for holes /// does not include the hole edge, containment for terrain includes the terrain edge. /// This is important, else e.g. knockback + terrain push placing an entity on an edge /// would potentially infinite loop. /// </summary> public static bool FindNearestLandPointAndIsInHole(this LocalGeometryView localGeometryView, DoubleVector2 query, out DoubleVector2 nearestLandPoint) { var punchedLandPolytree = localGeometryView.PunchedLand; punchedLandPolytree.AssertIsContourlessRootHolePunchResult(); PolyNode pickedNode; bool isHole; punchedLandPolytree.PickDeepestPolynode(query.LossyToIntVector2(), out pickedNode, out isHole); // If query point not in a hole, nearest land point is query point if (!isHole) { nearestLandPoint = query; return(false); } // Else, two cases to consider: nearest point is on an island inside this hole, alternatively // and (only if the hole has a contour), nearest point is on the hole contour. nearestLandPoint = DoubleVector2.Zero; double bestDistance = double.PositiveInfinity; if (pickedNode.Contour.Any()) { // the hole has a contour; that is, it's a hole inside of a landmass var result = GeometryOperations.FindNearestPointOnContour(pickedNode.Contour, query); bestDistance = result.Distance; nearestLandPoint = result.NearestPoint; } foreach (var childLandNode in pickedNode.Childs) { var result = GeometryOperations.FindNearestPointOnContour(childLandNode.Contour, query); if (result.Distance < bestDistance) { bestDistance = result.Distance; nearestLandPoint = result.NearestPoint; } } return(true); }
private void DebugRenderLocalGeometryView(LocalGeometryView localGeometryView, params IntLineSegment2[] segs) { if (!kEnableDebugRender) { return; } Size bounds = new Size(1280, 720); var renderScale = 1.0f; PerspectiveProjector CreateCanvasProjector() { var rotation = 95 * Math.PI / 180.0; var displaySize = new Size((int)(bounds.Width * renderScale), (int)(bounds.Height * renderScale)); var center = new DoubleVector3(0, 0, 0); var projector = new PerspectiveProjector( center + DoubleVector3.FromRadiusAngleAroundXAxis(1000, rotation), center, DoubleVector3.FromRadiusAngleAroundXAxis(1, rotation - Math.PI / 2), displaySize.Width, displaySize.Height); return(projector); } DebugMultiCanvasHost host = DebugMultiCanvasHost.CreateAndShowCanvas(bounds, new Point(0, 0), CreateCanvasProjector()); var canvas = host.CreateAndAddCanvas(0); canvas.DrawPolyNode(localGeometryView.PunchedLand); foreach (var hole in localGeometryView.Job.DynamicHoles) { canvas.DrawPolygonContours(hole.Value.holeExcludedContours, StrokeStyle.OrangeHairLineSolid); canvas.DrawPolygonContours(hole.Value.holeIncludedContours, StrokeStyle.RedHairLineSolid); } foreach (var seg in segs) { canvas.DrawLine(seg, StrokeStyle.CyanHairLineSolid); } }
public override List<EdgeJob> EmitCrossoverJobs(double crossoverPointSpacing, LocalGeometryView sourceLgv, LocalGeometryView destinationLgv) { // return new List<EdgeJob>(); var sourceSegmentVector = SourceSegment.First.To(SourceSegment.Second).ToDoubleVector2(); var destinationSegmentVector = DestinationSegment.First.To(DestinationSegment.Second).ToDoubleVector2(); var edgeJobs = new List<EdgeJob>(); var streamSource = X(SourceSegment, sourceLgv).ToArray(); var streamDest = X(DestinationSegment, destinationLgv).ToArray(); var crossResult = CrossTheStreams(streamSource, streamDest).ToArray(); foreach (var (source, dest, tStart, tEnd) in crossResult) { var sourceSubSegment = new DoubleLineSegment2( SourceSegment.First.ToDoubleVector2() + tStart * sourceSegmentVector, SourceSegment.First.ToDoubleVector2() + tEnd * sourceSegmentVector); var destinationSubSegment = new DoubleLineSegment2( DestinationSegment.First.ToDoubleVector2() + tStart * destinationSegmentVector, DestinationSegment.First.ToDoubleVector2() + tEnd * destinationSegmentVector); edgeJobs.Add(new EdgeJob { EdgeDescription = this, SourcePolyNode = source, SourceSegment = sourceSubSegment, DestinationPolyNode = dest, DestinationSegment = destinationSubSegment }); } return edgeJobs; }