/// <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 void PickDeepestPolynode(this PolyNode polyTree, IntVector2 query, out PolyNode result, out bool isHole) { polyTree.AssertIsContourlessRootHolePunchResult(); PolyNode current = polyTree; while (true) { // current is a hole PolyNode match; // if we fail to find the first child land node border-inclusively containing the query point if (!current.Childs.TryFindFirst(child => Clipper.PointInPolygon(new IntVector2(query.X, query.Y), child.Contour) != PolygonContainmentResult.OutsidePolygon, out match)) { result = current; isHole = true; return; } // next off, current is land current = match; // If we fail to find a child hole border-excludingly containing the query point if (!current.Childs.TryFindFirst(child => Clipper.PointInPolygon(new IntVector2(query.X, query.Y), child.Contour) == PolygonContainmentResult.InPolygon, out match)) { result = current; isHole = false; return; } // next off, current is a hole current = match; } }