海圖繪制流程
- 全局變量存儲海圖文件夾路徑。
public static class MySettings { // ... public static string ChartFolder = "..\\"; //海圖文件夾 }
- 遍歷海圖總文件夾,將子文件夾中的海圖文件夾挑選出來,然后加載海圖文件,并完成坐標(biāo)轉(zhuǎn)換惹苗、通過查詢表匹配符號化指令。
//窗體級變量,存儲海圖文件 private S57File[] readers;
//遍歷海圖總文件夾件已,將子文件夾里的海圖文件夾挑選出來 var chartFolders = new List<string>(); foreach (var folder in Directory.GetDirectories(MySettings.ChartFolder).OrderBy(x => x)) { var fileName = Path.GetFileNameWithoutExtension(folder); //包含000文件,是海圖文件夾 if(File.Exists($"{folder}\\{fileName}.000")) { chartFolders.Add(folder); } } //加載海圖元暴,完成坐標(biāo)轉(zhuǎn)換 var len = chartFolders.Count; readers = new S57File[len]; for (int i = 0; i < len; i++) { readers[i] = new S57File(chartFolders[i]); var comf = (double)readers[i].COMF; var somf = (double)readers[i].SOMF; foreach (var s in readers[i].Spatials.Values) { if(s.YCOOs != null) { s.Latitudes = new double[s.YCOOs.Length]; s.Longitude = new double[s.XCOOs.Length]; for (int j = 0; j < len; j++) { s.Latitudes[j] = s.YCOOs[j] / comf; s.Longitude[j] = s.XCOOs[j] / comf; } } if (s.VE3Ds != null) { s.Depths = new double[s.VE3Ds.Length]; for (int j = 0; j < len; j++) { s.Depths[j] = s.VE3Ds[j] / somf; } } } if(readers[i].SLAT == 100d) //不存在海圖邊界信息篷扩,則重新計算下 { readers[i].WLON = readers[i].Spatials.Values.Where(x => x.Longitude != null).Min(x => x.Longitude.Min()); readers[i].ELON = readers[i].Spatials.Values.Where(x => x.Longitude != null).Max(x => x.Longitude.Max()); readers[i].SLAT = readers[i].Spatials.Values.Where(x => x.Latitudes != null).Min(x => x.Latitudes.Min()); readers[i].NLAT = readers[i].Spatials.Values.Where(x => x.Latitudes != null).Max(x => x.Latitudes.Max()); } //通過查詢表匹配符號化指令 foreach (var f in readers[i].Features.Values) { f.LookUp = S52Tools.FindLookUpEntry(f); } //通過符號化指令排序 //第一排序字段為:顯示優(yōu)先級 //第二排序字段為:面 > 線 > 點 //第三排序字段為:分組 readers[i].Features = readers[i].Features.OrderBy(x => x.Value.LookUp.Priority) .ThenByDescending(x => x.Value.PRIM) .ThenBy(x => x.Value.GRUP) .ToDictionary(k => k.Key, v => v.Value); }
- 確定視窗中心經(jīng)緯:默認(rèn)為所加載海圖地理范圍的中心。
//確定顯示區(qū)域中心及顯示比例尺 double slat = 100, nlat = -100, elon = -200, wlon = 200; uint cscl = 0; for (int i = 0; i < len; i++) { if (slat > readers[i].SLAT) slat = readers[i].SLAT; if (nlat < readers[i].NLAT) nlat = readers[i].NLAT; if (wlon > readers[i].WLON) wlon = readers[i].WLON; if (elon < readers[i].ELON) elon = readers[i].ELON; if (readers[i].CSCL > cscl) cscl = readers[i].CSCL; } //視窗中心位置 initCenterPos.Latitude = (slat + nlat) / 2; initCenterPos.Longitude = (elon + wlon) / 2;
- 確定視窗的初始顯示比例尺:默認(rèn)為所加載海圖中最小的編譯比例尺茉盏。
當(dāng)海圖中編譯比例尺信息為空時鉴未,默認(rèn)顯示全部加載海圖。//顯示比例尺 if (cscl == 0) //沒有指定編譯比例尺鸠姨,則將所有海圖都顯示在視窗中 { var deltaY = (nlat - slat) * 0.1; var pix_X = (elon - wlon) * 60 * 1.2; var pix_Y = (GeoTools.MP(nlat + deltaY) - GeoTools.MP(slat - deltaY)); if (pix_X / pix_Y < (double)current_Width / current_Height) { current_Scale = (uint)(pix_X * GeoTools.MinPP / current_Width); } else { current_Scale = (uint)(pix_Y * GeoTools.MinPP / current_Height); } } else { current_Scale = cscl; }
- 比例尺與中心位置定好后铜秆,遍歷海圖文件,通過海圖范圍粗略判斷海圖是否在視窗范圍內(nèi)讶迁。
private void DrawEnc(SKCanvas ca) { //右上角位置 var trPos = GeoTools.ScreenPointToGeoPosition(current_Width, 0, current_Scale, current_Dx, current_Dy); //左下角位置 var blPos = GeoTools.ScreenPointToGeoPosition(0, current_Height, current_Scale, current_Dx, current_Dy); //區(qū)域矩形 var zoneRec = new SKRect(0, 0, current_Width, current_Height); for (int i = 0; i < readers.Length; i++) { var reader = readers[i]; //粗略判斷海圖范圍是否在視窗內(nèi) if (GeoTools.ShouldNotDisplay(trPos, blPos, reader.NLAT, reader.SLAT, reader.ELON, reader.WLON)) continue; //下一步操作 } }
- 遍歷海圖特征記錄连茧,只顯示點、線巍糯、面物標(biāo)啸驯。并且當(dāng)前顯示比例尺在物標(biāo)比例尺范圍之內(nèi),則繪制該特標(biāo)祟峦。
//下一步操作 foreach (var f in reader.Features.Values) { if (f.PRIM == 255) continue; //超出比例尺 if (current_Scale > f.ScaleMinium || current_Scale < f.ScaleMaximum) continue; //沒有繪制指令 if (f.LookUp.Instructions == null) continue; #region 繪制 }
- 按照物標(biāo)的符號化指令進(jìn)行繪制罚斗。