• gps点集合构造 简单多边形,排序 方向角,达到:边与边无交叉


    目的 

    • 一个点集合,可以输出多个不交叉的多边形;此类只能做到输出其中的一个,即:按夹角大小排序。(如下图左)
    • 不按夹角大小排序,也能输出得到不交叉的多边形(如下图右)。所以: 实际应用中,往往还是要根据实际情况来给各点排序、输出符合需求的多边形(如下图右);纯粹依赖排序这样的纯技术思维是不可取的。

    输出图例

      

    代码

    1.PolygonSort

    1. package util.polygon_sort;
    2. import java.util.Comparator;
    3. import java.util.HashMap;
    4. import java.util.Map;
    5. import java.util.TreeMap;
    6. /*
    7. * 点集合构造简单多边形,按逆时针,排序夹角,达到:边与边无交叉。
    8. * 一个点集合,可以输出多个不交叉的多边形;此类只能做到输出其中的一个。
    9. * 实际应用中,往往还是要根据实际情况来排序各点输出想要的多边形,而不是绝对按照夹角大小来排序。
    10. * Author:James Wang
    11. */
    12. public class PolygonSort{
    13. public static void main(String[] args) {
    14. /*
    15. Coordinate p1 = new Coordinate(53.0418333,24.9208333);//经度在前,纬度在后。
    16. Coordinate p2 = new Coordinate(53.0446667,24.9175);
    17. Coordinate p3 = new Coordinate(53.0448333,24.9045);
    18. Coordinate p4 = new Coordinate(53.0481667,24.9211667);
    19. Coordinate p5 = new Coordinate(53.057,24.8946667);
    20. Coordinate p6 = new Coordinate(53.0568333,24.8938333);
    21. Coordinate p7 = new Coordinate(54.0568333,24.9038333);
    22. Coordinate[] pList = { p1,p2,p3,p4,p5,p6,p7 };
    23. Map sortedMap = sort(pList) ;
    24. for (Map.Entry entry:sortedMap.entrySet() ){
    25. System.out.println("angle=" + entry.getKey() +",坐标等于 " + entry.getValue().toString() );
    26. }
    27. */
    28. //String s = "POLYGON((63.2505 24.6003333,62.5005 24.6003333,62.5005 24.3503333,63.2505 24.3503333))";
    29. String s = "POLYGON((51.41 26.352,52.2375 25.6245,51.6675 25.3138333,51.5903333 25.4816667,51.617 25.8458333,51.6913333 25.9155,51.4716667 26.0091667,51.275 26.2171667))";
    30. s = s.substring("POLYGON((".length(),s.lastIndexOf("))"));
    31. String[] ar = s.split(",");
    32. Map sortedMap2 = sort(ar) ;
    33. for (Map.Entry entry:sortedMap2.entrySet() ){
    34. System.out.println("angle=" + entry.getKey() +",坐标等于 " + entry.getValue().toString() );
    35. }
    36. }
    37. /* https://www.cnblogs.com/andyzeng/p/3754005.html
    38. * 点集合构造 简单多边形,排序 夹角,达到:边与边无交叉。
    39. */
    40. public static Map sort(Coordinate[] pList) {
    41. int minIdx = findMinLat(pList);
    42. Map bMap = getAngleMap(pList,minIdx);
    43. Map sortedMap = new TreeMap(new MapKeyComparator());
    44. sortedMap.putAll(bMap);
    45. /*double[] angle = getAngleList(pList,minIdx);
    46. /double[] sortedAngle = ArraySort.bubbleSort(angle,"asc");*/
    47. return sortedMap;
    48. }
    49. /*
    50. * 计算每个点到最小纬度点的angle
    51. */
    52. public static Map getAngleMap(Coordinate[] pList,int minIdx) {
    53. Map map = new HashMap();
    54. double angle = 0;
    55. for(int i=0;i
    56. angle = 0;
    57. if( i != minIdx ) {
    58. angle = aTan2(pList[minIdx],pList[i]);
    59. System.out.println( (i+1) + "->" + (minIdx+1) + ":角度"+ angle);
    60. }
    61. map.put(angle,pList[i]);
    62. }
    63. return map;
    64. }
    65. /*
    66. public static double[] getAngleList(Coordinate[] pList,int minIdx) {
    67. double[] angleList = new double[pList.length];
    68. for(int i=0;i
    69. if( i != minIdx ) {
    70. angleList[i] = aTan2(pList[minIdx],pList[i]);
    71. System.out.println( (i+1) + "->" + (minIdx+1) + ":角度"+ angleList[i]);
    72. }else {
    73. angleList[i] = 0;
    74. }
    75. }
    76. return angleList;
    77. }
    78. */
    79. /*
    80. * 找到最小lat的起点point,
    81. * 起点,在所有的其它点的下面,这样 其它点到起点的角度angle,都为正值(0度~180度),容易排序
    82. */
    83. public static int findMinLat(Coordinate[] pList) {
    84. int minIdx = 0;
    85. double min = 10000000;
    86. int minIdx2 = -1 ;
    87. for(int i=0;i
    88. if( pList[i].getLat() < min ) {
    89. min = pList[i].getLat();
    90. minIdx = i;
    91. }else if(pList[i].getLat() == min ) {
    92. minIdx2 = i;
    93. }
    94. }
    95. //System.out.println( "------第一遍---------最小lat的point的序号 为: " + (minIdx+1) + "=数组游标" + minIdx + "+1");
    96. if( minIdx2 >=0 ) {
    97. //System.out.println( "------第2遍---------最小lat的point的序号 为: " + (minIdx+1) + "=数组游标" + minIdx + "+1");
    98. if( pList[minIdx2].getLon() > pList[minIdx].getLon() ) {
    99. return minIdx2;
    100. }else if(pList[minIdx2].getLon() > pList[minIdx].getLon() ){
    101. System.out.println( "存在完全相同的点,不正常,手工剔除它们");
    102. return -1;
    103. }
    104. }
    105. return minIdx;
    106. }
    107. public static double aTan2(Coordinate p1,Coordinate p2) {//注意这里的aTan2返回degree,not radian
    108. double x = p2.getLon() - p1.getLon();
    109. double y = p2.getLat() - p1.getLat();
    110. //System.out.print(y + "," + x );
    111. return Math.toDegrees( Math.atan2(y,x) );
    112. }
    113. /*java的atan2函数学习例子 */
    114. public static void test() {
    115. double d = 45;
    116. double dR = Math.toRadians(d);//角度 转 弧度
    117. //System.out.println( (d* 180) / Math.PI);
    118. System.out.println( "tag " + d+ "(角)度=弧度:" + dR + "=" + Math.tan(dR) + ",约等于1, Math.atan(dR)= " + Math.atan(dR));//0.9999999999999999 约 等于 1
    119. //System.out.println( "atag45度=" + Math.atan(dR) + ",这个非常奇怪不等于 Math.tan !!");//0.9999999999999999
    120. System.out.println( "java.lang.Math.atan2()是已知一个角的正切值(也就是 y/x),求该角的弧度值。比如:Math.atan2(1,1) = "
    121. + Math.atan2(1,1) + ",转换成角度=" + Math.toDegrees( Math.atan2(1,1) ));//0.9999999999999999
    122. double dR30 = Math.toRadians(30);
    123. System.out.println("---------");
    124. System.out.println("正玄sin 30度=1/2=" + Math.sin(dR30) + "");//
    125. System.out.println("反正玄 asin 30度=2/1=" + Math.asin(dR30) + ",1/Math.sin(dR30)=" + (1/Math.sin(dR30) ) );//
    126. System.out.println("---------");
    127. System.out.println("cos 30 度=sqrt(3)/2=" + Math.cos(dR30) + ", 而手工计算(Math.sqrt(3)/2)= " + (Math.sqrt(3)/2)
    128. );//
    129. System.out.println("tag 30 度=1/sqrt(3)=" +Math.tan(dR30) + ", 而手工计算(1/Math.sqrt(3))= " + (1/Math.sqrt(3)));//
    130. System.out.println(Math.atan(dR30) + ",squar(3)/1=" + Math.sqrt(3));//
    131. System.out.println("---------");
    132. Coordinate p1 = new Coordinate(0,0);
    133. Coordinate p2 = new Coordinate(1,1);
    134. Coordinate p3 = new Coordinate(-1,Math.sqrt(3));
    135. System.out.println( aTan2(p1,p2) + ",角度=" + Math.toDegrees(aTan2(p1,p2) ));
    136. System.out.println( aTan2(p1,p3) + ",角度=" + Math.toDegrees(aTan2(p1,p3) ));
    137. }
    138. public static Map sort(String[] strList) {
    139. Coordinate[] pList = new Coordinate[strList.length];
    140. Coordinate p = null;
    141. double lat,lon;
    142. for( int i=0;i
    143. lon = Double.parseDouble(strList[i].split(" ")[0]);//经度在前,维度在后。
    144. lat = Double.parseDouble(strList[i].split(" ")[1]);
    145. p = new Coordinate(lat,lon);
    146. pList[i] = p;
    147. System.out.println( (i+1) + " 点:lat=" + lat + " lon= " + lon );
    148. }
    149. return sort(pList);
    150. }
    151. }
    152. class MapKeyComparator implements Comparator{
    153. @Override
    154. public int compare(Double angle1, Double angle2) {
    155. if( angle1>angle2 ) {
    156. return 1;
    157. }else if(angle1 < angle2 ){
    158. return -1;
    159. }else{
    160. return 0;
    161. }
    162. }
    163. }

    2.Coordinate

    1. package util.polygon_sort;
    2. public class Coordinate {
    3. double lat;
    4. double lon;
    5. public Coordinate(double lon,double lat) {//经度在前,纬度在后。
    6. this.lat = lat;
    7. this.lon = lon;
    8. }
    9. public Coordinate(String lon,String lat) {//经度在前,纬度在后。
    10. this.lat = Double.parseDouble(lat);
    11. this.lon = Double.parseDouble(lon);
    12. }
    13. public void setLat(double lat) {
    14. this.lat = lat;
    15. }
    16. public double getLat() {
    17. return lat;
    18. }
    19. public void setLon(double lon) {
    20. this.lon = lon;
    21. }
    22. public double getLon() {
    23. return lon;
    24. }
    25. @Override
    26. public String toString() {
    27. return lon + " " + lat ;
    28. }
    29. }

    参考文章

    几何算法:点集合构造简单多边形 - AndyZeng - 博客园

    Java数学函数 Math.atan2()详解 - 己平事 - 博客园

  • 相关阅读:
    【40】理解内存(上):虚拟内存和内存保护是什么?★★★★★
    Windows 11 使用 MySQL 官方压缩包手动安装
    Transformers 源码阅读之BertTokenizerFast分词模型
    金仓数据库KingbaseES安全指南--9.透明存储加密
    Openlayers 6 零基础教程
    Dotnet工具箱:开源、免费的纯前端工具网站,带你探索10大工具分类和73个实时在线小工具
    面试面经|Java面试kafka面试题
    Python处理word的常用操作详解
    springboot之@ImportResource:导入Spring配置文件~
    Buildroot 开发
  • 原文地址:https://blog.csdn.net/taikeqi/article/details/128042476