// ------------------------------------------------------------------------------------------------------------------- static Boolean handleRectOptions( FLTTopoData data ) { Boolean validated = true; // note : coordinates check first, so indices will be ignored if also specified if (rectCoordinatesSpecified) { Boolean coordinatesValid = true; var validationMessages = new List<String>(20); try { coordinatesValid = data.Descriptor.ValidateCoordinates( rectNorthLatitude, rectWestLongitude, rectSouthLatitude, rectEastLongitude, NorthString, WestString, SouthString, EastString, validationMessages ); } catch { throw; } // convert to indices if ( coordinatesValid ) { rectLeftIndex = data.Descriptor.LongitudeToColumnIndex( rectWestLongitude ); rectRightIndex = data.Descriptor.LongitudeToColumnIndex( rectEastLongitude ); rectTopIndex = data.Descriptor.LatitudeToRowIndex( rectNorthLatitude ); rectBottomIndex = data.Descriptor.LatitudeToRowIndex( rectSouthLatitude ); } else { Console.WriteLine("Errors in specified rect coordinates:"); foreach (var msg in validationMessages) { Console.WriteLine(" * " + msg); } validated = false; } } else if (rectIndicesSpecified) { Boolean indicesValidated = true; List<String> validationMessages = null; try { indicesValidated = data.Descriptor.ValidateRectIndices( rectLeftIndex, rectTopIndex, rectRightIndex, rectBottomIndex, rectLeftName, rectTopName, rectRightName, rectBottomName, out validationMessages); } catch { throw; } if (false == indicesValidated) { Console.WriteLine("Errors in rect indices:"); foreach (var msg in validationMessages) { Console.WriteLine(" * " + msg); } validated = false; } } else // no rect was specified, default to whole map { // TODO : may be better to get these extents from descriptor... rectLeftIndex = 0; rectRightIndex = data.NumCols - 1; rectTopIndex = 0; rectBottomIndex = data.NumRows - 1; } return validated; }
// ------------------------------------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------------------------- static int Main(string[] args) { const int ReturnErrorCode = 1; const int ReturnSuccess = 0; // ----- startup ----- initOptionSpecifiers(); initProgramNotes(); initColorsDictionary(); FLTDataLib.FLTTopoData topoData = new FLTDataLib.FLTTopoData(); System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); System.Console.WriteLine(); System.Console.WriteLine( BannerMessage ); System.Console.WriteLine( "Version : " + versionNumber.ToString() ); // ----- parse program arguments ----- Boolean parsed = parseArgs(args); if ( false == parsed ) { System.Console.WriteLine(); System.Console.WriteLine("Error : " + parseErrorMessage); if (helpRequested) { echoAvailableOptions(); echoProgramNotes(); } else { Console.WriteLine("\n(run with '" + HelpRequestChar + "' to see help)"); } return ReturnErrorCode; } else // args parsed successfully { if (helpRequested) { echoAvailableOptions(); echoProgramNotes(); } System.Console.WriteLine( ConsoleSectionSeparator ); // ---- read descriptor ----- try { readDescriptor( topoData, inputFileBaseName ); } catch { return ReturnErrorCode; } // ---- validate rect options ---- try { Boolean rectValidated = handleRectOptions(topoData); if (false == rectValidated) { return ReturnErrorCode; } } catch { return ReturnErrorCode; } // ---- validate image size options ---- try { Boolean imageSizeValidated = validateImageSizeOptions(topoData); if (false == imageSizeValidated) { return ReturnErrorCode; } } catch { return ReturnErrorCode; } // report current options echoSettingsValues(); // ---- read data ---- try { readData(topoData, inputFileBaseName); } catch { return ReturnErrorCode; } // ---- process ---- if ( dataReportOnly ) { dataReport( topoData ); } else { // pack extents into array var rectExtents = new int[4]; rectExtents[ TopoMapGenerator.RectLeftIndex ] = rectLeftIndex; rectExtents[ TopoMapGenerator.RectTopIndex ] = rectTopIndex; rectExtents[ TopoMapGenerator.RectRightIndex ] = rectRightIndex; rectExtents[ TopoMapGenerator.RectBottomIndex ] = rectBottomIndex; var setupData = new TopoMapGenerator.GeneratorSetupData(); setupData.Type = outputMapType; setupData.ContourHeights = contourHeights; setupData.Data = topoData; setupData.OutputFilename = outputFileName; setupData.RectIndices = rectExtents; setupData.ImageWidth = imageWidth; setupData.ImageHeight = imageHeight; setupData.AppendCoordinatesToFilenames = _appendCoordinatesToFilenames; setupData.ImageHeightScale = imageHeightScale; TopoMapGenerator generator = TopoMapGenerator.getGenerator( setupData ); generator.DetermineImageDimensions(); generator.setColorsDict(colorsDict); generator.addTimingHandler = addTiming; System.Console.WriteLine(ConsoleSectionSeparator); System.Console.WriteLine("Creating map in " + generator.GetName() + " mode."); generator.Generate(); } // end if !dataReportOnly if ( reportTimings ) { echoTimings(); } System.Console.WriteLine(); } // end if args parsed successfully return ReturnSuccess; // this should maybe be in the else proceed block above, and return an error if execution went here }
// --------------------------------------------------------------------------------------------------------------------- // must be called after rect options are validated and input rect indices are calculated private static bool validateImageSizeOptions( FLTTopoData data ) { bool validated = true; if ( TopoMapGenerator.ImageDimensionSpecified( imageWidth ) ) { // validate if ( imageWidth <= 0 ) { Console.WriteLine( "specified " + optionTypeToSpecDict[ OptionType.ImageWidth].Description + ImageDimensionLTEZeroErrorMessage ); validated = false; } } if ( TopoMapGenerator.ImageDimensionSpecified( imageHeight ) ) { if ( imageHeight <= 0 ) { Console.WriteLine( "specified " + optionTypeToSpecDict[ OptionType.ImageHeight].Description + ImageDimensionLTEZeroErrorMessage ); validated = false; } } /* int rectWidth = rectRightIndex - rectLeftIndex + 1; // TODO : maybe DRY this int rectHeight = rectBottomIndex - rectTopIndex + 1; if ( ( ImageDimensionNotSpecifiedValue == imageWidth ) && ( ImageDimensionNotSpecifiedValue == imageHeight ) ) { // neither specified, use rect size imageWidth = rectWidth; imageHeight = rectHeight; } else if ( ( ImageDimensionNotSpecifiedValue == imageWidth ) && ( ImageDimensionNotSpecifiedValue != imageHeight ) ) { // height specified, validate it is > 0 if ( imageHeight <= 0 ) { Console.WriteLine( ImageDimensionLTEZeroErrorMessage ); validated = false; } else { imageWidth = (int)(imageHeight * (rectWidth / (float)rectHeight)); } } else if ( ( ImageDimensionNotSpecifiedValue == imageHeight ) && ( ImageDimensionNotSpecifiedValue != imageWidth ) ) { // width specified, validate it is > 0 if ( imageWidth <= 0 ) { Console.WriteLine( ImageDimensionLTEZeroErrorMessage ); validated = false; } else { // width was specified, calculate height imageHeight = (int)(imageWidth * (rectHeight / (float)rectWidth)); } } // else user specified both, no changes */ return validated; }
// --------------------------------------------------------------------------------------------------------------------- private static void dataReport( FLTTopoData data ) { String indent = " "; // note : works with rect spec Console.WriteLine("Finding min/max"); float minElevationInRect = 0; int minElevationRow = 0, minElevationColumn = 0; float maxElevationInRect = 0; int maxElevationRow = 0, maxElevationColumn = 0; data.FindMinMaxInRect( rectLeftIndex, rectTopIndex, rectRightIndex, rectBottomIndex, ref minElevationInRect, ref minElevationRow, ref minElevationColumn, ref maxElevationInRect, ref maxElevationRow, ref maxElevationColumn); Console.WriteLine(ConsoleSectionSeparator); Console.WriteLine(indent + "Descriptor fields:"); var descriptorValues = data.Descriptor.GetValueStrings(); foreach (var valStr in descriptorValues) { Console.WriteLine(indent + indent + valStr); } Console.WriteLine( ConsoleSectionSeparator ); Console.WriteLine( "Data report :" ); Console.WriteLine( indent + "Map extents:" ); Console.WriteLine( indent + indent + WestString + " : " + data.Descriptor.WestLongitude ); Console.WriteLine( indent + indent + NorthString + " : " + data.Descriptor.NorthLatitude ); Console.WriteLine( indent + indent + EastString + " : " + data.Descriptor.EastLongitude ); Console.WriteLine( indent + indent + SouthString + " : " + data.Descriptor.SouthLatitude ); Console.WriteLine( indent + "Map Size (degrees):" ); Console.WriteLine( indent + indent + EastString + "/" + WestString + " : " + data.Descriptor.WidthDegrees ); Console.WriteLine( indent + indent + NorthString + "/" + SouthString + " : " + data.Descriptor.WidthDegrees); // show rect extents Console.WriteLine(ConsoleSectionSeparator); // min/max report echoRectExtents(); Console.WriteLine(); Console.WriteLine(indent + "Minimum elevation : " + minElevationInRect); // note : this assumes in northern/western hemisphere Console.WriteLine( indent + indent + "Found at " + data.Descriptor.RowIndexToLatitude( minElevationRow ) + NorthChar + "," + data.Descriptor.ColumnIndexToLongitude( minElevationColumn ) + WestChar ); Console.WriteLine( indent + "Maximum elevation : " + maxElevationInRect ); Console.WriteLine( indent + indent + "Found at " + data.Descriptor.RowIndexToLatitude( maxElevationRow ) + NorthChar + "," + data.Descriptor.ColumnIndexToLongitude( maxElevationColumn ) + WestChar ); Console.WriteLine(); }
// ----------------------------------------------------------------------------------------------------------------------- private static void readData( FLTTopoData data, String inputFileBaseName ) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Reset(); stopwatch.Start(); try { data.ReadDataFile(inputFileBaseName); } catch { throw; } stopwatch.Stop(); addTiming( "data read", stopwatch.ElapsedMilliseconds ); }
// ------------------------------------------------------------------------------------------------------------------- private static void readDescriptor( FLTTopoData data, String inputFileBaseName ) { try { data.ReadHeaderFile(inputFileBaseName); } catch { throw; } }
// ------------------------------------------------------------------------------------------------------------------ static Boolean validateCornerCoordinates( FLTTopoData data ) { var coordinates = new List<Tuple<double,double>>( 4 ); coordinates.Add( new Tuple<double,double>( cornerALatitude, cornerALongitude ) ); coordinates.Add( new Tuple<double,double>( cornerBLatitude, cornerBLongitude ) ); coordinates.Add( new Tuple<double,double>( cornerCLatitude, cornerBLongitude ) ); coordinates.Add( new Tuple<double,double>( cornerDLatitude, cornerDLongitude ) ); var invalidCoordinates = data.Descriptor.validateCoordinatesList( coordinates ); if ( invalidCoordinates.Count > 0 ) { Console.WriteLine( "Specified rect bounds were not all within map.\nInvalid coordinates:"); foreach ( var coords in invalidCoordinates ) { Console.WriteLine( " " + coords.Item1 + "," + coords.Item2 ); } } return null == invalidCoordinates ? true : false; }
// ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- static void Main(string[] args) { // ----- startup ----- initOptionSpecifiers(); initProgramNotes(); FLTDataLib.FLTTopoData topoData = new FLTDataLib.FLTTopoData(); System.Console.WriteLine(); System.Console.WriteLine(BannerMessage); System.Console.WriteLine("Version : " + versionNumber.ToString()); // ----- parse program arguments ----- Boolean parsed = parseArgs(args); if (false == parsed) { System.Console.WriteLine(); System.Console.WriteLine("Error : " + parseErrorMessage); if (helpRequested) { echoAvailableOptions(); } } else { if (helpRequested) { echoAvailableOptions(); echoProgramNotes(); } // validate that we got corners A/B and a width // ugh, TODO : clean this up maybe if ((floatNotSpecifiedValue == cornerALatitude) || (floatNotSpecifiedValue == cornerALongitude)) { Console.WriteLine("\nError : " + cornerANotSpecifiedErrorMessage); return; } else if ((floatNotSpecifiedValue == cornerBLatitude) || (floatNotSpecifiedValue == cornerBLongitude)) { Console.WriteLine("\nError : " + cornerBNotSpecifiedErrorMessage); return; } else if (floatNotSpecifiedValue == rectWidth) { Console.WriteLine("\nError : " + widthNotSpecifiedErrorMessage); return; } // report current options echoSettingsValues(); // ---- read descriptor ----- try { readDescriptor(topoData, inputFileBaseName); } catch { return; } // ---- echo map data ---- Console.WriteLine(ConsoleSectionSeparator); echoMapData(topoData); // ---- generate/validate rect corners ---- try { var invalidCoordinates = new List <String>(10); Console.WriteLine("Generating rect corners..."); generateRectCorners(topoData, invalidCoordinates); Console.WriteLine("cornerA : " + cornerALatitude + "," + cornerALongitude); Console.WriteLine("cornerB : " + cornerBLatitude + "," + cornerBLongitude); Console.WriteLine("cornerC : " + cornerCLatitude + "," + cornerCLongitude); Console.WriteLine("cornerD : " + cornerDLatitude + "," + cornerDLongitude); if (false == validateCornerCoordinates(topoData)) { return; } } catch { return; } // ---- generateRectIndices(topoData); // ---- read data ---- try { readData(topoData, inputFileBaseName); } catch { return; } Console.WriteLine("TODO : FINISH OUTPUT"); } } // end Main()
// ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- static void Main(string[] args) { // ----- startup ----- initOptionSpecifiers(); initProgramNotes(); FLTDataLib.FLTTopoData topoData = new FLTDataLib.FLTTopoData(); System.Console.WriteLine(); System.Console.WriteLine(BannerMessage); System.Console.WriteLine("Version : " + versionNumber.ToString()); // ----- parse program arguments ----- Boolean parsed = parseArgs(args); if (false == parsed) { System.Console.WriteLine(); System.Console.WriteLine("Error : " + parseErrorMessage); if (helpRequested) { echoAvailableOptions(); } } else { if (helpRequested) { echoAvailableOptions(); echoProgramNotes(); } // validate that we got corners A/B and a width // ugh, TODO : clean this up maybe if ( (floatNotSpecifiedValue == cornerALatitude) || (floatNotSpecifiedValue == cornerALongitude)) { Console.WriteLine( "\nError : " + cornerANotSpecifiedErrorMessage ); return; } else if ( (floatNotSpecifiedValue == cornerBLatitude) || (floatNotSpecifiedValue == cornerBLongitude)) { Console.WriteLine("\nError : " + cornerBNotSpecifiedErrorMessage ); return; } else if ( floatNotSpecifiedValue == rectWidth ) { Console.WriteLine("\nError : " + widthNotSpecifiedErrorMessage ); return; } // report current options echoSettingsValues(); // ---- read descriptor ----- try { readDescriptor(topoData, inputFileBaseName); } catch { return; } // ---- echo map data ---- Console.WriteLine( ConsoleSectionSeparator ); echoMapData( topoData ); // ---- generate/validate rect corners ---- try { var invalidCoordinates = new List<String>(10); Console.WriteLine( "Generating rect corners..." ); generateRectCorners(topoData, invalidCoordinates); Console.WriteLine( "cornerA : " + cornerALatitude + "," + cornerALongitude ); Console.WriteLine( "cornerB : " + cornerBLatitude + "," + cornerBLongitude ); Console.WriteLine( "cornerC : " + cornerCLatitude + "," + cornerCLongitude ); Console.WriteLine( "cornerD : " + cornerDLatitude + "," + cornerDLongitude ); if ( false == validateCornerCoordinates( topoData ) ) { return; } } catch { return; } // ---- generateRectIndices( topoData ); // ---- read data ---- try { readData(topoData, inputFileBaseName); } catch { return; } Console.WriteLine( "TODO : FINISH OUTPUT"); } }
// ------------------------------------------------------------------------------------------------------------ // converts rect lat/long coordinates to indices in topo data, and prepares for rasterization of the rect static void generateRectIndices( FLTTopoData data ) { // convert to indices cornerARow = data.Descriptor.LatitudeToRowIndex( cornerALatitude ); cornerAColumn = data.Descriptor.LongitudeToColumnIndex( cornerALongitude ); cornerBRow = data.Descriptor.LatitudeToRowIndex( cornerBLatitude ); cornerBColumn = data.Descriptor.LongitudeToColumnIndex( cornerBLongitude ); cornerCRow = data.Descriptor.LatitudeToRowIndex( cornerCLatitude ); cornerCColumn = data.Descriptor.LongitudeToColumnIndex( cornerCLongitude ); cornerDRow = data.Descriptor.LatitudeToRowIndex( cornerDLatitude ); cornerDColumn = data.Descriptor.LongitudeToColumnIndex( cornerDLongitude ); // detect some particular cases that simplify rasterization // is AB oriented north/south? if ( cornerAColumn == cornerBColumn ) { // must know if AB is on east or west side if ( cornerARow > cornerBRow ) { // cornerA is south of cornerB (because topo data rows increase from north to south // so, due to clockwise winding of points... /* B--C * | | * A--D */ } else // cornerARow < cornerBRow { /* * D--A * | | * C--B */ } } else if ( cornerARow == cornerBRow ) // is AB oriented east/west? { } else // rect is diagonally oriented { // orient points around rect so that A is the northernmost corner } }
// ------------------------------------------------------------------------------------------------------------------- // generates four corners of rect specified by user // NOTE : DOES NO VALIDATION ON COORDINATES static void generateRectCorners(FLTTopoData data, List<String> invalidCoordinates ) { const double MilesPerArcMinute = 1.15077945; // ye olde nautical mile, (the equatorial distance / 360) / 60 const double MilesPerDegree = MilesPerArcMinute * 60.0f; // about 69 miles (at the equator) const double DegreesPerMile = 1.0 / MilesPerDegree; Console.WriteLine("TODO : FINISH RECT VALIDATION"); /* We want a rect outlined by corners A,B,C,D. The user provides A and B, and the width (in some units, miles for now) of the rect perpendicular to AB. Assuming a clockwise winding of the points and that latitude and longitude form a right handed coordinate system (z representing increasing altitude), generate C and D. NOTE : This math works in continuous coordinates of degrees. NOTE : Nothing here accounts for changes in latitude with longitude. There will be errors at higher latitudes, but as the source data is "square" at any latitude this math will work without making any corrections. */ // create perpendicular to given edge double ABLatDelta = cornerBLatitude - cornerALatitude; double ABLongDelta = cornerBLongitude - cornerALongitude; double ABLength = Math.Abs( Math.Sqrt((ABLatDelta * ABLatDelta) + (ABLongDelta * ABLongDelta)) ); // need normalized length of AB double ABLatDeltaNorm = ABLatDelta / ABLength; double ABLongDeltaNorm = ABLongDelta / ABLength; // generate normalized perpendicular to AB double ABPerpLatDeltaNorm = ABLongDeltaNorm * -1; double ABPerpLongDeltaNorm = ABLatDeltaNorm; // generate perpendicular to AB, sized to Width // TODO : for now assuming width is in miles, may work with other units later double widthInDegrees = rectWidth * DegreesPerMile; double ABPerpLatDelta = ABPerpLatDeltaNorm * widthInDegrees; double ABPerpLongDelta = ABPerpLongDeltaNorm * widthInDegrees; Console.WriteLine( "ABPerpLatDelta = " + ABPerpLatDelta ); Console.WriteLine( "ABPerpLongDelta = " + ABPerpLongDelta ); // add the perp delta to A to generate D (remember that points wind around) cornerDLatitude = cornerALatitude + ABPerpLatDelta; cornerDLongitude = cornerALongitude + ABPerpLongDelta; // add the perp delta to B to generate C cornerCLatitude = cornerBLatitude + ABPerpLatDelta; cornerCLongitude = cornerBLongitude + ABPerpLongDelta; }
// ------------------------------------------------------------------------------------- static void echoMapData( FLTTopoData data ) { String indent = " "; Console.WriteLine( indent + "Map extents:" ); Console.WriteLine( indent + indent + WestString + " : " + data.Descriptor.WestLongitude ); Console.WriteLine( indent + indent + NorthString + " : " + data.Descriptor.NorthLatitude ); Console.WriteLine( indent + indent + EastString + " : " + data.Descriptor.EastLongitude ); Console.WriteLine( indent + indent + SouthString + " : " + data.Descriptor.SouthLatitude ); Console.WriteLine( indent + "Map Size (degrees):" ); Console.WriteLine( indent + indent + EastString + "/" + WestString + " : " + data.Descriptor.WidthDegrees ); Console.WriteLine( indent + indent + NorthString + "/" + SouthString + " : " + data.Descriptor.WidthDegrees); }
// ------------------------------------------------------ // ---- constructor ---- // note : as the generators are pixel focused, we'll only work with indices into the topo data (for now) public TopoMapGenerator( GeneratorSetupData setupData ) { /* ( FLTTopoData data, int contourHeights, String outputFilename, int[] rectIndices, int imageWidth, int imageHeight ) */ _data = setupData.Data; _contourHeights = setupData.ContourHeights; _outputFilename = setupData.OutputFilename; if ( setupData.RectIndices.Length < 4 ) { throw new System.InvalidOperationException( "Expected four indices, got : " + setupData.RectIndices.Length ); } else { _rectIndices = setupData.RectIndices; } _imageWidth = setupData.ImageWidth; _imageHeight = setupData.ImageHeight; addTimingHandler = null; }