public void LineSearchGridTestMethod() { LineSearchGrid<GridVector2> LineSearch = new LineSearchGrid<GridVector2>(new GridRectangle(-10, 10, -10, 10), 500); GridLineSegment lineA = new GridLineSegment(new GridVector2(-5, 3), new GridVector2(5, 3)); GridLineSegment lineB = new GridLineSegment(new GridVector2(3, -5), new GridVector2(3, 5)); GridLineSegment lineC = new GridLineSegment(new GridVector2(-6, -5), new GridVector2(-6, 5)); GridLineSegment lineD = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -8)); GridLineSegment lineE = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -2)); LineSearch.Add(lineA, lineA.A); LineSearch.Add(lineB, lineB.A); LineSearch.Add(lineC, lineC.A); LineSearch.Add(lineD, lineD.A); LineSearch.Add(lineE, lineE.B); GridVector2 intersection; double distance; GridVector2 value = LineSearch.GetNearest(new GridVector2(-5, 3), out intersection, out distance); Debug.Assert(value == lineA.A); value = LineSearch.GetNearest(new GridVector2(-10, -10), out intersection, out distance); Debug.Assert(value == lineC.A); }
public void LineSearchGridTestMethod() { LineSearchGrid<string> LineSearch = new LineSearchGrid<string>(new GridRectangle(-10, 10, -10, 10), 500); GridLineSegment lineA = new GridLineSegment(new GridVector2(-5, 3), new GridVector2(5, 3)); GridLineSegment lineB = new GridLineSegment(new GridVector2(3, -5), new GridVector2(3, 5)); GridLineSegment lineC = new GridLineSegment(new GridVector2(-6, -5), new GridVector2(-6, 5)); GridLineSegment lineD = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -8)); //Should be in seven grid cells GridLineSegment lineE = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -2)); LineSearch.Add(lineA, "A"); LineSearch.Add(lineB, "B"); LineSearch.Add(lineC, "C"); LineSearch.Add(lineD, "D"); LineSearch.Add(lineE, "E"); GridVector2 intersection; double distance; string value = LineSearch.GetNearest(new GridVector2(-5, 3), out intersection, out distance); Debug.Assert(value == "A"); value = LineSearch.GetNearest(new GridVector2(-10, -10), out intersection, out distance); Debug.Assert(value == "C"); value = LineSearch.GetNearest(new GridVector2(7, 4), out intersection, out distance); Debug.Assert(value == "A"); value = LineSearch.GetNearest(new GridVector2(3.5, 6), out intersection, out distance); Debug.Assert(value == "B"); }
internal GrdSegment(GridLineSegment segment) : base() { Ax = segment.PointA.X; Ay = segment.PointA.Y; Bx = segment.PointB.X; By = segment.PointB.Y; IsCellSegment = segment.IsCellSegment; }
public void GridLineSegmentDistanceToPoint() { //Check edge conditions for a horizontal line { GridLineSegment lineA = new GridLineSegment(new GridVector2(-5, 3), new GridVector2(5, 3)); //Check edge conditions for a horizontal line GridVector2 PointOnLine = new GridVector2(2, 3); double Distance; GridVector2 Intersection; Distance = lineA.DistanceToPoint(PointOnLine, out Intersection); Debug.Assert(Distance == 0); Debug.Assert(Intersection == PointOnLine); //Check if we go past the line in X axis GridVector2 PointLeftOfLine = new GridVector2(-10, 3); GridVector2 PointRightOfLine = new GridVector2(10, 3); Distance = lineA.DistanceToPoint(PointLeftOfLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == lineA.A); Distance = lineA.DistanceToPoint(PointRightOfLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == lineA.B); //Check if we go above or below line GridVector2 PointAboveLine = new GridVector2(3, 8); GridVector2 PointBelowLine = new GridVector2(3, -2); Distance = lineA.DistanceToPoint(PointAboveLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == new GridVector2(3, 3)); Distance = lineA.DistanceToPoint(PointBelowLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == new GridVector2(3, 3)); } //Check edge conditions for a vertical line { GridLineSegment lineB = new GridLineSegment(new GridVector2(3, -5), new GridVector2(3, 5)); GridVector2 PointOnLine = new GridVector2(3, 2); double Distance; GridVector2 Intersection; Distance = lineB.DistanceToPoint(PointOnLine, out Intersection); Debug.Assert(Distance == 0); Debug.Assert(Intersection == PointOnLine); //Check if we go above or below line GridVector2 PointAboveLine = new GridVector2(3, 10); GridVector2 PointBelowLine = new GridVector2(3, -10); Distance = lineB.DistanceToPoint(PointAboveLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == lineB.B); Distance = lineB.DistanceToPoint(PointBelowLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == lineB.A); //Check if we go left or right of line GridVector2 PointLeftOfLine = new GridVector2(-2, 4); GridVector2 PointRightOfLine = new GridVector2(8, 4); Distance = lineB.DistanceToPoint(PointLeftOfLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == new GridVector2(3, 4)); Distance = lineB.DistanceToPoint(PointRightOfLine, out Intersection); Debug.Assert(Distance == 5); Debug.Assert(Intersection == new GridVector2(3, 4)); } { //Check the diagonal line through the axis center GridLineSegment lineC = new GridLineSegment(new GridVector2(-5, -5), new GridVector2(5, 5)); GridVector2 PointOnLine = new GridVector2(0, 0); double Distance; GridVector2 Intersection; Distance = lineC.DistanceToPoint(PointOnLine, out Intersection); Debug.Assert(Distance == 0); Debug.Assert(Intersection == PointOnLine); GridVector2 PointOffLine = new GridVector2(-5, 5); Distance = lineC.DistanceToPoint(PointOffLine, out Intersection); Debug.Assert(Distance == Math.Sqrt(Math.Pow(5, 2) + Math.Pow(5,2))); Debug.Assert(Intersection == new GridVector2(0,0)); GridVector2 PointPastEdge = new GridVector2(-10, 0); Distance = lineC.DistanceToPoint(PointPastEdge, out Intersection); Debug.Assert(Distance == Math.Sqrt(Math.Pow(5, 2) + Math.Pow(5,2))); Debug.Assert(Intersection == new GridVector2(-5,-5)); } { //Check the diagonal line through the axis center GridLineSegment lineD = new GridLineSegment(new GridVector2(-6, -4), new GridVector2(4, 6)); GridVector2 PointOnLine = new GridVector2(-1, 1); double Distance; GridVector2 Intersection; Distance = lineD.DistanceToPoint(PointOnLine, out Intersection); Debug.Assert(Distance == 0); Debug.Assert(Intersection == PointOnLine); GridVector2 PointOffLine = new GridVector2(-6, 6); Distance = lineD.DistanceToPoint(PointOffLine, out Intersection); Debug.Assert(Distance == Math.Sqrt(Math.Pow(5, 2) + Math.Pow(5, 2))); Debug.Assert(Intersection == new GridVector2(-1, 1)); GridVector2 PointPastEdge = new GridVector2(9, 1); Distance = lineD.DistanceToPoint(PointPastEdge, out Intersection); Debug.Assert(Distance == Math.Sqrt(Math.Pow(5, 2) + Math.Pow(5, 2))); Debug.Assert(Intersection == new GridVector2(4, 6)); } }
public void GridLineSegmentIntersects() { // // TODO: Add test logic here // GridLineSegment lineA = new GridLineSegment(new GridVector2(-5,3), new GridVector2(5,3)); GridLineSegment lineB = new GridLineSegment(new GridVector2(3,-5), new GridVector2(3,5)); GridLineSegment lineC = new GridLineSegment(new GridVector2(-6, -5), new GridVector2(-6, 5)); GridLineSegment lineD = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -8)); GridLineSegment lineE = new GridLineSegment(new GridVector2(-9, 8), new GridVector2(1, -2)); GridVector2 intersect = new GridVector2(); bool result = lineA.Intersects(lineB, out intersect); Debug.Assert(result == true); Debug.Assert(intersect.X == 3 && intersect.Y == 3); result = lineA.Intersects(lineC, out intersect); Debug.Assert(result == false); result = lineA.Intersects(lineD, out intersect); Debug.Assert(result == false); // Debug.Assert(intersect.X == -4 && intersect.Y == 3); result = lineA.Intersects(lineE, out intersect); Debug.Assert(result == true); Debug.Assert(intersect.X == -4 && intersect.Y == 3); }
public double NearestLine(GridLineSegment L, out GridLineSegment foundCtrlLine, out GridLineSegment foundMapLine, out GridVector2 intersection) { double nearestIntersect = double.MaxValue; //For debugging only double nearestFailedIntersect = double.MaxValue; GridVector2 nearestFailedPoint = new GridVector2(); GridLineSegment nearestFailedSegment; foundCtrlLine = new GridLineSegment(); foundMapLine = new GridLineSegment(); intersection = new GridVector2(); IEnumerable<GridLineSegmentPair> _linePairs = _LineSegmentGrid.GetPotentialIntersections(L); foreach (GridLineSegmentPair pair in _linePairs) { //Build the edge and find out if it intersects GridLineSegment mapLine = pair.mapLine; if (mapLine.MinX > L.MaxX) continue; if (mapLine.MaxX < L.MinX) continue; if (mapLine.MinY > L.MaxY) continue; if (mapLine.MaxY < L.MinY) continue; GridVector2 result; bool bIntersected = mapLine.Intersects(L, out result); double distance = GridVector2.Distance(L.A, result); if (distance < nearestIntersect && bIntersected) { nearestIntersect = distance; intersection = result; foundMapLine = mapLine; foundCtrlLine = pair.ctrlLine; } if (distance < nearestFailedIntersect && !bIntersected) { nearestFailedPoint = result; nearestFailedSegment = mapLine; nearestFailedIntersect = distance; } } return nearestIntersect; }
public override double ConvexHullIntersection(GridLineSegment L, GridVector2 OutsidePoint, out GridLineSegment foundCtrlLine, out GridLineSegment foundMapLine, out GridVector2 intersection) { double distance = double.MaxValue; foundCtrlLine = new GridLineSegment(); foundMapLine = new GridLineSegment(); intersection = new GridVector2(); //In the grid transform we can simply calculate where the edge intersects if needed //The only place we expect this to be called is for intersections with the outside border, but we should implement it completely to be safe //Check the edges first if (MappedBounds.Intersects(L.BoundingBox) == false) return distance; GridLineSegment[] Borders = new GridLineSegment[] { MappedBounds.LeftEdge, MappedBounds.RightEdge, MappedBounds.TopEdge, MappedBounds.BottomEdge}; Direction[] BorderDir = new Direction[] { Direction.LEFT, Direction.RIGHT, Direction.TOP, Direction.BOTTOM}; GridVector2 BestIntersection = new GridVector2(); Direction IntersectDir = Direction.NONE; for(int iBorder = 0; iBorder < Borders.Length; iBorder++) { GridVector2 BorderIntersect; bool success = L.Intersects(Borders[iBorder], out BorderIntersect); if(success) { double IntersectDistance = GridVector2.Distance(OutsidePoint, BorderIntersect); if(IntersectDistance < distance) { distance = IntersectDistance; BestIntersection = BorderIntersect; IntersectDir = BorderDir[iBorder]; intersection = BestIntersection; } } } if(IntersectDir == Direction.NONE) { //Nothing found, stop return distance; } //Figure out the coordinates for L.A double X = ((BestIntersection.X - MappedBounds.Left) / MappedBounds.Width) * (GridSizeX - 1); double Y = ((BestIntersection.Y - MappedBounds.Bottom) / MappedBounds.Height) * (GridSizeY - 1); int iX = (int)X; int iY = (int)Y; GridLineSegmentPair pair = LinesForCoord(iX, iY, IntersectDir); GridVector2 testIntersection; double RoundErrorTestValue = 0; if (IntersectDir == Direction.RIGHT || IntersectDir == Direction.LEFT) { RoundErrorTestValue = X - Math.Floor(X); } else { RoundErrorTestValue = Y - Math.Floor(Y); } if (RoundErrorTestValue > 0.99) { //OK, better check if there is a rounding error we need to correct. if (!L.Intersects(foundMapLine, out testIntersection)) { //OK, probably a rounding error for a point very close to the end of the line if (IntersectDir == Direction.RIGHT || IntersectDir == Direction.LEFT) { iX = (int)Math.Round(X); } else { iY = (int)Math.Round(Y); } pair = LinesForCoord(iX, iY, IntersectDir); Debug.Assert(L.Intersects(pair.mapLine, out testIntersection)); } } Debug.Assert(L.Intersects(pair.mapLine, out testIntersection)); foundCtrlLine = pair.ctrlLine; foundMapLine = pair.mapLine; return distance; }
public void ThreadPoolCallback(Object threadContext) { List<MappingGridVector2> newPointsList = new List<MappingGridVector2>(iPoints.Length); foreach(int iPoint in iPoints) { MappingGridVector2 UnmappedPoint = warpingTransform.MapPoints[iPoint]; GridVector2 newControl; bool TransformSuccess = fixedTransform.TryTransform(UnmappedPoint.ControlPoint, out newControl); if (TransformSuccess) { newPointsList.Add( new MappingGridVector2(newControl, UnmappedPoint.MappedPoint) ); } else { this.AllPointsTransformed = false; //In this case we need to test each edge connecting this point to other points. List<int> MovingEdgeIndicies = warpingTransform.Edges[iPoint]; //Find out which of these edge points intersect triangles in the fixed warp. If they are inside the control warp //triangle mesh we find the point where the edge intersects the fixed warp mesh. for (int iEdge = 0; iEdge < MovingEdgeIndicies.Count; iEdge++) { int iEdgePoint = MovingEdgeIndicies[iEdge]; GridLineSegment ctrlLine = new GridLineSegment(UnmappedPoint.ControlPoint, this.warpingTransform.MapPoints[iEdgePoint].ControlPoint); GridLineSegment mapLine = new GridLineSegment(UnmappedPoint.MappedPoint, this.warpingTransform.MapPoints[iEdgePoint].MappedPoint); GridLineSegment foundCtrlLine; //Control line found in nearest line call GridLineSegment foundMapLine; //Corresponding map line found in nearest line call GridVector2 intersect; //Find out if there is a line in the fixed transform we intersect with. double distance = fixedTransform.ConvexHullIntersection(ctrlLine, UnmappedPoint.ControlPoint, out foundCtrlLine, out foundMapLine, out intersect); if (distance == double.MaxValue) continue; if (fixedTransform.GetTransform(this.warpingTransform.MapPoints[iEdgePoint].ControlPoint) == null) continue; //Translate from the fixed transform map space into control space. GridVector2 newCtrlPoint; { //Determine how far along the mapping line on the fixed transfrom is the intersect point. double mapLineDistance = GridVector2.Distance(foundMapLine.A, intersect); double mapLineFraction = mapLineDistance / foundMapLine.Length; //How far along the corresponding control line are we? double ctrlLineDistance = foundCtrlLine.Length * mapLineFraction; newCtrlPoint = foundCtrlLine.Direction; //Get unit vector describing direction and scale it newCtrlPoint.Scale(ctrlLineDistance); newCtrlPoint = newCtrlPoint + foundCtrlLine.A; } //Now we must find out where the point on the warping transform is by checking how far along the mapping line on the warping transform we were. GridVector2 newMapPoint; { //Figure out where the transformed point lies in the moving transform mapped space. //Make sure we measure from the same origin on both mapped and control lines double CtrlLineDistance = GridVector2.Distance(ctrlLine.A, intersect); double fraction = CtrlLineDistance / ctrlLine.Length; Debug.Assert(fraction <= 1.0 && fraction >= 0.0); if (fraction > 1f) fraction = 1f; else if (fraction < 0f) fraction = 0f; double mappedDistance = mapLine.Length * fraction; newMapPoint = mapLine.Direction; newMapPoint.Scale(mappedDistance); newMapPoint = newMapPoint + mapLine.A; } newPointsList.Add(new MappingGridVector2(newCtrlPoint, newMapPoint)); } } } MappingGridVector2.RemoveDuplicates(newPointsList); newPoints = newPointsList.ToArray(); DoneEvent.Set(); }
private void AddStructureLink(StructureObj SourceObj, SortedList<long, GridVector2> SourcePositions, long TargetStructID) { ConcurrentDictionary<long, LocationObj> LinkedLocationsOnSection; bool success = LocationsForStructure.TryGetValue(TargetStructID, out LinkedLocationsOnSection); if (success == false) return; SortedList<long, GridVector2> TargetPositions = new SortedList<long, GridVector2>(LinkedLocationsOnSection.Count); foreach (long locID in LinkedLocationsOnSection.Keys) { GridVector2 position; bool Success = TransformedLocationPositionDict.TryGetValue(locID, out position); if (Success) TargetPositions.Add(locID, position); } long BestSourceLocID = -1; long BestTargetLocID = -1; GridVector2 Origin = new GridVector2(); GridVector2 Destination = new GridVector2(); double MinDistance = double.MaxValue; //Brute force a search for the shortest distance between the two structures. foreach (long SourceID in SourcePositions.Keys) { GridVector2 SourcePos = SourcePositions[SourceID]; foreach (long TargetID in TargetPositions.Keys) { GridVector2 TargetPos = TargetPositions[TargetID]; double dist = GridVector2.Distance(SourcePos, TargetPos); if (dist < MinDistance) { BestSourceLocID = SourceID; BestTargetLocID = TargetID; Origin = SourcePos; Destination = TargetPos; MinDistance = dist; } } } //Could not find a pair if (MinDistance == double.MaxValue) return; StructureObj TargetStruct = Store.Structures.GetObjectByID(TargetStructID); GridLineSegment lineSegment = new GridLineSegment(Origin, Destination); StructureLinkObj StructLink = new StructureLinkObj(SourceObj.ID, TargetStructID, Locations[BestSourceLocID], Locations[BestTargetLocID], lineSegment); StructLink.AfterDelete += StructureLinkDeletedEventHandler; if (StructureLinksSearch.Contains(lineSegment)) { StructureLinkObj oldLink = StructureLinksSearch[lineSegment]; oldLink.AfterDelete -= StructureLinkDeletedEventHandler; StructureLinksSearch.Remove(lineSegment); } StructureLinksSearch.Add(lineSegment, StructLink); }
/// <summary> /// All locations which are linked get a line between them /// </summary> internal void RemoveLocationLinks(LocationObj obj) { foreach (long linkedID in obj.Links) { GridVector2 position; GridVector2 linkedPosition; bool success = TransformedLocationPositionDict.TryGetValue(obj.ID, out position); if (!success) continue; success = TransformedLocationPositionDict.TryGetValue(linkedID, out linkedPosition); if (!success) continue; GridLineSegment lineSegment = new GridLineSegment(position, linkedPosition); LocationLinkObj oldLink = null; success = LocationLinksSearch.TryRemove(lineSegment, out oldLink); if(success) { oldLink.OnAfterDelete -= LocationLinkDeletedEventHandler; } } }
/// <summary> /// All locations which are linked get a line between them /// </summary> internal void AddLocationLinks(LocationObj obj) { //Only add objects in the same section if (obj.Z != Section.Number) { return; } foreach (long linkedID in obj.Links) { GridVector2 position; GridVector2 linkedPosition; bool success = TransformedLocationPositionDict.TryGetValue(obj.ID, out position); if (!success) continue; success = TransformedLocationPositionDict.TryGetValue(linkedID, out linkedPosition); if (!success) continue; GridLineSegment lineSegment = new GridLineSegment(position, linkedPosition); LocationLinkObj locLink = new LocationLinkObj(obj, linkedID, lineSegment); locLink.OnAfterDelete += LocationLinkDeletedEventHandler; LocationLinkObj oldLink = null; success = LocationLinksSearch.TryRemove(lineSegment, out oldLink); if (oldLink != null) { oldLink.OnAfterDelete -= LocationLinkDeletedEventHandler; } success = LocationLinksSearch.TryAdd(lineSegment, locLink); } }
private bool AddLocationLinkToSectionSearchGrids(LocationObj AObj, LocationObj BObj, LocationLink linkView) { int minSection = AObj.Section < BObj.Section ? AObj.Section : BObj.Section; int maxSection = AObj.Section < BObj.Section ? BObj.Section : AObj.Section; GridLineSegment lineSegment = new GridLineSegment(AObj.VolumePosition, BObj.VolumePosition); bool success = false; //Add a grid line segment to each section the link intersects for (int iSection = minSection; iSection <= maxSection; iSection++) { //TODO: Check for missing sections! if (parent.Section.VolumeViewModel.SectionViewModels.ContainsKey(iSection) == false) continue; //int EstimatedLinks = Store.Locations.GetObjectsForSection(iSection).Count; //if (EstimatedLinks < 2000) int EstimatedLinks = 2500; LineSearchGrid<LocationLink> searchGrid = GetOrAddSearchGrid(iSection, EstimatedLinks); // Debug.WriteLine(iSection.ToString() + " add : " + linkView.ToString() + " " + searchGrid.Count.ToString()); //Debug.Assert(false == searchGrid.Contains(linkView)); bool sectionSuccess = searchGrid.TryAdd(lineSegment, linkView); success = success || sectionSuccess; //I had this on one line, but short-circuit logic had me beating my head against the wall for too long //Debug.Assert(success); } return success; }