原文链接

package cma.common.isoline;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;public abstract class   Coordinate   {//投影方式public static   int     LAMBERT     =   1 ;public static   int     MERCATOR    =   2 ;public static   int     BBQ         =   3 ;public static   int     NBQ         =   4 ;public static   int     LINEAR      =   5 ;public static   int     POLAR       =   6 ;//静态常量,地球半径,来源:《大气科学常用公式》,P601,附录public static   double   RADIUS         =   6371.004 ; //地球平均半径,单位:公里(Km)。public static   double   RADIUS_POLAR   =   6356.755 ; //地球两极半径,单位:公里(Km)。public static   double   RADIUS_EQUATOR =   6373.140 ; //地球赤道半径,单位:公里(Km)。//标准经纬度(0.0<=longitude<=360, -90.0<=latitude<=90.0)protected   Point2D.Double    standard; //兰勃特、极射赤面投影用到//中心经纬度(0.0<=longitude<=360, -90.0<=latitude<=90.0),用于定位,不一定是中心protected   Point2D.Double    center;//中心经纬度对应的屏幕坐标protected   Point             place;//偏移protected   Point             offset;//缩放比例(非0正值,经向纬向可以不同)protected   Point2D.Double    scaleXY;//缩放系数protected   double              scale;protected   double              scaleOriginal;public    int   type    = - 1 ;/*** 功能:*      获得标准经纬度* 参数:*      无* 返回值:*      标准经纬度*/public   Point2D.Double getStandard () {return ( standard ) ;}/*** 功能:*      获得中心经纬度* 参数:*      无* 返回值:*      中心经纬度*/public   Point2D.Double getCenter () {return ( center ) ;}/*** 功能:*      获得中心经纬度对应的屏幕坐标* 参数:*      无* 返回值:*      中心经纬度对应的屏幕坐标*/public   Point getPlace () {return ( place ) ;}/*** 功能:*      获得缩放系数* 参数:*      无* 返回值:*      缩放系数*/public   double   getScale () {return ( scale ) ;}/*** 功能:*      获得缩放比例* 参数:*      无* 返回值:*      缩放比例*/public   Point2D.Double getScaleXY () {return ( scaleXY ) ;}/*** 功能:*      放大* 参数:*      无* 返回值:*      无*/public   void   zoomIn () {scale   = scale *   2.0 ;}/*** 功能:*      缩小* 参数:*      无* 返回值:*      无*/public   void   zoomOut () {scale   = scale /   2.0 ;}/*** 功能:*      复原* 参数:*      无* 返回值:*      无*/public   void   revert () {scale   = scaleOriginal;}/*//======================================================================//  以下为抽象方法定义,具体实现由继承类来完成。//======================================================================*//*** 功能:*      获得屏幕坐标* 参数:*      lon     - 经度*      lat     - 纬度* 返回值:*      屏幕坐标*/public abstract   Point getPosition ( double   lon,   double   lat ) ;/*** 功能:*      获得屏幕坐标对应的经纬度* 参数:*      x       - 屏幕水平坐标*      y       - 屏幕垂直坐标* 返回值:*      对应的经纬度*/public abstract   Point2D.Double getCoordinate ( int   x,   int   y ) ;/*** 功能:*      获得角度(不同投影含义不同)* 参数:*      lon - 水平坐标*      lat - 垂直坐标* 返回值:*      角度值*///Lambert、Stereogram、Polar类需要重载此方法,Linear、Mercator类直接返回0。public   double   getAngle ( double   lon,   double   lat ) {return ( 0.0 ) ;}/*** 功能:*      画经线、纬线* 参数:*      g       - 图形设备*      f       - 字体*      c       - 画线颜色*      inc_lon - 经线间隔*      inc_lat - 纬线间隔* 返回值:*      无*/public abstract   void   drawGridLine ( Graphics2D g, Font f, Color c,   int   inc_lon,   int   inc_lat ) ;}
/*** */
package cma.common.isoline;import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import  java.text.DecimalFormat;public class Linear extends  Coordinate{/*** 功能:*      重置参数* 参数:*      lon,lat     - 中心经纬度,*      px,py       - 中心经纬度对应的屏幕坐标*      sx,sy       - 缩放系数* 返回值:*      无*/public  void  reset ( double  lon,  double  lat,  int  px,  int  py,  double  sc,  double  sx,  double  sy ) {type            = Coordinate.LINEAR;center          =  new  Point2D.Double (lon <    0.0  ?    0.0  : lon >  360.0  ?  360.0  : lon,lat < - 90.0  ? - 90.0  : lat >   90.0  ?   90.0  : lat) ;place           =  new  Point ( px, py ) ;scaleXY         =  new  Point2D.Double ( sx== 0.0 ? 1.0 :Math.abs ( sx ) , sy== 0.0 ? 1.0 :Math.abs ( sy )) ;scale           = Math.abs ( sc ) ;scaleOriginal   = scale;offset          =  new  Point ( 0 ,  0 ) ; //未用}/*** 功能:*      构造函数* 参数:*      无(使用缺省值)* 返回值:*      无*/public  Linear () {reset ( 109.40 ,  24.35 ,  640 ,  480 ,  1.0 ,  10.0 ,  10.0 ) ;}/*** 功能:*      构造函数* 参数:*      lon,lat     - 中心经纬度,*      px,py       - 中心经纬度对应的屏幕坐标*      sc          - 缩放系数* 返回值:*      无*/public  Linear ( double  lon,  double  lat,  int  px,  int  py,  double  sc ) {reset ( lon, lat, px, py, sc,  10.0 *sc,  10.0 *sc ) ;}/*** 功能:*      构造函数* 参数:*      lon,lat     - 中心经纬度,*      px,py       - 中心经纬度对应的屏幕坐标*      sx,sy       - 缩放比例* 返回值:*      无*/public  Linear ( double  lon,  double  lat,  int  px,  int  py,  double  sx,  double  sy ) {reset ( lon, lat, px, py,  1.0 , sx, sy ) ;}/*** 功能:*      重置参数* 参数:*      lon,lat     - 中心经纬度,*      px,py       - 中心经纬度对应的屏幕坐标*      sx,sy       - 缩放系数* 返回值:*      无*/public  void  reset ( double  lon,  double  lat,  int  px,  int  py,  double  sx,  double  sy ) {reset ( lon, lat, px, py,  1.0 , sx, sy ) ;}/*** 功能:*      获得屏幕坐标* 参数:*      lon     - 经度*      lat     - 纬度* 返回值:*      屏幕坐标*/public  Point getPosition ( double  lon,  double  lat ) {return (new  Point (place.x +  ( int )( 0.5  +  ( lon - center.x )  * scale * scaleXY.x ) ,place.y +  ( int )( 0.5  +  ( center.y - lat )  * scale * scaleXY.y ))) ;}/*** 功能:*      获得屏幕坐标对应的经纬度* 参数:*      x       - 屏幕水平坐标*      y       - 屏幕垂直坐标* 返回值:*      对应的经纬度*/public  Point2D.Double getCoordinate ( int  x,  int  y ) {return (new  Point2D.Double (center.x +  ( x - place.x )  / scale / scaleXY.x,center.y +  ( place.y - y )  / scale / scaleXY.y)) ;}/*** 功能:*      画经线、纬线* 参数:*      g       - 图形设备*      f       - 字体*      c       - 画线颜色*      inc_lon - 经线间隔*      inc_lat - 纬线间隔* 返回值:*      无*/public  void  drawGridLine ( Graphics2D g, Font f, Color c,  int  inc_lon,  int  inc_lat ) {DecimalFormat   df  =  new  DecimalFormat ( "0.#" ) ;Color   saveColor   = g.getColor () ;Font    saveFont    = g.getFont () ;g.setColor ( c ) ;g.setFont ( null ==f?f: new  Font ( "Times New Roman" , Font.PLAIN,  12 )) ;FontMetrics fm  = g.getFontMetrics () ;String      text;byte         tmpByte [] ;int          bytesWidth, bytesHeight = fm.getHeight () ;;Point       pos1, pos2;if (  inc_lon >  0  ) {for ( double  lon= 0.0 ;lon<= 360.0 ;lon=lon+inc_lon ) {if (  180.0  == lon  ) {for ( double  lat=- 90.0 ;lat<= 90.0 ;lat=lat+inc_lat ) {text        = df.format ( lat ) ;tmpByte     = text.getBytes () ;bytesWidth  = fm.bytesWidth ( tmpByte,  0 , tmpByte.length ) ;pos1    =  this .getPosition ( lon, lat ) ;g.drawString ( text, pos1.x-bytesWidth/ 2 , pos1.y+bytesHeight/ 3 ) ;}}pos1    =  this .getPosition ( lon, - 90.0 ) ;pos2    =  this .getPosition ( lon,   90.0 ) ;g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;}}if (  inc_lat >  0  ) {for ( double  lat=- 90.0 ;lat<= 90.0 ;lat=lat+inc_lat ) {if (  0.0  == lat  ) {for ( double  lon= 0.0 ;lon<= 360.0 ;lon=lon+inc_lon ) {text        = df.format ( lon ) ;tmpByte     = text.getBytes () ;bytesWidth  = fm.bytesWidth ( tmpByte,  0 , tmpByte.length ) ;pos1    =  this .getPosition ( lon, lat ) ;g.drawString ( text, pos1.x-bytesWidth/ 2 , pos1.y+bytesHeight/ 3 ) ;}}pos1    =  this .getPosition (   0.0 , lat ) ;pos2    =  this .getPosition ( 360.0 , lat ) ;g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;}}g.setFont ( saveFont ) ;g.setColor ( saveColor ) ;}
}
 package cma.common.isoline;public class TriangleVertex {//以从小到大的顺序存放A<B<Cpublic int A; //顶点A的在离散点序列中的索引public int B; //顶点B的在离散点序列中的索引public int C; //顶点C的在离散点序列中的索引/***功能:*重新设定*参数:*i,j,k-三顶点在离散点序列中的索引*返回值:*无*/public boolean reset ( int i, int j, int k ){if ( i< 0 ||j< 0 ||k< 0 || //顶点必须是正确的索引值i==j||j==k||k==i ){ //顶点不能相同A=- 1 ;B=- 1 ;C=- 1 ;return ( false ) ;}else {A=Math.min ( Math.min ( i,j ) ,k ) ;C=Math.max ( Math.max ( i,j ) ,k ) ;B=i!=A&&i!=C?i:j!=A&&j!=C?j:k; //k!=A&&k!=C?k:-1;/*if(B==-1){A=-1;C=-1;}*/return ( true ) ;}}/***功能:*构造函数*参数:*无*返回值:*无*/public TriangleVertex (){A=- 1 ;B=- 1 ;C=- 1 ;}/***功能:*构造函数*参数:*i,j,k-三顶点的索引*返回值:*无*/public TriangleVertex ( int i, int j, int k ){reset ( i,j,k ) ;}/***功能:*判断三角形是否等价于指定的三角形*备注:*两个均由(-1,-1,-1)构成的三角形是不相等的,因为不是一个有效的三角形*参数:*a,b-两个顶点的索引值*返回值:*true-存在*false-不存在*/public boolean equals ( int a, int b, int c ){return ( exists ( a,b,c )) ;}/***功能:*判断三角形是否有三个顶点与指定的参数相同,即两个三角形相等*参数:*a,b,c-三个顶点的索引值*返回值:*true-存在*false-不存在*/public boolean exists ( int a, int b, int c ){return (a!=b&&b!=c&&c!=a&&exists ( a ) &&exists ( b ) &&exists ( c )) ;}/***功能:*判断三角形是否有两个顶点与指定的参数相同*参数:*a,b-两个顶点的索引值*返回值:*true-存在*false-不存在*/public boolean exists ( int a, int b ){return ( a!=b&&exists ( a ) &&exists ( b )) ;}/***功能:*判断三角形是否存在指定的顶点*参数:*a-顶点的索引值*返回值:*true-存在*false-不存在*/public boolean exists ( int a ){return (a>= 0 && ( a==A||a==B||a==C )) ;}
}
package cma.common.isoline;import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.Vector;import javax.imageio.ImageIO;/*** @ClassName: Delaunary* @date: 2021年6月15日 下午4:36:23* * @Copyright: 2021 www.ankept.com Inc. All rights reserved.*/
public class Delaunay {// 由于研究不透其Triangulate方法,故按以下条件重写:
// 1、搜索满足外接圆包含新点的三角形序列;
// 2、在此序列中搜索非共有的边,即此三角形序列构成的边界;
// 3、判断新点与某三角形中作为边界的边是否可以建立新三角形,条件是:新点与该边对应的顶点同处该边界边的同侧。public Point2D.Double[] points; // 离散点序列// trianglecircleradius的长度一致public Vector triangle; // 三角形序列,存储TriangleVertex对象(各顶点在points中的索引)public Vector circle; // 三角形的外接圆圆心,存储Point2D.Double对象public Vector radius; // 三角形的外接圆半径,存储Double对象private int nt; // 三角形总数private int np; // 离散点总数/*** 功能: 构造函数 参数: pts-离散点序列,一般为经纬度值,长度必须>=3 返回值: 是否成功*/public Delaunay(Point2D.Double[] pts) {np = pts.length;points = new Point2D.Double[np + 3]; // 最后三个数据存放超大三角形的三个顶点for (int i = 0; i < np; i++) {points[i] = new Point2D.Double(pts[i].x, pts[i].y);}triangle = new Vector();circle = new Vector();radius = new Vector();nt = 0; //}/*** 功能: 构造一个SuperTriangle,使得所有离散点均落在该三角形内 参数: 无 返回值: 无*/private boolean createEdge() {double dmax, xmin, ymin, xmax, ymax, xmid, ymid;xmin = points[0].x;ymin = points[0].y;xmax = points[0].x;ymax = points[0].y;for (int i = 1; i < np; i++) {xmin = Math.min(xmin, points[i].x);ymin = Math.min(ymin, points[i].y);xmax = Math.max(xmax, points[i].x);ymax = Math.max(ymax, points[i].y);}xmin = Math.floor(xmin);xmax = Math.ceil(xmax);ymin = Math.floor(ymin);ymax = Math.ceil(ymax);// 源数据区域的中心xmid = (xmin + xmax) / 2.0;ymid = (ymin + ymax) / 2.0;// 经向和纬向最大距离的极值dmax,以中心为(xmid,ymid)、边长为dmax的正方形作为源数据的范围dmax = Math.max(xmax - xmin, ymax - ymin);dmax = Math.ceil(1.1 * dmax); // 增加0.1*dmax可确保离散点不在超大三角形的边上// 超大三角形的顶点points[np + 0] = new Point2D.Double(xmid - dmax, ymid - dmax / 2);points[np + 1] = new Point2D.Double(xmid, ymid + dmax / 2 + dmax);points[np + 2] = new Point2D.Double(xmid + dmax, ymid - dmax / 2);// 创建超大三角形boolean enabled = add(np + 0, np + 1, np + 2);return (enabled);}/*** 功能: 删除与SupperTriangle各顶点相关的三角形,包括SupperTriangle 参数: 无 返回值: 无*/private void deleteEdge() {int sA = np + 0;int sB = np + 1;int sC = np + 2;TriangleVertex tv;for (int i = nt - 1; i >= 0; i--) {tv = (TriangleVertex) triangle.get(i);if (tv.exists(sA) || tv.exists(sB) || tv.exists(sC)) { // 某个顶点与超大三角形相同this.delete(i);}}}/*** 功能:求三角形的外接圆圆心位置 参数: x1,y1-顶点A的位置 x2,y2-顶点B的位置 x3,y3-顶点C的位置 返回值: 外接圆的圆心位置 公式:* 根据“外接圆心到三顶点的距离均相等”推导得到* (1)r*r=(x-x1)*(x-x1)+(y-y1)*(y-y1)=x*x-2*x*x1+x1*x1+y*y-x*y*y1+y1*y1* (2)r*r=(x-x2)*(x-x2)+(y-y2)*(y-y2)=x*x-2*x*x2+x2*x2+y*y-x*y*y2+y2*y2* (3)r*r=(x-x3)*(x-x3)+(y-y3)*(y-y3)=x*x-2*x*x3+x3*x3+y*y-x*y*y3+y3*y3* 分别相减,略掉x*x和y*y* x=[(y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1)]/{2*(x3-x1)*(y2-y1)-2*((x2-x1)*(y3-y1)]}* y=[(x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1)]/{2*(y3-y1)*(x2-x1)-2*((y2-y1)*(x3-x1)]}*/public Point2D.Double circumcircle(double x1, double y1, double x2, double y2, double x3, double y3) {double x1x1 = x1 * x1;double x2x2 = x2 * x2;double x3x3 = x3 * x3;double y1y1 = y1 * y1;double y2y2 = y2 * y2;double y3y3 = y3 * y3;double x2_x1 = x2 - x1;double x3_x1 = x3 - x1;double y2_y1 = y2 - y1;double y3_y1 = y3 - y1;double x = ((y2_y1) * (y3y3 - y1y1 + x3x3 - x1x1) - (y3_y1) * (y2y2 - y1y1 + x2x2 - x1x1))/ (2 * (x3_x1) * (y2_y1) - 2 * (x2_x1) * (y3_y1));double y = ((x2_x1) * (x3x3 - x1x1 + y3y3 - y1y1) - (x3_x1) * (x2x2 - x1x1 + y2y2 - y1y1))/ (2 * (y3_y1) * (x2_x1) - 2 * (y2_y1) * (x3_x1));return (new Point2D.Double(x, y));}/*** 功能: 判断点相对于矢线a->b的位置 参数: x0,y0-要判断的点 x1,y1-线段端点a的位置 x2,y2-线段端点b的位置 返回值:* -1-在矢线a->b的左侧 0-在矢线a->b上(或延长线上) 1-在矢线a->b的右侧*/public int position(double x0, double y0, double x1, double y1, double x2, double y2) {double xab = (x0 - x1) * (y2 - y1) - (y0 - y1) * (x2 - x1);return (xab < 0.0 ? -1 : xab == 0.0 ? 0 : 1);}/*** 功能: 判断AB与CD是否相交 参数: xa,ya-线段AB的端点a的位置 xb,yb-线段AB的端点b的位置 xc,yc-线段CD的端点c的位置* xd,yd-线段CD的端点d的位置 返回值: true-相交 false-相交*/public boolean cross(double xa, double ya, double xb, double yb, double xc, double yc, double xd, double yd) {int a_cd = this.position(xa, ya, xc, yc, xd, yd);int b_cd = this.position(xb, yb, xc, yc, xd, yd);return (1 != a_cd * b_cd); // A与B在CD的同侧,则a_cd与b_cd同号,异侧则异号,某点在CD加上,则乘积为0}/*** 功能: 获得外接圆包含指定点的三角形序列中的索引值列表 参数: p-待检查的点 返回值: 序号列表*/private int[] contains(Point2D.Double p) {if (nt == 0) {return (null);}Vector lists = new Vector();Point2D.Double pc; // 三角形的外接圆圆心位置double r; // 三角形的外接圆半径double pr2;int[] res = new int[nt];int count = 0;Arrays.fill(res, -1);for (int i = 1; i < nt; i++) { // [0]是超大三角形,r = ((Double) radius.get(i)).doubleValue();pc = (Point2D.Double) circle.get(i);pr2 = (p.x - pc.x) * (p.x - pc.x) + (p.y - pc.y) * (p.y - pc.y);// 与外接圆圆心的距离不超过外接圆的半径if (pr2 <= r * r) {res[count++] = i;}}if (count == 0) {return (null);}int[] results = new int[count];for (int i = 0; i < count; i++) {results[i] = res[i];}return (results);}/*** 功能: 清空创建的三角形 参数: 无 返回值: 无*/public void clear() {triangle.clear();circle.clear();radius.clear();nt = 0;}/*** 功能: 删除指定的三角形 参数: index-三角形索引值 返回值: 无*/public void remove(int index) {if (index > 0 && index < nt) { // 不允许从类外删除SuperTriangledelete(index);}}/*** 功能: 删除指定的三角形 参数: index-三角形索引值 返回值: 无*/private void delete(int index) {if (index >= 0 && index < nt) {TriangleVertex tv = (TriangleVertex) triangle.get(index);// System.out.println("Delaunay.java#234:removeT"+String.valueOf(index)+"="+String.valueOf(tv.A)+","+String.valueOf(tv.B)+","+String.valueOf(tv.C));triangle.remove(index);circle.remove(index);radius.remove(index);nt--;}}/*** 功能: 删除指定的三角形 参数: index-三角形索引值 返回值: 无*/public void remove(int[] index) {if (null == index || index.length == 0) {return;}int[] idx = new int[index.length];for (int i = 0; i < index.length; i++) {idx[i] = index[i];}Arrays.sort(idx);for (int i = idx.length - 1; i >= 0; i--) {this.remove(idx[i]);}}/*** 注:此方法已废弃 功能: 根据index点与△abc的位置关系确定增加的三角形() 参数: index-新点的索引 abc-已知的三角形 返回值:* 能否成功创建*/public boolean add(int index, TriangleVertex abc) {// index点相对于△abc三边的位置int posAB = this.position(points[index].x, points[index].y, points[abc.A].x, points[abc.A].y, points[abc.B].x,points[abc.B].y);int posBC = this.position(points[index].x, points[index].y, points[abc.B].x, points[abc.B].y, points[abc.C].x,points[abc.C].y);int posCA = this.position(points[index].x, points[index].y, points[abc.C].x, points[abc.C].y, points[abc.A].x,points[abc.A].y);boolean inTriangle = // 全部在A->B->C->A的同一侧,说明在三角形内(posAB == -1 && posBC == -1 && posCA == -1) || (posAB == 1 && posBC == 1 && posCA == 1);boolean enabled = false;if (inTriangle) { // 在△abc内// System.out.println("Delaunay.java#295:P"+String.valueOf(index)+"inT("+String.valueOf(abc.A)+","+String.valueOf(abc.B)+","+String.valueOf(abc.C)+")");enabled = this.add(index, abc.A, abc.B) && this.add(index, abc.B, abc.C) && this.add(index, abc.C, abc.A);} else if (posBC == posCA) { // 在AB边上或AB边外// System.out.println("Delaunay.java#302:"+String.valueOf(nt)+"="+String.valueOf(index)+","+String.valueOf(abc.A)+","+String.valueOf(abc.B));enabled = this.add(index, abc.A, abc.B);} else if (posAB == posCA) { // 在BC边上或BC边外// System.out.println("Delaunay.java#306:"+String.valueOf(nt)+"="+String.valueOf(index)+","+String.valueOf(abc.B)+","+String.valueOf(abc.C));enabled = this.add(index, abc.B, abc.C);} else if (posAB == posBC) { // 在CA边上或CA边外// System.out.println("Delaunay.java#310:T"+String.valueOf(nt)+"="+String.valueOf(index)+","+String.valueOf(abc.C)+","+String.valueOf(abc.A));enabled = this.add(index, abc.C, abc.A);} else {// System.out.println("Delaunay.java#314:none");enabled = false;}return (enabled);}/*** 功能: 增加一个三角形,并计算其外接圆圆心和半径 参数: a,b,c-顶点的索引(必须保证是一个有效的三角形) 返回值: 能否成功创建*/public boolean add(int a, int b, int c) {boolean enabled = false;// 创建一个三角形TriangleVertex tv = new TriangleVertex();enabled = tv.reset(a, b, c);if (!enabled) {return (false);}int ntSave = nt; // 记录现有的项数try {triangle.add(tv);// 三角形的外接圆圆心Point2D.Double p = this.circumcircle(points[a].x, points[a].y, points[b].x, points[b].y, points[c].x,points[c].y);circle.add(p);// 三角形的外接圆半径Double d = new Double(Math.sqrt((points[a].x - p.x) * (points[a].x - p.x) + (points[a].y - p.y) * (points[a].y - p.y)));radius.add(d);// System.out.println("Delaunay.java#355:T"+String.valueOf(nt)+"="+String.valueOf(tv.A)+","+String.valueOf(tv.B)+","+String.valueOf(tv.C));nt++;return (true);} catch (Exception ex) { // 出错时删除已经增加的项for (int i = triangle.size() - 1; i > ntSave; i--) {triangle.remove(i);}for (int i = circle.size() - 1; i > ntSave; i--) {circle.remove(i);}for (int i = radius.size() - 1; i > ntSave; i--) {radius.remove(i);}nt = ntSave;System.out.println(ex.getMessage());ex.printStackTrace();return (false);}}/*** 功能: 增加一系列三角形,并计算外接圆圆心和半径 参数: index-离散点索引 lists-外接圆包含该离散点的三角形序列 返回值: 无*/public void add(int index, int[] lists) {if (null == lists) {return;}/** if(lists.length==1){ this.add(index,(TriangleVertex)triangle.get(lists[0]));* return; }*/ int[] idx = new int[lists.length];for (int i = 0; i < lists.length; i++) {idx[i] = lists[i];}Arrays.sort(idx);TriangleVertex[] tvs = new TriangleVertex[idx.length];boolean[][] existsSize = new boolean[3][idx.length]; // 判断是否为共有边Arrays.fill(existsSize[0], false); // AB边列表Arrays.fill(existsSize[1], false); // BC边列表Arrays.fill(existsSize[2], false); // CA边列表for (int i = 0; i < idx.length; i++) {tvs[i] = (TriangleVertex) triangle.get(idx[i]);}for (int i = 0; i < tvs.length; i++) { // 在三角形序列中查找非共有的边,即序列构成的区域的边界for (int j = 0; j < tvs.length; j++) {if (i != j) {existsSize[0][i] = existsSize[0][i] || tvs[j].exists(tvs[i].A, tvs[i].B); // 其它三角形是否也存在AB边existsSize[1][i] = existsSize[1][i] || tvs[j].exists(tvs[i].B, tvs[i].C); // 其它三角形是否也存在BC边existsSize[2][i] = existsSize[2][i] || tvs[j].exists(tvs[i].C, tvs[i].A); // 其它三角形是否也存在CA边}}}int pos1, pos2;for (int i = 0; i < tvs.length; i++) { // 非共有的边,与P(index)点构成新三角形if (!existsSize[0][i] && // 非共有的边!this.cross( // PC与AB不相交points[index].x, points[index].y, points[tvs[i].C].x, points[tvs[i].C].y,points[tvs[i].A].x, points[tvs[i].A].y, points[tvs[i].B].x, points[tvs[i].B].y)) {this.add(index, tvs[i].A, tvs[i].B); // 构成△PAB}if (!existsSize[1][i] && // 非共有的边!this.cross( // PA与BC不相交points[index].x, points[index].y, points[tvs[i].A].x, points[tvs[i].A].y,points[tvs[i].B].x, points[tvs[i].B].y, points[tvs[i].C].x, points[tvs[i].C].y)) {this.add(index, tvs[i].B, tvs[i].C); // 构成△PBC}if (!existsSize[2][i] && // 非共有的边!this.cross( // PB与CA不相交points[index].x, points[index].y, points[tvs[i].B].x, points[tvs[i].B].y,points[tvs[i].C].x, points[tvs[i].C].y, points[tvs[i].A].x, points[tvs[i].A].y)) {this.add(index, tvs[i].C, tvs[i].A); // 构成△PCA}}}/*** 功能: 建立三角形网格 参数: 无 返回值: 成功创建的三角形个数*/public int build() {// 清空已经存在的三角形网格this.clear();if (!createEdge() || // 创建超大三角形!this.add(0, np + 0, np + 1) || // 第一个离散点与超大三角形构成三个小三角形!this.add(0, np + 1, np + 2) || !this.add(0, np + 0, np + 2)) {return (0);}for (int i = 1; i < np; i++) { // 对所有离散点循环([0]已经使用)int[] lists = this.contains(points[i]); // 获得外接圆包含该点的三角形序列this.add(i, lists); // 添加三角形this.remove(lists);}deleteEdge();return (nt);}/*** 功能: 显示三角形网格 参数: g-图形设备 c-颜色 crd-坐标投影对象 返回值: 无*/public void draw(Graphics2D g, Color c, Coordinate crd) {Color saveColor = g.getColor();g.setColor(c);TriangleVertex tv;Point p1, p2, p3 /* ,p0 */ ;int r;for (int i = 0; i < nt; i++) {tv = (TriangleVertex) triangle.get(i);p1 = crd.getPosition(points[tv.A].x, points[tv.A].y);p2 = crd.getPosition(points[tv.B].x, points[tv.B].y);p3 = crd.getPosition(points[tv.C].x, points[tv.C].y);g.drawLine(p1.x, p1.y, p2.x, p2.y);g.drawLine(p2.x, p2.y, p3.x, p3.y);g.drawLine(p3.x, p3.y, p1.x, p1.y);}for (int i = 0; i < np; i++) {p1 = crd.getPosition(points[i].x, points[i].y);g.setColor(Color.red);g.fillRect(p1.x - 1, p1.y - 1, 3, 3);g.setColor(Color.blue);g.drawString(String.valueOf(i), p1.x, p1.y);}g.setColor(saveColor);}public static void main(String[] args) {int   points = 10;Point2D.Double[]  pts = new Point2D.Double[points];for(int i=0;i<points;i++) {pts[i] = new Point2D.Double(//在中国区域(70-140E, 10-60N)产生随机点70.0 + 69.0 * Math.random() + Math.random(),10.0 + 49.0 * Math.random() + Math.random());}Delaunay  delaunayT  = new Delaunay(pts);//创建Delaunay对象int     nTriangle  = delaunayT.build();//创建Delaunay网络Vector triangle2 = delaunayT.triangle;int       width  = 1600;int       height = 1024;BufferedImage  image  = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);Graphics2D   g    = image.createGraphics();g.setColor(new Color(192,240,255));//Micaps1.0的背景色g.fillRect(0, 0, width, height);//背景色填充Linear   coordinate = new Linear(110.0, 35.0,width/2, height/2, 15, 15);//线性投影//Diamond09.drawBorderline(g, Color.gray, coordinate, "/path/to/ProvinceMap.dat");//画省界、国界、洲界coordinate.drawGridLine(g, null, Color.green, 10, 10);//画经纬线delaunayT.draw(g, Color.blue, coordinate);//显示Delaunay网格File file = new File("D:/pic.jpg");try {ImageIO.write(image, "jpg", file);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

构造Delaunay三角形网格(代码整理)相关推荐

  1. 构造Delaunay三角形网格

    Delaunay是一种在离散点序列中快速构造三角形网格的方法,本代码依据的Delaunay三角形的性质:在已知的Dalaunay三角化的网格上加入一点P,只需要删除所有外接圆包含此点的三角形,并连接P ...

  2. 全排列及相关扩展算法(七)——组合数的字典序(另含全章代码整理)

    1.引入概念:要列出一个集合{1,2,3,4}的所有子集是很容易的,我们可以按照二进制数的顺序,0000,0001,0010,0011,0100,0101,0110,0111......来表示我们要取 ...

  3. 《统计学习导论》R语言代码整理

    <统计学习导论>R语言代码整理 一.特殊函数 二.基本函数 三.画图 一些函数 一些参数 type pch (plotting character) lty(line types) 特定问 ...

  4. html移动端隐藏代码,html Css PC 移动端 公用部分样式代码整理

    css常用公用部分样式代码整理: body, html, div, blockquote, img, label, p, h1, h2, h3, h4, h5, h6, pre, ul, ol, li ...

  5. php图文消息带代码详细注释,微信发送图文消息代码整理

    微信发送图文消息代码整理 这个就不多说什么了, 下单成功后微信提示图文消息.核心代码如下 if(!empty($openid)){ $wxinfo=curlgetcontents("http ...

  6. 常用代码整理(重要)

    常用代码整理: 1.判断邮箱格式是否正确的代码: //利用正则表达式验证 -(BOOL)isValidateEmail:(NSString *)email { NSString *emailRegex ...

  7. 策划文档html,html代码整理.doc

    Html代码整理 一.什么是 HTML? HTML 是用来描述网页的一种语言. HTML 指的是超文本标记语言 (Hyper Text Markup Language) HTML 不是一种编程语言,而 ...

  8. 2021年三大顶会时间序列论文代码整理

    作者:杰少,炼丹笔记嘉宾 2021年最新时间序列预测论文&代码整理 AAAI 2021 Deep Switching Auto-Regressive Factorization: Applic ...

  9. libsvm回归参数寻优cgp_【lightgbm/xgboost/nn代码整理二】xgboost做二分类,多分类以及回归任务...

    1.简介 该部分是代码整理的第二部分,为了方便一些初学者调试代码,作者已将该部分代码打包成一个工程文件,包含简单的数据处理.xgboost配置.五折交叉训练和模型特征重要性打印四个部分.数据处理部分参 ...

最新文章

  1. Winform开发的界面处理优化
  2. jota-time 练习
  3. 苹果应用ipa图片提取
  4. Effective C++ -----条款06:若不想使用编译器自动生成的函数,就该明确拒绝
  5. lopa分析_【风险分析方法】HAZOP、LOPA和FMEA三种分析方法,如何做到信息共享?...
  6. 官方wdpc安装文档,推荐RPM包安装
  7. CSS中position详解与常见应用实现
  8. iOS_9_scrollView分页
  9. 2020牛客NOIP赛前集训营-提高组(第三场)C-牛半仙的妹子Tree【虚树,最短路】
  10. Java Scanner next()方法与示例
  11. ASP.NET中Server.MapPath() 和Request.MapPath()使用
  12. docker 镜像命令
  13. php 开启memcache,php开启与安装 memcache
  14. python计算工资编程-老男孩学Python编程后薪资待遇高吗?
  15. sqoop和sqoop2区别
  16. gdal库读取tif影像坐标
  17. php 异步执行脚本,PHP语言实现脚本异步执行_PHP教程
  18. [转]Git详解之三 Git分支
  19. mysql导入时区_【MySQL】将时区信息导入MYSQL
  20. WiFi基础知识讲解

热门文章

  1. 三星s6 android 5.1.1,或开放特性 三星S6欲推安卓5.1.1
  2. android maxlength 汉字,Android TextView maxWidth、maxLines、maxLength、maxEms
  3. css实现带小三角形的边框
  4. 提取abaqus中节点集合的应力应变
  5. vue 获取视频第一帧
  6. GBase 8s典型安装
  7. 六顶思考帽(一)-----白色
  8. jcrop java_JAVA spring+jcrop.js实现简单的头像剪裁
  9. EXSI-NFS实验
  10. leetCode 978. Longest Turbulent Subarray