經緯座標(BLH)資料建立.kml檔案小工具設計 Java版
技術背景
KML,是 ofollow,noindex" target="_blank">標記語言 (Keyhole Markup Language)的縮寫,最初由Keyhole公司開發,是一種基於XML 語法與格式的、用於描述和儲存地理資訊(如點、線、影象、多邊形和模型等)的編碼規範,可以被 Google Earth 和 Google Maps 識別並顯示。
建立這個工具只是因為一次偶然的需求,因為要將一個2G的點雲資料導到Google Earth上進行顯示,手動編輯絕對是不可能的,所以臨時建立了這個小工具,為了方便使用,添加了一些簡易的操作介面,這樣便可以批量寫入經緯度三維座標資料(含高程)至kml檔案內,然後匯入Google Earth進行顯示。關於kml檔案的內部格式這裡就不再詳細描述了,具體內容請檢視參考部落格1【KML地圖檔案解析】。下面具體講述一下程式設計原理。
實現原理
本程式核心原理是很簡單的,首先將.csv(或.txt)檔案(內部格式為B,L,H 一行一個點座標)讀取以後,建立kml檔案的頭,然後根據kml檔案的固定格式,將資料寫入,最後檔案寫入完成以後,新增上檔案的尾部格式。檔案選擇採用的是JFileChooser,具體使用方法請檢視參考部落格2【 swing中JFileChooser的用法 】。
最後是介面的簡要製作,新增兩個控制元件,一個是用來選擇檔案的,另一個為程式退出按鈕。不再具體闡述了,原理比較簡單,直接上程式碼吧。
具體實現
專案結構
核心部分
1 package main; 2 3 import java.io.BufferedWriter; 4 import java.io.File; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.FileReader; 8 import java.io.FileWriter; 9 import java.io.IOException; 10 import java.io.LineNumberReader; 11 import java.io.PrintStream; 12 import javax.swing.JFileChooser; 13 import javax.swing.JLabel; 14 15 public class BlhToKml { 16 17 /** 18 * @param args 19 */ 20 public static String InputFilePath; 21 public static String OutputFilePath; 22 @SuppressWarnings("static-access") 23 public static void main() throws IOException{ 24 JFileChooser jfc=new JFileChooser(); 25 jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES ); 26 jfc.showDialog(new JLabel(), "選擇檔案"); 27 File file = jfc.getSelectedFile(); 28 if(file == null){ 29 return; 30 } 31 String FilePath = file.getAbsolutePath(); 32 InputFilePath=FilePath; 33 OutputFilePath=InputFilePath; 34 if(OutputFilePath.indexOf(".")>=0) 35 { 36 OutputFilePath = OutputFilePath.substring(0, OutputFilePath.lastIndexOf(".")); 37 }else{ 38 return; 39 } 40 OutputFilePath=OutputFilePath+".kml"; 41 //System.out.println(OutputFilePath); 42 WriteHeadInformationToFile1(); 43 WriteHeadInformationToFile2(); 44 ReplacePointInformation(); 45 WriteEndInformationToFile(); 46 TipFrame TF = new TipFrame(); 47 TF.tishifu("已經轉換完成!"); 48 } 49 //將標題寫入到指定路徑下的文字內 50 public static void WriteHeadInformationToFile1() { 51 String filePath = OutputFilePath; 52 try { 53 File file = new File(filePath); 54PrintStream ps = new PrintStream(new FileOutputStream(file)); 55ps.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 56ps.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\"\r\n"); 57} catch (FileNotFoundException e){ 58e.printStackTrace(); 59} 60} 61 public static void WriteHeadInformationToFile2(){ 62 String filePath = OutputFilePath; 63 try { 64FileWriter fw = new FileWriter(filePath, true); 65BufferedWriter bw = new BufferedWriter(fw); 66bw.write("xmlns:atom=\"http://www.w3.org/2005/Atom\">\r\n"); 67bw.write("<Document>\r\n"); 68bw.write("\t<name>Placemark.kml</name>\r\n"); 69bw.write("\t<Style id=\"sh_placemark_circle_highlight\">\r\n"); 70bw.write("\t\t<IconStyle>\r\n"); 71bw.write("\t\t\t<color>ff0000ff</color>\r\n"); 72bw.write("\t\t\t<scale>0.8</scale>\r\n"); 73bw.write("\t\t\t<Icon>\r\n"); 74bw.write("\t\t\t\t<href>http://maps.google.com/mapfiles/kml/shapes/open-diamond.png</href>\r\n"); 75bw.write("\t\t\t</Icon>\r\n"); 76bw.write("\t\t</IconStyle>\r\n"); 77bw.write("\t\t<ListStyle>\r\n"); 78bw.write("\t\t</ListStyle>\r\n"); 79bw.write("\t</Style>\r\n"); 80bw.write("\t<StyleMap id=\"msn_placemark_circle\">\r\n"); 81bw.write("\t\t<Pair>\r\n"); 82bw.write("\t\t\t<key>normal</key>\r\n"); 83bw.write("\t\t\t<styleUrl>#sn_placemark_circle</styleUrl>\r\n"); 84bw.write("\t\t</Pair>\r\n"); 85bw.write("\t\t<Pair>\r\n"); 86bw.write("\t\t\t<key>highlight</key>\r\n"); 87bw.write("\t\t\t<styleUrl>#sh_placemark_circle_highlight</styleUrl>\r\n"); 88bw.write("\t\t</Pair>\r\n"); 89bw.write("\t</StyleMap>\r\n"); 90bw.close(); 91fw.close(); 92} catch (Exception e) { 93e.printStackTrace(); 94} 95} 96 public static void ReplacePointInformation() throws IOException { 97 String filePath = OutputFilePath; 98 File sourceFile = new File(InputFilePath); 99 int lineNum = getTotalLines(sourceFile); 100 try { 101 FileWriter fw = new FileWriter(filePath, true); 102 BufferedWriter bw = new BufferedWriter(fw); 103 for(int i = 0;i<lineNum;i++){ 104 bw.write("\t<Placemark>\r\n"); 105 bw.write("\t\t<styleUrl>#msn_placemark_circle</styleUrl>\r\n"); 106 bw.write("\t\t<Point>\r\n"); 107 String str1=readAppointedLineNumber(sourceFile, i+1); 108 bw.write("\t\t\t<coordinates>"+str1+",</coordinates>\r\n"); 109 bw.write("\t\t</Point>\r\n"); 110 bw.write("\t</Placemark>\r\n"); 111 } 112 bw.close(); 113 fw.close(); 114 } catch (Exception e) { 115 e.printStackTrace(); 116 } 117 } 118 public static void WriteEndInformationToFile() { 119 String filePath = OutputFilePath; 120 try { 121 FileWriter fw = new FileWriter(filePath, true); 122 BufferedWriter bw = new BufferedWriter(fw); 123 bw.write("</Document>\r\n"); 124 bw.write("</kml>"); 125 bw.close(); 126 fw.close(); 127 } catch (Exception e) { 128 e.printStackTrace(); 129 } 130 } 131 // 讀取檔案指定行。 132public static String readAppointedLineNumber(File sourceFile, int lineNumber) 133throws IOException { 134FileReader in = new FileReader(sourceFile); 135LineNumberReader reader = new LineNumberReader(in); 136String s = ""; 137if (lineNumber <= 0 || lineNumber > getTotalLines(sourceFile)) { 138System.out.println("不在檔案的行數範圍(1至總行數)之內。"); 139System.exit(0); 140} 141int lines = 0; 142while (s != null) { 143lines++; 144s = reader.readLine(); 145if((lines - lineNumber) == 0) { 146//System.out.println(s); 147return s; 148} 149} 150reader.close(); 151in.close(); 152 return s; 153} 154// 檔案內容的總行數。 155public static int getTotalLines(File file) throws IOException { 156FileReader in = new FileReader(file); 157LineNumberReader reader = new LineNumberReader(in); 158String s = reader.readLine(); 159int lines = 0; 160while (s != null) { 161lines++; 162s = reader.readLine(); 163if(lines>=2){ 164if(s!=null){ 165//System.out.println(s+"$"); 166} 167} 168} 169reader.close(); 170in.close(); 171//System.out.println(lines); 172return lines; 173} 174 }
窗體部分1-主介面
1 package main; 2 3 import java.awt.Color; 4 import java.awt.FlowLayout; 5 import java.awt.Font; 6 import java.awt.Frame; 7 import java.awt.Label; 8 import java.awt.event.ActionEvent; 9 import java.awt.event.ActionListener; 10 import java.awt.event.WindowAdapter; 11 import java.awt.event.WindowEvent; 12 import java.io.IOException; 13 import javax.swing.JButton; 14 import javax.swing.JLabel; 15 import javax.swing.JPanel; 16 17 public class Frame1 { 18 19 /** 20 * @param args 21 */ 22 public static void main(String[] args) { 23 // TODO Auto-generated method stub 24 major_Frame(); 25 } 26 public static void major_Frame(){ 27 final Frame major = new Frame("KML轉換器"); 28 major.setLayout(new FlowLayout(FlowLayout.CENTER)); 29 major.setBounds(400, 300, 430, 250); 30 major.setBackground(new Color(255,255,255)); 31 JPanel jPanel = new JPanel();//建立jPanel 32 jPanel.setBackground(new Color(255,255,255) ); 33jPanel.add(new JLabel("<html><br>\t每一行的資料屬性為:精度,緯度,高程。每一個數據之間用英<br>" + 34"文逗號隔開。<br><br><br></html>"));//為jPanel新增JLabel 35 Label label1 = new Label("格式提示"); 36 label1.setFont(new Font("",1,18));//字型大小 37 label1.setBounds(100,200,400,200); 38 major.add(label1); 39 major.add(jPanel); 40 JButton btn1 = new JButton("輸入"); 41 btn1.addActionListener(new ActionListener(){ 42 @SuppressWarnings("unused") 43 public void actionPerformed(ActionEvent arg0) { 44 // TODO Auto-generated method stub 45 BlhToKml blhtokml = new BlhToKml(); 46 try { 47 BlhToKml.main(); 48 } catch (IOException e) { 49 // TODO Auto-generated catch block 50 e.printStackTrace(); 51 } 52 } 53 54 }); 55 JButton btn2 = new JButton("退出"); 56 btn2.addActionListener(new ActionListener(){ 57 public void actionPerformed(ActionEvent e) { 58 major.setVisible(false); 59 System.exit(0); 60 } 61 }); 62 major.add(btn1); 63 major.add(btn2); 64 major.addWindowListener(new WindowAdapter(){ 65 public void windowClosing(WindowEvent e){ 66 //System.exit(0); 67 major.setVisible(false); 68 major.dispose(); 69 } 70 }); 71 major.setVisible(true); 72 } 73 74 }
窗體部分2-提示窗
1 package main; 2 3 import java.awt.FlowLayout; 4 import java.awt.Font; 5 import java.awt.Frame; 6 import java.awt.GridLayout; 7 import java.awt.Label; 8 import java.awt.event.MouseEvent; 9 import java.awt.event.MouseListener; 10 import java.awt.event.WindowAdapter; 11 import java.awt.event.WindowEvent; 12 import javax.swing.JButton; 13 import javax.swing.JPanel; 14 15 public class TipFrame { 16 public static void tishifu(String str){ 17 final Frame f1=new Frame("提示"); 18 f1.setBounds(500, 300, 300, 160); 19 f1.setResizable(false); 20 f1.setLayout(new GridLayout(2,1)); 21 JPanel jpanel1 = new JPanel(new FlowLayout(FlowLayout.CENTER)); 22 Label label1 = new Label(str); 23 label1.setFont(new Font("",1,15)); 24 jpanel1.add(label1); 25 f1.add(jpanel1); 26 JPanel jpanel2 = new JPanel(new FlowLayout(FlowLayout.CENTER)); 27 JButton Yes =new JButton("確定"); 28 jpanel2.add(Yes); 29 f1.add(jpanel2); 30 f1.addWindowListener(new WindowAdapter() { 31 public void windowClosing(WindowEvent e) { 32 //System.exit(0); 33 f1.setVisible(false); 34 f1.dispose(); 35 } 36 }); 37 Yes.addMouseListener(new MouseListener(){ 38 @Override 39 public void mouseClicked(MouseEvent arg0) { 40 // TODO 自動生成的方法存根 41 } 42 @Override 43 public void mouseEntered(MouseEvent arg0) { 44 // TODO 自動生成的方法存根 45 } 46 @Override 47 public void mouseExited(MouseEvent arg0) { 48 // TODO 自動生成的方法存根 49 } 50 public void mousePressed(MouseEvent arg0) { 51 // TODO 自動生成的方法存根 52 f1.setVisible(false); 53 f1.dispose(); 54 } 55 @Override 56 public void mouseReleased(MouseEvent arg0) { 57 // TODO 自動生成的方法存根 58 } 59 }); 60 f1.setVisible(true); 61 } 62 }
執行效果
主窗體
選擇窗體
提示窗
執行結果
測試資料(部分)
成果資料(部分)
具體匯入到谷歌地圖就可以了
至此,小工具設計完成了!
原始碼我已經上傳至部落格圓了,下載地址:https://files.cnblogs.com/files/thyou/BLH_to_KML.zip,希望能對使用kml檔案這方面的同學有一絲幫助。
致謝
感謝博主對於相關技術的分享交流!
參考部落格
1、KML地圖檔案解析【https://blog.csdn.net/onlymydreams_mfc/article/details/81840232】
2、swing中JFileChooser的用法【https://www.cnblogs.com/happyPawpaw/archive/2013/04/27/3046414.html】
3、