代码
package com.dam.heuristic.util.paint;
import com.dam.heuristic.ils.test.IlsApi;
import com.dam.heuristic.ts.test.TsApi;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.File;
import java.io.FileInputStream;
public class PaintTspResult extends Application {
//存储每个城市对应的x,y坐标
private double[][] cityPositionArr;
//存储城市序列
private int[] sequence;
//当前的时间轴
private Timeline nowTimeline;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
调用tsp求解算法
double[][] distanceMatrix = this.getDistanceMatrix();
TsApi TSApi = new TsApi(20, 100000, 100, distanceMatrix);
this.sequence = TSApi.solve();
画图
try {
BorderPane root = new BorderPane();
root.setStyle("-fx-padding: 20;");
Scene scene = new Scene(root, 1600, 900);
double canvasWid = 1500;
double canvasHei = 800;
//根据画布大小缩放坐标值
this.fixPosition(canvasWid - 50, canvasHei - 50);
//画布和画笔
HBox canvasHbox = new HBox();
Canvas canvas = new Canvas();
canvas.setWidth(canvasWid);
canvas.setHeight(canvasHei);
canvasHbox.setPrefWidth(canvasWid);
canvasHbox.getChildren().add(canvas);
canvasHbox.setAlignment(Pos.CENTER);
canvasHbox.setStyle("-fx-spacing: 20;" +
"-fx-background-color: #ecf1c3;");
root.setTop(canvasHbox);
GraphicsContext paintBrush = canvas.getGraphicsContext2D();
//启动
HBox hBox2 = new HBox();
Button beginButton = new Button("启动 Tsp 路线可视化");
hBox2.getChildren().add(beginButton);
root.setBottom(hBox2);
hBox2.setAlignment(Pos.CENTER);
//启动仿真以及暂停仿真
beginButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
nowTimeline.play();
});
//创建扫描线连接动画
nowTimeline = new Timeline();
createAnimation(paintBrush, 0.1);
drawAllCircle(paintBrush);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 修正cityPositionArr的坐标,让画出来的点在画布内
*
* @param width
* @param height
*/
private void fixPosition(double width, double height) {
double minX = Double.MAX_VALUE;
double maxX = -Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxY = -Double.MAX_VALUE;
for (int i = 0; i < this.cityPositionArr.length; i++) {
minX = Math.min(minX, this.cityPositionArr[i][0]);
maxX = Math.max(maxX, this.cityPositionArr[i][0]);
minY = Math.min(minY, this.cityPositionArr[i][1]);
maxY = Math.max(maxY, this.cityPositionArr[i][1]);
}
double multiple = Math.max((maxX - minX) / width, (maxY - minY) / height);
for (int i = 0; i < this.cityPositionArr.length; i++) {
this.cityPositionArr[i][0] = this.cityPositionArr[i][0] / multiple + 20;
this.cityPositionArr[i][1] = this.cityPositionArr[i][1] / multiple + 20;
}
}
/**
* 用画笔在画布上画出所有的孔
*/
private void drawAllCircle(GraphicsContext paintBrush) {
paintBrush.setStroke(Color.BLACK);
for (int i = 0; i < this.sequence.length; i++) {
drawCircle(paintBrush, this.sequence[i]);
}
}
/**
* 用画笔在画布上画出一个孔
*/
private void drawCircle(GraphicsContext paintBrush, int cityCode) {
double x = this.cityPositionArr[cityCode][0];
double y = this.cityPositionArr[cityCode][1];
double radius = 2;
// 圆的直径
double diameter = radius * 2;
paintBrush.strokeOval(x, y, diameter, diameter);
}
/**
* 将原始的线转化成一条可以画出来的线
*/
private void drawLine(GraphicsContext paintBrush, int index) {
int nextCityIndex = index + 1;
nextCityIndex = nextCityIndex >= this.sequence.length ? 0 : nextCityIndex;
// System.out.println(this.sequence[index]+">>"+this.sequence[nextCityIndex]);
double startX = this.cityPositionArr[this.sequence[index]][0];
double startY = this.cityPositionArr[this.sequence[index]][1];
double endX = this.cityPositionArr[this.sequence[nextCityIndex]][0];
double endY = this.cityPositionArr[this.sequence[nextCityIndex]][1];
paintBrush.setStroke(Color.RED);
paintBrush.strokeLine(startX, startY, endX, endY);
}
/**
* 创建动画
*/
private void createAnimation(GraphicsContext paintBrush, double speed) {
for (int i = 0; i < this.sequence.length; i++) {
int finalI = i;
KeyFrame keyFrame = new KeyFrame(Duration.seconds(finalI * speed), event -> drawLine(paintBrush, finalI));
nowTimeline.getKeyFrames().add(keyFrame);
}
}
/**
* 读取数据
*
* @return
* @throws Exception
*/
public double[][] getDistanceMatrix() throws Exception {
读取数据
String data = read(new File("src/main/java/com/data/tsp/att48.txt"), "GBK");
String[] cityDataArr = data.split("\n");
//初始化数组
//距离矩阵,可以直接获取任意两个编号城市的距离
double[][] distanceMatrix = new double[cityDataArr.length][cityDataArr.length];
this.cityPositionArr = new double[cityDataArr.length][2];
for (int i = 0; i < cityDataArr.length; i++) {
String[] city1Arr = cityDataArr[i].split(" ");
this.cityPositionArr[i][0] = Double.valueOf(city1Arr[1]);
this.cityPositionArr[i][1] = Double.valueOf(city1Arr[2]);
int cityOne = Integer.valueOf(city1Arr[0]);
for (int j = 0; j < i; j++) {
String[] city2Arr = cityDataArr[j].split(" ");
int cityTwo = Integer.valueOf(city2Arr[0]);
if (cityOne == cityTwo) {
distanceMatrix[cityOne - 1][cityTwo - 1] = 0;
} else {
distanceMatrix[cityOne - 1][cityTwo - 1] = getDistance(Double.valueOf(city1Arr[1]), Double.valueOf(city1Arr[2]), Double.valueOf(city2Arr[1]), Double.valueOf(city2Arr[2]));
//对称赋值
distanceMatrix[cityTwo - 1][cityOne - 1] = distanceMatrix[cityOne - 1][cityTwo - 1];
}
}
}
return distanceMatrix;
}
/**
* 给定两个城市坐标,获取两个城市的直线距离
*
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
private double getDistance(double x1, double y1, double x2, double y2) {
return Math.sqrt((Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) / 10);
}
private String read(File f, String charset) throws Exception {
FileInputStream fstream = new FileInputStream(f);
try {
int fileSize = (int) f.length();
if (fileSize > 1024 * 512) {
throw new Exception("File too large to read! size=" + fileSize);
}
byte[] buffer = new byte[fileSize];
fstream.read(buffer);
return new String(buffer, charset);
} finally {
try {
fstream.close();
} catch (Exception e) {
}
}
}
}
测试
因为csdn上传的图片的大小会被限制为5M,所以降了分辨率和帧率才能导出这个图,看起来有点卡 /(ㄒoㄒ)/~~