//function called to read the tracked data and format it as objects for simplified processing void ProcessData() { Tanks = new Tank[(int)(TankCount.x * TankCount.y)]; //random variable for later Random r = new Random(); //Random names are given to the fish to identify them //Each fish has its own first name, but the fish that share a tank have the same last name string[] MaleFirstNames = { "Charles", "Carl", "Thomas", "Dave", "Fishy", "Eddie", "Louie" }; string[] FemaleFirstNames = { "Henrietta", "Camille", "Carla", "Patricia", "Ella", "Thelma", "Bea" }; string[] LastNames = { "Smith", "Da Vinci", "Ramirez", "von Gelsing", "McFishFace", "Pantel", "Olding", "Carlesburg" }; //Read the tracking file //The format for the tracking data is as follows: // /FISH_1_X1/FISH_1_Y1/BEHAVIOUR_1(if applicable)/FISH_2_X1/FISH_2_Y2/---/... // /FISH_1_X2/FISH_1_Y2/BEHAVIOUR_2(if applicable)/FISH_2_X2/FISH_2_Y2/---/... //... string[] Lines = System.IO.File.ReadAllLines("Results.csv"); //Loop through each line one at a time for (int i = 2; i < Lines.Length; i++) { //split each line into its cells (in a csv the cells are separated by commas string[] Cells = Lines[i].Split(','); //Go through each cell for (int j = 1; j < Cells.Length; j += 3) { //If the cell is empty, skip it if (Cells[j] == " ") { continue; } //Get the index of the current fish (since there are 3 cells per fish, it equals a third of the current cell index) int CurrentFish = (int)Math.Ceiling((double)j / 3); //If the current fish has no data yet, create a fish if (CurrentFish > fish.Count) { //Creates a new fish, by default with a male first name. If the fish ends up being female, the name will be changed //Also sets the path to a new array of vectors equal to the number of frames of the video Fish f = new Fish(MaleFirstNames[r.Next(0, MaleFirstNames.Length)]) { Path = new Vector[Frames] }; //Add this fish to the list of fish fish.Add(f); //Gets the tank index based on the current position int TankIndex = (int)(Math.Floor((float.Parse(Cells[j]) * TankCount.x / Dimensions.x)) * (TankCount.y) + Math.Floor((float.Parse(Cells[j + 1]) * TankCount.y / Dimensions.y))); //If the tank doesnt exist yet, add it if (Tanks[TankIndex] == null) { Tanks[TankIndex] = new Tank(LastNames[TankIndex], Frames); } //add the fish to the tank Tanks[TankIndex].FishInTank.Add(f); //Set the behaviour type of the fish, if it exists int Type = -1; int.TryParse(Cells[j + 2], out Type); Tanks[TankIndex].Behaviours[CurrentFrame] = (Behaviour)Type; Console.WriteLine((Behaviour)Type); } //set the location of the fish fish[CurrentFish - 1].Path[i - 2] = new Vector(float.Parse(Cells[j]), float.Parse(Cells[j + 1])); } } //Go through each tank foreach (Tank t in Tanks) { if (t.FishInTank.Count >= 2 && t.FishInTank[0].Path[0] != null && t.FishInTank[1].Path[0] != null) { //the male fish is always higher, so set them accordingly if (t.FishInTank[0].Path[0].y < t.FishInTank[1].Path[0].y) { t.Male = t.FishInTank[0]; t.Female = t.FishInTank[1]; } else { t.Male = t.FishInTank[1]; t.Female = t.FishInTank[0]; } } else { t.Male = t.FishInTank[0]; t.Female = t.FishInTank[0]; } //Sets the first name of the fish t.Female.FirstName = FemaleFirstNames[r.Next(0, FemaleFirstNames.Length)]; //Removes teh fish in the current tank t.FishInTank.Remove(t.Male); t.FishInTank.Remove(t.Female); //make sure the fish have a position the first frame if (t.Male.Path[0] == null) { t.Male.Path[0] = t.Female.Path[0]; } else if (t.Female.Path[0] == null) { t.Female.Path[0] = t.Male.Path[0]; } //loop through all the frames for (int i = 1; i < Frames; i++) { //if both fish dont have a current path if (t.Male.Path[i] == null && t.Female.Path[i] == null) { //give them empty vectors t.Male.Path[i] = new Vector(0, 0); t.Female.Path[i] = new Vector(0, 0); //get all fish currently existing List <Fish> ActiveFish = new List <Fish>(); foreach (Fish f in t.FishInTank) { if (f.Path[i] != null) { ActiveFish.Add(f); } } //if there is two fish active... if (ActiveFish.Count == 2) { //merge the active fish with the initial male/female fish based on closeness to each other if ((t.Male.Path[i - 1] - ActiveFish[0].Path[i]).GetMagnitude() > (t.Female.Path[i - 1] - ActiveFish[0].Path[i]).GetMagnitude()) { for (int j = i; j < Frames && ActiveFish[0].Path[j] != null; j++) { t.Male.Path[j] = ActiveFish[0].Path[j]; } for (int j = i; j < Frames && ActiveFish[1].Path[j] != null; j++) { t.Female.Path[j] = ActiveFish[1].Path[j]; } } else { for (int j = i; j < Frames && ActiveFish[1].Path[j] != null; j++) { t.Male.Path[j] = ActiveFish[1].Path[j]; } for (int j = i; j < Frames && ActiveFish[0].Path[j] != null; j++) { t.Female.Path[j] = ActiveFish[0].Path[j]; } } //if there is only one fish then they are probably at the same position, so give them both the same position } else if (ActiveFish.Count == 1) { for (int j = i; j < Frames && ActiveFish[0].Path[j] != null; j++) { t.Male.Path[j] = ActiveFish[0].Path[j]; t.Female.Path[j] = ActiveFish[0].Path[j]; } } //if only one fish disappears... } else if (t.Male.Path[i] == null) { //by default give it the position of the other fish temporarily t.Male.Path[i] = t.Female.Path[i]; //if ther are other active fish that were not active beforehand, then reassign that fish to the male fish foreach (Fish f in t.FishInTank) { if (f.Path[i - 1] == null && f.Path[i] != null) { for (int j = i; j < f.Path.Length && f.Path[j] != null; j++) { t.Male.Path[j] = f.Path[j]; } } } //the same process, but for the female } else if (t.Female.Path[i] == null) { //again, by default give the female the male's position t.Female.Path[i] = t.Male.Path[i]; //if any fish become active, then shift their data into this data foreach (Fish f in t.FishInTank) { if (f.Path[i - 1] == null && f.Path[i] != null) { for (int j = i; j < f.Path.Length && f.Path[j] != null; j++) { t.Female.Path[j] = f.Path[j]; } } } } } //add this tank to the dropdown box this.comboBox1.Items.Add(t); } //update everything comboBox1.SelectedIndex = 0; UpdateTextBox(); UpdateVisuals(); }