思想就是取最小的x,当x一样取最小的y,取每个点与当前比对点的正切值从大到小排序得到顺时针的顺序
package com.test.utils;
import java.util.*;
/**
* @version 1.0.0
* @author: gongchao
* @date: 2019/3/8 11:36
* 离散二维坐标的顺时针方向排序工具类
*/
public class PositionUtils {
//二维坐标
static class Position{
Double x;
Double y;
public Position(Double x,Double y){
this.x=x;
this.y=y;
}
@Override
public String toString() {
return "x="+x+"y="+y;
}
}
public static void main(String[] aa){
//255,459 511,459 1495,1050 310,1050
List<Position> list = new ArrayList<>();
list.add(new Position(255d,459d));
list.add(new Position( 511d,459d));
list.add(new Position(1495d,1050d));
list.add(new Position(310d,1050d));
// list.add(new Position(1069d,496d));
// list.add(new Position(1500d,1075d));
// list.add(new Position(434d,1075d));
// list.forEach((x)-> System.out.println((x.x/917+","+x.y/518)));
list.forEach((x)-> System.out.println((x.x/1920+","+x.y/1080)));
// list.add(new Position(0.2077,0.2698));
// list.add(new Position(0.0321,0.293));
// list.add(new Position(0.1435,0.4209));
// list.add(new Position(0.0514,0.5));
List<Position> positions = null;
try {
positions = PositionUtils.sortPosition(list);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*输入离散点得到顺时针的二维做标集合
* @param list
* @throws Exception
*/
public static List<Position> sortPosition(List<Position> list)throws Exception{
//保存X轴坐标一样的无限小正切的集合点,按x轴从小到大
List<Position> minTanXList=new ArrayList<>();
//保存Y轴坐标一样的为零正切的集合点,y轴从小到大
List<Position> zeroTanYList=new ArrayList<>();
//排序后的二维坐标
List<Position> afterSort=new ArrayList<>();
//将各个点到最小的tan值和坐标保存起来
Map<Double,Position> tanMap=new HashMap<>();
//将各个点到最小的tan值保存起来
List<Double> tanLists=new ArrayList<>();
//根据X轴坐标从小到大排序
List<Position> leftPosition = getLeftPosition(list);
//获取最左边且靠近原点的点
Position leftPostion = leftPosition.get(0);
//原点
afterSort.add(leftPostion);
//排除最小的点从1开始获取每个点到最小点的正切
for (int i=1;i<list.size();i++){
Position nextPostion = list.get(i);
//获取tan值的分子和分母
Double tanFenmu=nextPostion.x-leftPostion.x;
Double tanFenzi=nextPostion.y-leftPostion.y;
//考虑到多个点与参照点同一个X坐标导致正切无限小
if(tanFenmu.equals(0d)){
minTanXList.add(nextPostion);
}else if(tanFenzi.equals(0d)){
//y轴一样正切为0
zeroTanYList.add(nextPostion);
}else{
Double tan=(tanFenzi)/(tanFenmu);
tanMap.put(tan,nextPostion);
tanLists.add(tan);
}
}
//tan的值从大到小排列,相当于顺时针
tanLists.sort(Comparator.reverseOrder());
//正切无限大
if(!minTanXList.isEmpty()){
Collections.sort(minTanXList,( p1, p2)->p1.y.compareTo(p2.y));
afterSort.addAll(minTanXList);
}
// tanLists.forEach((tan)-> System.out.println(tan));
Boolean flag=Boolean.TRUE;
for (int i=0;i<tanLists.size();i++){
Double tan = tanLists.get(i);
//将排序后的从map取出来
//添加正切为零的数据
if(tan<0d&&flag){
if(!zeroTanYList.isEmpty()){
afterSort.addAll(zeroTanYList);
}
flag=Boolean.FALSE;
afterSort.add(tanMap.get(tan));
}else{
afterSort.add(tanMap.get(tan));
if(tanLists.size()==1){
afterSort.addAll(zeroTanYList);
}
if(tan>0&&i==tanLists.size()-1){
afterSort.addAll(zeroTanYList);
}
}
}
// afterSort.sort();
afterSort.forEach((x)-> System.out.println(x.x+","+x.y));
// afterSort.forEach((x)-> System.out.println(x.x*1920+","+x.y*1080));
return afterSort;
}
/**
* 根据X轴坐标从小到大排序
* @param list 随机离散点集合
* @return
* @throws Exception
*/
public static List<Position> getLeftPosition(List<Position> list)throws Exception{
if (list.size()<3){
throw new Exception("必须多余四个点");
}
// 取x最小的点,相同x取y小的点
Collections.sort(list,(Position o1, Position o2)->{
if(o1.x.equals(o2.x)){
return o1.y.compareTo(o2.y);
}else{
return o1.x.compareTo(o2.x);
}
});
return list;
}
}