1 | using System.Linq;
|
---|
2 | using System.Xml.Linq;
|
---|
3 | using System;
|
---|
4 | using System.IO;
|
---|
5 | using System.Collections.Generic;
|
---|
6 | using UnityEngine;
|
---|
7 |
|
---|
8 | //Holds the connections, the number of objects in them and the default
|
---|
9 | //attenuation values to output in the absence of an object pair.
|
---|
10 | public class Connection
|
---|
11 | {
|
---|
12 | public int name { get; set; }
|
---|
13 | public int defattn { get; set; }
|
---|
14 | public int maxobj { get; set; }
|
---|
15 | }
|
---|
16 |
|
---|
17 | //Holds the object details which include the name, the type, the id and
|
---|
18 | //the other objects it is linked to for each connection.
|
---|
19 | public class Objects
|
---|
20 | {
|
---|
21 | public string name { get; set; }
|
---|
22 | public string type { get; set; }
|
---|
23 | public int id { get; set; }
|
---|
24 | public Dictionary<int, string[]> links = new Dictionary<int, string[]>();
|
---|
25 | }
|
---|
26 |
|
---|
27 | public class TrackObject_Test : MonoBehaviour
|
---|
28 | {
|
---|
29 | List<Connection> connectionList = new List<Connection>();//List of connections of class type connection
|
---|
30 | List<Objects> objectlist = new List<Objects>();//List of objects of class type object
|
---|
31 |
|
---|
32 | Dictionary<string, float>[] attnupdate;//Contains an array of dictionary values of each connection type with the key being the link i.e., 1-2, 1-3, ... and the value being the final attenuation to write to file.
|
---|
33 | Dictionary<string, int> attnfactor = new Dictionary<string, int>(); // Holds a dictionary with the key as object type and the value being the attenuation factor.
|
---|
34 | Dictionary<string, string[]> objmap = new Dictionary<string, string[]>(); // Contains a map of the object name with its type. For example, 1 is a key for Car-121
|
---|
35 |
|
---|
36 | string path = @"Attenuation.csv";
|
---|
37 |
|
---|
38 | float interval, duration, frequency;
|
---|
39 | float nextTime = 0;
|
---|
40 |
|
---|
41 | bool exec = false;//bool value to start the trackers after all objects have been loaded
|
---|
42 | bool config = false;//bool value to run the trackers iff the config file exists. In its absence, the simulator exhibits normal behavior
|
---|
43 | public void GetDefValues()
|
---|
44 | {
|
---|
45 | using (var xmlReader = new StreamReader("config.xml"))
|
---|
46 | {
|
---|
47 | var doc = XDocument.Load(xmlReader);
|
---|
48 | XNamespace nonamespace = XNamespace.None;
|
---|
49 |
|
---|
50 | var xmlProducts = doc.Descendants(nonamespace + "link");//Obtains all descendants of tag 'link'
|
---|
51 | foreach (var item in xmlProducts)
|
---|
52 | {
|
---|
53 | if (item != null && item.Attribute("default_attn") != null)
|
---|
54 | {
|
---|
55 | var connection = new Connection//Populates the connectionList
|
---|
56 | {
|
---|
57 | name = int.Parse(item.Attribute("name").Value),
|
---|
58 | defattn = int.Parse(item.Attribute("default_attn").Value),
|
---|
59 | maxobj = int.Parse(item.Attribute("max_obj").Value)
|
---|
60 | };
|
---|
61 | connectionList.Add(connection);
|
---|
62 | }
|
---|
63 | }
|
---|
64 | }
|
---|
65 | }
|
---|
66 | //Populates the objectlist from the xml file
|
---|
67 | public void GetConnections()
|
---|
68 | {
|
---|
69 | using (var xmlReader = new StreamReader("config.xml"))
|
---|
70 | {
|
---|
71 | var doc = XDocument.Load(xmlReader);
|
---|
72 | XNamespace nonamespace = XNamespace.None;
|
---|
73 |
|
---|
74 | var xmlProducts = doc.Descendants(nonamespace + "object");
|
---|
75 | foreach (var item in xmlProducts)
|
---|
76 | {
|
---|
77 | if (item != null && item.Attribute("id") != null)
|
---|
78 | {
|
---|
79 | var objlist = new Objects
|
---|
80 | {
|
---|
81 | name = item.Attribute("name").Value,
|
---|
82 | type = item.Attribute("type").Value,
|
---|
83 | id = int.Parse(item.Attribute("id").Value),
|
---|
84 | };
|
---|
85 |
|
---|
86 | string[] conList;
|
---|
87 | foreach (var size in item.Descendants("link"))
|
---|
88 | {
|
---|
89 | int i = int.Parse(size.Attribute("name").Value);
|
---|
90 | conList = (size.Value).Split(',');
|
---|
91 | objlist.links.Add(i, conList);
|
---|
92 | }
|
---|
93 | objectlist.Add(objlist);
|
---|
94 | }
|
---|
95 | }
|
---|
96 | }
|
---|
97 | }
|
---|
98 |
|
---|
99 | //Populates the attnfactor from the config file
|
---|
100 | public void GetAttnFactor()
|
---|
101 | {
|
---|
102 | using (var xmlReader = new StreamReader("config.xml"))
|
---|
103 | {
|
---|
104 | var doc = XDocument.Load(xmlReader);
|
---|
105 | XNamespace nonamespace = XNamespace.None;
|
---|
106 |
|
---|
107 | var xmlProducts = doc.Descendants(nonamespace + "attn");
|
---|
108 | foreach (var item in xmlProducts)
|
---|
109 | {
|
---|
110 | if (item != null)
|
---|
111 | {
|
---|
112 | int fac = int.Parse(item.Attribute("factor").Value);
|
---|
113 | string type = item.Attribute("type").Value;
|
---|
114 | attnfactor.Add(type, fac);
|
---|
115 | }
|
---|
116 | }
|
---|
117 | }
|
---|
118 | }
|
---|
119 |
|
---|
120 | //Reads the simulation parameters like the time interval, run time and the frequency to be used with attenuation calculations
|
---|
121 | public void GetParameters()
|
---|
122 | {
|
---|
123 | using (var xmlReader = new StreamReader("config.xml"))
|
---|
124 | {
|
---|
125 | var doc = XDocument.Load(xmlReader);
|
---|
126 | XNamespace nonamespace = XNamespace.None;
|
---|
127 | var xmlProducts = doc.Descendants(nonamespace + "sim_parameters");
|
---|
128 | foreach (var item in xmlProducts)
|
---|
129 | {
|
---|
130 | interval = int.Parse(item.Attribute("time_int").Value);
|
---|
131 | duration = int.Parse(item.Attribute("max_time").Value);
|
---|
132 | frequency = int.Parse(item.Attribute("frequency").Value);
|
---|
133 | }
|
---|
134 | }
|
---|
135 | }
|
---|
136 |
|
---|
137 | //Populates the attenuation update dictionary with default values at time t=0.
|
---|
138 | //Also allocates space to each element of Dictionary array based on the
|
---|
139 | //number of elements of each connection type.
|
---|
140 | public void PopulateDefaultValues()
|
---|
141 | {
|
---|
142 | attnupdate = new Dictionary< string, float>[connectionList.Count];
|
---|
143 | for (int i=0; i< connectionList.Count; i++)
|
---|
144 | {
|
---|
145 | attnupdate[i] = new Dictionary<string, float>();
|
---|
146 | for (int j = 1; j <= (connectionList[i].maxobj); j++)
|
---|
147 | {
|
---|
148 | for (int k = j+1; k <= (connectionList[i].maxobj); k++)//n(n-1) links for max n objects
|
---|
149 | {
|
---|
150 | attnupdate[i].Add((j.ToString() + "-" + k.ToString()), connectionList[i].defattn);
|
---|
151 | }
|
---|
152 | }
|
---|
153 | }
|
---|
154 | }
|
---|
155 |
|
---|
156 | //Maps object name to "objecttype-id"
|
---|
157 | void Compobjmap()
|
---|
158 | {
|
---|
159 | string temp = "";
|
---|
160 | for (int i = 0; i < objectlist.Count; i++)
|
---|
161 | {
|
---|
162 | temp = objectlist[i].type + "-" + objectlist[i].id;
|
---|
163 | objmap.Add(objectlist[i].name, temp.Split('-'));
|
---|
164 | }
|
---|
165 | }
|
---|
166 |
|
---|
167 | //Computes the attenuation values for the object pairs specified in the config file.
|
---|
168 | void ComputeDistance()
|
---|
169 | {
|
---|
170 | Vector3 coord1 = new Vector3();//Holds coordinates for the first object
|
---|
171 | Vector3 coord2 = new Vector3();//Holds coordinates for the second object
|
---|
172 |
|
---|
173 | for (int i = 0; i < objectlist.Count; i++)//Iterate through every object
|
---|
174 | {
|
---|
175 | for(int j=0;j<connectionList.Count;j++)//Iterate through all the objects that the 'i'th object is paired with for each connection type.
|
---|
176 | {
|
---|
177 | string[] a;
|
---|
178 | if (objectlist[i].links.ContainsKey(connectionList[j].name) )
|
---|
179 | {
|
---|
180 | a = objectlist[i].links[connectionList[j].name];//Holds the objects that object i is connected to of connection type j
|
---|
181 |
|
---|
182 | coord1 = GetCoordinates(objectlist[i].name);
|
---|
183 | for (int k = 0; k < a.Length; k++)
|
---|
184 | {
|
---|
185 | string temp = "";
|
---|
186 | coord2 = GetCoordinates(a[k]);
|
---|
187 |
|
---|
188 | if (int.Parse(a[k]) < int.Parse(objectlist[i].name))//Checks to ensure that in the link i-j, i<j and the key i-j always has i<j
|
---|
189 | temp = a[k] + "-" + objectlist[i].name;
|
---|
190 | else if (int.Parse(a[k]) > int.Parse(objectlist[i].name))
|
---|
191 | temp = objectlist[i].name + "-" + a[k];
|
---|
192 |
|
---|
193 | if (temp != "" && int.Parse(a[k]) <= connectionList[j].maxobj && int.Parse(objectlist[i].name) <= connectionList[j].maxobj)
|
---|
194 | attnupdate[j][temp] = DistanceFunction(Vector3.Distance(coord1, coord2)) + GetRayHit(coord1, coord2);//Update the jth index of dictionary array attn update for object i. Sums up the distance function and the attenuation caused by objects present between the source and destination.
|
---|
195 | }
|
---|
196 | }
|
---|
197 | }
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | //Writes to Attenuation.csv. Creates new file if file doesn't already exist
|
---|
202 | void WriteToFile(float timestamp)
|
---|
203 | {
|
---|
204 | string fileText = "";
|
---|
205 | string[] output = new string[connectionList.Count];
|
---|
206 |
|
---|
207 | for (int i = 0; i < connectionList.Count; i++)
|
---|
208 | {
|
---|
209 | output[i] = "";
|
---|
210 | for (int j = 1; j <= (connectionList[i].maxobj); j++)
|
---|
211 | {
|
---|
212 | for (int k = j + 1; k <= (connectionList[i].maxobj); k++)
|
---|
213 | {
|
---|
214 | output[i] += ((attnupdate[i][j.ToString() + "-" + k.ToString()]).ToString()) + ",";//Returns the attenuation value for the key "object 1 - object 2"
|
---|
215 | }
|
---|
216 | }
|
---|
217 |
|
---|
218 | if (i != connectionList.Count - 1)
|
---|
219 | {
|
---|
220 | output[i] += ",";
|
---|
221 | }
|
---|
222 | }
|
---|
223 | fileText = timestamp.ToString() + ",";
|
---|
224 |
|
---|
225 | for (int i = 0; i < connectionList.Count; i++)
|
---|
226 | {
|
---|
227 | fileText += output[i];
|
---|
228 | }
|
---|
229 |
|
---|
230 | if (!File.Exists(path))
|
---|
231 | File.WriteAllText(path, fileText);
|
---|
232 | else
|
---|
233 | File.AppendAllText(path, fileText);
|
---|
234 |
|
---|
235 | File.AppendAllText(path, "\n");
|
---|
236 | }
|
---|
237 |
|
---|
238 | //Returns the coordinates for object type passed.
|
---|
239 | //The objmap dictionary gives the name and id of the object
|
---|
240 | Vector3 GetCoordinates(string item)
|
---|
241 | {
|
---|
242 | GameObject[] ob = null;
|
---|
243 | string[] dob;
|
---|
244 | objmap.TryGetValue(item, out dob);
|
---|
245 | ob = GameObject.FindGameObjectsWithTag(dob[0]);//0th index is the name of the object
|
---|
246 | return ob[int.Parse(dob[1])].transform.position;//1st index holds the id
|
---|
247 | }
|
---|
248 | //Returns the sum of the attenuation factor of all objects between 2 objects
|
---|
249 | float GetRayHit(Vector3 source, Vector3 dest)
|
---|
250 | {
|
---|
251 | RaycastHit[] hits;
|
---|
252 | string obj = "";
|
---|
253 | int fac = 0, attn = 0;
|
---|
254 | hits = Physics.RaycastAll(source, dest, Vector3.Distance(source, dest));//Array of objects between source and destination
|
---|
255 |
|
---|
256 | for (int i = 0; i < hits.Length; i++)
|
---|
257 | {
|
---|
258 | obj = hits[i].collider.tag;
|
---|
259 | attnfactor.TryGetValue(obj, out fac);//Fetch attnfactor for the object
|
---|
260 | attn += fac;
|
---|
261 | }
|
---|
262 | return attn;
|
---|
263 | }
|
---|
264 |
|
---|
265 | float DistanceFunction(float distance)
|
---|
266 | {
|
---|
267 | return 20f * (float)Math.Log10(distance) + 20f * (float)Math.Log10(frequency) - 27.55f ;
|
---|
268 | }
|
---|
269 |
|
---|
270 | void Start()//Called once before start of simulation for initialization
|
---|
271 | {
|
---|
272 | if (File.Exists("config.xml"))//Checks if config file exists
|
---|
273 | config = true;
|
---|
274 | if (Time.time <= duration && config)//If config file exists and the time is less than the duration
|
---|
275 | {
|
---|
276 | GetDefValues();//Read XML for connections
|
---|
277 | GetConnections();//Read XML for objects
|
---|
278 | PopulateDefaultValues();//Populate the attnupdate dictionary with default values
|
---|
279 | GetParameters();//Read XML for simulation parameters
|
---|
280 | GetAttnFactor();//Read XML for attenuation factors
|
---|
281 |
|
---|
282 | objectlist = objectlist.OrderBy(o => o.name).ToList();//Sort objectlist by name
|
---|
283 | connectionList = connectionList.OrderBy(o => o.name).ToList();//Sort connectionlist by name
|
---|
284 |
|
---|
285 | Compobjmap();//Maps name to object type and id
|
---|
286 | }
|
---|
287 | }
|
---|
288 |
|
---|
289 | void FixedUpdate()//Called every 0.03 secs
|
---|
290 | {
|
---|
291 | if (Time.time >= nextTime && Time.time <= duration && config)//Checks if its time for the next update and time is less than duration
|
---|
292 | {
|
---|
293 | if (exec)//Set to true if objects have been loaded.
|
---|
294 | {
|
---|
295 | ComputeDistance();//Compute attenuation values
|
---|
296 | WriteToFile(nextTime);//Write the values to the file
|
---|
297 | nextTime += (interval / 1000);//Update the clock for the next time the values have to be updated
|
---|
298 | }
|
---|
299 | else//See if objects have been loaded
|
---|
300 | {
|
---|
301 | GameObject[] sample = GameObject.FindGameObjectsWithTag("Car");
|
---|
302 | if (sample.Length > 1)
|
---|
303 | {
|
---|
304 | exec = true;
|
---|
305 | }
|
---|
306 | }
|
---|
307 | }
|
---|
308 | else if(Time.time > duration)//Quit if duration has exceeded
|
---|
309 | {
|
---|
310 | Application.Quit();
|
---|
311 | }
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|