예제 #1
0
파일: ar3.cs 프로젝트: RudyMeijer/route66
        /// <summary>
        /// Read AR3 file. See http://confluence.ash.ads.org/display/EHP/Autologic+ar3+route+file+format.+V2
        /// </summary>
        /// <param name="filename">ar3 filename</param>
        /// <returns>ar3 route</returns>
        public static Route ReadAr3(string filename)
        {
            #region FIELDS
            //
            // The distance table contains the relation between LatLng and distance.
            // Filled during Read Gps markers. Filled with unique latlng and sorted distance.
            //
            var distanceTable = new Dictionary <PointLatLng, int>();
            var line          = string.Empty;
            var version       = string.Empty;
            var startPoint    = new PointLatLng();
            var lastDistance  = -1;
            var route         = new Route()
            {
                FileName = filename
            };
            var random = new Random();
            var previousChangeMarker = new ChangeMarker();
            errors = new int[5];             // used in unittesting.
            #endregion
            using (TextReader reader = new StreamReader(filename))
            {
                while ((line = reader.ReadLine()) != null)
                {
                    try
                    {
                        var s = line.Split(':', ',');
                        //
                        #region READ HEADER
                        //
                        if (line.StartsWith("Ar3"))
                        {
                            version = s[1];
                        }
                        else if (line.StartsWith("MachineType"))
                        {
                            route.MachineType = My.GetEnum <MachineTypes>(s[1]);
                        }
                        #endregion
                        //
                        #region READ GPS MARKERS
                        //
                        else if (line.StartsWith("WayPoint["))
                        {
                            var distance = (int)My.Val(s[3]);
                            if (distance < lastDistance)
                            {
                                My.Log($"{++errors[0]} {line} has descending distance and will be ignored.");
                            }
                            else if (distance == lastDistance)
                            {
                                My.Log($"{++errors[1]} Duplicated line {line}");
                            }
                            else
                            {
                                var point = Unique(new PointLatLng(My.Val(s[2]), My.Val(s[1])), distance);
                                route.GpsMarkers.Add(new GpsMarker(point));
                                if (startPoint.IsEmpty)
                                {
                                    startPoint     = point;
                                    latLngFirstNav = Unique(startPoint, 20);                                     // Sort dictionary 4 holten_cityjet.ar3
                                }
                            }
                            lastDistance = distance;
                        }
                        #endregion
                        //
                        #region READ NAVIGATION MARKERS
                        //
                        else if (line.StartsWith("Instruction["))
                        {
                            PointLatLng latlng;

                            if (s[1] == "0")                             // Set first Navigation marker not at distance zero. This is reserved for Change marker.
                            {
                                latlng = latLngFirstNav;
                                route.GpsMarkers.Insert(1, new GpsMarker(latlng));
                            }
                            else
                            {
                                latlng = FindLatLng(s[1]);
                            }
                            var marker = new NavigationMarker(latlng);

                            if (s[2] == "1007")                             // Get custom message.
                            {
                                marker.Message = (s[6] != "") ? s[6] : Path.GetFileNameWithoutExtension(s[5]);
                            }
                            else
                            {
                                marker.Message = NavigationMessage(s[2]);
                            }
                            //
                            // Get roundabout index.
                            //
                            marker.RoundAboutIndex = Math.Max((int)My.Val(s[3]), 0);
                            if (marker.Message == "-")
                            {
                                My.Log($"{++errors[2]} {line} Unkown navigation type {s[2]}");
                            }
                            marker.SoundFile = My.ValidateFilename((s[5] != "") ? s[5] : (marker.Message + ".wav"));                             // Todo create soundfile.
                            route.NavigationMarkers.Add(marker);
                        }
                        #endregion
                        //
                        #region READ CHANGE MARKERS
                        //
                        else if (line.StartsWith("ChangePoint["))
                        {
                            var marker = new ChangeMarker(FindLatLng(s[1]));
                            if (route.MachineType == MachineTypes.StreetWasher)
                            {
                                // 1=DistanceFromStart, ActivityState, LeftNozzleIsActive, LeftNozzlePosition, RightNozzleIsActive, RightNozzlePosition, waterpressure,Marked, Message
                                // If this code is changed then modify also methode DisplayOnForm.
                                //
                                // Handle empty strings; use previous marker value.
                                marker.SpreadingOnOff      = My.Bool(s[2], previousChangeMarker.SpreadingOnOff);
                                marker.Hopper1OnOff        = My.Bool(s[3], previousChangeMarker.Hopper1OnOff);
                                marker.SpreadingWidthLeft  = My.Val(s[4], previousChangeMarker.SpreadingWidthLeft);
                                marker.Hopper2OnOff        = My.Bool(s[5], previousChangeMarker.Hopper2OnOff);
                                marker.SpreadingWidthRight = My.Val(s[6], previousChangeMarker.SpreadingWidthRight);
                                marker.Dosage = My.Val(s[7], previousChangeMarker.Dosage);
                                //
                                // Set default pressure according spec.
                                //
                                if (marker.Dosage < 5)
                                {
                                    marker.Dosage = 5;
                                }
                            }
                            else
                            {
                                // 1=DistanceFromStartInCm, SpreadSprayOnOff, SprayModeOnOff, Max, SecMat,Dosage, WidthLeft, WidthRight, SecDos, WidthLeftSpraying, WidthRightSpraying, CombiPercentage, HopperSelection, Marked, Message
                                marker.SpreadingOnOff      = My.Bool(s[2], previousChangeMarker.SpreadingOnOff);
                                marker.SprayingOnOff       = My.Bool(s[3], previousChangeMarker.SprayingOnOff);
                                marker.MaxOnOff            = My.Bool(s[4], previousChangeMarker.MaxOnOff);
                                marker.SecMatOnOff         = My.Bool(s[5], previousChangeMarker.SecMatOnOff);
                                marker.Dosage              = My.Val(s[6], previousChangeMarker.Dosage * 100) / 100;
                                marker.SpreadingWidthLeft  = My.Val(s[7], previousChangeMarker.SpreadingWidthLeft * 100) / 100;
                                marker.SpreadingWidthRight = My.Val(s[8], previousChangeMarker.SpreadingWidthRight * 100) / 100;
                                marker.DosageLiquid        = My.Val(s[9], previousChangeMarker.DosageLiquid * 100) / 100;
                                marker.SprayingWidthLeft   = My.Val(s[10], previousChangeMarker.SprayingWidthLeft * 100) / 100;
                                marker.SprayingWidthRight  = My.Val(s[11], previousChangeMarker.SprayingWidthRight * 100) / 100;
                                marker.PersentageLiquid    = My.Val(s[12], previousChangeMarker.PersentageLiquid);
                            }
                            //
                            // First change marker should have distance 0.
                            //
                            if (route.ChangeMarkers.Count == 0 && s[1] != "0")
                            {
                                route.ChangeMarkers.Add(new ChangeMarker(startPoint));
                            }
                            route.ChangeMarkers.Add(marker);
                            previousChangeMarker = marker;
                        }
                        #endregion
                    }
                    catch (Exception ee) { Log($"{++errors[3]} Error in {line} {ee.Message} {ee.StackTrace}"); }
                }
                //
                // First change marker should have distance 0.
                //
                if (route.ChangeMarkers.Count == 0)
                {
                    route.ChangeMarkers.Add(new ChangeMarker(startPoint));
                }
            }
            My.Log("End of requirement analyze.");
            return(route);

            //
            // Make unique LatLng point. See Software Design Document.
            //
            PointLatLng Unique(PointLatLng point, int distance)
            {
                while (distanceTable.ContainsKey(point))
                {
                    var r = random.NextDouble() / 100000;
                    point = new PointLatLng(point.Lat + r, point.Lng + r);
                }
                distanceTable.Add(point, distance);
                return(point);
            }

            PointLatLng FindLatLng(string sdistance)
            {
                var distance = (int)My.Val(sdistance);
                var last     = default(KeyValuePair <PointLatLng, int>);
                var idx      = 0;

                foreach (var item in distanceTable)
                {
                    ++idx;
                    if (item.Value < distance)
                    {
                        last = item;
                    }
                    else if (item.Value == distance)
                    {
                        last = item;
                        break;
                    }
                    else if (item.Value > distance)                     // No corresponding Gps marker (orphan).
                    {
                        if (last.Key.IsEmpty)
                        {
                            last = item;
                        }
                        if (item.Value - distance < distance - last.Value)
                        {
                            last = item;
                        }
                        if (distance - last.Value < 200)
                        {
                            break;                                                      // Don't mark as orphan when marker is within 200 cm of current or previous marker.
                        }
                        if (item.Value - distance < 200)
                        {
                            break;
                        }
                        ++errors[4];
                        break;
                    }
                }
                distanceTable.Remove(last.Key);                 // Use distance only one's so that both Navigation- and Change marker can't be added to one gps marker.

                return(last.Key);
            }
        }