JavaFx анимация пути с помощью формы - PullRequest
0 голосов
/ 20 ноября 2018

Я работаю над проектом с функцией анимации пути с помощью линии.Поэтому, когда я нажимаю кнопку, линия проходит через все круги на холсте.Но я вижу, что есть небольшая разница в моем пути и линии хода.Это не проходит через круги.Пожалуйста, добрый совет, спасибо.Это мой код:

import java.util.ArrayList;
import java.util.Random;

import javafx.animation.Animation;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PathVisualization extends Application {

private static double SCENE_WIDTH = 1000;
private static double SCENE_HEIGHT = 500;

private Canvas canvas;
private GraphicsContext gc;
private Button clear; 
private Animation animation;
private ArrayList<Circle> num;

 @Override
public void start(Stage primaryStage) throws Exception {

    BorderPane bp = new BorderPane();
    Pane root = new Pane();
    root.setMaxSize(800,500);
   // path = new Path();
    canvas = new Canvas(SCENE_WIDTH,SCENE_HEIGHT);

    TextField no = new TextField();
    Button add = new Button("Add Circle");
    Button playAnimation = new Button("Play");
    clear = new Button("Clear");
    Button pause = new Button("Pause");

    VBox control = new VBox();
    control.getChildren().add(no);
    control.getChildren().add(add);
    control.getChildren().add(playAnimation);
    control.getChildren().add(clear);
    control.getChildren().add(pause);


    root.getChildren().add(canvas);
    bp.setCenter(root);
    bp.setLeft(control);

    num = new ArrayList<Circle>();

    clear.setOnMouseClicked(event->{
        num.clear();
        gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
        root.getChildren().clear();
        root.getChildren().add(canvas);
    });

    add.setOnMouseClicked(event->{
        int cirNum = Integer.parseInt(no.getText());
        Random rand = new Random();
        for (int j=0;j<cirNum;j++) {
            int x = rand.nextInt((int)root.getMaxWidth()-1);
            int y = rand.nextInt((int)root.getMaxHeight()-1);
            Circle circle = new Circle(x,y,10);
            num.add(circle);
            root.getChildren().add(circle);
        }

        //Heuristic Change
        Path path = new Path();
        path.setStroke(Color.RED);
        path.getElements().add(new MoveTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
        path.setStrokeWidth(1);

        for (int i=0;i<num.size();i++) {
            try {
                path.getElements().addAll(new LineTo(num.get(i).getCenterX(),num.get(i).getCenterY()));
            }catch(IndexOutOfBoundsException e) {
                path.getElements().addAll(new LineTo(num.get(0).getCenterX(),num.get(0).getCenterY()));
            }
        }


        root.getChildren().addAll(path);

        //create animation
        animation = createPathAnimation(path, Duration.seconds(num.size()/4));

    });

     playAnimation.setOnMouseClicked(e ->{
          animation.play();
    });

     pause.setOnMouseClicked(e->{
         animation.pause();
     });


    primaryStage.setScene(new Scene(bp, SCENE_WIDTH, SCENE_HEIGHT));
    primaryStage.show();

}



private Animation createPathAnimation(Path path, Duration duration) {

    gc = canvas.getGraphicsContext2D();

    // move a node along a path. we want its position
    Circle pen = new Circle(0,0,0);
    // create path transition
    PathTransition pathTransition = new PathTransition(duration, path, pen);
    pathTransition.currentTimeProperty().addListener( new ChangeListener<Duration>() {

      Location oldLocation = null;

        /**
         * Draw a line from the old location to the new location
         */
        @Override
        public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {

            // skip starting at 0/0
            if( oldValue == Duration.ZERO)
                return;

            // get current location

            double x = pen.getTranslateX();
            double y = pen.getTranslateY();



         // initialize the location
            if( oldLocation == null) {
                oldLocation = new Location();
                oldLocation.x = x;
                oldLocation.y = y;
                return;
            }

            // draw line
            gc.setStroke(Color.GREENYELLOW);

            gc.setLineWidth(5);

            gc.strokeLine(oldLocation.x, oldLocation.y, x, y);


            // update old location with current one
            oldLocation.x = x;
            oldLocation.y = y;

        }
    });

    pathTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);  
    return pathTransition;
}

public static class Location {
    double x;
    double y;
}

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

Это проблема.В определенных углах штриховая линия не проходит через круг и делает странный разрез.

введите описание изображения здесь

1 Ответ

0 голосов
/ 21 ноября 2018

Изначально я не смог воспроизвести его, но после нескольких попыток мне удалось воспроизвести его.Похоже, это связано с задержкой.

Насколько я знаю (я не специалист по анимации), анимации (включая PathTransition) используют таймер внутри, и каждый тик обычно эквивалентенДлительность импульса графа сцены JavaFX.Это означает, что анимация обновляется максимум 60 раз в секундуКогда происходит импульс, PathTransition вычисляет новые значения перевода на основе прошедшего времени на таймере.Итак, что здесь происходит, так это то, что вычисленные значения перевода довольно далеко друг от друга между двумя конкретными импульсами.В общем, чем больше вещей вы пытаетесь сделать в потоке приложений JavaFX, тем больше вероятность того, что это произойдет.

Если вы пытаетесь нарисовать линию трассировки на основе анимации, вы не сможете избежать этого.это время ожидания.Тем не менее, вы можете избежать проблемы прорисовки контуров, разбив их на несколько анимаций.Каждая анимация будет двигаться по прямой линии, и каждая из ваших линий трассировки гарантированно будет начинаться с начала и до конца в конечной точке.

Я пробовал это, и это работает:

// Heuristic Change
// Path path = new Path();
// path.setStroke(Color.RED);
// path.getElements().add(new MoveTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// path.setStrokeWidth(1);

// for (int i = 0; i < num.size(); i++) {
// try {
// path.getElements().addAll(new LineTo(num.get(i).getCenterX(), num.get(i).getCenterY()));
// }
// catch (IndexOutOfBoundsException e) {
// path.getElements().addAll(new LineTo(num.get(0).getCenterX(), num.get(0).getCenterY()));
// }
// }

List<Path> paths = new ArrayList<>();

for (int i = 0; i < num.size() - 1; i++) {
    Circle current = num.get(i);
    Circle next = num.get(i + 1);

    Path path = new Path();
    path.setStroke(Color.RED);
    path.getElements().addAll(new MoveTo(current.getCenterX(), current.getCenterY()),
            new LineTo(next.getCenterX(), next.getCenterY()));
    path.setStrokeWidth(1);

    paths.add(path);
}

// root.getChildren().addAll(path);

root.getChildren().addAll(paths);

Circle pen = new Circle();

// create animation
// animation = createPathAnimation(path, Duration.seconds(num.size()/4));
animation = createPathAnimation(paths, Duration.millis(200), pen);

И ...

private Animation createPathAnimation(List<Path> paths, Duration duration, Circle pen) {
    SequentialTransition seq = new SequentialTransition();

    // ...

    for (Path path : paths) {
        // The same PathTransition stuff you had

        seq.getChildren().add(pathTransition);
    }

    return seq;
}

Единственное, что изменилось, это то, что скорость изменяется на каждом отрезке полного пути.Если вы хотите сохранить эту константу, вы должны применить теорему Пифагора, чтобы найти расстояние, и соответствующим образом скорректировать продолжительность.

...