自己寫的點的抽稀(point wedding)演算法,類似Douglas-Peuker
阿新 • • 發佈:2018-12-19
自己寫的點的抽稀(point wedding)演算法
演算法思想
想到這個演算法的“契機”是上課沒好好聽課,強行理解道格拉斯撲克演算法成了這個樣子…
不過搜了一下好像還沒有這種演算法,權當是自己創作的了…
類似道格拉斯撲克演算法,實現點的抽稀。 將一組二維座標點,第一步設定預設值,首尾相連,如圖,P0連線P6成直線L 先從後往前計算,P5到L的距離,若距離小於預設值,則去除該點,計算下一個點P4,以此類推;若大於預設值,則P5為L的後端點,並從前端點開始往後計算每個點。
即:首次從後計算每個點到直線距離,小於預設值的點去除,大於預設值的點成為新的端點,並計算順序改變,直到所有點被遍歷過。
已知的演算法缺點:效率低(每次都要計算點到直線距離,並再判斷,老師說的)
程式碼實現
這是計算類,用於計算兩點之間的距離和三角形的高(傳入引數為三邊長度,用來得到點到直線距離)
public class calcu { //計算兩點之間的距離 public double dist(double x1,double x2,double y1,double y2) { double dis=-1; double dist=(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1); dis=Math.sqrt(dist); return dis; } public double calcuteS(double a,double b,double c) { double s =(a+b+c)/2f; double S = Math.sqrt(s*(s-a)*(s-b)*(s-c)); return S; } }
這是讀取TXT文件的類,讀取資料並分割 資料格式如圖
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class ReadTXT { /** * 讀取檔案 * @param filePath * @return */ public static List readTxtFile(String filePath) { List<String> list = new ArrayList<String>(); try { String encoding = "UTF-8"; File file = new File(filePath); if (file.isFile() && file.exists()) { InputStreamReader read = new InputStreamReader( new FileInputStream(file), encoding); BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { if (!lineTxt.startsWith("#")) list.add(lineTxt); } read.close(); } else { System.out.println("找不到檔案"); } } catch (Exception e) { System.out.println("出錯了"); e.printStackTrace(); } return list; } /** * 建立二維陣列 * @param list * @return */ public static String[][] createArray(String filePath){ List<String> list = readTxtFile(filePath); String array[][] = new String[list.size()][]; for(int i=0;i<list.size();i++){ array[i] = new String[2]; String linetxt=list.get(i); String[] myArray = linetxt.replaceAll("\\s+", "@").split("@"); for(int j=0;j<myArray.length;j++){ if(j<2){ array[i][j]=myArray[j]; } } } return array; } }
以下為抽稀演算法實現
TXT檔案目錄為:D:\java_workspace\homework2\point.txt
import java.util.Scanner;
import point.ReadTXT;
public class Weending {
public static void main(String[] args) {
// TODO Auto-generated method stub
ReadTXT rd=new ReadTXT();
String array[][] = rd.createArray("D:\\java_workspace\\homework2\\point.txt"); //開啟並讀取文件
// 將文件讀取出的資料(String型別)轉成double型別,存入二維陣列
double[][] aa=new double[array.length][2];
for(int i=0;i<array.length;i++) {
aa[i][0]=Double.parseDouble(array[i][0]);
aa[i][1]=Double.parseDouble(array[i][1]);
//System.out.println(aa[i][0]);
}
//控制檯輸入預設值
System.out.println("請輸入預設值(小於預設垂線距離的點將會被除掉):");
Scanner cin=new Scanner(System.in);
double def; //預設值
/*
-------------------------------------------------------
*/
def=cin.nextDouble(); //將控制檯輸入存放入def變數中
cin.close(); //關閉輸入流
calcu ca=new calcu(); //建立calcu的物件
int temp=aa.length-2;
//temp為從後往前的計算點,temp1位從前往後計算點,為三角形中的位於中間位置的點,
//另外兩個為bg和oe,代表起點和止點,也是三角形上的點。
int temp1=1;
//temp從倒數第二個開始,即aa陣列的倒數第二個,aa.length-2;
//對應的temp從第二個開始(而不是第一個,第一個點為最初的起點bg,為三角形內的另一個點)
//建立三角形的目的是為了求三角形面積,進而計算頂點即temp(或者temp1)到起止點連線的垂線長度(h)
int bg=0,oe=aa.length-1;
int k=1;
/*設立k的目的是當某個temp(或者temp1)計算得到的垂線大於預設值def時,則該點會被保留,
* 且該點會被重設為終點(或起點),且計算需要從另一個方向開始,這個時候k值加一,從而使迴圈
* 由從後向前變成從前向後(或者從前向後變成從後向前)
*/
while (temp>temp1){
double len=ca.dist(aa[bg][0], aa[oe][0],aa[bg][1], aa[oe][1]);
if (k%2==1) {
for(int i=0;i < temp;i++) {
double len1=ca.dist(aa[bg][0], aa[temp][0],aa[bg][1], aa[temp][1]);
double len2=ca.dist(aa[oe][0], aa[temp][0],aa[oe][1], aa[temp][1]);
double s=ca.calcuteS(len, len1, len2);
double h=s/len;
if (len1==0|len2==0) {
break;
}
if (h>def) {
oe=temp;
i=aa.length;
k++;
temp=oe-1;
}else {
temp=temp-1;
if (temp<=bg) {
break;
}
aa[temp+1][0]=0;
aa[temp+1][1]=0;
}
}
}else {
for (int j = 0; j < oe-bg; j++) {
double len1=ca.dist(aa[bg][0], aa[temp1][0],aa[bg][1], aa[temp1][1]);
double len2=ca.dist(aa[oe][0], aa[temp1][0],aa[oe][1], aa[temp1][1]);
double s=ca.calcuteS(len, len1, len2);
double h=s/len;
if (h>def) {
bg=temp1;
j=aa.length;
k++;
temp1=bg+1;
}else {
temp1=temp1+1;
if (temp1>=oe) {
break;
}
aa[temp1-1][0]=0;
aa[temp1-1][1]=0;
}
}
}
}
int num=1;
for (int i = 1; i < aa.length; i++) {
if ((aa[i][0]==0) & (aa[i][1]==0)) {
}else {
num=num+1;
}
}
//System.out.println(num);
double[][] aaa=new double[num][2];
aaa[0][0]=aa[0][0];
aaa[0][1]=aa[0][1];
aaa[num-1][0]=aa[aa.length-1][0];
aaa[num-1][1]=aa[aa.length-1][1];
int index=1;
for (int i = 1; i <aa.length; i++) {
if (aa[i][0]!=0&aa[i][1]!=0) {
aaa[index][0]=aa[i][0];
aaa[index][1]=aa[i][1];
index++;
}
}
System.out.println("除草前的點為:");
for (int i = 0; i < array.length; i++) {
System.out.println(array[i][0]+","+array[i][1]);
}
System.out.println("除草後的點為:");
for (int i = 0; i < aaa.length; i++) {
System.out.println(aaa[i][0]+","+aaa[i][1]);
}
}
}
控制檯輸入預設值,將會對TXT內座標點進行抽稀
其中有一步,將陣列內需要去除的點,先設為(0,0),之後儲存到另一個數組時去掉(0,0)的點,這樣就會有一個問題,如果一個點本身就是(0,0)那麼它也會被去除,水平有限,沒有想到能解決的辦法。 我知道,我程式碼又臭又長… 沒辦法,初學java,什麼都還不會,能成功執行已是不易。望各位輕噴。