/// <summary> /// Get the vertex at the given position or, if it does not exist, construct a new vertex /// </summary> /// <param name="vector2"></param> /// <returns></returns> public Vertex <TVTag, TETag, TFTag> GetOrConstructVertex(Vector2 vector2) { Contract.Ensures(Contract.Result <Vertex <TVTag, TETag, TFTag> >() != null); Contract.Ensures(!Contract.Result <Vertex <TVTag, TETag, TFTag> >().IsDeleted); //Select candidate vertices within range (square query) var candidates = _vertices.Intersects(new BoundingRectangle(vector2 - new Vector2(VERTEX_EPSILON / 2), vector2 + new Vector2(VERTEX_EPSILON / 2))); //Select best candidate (nearest) float bestDistance = float.MaxValue; Vertex <TVTag, TETag, TFTag> best = null; foreach (var candidate in candidates) { var d = Vector2.DistanceSquared(candidate.Position, vector2); if (d < bestDistance && d < VERTEX_EPSILON * VERTEX_EPSILON) { bestDistance = d; best = candidate; } } //If we found a suitable one, return it if (best != null) { return(best); } //Otherwise create a new vertex and return that var v = new Vertex <TVTag, TETag, TFTag>(this, vector2); _vertices.Insert(new BoundingRectangle(v.Position, v.Position).Inflate(0.1f), v); return(v); }
public void AssertThat_Intersects_FindsItemInBounds() { _tree.Insert(new BoundingRectangle(new Vector2(10, 10), new Vector2(20, 20)), "A"); _tree.Insert(new BoundingRectangle(new Vector2(90, 90), new Vector2(80, 80)), "B"); var results = _tree.Intersects(new BoundingRectangle(new Vector2(0, 0), new Vector2(20, 20))).ToArray(); Assert.AreEqual(1, results.Length); Assert.AreEqual("A", results.Single()); }
/// <summary> /// Find edges close to given position /// </summary> /// <param name="position"></param> /// <param name="radius"></param> /// <returns></returns> private IEnumerable <Edge> FindEdges(Vector2 position, float radius) { Contract.Requires(_vertices != null); Contract.Ensures(Contract.Result <IEnumerable <Edge> >() != null); return(_vertices.Intersects( new BoundingRectangle( new Vector2(position.X - radius, position.Y - radius), new Vector2(position.X + radius, position.Y + radius) ) ).SelectMany(v => v.Edges).Distinct()); }
private Edge FindIntersectingEdge(Vector2 a, Vector2 b, out Vector2 intersectPosition) { var min = new Vector2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); var max = new Vector2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); //Select the all intersections (by checking all edges in octree result) var segment = new LineSegment2(a, b); var best = (from candidate in _edges.Intersects(new BoundingRectangle(min, max)) let intersectionMaybe = new LineSegment2(candidate.A.Position, candidate.B.Position).Intersects(segment) where intersectionMaybe.HasValue let intersection = intersectionMaybe.Value select new KeyValuePair <LinesIntersection2, Edge>(intersection, candidate)); intersectPosition = Vector2.Zero; Edge bestEdge = null; var bestScore = float.MaxValue; foreach (var keyValuePair in best) { if (keyValuePair.Key.DistanceAlongB < bestScore) { intersectPosition = keyValuePair.Key.Position; bestEdge = keyValuePair.Value; bestScore = keyValuePair.Key.DistanceAlongB; } } return(bestEdge); }
/// <summary> /// Find edges which itnersect the given bounds /// </summary> /// <param name="rectangle"></param> /// <returns></returns> public IEnumerable <HalfEdge <TVTag, TETag, TFTag> > FindEdges(BoundingRectangle rectangle) { Contract.Ensures(Contract.Result <IEnumerable <HalfEdge <TVTag, TETag, TFTag> > >() != null); Contract.Ensures(Contract.ForAll(Contract.Result <IEnumerable <HalfEdge <TVTag, TETag, TFTag> > >(), a => !a.IsDeleted)); return(_halfEdges.Intersects(rectangle)); }
// Update is called once per frame void Update() { Junction j = new Junction(1, 0, 1); var foundJ = junctions.Intersects(j.Bound); Debug.Log(j.Bound); Debug.Log(j.Bound.Contains(new Vector2(1, 1))); foreach (var jo in foundJ) { jo.add(new Road(Vector3.back, Vector3.forward, 1f)); Debug.Log(jo.RoadsCount); } }
private TSelf ConstructFromSlicePart(IReadOnlyList <Vector2> polygon, Quadtree <Side> inputSidesQuad, Ray2?sliceLine, List <KeyValuePair <TSelf, Side> > outInternalSides) { Contract.Requires(polygon != null); Contract.Requires(inputSidesQuad != null); Contract.Requires(outInternalSides != null); Contract.Ensures(Contract.Result <TSelf>() != null); var outputSides = new List <Side>(); var internalSides = new List <Side>(); for (var i = 0; i < polygon.Count; i++) { var a = polygon[i]; var b = polygon[(i + 1) % polygon.Count]; var ab = new LineSegment2(a, b).LongLine; //Find all sides from the input which overlap this line. Slightly expand the box to handle a perfectly flat line (which would create an empty box and select nothing) var candidates = inputSidesQuad .Intersects(new BoundingRectangle(Vector2.Min(a, b) - new Vector2(0.01f), Vector2.Max(a, b) + new Vector2(0.01f))) //.Where(c => c.Start == a || c.End == b) ; //There are three types of edge in the sliced shapes: // - unchanged edges. start and end in the same place as an existing side // - sliced edges. start or end at the same place as an existing edge and co-linear with it // - dividing edge. co-linear with slice line var unchanged = candidates.SingleOrDefault(c => c.Start.Equals(a) && c.End.Equals(b)); if (unchanged != null) { //Side completely unchanged, simply copy across the data outputSides.Add(new Side(a, b, unchanged.Sections)); continue; } var slicedStart = candidates.SingleOrDefault(c => c.Start.Equals(a) && new LineSegment2(c.Start, c.End).LongLine.Parallelism(ab) == Parallelism.Collinear && new LineSegment2(c.Start, c.End).DistanceToPoint(b) <= 0.01f); if (slicedStart != null) { //Side overlapping at start, select the correct sections from OverlapPoint -> 0 (Start) outputSides.Add(new Side(a, b, SelectSections(slicedStart, a, b))); continue; } var slicedEnd = candidates.SingleOrDefault(c => c.End.Equals(b) && new LineSegment2(c.Start, c.End).LongLine.Parallelism(ab) == Parallelism.Collinear && new LineSegment2(c.Start, c.End).DistanceToPoint(a) <= 0.01f); if (slicedEnd != null) { //Side overlapping at end, select the correct sections from OverlapPoint -> 1 (End) outputSides.Add(new Side(a, b, SelectSections(slicedEnd, a, b))); continue; } if (!sliceLine.HasValue) { outputSides.Add(new Side(a, b, new TSection[0])); } else { if (sliceLine.Value.Parallelism(ab) == Parallelism.Collinear) { //this is the slice line, need to add a neighbour section //But which section is the neighbour? we can't know yet because not all sections exist yet! //Create a side with a null section, we'll fix this up later var s = new Side(a, b, null); internalSides.Add(s); outputSides.Add(s); continue; } throw new InvalidOperationException("Failed to match up sides when slicing polygon region"); } } var region = Construct(outputSides); outInternalSides.AddRange(internalSides.Select(a => new KeyValuePair <TSelf, Side>(region, a))); return(region); }