// Start is called before the first frame update void Start() { string data = "Bell_Dioramas_Touchscreen_FieldGuides_FINAL_CRiver-BigWoods_only.csv"; string BBSData = "A2286.csv"; string RouteData = "I2286.csv"; string classification = "classifications.txt"; Diorama diorama = gameObject.AddComponent <Diorama>(); Parse.ParseCSV( ref diorama, Application.streamingAssetsPath + "/" + data, Application.streamingAssetsPath + "/" + classification); Parse.ParseBBSData( ref diorama, Application.streamingAssetsPath + "/" + BBSData); Parse.ParseRouteData( ref diorama, Application.streamingAssetsPath + "/" + RouteData); //// Visualize all of our population data //Visualization visualization = gameObject.AddComponent<Visualization>(); /* * Save our created textures for real-time use */ //for (int i = 0; i < diorama.organisms.Count; i++) { // // Make sure we are only working with birds // if (diorama.organisms[i].classification != Classification.bird) { // continue; // } // // Calculate maxCount at any route // List<float> extrapCounts = new List<float>(); // for (int j = 0; j < diorama.popByRoute.Count; j++) { // Route populations // for (int k = 0; k < diorama.popByRoute[j].organisms[i].data.Count; k++) { // years // int count = diorama.popByRoute[j].organisms[i].data[k].count; // int numRoutes = diorama.popByRoute[j].organisms[i].data[k].numRoutes; // extrapCounts.Add(count / (float)numRoutes); // } // } // // Get a ceiling to the nearest 50 // int maxCount = Mathf.CeilToInt(Mathf.Max(extrapCounts.ToArray()) / 5.0f) * 5; // // Get a useable save name // string name = diorama.organisms[i].GetName().Trim(); // name = name.Replace(" ", "_"); // name = name.Replace(",", ""); // // Get directory for animal // string dirPath = Application.dataPath + "/Data/" + name + "_" + maxCount.ToString() + "/"; // if (!Directory.Exists(dirPath)) { // Directory.CreateDirectory(dirPath); // } // // Run through all years of data on birds // for (int k = 1967; k <= 2017; k++) { // // i is bird index, k is year // Texture2D tex = visualization.Visualize(diorama, MNTexture2D, Colormap, i, k, maxCount); // File.WriteAllBytes(dirPath + k.ToString() + ".png", tex.EncodeToPNG()); // } //} //// Set our sprite now //Rect r = new Rect(0, 0, tex.width, tex.height); //MNGameObject.GetComponent<SpriteRenderer>().sprite = Sprite.Create(tex, r, new Vector2(0.5f, 0.5f)); }
/* Runs through our data from BBS and determines counts of birds over * years and routes */ public static void ParseBBSData(ref Diorama d, string filepath) { string[] fileData = System.IO.File.ReadAllLines(filepath); List <routeData> routes = new List <routeData>(); int index; // Deep copy of organisms List <Organism> copyOfOrganisms = new List <Organism>(); for (int i = 0; i < d.organisms.Count; i++) { copyOfOrganisms.Add(d.organisms[i].Clone()); } // First line is text, so start on second for (int i = 1; i < fileData.Length; i++) { string s = fileData[i]; string[] lineData = s.Trim().Split(','); // If we have no info on this route, add it to our list string routeId = lineData[2]; // Get a Deep Copy of our static info List <Organism> currClone = new List <Organism>(); for (int j = 0; j < copyOfOrganisms.Count; j++) { currClone.Add(copyOfOrganisms[j].Clone()); } routeData r = new routeData { routeID = routeId, organisms = currClone }; // Get our current species info int aou = int.Parse(lineData[4]); yearData p = new yearData { year = int.Parse(lineData[3]), numRoutes = 1, count = int.Parse(lineData[5]) }; // Find the animal with the matching aou so we can add data to it for (int k = 0; k < d.organisms.Count; k++) { if (d.organisms[k].aou == aou) { // We have found the matching animal, now we need to see if it // already has data for the year we are on index = d.organisms[k].data.FindIndex(data => data.year == p.year); if (index == -1) { // It did not have existing data, so we add it d.organisms[k].data.Add(p); } else if (d.organisms[k].classification == Classification.bird) { // The data already existed, so now we increment int totalCounts = p.count + d.organisms[k].data[index].count; int totalRoutes = d.organisms[k].data[index].numRoutes + 1; d.organisms[k].data[index] = new yearData { year = p.year, numRoutes = totalRoutes, count = totalCounts }; } } } // See if we already have this route number, if not add it index = routes.FindIndex(route => string.Compare(route.routeID, routeId) == 0); if (index == -1) { routes.Add(r.Clone()); index = routes.Count - 1; } // Get a reference to our routes data List <Organism> o = routes[index].organisms; int organismIndex = o.FindIndex(organism => organism.GetAOU() == aou); if (o[organismIndex].classification == Classification.bird) { // Add data on this bird for our route index = o[organismIndex].data.FindIndex(data => data.year == p.year); if (index == -1) { // It did not have existing data, so we add it o[organismIndex].data.Add(p); } else { // The data already existed, so now we increment int totalCounts = p.count + o[organismIndex].data[index].count; int totalRoutes = o[organismIndex].data[index].numRoutes + 1; o[organismIndex].data[index] = new yearData { year = p.year, numRoutes = totalRoutes, count = totalCounts }; } } } // Now that all data is stored in birds, sort them so they are sequential for (int i = 0; i < d.organisms.Count; i++) { d.organisms[i].data.Sort((d1, d2) => d1.year.CompareTo(d2.year)); } // Sort our birds by year, per route foreach (routeData p in routes) { for (int i = 0; i < p.organisms.Count; i++) { p.organisms[i].data.Sort((d1, d2) => d1.year.CompareTo(d2.year)); } } d.popByRoute = routes; }
public Texture2D Visualize(Diorama d, Texture2D MNTexture2D, Texture2D colormap, int birdIndex, int year, int maxCount) { // Initialization popByYear = new List <extrapPopDataByYear>(); popByRoute = new List <extrapPopDataByRoute>(); List <routeData> rData = d.popByRoute; Texture2D tex = new Texture2D(MNTexture2D.width, MNTexture2D.height); Graphics.CopyTexture(MNTexture2D, tex); // Get our per-year population data foreach (Organism o in d.organisms) { List <int> years = new List <int>(); List <float> extrapolatedCount = new List <float>(); for (int i = 0; i < o.GetPopulationData().Count; i++) { years.Add(o.data[i].year); extrapolatedCount.Add(o.data[i].count / (float)o.data[i].numRoutes); } if (years.Count > 0) { extrapPopDataByYear b = new extrapPopDataByYear { name = o.GetName(), years = years, extrapolatedCount = extrapolatedCount }; popByYear.Add(b); } } // Get extrapolated population by routes for (int i = 0; i < d.popByRoute.Count; i++) { string rId = d.popByRoute[i].routeID; List <extrapPopDataByYear> routePop = new List <extrapPopDataByYear>(); foreach (Organism o in d.popByRoute[i].organisms) { List <int> years = new List <int>(); List <float> extrapolatedCount = new List <float>(); for (int k = 0; k < o.GetPopulationData().Count; k++) { years.Add(o.data[k].year); extrapolatedCount.Add(o.data[k].count / (float)o.data[k].numRoutes); } extrapPopDataByYear b = new extrapPopDataByYear { name = o.GetName(), years = years, extrapolatedCount = extrapolatedCount }; routePop.Add(b); } extrapPopDataByRoute r = new extrapPopDataByRoute { routeId = rId, popByYear = routePop }; popByRoute.Add(r); } // Get extrapolated pixel locations of each route for (int i = 0; i < rData.Count; i++) { int x = ChangeScale_FtoI(0, tex.width - 1, minLong, maxLong, rData[i].longitude); int y = ChangeScale_FtoI(0, tex.height - 1, minLat, maxLat, rData[i].latitude); rData[i] = new routeData { routeID = rData[i].routeID, organisms = rData[i].organisms, latitude = rData[i].latitude, longitude = rData[i].longitude, pixelX = x, pixelY = y }; } // At this point, we now have stored population data by year // We have extrapolated our lat/longitude to pixel coordinates // Now, we want to change all pixels colors by the data at a specific year at all routes // Need a color map Color max = Color.white; Color min = Color.black; Color[] pixels = tex.GetPixels(); Color[] newPixels = new Color[pixels.Length]; float[] values = new float[popByRoute.Count]; float[] inverseDistances = new float[popByRoute.Count]; float[] ratios = new float[popByRoute.Count]; List <float> routeCounts = new List <float>(); // Get our max value found so that we can normalize our colormap for (int i = 0; i < popByRoute.Count; i++) { routeData r = rData[i]; // Find the route int index = popByRoute.FindIndex(route => route.routeId.CompareTo(r.routeID) == 0); // Find yearly data in this route int yearIndex = popByRoute[index].popByYear[birdIndex].years.IndexOf(year); // If it fails, add 0, else add it's pop value if (yearIndex == -1) { routeCounts.Add(0f); } else { routeCounts.Add(popByRoute[index].popByYear[birdIndex].extrapolatedCount[yearIndex]); } } /* * Starting per-pixel calculations */ for (int i = 0; i < pixels.Length; i++) { // We don't want to edit transparent sections of the image, black, or white if (pixels[i].a == 0 || (pixels[i].r < 0.1f && pixels[i].g < 0.1f && pixels[i].b < 0.1f) || (pixels[i].r > 0.9f && pixels[i].g > 0.9f && pixels[i].b > 0.9f)) { newPixels[i] = pixels[i]; continue; } // Initialize pixel value for our Lerp float pixelVal = 0; // Getting our inverse distance relationship values // Further away routes have less impact on pixels color int imgWidth = tex.width; int imgHeight = tex.height; for (int k = 0; k < popByRoute.Count; k++) { int px = rData[k].pixelX; int py = rData[k].pixelY; int x = i % imgWidth; int y = (i - x) / (imgWidth - 1); float dist = (px - x) * (px - x) + (py - y) * (py - y); if (dist == 0) { dist = 1f; } inverseDistances[k] = (1.0f / (dist * dist)); } float totalDist = SumArray(inverseDistances); // Turn these inverseDistances into ratios to multiply by the pixels // Normalize the distances float inverseTotalDist = 1.0f / totalDist; for (int k = 0; k < popByRoute.Count; k++) { ratios[k] = inverseDistances[k] * inverseTotalDist; } // Multiply our pre-computed route population count data by our ratio for this specific pixel for (int k = 0; k < popByRoute.Count; k++) { if (ratios[k] < 0.0001f) { values[k] = 0.0f; continue; } values[k] = (ratios[k] * routeCounts[k]); } // Need to sum it up and Lerp pixelVal = Mathf.Max(Mathf.Min(SumArray(values) / maxCount, 1), 0); newPixels[i] = colormap.GetPixel((colormap.width - 1) - (int)(pixelVal * (colormap.width - 1)), 0); //newPixels[i] = Color.Lerp(Color.black, Color.white, Mathf.Clamp(pixelVal, 0.001f, 0.999f)); } // Apply our pixel colors to our textures tex.SetPixels(newPixels); tex.Apply(); // // Draw our route locations on our texture as well for debugging // for (int i = 0; i < rData.Count; i++) { // int x = rData[i].pixelX; // int y = rData[i].pixelY; // MNTexture2D.SetPixel(x, y, Color.black); // } // MNTexture2D.Apply(); return(tex); }