Beispiel #1
0
 internal void Randomize(double factor)
 {
     for (int i = 2; i < 8; i++)
     {
         Vector v = LinearCombinations.ElementAt(i);
         if (!ImmutablePoints.Contains(v))
         {
             int    sign = (i % 2 == 1) ? 1 : -1;
             Vector orth = Vector.Orthogonal(End - Start);
             orth = (orth / Vector.Abs(orth)) * (Utils.getNextDouble() * factor * sign);
             v.X += orth.X;
             v.Y += orth.Y;
         }
     }
 }
Beispiel #2
0
        public void addPolygons()
        {
            Vector ChannelRadius = Channels[3].Start - Channels[0].Start;

            Point Ende = new Point();

            Ende.longitude = c.XtoLongitude(Channels[3].Start.X);
            Ende.latitude  = c.YtoLatitude(Channels[3].Start.Y);
            Point Start = new Point();

            Start.longitude = c.XtoLongitude(Channels[0].Start.X);
            Start.latitude  = c.YtoLatitude(Channels[0].Start.Y);
            double origDist = Converter.Distance(Ende, Start);

            ChannelRadius = (ChannelRadius / origDist) * (channel * (-1.0 / 2.0));
            Vector ortho             = Vector.Orthogonal(ChannelRadius) / 10.0;
            double factorLengthSides = 10.0;
            double distChannelRadius = -Vector.Abs(ChannelRadius);
            double orthoLengthFactor = 1.0;

            for (int i = 1; i < 8; i += 1)
            {
                Vector localChannelRadius;
                localChannelRadius = Vector.Orthogonal(Channels[0].LinearCombinations[i + 1] - Channels[0].LinearCombinations[i]);
                localChannelRadius = (localChannelRadius / Vector.Abs(localChannelRadius)) * distChannelRadius;
                ortho = Vector.Orthogonal(localChannelRadius) / orthoLengthFactor;

                Vector a1 = Channels[0].LinearCombinations[i] + localChannelRadius + ortho;
                Vector a2 = Channels[0].LinearCombinations[i + 1] + localChannelRadius - ortho;
                Vector a3 = a1 + ChannelRadius * factorLengthSides + ortho;
                Vector a4 = a2 + ChannelRadius * factorLengthSides - ortho;
                Polygons.Add(new ParcourPolygon(a1, a2, a4, a3));

                Vector b1 = Channels[0].LinearCombinations[i] - localChannelRadius + ortho;
                Vector b2 = Channels[0].LinearCombinations[i + 1] - localChannelRadius - ortho;

                localChannelRadius = Vector.Orthogonal(Channels[1].LinearCombinations[i + 1] - Channels[1].LinearCombinations[i]);
                localChannelRadius = (localChannelRadius / Vector.Abs(localChannelRadius)) * distChannelRadius;
                ortho = Vector.Orthogonal(localChannelRadius) / orthoLengthFactor;

                Vector b3 = Channels[1].LinearCombinations[i] + localChannelRadius + ortho;
                Vector b4 = Channels[1].LinearCombinations[i + 1] + localChannelRadius - ortho;
                Polygons.Add(new ParcourPolygon(b1, b2, b4, b3));

                Vector c1 = Channels[1].LinearCombinations[i] - localChannelRadius + ortho;
                Vector c2 = Channels[1].LinearCombinations[i + 1] - localChannelRadius - ortho;

                localChannelRadius = Vector.Orthogonal(Channels[2].LinearCombinations[i + 1] - Channels[2].LinearCombinations[i]);
                localChannelRadius = (localChannelRadius / Vector.Abs(localChannelRadius)) * distChannelRadius;
                ortho = Vector.Orthogonal(localChannelRadius) / orthoLengthFactor;

                Vector c3 = Channels[2].LinearCombinations[i] + localChannelRadius + ortho;
                Vector c4 = Channels[2].LinearCombinations[i + 1] + localChannelRadius - ortho;
                Polygons.Add(new ParcourPolygon(c1, c2, c4, c3));

                Vector d1 = Channels[2].LinearCombinations[i] - localChannelRadius + ortho;
                Vector d2 = Channels[2].LinearCombinations[i + 1] - localChannelRadius - ortho;


                localChannelRadius = Vector.Orthogonal(Channels[3].LinearCombinations[i + 1] - Channels[3].LinearCombinations[i]);
                localChannelRadius = (localChannelRadius / Vector.Abs(localChannelRadius)) * distChannelRadius;
                ortho = Vector.Orthogonal(localChannelRadius) / orthoLengthFactor;

                Vector d3 = Channels[3].LinearCombinations[i] + localChannelRadius + ortho;
                Vector d4 = Channels[3].LinearCombinations[i + 1] + localChannelRadius - ortho;
                Polygons.Add(new ParcourPolygon(d1, d2, d4, d3));


                Vector e1 = Channels[3].LinearCombinations[i] - localChannelRadius + ortho;
                Vector e2 = Channels[3].LinearCombinations[i + 1] - localChannelRadius - ortho;
                Vector e3 = e1 - ChannelRadius * factorLengthSides + ortho;
                Vector e4 = e2 - ChannelRadius * factorLengthSides - ortho;
                Polygons.Add(new ParcourPolygon(e1, e2, e4, e3));
            }
        }
