/// <summary> /// A recursive method which trace a ray until its power is less than ray-minimum power thershold /// </summary> /// <param name="path">New PathFromTxToRy object.</param> /// <param name="ray">A starting ray (first ray)</param> /// <param name="lastIntersectPart">A world object which this ray last intersect, or start</param> /// <returns>PathFromTxToRy with True if it reaches receiver and False if it did not reach the receiver.</returns> public PathFromTxToRy traceRay(PathFromTxToRy path, Ray ray, SceneObjectPart lastIntersectPart) { EntityIntersectionWithPart nextHit = findNextHit(ray, transmitter.RootPart); if (nextHit.intersection.HitTF) { //Check for limit number of reflection allowed. if(path.getNoOfReflection() >= MAX_REFLECTIONS) { path.reachesReceiver = false; return path; } //drawRay(ray.Origin, nextHit.intersection.ipoint); else if (nextHit.intersectPart.Equals(receiver.RootPart)) //If it reaches the receiver { path.reachesReceiver = true; path.addNextPoint(nextHit.intersection.ipoint, receiver.RootPart.Material); return path; }//if //recursive case, keep tracing this ray. else { path.addNextPoint(nextHit.intersection.ipoint, nextHit.intersectPart.Material); Vector3 reflectedVector = getReflectedVector(ray.Direction, nextHit.intersection.normal); Ray newRay = new Ray(nextHit.intersection.ipoint, reflectedVector); return traceRay(path, newRay, nextHit.intersectPart); }//else if } else //It didn't hit anything { path.reachesReceiver = false; return path; }//else }
/// <summary> /// Draw a given path (A given path may contains many rays). This method just get all the ray in the /// given path and draw them sequentially. /// </summary> /// <param name="path"></param> public void drawRayPath(PathFromTxToRy path) { foreach(KeyValuePair<string, RayAsPathSection> ray in path.rayList) { //Note: Team KeyValuePair and Value are c# syntax for accessing dictionary element value and its key. // To get the key, we do section.Key. To get the value we do section.Value; string name = "ray_" + path.getNoOfReflection() + "_" + path.id + "_" + ray.Value.id; drawRay(ray.Value.startPoint, ray.Value.endPoint, name); } }
public void getOneReflection() { int worldPartsSize = worldObjects.Count(); float toPercent = 100.0f / worldPartsSize; float currentElementIndex = 1.0f; Vector3 transmitterPos = transmitter.RootPart.AbsolutePosition; Vector3 receiverPos = receiver.RootPart.AbsolutePosition; //For each scenobjectpart, find the reflection point between the transmitter and the reciever. foreach (SceneObjectPart part in worldObjects) { //Make sure that it doesn't reflect off the transmitter or the reciever if (!part.Equals(transmitter.RootPart) && !part.Equals(receiver.RootPart)) { //Check if the intersection point is found ReflectionPoint reflectedPoint = findReflectionPoint(transmitterPos, receiverPos, part); if (reflectedPoint.found) { string pathID = getPathID(); PathFromTxToRy newPath = new PathFromTxToRy(this, transmitter.RootPart.AbsolutePosition, pathID); newPath.addNextPoint(reflectedPoint.reflectionPoint, reflectedPoint.surfaceMaterial); newPath.addNextPoint(receiver.RootPart.AbsolutePosition, receiver.RootPart.Material); newPath.reachesReceiver = true; if (!checkPathIsDrawn(newPath)) { pathHits[1].Add(pathID, newPath); }//if }//if }//if //Progress bar update if (currentElementIndex < worldPartsSize) { updateProgressBar(currentElementIndex * toPercent); } else { updateProgressBar(100.0f); } currentElementIndex++; }//forEachPart }
public void getLineOfSight() { string pathID = getPathID(); PathFromTxToRy path = new PathFromTxToRy(this, transmitter.RootPart.AbsolutePosition, pathID); //Direction from transmitter to the reciever Vector3 direction = receiver.RootPart.AbsolutePosition - transmitter.RootPart.AbsolutePosition; //Ray vector from transmitter to the receiver Ray ray = new Ray(transmitter.RootPart.AbsolutePosition, direction); //Get the first object the ray hit EntityIntersectionWithPart intersection = findNextHit(ray, transmitter.RootPart); path.addNextPoint(receiver.RootPart.AbsolutePosition, receiver.RootPart.Material); path.reachesReceiver = true; if (!checkPathIsDrawn(path)) { pathHits[0].Add(pathID, path); } }
/// <summary> /// From the transmitter, we create a ray in all direction (with angle between ray = ANGLE_BETWEEN_RAY). For each /// of those ray, we 'trace/follow' them and find where they are heading. If they reaches the reciever, then /// we store them in a list. /// </summary> public void startRayTracerBrutefoce() { m_log.DebugFormat("[BARE BONES NON SHARED] Started Raytracing!"); float lat, lon; float toPercent = 100.0f/360.0f; //For every lon and lat increase by ANGLE_BETWEEN_RAY for (lon = 0; lon < 360; lon += ANGLE_BETWEEN_RAY) { for (lat = 0; lat < 360; lat += ANGLE_BETWEEN_RAY) { double lonr = lon * DEG_TO_RAD; double latr = lat * DEG_TO_RAD; //Note: Lat = angle of elevation. Lon = angle around the z-axis //To get a point on a sphere using 2 angle //Assuming Radius = 1 so we can get rid of multiplying radius. //http://stackoverflow.com/questions/969798/plotting-a-point-on-the-edge-of-a-sphere float x = (float)(Math.Sin(latr) * Math.Cos(lonr)); float y = (float)(Math.Sin(latr) * Math.Sin(lonr)); float z = (float)(Math.Cos(latr)); Vector3 pointOnSphere = new Vector3(x, y, z); pointOnSphere.Normalize(); Vector3 direction = pointOnSphere; Ray ray = new Ray(transmitter.RootPart.AbsolutePosition, direction); //Trace this ray string pathID = getPathID(); PathFromTxToRy thisRayPath = new PathFromTxToRy(this, transmitter.RootPart.AbsolutePosition, pathID); thisRayPath = traceRay(thisRayPath, ray, transmitter.RootPart); //If it reaches the receiver, then add it to the hit list. if (thisRayPath.reachesReceiver && !checkPathIsDrawn(thisRayPath)) { pathHits[thisRayPath.getNoOfReflection()].Add(pathID, thisRayPath); } } //If lon < 359 then calculate the progress if (lon < 359) { updateProgressBar(lon * toPercent); } else //else it is completed so return 100% { updateProgressBar(100.0f); } }//for }
/// <summary> /// Start a ray tracer from a given model. The model has 3 sections seperate by '//' /// First section: Just says 'RTModel' to indicate that this is a ray tracer model /// Second section: Variables section. This contians the variables which were set by the user /// Third section: Set of paths from transmitter to the receiver. /// </summary> public void RayTraceFromModel(string givenModel, Scene _scene, UUID _scriptID) { string[] tokens = Regex.Split(givenModel, "//"); string section1 = tokens[0]; string section2 = tokens[1]; string section3 = tokens[2]; //Do a small check on the file. To make this better, we can do a checksum and keep it in here //instead of 'RTModel' if (section1 != "RTModel") { throw new Exception("The given ray trace model is not compatible"); } Initialise(_scene, section2, _scriptID); if (!sameTransmitter(section3)) { throw new Exception("This model is invalid as the transmitter is moved"); } //Each path is seperate by '#' so we split by '#' to get each path //It only goes up to pathList.Length -1 because the last element is the empty string. string[] pathList = section3.Split('#'); for(int i = 0; i < pathList.Length - 1; i++) { //Each position/point is seperate by '_' so we split path by '_' //It only goes up to listOfPoints.Length -1 because the last element is the empty string. string[] listOfPoints = pathList[i].Split('_'); //index 0 = starting point. //Each coordinate (x, y, z) is seperate by ',' or we split this point by ',' string[] pointElements = listOfPoints[0].Split(','); Vector3 currentPoint = new Vector3(float.Parse(pointElements[0]), float.Parse(pointElements[1]), float.Parse(pointElements[2])); string pathID = getPathID(); PathFromTxToRy newPath = new PathFromTxToRy(this, currentPoint, pathID); for(int j = 1; j < listOfPoints.Length - 1; j++) { pointElements = listOfPoints[j].Split(','); currentPoint = new Vector3(float.Parse(pointElements[0]), float.Parse(pointElements[1]), float.Parse(pointElements[2])); newPath.addNextPoint(currentPoint, float.Parse(pointElements[3])); } pathHits[newPath.getNoOfReflection()].Add(pathID, newPath); }//for RayTraceIsCalculated = true; packAndSendGETMessages(false); m_log.DebugFormat("[Finished Loaded a model]"); }
/// <summary> /// There seems to be a bug that causes each path to be drawn twice. This function check, if the /// given path has already been drawn. This function should be called everytime before adding a path /// to a hit list. /// </summary> /// <param name="path"></param> /// <returns>True = the path has already been drawn. False = the path hasn't been drawn</returns> bool checkPathIsDrawn(PathFromTxToRy path) { Vector3 midPoint = new Vector3(); //To reduce the computation time, we only one ray from a path. i.e. break the loop when getting the first one. foreach (KeyValuePair<string, RayAsPathSection> ray in path.rayList) { midPoint = ray.Value.endPoint - ray.Value.startPoint; midPoint.X = Math.Abs(midPoint.X); midPoint.Y = Math.Abs(midPoint.Y); midPoint.Z = Math.Abs(midPoint.Z); break; }//foreach //This loop will determine whether or not this path has been drawn before. It does this by //compare the 'midPoint' against the list of other mid-points. foreach (Vector3 pos in allRayPos) { if (pos.CompareTo(midPoint) == 0) { return true; }//if }//foreach //Meaning that this path hasn't been drawm before. Add all of its ray's midpoint to the list foreach (KeyValuePair<string, RayAsPathSection> ray in path.rayList) { Vector3 newRayPos = new Vector3(); newRayPos = ray.Value.endPoint - ray.Value.startPoint; newRayPos.X = Math.Abs(newRayPos.X); newRayPos.Y = Math.Abs(newRayPos.Y); newRayPos.Z = Math.Abs(newRayPos.Z); allRayPos.Add(newRayPos); }//foreach return false; }