JavaFX多边形共享点

时间:2017-09-13 01:22:36

标签: javafx

我有一个班级" Vertex"包含双x,y。 另一课"面对"持有" Vertex"对象。相邻的面共享相同的顶点。

目前我正在为每个Face创建一个javafx.scene.shape.Polygon并将它们全部添加到我的场景中,如下所示: Screenshot

现在我计划修改多边形,类似于:JavaFX modify polygons

问题是多边形不会保存对我的Vertex对象的引用,但会加倍值。当我改变一个点的位置时,相邻多边形中的相同点仍处于旧位置。如何将这些点相互链接?以及如何将更改保存回我的" Face"对象

请求的代码示例:pastebin.com/C3JHb2nM

2 个答案:

答案 0 :(得分:0)

制作顶点属性的xy坐标。然后,您可以将侦听器添加到修改Polygon s:

的点的属性中
public class Vertex {

    public DoubleProperty xProperty() {
        ...
    }

    public DoubleProperty yProperty() {
        ...
    }

}
public class VertexListener implements InvalidationListerner {
    private final Vertex vertex;
    private final int firstIndex;
    private final List<Double> points;

    public VertexListener(Vertex vertex, Polygon polygon, int pointIndex) {
        this.firstIndex = 2 * pointIndex;
        this.vertex = vertex;
        this.points = polygon.getPoints();

        vertex.xProperty().addListener(this);
        vertex.yProperty().addListener(this);
    } 

    public void dispose() {
        vertex.xProperty().removeListener(this);
        vertex.yProperty().removeListener(this);
    }

    @Override
    public void invalidated(Observable observable) {
        double x = vertex.getX();
        double y = vertex.getY();
        points.set(firstIndex, x);
        points.set(firstIndex+1, y);
    }
}

这样您只需调整Vertex中的属性值,听众就会添加所有事件面......

答案 1 :(得分:0)

你走了。计算出的公共锚点位置然后在移动一个时调整所有常见的锚点位置。

Anchor包含addCommon函数,该函数添加了一个常见的锚点。 common变量存储所有常见锚点。然后,当调用handle时,所有常见的x and y位置也会发生变化。

另外,我建议您在Faces中保留共同点。我已经创建了一个简单的方法来计算在所述类中共享顶点的所有Faces。但是遵循MVC准则,您需要有一个模型,提供创建GUI所需的所有数据。我建议Mesh,Face和Vertex应该提供创建GUI的所有必要信息,而不是双向的。基本上,Anchor不应该以任何方式改变你的模型。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;

public class Main extends Application {

    public class Vertex {

        private double x, y;

        public Vertex(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public Double[] getPoint() {
            return new Double[]{x, y};
        }
    }

    public class Face {

        private List<Vertex> verts;

        public Face(Vertex... verts) {
            this.verts = new ArrayList<>(Arrays.asList(verts));
        }

        public Polygon getPolygon() {
            Polygon polygon = new Polygon();
            polygon.setFill(Color.GRAY);
            polygon.setStroke(Color.BLACK);

            for (Vertex vertex : verts) {
                polygon.getPoints().addAll(vertex.getPoint());
            }
            return polygon;
        }

        public boolean containsVertex(Vertex ver) {
            for (Vertex v : this.verts) {
                if (v.x == ver.x && v.y == ver.y) {
                    return true;
                }
            }
            return false;
        }
    }

    public class Mesh {

        private List<Vertex> verts = new ArrayList<Vertex>();
        private List<Face> faces = new ArrayList<Face>();
        private Map<Vertex, List<Face>> commonVertices = new HashMap<>();

        public List<Polygon> getPolygons() {
            List<Polygon> polygons = new ArrayList<Polygon>();

            for (Face face : faces) {
                polygons.add(face.getPolygon());
            }
            return polygons;
        }

        public Mesh() {
            verts.add(new Vertex(50, 50));
            verts.add(new Vertex(300, 50));
            verts.add(new Vertex(500, 50));
            verts.add(new Vertex(50, 300));
            verts.add(new Vertex(250, 300));
            verts.add(new Vertex(500, 300));
            verts.add(new Vertex(50, 600));
            verts.add(new Vertex(300, 700));
            verts.add(new Vertex(500, 700));

            faces.add(new Face(verts.get(0), verts.get(1), verts.get(4), verts.get(3)));
            faces.add(new Face(verts.get(4), verts.get(1), verts.get(2), verts.get(5)));
            faces.add(new Face(verts.get(3), verts.get(4), verts.get(7), verts.get(6)));
            faces.add(new Face(verts.get(7), verts.get(4), verts.get(5)));
            faces.add(new Face(verts.get(7), verts.get(5), verts.get(8)));

            findCommonVertices();
        }