Beispiel #3
0
        public void addPolygons()
        {
            Point Start = new Point();

            Start.longitude = c.XtoLongitude(Channel.Start.X);
            Start.latitude  = c.YtoLatitude(Channel.Start.Y);
            //TODO

            double latitude  = Start.latitude;
            double longitude = Start.longitude;

            double channelMeterKm = channelWidth;
            double latitudePlus1  = latitude + 1;
            double longitudePlus1 = longitude + 1;

            double distLat1  = Converter.Distance(longitude, latitude, longitude, latitudePlus1);
            double distLong1 = Converter.Distance(longitude, latitude, longitudePlus1, latitude);

            double corridorDiffInLat  = channelMeterKm / distLat1;
            double corridorDiffInLong = channelMeterKm / distLong1;

            double channelLatitude  = corridorDiffInLat / 2;
            double channelLongitude = corridorDiffInLong / 2;

            double longitudePlusChannel = longitude + channelLongitude;
            double latitudePlusChannel  = latitude + channelLatitude;

            double channelx = c.LongitudeToX(longitudePlusChannel) - Channel.Start.X;
            double channely = c.LatitudeToY(latitudePlusChannel) - Channel.Start.Y;

            Vector channel = new Vector(channelx, channely, 0);

            Vector startEnd                = new Vector(Channel.End.X, Channel.End.Y, 0) - new Vector(Channel.Start.X, Channel.Start.Y, 0);
            Vector startEndOrtho           = Vector.Orthogonal(startEnd) * (-1);
            Vector startEndOrthoNormalized = (startEndOrtho / Vector.Abs(startEndOrtho)) * Vector.Abs(channel);
            Vector startEndNormalized      = (startEnd / Vector.Abs(startEnd)) * Vector.Abs(channel);

            for (int i = 1; i < 8; i++)
            {
                Vector localChannel                = Channel.LinearCombinations[i + 1] - Channel.LinearCombinations[i];
                Vector localChannelOrtho           = Vector.Orthogonal(localChannel);
                Vector localChannelOrthoNormalized = (localChannelOrtho / Vector.Abs(localChannelOrtho)) * -Vector.Abs(channel);

                Vector a1_intersection = Vector.InterceptionLine(Channel.LinearCombinations[i], startEndOrtho, Channel.LinearCombinations[i] + localChannelOrthoNormalized - localChannel * 10, Channel.LinearCombinations[i + 1] + localChannelOrthoNormalized + localChannel * 10);

                {
                    Vector localChannel2                = Channel.LinearCombinations[i] - Channel.LinearCombinations[i - 1];
                    Vector localChannelOrtho2           = Vector.Orthogonal(localChannel2);
                    Vector localChannelOrthoNormalized2 = (localChannelOrtho2 / Vector.Abs(localChannelOrtho2)) * -Vector.Abs(channel);
                    Vector a1_intersection2             = Vector.InterceptionLine(Channel.LinearCombinations[i], startEndOrtho, Channel.LinearCombinations[i] + localChannelOrthoNormalized2 - localChannel2 * 10, Channel.LinearCombinations[i] + localChannelOrthoNormalized2 + localChannel2 * 10);
                    a1_intersection = new Vector(a1_intersection.X, Math.Min(a1_intersection.Y, a1_intersection2.Y), 0);
                }

                Vector a2_intersection = Vector.InterceptionLine(Channel.LinearCombinations[i + 1], startEndOrtho, Channel.LinearCombinations[i] + localChannelOrthoNormalized - localChannel * 10, Channel.LinearCombinations[i + 1] + localChannelOrthoNormalized + localChannel * 10);

                {
                    Vector localChannel2                = Channel.LinearCombinations[i + 2] - Channel.LinearCombinations[i + 1];
                    Vector localChannelOrtho2           = Vector.Orthogonal(localChannel2);
                    Vector localChannelOrthoNormalized2 = (localChannelOrtho2 / Vector.Abs(localChannelOrtho2)) * -Vector.Abs(channel);
                    Vector a2_intersection2             = Vector.InterceptionLine(Channel.LinearCombinations[i + 1], startEndOrtho, Channel.LinearCombinations[i + 1] + localChannelOrthoNormalized2 - localChannel2 * 10, Channel.LinearCombinations[i + 1] + localChannelOrthoNormalized2 + localChannel2 * 10);
                    a2_intersection = new Vector(a2_intersection.X, Math.Min(a2_intersection.Y, a2_intersection2.Y), 0);
                }

                Vector a1 = a1_intersection;
                Vector a2 = a2_intersection;
                Vector a3 = a1 + startEndOrtho / 3;
                Vector a4 = a2 + startEndOrtho / 3;
                Polygons.Add(new ParcourPolygon(a1, a2, a4, a3));



                Vector b1_intersection = Vector.InterceptionLine(Channel.LinearCombinations[i], startEndOrtho, Channel.LinearCombinations[i] - localChannelOrthoNormalized - localChannel * 10, Channel.LinearCombinations[i + 1] - localChannelOrthoNormalized + localChannel * 10);
                {
                    Vector localChannel2                = Channel.LinearCombinations[i] - Channel.LinearCombinations[i - 1];
                    Vector localChannelOrtho2           = Vector.Orthogonal(localChannel2);
                    Vector localChannelOrthoNormalized2 = (localChannelOrtho2 / Vector.Abs(localChannelOrtho2)) * -Vector.Abs(channel);
                    Vector b1_intersection2             = Vector.InterceptionLine(Channel.LinearCombinations[i], startEndOrtho, Channel.LinearCombinations[i] - localChannelOrthoNormalized2 - localChannel2 * 10, Channel.LinearCombinations[i] - localChannelOrthoNormalized2 + localChannel2 * 10);
                    b1_intersection = new Vector(b1_intersection.X, Math.Max(b1_intersection.Y, b1_intersection2.Y), 0);
                }

                Vector b2_intersection = Vector.InterceptionLine(Channel.LinearCombinations[i + 1], startEndOrtho, Channel.LinearCombinations[i] - localChannelOrthoNormalized - localChannel * 10, Channel.LinearCombinations[i + 1] - localChannelOrthoNormalized + localChannel * 10);

                {
                    Vector localChannel2                = Channel.LinearCombinations[i + 2] - Channel.LinearCombinations[i + 1];
                    Vector localChannelOrtho2           = Vector.Orthogonal(localChannel2);
                    Vector localChannelOrthoNormalized2 = (localChannelOrtho2 / Vector.Abs(localChannelOrtho2)) * -Vector.Abs(channel);
                    Vector b2_intersection2             = Vector.InterceptionLine(Channel.LinearCombinations[i + 1], startEndOrtho, Channel.LinearCombinations[i + 1] - localChannelOrthoNormalized2 - localChannel2 * 10, Channel.LinearCombinations[i + 1] - localChannelOrthoNormalized2 + localChannel2 * 10);
                    b2_intersection = new Vector(b2_intersection.X, Math.Max(b2_intersection.Y, b2_intersection2.Y), 0);
                }

                Vector b1 = b1_intersection;
                Vector b2 = b2_intersection;
                Vector b3 = b1 - startEndOrtho / 3;
                Vector b4 = b2 - startEndOrtho / 3;
                Polygons.Add(new ParcourPolygon(b1, b2, b4, b3));
            }
        }
