构造Delaunay三角形网格(代码整理)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                构造Delaunay三角形网格(代码整理)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                原文鏈接
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三角形网格(代码整理)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: bzoj - 1002 【Kirchho
- 下一篇: 第02讲:Hadoop 发行版选型和伪分
