RaySegmentPair createRaySegmentPair(Vector2 A1, Vector2 A2, Vector2 B1, Vector2 B2, float id, float theta) { RaySegmentPair pair = new RaySegmentPair(); pair.A1 = A1; pair.A2 = A2; pair.B1 = B1; pair.B2 = B2; pair.id = id; pair.theta = theta; return(pair); }
List <VisionArc> UpdateVisionArcs() { calculationCounter++; //########################################### VERSION 1 #################################### lastHitId = -1; //Every frame the active segments and collisions are unique. Dictionary <int, Segment> activeSegments = new Dictionary <int, Segment>(); collisions = new List <RaySegmentPair>(); List <VisionArc> newVisionArcs = new List <VisionArc>(); VisionArc VA = new VisionArc(); VisionArc finalArc = new VisionArc(); int finalArcId = -1; List <RaySegmentPair> tempCollisionBuffer = new List <RaySegmentPair>(); // Used for first collision (we need more context to identify order of points) Vector2 origin = new Vector2(observer.position.x, observer.position.z); //Points are to be processed in order of angle relative to observer. for (int i = 0; i < points.Count; i++) { points[i].recalculateTheta(origin); } points.Sort((a, b) => a.theta.CompareTo(b.theta)); //At this point we know the starting angle of our first vision arc: VA.startingAngle = points[0].theta; if (useHashing) { List <Segment> startingSegments = segments.FindAll(x => angleInRange(x.A.theta, x.B.theta, points[0].theta) == 0); foreach (Segment seg in startingSegments) //instead of starting segments { activeSegments.Add(seg.id, seg); } } else { foreach (Segment seg in segments) //O(n^2) complexity but is mitigated by doing comparison on GPU. { activeSegments.Add(seg.id, seg); } } //Iterate through points. for (int i = 0; i < points.Count; i++) { bool segmentProcessed = false; if (useHashing) { if (activeSegments.ContainsKey(points[i].segmentId)) { //Then we need to remove this segment at the end. segmentProcessed = true; } else { activeSegments.Add(points[i].segmentId, segments[points[i].segmentId]); } } //Compare this ray to every active segment //Create segment pairs: int j = 0; RaySegmentPair[] segmentPairs = new RaySegmentPair[activeSegments.Count]; int targetIndex = 0; foreach (Segment s in activeSegments.Values) { if (points[i].segmentId == s.id) { targetIndex = j; } segmentPairs[j] = createRaySegmentPair(origin, points[i].coor, s.A.coor, s.B.coor, s.id, points[i].theta); j++; } List <int> hitIndeces = FindClosestIntersect(segmentPairs); //If this is the first point, we have special measures: if (i == 0) { //First point to be processed requires special measures since we don't have any vision arcs yet. if (hitIndeces.Count > 1) { //We have 2 points, load them into the buffer tempCollisionBuffer.Add(segmentPairs[hitIndeces[0]]); tempCollisionBuffer.Add(segmentPairs[hitIndeces[1]]); } else { //We only have 1 point, add it to the buffer. tempCollisionBuffer.Add(segmentPairs[hitIndeces[0]]); } } else if (i == 1) //This is our second collision check, Make sense of our first collision using the second. { if (hitIndeces.Count > 1) { //Figure out if our second collision --the target index not the dead on collision-- //has the same id as either of our points. //We want to match the closest collision if possible if (tempCollisionBuffer.Count > 1) { if ((int)segmentPairs[hitIndeces[1]].id / 2 == tempCollisionBuffer[1].id / 2) { // Our target indexes match so they form the first segment. //Our other point must form our final segment: finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; //Establish arc start: VA.startingAngle = tempCollisionBuffer[1].theta; VA.startingDistSqr = tempCollisionBuffer[1].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[1].A1.x, 0, tempCollisionBuffer[1].A1.y); //Establish arc end: VA.endingAngle = segmentPairs[hitIndeces[1]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; }//if the id's of the two targets don't match then check to see if our segment is being occluded by a new segment: //Occlusion would give us a primary collision matching our target id: else if ((int)segmentPairs[hitIndeces[0]].id / 2 == (int)tempCollisionBuffer[1].id / 2) { // finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; //Establish arc start at first segment start: VA.startingAngle = tempCollisionBuffer[1].theta; VA.startingDistSqr = tempCollisionBuffer[1].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[1].A1.x, 0, tempCollisionBuffer[1].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[1]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[1]].id; }//If not being occluded, then the next point could be another occluder else { //Crash? finalArc.endingAngle = tempCollisionBuffer[1].theta; finalArc.endingDistSqr = tempCollisionBuffer[1].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[1].A1.x, 0, tempCollisionBuffer[1].A1.y); finalArcId = (int)tempCollisionBuffer[1].id; //Establish arc start at first segment start: VA.startingAngle = tempCollisionBuffer[0].theta; VA.startingDistSqr = tempCollisionBuffer[0].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[1]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[1]].id; } } else //We started off with only 1 collision.. { //Check if we're being occluded if ((int)segmentPairs[hitIndeces[0]].id / 2 == (int)tempCollisionBuffer[0].id / 2) { finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; VA.startingAngle = tempCollisionBuffer[0].theta; VA.startingDistSqr = tempCollisionBuffer[0].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[1]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[1]].id; } else { //We've hit the end of the segment finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; VA.startingAngle = tempCollisionBuffer[0].theta; VA.startingDistSqr = tempCollisionBuffer[0].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[1]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } } } else { //We only have 1 collision if (tempCollisionBuffer.Count > 1) { //Compare our 1 recent collision to our 2 previous hits if ((int)tempCollisionBuffer[1].id / 2 == (int)segmentPairs[hitIndeces[0]].id / 2)//If our target has the same id as what we've hit... { //If our new collision matches our new point then our segment is obscuring something. finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; VA.startingAngle = tempCollisionBuffer[1].theta; VA.startingDistSqr = tempCollisionBuffer[1].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[1].A1.x, 0, tempCollisionBuffer[1].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } else //it must match our first point right? { finalArc.endingAngle = tempCollisionBuffer[1].theta; finalArc.endingDistSqr = tempCollisionBuffer[1].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[1].A1.x, 0, tempCollisionBuffer[1].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; VA.startingAngle = tempCollisionBuffer[0].theta; VA.startingDistSqr = tempCollisionBuffer[0].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } } else // We have 1 collision to start with and we just got 1 collision { //Only 1 way this can be: finalArc.endingAngle = tempCollisionBuffer[0].theta; finalArc.endingDistSqr = tempCollisionBuffer[0].B2.x; finalArc.point2 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); finalArcId = (int)tempCollisionBuffer[0].id; VA.startingAngle = tempCollisionBuffer[0].theta; VA.startingDistSqr = tempCollisionBuffer[0].B2.x; VA.point1 = new Vector3(tempCollisionBuffer[0].A1.x, 0, tempCollisionBuffer[0].A1.y); //Establish arc end at solid hit on occluding segment VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Commit arc to memory. newVisionArcs.Add(VA); //Establish next arc start: VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } } } else //This isn't one of our nightmare bootstrapping cases. Proceed as normal { if (hitIndeces.Count > 1) //if we have multiple collisions. { if ((int)segmentPairs[hitIndeces[1]].id / 2 == lastHitId / 2) { //We're occluding something: VA.endingAngle = segmentPairs[hitIndeces[1]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); newVisionArcs.Add(VA); VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } else//We are being occluded. { VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); newVisionArcs.Add(VA); VA.startingAngle = segmentPairs[hitIndeces[1]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[1]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[1]].A1.x, 0, segmentPairs[hitIndeces[1]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[1]].id; } } else { //If we hit the same segment, we didn't gain any information (ignore this case if this is the last point for safety) if (i != points.Count - 1 && lastHitId / 2 == (int)segmentPairs[hitIndeces[0]].id / 2 && segmentPairs[hitIndeces[0]].id > 3) { //No new information gained, ignore triangle. continue; } //we only have 1 collision. VA.endingAngle = segmentPairs[hitIndeces[0]].theta; VA.endingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point2 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); newVisionArcs.Add(VA); VA.startingAngle = segmentPairs[hitIndeces[0]].theta; VA.startingDistSqr = segmentPairs[hitIndeces[0]].B2.x; VA.point1 = new Vector3(segmentPairs[hitIndeces[0]].A1.x, 0, segmentPairs[hitIndeces[0]].A1.y); //Record last hit id: lastHitId = (int)segmentPairs[hitIndeces[0]].id; } } //Remove segment if this is the second time we've encountered this segment. if (useHashing && segmentProcessed) { activeSegments.Remove(points[i].segmentId); } } //Final Stitch up VA.endingAngle = finalArc.endingAngle; VA.endingDistSqr = finalArc.endingDistSqr; VA.point2 = finalArc.point2; newVisionArcs.Add(VA); return(newVisionArcs); }