/// <summary>
        /// Get the closest points on 2 paths
        /// </summary>
        /// <param name="path1"></param>
        /// <param name="path2"></param>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        public static void GetClosestPoints(Path path1, Path path2, out PointOnPath p1, out PointOnPath p2, out double distance)
        {
            PointOnPath closest1 = path1.StartPoint;
            PointOnPath closest2 = path2.StartPoint;
            double dist = Double.MaxValue;

            PointOnPath current = path1.StartPoint;
            double increment = 1;

            double tmpIncrement = 0;

            while (tmpIncrement == 0)
            {
                PointOnPath test = path2.GetClosest(current.pt);
                double tmpDist = test.pt.DistanceTo(current.pt);

                if (tmpDist < dist)
                {
                    closest1 = current;
                    closest2 = test;
                    dist = tmpDist;
                }

                tmpIncrement = increment;
                current = path1.AdvancePoint(current, ref tmpIncrement);
            }

            p1 = closest1;
            p2 = closest2;
            distance = dist;
        }
 public PathFollowingBehavior(Path basePath, LineList leftBound, LineList rightBound, SpeedCommand speedCommand)
 {
     this.basePath = basePath;
     this.leftBound = leftBound;
     this.rightBound = rightBound;
     this.speedCommand = speedCommand;
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="initialLane"></param>
 /// <param name="finalLane"></param>
 public ChangeLanesState(bool initialIsOncoming, LaneID initialLane, LaneID finalLane, Path changeLanesPath,
     PointOnPath initialPosition, PointOnPath lowerBound, PointOnPath upperBound)
     : base(initialLane, finalLane)
 {
     this.initialIsOncoming = initialIsOncoming;
     this.ChangeLanesPath = changeLanesPath;
     this.InitialPosition = initialPosition;
     this.LowerBound = lowerBound;
     this.UpperBound = upperBound;
 }
        private LinePath ConvertPath(UrbanChallenge.Common.Path.Path p)
        {
            LinePath lineList = new LinePath();

            lineList.Add(p[0].Start);
            for (int i = 0; i < p.Count; i++)
            {
                lineList.Add(p[i].End);
            }

            return(lineList);
        }
        private void RenderRelativePath(VehicleState vs, Path transPath, Graphics g, WorldTransform t, bool isArbiterPath)
        {
            if((isArbiterPath && DrawingUtility.DrawArbiterLanePath) ||
                (!isArbiterPath && DrawingUtility.DrawOperationalLanePath))
            {
                // compute the rotation matrix to add in our vehicles rotation
                /*Matrix3 rotMatrix = new Matrix3(
                    Math.Cos(vs.heading.ArcTan), -Math.Sin(vs.heading.ArcTan), 0,
                    Math.Sin(vs.heading.ArcTan), Math.Cos(vs.heading.ArcTan), 0,
                    0, 0, 1);

                // compute the translation matrix to move our vehicle's location
                Matrix3 transMatrix = new Matrix3(
                    1, 0, vs.xyPosition.X,
                    0, 1, vs.xyPosition.Y,
                    0, 0, 1);

                // compute the combined transformation matrix
                Matrix3 m = rotMatrix * transMatrix;

                // clone, transform and add each segment to our path
                transPath.Transform(m);*/

                float nomPixelWidth = 2.0f;
                float penWidth = nomPixelWidth / t.Scale;
                Pen arbiterPen = new Pen(Color.FromArgb(100, DrawingUtility.ArbiterLanePath), penWidth);
                Pen operationalPen = new Pen(Color.FromArgb(100, DrawingUtility.OperationalLanePath), penWidth);

                // display path
                foreach (IPathSegment ps in transPath)
                {
                    if (ps is BezierPathSegment)
                    {
                        BezierPathSegment seg = (BezierPathSegment)ps;
                        CubicBezier cb = seg.cb;

                        if (isArbiterPath)
                        {
                            g.DrawBezier(arbiterPen, DrawingUtility.ToPointF(cb.P0), DrawingUtility.ToPointF(cb.P1), DrawingUtility.ToPointF(cb.P2), DrawingUtility.ToPointF(cb.P3));
                        }
                        else
                        {
                            g.DrawBezier(operationalPen, DrawingUtility.ToPointF(cb.P0), DrawingUtility.ToPointF(cb.P1), DrawingUtility.ToPointF(cb.P2), DrawingUtility.ToPointF(cb.P3));
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Reason about changing lanes
        /// </summary>
        /// <param name="previousChangeLanePath">previous change lane path</param>
        /// <param name="initialLanePath">lane path that vehicle is changing from</param>
        /// <param name="targetLanePath">	lane path that vehicle is changing to</param>
        /// <param name="targetType">type for target lane, left or right</param>
        /// <param name="initialLaneVehicles">observed vehicles on initial lane</param>
        /// <param name="initialLaneLowerBound">lower bound point on initial lane (similar to obstacle on target lane)</param>
        /// <param name="initialLaneUpperBound">upper bound point on initial lane (similar to obstacle on initial lane)</param>
        /// <param name="vehicleState">vehicle state</param>
        public Path LaneChangeObstacleReasoning(Path previousChangeLanePath,
            Path initialLanePath, Path targetLanePath,
            TargetLaneChangeType targetType,
            ObservedVehicle[] initialLaneVehicles,
            PointOnPath initialLaneLowerBound,
            PointOnPath initialLaneUpperBound,
            VehicleState vehicleState)
        {
            // check if target lane is to the left or right
            if (targetType == TargetLaneChangeType.Left) {
                // set up vehicle and lane information
                InitialiseInformation(vehicleState.xyPosition, vehicleState.heading, vehicleState.speed,
                                                            null, targetLanePath, initialLanePath);
            }
            else {
                // set up vehicle and lane information
                InitialiseInformation(vehicleState.xyPosition, vehicleState.heading, vehicleState.speed,
                                                            initialLanePath, targetLanePath, null);
            }

            // set up static obstacles (none for now)
            staticObstaclesIn.Clear();
            staticObstaclesOut.Clear();
            staticObstaclesFake.Clear();

            // set up dynamic obstacles
            dynamicObstacles.Clear();
            dynamicObstaclesPaths.Clear();
            SetDynamicObstacles(initialLanePath, initialLaneVehicles);

            // determine risk of previous spline path, if provided
            double pathRisk, pathRiskDist, pathSepDist;
            if (previousChangeLanePath != null) {
                // check risk of  previous spline path
                CheckPathRisk(previousChangeLanePath, out pathRisk, out pathRiskDist, out pathSepDist);

                // if no risk was found, return previous spline path
                if (pathRisk == 0)
                    return previousChangeLanePath;
            }

            // set up number of paths based on lane width
            double spacing = 0.25;
            int numPaths = (int)Math.Round(currentLaneWidth / spacing);
            if ((int)Math.IEEERemainder((double)numPaths, 2.0) == 0)
                numPaths -= 1;

            // increase number of drift paths
            int midPathIndex;
            numPaths += 12;
            midPathIndex = (numPaths - 1) / 2;

            double[] pathsRisk, pathsRiskDist, pathsSepDist, pathsCost;
            Path[] paths = new Path[numPaths];
            int selectedPathIndex;

            PointOnPath targetLaneLowerBound = targetLanePath.GetClosest(initialLaneLowerBound.pt);
            PointOnPath targetLaneUpperBound = targetLanePath.GetClosest(initialLaneUpperBound.pt);
            double targetLaneLowerBoundDist = Math.Round(targetLanePath.DistanceBetween(currentLanePosition, targetLaneLowerBound), 1);
            double targetLaneUpperBoundDist = Math.Round(targetLanePath.DistanceBetween(currentLanePosition, targetLaneUpperBound), 1);

            // generate obstacles for lower and upper bound points
            Coordinates lowerBoundObstacle = targetLaneLowerBound.pt;
            Coordinates upperBoundObstacle = initialLaneUpperBound.pt;
            if (targetType == TargetLaneChangeType.Left) {
                lowerBoundObstacle += targetLaneLowerBound.segment.Tangent(targetLaneLowerBound).RotateM90().Normalize(0.5 * currentLaneWidth - 1.0);
                upperBoundObstacle += initialLaneUpperBound.segment.Tangent(initialLaneUpperBound).Rotate90().Normalize(0.5 * rightLaneWidth - 1.0);
            }
            else {
                lowerBoundObstacle += targetLaneLowerBound.segment.Tangent(targetLaneLowerBound).Rotate90().Normalize(0.5 * currentLaneWidth - 1.0);
                upperBoundObstacle += initialLaneUpperBound.segment.Tangent(initialLaneUpperBound).RotateM90().Normalize(0.5 * leftLaneWidth - 1.0);
            }
            staticObstaclesFake.Add(lowerBoundObstacle);
            staticObstaclesFake.Add(upperBoundObstacle);

            // path projection distance
            double projectionDist = Math.Max(targetLaneLowerBoundDist, TahoeParams.VL + TahoeParams.FL);
            double origProjectionDist = projectionDist;

            Path currentChangeLanePath = new Path();

            do {
                // lookahead point
                double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = targetLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for first part of spline path
                Coordinates startPoint = vehiclePosition;
                Coordinates midPoint	 = lookaheadPt.pt + offsetVec;
                Coordinates startVec	 = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
                Coordinates midVec		 = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                // lookahead point (for end point)
                lookaheadDist = projectionDist + 10;
                lookaheadPt = targetLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path (for end point)
                offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for second part of spline path
                Coordinates endPoint = lookaheadPt.pt + offsetVec;
                Coordinates endVec	 = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                /////////////////////////////////
                Coordinates shiftedMidPoint, shiftedEndPoint;
                Coordinates shiftMidVec = midVec.Rotate90();
                Coordinates shiftEndVec = endVec.Rotate90();

                // generate multiple spline paths
                for (int i = 0; i < numPaths; i++) {
                    shiftedMidPoint = midPoint - shiftMidVec.Normalize((i - midPathIndex) * spacing);
                    shiftedEndPoint = endPoint - shiftEndVec.Normalize((i - midPathIndex) * spacing);

                    // generate spline path
                    paths[i] = GenerateBezierPath(startPoint, shiftedMidPoint, startVec, midVec);

                    // generate extension to spline path
                    Path extPath = GenerateBezierPath(shiftedMidPoint, shiftedEndPoint, midVec, endVec);

                    // add extension to path
                    paths[i].Add((BezierPathSegment)extPath[0]);
                }

                // evaluate paths and select safest path
                selectedPathIndex = EvaluatePaths(paths, midPathIndex, out pathsRisk, out pathsRiskDist, out pathsSepDist, out pathsCost);

                // project further if current spline path has risk
                if (pathsRisk[selectedPathIndex] != 0) {
                    if (projectionDist == targetLaneUpperBoundDist + TahoeParams.RL)
                        break;

                    projectionDist = Math.Min(projectionDist + TahoeParams.VL / 2, targetLaneUpperBoundDist + TahoeParams.RL);
                }

            } while (pathsRisk[selectedPathIndex] != 0 && projectionDist <= targetLaneUpperBoundDist + TahoeParams.RL);

            // check if path without risk was found
            if (pathsRisk[selectedPathIndex] == 0)
                return paths[selectedPathIndex];
            else
                return null;
        }
        /// <summary>
        /// Set dynamic obstacles given in absolute coordinates (Version 2a)
        /// </summary>
        /// <param name="obstacles"></param>
        public void SetDynamicObstacles(Path observedVehiclePath, ObservedVehicle[] observedVehicles)
        {
            // generate paths for
            for (int i = 0; i < observedVehicles.Length; i++) {
                // add observed vehicle
                dynamicObstacles.Add(observedVehicles[i]);

                // lane position
                PointOnPath observedVehicleLanePosition = observedVehiclePath.GetClosest(observedVehicles[i].AbsolutePosition);

                // lookahead point
                double projectionDist = Math.Max(observedVehicles[i].Speed * 5, 10) + 0.5 * TahoeParams.VL;
                double lookaheadDist = projectionDist;
                PointOnPath projectionPoint = observedVehiclePath.AdvancePoint(observedVehicleLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = projectionPoint.segment.Tangent(projectionPoint).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = observedVehicles[i].AbsolutePosition;
                Coordinates endPoint = projectionPoint.pt + offsetVec;
                Coordinates startVec = observedVehicleLanePosition.segment.Tangent(observedVehicleLanePosition).Normalize(Math.Max(observedVehicles[i].Speed, 2.0));
                Coordinates endVec = projectionPoint.segment.Tangent(projectionPoint).Normalize(Math.Max(observedVehicles[i].Speed, 2.0));

                // generate mid points of path
                int midPointsTotal = (int)Math.Round(projectionDist / 5.0) - 1;
                double midPointStepDist = projectionDist / (midPointsTotal + 1);
                Coordinates[] midPoints = new Coordinates[midPointsTotal];
                Coordinates[] midVecs = new Coordinates[midPointsTotal];
                Coordinates[] midShiftVecs = new Coordinates[midPointsTotal];
                for (int j = 0; j < midPointsTotal; j++) {
                    // lookahead point
                    lookaheadDist = projectionDist * (j + 1) / (midPointsTotal + 1);
                    projectionPoint = observedVehiclePath.AdvancePoint(observedVehicleLanePosition, ref lookaheadDist);

                    // extend point if at end of path
                    offsetVec = new Coordinates(0, 0);
                    if (lookaheadDist > 0.5)
                        offsetVec = projectionPoint.segment.Tangent(projectionPoint).Normalize(lookaheadDist);

                    // prepare ctrl points for spline path
                    midPoints[j]		= projectionPoint.pt + offsetVec;
                    midVecs[j]			= projectionPoint.segment.Tangent(projectionPoint).Normalize(Math.Max(vehicleSpeed, 2.0));
                    midShiftVecs[j] = midVecs[j].Rotate90();
                }

                // vehicle vector with respect to segment closest point
                Coordinates carVec = observedVehicles[i].AbsolutePosition - observedVehicleLanePosition.pt;
                // segment tangent vector
                Coordinates pathVec = observedVehicleLanePosition.segment.Tangent(observedVehicleLanePosition);
                // compute offtrack error
                double offtrackError = Math.Sign(carVec.Cross(pathVec)) * observedVehicleLanePosition.pt.DistanceTo(observedVehicles[i].AbsolutePosition);

                // path points
                Coordinates[] pathPoints = new Coordinates[midPointsTotal + 2];
                pathPoints[0] = startPoint;
                pathPoints[midPointsTotal + 1] = endPoint;
                for (int j = 0; j < midPointsTotal; j++) {
                        double control = 0.0;
                        if (j == 0)
                            control = 0.35;
                        else if (j == midPointsTotal - 1)
                            control = -0.35;

                        pathPoints[j + 1] = midPoints[j] - midShiftVecs[j].Normalize(offtrackError *
                                                                                                                                                 (midPointsTotal - j + control) /
                                                                                                                                                 (midPointsTotal + 1));
                }

                // generate spline path with points
                Path projectedPath = new Path();
                CubicBezier[] beziers = SmoothingSpline.BuildC2Spline(pathPoints, startVec.Normalize(0.5 * midPointStepDist),
                                                                                                                            endVec.Normalize(0.5 * midPointStepDist), 0.5);
                for (int j = 0; j < beziers.Length; j++) {
                    projectedPath.Add(new BezierPathSegment(beziers[j], (double?)null, false));
                }

                // generate spline path
                dynamicObstaclesPaths.Add(projectedPath);

                // generate static obstacles if speed is close to zero
                if (observedVehicles[i].Speed < 1.0) {
                    Coordinates tVec = observedVehicleLanePosition.segment.Tangent(observedVehicleLanePosition).Normalize(observedVehicles[i].Length / 2);
                    Coordinates rVec = observedVehicleLanePosition.segment.Tangent(observedVehicleLanePosition).Rotate90().Normalize(observedVehicles[i].Width / 2);
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition + tVec + rVec); // front left
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition + tVec - rVec); // front right
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition - tVec + rVec); // rear left
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition - tVec - rVec); // rear right
                }
            }
        }
        /// <summary>
        /// Produces an obstacle reasoning path for an intersection situation
        /// </summary>
        /// <param name="originalTurnPath">The default turn path for the turn</param>
        /// <param name="entryAdjacentLanePath">The path defining the lane that is adjacent to the entry lane</param>
        /// <param name="entryPath">The path we will follow in the entry lane</param>
        /// <param name="entryAdjacentLaneVehicles">The vehicles in the lane adjacent to the entry we are traveling to</param>
        /// <param name="vehicleState">Our current vehicle state</param>
        /// <returns>A modified turn path to follow that avoids the obstacles in the entry's adjacent lane</returns>
        public Path IntersectionObstacleReasoning(Path originalTurnPath,
            Path entryAdjacentLanePath, Path entryPath,
            ObservedVehicle[] entryAdjacentLaneVehicles,
            VehicleState vehicleState)
        {
            // set up vehicle and lane information
            InitialiseInformation(vehicleState.xyPosition, vehicleState.heading, vehicleState.speed,
                                                        null, originalTurnPath, null);

            // set up static obstacles (none for now)
            staticObstaclesIn.Clear();
            staticObstaclesOut.Clear();
            staticObstaclesFake.Clear();

            // set up dynamic obstacles
            dynamicObstacles.Clear();
            dynamicObstaclesPaths.Clear();
            SetDynamicObstacles(entryAdjacentLanePath, entryAdjacentLaneVehicles);

            // set up number of paths based on lane width
            double spacing = 0.25;
            int numPaths = (int)Math.Round(currentLaneWidth / spacing);
            if ((int)Math.IEEERemainder((double)numPaths, 2.0) == 0)
                numPaths -= 1;

            // increase number of drift paths
            int midPathIndex;
            numPaths += 12;
            midPathIndex = (numPaths - 1) / 2;

            double[] pathsRisk, pathsRiskDist, pathsSepDist, pathsCost;
            Path[] paths = new Path[numPaths];

            // path shift vector
            Coordinates pathStartVec = originalTurnPath[0].Tangent(originalTurnPath.StartPoint);
            Coordinates pathEndVec	 = originalTurnPath[originalTurnPath.Count - 1].Tangent(originalTurnPath.EndPoint);
            Coordinates shiftVec = Math.Sign(pathEndVec.Cross(pathStartVec)) * originalTurnPath[0].Tangent(originalTurnPath.StartPoint);

            // generate multiple paths
            for (int i = 0; i < numPaths; i++) {
                // determine path shift vector
                Coordinates sVec = shiftVec.Normalize((i - midPathIndex) * spacing);

                // generate path
                paths[i] = new Path();
                BezierPathSegment bezSeg = (BezierPathSegment)originalTurnPath[0];
                paths[i].Add(new BezierPathSegment(bezSeg.cb.P0, bezSeg.cb.P1,
                                                                                     bezSeg.cb.P2 - sVec, bezSeg.cb.P3 - sVec, (double?)null, false));
                for (int j = 1; j < originalTurnPath.Count; j++) {
                    bezSeg = (BezierPathSegment)originalTurnPath[j];
                    paths[i].Add(new BezierPathSegment(bezSeg.cb.P0 - sVec, bezSeg.cb.P1 - sVec,
                                                                                         bezSeg.cb.P2 - sVec, bezSeg.cb.P3 - sVec, (double?)null, false));
                }
            }

            // evaluate paths and select safest path
            int selectedPathIndex = EvaluatePaths(paths, midPathIndex, out pathsRisk, out pathsRiskDist, out pathsSepDist, out pathsCost);

            // check if path without risk was found
            if (pathsRisk[selectedPathIndex] == 0)
                return paths[selectedPathIndex];
            else
                return null;
        }
        /// <summary>
        /// Generates a relative or absolute path based upon an input list of coordinates
        /// </summary>
        /// <param name="coordiantes"></param>
        /// <param name="position"></param>
        /// <param name="heading"></param>
        /// <param name="relative"></param>
        /// <returns></returns>
        public static IPath GeneratePathFromCoordinates(List<Coordinates> coordinates, Coordinates position, Coordinates heading, bool relative)
        {
            // 1. if this needs to be a vehicle relative path
            if (relative)
            {
                // use the relative path generation function to return
                IPath path = VehicleRelativePath(coordinates, position, heading);
                return path;

            }
            // 2. otherwise this needs to be an absolute path
            else
            {
                // Create cubic spline based upon the coordinates
                List<CubicBezier> spline = SplineC2FromPoints(coordinates);

                // Create the Path Segments
                List<IPathSegment> bezierPathSegments = new List<IPathSegment>();
                foreach (CubicBezier bezier in spline)
                {
                    bezierPathSegments.Add(new BezierPathSegment(bezier, null, false));
                }

                // Create the path
                Path path = new Path(bezierPathSegments);
                path.CoordinateMode = CoordinateMode.AbsoluteProjected;

            /*if (relative)
            {
                Debug.WriteLine("-heading arc tan: -" + (heading.ArcTan * 180 / Math.PI));

                // compute the rotation matrix to add in our vehicles rotation
                Matrix3 rotMatrix = new Matrix3(
                    Math.Cos(-heading.ArcTan), -Math.Sin(-heading.ArcTan), 0,
                    Math.Sin(-heading.ArcTan), Math.Cos(-heading.ArcTan), 0,
                    0, 0, 1);

                // compute the translation matrix to move our vehicle's location
                Matrix3 transMatrix = new Matrix3(
                    1, 0, -position.X,
                    0, 1, -position.Y,
                    0, 0, 1);

                // compute the combined transformation matrix
                Matrix3 m = transMatrix * rotMatrix;

                // clone, transform and add each segment to our path
                path.Transform(m);
            }*/
                // Return
                return path;
            }
        }
        /// <summary>
        /// Transformas a path into a vehicle relative path
        /// </summary>
        /// <param name="spline"></param>
        /// <param name="position"></param>
        /// <param name="heading"></param>
        /// <returns></returns>
        public static IPath VehicleRelativePath(List<Coordinates> absolutePath, Coordinates position, Coordinates heading)
        {
            // 1. Transform the absolute path into a vehicle relative path w.r.t position
            List<Coordinates> translatedPath = new List<Coordinates>();
            foreach (Coordinates coordinate in absolutePath)
            {
                Coordinates translatedCoordinate = coordinate - position;
                translatedPath.Add(translatedCoordinate);
            }

            // 2. Rotate the translated path into a vehicle relative path w.r.t heading
            List<Coordinates> rotatedPath = new List<Coordinates>();
            Coordinates zeroAngle = new Coordinates(1,0);
            foreach (Coordinates coordinate in translatedPath)
            {
                Coordinates rotatedCoordinate = coordinate.Rotate(zeroAngle.ArcTan - heading.ArcTan);
                rotatedPath.Add(rotatedCoordinate);
            }

            // 3. Create cubic spline based upon the coordinates
            List<CubicBezier> spline = SplineC2FromPoints(rotatedPath);

            // 4. Create the Path Segments
            List<IPathSegment> bezierPathSegments = new List<IPathSegment>();
            foreach(CubicBezier bezier in spline)
            {
                bezierPathSegments.Add(new BezierPathSegment(bezier, null, false));
            }

            // 5. Create the path
            Path path = new Path(bezierPathSegments, CoordinateMode.VehicleRelative);
            path.CoordinateMode = CoordinateMode.VehicleRelative;

            // 6. Return
            return path;
        }
        public void AvoidancePath(Path currentLanePath, Path leftLanePath, Path rightLanePath,
            ObservedObstacles observedObstacles,
            ObservedVehicle[] observedVehicles,
            Coordinates position, Coordinates heading, double speed,
            out AboutPath aboutPath, out Path avoidancePath)
        {
            // set up vehicle and lane information
            InitialiseInformation(position, heading, speed, leftLanePath, currentLanePath, rightLanePath);

            // manage static and dynamic dynamic obstacles
            //SetDynamicObstacles(observedVehicles);
            SetStaticObstacles(currentLanePath, observedObstacles);

            // obtain points along the path and their tangents
            List<Coordinates> pathPoints, pathPointTangents;
            List<double> pathPointDistances;
            GetPointsOnPath(currentLanePath, currentLanePosition, 25, 1,
                                            out pathPoints, out pathPointTangents, out pathPointDistances);

            int binTotal = 41; // odd
            int binMidIndex = (binTotal - 1) / 2;
            double binSize = 0.2;
            double binRange = binTotal * binSize;
            int[] binSelectedIndexes = new int[pathPoints.Count];
            Coordinates[] pathShifts = new Coordinates[pathPoints.Count];

            for (int i = 0; i < pathPoints.Count; i++) {

                double[] bins = new double[binTotal];
                foreach (Coordinates obstacle in staticObstaclesIn) {
                    if (Math.Abs(pathPoints[i].X - obstacle.X) > 5.0 ||
                            Math.Abs(pathPoints[i].Y - obstacle.Y) > 5.0)
                        continue;

                    Coordinates obsTf = obstacle - pathPoints[i];
                    obsTf = obsTf.Rotate(-pathPointTangents[i].ArcTan);

                    if (Math.Abs(obsTf.Y) < 4.0 && Math.Abs(obsTf.X) < 4.0)
                        bins[(int)Math.Round(-obsTf.Y / binSize) + binMidIndex] += 1;
                }

                double[] riskBins = new double[binTotal];
                for (int j = 0; j < binTotal; j++) {
                    for (int k = Math.Max(j-10, 0); k < Math.Min(j+10, binTotal); k++) {
                        riskBins[j] += bins[k];
                    }
                }

                List<int> candidateBinIndexes = new List<int>();
                for (int j = 0; j < binTotal; j++) {
                    if (riskBins[j] == 0)
                        candidateBinIndexes.Add(j);
                }

                double weightDev = 5;   // weight for path deviation penalty
                double weightDir = 1;   // weight for left path penalty
                List<double> costBins = new List<double>();
                foreach (int candidateBinIndex in candidateBinIndexes) {
                    double dir;
                    if (candidateBinIndex < binMidIndex)
                        dir = 1;
                    else
                        dir = 0;
                    costBins.Add(weightDev * Math.Abs(candidateBinIndex - binMidIndex) +
                                             weightDir * dir);
                }

                binSelectedIndexes[i] = -1;
                double minCost = -1;
                for (int j = 0; j < candidateBinIndexes.Count; j++) {
                    if (costBins[j] < minCost || minCost == -1) {
                        binSelectedIndexes[i] = candidateBinIndexes[j];
                        minCost = costBins[j];
                    }
                }

                pathShifts[i] += binSize * (binMidIndex - binSelectedIndexes[i]) * pathPointTangents[i].RotateM90().Normalize();
            }

            for (int i = 1; i < pathPoints.Count-1; i++) {
                if (binSelectedIndexes[i] != binSelectedIndexes[i - 1] && binSelectedIndexes[i] != binSelectedIndexes[i + 1])
                    binSelectedIndexes[i] = binSelectedIndexes[i - 1];
            }

            for (int i = 0; i < pathPoints.Count; i++) {
                pathPoints[i] += binSize * (binSelectedIndexes[i] - binMidIndex) * pathPointTangents[i].RotateM90().Normalize();
            }

            // generate path with points
            CubicBezier[] beziers = SmoothingSpline.BuildC2Spline(pathPoints.ToArray(), null, null, 0.5);
            avoidancePath = new Path();
            for (int i = 0; i < beziers.Length; i++) {
                avoidancePath.Add(new BezierPathSegment(beziers[i], (double?)null, false));
            }
            aboutPath = AboutPath.Normal;
        }
        /// <summary>
        /// Produces an obstacle reasoning path for lane type situations (Version 1)
        /// </summary>
        /// <param name="leftLanePath">The path representing the left lane</param>
        /// <param name="leftLaneIsOncoming">Whether the left lane path is oncoming or not</param>
        /// <param name="leftLaneVehicles">The vehicles referenced to the left lane</param>
        /// <param name="currentLaneDefaultPath">The default path for the current lane</param>
        /// <param name="rightLanePath">The path of the right lane, always going in our same direction</param>
        /// <param name="rightLaneVehicles">The vehicles referenced to the right lane</param>
        /// <param name="vehicleState">Our current vehicle state</param>
        /// <returns>A modified lane path that avoids the vehicles in the adjacent lanes while staying in the current lane</returns>
        public Path LaneObstacleReasoningVer1(Path leftLanePath, bool leftLaneIsOncoming,
            ObservedVehicle[] leftLaneVehicles,
            Path currentLanePath,
            Path rightLanePath,
            ObservedVehicle[] rightLaneVehicles,
            VehicleState vehicleState)
        {
            // set up vehicle and lane information
            InitialiseInformation(vehicleState.xyPosition, vehicleState.heading, vehicleState.speed,
                                                        leftLanePath, currentLanePath, rightLanePath);

            // set up static obstacles (none for now)
            staticObstaclesIn.Clear();
            staticObstaclesOut.Clear();
            staticObstaclesFake.Clear();

            // set up dynamic obstacles
            dynamicObstacles.Clear();
            dynamicObstaclesPaths.Clear();
            SetDynamicObstacles(leftLanePath,  leftLaneVehicles);
            SetDynamicObstacles(rightLanePath, rightLaneVehicles);

            double projectionDist = Math.Max(vehicleSpeed * 3, 10) + TahoeParams.FL;
            double origProjectionDist = projectionDist;

            // set up number of paths based on lane width
            double spacing = 0.25;
            int numPaths = (int)Math.Round(currentLaneWidth / spacing);
            if ((int)Math.IEEERemainder((double)numPaths, 2.0) == 0)
                numPaths -= 1;

            // increase number of drift paths
            int midPathIndex;
            if (leftLaneIsOncoming == true) {
                midPathIndex = (numPaths - 1) / 2;
                numPaths += 6;
            }
            else {
                numPaths += 12;
                midPathIndex = (numPaths - 1) / 2;
            }

            double[] pathsRisk, pathsRiskDist, pathsSepDist, pathsCost;
            Path[] paths = new Path[numPaths];
            int selectedPathIndex;

            do {
                // lookahead point
                double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = currentLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = vehiclePosition;
                Coordinates endPoint = lookaheadPt.pt + offsetVec;
                Coordinates startVec = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
                Coordinates endVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                Coordinates shiftVec = endVec.Rotate90();

                // generate multiple spline paths
                for (int i = 0; i < numPaths; i++) {
                    // generate spline path
                    paths[i] = GenerateBezierPath(startPoint, endPoint - shiftVec.Normalize((i - midPathIndex) * spacing), startVec, endVec);
                }

                // evaluate paths and select safest path
                selectedPathIndex = EvaluatePaths(paths, midPathIndex, out pathsRisk, out pathsRiskDist, out pathsSepDist, out pathsCost);

                if (pathsRisk[selectedPathIndex] != 0)
                    projectionDist = Math.Max(pathsRiskDist[selectedPathIndex] - 1, 0);

            } while (pathsRisk[selectedPathIndex] != 0 && projectionDist > 7.5);

            // return back safest path
            return paths[selectedPathIndex];
        }
        /// <summary>
        /// Get polygon surrounding a path
        /// </summary>
        /// <param name="path"></param>
        /// <param name="startPosition"></param>
        /// <param name="lookaheadDist"></param>
        /// <param name="stepDist"></param>
        /// <param name="leftLimit"></param>
        /// <param name="rightLimit"></param>
        /// <returns></returns>
        private Polygon GetPathPolygon(Path path, PointOnPath startPosition, 
            double lookaheadDist, double stepDist, double leftLimit, double rightLimit)
        {
            // obtain points along the path and their tangents
            List<Coordinates> pathPoints, pathPointTangents;
            List<double> pathPointDistances;
            GetPointsOnPath(path, startPosition, lookaheadDist, stepDist,
                                            out pathPoints, out pathPointTangents, out pathPointDistances);

            // left and right boundaries of region
            List<Coordinates> leftPoints = new List<Coordinates>();
            List<Coordinates> rightPoints = new List<Coordinates>();
            for (int i = 0; i < pathPoints.Count; i++) {
                leftPoints.Add(pathPoints[i] + pathPointTangents[i].Rotate90().Normalize(leftLimit));
                rightPoints.Insert(0, pathPoints[i] + pathPointTangents[i].RotateM90().Normalize(rightLimit));
            }

            // obtain points for sensor region
            leftPoints.AddRange(rightPoints);

            // prune points defining region
            Coordinates prevPoint;
            Coordinates nextPoint;
            double prevAngle;
            double nextAngle;
            double diffAngle;
            for (int i = 1; i < leftPoints.Count - 1; i++) {
                prevPoint = leftPoints[i - 1] - leftPoints[i];
                nextPoint = leftPoints[i + 1] - leftPoints[i];
                prevAngle = prevPoint.ArcTan;
                nextAngle = nextPoint.ArcTan;
                if (prevAngle < 0) prevAngle += 2 * Math.PI;
                if (nextAngle < 0) nextAngle += 2 * Math.PI;
                if (prevAngle > nextAngle)
                    diffAngle = prevAngle - nextAngle;
                else
                    diffAngle = nextAngle - prevAngle;

                if (Math.Abs(diffAngle - Math.PI) < 5 * Math.PI / 180) {
                    leftPoints.RemoveAt(i);
                    i--;
                }
            }

            // define sensor polygon
            return new Polygon(leftPoints);
        }
        /// <summary>
        /// Get the points along a path and their tangents and distances
        /// </summary>
        /// <param name="path">path to find points on</param>
        /// <param name="startPoint">point on path to start from</param>
        /// <param name="lookaheadDist">distance to lookahead for points</param>
        /// <param name="stepDist">step distance between points on path</param>
        /// <param name="pathPoints">return points on path</param>
        /// <param name="pathPointTangents">returns tangents of points on paths</param>
        private void GetPointsOnPath(Path path, PointOnPath startPoint, double lookaheadDist, double stepDist, 
            out List<Coordinates> pathPoints,
            out List<Coordinates> pathPointTangents,
            out List<double>      pathPointDistances)
        {
            double tStep;
            double remDist, travelDist = 0;
            pathPoints = new List<Coordinates>();
            pathPointTangents  = new List<Coordinates>();
            pathPointDistances = new List<double>();

            // retrieve current segment
            int segmentIndex = path.IndexOf(startPoint.segment);
            BezierPathSegment segment = (BezierPathSegment)path[segmentIndex];

            // determine t for start point when segment length is normalized to 1
            double t = startPoint.dist / segment.Length;

            // add start point and tangent
            pathPoints.Add(startPoint.pt);
            pathPointTangents.Add(segment.Bezier.dBdt(t));
            pathPointDistances.Add(0);

            // travel along path to find points until lookahead distance is reached
            while (travelDist < lookaheadDist) {
                // determine time step for step distance when segment length is normalized to 1
                tStep = stepDist / segment.Length;

                // increment t to move along path by step distance
                t += tStep;

                // check if reached end of current segment
                if (t < 1) {
                    // still on current segment

                    // add path point
                    pathPoints.Add(segment.Bezier.Bt(t));

                    // update distance travelled along path
                    travelDist += stepDist;
                }
                else {
                    // reached end of current segment

                    t -= 1; // remaining t

                    // determine remaining distance on next segment
                    remDist = t * segment.Length;

                    // update distance travelled so far on current segment
                    travelDist += stepDist - remDist;

                    // increment segment index
                    segmentIndex += 1;

                    // check if reached end of path
                    if (segmentIndex < path.Count) {
                        // not at end of path yet

                        // retrieve next segment
                        segment = (BezierPathSegment)path[segmentIndex];

                        // determine t for remaining distance when segment length is normalized to 1
                        t = remDist / segment.Length;

                        // add path point
                        pathPoints.Add(segment.Bezier.Bt(t));
                    }
                    else {
                        // at end of path

                        remDist = lookaheadDist - travelDist;

                        // add extended path point
                        pathPoints.Add(segment.End + segment.Bezier.dBdt(t).Normalize(remDist));
                    }

                    // update remaining distance tarvelled along path
                    travelDist += remDist;
                }

                // add path point tangent and distance
                pathPointTangents.Add(segment.Bezier.dBdt(t));
                pathPointDistances.Add(travelDist);
            }
        }
        // evaluate paths and select safest path
        private int EvaluatePaths(Path[] paths, int goalPathIndex,
            out double[] pathsRisk,
            out double[] pathsRiskDist,
            out double[] pathsSepDist,
            out double[] pathsCost)
        {
            int numPaths = paths.Length;
            int selectedPathIndex;
            pathsRisk			= new double[numPaths];
            pathsRiskDist = new double[numPaths];
            pathsSepDist	= new double[numPaths];
            pathsCost			= new double[numPaths];

            // determine risk of spline path
            for (int i = 0; i < numPaths; i++) {
                CheckPathRisk(paths[i], out pathsRisk[i], out pathsRiskDist[i], out pathsSepDist[i]);
            }

            // find minimum path risk (0 means it is a safe path, non-zero means it has some risk
            double minPathRisk = -1;
            for (int i = 0; i < numPaths; i++) {
                pathsRisk[i] = Math.Round(pathsRisk[i], 3);
                if (pathsRisk[i] < minPathRisk || minPathRisk == -1)
                    minPathRisk = pathsRisk[i];
            }

            // select candidate paths and set up their cost
            for (int i = 0; i < numPaths; i++) {
                if (pathsRisk[i] == minPathRisk)
                    pathsCost[i] = 0;
                else
                    pathsCost[i] = -1;
            }

            // find cost of candidate paths
            double weightDev = 5;   // weight for path deviation penalty
            double weightDir = 1;   // weight for left path penalty
            for (int i = 0; i < numPaths; i++) {

                // skip paths with risk in first spline
                if (pathsCost[i] < 0)
                    continue;

                double dir;
                if (i < goalPathIndex)
                    dir = 1;
                else
                    dir = 0;

                pathsCost[i] = weightDev * Math.Abs(i - goalPathIndex) +
                                             weightDir * dir;
            }

            // find index of path to select
            selectedPathIndex  = -1;
            double minPathCost = -1;
            for (int i = 0; i < numPaths; i++) {
                if (pathsCost[i] < 0)
                    continue;

                if (pathsCost[i] < minPathCost || minPathCost == -1) {
                    selectedPathIndex = i;
                    minPathCost = pathsCost[i];
                }
            }

            return selectedPathIndex;
        }
        /// <summary>
        /// Generate spline path with one bezier path segment
        /// </summary>
        /// <param name="startPoint">	start point of bezier path</param>
        /// <param name="endPoint">		end point of bezier path</param>
        /// <param name="startVec">		start tangent of bezier path where magnitude reflects speed</param>
        /// <param name="endVec">			end tangent of bezier path where magnitude reflects speed</param>
        /// <returns></returns>
        private Path GenerateBezierPath(Coordinates startPoint, Coordinates endPoint, Coordinates startVec, Coordinates endVec)
        {
            Coordinates p = startPoint - endPoint;
            Coordinates w = startVec - (-endVec);
            double d = w.Length;
            double time2cpa = 0;

            // find time to closest point of approach
            if (Math.Abs(d) > 1e-6)
                time2cpa = -p.Dot(w) / Math.Pow(d, 2);

            // set minimum time to 0.1 to prevent middle control points from
            if (time2cpa < 0.1)
                time2cpa = 0.1;

            // generate bezier path
            double splineGain = 0.75;
            Coordinates p0 = startPoint;
            Coordinates p1 = startPoint + splineGain * time2cpa * startVec;
            Coordinates p2 = endPoint   + splineGain * time2cpa * (-endVec);
            Coordinates p3 = endPoint;
            Path bezierPath = new Path();
            bezierPath.Add(new BezierPathSegment(p0, p1, p2, p3, (double?)null, false));

            return bezierPath;
        }
        /// <summary>
        /// Defines the sensor region to group obstacles
        /// </summary>
        /// <param name="currentPath"></param>
        /// <returns></returns>
        private void DefineSensorRegion(Path currentPath)
        {
            // left and right limits of sensor region
            double leftLimit  = (leftLaneValid  ? leftLaneWidth  : 0) + currentLaneWidth / 2;
            double rightLimit = (rightLaneValid ? rightLaneWidth : 0) + currentLaneWidth / 2;

            // get polygon around path
            sensorPolygon = GetPathPolygon(currentPath, currentLanePosition, maxPlanDist + TahoeParams.FL, 5, leftLimit, rightLimit);
        }
        /// <summary>
        /// Check for risk of path
        /// </summary>
        /// <param name="planPath">			path to be evaluated</param>
        /// <param name="pathRisk">			risk of path</param>
        /// <param name="pathRiskDist">	distance when risk is first encountered</param>
        /// <param name="pathSepDist">	minimum separation distance encountered</param>
        private void CheckPathRisk(Path planPath, out double pathRisk, out double pathRiskDist, out double pathSepDist)
        {
            double avoidDistInsideLane	= TahoeParams.T / 2 + 1.0;
            double avoidDistOutsideLane = TahoeParams.T / 2 + 0.3;
            double avoidDistFake				= TahoeParams.T / 2 + 1.0;

            // evaluate for static obstacles

            // obtain points along the path and their tangents
            double pathStepDist = 0.5;
            List<Coordinates> pathPoints, pathPointTangents;
            List<double> pathPointDistances;
            GetPointsOnPath(planPath, planPath.StartPoint, planPath.Length, pathStepDist,
                                            out pathPoints, out pathPointTangents, out pathPointDistances);

            // find risk of path
            double sepDist;
            Coordinates pathPoint;

            // initialise path risk values
            pathRisk		 = 0;
            pathRiskDist = -1;
            pathSepDist	 = avoidDistInsideLane;

            // check all path points for separation
            for (int i = 1; i < pathPoints.Count; i++) {
                // check vehicle rear and front axle points
                for (int j = 0; j < 2; j++) {
                    if (j == 0)
                        pathPoint = pathPoints[i]; // rear axle point
                    else
                        pathPoint = pathPoints[i] + pathPointTangents[i].Normalize(TahoeParams.L); // front axle point

                    // check for separation with obstacles inside lanes
                    foreach (Coordinates obstacle in staticObstaclesIn) {
                        if (Math.Abs(pathPoint.X - obstacle.X) > avoidDistInsideLane ||
                                Math.Abs(pathPoint.Y - obstacle.Y) > avoidDistInsideLane)
                            continue;

                        // determine separation distance
                        sepDist = pathPoint.DistanceTo(obstacle);

                        // check if required separation distance is met
                        if (sepDist < avoidDistInsideLane) {
                            // update risk
                            pathRisk += (avoidDistInsideLane - sepDist) / pathPointDistances[i];

                            // save distance of first occurence of risk
                            if (pathRiskDist == -1)
                                pathRiskDist = pathPointDistances[i];

                            // save minimum separation distance encounter
                            if (pathSepDist > sepDist || pathSepDist == -1)
                                pathSepDist = sepDist;
                        }
                    }

                    // check for separation with obstacles outside lanes
                    foreach (Coordinates obstacle in staticObstaclesOut) {
                        if (Math.Abs(pathPoint.X - obstacle.X) > avoidDistOutsideLane ||
                                Math.Abs(pathPoint.Y - obstacle.Y) > avoidDistOutsideLane)
                            continue;

                        // determine separation distance
                        sepDist = pathPoint.DistanceTo(obstacle);

                        // check if required separation distance is met
                        if (sepDist < avoidDistOutsideLane) {
                            // update risk
                            pathRisk += (avoidDistOutsideLane - sepDist) / pathPointDistances[i];

                            // save distance of first occurence of risk
                            if (pathRiskDist == -1)
                                pathRiskDist = pathPointDistances[i];

                            // save minimum separation distance encounter
                            if (pathSepDist > sepDist || pathSepDist == -1)
                                pathSepDist = sepDist;
                        }
                    }

                    // check for separation with fake obstacles
                    foreach (Coordinates obstacle in staticObstaclesFake) {
                        if (Math.Abs(pathPoint.X - obstacle.X) > avoidDistFake ||
                                Math.Abs(pathPoint.Y - obstacle.Y) > avoidDistFake)
                            continue;

                        // determine separation distance
                        sepDist = pathPoint.DistanceTo(obstacle);

                        // check if required separation distance is met
                        if (sepDist < avoidDistFake) {
                            // update risk
                            pathRisk += (avoidDistFake - sepDist) / pathPointDistances[i];

                            // save distance of first occurence of risk
                            if (pathRiskDist == -1)
                                pathRiskDist = pathPointDistances[i];

                            // save minimum separation distance encounter
                            if (pathSepDist > sepDist || pathSepDist == -1)
                                pathSepDist = sepDist;
                        }
                    }
                }
            }

            // evaluate for dynamic obstacles

            // obtain points along the vehicle path and their tangents
            pathStepDist = vehicleSpeed * 0.1;
            pathPoints.Clear();
            pathPointTangents.Clear();
            pathPointDistances.Clear();
            GetPointsOnPath(planPath, planPath.StartPoint, Math.Min(vehicleSpeed * 5, planPath.Length), pathStepDist,
                                            out pathPoints, out pathPointTangents, out pathPointDistances);

            double dynObsPathStepDist;
            List<Coordinates> dynObsPathPoints, dynObsPathPointTangents;
            List<double> dynObsPathPointDistances;

            // check separation with dynamic obstacles
            for (int i = 0; i < dynamicObstacles.Count; i++) {

                // treat as zero speed if going slow
                double dynObsSpeed = 0;
                if (dynamicObstacles[i].Speed > 0.1)
                    dynObsSpeed = dynamicObstacles[i].Speed;

                // obtain points along the dynamic obstacle and their tangents
                dynObsPathStepDist = dynObsSpeed * 0.1;
                GetPointsOnPath(dynamicObstaclesPaths[i], dynamicObstaclesPaths[i].StartPoint,
                                                Math.Min(dynObsSpeed * 5, dynamicObstaclesPaths[i].Length),
                                                dynObsPathStepDist, out dynObsPathPoints,
                                                out dynObsPathPointTangents, out dynObsPathPointDistances);

                int maxPoints;
                if (dynObsSpeed == 0)
                    maxPoints = pathPoints.Count;
                else
                    maxPoints = (int)Math.Min(pathPoints.Count, dynObsPathPoints.Count);

                for (int j = 0; j < maxPoints; j++) {

                    // find points of dynamic obstacle
                    Coordinates[] dynObsPoints = new Coordinates[4];
                    Coordinates tVec, rVec;
                    int dynObsPathIndex;
                    if (dynObsSpeed == 0)
                        dynObsPathIndex = 0;
                    else
                        dynObsPathIndex = j;
                    tVec = dynObsPathPointTangents[dynObsPathIndex].Normalize(dynamicObstacles[i].Length / 2);
                    rVec = dynObsPathPointTangents[dynObsPathIndex].Rotate90().Normalize(dynamicObstacles[i].Width / 2);
                    dynObsPoints[0] = dynObsPathPoints[dynObsPathIndex] + tVec + rVec; // front left
                    dynObsPoints[1] = dynObsPathPoints[dynObsPathIndex] + tVec - rVec; // front right
                    dynObsPoints[2] = dynObsPathPoints[dynObsPathIndex] - tVec + rVec; // rear left
                    dynObsPoints[3] = dynObsPathPoints[dynObsPathIndex] - tVec - rVec; // rear right

                    // check vehicle rear and front axle points
                    for (int k = 0; k < 2; k++) {
                        if (k == 0)
                            pathPoint = pathPoints[j]; // rear axle point
                        else
                            pathPoint = pathPoints[j] + pathPointTangents[j].Normalize(TahoeParams.L); // front axle point

                        // check for separation with dynamic obstacles
                        for (int d = 0; d < dynObsPoints.Length; d++) {
                            sepDist = pathPoint.DistanceTo(dynObsPoints[d]);

                            // check if required separation distance is met
                            if (sepDist < avoidDistInsideLane) {
                                pathRisk += (avoidDistInsideLane - sepDist) / pathPointDistances[j];

                                // save distance of first occurence of risk
                                if (pathRiskDist == -1)
                                    pathRiskDist = pathPointDistances[j];

                                // save minimum separation distance encounter
                                if (pathSepDist > sepDist || pathSepDist == -1)
                                    pathSepDist = sepDist;
                            }
                        }
                    }
                }
            }

            // update minimum separation distance encountered
            pathSepDist = Math.Max(pathSepDist - TahoeParams.T / 2, 0);
        }
        /// <summary>
        /// Set dynamic obstacles given in absolute coordinates (Version 1)
        /// </summary>
        /// <param name="obstacles"></param>
        public void SetDynamicObstaclesVer1(Path observedVehiclePath, ObservedVehicle[] observedVehicles)
        {
            // generate paths for
            for (int i = 0; i < observedVehicles.Length; i++) {
                // add observed vehicle
                dynamicObstacles.Add(observedVehicles[i]);

                // lane position
                PointOnPath observedVehiclePosition = observedVehiclePath.GetClosest(observedVehicles[i].AbsolutePosition);

                // lookahead point
                double projectionDist = Math.Max(vehicleSpeed * 3, 10) + TahoeParams.FL;
                double lookaheadDist = projectionDist;
                PointOnPath projectionPoint = observedVehiclePath.AdvancePoint(observedVehiclePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = projectionPoint.segment.Tangent(projectionPoint).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = observedVehicles[i].AbsolutePosition;
                Coordinates endPoint = projectionPoint.pt + offsetVec;
                Coordinates startVec = observedVehiclePosition.segment.Tangent(observedVehiclePosition).Normalize(Math.Max(observedVehicles[i].Speed, 2.0));
                Coordinates endVec = projectionPoint.segment.Tangent(projectionPoint).Normalize(Math.Max(observedVehicles[i].Speed, 2.0));

                // generate spline path
                dynamicObstaclesPaths.Add(GenerateBezierPath(startPoint, endPoint, startVec, endVec));

                // generate static obstacles if speed is close to zero
                if (observedVehicles[i].Speed < 1.0) {
                    Coordinates tVec = observedVehiclePosition.segment.Tangent(observedVehiclePosition).Normalize(observedVehicles[i].Length / 2);
                    Coordinates rVec = observedVehiclePosition.segment.Tangent(observedVehiclePosition).Rotate90().Normalize(observedVehicles[i].Width / 2);
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition + tVec + rVec); // front left
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition + tVec - rVec); // front right
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition - tVec + rVec); // rear left
                    staticObstaclesIn.Add(observedVehicles[i].AbsolutePosition - tVec - rVec); // rear right
                }
            }
        }
        /// <summary>
        /// Reason about changing lanes (simple version)
        /// </summary> 
        public void LaneChangePlan(Path changeLanesPath, Path initialLane, Path targetLane,
            ObservedObstacles observedObstacles,
            ObservedVehicle[] initialLaneObservedVehicles,
            ObservedVehicle[] targetLaneObservedVehicles,
            PointOnPath lowerBound, PointOnPath upperBound,
            Coordinates position, Coordinates heading, double speed,
            out AboutPath aboutPath, out Path laneChangePath)
        {
            // set up vehicle states
            vehiclePosition = position;
            vehicleSpeed = speed;
            vehicleHeading = heading.ArcTan;
            currentLanePosition = targetLane.GetClosest(vehiclePosition);
            leftLanePosition = initialLane != null ? initialLane.GetClosest(vehiclePosition) : new PointOnPath();
            rightLanePosition = initialLane != null ? initialLane.GetClosest(vehiclePosition) : new PointOnPath();

            //// set up lane information
            leftLaneWidth = initialLane != null ? leftLanePosition.pt.DistanceTo(currentLanePosition.pt) : double.NaN;
            rightLaneWidth = initialLane != null ? rightLanePosition.pt.DistanceTo(currentLanePosition.pt) : double.NaN;
            if (double.IsNaN(leftLaneWidth))
                if (double.IsNaN(rightLaneWidth))
                    currentLaneWidth = 3;
                else
                    currentLaneWidth = rightLaneWidth;
            else
                currentLaneWidth = leftLaneWidth;

            //// manage static and dynamic dynamic obstacles
            //ManageObstacles(targetLane, observedObstacles,
            //                initialLaneObservedVehicles, targetLaneObservedVehicles);

            double projectionDist = 15;
            double origProjDist = projectionDist;
            double pathRisk, pathRiskDist, pathSepDist;

            // lookahead point
            double lookaheadDist = projectionDist;
            PointOnPath lookaheadPt = targetLane.AdvancePoint(currentLanePosition, ref lookaheadDist);

            // extend point if at end of path
            Coordinates offsetVec = new Coordinates(0, 0);
            if (lookaheadDist > 0.5)
                offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

            PointOnPath targetUpperBound = targetLane.GetClosest(upperBound.pt);

            // prepare ctrl points for spline path
            Coordinates startPoint = vehiclePosition;
            //Coordinates rVec = lookaheadPt.segment.Tangent(lookaheadPt).Rotate90().Normalize(endOffset);
            Coordinates endPoint = targetUpperBound.pt; // lookaheadPt.pt + offsetVec + rVec;
            Coordinates startVec = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
            Coordinates endVec = targetLane.GetClosest(targetUpperBound.pt).segment.Tangent(targetUpperBound).Normalize(Math.Max(vehicleSpeed, 2.0));
            //Coordinates endVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

            // generate spline path
            laneChangePath = GenerateBezierPath(startPoint, endPoint, startVec, endVec);

            // determine risk of spline path
            CheckPathRisk(laneChangePath, out pathRisk, out pathRiskDist, out pathSepDist);

            if (pathRisk == 0)
                aboutPath = AboutPath.Normal;
            else
                aboutPath = AboutPath.Stop;
        }
        /// <summary>
        /// Initialise vehicle and lane information
        /// </summary>
        private void InitialiseInformation(Coordinates position, Coordinates heading, double speed, 
            Path leftLanePath, Path currentLanePath, Path rightLanePath)
        {
            // set up vehicle information
            vehiclePosition = position;
            vehicleSpeed		= speed;
            vehicleHeading	= heading.ArcTan;

            // set up lane valid flags
            leftLaneValid	 = leftLanePath  != null ? true : false;
            rightLaneValid = rightLanePath != null ? true : false;

            // set up positions on lanes
            currentLanePosition = currentLanePath.GetClosest(vehiclePosition);
            leftLanePosition		= leftLaneValid  ? leftLanePath.GetClosest(vehiclePosition)  : new PointOnPath();
            rightLanePosition		= rightLaneValid ? rightLanePath.GetClosest(vehiclePosition) : new PointOnPath();

            // set up lane information
            leftLaneWidth  = leftLaneValid  ? leftLanePosition.pt.DistanceTo(currentLanePosition.pt)  : double.NaN;
            rightLaneWidth = rightLaneValid ? rightLanePosition.pt.DistanceTo(currentLanePosition.pt) : double.NaN;
            if (leftLaneValid)
                currentLaneWidth = leftLaneWidth;
            else if (rightLaneValid)
                currentLaneWidth = rightLaneWidth;
            else
                currentLaneWidth = TahoeParams.T + 1.0;
        }
        /// <summary>
        /// Reason about changing lanes
        /// </summary>
        /// <param name="previousChangeLanePath">previous change lane path</param>
        /// <param name="initialLanePath">lane path that vehicle is changing from</param>
        /// <param name="targetLanePath">	lane path that vehicle is changing to</param>
        /// <param name="targetType">	type for target lane, left or right</param>
        /// <param name="observedObstacles">static obstacles</param>
        /// <param name="observedVehicles">observed vehicles</param>
        /// <param name="lowerBound">	lower bound point on initial lane (similar to obstacle on target lane)</param>
        /// <param name="upperBound"> upper bound point on initial lane (similar to obstacle on initial lane)</param>
        /// <param name="position">		vehicle absolute position in m</param>
        /// <param name="heading">		vehicle heading as a vector</param>
        /// <param name="speed">			vehicle speed in m/s</param>
        /// <param name="aboutPath">	type of path being returned</param>
        /// <param name="currentChangeLanePath">change lane path</param>
        public void LaneChangePlanAdvance(Path previousChangeLanePath,
            Path initialLanePath, Path targetLanePath,
            TargetLaneChangeType targetType,
            ObservedObstacles observedObstacles,
            ObservedVehicle[] observedVehicles,
            PointOnPath initialLaneLowerBound, PointOnPath initialLaneUpperBound,
            Coordinates position, Coordinates heading, double speed,
            out AboutPath aboutPath, out Path currentChangeLanePath)
        {
            // check if target lane is to the left or right
            if (targetType == TargetLaneChangeType.Left) {
                // set up vehicle and lane information
                InitialiseInformation(position, heading, speed, null, targetLanePath, initialLanePath);
                // manage static and dynamic dynamic obstacles
                InitialiseObstacles(null, targetLanePath, initialLanePath, observedObstacles, observedVehicles);
            }
            else {
                // set up vehicle and lane information
                InitialiseInformation(position, heading, speed, initialLanePath, targetLanePath, null);
                // manage static and dynamic dynamic obstacles
                InitialiseObstacles(initialLanePath, targetLanePath, null, observedObstacles, observedVehicles);
            }

            // determine risk of previous spline path, if provided
            double pathRisk, pathRiskDist, pathSepDist;
            if (previousChangeLanePath != null) {
                // check risk of  previous spline path
                CheckPathRisk(previousChangeLanePath, out pathRisk, out pathRiskDist, out pathSepDist);

                if (pathRisk == 0) {
                    // no risk was found, return previous spline path
                    currentChangeLanePath = previousChangeLanePath;
                    aboutPath = AboutPath.Normal;
                    return;
                }
            }

            PointOnPath targetLaneLowerBound = targetLanePath.GetClosest(initialLaneLowerBound.pt);
            PointOnPath targetLaneUpperBound = targetLanePath.GetClosest(initialLaneUpperBound.pt);
            double targetLaneLowerBoundDist = Math.Round(targetLanePath.DistanceBetween(currentLanePosition, targetLaneLowerBound),1);
            double targetLaneUpperBoundDist = Math.Round(targetLanePath.DistanceBetween(currentLanePosition, targetLaneUpperBound),1);

            // generate obstacles for lower and upper bound points
            Coordinates lowerBoundObstacle = targetLaneLowerBound.pt;
            Coordinates upperBoundObstacle = initialLaneUpperBound.pt;
            if (targetType == TargetLaneChangeType.Left) {
                lowerBoundObstacle += targetLaneLowerBound.segment.Tangent(targetLaneLowerBound).RotateM90().Normalize(0.5 * currentLaneWidth - 1.0);
                upperBoundObstacle += initialLaneUpperBound.segment.Tangent(initialLaneUpperBound).Rotate90().Normalize(0.5 * rightLaneWidth - 1.0);
            }
            else {
                lowerBoundObstacle += targetLaneLowerBound.segment.Tangent(targetLaneLowerBound).Rotate90().Normalize(0.5 * currentLaneWidth - 1.0);
                upperBoundObstacle += initialLaneUpperBound.segment.Tangent(initialLaneUpperBound).RotateM90().Normalize(0.5 * leftLaneWidth - 1.0);
            }
            staticObstaclesFake.Add(lowerBoundObstacle);
            staticObstaclesFake.Add(upperBoundObstacle);

            // path projection distance
            double projectionDist = Math.Max(targetLaneLowerBoundDist, TahoeParams.VL + TahoeParams.FL);
            double origProjectionDist = projectionDist;

            do {
              // lookahead point
              double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = targetLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

              // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                  offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

              // prepare ctrl points for spline path
              Coordinates startPoint = vehiclePosition;
              Coordinates endPoint = lookaheadPt.pt + offsetVec;
              Coordinates startVec = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
              Coordinates endVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

              // generate spline path
              currentChangeLanePath = GenerateBezierPath(startPoint, endPoint, startVec, endVec);

              // determine risk of spline path
                CheckPathRisk(currentChangeLanePath, out pathRisk, out pathRiskDist, out pathSepDist);

                // project further if current spline path has risk
                if (pathRisk != 0) {
                    if (projectionDist == targetLaneUpperBoundDist + TahoeParams.RL)
                        break;

                    projectionDist = Math.Min(projectionDist + TahoeParams.VL / 2, targetLaneUpperBoundDist + TahoeParams.RL);
                }

            } while (pathRisk != 0 && projectionDist <= targetLaneUpperBoundDist + TahoeParams.RL);

            // check if path without risk was found
            if (pathRisk == 0)
                aboutPath = AboutPath.Normal;
            else
                aboutPath = AboutPath.Null;
        }
 public SimplePathFollowingBehavior(Path path, float vel, bool constVelocityMode)
 {
     this.path = path;
     this.velocity = vel;
     this.constVelocityMode = constVelocityMode;
 }
        /// <summary>
        /// Produces an obstacle reasoning path for lane type situations (Version 2b - Latest)
        /// </summary>
        /// <param name="leftLanePath">The path representing the left lane</param>
        /// <param name="leftLaneIsOncoming">Whether the left lane path is oncoming or not</param>
        /// <param name="leftLaneVehicles">The vehicles referenced to the left lane</param>
        /// <param name="currentLaneDefaultPath">The default path for the current lane</param>
        /// <param name="rightLanePath">The path of the right lane, always going in our same direction</param>
        /// <param name="rightLaneVehicles">The vehicles referenced to the right lane</param>
        /// <param name="vehicleState">Our current vehicle state</param>
        /// <returns>A modified lane path that avoids the vehicles in the adjacent lanes while staying in the current lane</returns>
        public Path LaneObstacleReasoning(Path leftLanePath, bool leftLaneIsOncoming,
            ObservedVehicle[] leftLaneVehicles,
            Path currentLanePath,
            Path rightLanePath,
            ObservedVehicle[] rightLaneVehicles,
            VehicleState vehicleState)
        {
            // set up vehicle and lane information
            InitialiseInformation(vehicleState.xyPosition, vehicleState.heading, vehicleState.speed,
                                                        leftLanePath, currentLanePath, rightLanePath);

            // set up static obstacles (none for now)
            staticObstaclesIn.Clear();
            staticObstaclesOut.Clear();
            staticObstaclesFake.Clear();

            // set up dynamic obstacles
            dynamicObstacles.Clear();
            dynamicObstaclesPaths.Clear();
            SetDynamicObstacles(leftLanePath, leftLaneVehicles);
            SetDynamicObstacles(rightLanePath, rightLaneVehicles);

            double projectionDist = Math.Max(vehicleSpeed * 5, 10) + TahoeParams.FL;
            double origProjectionDist = projectionDist;

            // set up number of paths based on lane width
            double spacing = 0.25;
            int numPaths = (int)Math.Round(currentLaneWidth / spacing);
            if ((int)Math.IEEERemainder((double)numPaths, 2.0) == 0)
                numPaths -= 1;

            // increase number of drift paths
            int midPathIndex;
            if (leftLaneIsOncoming == true) {
                midPathIndex = (numPaths - 1) / 2;
                numPaths += 6;
            }
            else {
                numPaths += 12;
                midPathIndex = (numPaths - 1) / 2;
            }

            double[] pathsRisk, pathsRiskDist, pathsSepDist, pathsCost;
            Path[] paths = new Path[numPaths];
            int selectedPathIndex;

            do {
                // lookahead point
                double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = currentLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = vehiclePosition;
                Coordinates endPoint = lookaheadPt.pt + offsetVec;
                Coordinates startVec = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
                Coordinates endVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                // generate mid points of path
                int midPointsTotal = (int)Math.Round(projectionDist / 5.0) - 1;
                double midPointStepDist = projectionDist / (midPointsTotal + 1);
                Coordinates[] midPoints = new Coordinates[midPointsTotal];
                Coordinates[] midVecs		= new Coordinates[midPointsTotal];
                Coordinates[] midShiftVecs = new Coordinates[midPointsTotal];
                for (int i = 0; i < midPointsTotal; i++) {
                    // lookahead point
                    lookaheadDist = projectionDist * (i + 1) / (midPointsTotal + 1);
                    lookaheadPt = currentLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                    // extend point if at end of path
                    offsetVec = new Coordinates(0, 0);
                    if (lookaheadDist > 0.5)
                        offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                    // prepare ctrl points for spline path
                    midPoints[i] = lookaheadPt.pt + offsetVec;
                    midVecs[i]	 = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));
                    midShiftVecs[i] = midVecs[i].Rotate90();
                }

                Coordinates endShiftVec = endVec.Rotate90();

                // generate multiple spline paths
                for (int i = 0; i < numPaths; i++) {

                    // vehicle vector with respect to segment closest point
                    Coordinates carVec = vehiclePosition - currentLanePosition.pt;
                    // segment tangent vector
                    Coordinates pathVec = currentLanePosition.segment.Tangent(currentLanePosition);
                    // compute offtrack error
                    double offtrackError = Math.Sign(carVec.Cross(pathVec)) * currentLanePosition.pt.DistanceTo(vehiclePosition);

                    // path points
                    Coordinates[] pathPoints = new Coordinates[midPointsTotal + 2];
                    pathPoints[0] = startPoint;
                    pathPoints[midPointsTotal + 1] = endPoint - endShiftVec.Normalize((i - midPathIndex) * spacing);
                    for (int j = 0; j < midPointsTotal; j++) {
                        double control = 0.0;
                        if (j == 0)
                            control = 0.35;
                        else if (j == midPointsTotal - 1)
                            control = -0.35;

                        pathPoints[j+1] = midPoints[j] -
                            midShiftVecs[j].Normalize((i - midPathIndex) * spacing * (j + 1 - control) / (midPointsTotal + 1) +
                                                                                offtrackError * (midPointsTotal - j + control) / (midPointsTotal + 1));
                    }

                    // generate spline path with points
                    paths[i] = new Path();
                    CubicBezier[] beziers = SmoothingSpline.BuildC2Spline(pathPoints, startVec.Normalize(0.5 * midPointStepDist),
                                                                                                                                endVec.Normalize(0.5 * midPointStepDist), 0.5);
                    for (int j = 0; j < beziers.Length; j++) {
                        paths[i].Add(new BezierPathSegment(beziers[j], (double?)null, false));
                    }
                }

                // evaluate paths and select safest path
                selectedPathIndex = EvaluatePaths(paths, midPathIndex, out pathsRisk, out pathsRiskDist, out pathsSepDist, out pathsCost);

                if (pathsRisk[selectedPathIndex] != 0)
                    projectionDist = Math.Max(pathsRiskDist[selectedPathIndex] - 1, 0);

            } while (pathsRisk[selectedPathIndex] != 0 && projectionDist > 7.5);

            // return back safest path
            //int index = DateTime.Now.Second;
            //selectedPathIndex = index - (paths.Length - 1) * (int)Math.Floor((double)index / (paths.Length - 1));
            return paths[selectedPathIndex];
        }
        /// <summary>
        /// Set static obstacles given as vectors relative from imu
        /// </summary>
        /// <param name="obstacles">observed obstacles in relative vectors from imu</param>
        private void SetStaticObstacles(Path path, ObservedObstacles observedObstacles)
        {
            // clear static obstacles
            staticObstaclesIn.Clear();
            staticObstaclesOut.Clear();
            staticObstaclesFake.Clear();

            // determine sensor region to group obstacles
            DefineSensorRegion(path);

            List<PointOnPath> pop = new List<PointOnPath>();

            // prepare static obstacles for obstacle reasoning
            for (int i = 0; i < observedObstacles.Obstacles.Length; i++) {
                // transform obstacle to absolute coordinates
                Coordinates obs = new Coordinates(TahoeParams.IL, 0);
                obs += observedObstacles.Obstacles[i].ObstacleVector;
                obs = obs.Rotate(vehicleHeading) + vehiclePosition;

                // sort out static obstacles
                if (sensorPolygon.IsInside(obs) == true)
                    staticObstaclesIn.Add(obs);
                else
                    staticObstaclesOut.Add(obs);
            }
        }
 public SimpleStayInLaneBehavior(Path basePath, double laneWidth, double maxSpeed)
 {
     this.basePath = basePath;
     this.laneWidth = laneWidth;
     this.maxSpeed = maxSpeed;
 }
        /// <summary>
        /// Reason about travelling the lane ahead
        /// </summary>
        /// <param name="currentLanePath">lane path that vehicle is following</param>
        /// <param name="leftLanePath">lane path to the left of vehicle</param>
        /// <param name="rightLanePath">lane path to the right of vehicle</param>
        /// <param name="observedObstacles">static obstacles</param>
        /// <param name="observedVehicles">observed vehicles</param>
        /// <param name="position">		vehicle absolute position in m</param>
        /// <param name="heading">		vehicle heading as a vector</param>
        /// <param name="speed">			vehicle speed in m/s</param>
        /// <param name="aboutPath">	type of path being returned</param>
        /// <param name="forwardPath">forward path</param>
        public void ForwardPlan(Path currentLanePath, Path leftLanePath, Path rightLanePath,
            ObservedObstacles observedObstacles,
            ObservedVehicle[] observedVehicles,
            Coordinates position, Coordinates heading, double speed,
            out AboutPath aboutPath, out Path forwardPath)
        {
            // set up vehicle and lane information
            InitialiseInformation(position, heading, speed, leftLanePath, currentLanePath, rightLanePath);

            // manage static and dynamic dynamic obstacles
            InitialiseObstacles(leftLanePath, currentLanePath, rightLanePath,
                                                    observedObstacles, observedVehicles);

            double projectionDist = Math.Max(vehicleSpeed * 3, 10) + TahoeParams.FL;
            double origProjectionDist = projectionDist;

            double spacing = 0.4;
            int numPaths = (int)Math.Round(currentLaneWidth / spacing);
            numPaths -= (int)Math.IEEERemainder((double)numPaths, 2.0);
            int midPathIndex = (numPaths - 1) / 2;
            int selectedPathIndex;
            double[] pathsRisk = new double[numPaths];
            double[] pathsRiskDist = new double[numPaths];
            double[] pathsSepDist = new double[numPaths];
            double[] pathsCost = new double[numPaths];
            Path[] paths = new Path[numPaths];

            do {
                // lookahead point
                double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = currentLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                  offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = vehiclePosition;
                Coordinates endPoint	 = lookaheadPt.pt + offsetVec;
                Coordinates startVec	 = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
                Coordinates endVec		 = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                Coordinates rVec = endVec.Rotate90();

                // generate multiple spline paths and evaluate their risks
                for (int i = 0; i < numPaths; i++) {
                    // generate spline path
                    paths[i] = GenerateBezierPath(startPoint, endPoint + rVec.Normalize((i - midPathIndex) * spacing), startVec, endVec);

                    // determine risk of spline path
                    CheckPathRisk(paths[i], out pathsRisk[i], out pathsRiskDist[i], out pathsSepDist[i]);
                }

                // find minimum path risk (0 means it is a safe path, non-zero means it has some risk
                double minPathRisk = -1;
                for (int i = 0; i < numPaths; i++) {
                    pathsRisk[i] = Math.Round(pathsRisk[i], 3);
                    if (pathsRisk[i] < minPathRisk || minPathRisk == -1)
                        minPathRisk = pathsRisk[i];
                }

                // select candidate paths and set up their cost
                for (int i = 0; i < numPaths; i++) {
                    if (pathsRisk[i] == minPathRisk)
                        pathsCost[i] = 0;
                    else
                        pathsCost[i] = -1;
                }

                // find cost of candidate paths
                double weightDev = 5;   // weight for path deviation penalty
                double weightDir = 1;   // weight for left path penalty
                for (int i = 0; i < numPaths; i++) {

                    // skip paths with risk in first spline
                    if (pathsCost[i] < 0)
                        continue;

                    double dir;
                    if (i < midPathIndex)
                        dir = 1;
                    else
                        dir = 0;

                    pathsCost[i] = weightDev * Math.Abs(i - midPathIndex) +
                                                 weightDir * dir;
                }

                // find index of path to select
                selectedPathIndex = -1;
                double minPathCost = -1;
                for (int i = 0; i < numPaths; i++) {
                    if (pathsCost[i] < 0)
                        continue;

                    if (pathsCost[i] < minPathCost || minPathCost == -1) {
                        selectedPathIndex = i;
                        minPathCost = pathsCost[i];
                    }
                }

                if (pathsRisk[selectedPathIndex] != 0)
                    projectionDist = Math.Max(pathsRiskDist[selectedPathIndex] - 1, 0);

            } while (pathsRisk[selectedPathIndex] != 0 && projectionDist > 7.5);

            // prepare safest path
            forwardPath = new Path();
            forwardPath.Add((BezierPathSegment)(paths[selectedPathIndex][0]));

            if (pathsRisk[selectedPathIndex] == 0)
                aboutPath = AboutPath.Normal;
            else if (projectionDist != 0)
                aboutPath = AboutPath.Stop;
            else
                aboutPath = AboutPath.Null;
        }
        /// <summary>
        /// Preprocesses the lane paths
        /// </summary>
        /// <param name="lane"></param>
        /// <param name="forwardsPath"></param>
        /// <param name="backwardsPath"></param>
        public static void PreprocessLanePaths(Lane lane,
            out Path forwardsPath, out Path backwardsPath, out List<CubicBezier> forwardSpline)
        {
            // 1. list of absolute positions of lane coordinates
            List<Coordinates> forwardCoordinates = new List<Coordinates>();

            // 2. loop through waypoints
            foreach (RndfWayPoint rwp in lane.Waypoints.Values)
            {
                // add position
                forwardCoordinates.Add(rwp.Position);
            }

            // 3. generate spline
            CubicBezier[] bez = SmoothingSpline.BuildC2Spline(forwardCoordinates.ToArray(), null, null, 0.5);

            // 4. generate path
            List<IPathSegment> forwardPathSegments = new List<IPathSegment>();

            // spline generation
            List<CubicBezier> tmpForwardSpline = new List<CubicBezier>();

            // 5. loop through individual beziers
            foreach (CubicBezier cb in bez)
            {
                // add to spline
                tmpForwardSpline.Add(cb);

                // add to final spline
                forwardPathSegments.Add(new BezierPathSegment(cb, null, false));
            }

            // set spline
            forwardSpline = tmpForwardSpline;

            // 6. Create the forward path
            forwardsPath = new Path(forwardPathSegments, CoordinateMode.AbsoluteProjected);

            // 7. list of backwards coordinates
            List<Coordinates> backwardsCoordinates = forwardCoordinates;
            backwardsCoordinates.Reverse();

            // 8. generate spline
            bez = SmoothingSpline.BuildC2Spline(backwardsCoordinates.ToArray(), null, null, 0.5);

            // 9. generate path
            List<IPathSegment> backwardPathSegments = new List<IPathSegment>();

            // 10. loop through individual beziers
            foreach (CubicBezier cb in bez)
            {
                // add to final spline
                backwardPathSegments.Add(new BezierPathSegment(cb, null, false));
            }

            // 11. generate backwards path
            backwardsPath = new Path(backwardPathSegments, CoordinateMode.AbsoluteProjected);
        }
        /// <summary>
        /// Reason about travelling the lane ahead
        /// </summary>
        /// <param name="currentLanePath">lane path that vehicle is following</param>
        /// <param name="leftLanePath">lane path to the left of vehicle</param>
        /// <param name="rightLanePath">lane path to the right of vehicle</param>
        /// <param name="observedObstacles">static obstacles</param>
        /// <param name="observedVehicles">observed vehicles</param>
        /// <param name="position">		vehicle absolute position in m</param>
        /// <param name="heading">		vehicle heading as a vector</param>
        /// <param name="speed">			vehicle speed in m/s</param>
        /// <param name="aboutPath">	type of path being returned</param>
        /// <param name="forwardPath">forward path</param>
        public void ForwardPlanSimple(Path currentLanePath, Path leftLanePath, Path rightLanePath,
            ObservedObstacles observedObstacles,
            ObservedVehicle[] observedVehicles,
            Coordinates position, Coordinates heading, double speed,
            out AboutPath aboutPath, out Path forwardPath)
        {
            // set up vehicle and lane information
            InitialiseInformation(position, heading, speed, leftLanePath, currentLanePath, rightLanePath);

            // manage static and dynamic dynamic obstacles
            InitialiseObstacles(leftLanePath, currentLanePath, rightLanePath,
                                                    observedObstacles, observedVehicles);

            double projectionDist = Math.Max(vehicleSpeed * 3, 10) + TahoeParams.FL;
            double origProjectionDist = projectionDist;
            double pathRisk, pathRiskDist, pathSepDist;

            do {
                // lookahead point
                double lookaheadDist = projectionDist;
                PointOnPath lookaheadPt = currentLanePath.AdvancePoint(currentLanePosition, ref lookaheadDist);

                // extend point if at end of path
                Coordinates offsetVec = new Coordinates(0, 0);
                if (lookaheadDist > 0.5)
                    offsetVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(lookaheadDist);

                // prepare ctrl points for spline path
                Coordinates startPoint = vehiclePosition;
                Coordinates endPoint = lookaheadPt.pt + offsetVec;
                Coordinates startVec = new Coordinates(1, 0).Rotate(vehicleHeading).Normalize(Math.Max(vehicleSpeed, 2.0));
                Coordinates endVec = lookaheadPt.segment.Tangent(lookaheadPt).Normalize(Math.Max(vehicleSpeed, 2.0));

                // generate spline path
                forwardPath = GenerateBezierPath(startPoint, endPoint, startVec, endVec);

                // determine risk of spline path
                CheckPathRisk(forwardPath, out pathRisk, out pathRiskDist, out pathSepDist);

                if (pathRisk != 0)
                    projectionDist = Math.Max(pathRiskDist - 1, 0);

            } while (pathRisk != 0 && projectionDist != 0);

            if (pathRisk == 0 && projectionDist == origProjectionDist)
                aboutPath = AboutPath.Normal;
            else if (projectionDist != 0)
                aboutPath = AboutPath.Stop;
            else
                aboutPath = AboutPath.Null;
        }
        /// <summary>
        /// Manage obstacle information
        /// </summary>
        /// <param name="currentPath"></param>
        /// <param name="observedObstacles"></param>
        /// <param name="currentLaneObservedVehicles"></param>
        /// <param name="leftLaneObservedVehicles"></param>
        /// <param name="rightLaneObservedVehicles"></param>
        private void InitialiseObstacles(Path leftPath, Path currentPath, Path rightPath, 
            ObservedObstacles observedObstacles,
            ObservedVehicle[] observedVehicles)
        {
            //SetDynamicObstacles(observedVehicles);

            SetStaticObstacles(currentPath, observedObstacles);
        }
        /// <summary>
        /// Check if the other line path intersects this line path
        /// </summary>
        /// <param name="other"></param>
        /// <param name="tol"></param>
        /// <returns></returns>
        public bool Intersects(Path other, double tol)
        {
            // start point want to be outside of this lane
            PointOnPath current = this.PartitionPath.StartPoint;

            double increment = tol / 2.0;
            double dist = 0;

            while (dist == 0)
            {
                Coordinates pt = this.PartitionPath.GetClosest(current.pt).pt;
                PointOnPath tmp = other.GetClosest(pt);
                if (tmp.pt.DistanceTo(pt) <= tol)
                {
                    return true;
                }

                dist = increment;
                current = this.PartitionPath.AdvancePoint(current, ref dist);
            }

            return false;
        }