JavaFX 圈选 仿百度地图路线

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haoranhaoshi/article/details/85335430

在这里插入图片描述
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class PolygonTest2 extends Application {
// 最近一次存储的箭尾
Point2D arrowTailPoint;
// 最近的箭是否已绘制
boolean isHasLastArrow;
// 上一个居中折线的点
Point2D lastPolylinePoint2D;
// 居中折线的起点
Point2D startPolylinePoint2D;

public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) {
    Polygon polygon = new Polygon();
    polygon.setStroke(Color.GREEN);
    polygon.setStrokeWidth(8);
    polygon.setFill(null);

    Polyline polyline = new Polyline();
    polyline.setStrokeWidth(2);
    polyline.setStroke(Color.YELLOW);
    DropShadow polylineDropShadow = new DropShadow();
    polylineDropShadow.setRadius(5);
    polyline.setEffect(polylineDropShadow);

    Pane pane = new Pane();
    pane.setPrefWidth(1000);
    pane.setMaxHeight(500);

    // 箭尾间隔
    double arrowInternal = 100;
    // 箭身长度
    double arrowLength = 10;
    // 界线和居中折线间的距离
    double polylineDistance = polygon.getStrokeWidth() / 2;
    // 箭身中点垂足到箭头一侧终点的距离,是箭头斜度的关键参数
    double arrowHeadAngleKeyValue = polylineDistance - 2;

    // 一侧折线(在顺时针时表现为外侧,在逆时针时表现为内侧)
    Polyline firstSidePolyline = new Polyline();
    firstSidePolyline.setStroke(Color.BLACK);
    firstSidePolyline.setStrokeWidth(1);
    // 另一侧折线(在顺时针时表现为内侧,在逆时针时表现为外侧)
    Polyline secondSidePolyline = new Polyline();
    secondSidePolyline.setStroke(Color.BLACK);
    secondSidePolyline.setStrokeWidth(1);

    List<Polyline> arrowHeadPolylineList = new ArrayList<>();
    List<Polyline> arrowBodyPolylineList = new ArrayList<>();

    Label label1 = new Label("测试标签1");
    label1.setTranslateX(50);
    label1.setTranslateY(50);
    Label label2 = new Label("测试标签2");
    label2.setTranslateX(100);
    label2.setTranslateY(100);
    Label label3 = new Label("测试标签3");
    label3.setTranslateX(150);
    label3.setTranslateY(150);
    // 加入测试标签
    pane.getChildren().addAll(label1,label2,label3);

    pane.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            if (event.getButton().equals(MouseButton.PRIMARY)) {
                // 清空
                pane.getChildren().clear();
                arrowHeadPolylineList.clear();
                arrowBodyPolylineList.clear();

                polygon.getPoints().clear();
                firstSidePolyline.getPoints().clear();
                secondSidePolyline.getPoints().clear();
                polyline.getPoints().clear();

                // 加入测试标签
                pane.getChildren().addAll(label1,label2,label3);

                // 加入折线
                pane.getChildren().add(polyline);
                polyline.getPoints().add(event.getX());
                polyline.getPoints().add(event.getY());

                polygon.getPoints().add(event.getX());
                polygon.getPoints().add(event.getY());
                arrowTailPoint = new Point2D(event.getX(), event.getY());
                lastPolylinePoint2D = new Point2D(event.getX(), event.getY());
                startPolylinePoint2D = new Point2D(event.getX(), event.getY());
                isHasLastArrow = false;
            }
        }
    });

    pane.addEventHandler(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            if (event.getButton().equals(MouseButton.PRIMARY)) {
                polygon.getPoints().add(event.getX());
                polygon.getPoints().add(event.getY());
                polyline.getPoints().add(event.getX());
                polyline.getPoints().add(event.getY());
                // 绘制两侧界线(平移居中线)
                // 上一个点
                double lastPolylinePointX = lastPolylinePoint2D.getX();
                double lastPolylinePointY = lastPolylinePoint2D.getY();
                // 当前点
                double currentPlylinePointX = event.getX();
                double currentPlylinePointY = event.getY();
                // 当前点和上一个点的横纵坐标差
                double polylinePointDeleteX = currentPlylinePointX - lastPolylinePointX;
                double polylinePointDeleteY = currentPlylinePointY - lastPolylinePointY;
                // 折线垂直线斜率
                double polylineVerticalArc = Math.PI / 2 - (Math.atan(Math.abs(polylinePointDeleteY / polylinePointDeleteX)));
                // 内外折线和居中折线的横向和纵向距离
                double polylineInternalX = polylineDistance * Math.cos(polylineVerticalArc);
                double polylineInternalY = polylineDistance * Math.sin(polylineVerticalArc);
                // 折线加点
                firstSidePolyline.getPoints().addAll(new Double[]{currentPlylinePointX + ((currentPlylinePointY >= lastPolylinePointY) ? -1 : 1) * polylineInternalX, currentPlylinePointY + ((currentPlylinePointX <= lastPolylinePointX) ? -1 : 1) * polylineInternalY});
                secondSidePolyline.getPoints().addAll(new Double[]{currentPlylinePointX + ((currentPlylinePointY >= lastPolylinePointY) ? 1 : -1) * polylineInternalX, currentPlylinePointY + ((currentPlylinePointX <= lastPolylinePointX) ? 1 : -1) * polylineInternalY});
                // 存储当前点
                lastPolylinePoint2D = new Point2D(currentPlylinePointX, currentPlylinePointY);

                // 绘制箭(根据箭尾和箭头垂直线得到箭头两侧终点)
                if (!isHasLastArrow && arrowTailPoint.distance(new Point2D(event.getX(), event.getY())) >= arrowLength) {
                    // 箭尾坐标
                    double arrowTailX = arrowTailPoint.getX();
                    double arrowTailY = arrowTailPoint.getY();
                    // 初始箭头坐标
                    double arrowHeadX = event.getX();
                    double arrowHeadY = event.getY();
                    // 实际箭身长
                    double arrowRealLength = new Point2D(arrowHeadX, arrowHeadY).distance(new Point2D(arrowTailX, arrowTailY));
                    // 最终箭头坐标
                    arrowHeadX = arrowTailX + (arrowLength / arrowRealLength) * (arrowHeadX - arrowTailX);
                    arrowHeadY = arrowTailY + (arrowLength / arrowRealLength) * (arrowHeadY - arrowTailY);
                    // 箭身中点坐标
                    double arrowMiddleX = (arrowTailX + arrowHeadX) / 2;
                    double arrowMiddleY = (arrowTailY + arrowHeadY) / 2;
                    // 箭头和尾的横纵坐标差
                    double arrowHTDeleteX = arrowHeadX - arrowTailX;
                    double arrowHTDeleteY = arrowHeadY - arrowTailY;
                    // 箭身垂直线斜率对应的弧度
                    double arrowVerticalArc = Math.PI / 2 - (Math.atan(Math.abs(arrowHTDeleteY / arrowHTDeleteX)));
                    // 箭头两侧终点与箭身中点的横向和纵向距离
                    double arrowHSMInternalX = arrowHeadAngleKeyValue * Math.cos(arrowVerticalArc);
                    double arrowHSMInternalY = arrowHeadAngleKeyValue * Math.sin(arrowVerticalArc);
                    //System.out.println(arrowHSMInternalX + "--箭头两侧终点与箭身中点的横向和纵向距离--" + arrowHSMInternalY);
                    // 箭头两侧终点
                    double arrowHeadSideX1;
                    double arrowHeadSideX2;
                    double arrowHeadSideY1;
                    double arrowHeadSideY2;
                    if (arrowHTDeleteX * arrowHTDeleteY <= 0) {
                        // 箭身呈矩阵副对角线方向
                        arrowHeadSideX1 = arrowMiddleX + arrowHSMInternalX;
                        arrowHeadSideY1 = arrowMiddleY + arrowHSMInternalY;
                        arrowHeadSideX2 = arrowMiddleX - arrowHSMInternalX;
                        arrowHeadSideY2 = arrowMiddleY - arrowHSMInternalY;
                    } else {
                        // 箭身呈矩阵主对角线方向
                        arrowHeadSideX1 = arrowMiddleX + arrowHSMInternalX;
                        arrowHeadSideY1 = arrowMiddleY - arrowHSMInternalY;
                        arrowHeadSideX2 = arrowMiddleX - arrowHSMInternalX;
                        arrowHeadSideY2 = arrowMiddleY + arrowHSMInternalY;
                    }

                    //System.out.println(arrowHeadSideX1 + "_" + arrowHeadSideY1 + "--箭头两侧终点--" + arrowHeadSideX2 + "_" + arrowHeadSideY2);
                    // 绘制箭头
                    Polyline arrowHeadPolyline = new Polyline();
                    arrowHeadPolyline.setStroke(Color.WHITE);
                    arrowHeadPolyline.setStrokeWidth(2);
                    arrowHeadPolyline.getPoints().add(arrowHeadSideX1);
                    arrowHeadPolyline.getPoints().add(arrowHeadSideY1);
                    arrowHeadPolyline.getPoints().add(arrowHeadX);
                    arrowHeadPolyline.getPoints().add(arrowHeadY);
                    arrowHeadPolyline.getPoints().add(arrowHeadSideX2);
                    arrowHeadPolyline.getPoints().add(arrowHeadSideY2);
                    // 加入箭头
                    arrowHeadPolylineList.add(arrowHeadPolyline);
                    // 绘制箭身
                    /*Polyline arrowBodyPolyline = new Polyline();
                    arrowBodyPolyline.setStroke(Color.WHITE);
                    arrowBodyPolyline.setStrokeWidth(2);
                    arrowBodyPolyline.getPoints().add(arrowTailX);
                    arrowBodyPolyline.getPoints().add(arrowTailY);
                    arrowBodyPolyline.getPoints().add(arrowHeadX);
                    arrowBodyPolyline.getPoints().add(arrowHeadY);
                    // 加入箭身
                    arrowBodyPolylineList.add(arrowBodyPolyline);*/

                    isHasLastArrow = true;
                }

                // 存储下一个箭尾
                if (arrowTailPoint.distance(new Point2D(event.getX(), event.getY())) >= arrowInternal) {
                    arrowTailPoint = new Point2D(event.getX(), event.getY());
                    isHasLastArrow = false;
                }
            }
        }
    });

    pane.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            // 清空
            pane.getChildren().clear();
            // 加入测试标签
            pane.getChildren().addAll(label1,label2,label3);
            // 加入居中折线对应的多边形、两侧界线
            pane.getChildren().addAll(polygon, firstSidePolyline, secondSidePolyline);
            // 加入箭头
            for(Polyline polyline : arrowHeadPolylineList){
                pane.getChildren().add(polyline);
            }

            // 加入箭身
            for(Polyline polyline : arrowBodyPolylineList){
                pane.getChildren().add(polyline);
            }
            // 绘制两侧界线
            // 当前点
            double currentPlylinePointX = event.getX();
            double currentPlylinePointY = event.getY();
            // 终点
            double endPolylinePointX = startPolylinePoint2D.getX();
            double endPolylinePointY = startPolylinePoint2D.getY();
            // 当前点和上一个点的横纵坐标差
            double polylinePointDeleteX = currentPlylinePointX - endPolylinePointX;
            double polylinePointDeleteY = currentPlylinePointY - endPolylinePointY;
            // 折线垂直线斜率
            double polylineVerticalArc = Math.PI / 2 - (Math.atan(Math.abs(polylinePointDeleteY / polylinePointDeleteX)));
            // 内外折线和居中折线的横向和纵向距离
            double polylineInternalX = polylineDistance * Math.cos(polylineVerticalArc);
            double polylineInternalY = polylineDistance * Math.sin(polylineVerticalArc);
            // 折线加点
            firstSidePolyline.getPoints().addAll(new Double[]{endPolylinePointX + ((endPolylinePointY >= currentPlylinePointY) ? -1 : 1) * polylineInternalX, endPolylinePointY + ((endPolylinePointX <= currentPlylinePointX) ? -1 : 1) * polylineInternalY});
            secondSidePolyline.getPoints().addAll(new Double[]{endPolylinePointX + ((endPolylinePointY >= currentPlylinePointY) ? 1 : -1) * polylineInternalX, endPolylinePointY + ((endPolylinePointX <= currentPlylinePointX) ? 1 : -1) * polylineInternalY});

            Polygon polygonTemp = new Polygon();
            polygonTemp.getPoints().addAll(polygon.getPoints());
            List<Label> labelList = new ArrayList<>();
            labelList.add(label1);
            labelList.add(label2);
            labelList.add(label3);
            // 被选中的图形对象
            List<Label> selectedElmentList = new ArrayList<>();
            for(Label label : labelList){
                if (isIntersectWithPolygon(polygonTemp, label)) {
                    selectedElmentList.add(label);
                }
            }

            String alertInfo;
            if(selectedElmentList.size() == 0){
                alertInfo = "你未圈选任何测试标签!";
            }else{
                alertInfo = "你圈选了";
            }

            for(int i = 0;i < selectedElmentList.size();i++){
                Label label = selectedElmentList.get(i);
                alertInfo += label.getText() + (i < selectedElmentList.size() - 1 ? "、" : "。");
            }

            Alert alert = new Alert(Alert.AlertType.INFORMATION, alertInfo, ButtonType.FINISH);
            alert.show();
        }
    });

    primaryStage.setScene(new Scene(pane, 1000, 500));
    primaryStage.show();
}

private boolean isIntersectWithPolygon(Polygon polygon, Label label) {
    try {
        if (polygon != null && label != null) {
            Node displayNode = label;
            List<Shape> shapeList = getShapeListFromNode(displayNode);

            for (Shape shape : shapeList) {
                // 圈选的图形特别复杂时,会产生效率问题
                Shape intersectShape = Shape.intersect(polygon, shape);
                if (intersectShape.getBoundsInLocal().getWidth() != -1) {
                    return true;
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

private static List<Shape> getShapeListFromNode(Node node) {
    List<Shape> shapeList = new ArrayList<Shape>();
    if (node instanceof Parent) {
        Parent parent = (Parent) node;
        ObservableList<Node> subNodeList = parent.getChildrenUnmodifiable();
        for (Node subNode : subNodeList) {
            List<Shape> subNodeShapeList = getShapeListFromNode(subNode);
            shapeList.addAll(subNodeShapeList);
        }
    } else if (node instanceof Shape) {
        shapeList.add((Shape) node);
    }
    return shapeList;
}

}

猜你喜欢

转载自blog.csdn.net/haoranhaoshi/article/details/85335430