算法思想
类似道格拉斯扑克算法,实现点的抽稀。
将一组二维坐标点,第一步设置预设值,首尾相连,如图,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,什么都还不会,能成功运行已是不易。望各位轻喷。