public static void Main(string[] args) { bool markers = false; bool nosplit = false; string basename = null; mingrid = Color.Transparent; for (int i = 0; i < args.Length; i++) { if (args[i] == "-markers") { markers = true; continue; } if (args[i] == "-mingrid") { mingrid = NameToColor(args[++i]); continue; } if (args[i] == "-nosplit") { nosplit = true; continue; } if (args[i][0] == '-') { throw new Exception("unknown option " + args[i]); } if (basename != null) { throw new Exception("extra arg " + args[i]); } basename = args[i]; } if (basename == null) { throw new Exception("missing basename"); } chart = new ChartTiff("", basename); /* * Draw lines every minute for debugging. */ if (mingrid.A != 0) { double hilatdeg, hilondeg, lat, lolatdeg, lolondeg, lon; int lastx, lasty, latmin, lonmin, thisx, thisy; chart.Pixel2LatLon(chart.width, 0, out hilatdeg, out hilondeg); chart.Pixel2LatLon(0, chart.height, out lolatdeg, out lolondeg); int hilatmin = (int)(hilatdeg * 60.0) + 30; int hilonmin = (int)(hilondeg * 60.0) + 30; int lolatmin = (int)(lolatdeg * 60.0) - 30; int lolonmin = (int)(lolondeg * 60.0) - 30; for (latmin = lolatmin; latmin < hilatmin; latmin++) { lonmin = lolonmin; lat = (double)latmin / 60.0; lon = (double)lonmin / 60.0; chart.LatLon2Pixel(lat, lon, out lastx, out lasty); while (++lonmin < hilonmin) { lon = (double)lonmin / 60.0; chart.LatLon2Pixel(lat, lon, out thisx, out thisy); DrawLine(lastx, lasty, thisx, thisy, MinGridSetPixel); lastx = thisx; lasty = thisy; } } for (lonmin = lolonmin; lonmin < hilonmin; lonmin++) { latmin = lolatmin; lat = (double)latmin / 60.0; lon = (double)lonmin / 60.0; chart.LatLon2Pixel(lat, lon, out lastx, out lasty); while (++latmin < hilatmin) { lat = (double)latmin / 60.0; chart.LatLon2Pixel(lat, lon, out thisx, out thisy); DrawLine(lastx, lasty, thisx, thisy, MinGridSetPixel); lastx = thisx; lasty = thisy; } } } /* * Split it up into wstep/hstep-sized .png files. */ if (!nosplit) { string dirname = basename.Replace(' ', '_'); Directory.CreateDirectory(dirname); for (int hhh = 0; hhh < chart.height; hhh += hstep) { int thish = chart.height - hhh; if (thish > hstep + overlap) { thish = hstep + overlap; } string subdirname = dirname + "/" + (hhh / hstep).ToString(); Directory.CreateDirectory(subdirname); for (int www = 0; www < chart.width; www += wstep) { int thisw = chart.width - www; if (thisw > wstep + overlap) { thisw = wstep + overlap; } string savename = subdirname + "/" + (www / wstep).ToString() + ".png"; Bitmap thisbm = new Bitmap(thisw, thish); for (int h = 0; h < thish; h++) { for (int w = 0; w < thisw; w++) { thisbm.SetPixel(w, h, chart.bmp.GetPixel(www + w, hhh + h)); } } thisbm.Save(savename, System.Drawing.Imaging.ImageFormat.Png); } } /* * Make thumbnail 256 pixels high with correct width to maintain aspect ratio. */ int iconh = 256; int iconw = chart.width * iconh / chart.height; Bitmap iconbm = new Bitmap(chart.bmp, iconw, iconh); string iconname = dirname + "/icon.png"; iconbm.Save(iconname, System.Drawing.Imaging.ImageFormat.Png); } if (markers) { /* * Create whole .png file containing lat/lon markers for visual inspection. */ Console.WriteLine(basename + ".png"); /* * Draw a vertical line through centerLon, ie, easting = 0 */ for (int y = 0; y < chart.height; y++) { double easting = 0; int x = (int)((easting - chart.tfw_e - chart.tfw_c * y) / chart.tfw_a); for (int d = -2; d <= 2; d++) { SetPixel(x + d, y, Color.Yellow); } } /* * Draw an horizontal line through centerLat, ie, northing = 0 */ for (int x = 0; x < chart.width; x++) { double northing = 0; int y = (int)((northing - chart.tfw_f - chart.tfw_b * x) / chart.tfw_d); for (int d = -2; d <= 2; d++) { SetPixel(x, y + d, Color.Yellow); } } /* * LatLon -> Pixel conversion testing. */ for (int lat = -90; lat < 90; lat++) { for (int lon = -180; lon < 180; lon++) { int x, y; chart.LatLon2Pixel(lat, lon, out x, out y); /* * Draw a red plus sign at that location. */ for (int d = -25; d <= 25; d++) { for (int e = -2; e <= 2; e++) { SetPixel(x + e, y + d, Color.Red); SetPixel(x + d, y + e, Color.Red); } } } } chart.bmp.Save(basename + ".png", System.Drawing.Imaging.ImageFormat.Png); } }
public static void Main(string[] args) { string basename = null; for (int i = 0; i < args.Length; i++) { if (args[i][0] == '-') { throw new Exception("unknown option " + args[i]); } if (basename != null) { throw new Exception("extra arg " + args[i]); } basename = args[i]; } if (basename == null) { throw new Exception("missing basename"); } chart = new ChartTiff("charts/", basename); /* * Mark all transparent pixels as white. */ for (int y = 0; y < chart.height; y++) { for (int x = 0; x < chart.width; x++) { Color c = chart.bmp.GetPixel(x, y); if (c.A < 200) { chart.bmp.SetPixel(x, y, Color.White); } } } /* * Mark all pixels outside lat/lon limits for the chart * as white so we don't misidentify them. */ int xmin = chart.width; int ymin = chart.height; int xmax = 0; int ymax = 0; for (int y = 0; y < chart.height; y++) { for (int x = 0; x < chart.width; x++) { double lat, lon; chart.Pixel2LatLon(x, y, out lat, out lon); if ((x == 0 || x == chart.width - 1) && (y == 0 || y == chart.height - 1)) { Console.WriteLine("(" + x + "," + y + ") => " + lat + "," + lon); } if ((lon < chart.westLonLimit) || (lon > chart.eastLonLimit) || (lat > chart.northLatLimit) || (lat < chart.southLatLimit)) { chart.bmp.SetPixel(x, y, Color.White); } else { if (xmin > x) { xmin = x; } if (ymin > y) { ymin = y; } if (xmax < x) { xmax = x; } if (ymax < y) { ymax = y; } } } } Console.WriteLine("xmin=" + xmin); Console.WriteLine("ymin=" + ymin); Console.WriteLine("xmax=" + xmax); Console.WriteLine("ymax=" + ymax); /* * Convert magenta pixels to black and everything else to white * for easy processing. */ Console.WriteLine("monochromaticising"); blacks = new byte[chart.height, chart.width]; for (int y = ymin; y < ymax; y++) { for (int x = xmin; x < xmax; x++) { Color c = chart.bmp.GetPixel(x, y); int r = c.R; int g = c.G; int b = c.B; if ((r >= 100) && (r <= 130) && (g >= 70) && (g <= 90) && (b >= 100) && (b <= 130)) { blacks[y, x] = 1; chart.bmp.SetPixel(x, y, Color.Black); } else { blacks[y, x] = 0; chart.bmp.SetPixel(x, y, Color.White); } } } chart.bmp.Save("stage1.png", System.Drawing.Imaging.ImageFormat.Png); /* * If a white pixel is surrounded by at least 7 blacks, * change the white to a black. This will fill in a lot * of spotty airports and not much else. */ Console.WriteLine("filling in spots"); for (int y = ymin + 1; y < ymax - 1; y++) { for (int x = xmin + 1; x < xmax - 1; x++) { if (blacks[y, x] == 0) { if (blacks[y - 1, x - 1] + blacks[y - 1, x] + blacks[y - 1, x + 1] + blacks[y, x - 1] + blacks[y, x + 1] + blacks[y + 1, x - 1] + blacks[y + 1, x] + blacks[y + 1, x + 1] > 6) { blacks[y, x] = 1; chart.bmp.SetPixel(x, y, Color.Black); } } } } chart.bmp.Save("stage2.png", System.Drawing.Imaging.ImageFormat.Png); /* * Draw box around where each airport should be on the chart. */ Console.WriteLine("finding airports"); string[] csvnames = Directory.GetFiles("datums", "airports_*.csv"); string bestcsvname = null; foreach (string csvname in csvnames) { if ((bestcsvname == null) || StrLt(bestcsvname, csvname)) { bestcsvname = csvname; } } StreamReader csvreader = new StreamReader(bestcsvname); string csvline; while ((csvline = csvreader.ReadLine()) != null) { /* * Compute where the airport should be on the map * trusting the gubmint's numbers. */ string[] csvtokens = ChartTiff.SplitQuotedCSVLine(csvline); string aptid = csvtokens[1]; double csvlat = double.Parse(csvtokens[4]); double csvlon = double.Parse(csvtokens[5]); int csvpixx, csvpixy; chart.LatLon2Pixel(csvlat, csvlon, out csvpixx, out csvpixy); /* * Skip airport if not on graphics part of chart. */ if ((csvpixx < xmin) || (csvpixx >= xmax)) { continue; } if ((csvpixy < ymin) || (csvpixy >= ymax)) { continue; } Console.Write(aptid.PadLeft(5)); /* * Search the surrounding area for a tight fitting circle around * black pixels. */ double bestRatio = 0; int bestRadius = 0; int bestCenterX = 0; int bestCenterY = 0; for (int dy = -20; dy <= 20; dy++) { for (int dx = -20; dx <= 20; dx++) { for (int rad = 14; rad <= 22; rad++) { int loestx = csvpixx + dx - rad - 2; int loesty = csvpixy + dy - rad - 2; int hiestx = csvpixx + dx + rad + 2; int hiesty = csvpixy + dy + rad + 2; if ((loestx < xmin) || (hiestx >= xmax)) { continue; } if ((loesty < ymin) || (hiesty >= ymax)) { continue; } int nbi = 0; // number blacks inside radius int nbo = 0; // number blacks outside radius int num = 0; // number of angles checked for (double ang = 0.0; ang < Math.PI * 2.0; ang += 0.5 / rad) { double cos = Math.Cos(ang); double sin = Math.Sin(ang); int xxi = (int)((rad + 0) * cos + 0.5); int yyi = (int)((rad + 0) * sin + 0.5); int xxo = (int)((rad + 1) * cos + 0.5); int yyo = (int)((rad + 1) * sin + 0.5); if (Math.Abs(xxi - xxo) + Math.Abs(yyi - yyo) == 2) { nbi += blacks[csvpixy + dy + yyi, csvpixx + dx + xxi]; nbo += blacks[csvpixy + dy + yyo, csvpixx + dx + xxo]; num++; } } if ((num >= 8) && (nbo > 0) && (nbi * 2 > nbo * 6)) { double ratio = (double)nbi / (double)nbo; if (bestRatio < ratio) { bestRatio = ratio; bestRadius = rad; bestCenterX = csvpixx + dx; bestCenterY = csvpixy + dy; } } } } } if (bestRadius > 0) { DrawCircle(bestCenterX, bestCenterY, bestRadius, Color.Red); DrawCircle(csvpixx, csvpixy, bestRadius, Color.Magenta); } else { DrawCircle(csvpixx, csvpixy, 30, Color.Cyan); } } Console.WriteLine(""); csvreader.Close(); chart.bmp.Save("stage3.png", System.Drawing.Imaging.ImageFormat.Png); }
public static void Main(string[] args) { string basename = args[0]; string savename = args[1]; ChartTiff tiffchart = new ChartTiff("charts/", basename); int tw = tiffchart.width; int th = tiffchart.height; double upperLeftLat, upperLeftLon; tiffchart.Pixel2LatLon(0, 0, out upperLeftLat, out upperLeftLon); double upperRiteLat, upperRiteLon; tiffchart.Pixel2LatLon(tw, 0, out upperRiteLat, out upperRiteLon); double lowerLeftLat, lowerLeftLon; tiffchart.Pixel2LatLon(0, th, out lowerLeftLat, out lowerLeftLon); double lowerRiteLat, lowerRiteLon; tiffchart.Pixel2LatLon(tw, th, out lowerRiteLat, out lowerRiteLon); double loestLat = Math.Min(Math.Min(upperLeftLat, upperRiteLat), Math.Min(lowerLeftLat, lowerRiteLat)); double hiestLat = Math.Max(Math.Max(upperLeftLat, upperRiteLat), Math.Max(lowerLeftLat, lowerRiteLat)); double loestLon = Math.Min(Math.Min(upperLeftLon, upperRiteLon), Math.Min(lowerLeftLon, lowerRiteLon)); double hiestLon = Math.Max(Math.Max(upperLeftLon, upperRiteLon), Math.Max(lowerLeftLon, lowerRiteLon)); double avgLat = (loestLat + hiestLat) / 2.0; double avgLon = (loestLon + hiestLon) / 2.0; int oneNorthX, oneNorthY, oneSouthX, oneSouthY; tiffchart.LatLon2Pixel(avgLat + 0.5, avgLon, out oneNorthX, out oneNorthY); tiffchart.LatLon2Pixel(avgLat - 0.5, avgLon, out oneSouthX, out oneSouthY); double pixperdeglat = Hypot(oneNorthX - oneSouthX, oneNorthY - oneSouthY); double pixperdeglon = pixperdeglat * Math.Cos(avgLat * Math.PI / 180.0); int pngwidth = (int)Math.Round((hiestLon - loestLon) * pixperdeglon); int pngheight = (int)Math.Round((hiestLat - loestLat) * pixperdeglat); Console.WriteLine("pngwidth,height=" + pngwidth + "," + pngheight); Bitmap pngbm = new Bitmap(pngwidth, pngheight); for (int pngy = 0; pngy < pngheight; pngy++) { if (pngy % 100 == 0) { Console.Write("\rpngy=" + pngy); } for (int pngx = 0; pngx < pngwidth; pngx++) { double lat = (double)pngy / pngheight * (loestLat - hiestLat) + hiestLat; double lon = (double)pngx / pngwidth * (hiestLon - loestLon) + loestLon; int tiffx, tiffy; tiffchart.LatLon2Pixel(lat, lon, out tiffx, out tiffy); if ((tiffx >= 0) && (tiffx < tw) && (tiffy >= 0) && (tiffy < th)) { Color pixel = tiffchart.bmp.GetPixel(tiffx, tiffy); pngbm.SetPixel(pngx, pngy, pixel); } } } Console.WriteLine(""); pngbm.Save(savename, System.Drawing.Imaging.ImageFormat.Png); string csvline = "box:" + hiestLat + "," + loestLon + "," + loestLat + "," + hiestLon + "," + pngwidth + "," + pngheight + "," + tiffchart.enddate + "," + tiffchart.spacename; File.WriteAllText(savename + ".csv", csvline + "\n"); }