1. 程式人生 > >自己寫的點的抽稀(point wedding)演算法,類似Douglas-Peuker

自己寫的點的抽稀(point wedding)演算法,類似Douglas-Peuker

自己寫的點的抽稀(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,什麼都還不會,能成功執行已是不易。望各位輕噴。