Beispiel #4
0
        public static List <PenaltySet> CalculatePenaltyPoints(FlightSet flight, out List <IntersectionPoint> lstIntersectionPoints)
        {
            bool useProhZoneCalculation = false;

            Point             last             = null;
            List <PenaltySet> result           = new List <PenaltySet>();
            List <LineP>      PenaltyZoneLines = new List <LineP>();
            // intersectionPoints will contain the intersection poinst of the flight path with SP, FP, PROH areas
            List <IntersectionPoint> intersectionPoints = new List <IntersectionPoint>();
            QualificationRoundSet    qr = flight.QualificationRoundSet;
            ParcourSet parcour          = flight.QualificationRoundSet.ParcourSet;

            useProhZoneCalculation = (parcour.PenaltyCalcType != (int)ParcourType.CHANNELS);


            List <LineP> ChannelZoneLines = getAssignedChannelLineP(parcour, (Route)flight.Route);

            foreach (Line nl in parcour.Line.Where(p => p.Type == (int)LineType.PENALTYZONE))
            {
                PenaltyZoneLines.Add(getLine(nl));
            }

            // add also all channel-specific prohibited zones assigned channel
            PenaltyZoneLines.AddRange(getAssignedProhZonelLines(parcour, (Route)flight.Route));

            List <LineP> dataLines = new List <LineP>();

            foreach (Point g in flight.Point)
            {
                if (last != null)
                {
                    LineP l = new LineP();
                    l.end           = new Vector(g.longitude, g.latitude, 0);
                    l.TimestamEnd   = g.Timestamp;
                    l.start         = new Vector(last.longitude, last.latitude, 0);
                    l.TimestamStart = last.Timestamp;
                    dataLines.Add(l);
                }
                last = g;
            }
            LineP startLine = getStartLine(parcour, (Route)flight.Route);
            LineP endLine   = getEndLine(parcour, (Route)flight.Route);

            if (startLine == null || endLine == null)
            {
                lstIntersectionPoints = intersectionPoints;
                return(result);
            }
            LineP takeOffLine = new LineP();

            takeOffLine.start       = new Vector(qr.TakeOffLine.A.longitude, qr.TakeOffLine.A.latitude, 0);
            takeOffLine.end         = new Vector(qr.TakeOffLine.B.longitude, qr.TakeOffLine.B.latitude, 0);
            takeOffLine.orientation = Vector.Orthogonal(takeOffLine.end - takeOffLine.start);

            long maxTimestamp = 0;

            maxTimestamp = flight.Point.Max(x => x.Timestamp);

            // For TakeOff-, Start- and End Line, we obviously(?) assume that these lines should have been passed two minutes before the end of recording
            // below values are used in case they are not passed
            bool shouldHaveCrossedTakeOff = (maxTimestamp - 2 * tickOfMinute) > flight.TimeTakeOff;
            bool shouldHaveCrossedStart   = (maxTimestamp - 2 * tickOfMinute) > flight.TimeStartLine;
            bool shouldHaveCrossedEnd     = (maxTimestamp - 2 * tickOfMinute) > flight.TimeEndLine;

            bool haveCrossedTakeOff         = false;
            bool haveCrossedStart           = false;
            bool haveCrossedEnd             = false;
            bool insidePenalty              = false;
            long timeSinceInsidePenalty     = 0;
            bool outsideOwnChannel          = true;
            long timeSinceOutsideOwnChannel = 0;
            bool isFirstTimeIntoChannel     = true;

            IntersectionPoint ipTakeOff = new IntersectionPoint();
            IntersectionPoint ipStart   = new IntersectionPoint();
            IntersectionPoint ipEnd     = new IntersectionPoint();

            foreach (LineP l in dataLines)
            {
                double            intersectionTakeOff = getIntersection(l, takeOffLine);
                double            intersectionStart   = getIntersection(l, startLine);
                double            intersectionEnd     = getIntersection(l, endLine);
                IntersectionPoint ip = new IntersectionPoint();

                #region crossing takeOff line
                if (getIntersection(l, takeOffLine, out ip) && !haveCrossedTakeOff)
                {
                    haveCrossedTakeOff = true;
                    intersectionPoints.Add(ip);
                    long crossTime = ip.Timestamp;
                    crossTime = ((crossTime + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // round
                    ipTakeOff = ip;
                    long       diff    = crossTime - flight.TimeTakeOff;
                    PenaltySet penalty = new PenaltySet();
                    penalty.Points = (diff > C_TKOF_TimeUpper * tickOfSecond || diff < C_TKOF_TimeLower * tickOfSecond) ? C_TKOF_MaxPenalty : 0;
                    penalty.Reason = string.Format("Take-off Line planned: {1}, actual: {0}", new DateTime((Int64)crossTime).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime((Int64)flight.TimeTakeOff).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                    result.Add(penalty);
                }
                #endregion

                #region crossing start line
                if (getIntersection(l, startLine, out ip) & !haveCrossedStart)
                {
                    haveCrossedStart = true;
                    intersectionPoints.Add(ip);
                    long crossTime = ip.Timestamp;
                    ipStart = ip;
                    long diff = Math.Abs(crossTime - flight.TimeStartLine);
                    crossTime = ((crossTime + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // round
                    int        sec     = (int)((diff + (tickOfSecond / 2) + 1) / tickOfSecond);
                    PenaltySet penalty = new PenaltySet();
                    penalty.Points = (diff > C_SPFP_TimeTolerance * tickOfSecond) ? Math.Min((sec - C_SPFP_TimeTolerance) * C_PointsPerSec, C_SPFP_MaxPenalty) : 0;
                    penalty.Reason = string.Format("SP Line planned: {1}, actual: {0}", new DateTime((Int64)crossTime).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime((Int64)flight.TimeStartLine).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                    result.Add(penalty);
                }
                #endregion

                if (useProhZoneCalculation || ChannelZoneLines.Count == 0)
                {
                    #region entering or leaving prohibited zone

                    bool stateChanged = false;
                    //IntersectionPoint ip = new IntersectionPoint();
                    if (intersectsProhAreaPoint(PenaltyZoneLines, l, out stateChanged, out ip))
                    {
                        if (stateChanged)
                        {
                            intersectionPoints.Add(ip);
                            if (!insidePenalty)
                            {
                                insidePenalty          = true;
                                timeSinceInsidePenalty = ip.Timestamp;
                            }
                            else
                            {
                                insidePenalty = false;
                                long diff = ip.Timestamp - timeSinceInsidePenalty;
                                if (diff > tickOfSecond * C_PROH_TimeTolerance)
                                {
                                    PenaltySet penalty = new PenaltySet();
                                    // round times for entering/leaving penalty zone to nearest full second
                                    long pstart = ((timeSinceInsidePenalty + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // rounded
                                    long pend   = ((ip.Timestamp + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond;           // rounded
                                    int  sec    = (int)((pend - pstart) / tickOfSecond);
                                    penalty.Points = (sec - C_PROH_TimeTolerance) * C_PointsPerSec;
                                    // Max penalty inside PROH zone: ======>> NOTE: acc FAI rules disabled after NOV 2017; zero means no maximum per event
                                    penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - C_PROH_TimeTolerance) * C_PointsPerSec, C_MaxPenaltyPerEvent) : penalty.Points;
                                    //penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - 5) * 3, C_MaxPenaltyPerEvent) : penalty.Points;
                                    penalty.Reason = string.Format("Penalty zone for {0} sec, [{1} - {2}]", sec, new DateTime(pstart).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime(pend).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                                    result.Add(penalty);
                                }
                            }
                        }
                    }
                    #endregion
                }
                else
                {
                    #region entering or leaving channel

                    bool stateChanged = false;
                    if (intersectsOwnChannel(ChannelZoneLines, l, out stateChanged, out ip))
                    {
                        if (stateChanged)
                        {
                            intersectionPoints.Add(ip);
                            if (!outsideOwnChannel)
                            {
                                outsideOwnChannel          = true;
                                timeSinceOutsideOwnChannel = ip.Timestamp;
                            }
                            else
                            {
                                if (isFirstTimeIntoChannel)
                                {
                                    isFirstTimeIntoChannel = false;
                                    if (haveCrossedStart)
                                    {
                                        timeSinceOutsideOwnChannel = ipStart.Timestamp;
                                    }
                                    else
                                    {
                                        timeSinceOutsideOwnChannel = flight.TimeStartLine;
                                    }
                                }
                                outsideOwnChannel = false;
                                long diff = ip.Timestamp - timeSinceOutsideOwnChannel;
                                if (diff > tickOfSecond * C_PROH_TimeTolerance)
                                {
                                    PenaltySet penalty = new PenaltySet();
                                    // round times for entering/leaving penalty zone to nearest full second
                                    long pstart = ((timeSinceOutsideOwnChannel + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // rounded
                                    long pend   = ((ip.Timestamp + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond;               // rounded
                                    int  sec    = (int)((pend - pstart) / tickOfSecond);
                                    penalty.Points = (sec - C_PROH_TimeTolerance) * C_PointsPerSec;
                                    penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - C_PROH_TimeTolerance) * C_PointsPerSec, C_MaxPenaltyPerEvent) : penalty.Points;
                                    //penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - 5) * 3, C_MaxPenaltyPerEvent) : penalty.Points;
                                    penalty.Reason = string.Format("outside channel for {0} sec, [{1} - {2}]", sec, new DateTime(pstart).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime(pend).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                                    result.Add(penalty);
                                }
                            }
                        }
                    }
                    else
                    {
                        // check if end line is passed now but outside the cannel. if yes, set outSideOwnChannel = false
                        if (getIntersection(l, endLine, out ip))
                        {
                            outsideOwnChannel = false;
                            long diff = ip.Timestamp - timeSinceOutsideOwnChannel;
                            if (diff > tickOfSecond * C_PROH_TimeTolerance)
                            {
                                PenaltySet penalty = new PenaltySet();
                                // round times for entering/leaving penalty zone to nearest full second
                                long pstart = ((timeSinceOutsideOwnChannel + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // rounded
                                long pend   = ((ip.Timestamp + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond;               // rounded
                                int  sec    = (int)((pend - pstart) / tickOfSecond);
                                penalty.Points = (sec - C_PROH_TimeTolerance) * C_PointsPerSec;
                                // Max penalty outside channel; zero value means no Max penalty
                                penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - C_PROH_TimeTolerance) * C_PointsPerSec, C_MaxPenaltyPerEvent) : penalty.Points;
                                //penalty.Points = C_MaxPenaltyPerEvent > 0 ? Math.Min((sec - 5) * 3, C_MaxPenaltyPerEvent) : penalty.Points;
                                penalty.Reason = string.Format("outside channel for {0} sec, [{1} - {2}]", sec, new DateTime(pstart).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime(pend).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                                result.Add(penalty);
                            }
                        }
                    }

                    #endregion
                }

                #region crossing end line
                if (getIntersection(l, endLine, out ip) & !haveCrossedEnd)
                {
                    haveCrossedEnd = true;
                    intersectionPoints.Add(ip);
                    long crossTime = ip.Timestamp;
                    ipEnd = ip;
                    long diff = Math.Abs(crossTime - flight.TimeEndLine);
                    crossTime = ((crossTime + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // round
                    int        sec     = (int)((diff + (tickOfSecond / 2) + 1) / tickOfSecond);
                    PenaltySet penalty = new PenaltySet();
                    penalty.Points = (diff > C_SPFP_TimeTolerance * tickOfSecond) ? Math.Min((sec - C_SPFP_TimeTolerance) * C_PointsPerSec, C_SPFP_MaxPenalty) : 0;
                    penalty.Reason = string.Format("FP Line planned: {1}, actual: {0}", new DateTime((Int64)crossTime).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime((Int64)flight.TimeEndLine).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                    result.Add(penalty);
                }
                #endregion
            }

            #region handling cases where Takeoff-, Start- or End line are not observed/never crossed

            if (shouldHaveCrossedStart && !haveCrossedStart)
            {
                PenaltySet penalty = new PenaltySet();
                penalty.Points = C_SPFP_MaxPenalty;
                penalty.Reason = "SP Line not passed";
                result.Insert(0, penalty); // add to begin of list
            }
            ;
            if (shouldHaveCrossedTakeOff && !haveCrossedTakeOff)
            {
                PenaltySet penalty = new PenaltySet();
                penalty.Points = C_TKOF_MaxPenalty;
                penalty.Reason = "Takeoff Line not passed";
                result.Insert(0, penalty); // add to begin of list
            }
            ;
            if (shouldHaveCrossedEnd && !haveCrossedEnd)
            {
                PenaltySet penalty = new PenaltySet();
                // TODO: handle the case where we have channel calculation but no FP line
                if (!(useProhZoneCalculation || ChannelZoneLines.Count == 0) && outsideOwnChannel)
                {
                    outsideOwnChannel = false;
                    long crossTime = flight.TimeEndLine;
                    long diff      = Math.Abs(crossTime - timeSinceOutsideOwnChannel);
                    if (diff > C_SPFP_TimeTolerance * tickOfSecond)
                    {
                        crossTime = ((crossTime + (tickOfSecond / 2) + 1) / tickOfSecond) * tickOfSecond; // round
                        int sec = (int)((diff + (tickOfSecond / 2) + 1) / tickOfSecond);
                        penalty.Points = Math.Min((sec - C_SPFP_TimeTolerance) * C_PointsPerSec, C_SPFP_MaxPenalty);
                        penalty.Reason = string.Format("outside channel for {0} sec, [{1} - {2}]", sec, new DateTime(timeSinceOutsideOwnChannel).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo), new DateTime(crossTime).ToString(C_TimeFormat, DateTimeFormatInfo.InvariantInfo));
                        result.Add(penalty);
                    }
                }
                penalty        = new PenaltySet();
                penalty.Points = C_SPFP_MaxPenalty;
                penalty.Reason = "FP Line not passed";
                result.Add(penalty);
            }
            ;
            #endregion



            lstIntersectionPoints = intersectionPoints;
            return(result);
        }