public void Gradient() { var f = new PiecewiseLinearFunction <double>(new List <IVector <double> >() { new Vector <double>(1d), new Vector <double>(2d) }); var grad = f.Gradient(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(0.5d)); Assert.True(grad.Count == 6); Assert.True(grad.Skip(2).All(x => Math.Abs(x) < 1e-14)); Assert.True(Math.Abs(grad[0] - 0.5) < 1e-14); Assert.True(Math.Abs(grad[1] - 1) < 1e-14); grad = f.Gradient(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(1.5d)); Assert.True(grad.Count == 6); Assert.True(grad.Take(2).All(x => Math.Abs(x) < 1e-14)); Assert.True(grad.TakeLast(2).All(x => Math.Abs(x) < 1e-14)); Assert.True(Math.Abs(grad[2] - 1.5) < 1e-14); Assert.True(Math.Abs(grad[3] - 1) < 1e-14); grad = f.Gradient(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(3d)); Assert.True(grad.Count == 6); Assert.True(grad.Take(4).All(x => Math.Abs(x) < 1e-14)); Assert.True(Math.Abs(grad[4] - 3) < 1e-14); Assert.True(Math.Abs(grad[5] - 1) < 1e-14); grad = f.Gradient(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(2d)); Assert.True(grad.Count == 6); Assert.True(grad.Count == 6); Assert.True(grad.Take(4).All(x => Math.Abs(x) < 1e-14)); Assert.True(Math.Abs(grad[4] - 2) < 1e-14); Assert.True(Math.Abs(grad[5] - 1) < 1e-14); Assert.True(1e-14 > 6 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(new[] { 1d }))); grad = f.Gradient(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(1.5d)); Assert.True(grad.Count == 6); Assert.True(grad.Take(2).All(x => Math.Abs(x) < 1e-14)); Assert.True(grad.TakeLast(2).All(x => Math.Abs(x) < 1e-14)); Assert.True(Math.Abs(grad[2] - 1.5) < 1e-14); Assert.True(Math.Abs(grad[3] - 1) < 1e-14); }
public static BTStatus LandMovement(Animal agent, Vector2 direction, float speed, AnimalAnimationState state, float minDistance = 2f, float maxDistance = 20f, float minDirectionOffsetDegrees = 0, float maxDirectionOffsetDegrees = 360, int tryCount = 10) { var search = AIUtilities.FindRoute(agent.Position, 2f, 20f, direction); if (search != null) { var smoothed = search.LineOfSightSmooth(agent.Position); PiecewiseLinearFunction route = AIUtilities.ProjectRoute(smoothed, speed); agent.NextTick = WorldTime.Seconds + route.EndTime; agent.Target.SetPath(route); agent.AnimationState = state; return BTStatus.Success; } else return LandAnimalUnStuckOrDie(agent, speed, state); }
internal void GetMembership_WithVariousInputs_ReturnsExpectedResult(double x, double expected) { // Arrange var points = new FuzzyPoint[] { new FuzzyPoint(2, 0.5), new FuzzyPoint(3, 1) }; var function = new PiecewiseLinearFunction(points); // Act var result = function.GetMembership(x); // Assert Assert.Equal(UnitInterval.Create(expected), result); }
public static BTStatus AmphibiousMovement(Animal agent, Vector2 generalDirection, float speed, AnimalAnimationState state, float minDistance = 2f, float maxDistance = 20f) { var start = agent.Position.WorldPosition3i; if (!World.World.IsUnderwater(start)) start = RouteManager.NearestWalkableY(agent.Position.WorldPosition3i); if (!start.IsValid) return LandMovement(agent, generalDirection, speed, state, minDistance, maxDistance); if (generalDirection == Vector2.zero) generalDirection = Vector2.right.Rotate(RandomUtil.Range(0f, 360)); else generalDirection = generalDirection.Normalized; var target = (agent.Position + (generalDirection * RandomUtil.Range(minDistance, maxDistance)).X_Z()).WorldPosition3i; if (World.World.IsUnderwater(target)) target.y = World.World.MaxWaterHeight[target]; else target = RouteManager.NearestWalkableXYZ(target, 5); // This is a low-effort search that includes water surface and should occasionally fail, just pick a semi-random node that was visited when it fails var allowWaterSearch = new AStarSearch(RouteCacheData.NeighborsIncludeWater, start, target, 30); if (allowWaterSearch.Status != SearchStatus.PathFound) { target = allowWaterSearch.Nodes.Last().Key; allowWaterSearch.GetPath(target); } if (allowWaterSearch.Path.Count < 2) return BTStatus.Failure; else if (allowWaterSearch.Status == SearchStatus.Unpathable && allowWaterSearch.Nodes.Count < RouteRegions.MinimumRegionSize && !World.World.IsUnderwater(agent.Position.WorldPosition3i)) { // Search region was unexpectedly small and agent is on land, might be trapped by player construction. // Try regular land movement so region checks can apply & the agent can get unstuck (or die) return LandMovement(agent, generalDirection, speed, state, minDistance, maxDistance); } var smoothed = allowWaterSearch.LineOfSightSmooth(agent.Position); PiecewiseLinearFunction route = AIUtilities.ProjectRoute(smoothed, speed); agent.AnimationState = state; agent.NextTick = WorldTime.Seconds + route.EndTime; agent.Target.SetPath(route); return BTStatus.Success; }
internal void LowerBound_ReturnsExpectedResult() { // Arrange // Arrange var points = new FuzzyPoint[] { new FuzzyPoint(2, 0.5), new FuzzyPoint(3, 1) }; var function = new PiecewiseLinearFunction(points); // Act var result = function.LowerBound; // Assert Assert.Equal(2, result); }
internal void MaxY_ReturnsExpectedResult() { // Arrange // Arrange var points = new FuzzyPoint[] { new FuzzyPoint(2, 0), new FuzzyPoint(3, 1) }; var function = new PiecewiseLinearFunction(points); // Act var result = function.MaxY; // Assert Assert.Equal(UnitInterval.One(), result); }
public void Value() { var f = new PiecewiseLinearFunction <double>(new List <IVector <double> >() { new Vector <double>(1d), new Vector <double>(2d) }); Assert.True(1e-14 > Math.Abs(0 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(0.5d)))); Assert.True(1e-14 > Math.Abs(7.5 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(1.5d)))); Assert.True(1e-14 > Math.Abs(40 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(3d)))); Assert.True(1e-14 > Math.Abs(30 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(new[] { 2d })))); Assert.True(1e-14 > Math.Abs(6 - f.Value(new Vector <double>(new[] { 0d, 0d, 3d, 3d, 10d, 10d }), new Vector <double>(new[] { 1d })))); }
public ContourAnimationInfo getContourAnimations(ContourQuery contourQuery) { List <List <TrendingDataLocation> > frames = GetFramesFromHistorian(contourQuery); PiecewiseLinearFunction colorScale = GetColorScale(contourQuery); Func <double, double> colorFunc = colorScale; // The actual startDate is the timestamp of the // first frame after contourQuery.GetStartDate() DateTime startDate = contourQuery.GetStartDate(); int stepSize = contourQuery.StepSize; int startTimeOffset = (int)Math.Ceiling((startDate - startDate.Date).TotalMinutes / stepSize); startDate = startDate.Date.AddMinutes(startTimeOffset * stepSize); double latDif = frames.Min(frame => frame.Max(location => location.Latitude)) - frames.Min(frame => frame.Min(location => location.Latitude)); double lonDif = frames.Min(frame => frame.Max(location => location.Longitude)) - frames.Min(frame => frame.Min(location => location.Longitude)); double minLat = frames.Min(frame => frame.Min(location => location.Latitude)) - (latDif * 0.1D); double maxLat = frames.Min(frame => frame.Max(location => location.Latitude)) + (latDif * 0.1D); double minLng = frames.Min(frame => frame.Min(location => location.Longitude)) - (lonDif * 0.1D); double maxLng = frames.Min(frame => frame.Max(location => location.Longitude)) + (lonDif * 0.1D); GeoCoordinate topLeft = new GeoCoordinate(maxLat, minLng); GeoCoordinate bottomRight = new GeoCoordinate(minLat, maxLng); GSF.Drawing.Point topLeftPoint = s_crs.Translate(topLeft, contourQuery.Resolution); GSF.Drawing.Point bottomRightPoint = s_crs.Translate(bottomRight, contourQuery.Resolution); topLeftPoint = new GSF.Drawing.Point(Math.Floor(topLeftPoint.X), Math.Floor(topLeftPoint.Y)); bottomRightPoint = new GSF.Drawing.Point(Math.Ceiling(bottomRightPoint.X), Math.Ceiling(bottomRightPoint.Y)); topLeft = s_crs.Translate(topLeftPoint, contourQuery.Resolution); bottomRight = s_crs.Translate(bottomRightPoint, contourQuery.Resolution); int width = (int)(bottomRightPoint.X - topLeftPoint.X + 1); int height = (int)(bottomRightPoint.Y - topLeftPoint.Y + 1); int animationID; string timeZoneID = null; using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter))) { connection.ExecuteNonQuery("INSERT INTO ContourAnimation(ColorScaleName, StartTime, EndTime, StepSize) VALUES({0}, {1}, {2}, {3})", contourQuery.ColorScaleName, contourQuery.GetStartDate(), contourQuery.GetEndDate(), contourQuery.StepSize); animationID = connection.ExecuteScalar <int>("SELECT @@IDENTITY"); if (contourQuery.IncludeWeather) { timeZoneID = connection.ExecuteScalar <string>("SELECT Value FROM Setting WHERE Name = 'XDATimeZone'"); } } GSF.Threading.CancellationToken cancellationToken = new GSF.Threading.CancellationToken(); s_cancellationTokens[animationID] = cancellationToken; ProgressCounter progressCounter = new ProgressCounter(frames.Count); s_progressCounters[animationID] = progressCounter; Action <int> createFrame = i => { List <TrendingDataLocation> frame = frames[i]; IDWFunc idwFunction = GetIDWFunction(contourQuery, frame); uint[] pixelData; if (contourQuery.IncludeWeather) { TimeZoneInfo tzInfo = !string.IsNullOrEmpty(timeZoneID) ? TimeZoneInfo.FindSystemTimeZoneById(timeZoneID) : TimeZoneInfo.Local; // Weather data is only available in 5-minute increments DateTime frameTime = TimeZoneInfo.ConvertTimeToUtc(startDate.AddMinutes(stepSize * i), tzInfo); double minutes = (frameTime - frameTime.Date).TotalMinutes; int weatherMinutes = (int)Math.Ceiling(minutes / 5) * 5; NameValueCollection queryString = HttpUtility.ParseQueryString(string.Empty); queryString["service"] = "WMS"; queryString["request"] = "GetMap"; queryString["layers"] = "nexrad-n0r-wmst"; queryString["format"] = "image/png"; queryString["transparent"] = "true"; queryString["version"] = "1.1.1"; queryString["time"] = frameTime.Date.AddMinutes(weatherMinutes).ToString("o"); queryString["height"] = height.ToString(); queryString["width"] = width.ToString(); queryString["srs"] = "EPSG:3857"; GSF.Drawing.Point topLeftProjected = s_crs.Projection.Project(topLeft); GSF.Drawing.Point bottomRightProjected = s_crs.Projection.Project(bottomRight); queryString["bbox"] = string.Join(",", topLeftProjected.X, bottomRightProjected.Y, bottomRightProjected.X, topLeftProjected.Y); string weatherURL = "http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r-t.cgi?" + queryString.ToString(); using (WebClient client = new WebClient()) using (MemoryStream stream = new MemoryStream(client.DownloadData(weatherURL))) using (Bitmap bitmap = new Bitmap(stream)) { pixelData = bitmap.ToPixelData(); } } else { pixelData = new uint[width * height]; } if (cancellationToken.IsCancelled) { return; } for (int x = 0; x < width; x++) { if (cancellationToken.IsCancelled) { return; } for (int y = 0; y < height; y++) { if (cancellationToken.IsCancelled) { return; } if (pixelData[y * width + x] > 0) { continue; } GSF.Drawing.Point offsetPixel = new GSF.Drawing.Point(topLeftPoint.X + x, topLeftPoint.Y + y); GeoCoordinate pixelCoordinate = s_crs.Translate(offsetPixel, contourQuery.Resolution); double interpolatedValue = idwFunction(pixelCoordinate.Longitude, pixelCoordinate.Latitude); pixelData[y * width + x] = (uint)colorFunc(interpolatedValue); } } if (cancellationToken.IsCancelled) { return; } using (Bitmap bitmap = BitmapExtensions.FromPixelData(width, pixelData)) using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream, ImageFormat.Png); using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter))) { connection.ExecuteNonQuery("INSERT INTO ContourAnimationFrame VALUES({0}, {1}, {2})", animationID, i, stream.ToArray()); } } progressCounter.Increment(); }; Task.Run(() => { ICancellationToken token; ProgressCounter counter; Parallel.For(0, frames.Count, createFrame); s_cancellationTokens.TryRemove(animationID, out token); s_progressCounters.TryRemove(animationID, out counter); if (cancellationToken.IsCancelled) { using (AdoDataConnection connection = new AdoDataConnection(connectionstring, typeof(SqlConnection), typeof(SqlDataAdapter))) { connection.ExecuteNonQuery("DELETE FROM ContourAnimationFrame WHERE ContourAnimationID = {0}", animationID); connection.ExecuteNonQuery("DELETE FROM ContourAnimation WHERE ID = {0}", animationID); } } }); s_cleanUpAnimationOperation.TryRunOnceAsync(); return(new ContourAnimationInfo() { AnimationID = animationID, ColorDomain = colorScale.Domain, ColorRange = colorScale.Range, MinLatitude = bottomRight.Latitude, MaxLatitude = topLeft.Latitude, MinLongitude = topLeft.Longitude, MaxLongitude = bottomRight.Longitude, Infos = frames.Select((frame, index) => new ContourInfo() { Locations = frame, URL = string.Format("./mapService.asmx/getContourAnimationFrame?animation={0}&frame={1}", animationID, index), Date = contourQuery.GetStartDate().AddMinutes(index * contourQuery.StepSize).ToString() }).ToList() }); }
public static IEnumerator <BTStatus> FoodFinder(Animal agent, Func <Animal, BTStatus> noNearbyFoodBehavior, float hungerRestored) { var lastPos = Vector3.Zero; Queue <Vector3> foodSources = new Queue <Vector3>(); while (agent.Hunger > Brain.HungerSatiated) { foodSources.Clear(); while (foodSources.Count == 0) { if (Vector3.WrappedDistanceSq(lastPos, agent.Position) > 100) { var agentRegion = RouteRegions.GetRegion(agent.Position.WorldPosition3i); foodSources.AddRange(EcoSim.PlantSim.PlantsWithinRange(agent.Position, 10, plant => agent.Species.Eats(plant.Species) && RouteRegions.GetRegion(plant.Position.WorldPosition3i.Down()) == agentRegion).Shuffle().Select(plant => plant.Position + Vector3.Down)); lastPos = agent.Position; } else { yield return(noNearbyFoodBehavior(agent)); } } while (foodSources.Count > 0 && agent.Hunger > Brain.HungerSatiated && Vector3.WrappedDistanceSq(lastPos, agent.Position) < 100) { // low-effort search for the first option or any other option visited while trying to hit the first Vector3 targetPlantPosition; PiecewiseLinearFunction route = AIUtilities.GetRouteToAny(agent.Position, foodSources, agent.Species.WanderingSpeed, out targetPlantPosition, 100, 20, agent.Species.HeadDistance); if (route == null) { break; } agent.Target.SetPath(route); agent.Target.LookPos = targetPlantPosition; agent.AnimationState = AnimalAnimationState.LookingForFood; var target = route.EndPosition; // just in case something interrupts the path while (agent.Target.TargetTime > WorldTime.Seconds && agent.Target.TargetPosition == target) { agent.NextTick = agent.Target.TargetTime; yield return(BTStatus.Running); } if (Vector3.WrappedDistanceSq(target, agent.Position) < 4) { agent.AnimationState = AnimalAnimationState.Eating; agent.NextTick = WorldTime.Seconds + 10; agent.Hunger -= hungerRestored; agent.Target.LookPos = targetPlantPosition; yield return(BTStatus.Running); } // something interrupted eating, probably need to find new food if (agent.Target.TargetPosition != target) { break; } } } }