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);
    }