public static OverlayShape[] Parse(string overlayFileName, out string sourceOverlay, out string expandedRangeKm) { sourceOverlay = null; expandedRangeKm = null; var curColor = Colors.Red; var shapes = new List<OverlayShape>(); var locationMode = OverlayLocationMode.LatLong; var curState = OverlayParseState.Initialization; Geo lastPoint = null; var curStyle = LineStyle.Solid; var reader = new LineReader(); var tokenizer = new Tokenizer {CommentIndicators = new[] {"#"}}; var commentSplit = new[] { "=" }; reader.FileName = overlayFileName; tokenizer.LineReader = reader; Token curToken; while ((curToken = tokenizer.NextToken()) != null) { Geo[] curPoints; switch (curState) { case OverlayParseState.Initialization: switch (((string) curToken.Value).ToLower()) { case OverlayKeywords.Comment: var originalComment = reader.Lines[curToken.LineNumber]; if (originalComment.StartsWith("# ")) { var step1 = originalComment.Substring(2, originalComment.Length - 2).Trim(); var step2 = step1.Split(commentSplit, StringSplitOptions.RemoveEmptyEntries); if (step2.Length != 2) break; switch (step2[0]) { case "sourceOverlay": sourceOverlay = step2[1]; break; case "expandedRangeKm": expandedRangeKm = step2[1]; break; } } break; case OverlayKeywords.Move: curPoints = GetPoints(tokenizer, locationMode, null); lastPoint = curPoints.Last(); curState = OverlayParseState.ShapeBuild; //Change State to ShapeBuild break; case OverlayKeywords.Absolute: break; case OverlayKeywords.Relative: throw new ApplicationException("Unimplemented position mode: Relative"); case OverlayKeywords.DegreesMinutesSeconds: locationMode = OverlayLocationMode.DegreesMinutesSeconds; break; case OverlayKeywords.LatLong: locationMode = OverlayLocationMode.LatLong; break; case OverlayKeywords.XYPair: locationMode = OverlayLocationMode.XYPair; break; case OverlayKeywords.Color: if (tokenizer.Count < 3) throw new ApplicationException("OverlayParser.Parse: Not all color information are found\n"); var red = tokenizer.NextToken().Value as float?; var green = tokenizer.NextToken().Value as float?; var blue = tokenizer.NextToken().Value as float?; if ((red == null) || (green == null) || (blue == null)) throw new ApplicationException("OverlayParser: Invalid color definition at line " + curToken.LineNumber); curColor = Color.FromArgb(255, (byte) red, (byte) green, (byte) blue); break; #if false // DA: Removed all support for color because NUWC decided to throw colors in new and interesting places in overlay files // Color keywords are completely stripped out by the tokenizer case OverlayKeywords.Red: curColor = Colors.Red; break; case OverlayKeywords.Green: curColor = Colors.Green; break; case OverlayKeywords.Purple: curColor = Colors.Purple; break; case OverlayKeywords.Yellow: curColor = Colors.Yellow; break; case OverlayKeywords.White: curColor = Colors.White; break; case OverlayKeywords.Orange: curColor = Colors.Orange; break; case OverlayKeywords.Blue: curColor = Colors.Blue; break; case OverlayKeywords.Cyan: curColor = Colors.Cyan; break; #endif case OverlayKeywords.Origin: tokenizer.DiscardToEndOfLine(); break; case OverlayKeywords.Solid: curStyle = LineStyle.Solid; break; case OverlayKeywords.Dash: curStyle = LineStyle.Dash; break; case OverlayKeywords.DashDot: curStyle = LineStyle.DashDot; break; case OverlayKeywords.Dot: curStyle = LineStyle.Dot; break; case OverlayKeywords.Point: tokenizer.DiscardNext(); break; case OverlayKeywords.Red: curColor = Colors.Red; break; case OverlayKeywords.Green: curColor = Colors.Green; break; case OverlayKeywords.Purple: curColor = Colors.Purple; break; case OverlayKeywords.Yellow: curColor = Colors.Yellow; break; case OverlayKeywords.White: curColor = Colors.White; break; case OverlayKeywords.Orange: curColor = Colors.Orange; break; case OverlayKeywords.Blue: curColor = Colors.Blue; break; case OverlayKeywords.Cyan: curColor = Colors.Cyan; break; default: throw new FormatException("OverlayParser: Unknown token at line " + curToken.LineNumber + ": " + curToken.Value); } //Initialization Switch(curToken) break; //break for the Initialization Case case OverlayParseState.ShapeBuild: float curSize; int curLinenumber; OverlayShape curShape; switch (curToken.Value as string) { case OverlayKeywords.Move: //Submit Shape and Points //continue in ShapeBuild curPoints = GetPoints(tokenizer, locationMode, null); lastPoint = curPoints.Last(); break; case OverlayKeywords.Lines: curLinenumber = curToken.LineNumber; if (curLinenumber == tokenizer.Peek().LineNumber) curSize = (float) ((float?) tokenizer.NextToken().Value); else curSize = 2f; curShape = new OverlayLineSegments(GetPoints(tokenizer, locationMode, lastPoint), curColor, curSize, curStyle) { LineStyle = curStyle }; shapes.Add(curShape); break; case OverlayKeywords.Point: curLinenumber = curToken.LineNumber; if (curLinenumber == tokenizer.Peek().LineNumber) curSize = (float) ((float?) tokenizer.NextToken().Value); else curSize = 2; curShape = new OverlayPoint(lastPoint, curColor, curSize); shapes.Add(curShape); break; case OverlayKeywords.Circle: //get radius //its the previous point curSize = (float) ((float?) tokenizer.NextToken().Value); curShape = new OverlayCircle(lastPoint, curColor, curStyle, curSize * YardsToMeters) { LineStyle = curStyle }; shapes.Add(curShape); //SubmitShape(PositionMode); curState = OverlayParseState.Initialization; break; case OverlayKeywords.Label: //shapes.Add(new OverlayLabel(lastPoint, curColor, tokenizer.NextToken().Value as string)); tokenizer.NextToken(); break; case OverlayKeywords.Red: curColor = Colors.Red; break; case OverlayKeywords.Green: curColor = Colors.Green; break; case OverlayKeywords.Purple: curColor = Colors.Purple; break; case OverlayKeywords.Yellow: curColor = Colors.Yellow; break; case OverlayKeywords.White: curColor = Colors.White; break; case OverlayKeywords.Orange: curColor = Colors.Orange; break; case OverlayKeywords.Blue: curColor = Colors.Blue; break; case OverlayKeywords.Cyan: curColor = Colors.Cyan; break; case OverlayKeywords.Comment: case OverlayKeywords.Origin: break; case OverlayKeywords.Solid: curStyle = LineStyle.Solid; break; case OverlayKeywords.Dash: curStyle = LineStyle.Dash; break; case OverlayKeywords.DashDot: curStyle = LineStyle.DashDot; break; case OverlayKeywords.Dot: curStyle = LineStyle.Dot; break; case OverlayKeywords.Color: if (tokenizer.Count < 3) throw new ApplicationException("OverlayParser.Parse: Not all color information are found\n"); var red = tokenizer.NextToken().Value as float?; var green = tokenizer.NextToken().Value as float?; var blue = tokenizer.NextToken().Value as float?; if ((red == null) || (green == null) || (blue == null)) throw new ApplicationException("OverlayParser: Invalid color definition at line " + curToken.LineNumber); curColor = Color.FromArgb(255, (byte)red, (byte)green, (byte)blue); break; default: throw new FormatException("OverlayParser: Unknown token at line " + curToken.LineNumber + ": " + curToken.Value); } //Switch for shape Build break; default: throw new ApplicationException("OverlayParser.Parse: Unknown state!\n"); } // switch (curState) } // while (curToken != null) return shapes.ToArray(); }
void MovementModel() { var timestepCount = (int) NemoPlatform.NemoScenario.Duration.DivideBy(NemoBase.SimulationStepTime); var currentTime = NemoPlatform.NemoScenario.StartTime; PlatformStates = new PlatformStates(); NemoTrackdef curTrackdef = null; var curLocation = new Geo(); Course course = null; //double curCourseDegrees = 0; double curSpeedMetersPerSecond = 0; var overlayPoints = new List<Geo>(); OverlayShape curTrackBoundingRegion = null; CourseChangePoints = new List<CourseChangeDatum>(); overlayPoints.Add(new Geo(NemoPlatform.Trackdefs[0].InitialLocation)); // Put trackdefs in ascending start-time order, if they weren't already NemoPlatform.Trackdefs.Sort(); for (var i = 0; i < timestepCount; i++, currentTime += NemoBase.SimulationStepTime) { // if we have a current trackdef we're processing, AND that current trackdef DOES NOT CONTAIN the current time // THEN we no longer have a current trackdef if ((curTrackdef != null) && (!curTrackdef.Contains(currentTime))) curTrackdef = null; // if we don't have a current trackdef if (curTrackdef == null) { // look through all of our trackdefs foreach (var trackdef in NemoPlatform.Trackdefs) // If we find one that contains the current time if (trackdef.Contains(currentTime)) { // make this trackdef the current one curTrackdef = trackdef; curLocation = curTrackdef.InitialLocation; course = new Course(curTrackdef.InitialCourse); curSpeedMetersPerSecond = curTrackdef.InitialSpeed * 0.514444444f; CourseChangePoints.Add(new CourseChangeDatum { IsStart = true, Location = curLocation, NewCourse = course.Degrees, }); // Conversion factor for knots to meters per second if (curTrackdef.OverlayFile != null) { if (curTrackdef.OverlayFile.Shapes.Count() != 1) throw new PlatformMovementException(string.Format("Specified overlay file {0} is unsuitable for use as a bounding region.\nReason(s): Overlay file contains multiple shapes, therefore the bounding shape is undefined", curTrackdef.OverlayFile.FileName)); curTrackBoundingRegion = curTrackdef.OverlayFile.Shapes[0]; #if true if (!curTrackBoundingRegion.IsUsableAsPerimeter) { var reasons = new StringBuilder(); if (!curTrackBoundingRegion.IsClosed) reasons.Append("Bounding region is not closed, "); if (curTrackBoundingRegion.HasCrossingSegments) reasons.Append("Bounding region is not a simple polygon (segments cross each other), "); if (reasons.Length != 0) reasons.Remove(reasons.Length - 2, 2); // Remove the trailing ", " throw new PlatformMovementException(string.Format("Specified overlay file {0} is unsuitable for use as a bounding region.\nReason(s): {1}", curTrackdef.OverlayFile.FileName, reasons)); } #endif if (!curTrackBoundingRegion.Contains(curLocation)) throw new PlatformMovementException(string.Format("Specified start location ({0:0.####}, {1:0.####}) is not contained within the trackdef bounding region", curLocation.Latitude, curLocation.Longitude)); } else { // Else, the current trackdef's overlay file IS null, and if the type is perimeter_bounce, that's a no-no if (curTrackdef.TrackType.ToLower() == "perimeter_bounce") throw new PlatformMovementException("PERIMETER_BOUNCE trackdefs require a bounding region, none was supplied."); } break; } } // If we have a current trackdef, use it, otherwise we don't update the location or course if (curTrackdef != null) { switch (curTrackdef.TrackType.ToLower()) { default: case "stationary": curSpeedMetersPerSecond = 0; break; case "straight_line": // straight line navigation code curLocation = curLocation.Offset(Geo.KilometersToRadians((curSpeedMetersPerSecond * NemoBase.SimulationStepTime.TotalSeconds) / 1000), course.Radians); break; case "perimeter_bounce": // perimeter bounce navigation code here var proposedLocation = curLocation.Offset(Geo.KilometersToRadians((curSpeedMetersPerSecond * NemoBase.SimulationStepTime.TotalSeconds) / 1000), course.Radians); //proposedLocation = new EarthCoordinate3D(curLocation); //proposedLocation.Move(curCourseDegrees, curSpeedMetersPerSecond*NemoBase.SimulationStepTime.TotalSeconds); if (curTrackBoundingRegion == null) throw new PlatformBehaviorException("Platform behavior is specified as Perimeter Bounce, but no bounding shape was specified"); if (curTrackBoundingRegion.Contains(proposedLocation)) curLocation = proposedLocation; else { //curLocation.Compare(proposedLocation); Course proposedCourse; proposedLocation = new Geo(curTrackBoundingRegion.Reflect(curLocation, proposedLocation, out proposedCourse)); if (!curTrackBoundingRegion.Contains(proposedLocation)) { proposedLocation = new Geo(curTrackBoundingRegion.Reflect(curLocation, proposedLocation, out proposedCourse)); if (!curTrackBoundingRegion.Contains(proposedLocation)) throw new PlatformMovementException("Two reflections failed to keep the platform inside the bounding region. Please check the bounding region closely for small pockets or other irregularities"); } var newCourse = new Course(curLocation, proposedLocation); CourseChangePoints.Add(new CourseChangeDatum { Location = curLocation, OldCourse = course.Degrees, NewCourse = newCourse.Degrees, }); //curLocation.Compare(proposedLocation); course = newCourse; curLocation = new Geo(proposedLocation); if (!curTrackBoundingRegion.Contains(curLocation)) throw new PlatformMovementException("Reflected position is outside the bounding region"); overlayPoints.Add(curLocation); } break; } } else // If we don't have a current trackdef, that means our speed is zero curSpeedMetersPerSecond = 0; // Put the current location, course, speed and time into the PlatformStates list PlatformStates.Add(new PlatformLocation { Location = curLocation, Course = (float) course.Degrees, Speed = (float) curSpeedMetersPerSecond, //SimulationTime = currentTime }); } overlayPoints.Add(new Geo(curLocation)); CourseOverlay = new OverlayLineSegments(overlayPoints.ToArray(), Colors.Orange, 1, LineStyle.Dot); CourseEnd = new OverlayPoint(curLocation, Colors.Red, 2); CourseChangePoints.Add(new CourseChangeDatum { IsEnd = true, Location = curLocation, OldCourse = course.Degrees, }); CourseStart = new OverlayPoint(NemoPlatform.Trackdefs[0].InitialLocation, Colors.Green, 2); }