public IAvidMark AddMark(int categoryId, string text, bool visible, bool underlined, AvidWindow position) { var newMark = new AvidMarkViewModel(this, text, visible, underlined, categoryId, -1, position); _marks.Add(newMark); RecalculateSharing(); return newMark; }
private void ProcessLaunchWindowSelection(AvidWindow result) { if (result != null) { // Overwriting all previous launch windows. PrepareWindowList(new[] { result }); } }
public int GetCourseOffset(AvidWindow targetVector, AvidWindow crossingVector) { if (AvidWindow.IsNullOrZero(targetVector) || AvidWindow.IsNullOrZero(crossingVector)) { return(6); } return(CountWindows(targetVector, crossingVector)); }
public void UpdateVector(AvidVector vector, bool isVisible) { IsVisible = !AvidWindow.IsNullOrZero(vector) && isVisible; Magnitude = vector != null ? vector.Magnitude : 0; Window = vector; OnPropertyChanged(Properties.IsVisible); OnPropertyChanged(Properties.Magnitude); OnPropertyChanged(Properties.Window); }
public AvidMarkViewModel(IMarkArranger markArranger, string text, bool visible, bool underlined, int categoryId, int sharingPosition, AvidWindow window) { _markArranger = markArranger; Text = text; Underlined = underlined; Visible = visible; CategoryId = categoryId; SharingPosition = sharingPosition; Window = window; }
private double CalculateWindowCenter(AvidWindow window) { double angle = _avidCalculator.DirectionToAngle(window.Direction); var length = (int)(RingWidth * GetAvidRingProjectionNumber(window.Ring)); double coordinate = Axis == ConversionAxis.AxisY ? CanvasSize / 2d - (length * Math.Sin(angle)) : CanvasSize / 2d + (length * Math.Cos(angle)); return coordinate; }
public LaunchWindowViewModel(AvidWindow window) { if (window == null) { throw new ArgumentException(Resources.LaunchWindowViewModel_WindowMustBeValid, "window"); } _window = window; ReferenceDirection = AvidDirection.Undefined; }
private double CalculateCoordinate(AvidWindow window) { double angle = _avidCalculator.DirectionToAngle(window.Direction); int length = RingRadius * GetAvidRingProjectionNumber(window.Ring); double coordinate = Axis == ConversionAxis.AxisY ? CanvasSize / 2d - (length * Math.Sin(angle)) : CanvasSize / 2d + (length * Math.Cos(angle)); return coordinate - ElementRadius / 2d; }
private double CalculateCoordinate(AvidWindow window) { double angle = _avidCalculator.DirectionToAngle(window.Direction); int length = RingRadius * GetAvidRingProjectionNumber(window.Ring); double coordinate = Axis == ConversionAxis.AxisY ? CanvasSize / 2d - (length * Math.Sin(angle)) : CanvasSize / 2d + (length * Math.Cos(angle)); return(coordinate - ElementRadius / 2d); }
private double CalculateWindowCenter(AvidWindow window) { double angle = _avidCalculator.DirectionToAngle(window.Direction); var length = (int)(RingWidth * GetAvidRingProjectionNumber(window.Ring)); double coordinate = Axis == ConversionAxis.AxisY ? CanvasSize / 2d - (length * Math.Sin(angle)) : CanvasSize / 2d + (length * Math.Cos(angle)); return(coordinate); }
private AvidWindow Vector3ToAvid(Vector3 vector) { var result = new AvidWindow { Ring = CoordinateToRing(vector.Z) }; result.Direction = result.Ring != AvidRing.Magenta ? GetDirection(vector) : AvidDirection.Undefined; result.AbovePlane = vector.Z >= 0 || result.Ring == AvidRing.Ember; return(result); }
public void Initialize(IUnitModel target, IShellstarModel shellstar, AvidWindow[] launchWindows) { UnsubscribeFromEvents(); _target = target; _shellstar = shellstar; CanAttach = GetCanAttachShellstar(); Caption = GetCaption(); IsDataAvailable = GetIsDataAvailable(); string targetName = _target != null ? _target.Name : string.Empty; _shellstarViewModel.Initialize(shellstar, targetName); _launchWindowControlViewModel.Initialize(_shellstar != null ? _shellstar.EvasionInfo : null, launchWindows); SubscribeToEvents(); }
public AvidOrientation GetOrientationWithoutRoll(AvidWindow nose, AvidDirection referenceDirection) { Vector3 vectorX = WindowToVector3(nose); var axis = _vectorLibrary.GetLocalAxis(vectorX, 0d, DirectionToAngle(referenceDirection)); var result = new AvidOrientation { Nose = Vector3ToAvid(axis[0]), Starboard = Vector3ToAvid(axis[1]), Top = Vector3ToAvid(axis[2]), }; result.Aft = GetOppositeWindow(result.Nose); result.Port = GetOppositeWindow(result.Starboard); result.Bottom = GetOppositeWindow(result.Top); return(result); }
private void CreateOrUpdateVector(AvidVector originalVector, ref IAvidMark targetVector, int categoryId, bool underlined) { string markText = originalVector != null?originalVector.Magnitude.ToString("D") : string.Empty; AvidWindow position = originalVector ?? new AvidWindow(); if (targetVector == null) { targetVector = _elementBoard.AddMark(categoryId, markText, originalVector != null, underlined, position); } else { targetVector.Text = markText; targetVector.Window = position; targetVector.Visible = !AvidWindow.IsNullOrZero(position); } }
public void RotationRingCalculationTest4() { var axis = new AvidWindow(AvidDirection.B, AvidRing.Blue, true); var result = ServiceFactory.Library.AvidCalculator.GetRotationCircleFromNormal(axis); TestChecksUtility.CheckAvidWindow(result[0], AvidDirection.E, AvidRing.Green, true); TestChecksUtility.CheckAvidWindow(result[1], AvidDirection.D, AvidRing.Green, true); TestChecksUtility.CheckAvidWindow(result[2], AvidDirection.CD, AvidRing.Blue, true); TestChecksUtility.CheckAvidWindow(result[3], AvidDirection.CD, AvidRing.Ember, true); TestChecksUtility.CheckAvidWindow(result[4], AvidDirection.CD, AvidRing.Blue, false); TestChecksUtility.CheckAvidWindow(result[5], AvidDirection.C, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[6], AvidDirection.B, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[7], AvidDirection.A, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[8], AvidDirection.FA, AvidRing.Blue, false); TestChecksUtility.CheckAvidWindow(result[9], AvidDirection.FA, AvidRing.Ember, true); TestChecksUtility.CheckAvidWindow(result[10], AvidDirection.FA, AvidRing.Blue, true); TestChecksUtility.CheckAvidWindow(result[11], AvidDirection.F, AvidRing.Green, true); }
public void UpdateDirections(AvidWindow launchWindow, AvidDirection referenceDirection) { if (AvidWindow.IsNullOrZero(launchWindow) || (launchWindow.Ring == AvidRing.Magenta && referenceDirection == AvidDirection.Undefined)) { ResetEvasionInfo(); return; } var impactWindow = _avidCalculator.GetOppositeWindow(launchWindow); var axis = _avidCalculator.GetOrientationWithoutRoll(impactWindow, referenceDirection); ImpactWindow = axis.Nose; EvasionUp = axis.Top; EvasionDown = axis.Bottom; EvasionLeft = axis.Port; EvasionRight = axis.Starboard; OnEvasionChanged(); }
public void SubmitBearingVerificationResult(AvidWindow verificationResult) { if (verificationResult == null) { OnVerificationRequired(); return; } var vectorResult = verificationResult as AvidVector; int magnitude = vectorResult != null ? vectorResult.Magnitude : 0; TargetDistance = new AvidVector(verificationResult.Direction, verificationResult.Ring, verificationResult.AbovePlane, magnitude); CourseOffset = _avidCalculator.GetCourseOffset(TargetDistance, CrossingVector); OnVectorsUpdated(); UpdateFiringSolution(null, null, null); }
public void RotationRingCalculationTest5() { var axis = new AvidWindow(AvidDirection.CD, AvidRing.Blue, false); var result = ServiceFactory.Library.AvidCalculator.GetRotationCircleFromNormal(axis); TestChecksUtility.CheckAvidWindow(result[0], AvidDirection.CD, AvidRing.Green, true); TestChecksUtility.CheckAvidWindow(result[1], AvidDirection.DE, AvidRing.Green, true); TestChecksUtility.CheckAvidWindow(result[2], AvidDirection.E, AvidRing.Blue, true); TestChecksUtility.CheckAvidWindow(result[3], AvidDirection.E, AvidRing.Ember, true); TestChecksUtility.CheckAvidWindow(result[4], AvidDirection.E, AvidRing.Blue, false); TestChecksUtility.CheckAvidWindow(result[5], AvidDirection.EF, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[6], AvidDirection.FA, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[7], AvidDirection.AB, AvidRing.Green, false); TestChecksUtility.CheckAvidWindow(result[8], AvidDirection.B, AvidRing.Blue, false); TestChecksUtility.CheckAvidWindow(result[9], AvidDirection.B, AvidRing.Ember, true); TestChecksUtility.CheckAvidWindow(result[10], AvidDirection.B, AvidRing.Blue, true); TestChecksUtility.CheckAvidWindow(result[11], AvidDirection.BC, AvidRing.Green, true); }
public void OppositeWindowTest() { var window = new AvidWindow(AvidDirection.A, AvidRing.Ember, true); var result = ServiceFactory.Library.AvidCalculator.GetOppositeWindow(window); TestChecksUtility.CheckAvidWindow(result, AvidDirection.D, AvidRing.Ember, true); window.Direction = AvidDirection.Undefined; window.Ring = AvidRing.Magenta; result = ServiceFactory.Library.AvidCalculator.GetOppositeWindow(window); TestChecksUtility.CheckAvidWindow(result, AvidDirection.Undefined, AvidRing.Magenta, false); window.Direction = AvidDirection.BC; window.Ring = AvidRing.Blue; window.AbovePlane = false; result = ServiceFactory.Library.AvidCalculator.GetOppositeWindow(window); TestChecksUtility.CheckAvidWindow(result, AvidDirection.EF, AvidRing.Blue, true); }
private object AcquireReferenceDirectionContext() { if (_selectedWindow == null) { throw new NullReferenceException("Direction selection was called while the window is not yet selected."); } string comment = string.Format("Please select reference direction for the launch window {0}.{1}Per F1.253, this direction should be the same as the direction of the target's top marker, or nose marker if the former is in the magenta ring.", _selectedWindow.Name, Environment.NewLine); var window = new AvidWindow(_selectedWindow.ReferenceDirection != AvidDirection.Undefined ? _selectedWindow.ReferenceDirection : AvidDirection.A, AvidRing.Ember, true); return(new WindowSelectionContext { CanSelectDirection = true, CanSelectRing = false, InitialWindow = window, Caption = "Select reference direction", Message = comment }); }
public AvidWindow[] GetRotationCircleFromNormal(AvidWindow rotationAxis) { bool adjustmentNeeded = rotationAxis.Ring == AvidRing.Blue || rotationAxis.Ring == AvidRing.Green; Vector3 axisVector = WindowToVector3(rotationAxis); var localAxis = _vectorLibrary.GetLocalAxis(axisVector, adjustmentNeeded ? Consts.RotationAdjustmentAngle : 0d, 0d); axisVector = localAxis[0]; Vector3 upVector = localAxis[2]; var result = new AvidWindow[12]; //There are always 12 windows if the rotation circle is continuous. for (int i = 0; i < 12; i++) { //Rotation is always clockwise. Vector3 rotatedAxis = _vectorLibrary.RotateVectorAroundAxis(upVector, axisVector, -i * Math.PI / 6d); result[i] = Vector3ToAvid(rotatedAxis); } return(result); }
public AvidPathfindingResult GetShortestPaths(AvidModel model, AvidWindow start, AvidWindow destination, AvidPathingOptions options) { AvidModelWindow startWnd = model.ProjectWindow(start); AvidModelWindow destinationWnd = model.ProjectWindow(destination); InitializeNodes(model, startWnd, destinationWnd); var validLeaves = BuildTree(startWnd, destinationWnd, options); var result = new AvidPathfindingResult { PathExists = validLeaves.Length > 0 }; if (result.PathExists) { result.MinimalDistance = validLeaves[0].NodeDistance; result.AllShortestPaths.AddRange(validLeaves.Select(lf => TracePath(lf, startWnd, destinationWnd))); } return(result); }
public AvidPathfindingResult GetShortestPaths(AvidModel model, AvidWindow start, AvidWindow destination, AvidPathingOptions options) { AvidModelWindow startWnd = model.ProjectWindow(start); AvidModelWindow destinationWnd = model.ProjectWindow(destination); InitializeNodes(model, startWnd, destinationWnd); var validLeaves = BuildTree(startWnd, destinationWnd, options); var result = new AvidPathfindingResult { PathExists = validLeaves.Length > 0 }; if (result.PathExists) { result.MinimalDistance = validLeaves[0].NodeDistance; result.AllShortestPaths.AddRange(validLeaves.Select(lf => TracePath(lf, startWnd, destinationWnd))); } return result; }
public int CountWindows(AvidWindow start, AvidWindow destination) { if (start.Equals(destination) || AvidWindow.IsNullOrZero(start) || AvidWindow.IsNullOrZero(destination)) { return(0); } var pathingResult = _avidPathfinder.GetShortestPaths(_avidModel, start, destination, AvidPathingOptions.DiagonalTransitionsLimitWithPolar); if (!pathingResult.PathExists) { throw new Exception("Failed to find path from start to destination. That must be the problem with the algorithm."); } if (Math.Abs(pathingResult.MinimalDistance - GetDistanceFromAngle(start, destination) * 2) > 1) { //throw new Exception("Distance inconsistent."); } // Since all normal transitions on the avid are two points, we need to halve the result. return(pathingResult.MinimalDistance / 2); }
public AvidWindow GetOppositeWindow(AvidWindow window) { var oppositeDirection = window.Direction == AvidDirection.Undefined ? window.Direction : (AvidDirection)((((byte)window.Direction) + 5) % 12 + 1); return(new AvidWindow(oppositeDirection, window.Ring, window.Ring == AvidRing.Ember || !window.AbovePlane)); }
public AvidOrientation GetOrientation(AvidWindow nose, AvidWindow top) { throw new NotImplementedException(); }
public AvidWindow[] GetPossibleLaunchWindows(int courseOffset, AvidWindow targetWindow, AvidWindow crossingVector) { if (AvidWindow.IsNullOrZero(targetWindow)) { return(new[] { GetOppositeWindow(crossingVector) }); //This may still result in undefined vector if both are zero. // This is fine. If both ships aren't moving and sit in the same hex, launch window can't be determined. This situation should // not arise in any real scenario, but we still need to handle it. } if (courseOffset == 0 || targetWindow.Equals(crossingVector) || AvidWindow.IsNullOrZero(crossingVector)) { return(new [] { targetWindow }); } var pathingResult = _avidPathfinder.GetShortestPaths(_avidModel, targetWindow, crossingVector, AvidPathingOptions.DiagonalTransitionsLimitWithPolar); if (!pathingResult.PathExists) { return(new AvidWindow[] { }); } return(pathingResult.AllShortestPaths.Select(pi => pi.PathNodes[courseOffset]) .Where(lan => lan.Window.MinDistance >= lan.NodeDistance) // This is to exclude windows, that could be reached through diagonal transition // but can also reached by two non-diagonal transitions. So, in the final result for course offset = 2, it would look like two windows .Select(lan => (AvidWindow)lan.Window).Distinct().ToArray()); }
/// <summary> /// This method is needed because we have to ignore position relative to the plane of AVID when calculating shering. /// Ex. F+ and F- are still in the same window on AVID. /// </summary> private int GetWindowCode(AvidWindow window) { return(10 * (byte)window.Direction + (byte)window.Ring); }
private static void CreateLoadSitRepMappings() { Mapper.CreateMap <HexVectorComponentSto, HexVectorComponent>() .ForMember(hvc => hvc.Direction, ac => ac.MapFrom(vcs => Enum.Parse(typeof(HexAxis), vcs.Direction))) .ForMember(hvc => hvc.Magnitude, ac => ac.MapFrom(vcs => vcs.Value)); Mapper.CreateMap <HexVectorSto, RawHexVector>() .ForMember(hvc => hvc.Components, ac => ac.Ignore()) .AfterMap((hvs, rhv) => rhv.AddComponents(Mapper.Map <IEnumerable <HexVectorComponentSto>, IEnumerable <HexVectorComponent> >(hvs.Components))); Mapper.CreateMap <ImpulseRecordSto, ImpulseTrackElement>() .ForMember(ite => ite.Impulse, ac => ac.MapFrom(irs => TurnData.Parse(irs.Impulse))); Mapper.CreateMap <ShellstarSto, ShellstarInfo>(); Mapper.CreateMap <UnitSto, UnitModel>() .ForMember(um => um.Position, ac => ac.MapFrom(uns => HexGridCoordinate.Parse(uns.Position))) .ForMember(um => um.Vectors, ac => ac.MapFrom(uns => uns.Velocity)) .AfterMap((uns, um) => uns.IncomingProjectiles.ForEach(st => { var evasionInfo = new EvasionInfoModel(AvidWindow.Parse(st.EvasionInfo.ImpactWindow), AvidWindow.Parse(st.EvasionInfo.EvasionUp).Direction); var shellstarModel = new ShellstarModel(Mapper.Map <ShellstarSto, ShellstarInfo>(st), TurnData.Parse(st.SegmentOfLaunch), evasionInfo); shellstarModel.Tag = st.Tag; um.AttachShellstar(shellstarModel); })); }
public int CountWindows(AvidWindow start, AvidWindow destination) { if (start.Equals(destination) || AvidWindow.IsNullOrZero(start) || AvidWindow.IsNullOrZero(destination)) { return 0; } var pathingResult = _avidPathfinder.GetShortestPaths(_avidModel, start, destination, AvidPathingOptions.DiagonalTransitionsLimitWithPolar); if (!pathingResult.PathExists) { throw new Exception("Failed to find path from start to destination. That must be the problem with the algorithm."); } if (Math.Abs(pathingResult.MinimalDistance - GetDistanceFromAngle(start, destination) * 2) > 1) { //throw new Exception("Distance inconsistent."); } // Since all normal transitions on the avid are two points, we need to halve the result. return pathingResult.MinimalDistance / 2; }
public AvidMarkViewModel() { _window = new AvidWindow(); }
public AvidModelWindow ProjectWindow(AvidWindow window) { return Windows.Single(amw => amw.Equals(window)); }
public EvasionInfoModel(AvidWindow impactWindow, AvidDirection referenceDirection) { _avidCalculator = ServiceFactory.Library.AvidCalculator; UpdateDirections(_avidCalculator.GetOppositeWindow(impactWindow), referenceDirection); }
private object AcquireReferenceDirectionContext() { if (_selectedWindow == null) { throw new NullReferenceException("Direction selection was called while the window is not yet selected."); } string comment = string.Format("Please select reference direction for the launch window {0}.{1}Per F1.253, this direction should be the same as the direction of the target's top marker, or nose marker if the former is in the magenta ring.", _selectedWindow.Name, Environment.NewLine); var window = new AvidWindow(_selectedWindow.ReferenceDirection != AvidDirection.Undefined ? _selectedWindow.ReferenceDirection : AvidDirection.A, AvidRing.Ember, true); return new WindowSelectionContext { CanSelectDirection = true, CanSelectRing = false, InitialWindow = window, Caption = "Select reference direction", Message = comment }; }
public AvidWindow GetOppositeWindow(AvidWindow window) { var oppositeDirection = window.Direction == AvidDirection.Undefined ? window.Direction : (AvidDirection)((((byte)window.Direction) + 5) % 12 + 1); return new AvidWindow(oppositeDirection, window.Ring, window.Ring == AvidRing.Ember || !window.AbovePlane); }
private void ProcessReferenceDirectionSelection(AvidWindow result) { _evasionInfo.UpdateDirections(SelectedWindow.Window, result.Direction); _selectedWindow.ReferenceDirection = result.Direction; }
public IAvidMark AddMark(int categoryId, string text, bool visible, bool underlined, AvidWindow position) { var newMark = new AvidMarkViewModel(this, text, visible, underlined, categoryId, -1, position); _marks.Add(newMark); RecalculateSharing(); return(newMark); }
public void Initialize(IEvasionInfoModel evasionInfo, AvidWindow[] availableWindows) { _evasionInfo = evasionInfo; PrepareWindowList(availableWindows); }
public AvidOrientation GetOrientationWithoutRoll(AvidWindow nose, AvidDirection referenceDirection) { Vector3 vectorX = WindowToVector3(nose); var axis = _vectorLibrary.GetLocalAxis(vectorX, 0d, DirectionToAngle(referenceDirection)); var result = new AvidOrientation { Nose = Vector3ToAvid(axis[0]), Starboard = Vector3ToAvid(axis[1]), Top = Vector3ToAvid(axis[2]), }; result.Aft = GetOppositeWindow(result.Nose); result.Port = GetOppositeWindow(result.Starboard); result.Bottom = GetOppositeWindow(result.Top); return result; }
public AvidWindow[] GetRotationCircleFromNormal(AvidWindow rotationAxis) { bool adjustmentNeeded = rotationAxis.Ring == AvidRing.Blue || rotationAxis.Ring == AvidRing.Green; Vector3 axisVector = WindowToVector3(rotationAxis); var localAxis = _vectorLibrary.GetLocalAxis(axisVector, adjustmentNeeded ? Consts.RotationAdjustmentAngle : 0d, 0d); axisVector = localAxis[0]; Vector3 upVector = localAxis[2]; var result = new AvidWindow[12]; //There are always 12 windows if the rotation circle is continuous. for (int i = 0; i < 12; i++) { //Rotation is always clockwise. Vector3 rotatedAxis = _vectorLibrary.RotateVectorAroundAxis(upVector, axisVector, -i * Math.PI / 6d); result[i] = Vector3ToAvid(rotatedAxis); } return result; }
public int GetDistanceFromAngle(AvidWindow a, AvidWindow b) { return((int)(6 * _vectorLibrary.GetAngleBetweenVectors(WindowToVector3(a), WindowToVector3(b)) / Math.PI)); }
private AvidWindow Vector3ToAvid(Vector3 vector) { var result = new AvidWindow { Ring = CoordinateToRing(vector.Z) }; result.Direction = result.Ring != AvidRing.Magenta ? GetDirection(vector) : AvidDirection.Undefined; result.AbovePlane = vector.Z >= 0 || result.Ring == AvidRing.Ember; return result; }
public int GetDistanceFromAngle(AvidWindow a, AvidWindow b) { return (int)(6 * _vectorLibrary.GetAngleBetweenVectors(WindowToVector3(a), WindowToVector3(b)) / Math.PI); }
/// <summary> /// This method is needed because we have to ignore position relative to the plane of AVID when calculating shering. /// Ex. F+ and F- are still in the same window on AVID. /// </summary> private int GetWindowCode(AvidWindow window) { return 10 * (byte)window.Direction + (byte)window.Ring; }
public int GetCourseOffset(AvidWindow targetVector, AvidWindow crossingVector) { if (AvidWindow.IsNullOrZero(targetVector) || AvidWindow.IsNullOrZero(crossingVector)) { return 6; } return CountWindows(targetVector, crossingVector); }
private Vector3 WindowToVector3(AvidWindow rotationAxis) { double angleA = DirectionToAngle(rotationAxis.Direction); double angleB = rotationAxis.AbovePlane ? RingToLatitude(rotationAxis.Ring) : 2 * Math.PI - RingToLatitude(rotationAxis.Ring); return new Vector3(Math.Cos(angleA) * Math.Cos(angleB), Math.Sin(angleA) * Math.Cos(angleB), Math.Sin(angleB)); }
public static bool IsNullOrZero(AvidVector vector) { return(AvidWindow.IsNullOrZero(vector) || vector.Magnitude == 0); }
public static void CheckAvidWindow(AvidWindow window, AvidDirection expectedDirection, AvidRing expectedRing, bool abovePlane) { window.Direction.Should().Be(expectedDirection); window.Ring.Should().Be(expectedRing); window.AbovePlane.Should().Be(abovePlane); }
public AvidWindow[] GetPossibleLaunchWindows(int courseOffset, AvidWindow targetWindow, AvidWindow crossingVector) { if (AvidWindow.IsNullOrZero(targetWindow)) { return new[] { GetOppositeWindow(crossingVector) }; //This may still result in undefined vector if both are zero. // This is fine. If both ships aren't moving and sit in the same hex, launch window can't be determined. This situation should // not arise in any real scenario, but we still need to handle it. } if (courseOffset == 0 || targetWindow.Equals(crossingVector) || AvidWindow.IsNullOrZero(crossingVector)) { return new [] { targetWindow }; } var pathingResult = _avidPathfinder.GetShortestPaths(_avidModel, targetWindow, crossingVector, AvidPathingOptions.DiagonalTransitionsLimitWithPolar); if (!pathingResult.PathExists) { return new AvidWindow[] { }; } return pathingResult.AllShortestPaths.Select(pi => pi.PathNodes[courseOffset]) .Where(lan => lan.Window.MinDistance >= lan.NodeDistance) // This is to exclude windows, that could be reached through diagonal transition // but can also reached by two non-diagonal transitions. So, in the final result for course offset = 2, it would look like two windows .Select(lan => (AvidWindow)lan.Window).Distinct().ToArray(); }