/// <summary>
        /// If the a ship's bearing to a given position is less than 90 degrees away from exact heading needed to get to the port,
        /// Then we says that a ship is moving toward that port
        /// </summary>
        /// <param name="shipTest">shipTest object</param>
        /// <param name="position">Location of port that ship may be moving toward</param>
        /// <returns>true or false</returns>
        public static bool IsMovingToward(this ShipTest shipTest, Position position)
        {
            var bearing    = GeoHelper.GetBearing(shipTest.Position, position);
            var difference = Math.Abs(shipTest.Heading - bearing);

            return(difference <= 90);
        }
        /// <summary>
        /// Does the ship's heading put it on course to enter Duluth Canal?
        /// Ships report numerous false destinations. Therefore, we use this method
        /// to check a ship's actual heading against the bearing to the two nearest ports
        /// and make a determination whether or not the ship will actually use Duluth Canal
        /// </summary>
        /// <param name="shipTest">shipTest object</param>
        /// <returns>true or false</returns>
        public static bool IsHeadingTowardDuluth(this ShipTest shipTest)
        {
            var twoNearestPortsAndBearing = Ports.All.Select(p => {
                var bearing    = GeoHelper.GetBearing(shipTest.Position, p);
                var adjustment = Math.Abs(bearing - shipTest.Heading);
                if (adjustment > 180)
                {
                    adjustment = 360 - adjustment;
                }
                return(new {
                    Position = p,
                    Bearing = bearing,
                    Adjustment = adjustment
                });
            }).OrderBy(
                p => p.Adjustment
                ).Take(2).ToArray();

            var firstPort  = twoNearestPortsAndBearing[0];
            var secondPort = twoNearestPortsAndBearing[1];

            var portBearingDiff = Math.Abs(firstPort.Bearing - secondPort.Bearing);

            var weight = 1 / 2D;

            if (shipTest.Destination == firstPort.Position)
            {
                weight = 2 / 3D;
            }
            else if (shipTest.Destination == secondPort.Position)
            {
                weight = 1 / 3D;
            }

            var threshold = weight * portBearingDiff;

            Position nearestPort = null;

            if (firstPort.Adjustment <= threshold)
            {
                nearestPort = firstPort.Position;
            }
            else if (secondPort.Adjustment <= threshold)
            {
                nearestPort = secondPort.Position;
            }
            else if (shipTest.IsMovingToward(firstPort.Position))
            {
                nearestPort = firstPort.Position;
            }

            return(nearestPort == Ports.Duluth);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Method to populate a derived Eta for ships we deem will use Duluth Canal
        /// </summary>
        /// <param name="shipTest">ship test permutation</param>
        public static void Update(this ShipTest shipTest)
        {
            var inHarbor = shipTest.IsInDuluthSuperiorHarbor();

            if (inHarbor && !shipTest.CanalEntryTimestamp.HasValue)
            {
                shipTest.CanalEntryTimestamp = DateTime.UtcNow.AddHours(CanalEntryTimestampOffset);
            }
            else if (!inHarbor)
            {
                shipTest.CanalEntryTimestamp = null;
            }

            if (shipTest.IsUnderway())
            {
                if (shipTest.IsWithinFiftyMilesOfDuluth())
                {
                    if (shipTest.IsInDuluthSuperiorHarborForMoreThanHour())
                    {
                        if (shipTest.IsInStLouisBay())
                        {
                            shipTest.DerivedEta = CalculateEtaToDuluthFromStLouisBay(shipTest.Position, shipTest.Speed);
                        }
                        else if (shipTest.IsMovingTowardDuluth())
                        {
                            shipTest.DerivedEta = CalculateEtaToDuluth(shipTest.Position, shipTest.Speed);
                        }
                    }
                    else if (!inHarbor && shipTest.IsHeadingTowardDuluth())
                    {
                        shipTest.DerivedEta = CalculateEtaToDuluth(shipTest.Position, shipTest.Speed);
                    }
                }
                else if (shipTest.IsDestinationDuluth() && shipTest.IsMovingTowardDuluth())
                {
                    shipTest.DerivedEta = shipTest.Eta;
                }
            }
        }
        /// <summary>
        /// Evaluation method and logic. Similar to shipTest Processor logic
        /// First, only evaluate ship that report navigational status == underway
        /// Next, ask if ship is within 50 miles of the Duluth Harbor
        /// Locate ship inside or outside harbor
        /// For ships in the harbor, treat ships in St. Louis Bay differently than other ships
        /// For ships outside the harbor, populate derived eta according to bearing to nearest port
        /// </summary>
        /// <param name="shipTest">shipTest object</param>
        public static void Evaluate(ShipTest shipTest)
        {
            if (shipTest.IsUnderway())
            {
                if (shipTest.IsWithinFiftyMilesOfDuluth())
                {
                    if (shipTest.IsInDuluthSuperiorHarborForMoreThanHour())
                    {
                        shipTest.Evaluation = shipTest.IsInStLouisBay() || shipTest.IsMovingTowardDuluth();
                    }
                    else
                    {
                        shipTest.Evaluation = !shipTest.IsInDuluthSuperiorHarbor() && shipTest.IsHeadingTowardDuluth();
                    }
                }
                else
                {
                    shipTest.Evaluation = shipTest.IsDestinationDuluth() && shipTest.IsMovingTowardDuluth();
                }
            }

            shipTest.Evaluation = shipTest.Evaluation == shipTest.DerivedEta.HasValue;
            shipTest.Tally      = Convert.ToInt32(shipTest.Evaluation);
        }
 /// <summary>
 /// Has a ship been in the Duluth Superior Harbor for more than an hour?
 /// Reasoning: We use this test because ships have a variety of movements inside the harbor.
 /// If a ship has entered the harbor recently, we're going to ignore its movements for a certain length of time
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsInDuluthSuperiorHarborForMoreThanHour(this ShipTest shipTest)
 {
     return(shipTest.CanalEntryTimestamp.HasValue && shipTest.CanalEntryTimestamp < DateTime.UtcNow.AddHours(-1));
 }
 /// <summary>
 /// If the a ship's bearing to a given position is less than 90 degrees away from exact heading needed to get to the port,
 /// Then we says that a ship is moving toward that port
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsMovingTowardDuluth(this ShipTest shipTest)
 {
     return(shipTest.IsMovingToward(Ports.Duluth));
 }
 /// <summary>
 /// Is a ship reporting a destination of Duluth?
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsDestinationDuluth(this ShipTest shipTest)
 {
     return(shipTest.Destination == Ports.Duluth);
 }
 /// <summary>
 /// Is a ship within 50 miles of the Duluth Canal?
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsWithinFiftyMilesOfDuluth(this ShipTest shipTest)
 {
     return(GeoHelper.DistanceBetweenCoord(shipTest.Position, Ports.Duluth) <= 50);
 }
 /// <summary>
 /// Does the ship's reported navigational status contain the string "underway"?
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsUnderway(this ShipTest shipTest)
 {
     return(shipTest.NavigationalStatus == NavigationalStatus.Underway);
 }
 /// <summary>
 /// Is a ship located in St. Louis Bay?
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsInStLouisBay(this ShipTest shipTest)
 {
     return(GeoHelper.IsPointInPolygon(shipTest.Position, Areas.StLouisBay));
 }
 /// <summary>
 /// Uses point in polygon test to determine if a ship is located in the Duluth Superior Harbor
 /// </summary>
 /// <param name="shipTest">shipTest object</param>
 /// <returns>true or false</returns>
 public static bool IsInDuluthSuperiorHarbor(this ShipTest shipTest)
 {
     return(GeoHelper.IsPointInPolygon(shipTest.Position, Areas.DuluthSuperiorHarbor));
 }