        private void findCommonVertices() {
            for (Vertex ver : this.verts) {
                List<Face> share = new ArrayList<>();
                for (Face face : this.faces) {
                    if (face.containsVertex(ver)) {
                        share.add(face);
                    }
                }
                commonVertices.put(ver, share);
            }
        }

        public Map<Vertex, List<Face>> getCommonVertices() {
            return this.commonVertices;
        }

    }

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 1024, 768);
        stage.setScene(scene);

        Group g = new Group();
        Mesh mesh = new Mesh();
        List<Polygon> polygons = mesh.getPolygons();

        g.getChildren().addAll(polygons);

        List<Anchor> anchors = new ArrayList<>();
        for (Polygon p : polygons) {
            ObservableList<Anchor> temp = createControlAnchorsFor(p.getPoints());
            g.getChildren().addAll(temp);
            for (Anchor kk : temp) {
                anchors.add(kk);
            }
        }

        for (int i = 0; i < anchors.size(); i++) {
            List<Anchor> common = new ArrayList<>();
            for (int j = 0; j < anchors.size(); j++) {
                if (i != j) {
                    if (anchors.get(i).x.doubleValue() == anchors.get(j).x.doubleValue() && anchors.get(i).y.doubleValue() == anchors.get(j).y.doubleValue()) {
                        anchors.get(i).addCommon(anchors.get(j));
                        System.out.println("COMMON " + i + "  " + j);
                    }
                }
            }
           // anchors.get(i).setCommon(common);
        }

        scene.setRoot(g);
        stage.show();
    }

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

    // Everything below was copied from here: https://gist.github.com/jewelsea/5375786
    // @return a list of anchors which can be dragged around to modify points in the format [x1, y1, x2, y2...]
    private ObservableList<Anchor> createControlAnchorsFor(final ObservableList<Double> points) {
        ObservableList<Anchor> anchors = FXCollections.observableArrayList();

        for (int i = 0; i < points.size(); i += 2) {
            final int idx = i;

            DoubleProperty xProperty = new SimpleDoubleProperty(points.get(i));
            DoubleProperty yProperty = new SimpleDoubleProperty(points.get(i + 1));

            xProperty.addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> ov, Number oldX, Number x) {
                    points.set(idx, (double) x);
                }
            });

            yProperty.addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> ov, Number oldY, Number y) {
                    points.set(idx + 1, (double) y);
                }
            });

            anchors.add(new Anchor(Color.GOLD, xProperty, yProperty));
        }

        return anchors;
    }

    // a draggable anchor displayed around a point.
    class Anchor extends Circle {

        private final DoubleProperty x, y;
        List<Anchor> common = new ArrayList<>();

        public void setCommon(List<Anchor> common) {
            this.common = common;
        }

        public void addCommon(Anchor com) {
            common.add(com);
            enableDrag();
        }

        Anchor(Color color, DoubleProperty x, DoubleProperty y) {
            super(x.get(), y.get(), 10);
            setFill(color.deriveColor(1, 1, 1, 0.5));
            setStroke(color);
            setStrokeWidth(2);
            setStrokeType(StrokeType.OUTSIDE);

            this.x = x;
            this.y = y;

            x.bind(centerXProperty());
            y.bind(centerYProperty());
               enableDrag();
        }

        // make a node movable by dragging it around with the mouse.
        private void enableDrag() {
            final Delta dragDelta = new Delta();
            setOnMousePressed(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    // record a delta distance for the drag and drop operation.
                    dragDelta.x = getCenterX() - mouseEvent.getX();
                    dragDelta.y = getCenterY() - mouseEvent.getY();
                    getScene().setCursor(Cursor.MOVE);
                }
            });
            setOnMouseReleased(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    getScene().setCursor(Cursor.HAND);
                }
            });
            setOnMouseDragged(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    double newX = mouseEvent.getX() + dragDelta.x;
                    if (newX > 0 && newX < getScene().getWidth()) {
                        setCenterX(newX);
                        if (common != null) {
                            for (Anchor an : common) {
                                an.setCenterX(newX);
                                System.out.println("CALLED");
                            }
                        }
                    }
                    double newY = mouseEvent.getY() + dragDelta.y;
                    if (newY > 0 && newY < getScene().getHeight()) {
                        setCenterY(newY);
                        if (common != null) {
                            for (Anchor an : common) {
                                an.setCenterY(newY);
                            }
                        }
                    }
                }
            });
            setOnMouseEntered(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    if (!mouseEvent.isPrimaryButtonDown()) {
                        getScene().setCursor(Cursor.HAND);
                    }
                }
            });
            setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent mouseEvent) {
                    if (!mouseEvent.isPrimaryButtonDown()) {
                        getScene().setCursor(Cursor.DEFAULT);
                    }
                }
            });
        }

        // records relative x and y co-ordinates.
        private class Delta {

            double x, y;
        }
    }
}