2016-03-18 4 views
0

Я рисую Path в JavaFX, и я хотел бы обратить путь (lineTo и arcTo) этого типа: picture only for illustrationГладкий путь в JavaFX

Есть ли простой способ, как соединить дуги с линиями (и другие дуги), чтобы получить такой гладкий путь?

Я не знаю периметра дуги, я знаю только начальную точку и конечную точку. На картинке только половина кругов, мне нужно также рисовать другие типы arcTo.

Единственная идея, что я до сих пор получал направление конца пути, а затем подсчитывал и соединял другой arcTo/lineTo в этом направлении. Однако я не нашел никакого способа сделать это.

+0

Для заданной длины, как часто должны быть дуги?Кроме того, проясните эти «другие типы' arcTo' » – RAnders00

+0

Я ищу плавное решение для соединения дуг с линиями не только для одного случая (изображение было только для иллюстрации проблемы), поэтому я не может указать, как часто должны быть дуги. Под другим типом arcTo я имею в виду дуги с центральным углом, отличным от 180 ° –

+0

Итак, у вас есть данный массив/список дуг, которые вы хотите подключить? – RAnders00

ответ

2

Cubic Bezier Curve определяется четырьмя точками, start, end, и два «контрольных точек» control1 и control2. Он обладает свойством, что

  • она начинается и заканчивается в start и end
  • изначально (т.е. при start) по касательной к сегменту линии между start и control1
  • на end по касательной к линии отрезок между control2 и end

форма кривой также определяется размерами т он от start до control1 и control2 до end: грубо говоря, они управляют «скоростью», с которой линия приближается к контрольным точкам, прежде чем поворачиваться к конечным точкам.

Таким образом, чтобы присоединиться к двум линейным сегментам с гладкой кривой, вы можете использовать кубическую кривую, начало которой является концом первого отрезка линии и конец которого является началом второго сегмента линии. Вычислите контрольные точки, просто расширив каждую линию за ее пределами (первая строка) или запустите (вторая строка). Использование такой же длины для расширений даст сбалансированный вид.

Вот пример. Запустите этот код: перетащите указатель мыши по панели, чтобы нарисовать одну строку, затем снова нарисуйте вторую строку, и две линии будут соединены кубической кривой.

import javafx.application.Application; 
import javafx.geometry.Point2D; 
import javafx.scene.Scene; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.CubicCurve; 
import javafx.scene.shape.Line; 
import javafx.stage.Stage; 

public class JoinLineSegmentsWithCubic extends Application { 

    private Line unconnectedLine = null ; 
    private Line currentDraggingLine = null ; 

    @Override 
    public void start(Stage primaryStage) { 
     Pane pane = new Pane(); 
     pane.setOnDragDetected(e -> { 
      currentDraggingLine = new Line(e.getX(), e.getY(), e.getX(), e.getY()); 
      pane.getChildren().add(currentDraggingLine); 
     }); 
     pane.setOnMouseDragged(e -> { 
      if (currentDraggingLine != null) { 
       currentDraggingLine.setEndX(e.getX()); 
       currentDraggingLine.setEndY(e.getY()); 
      } 
     }); 
     pane.setOnMouseReleased(e -> { 
      if (currentDraggingLine != null) { 
       currentDraggingLine.setEndX(e.getX()); 
       currentDraggingLine.setEndY(e.getY()); 

       if (unconnectedLine != null) { 
        connect(unconnectedLine, currentDraggingLine, pane); 
       } 
       unconnectedLine = currentDraggingLine ; 
       currentDraggingLine = null ; 
      } 
     }); 

     Scene scene = new Scene(pane, 600, 600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private void connect(Line line1, Line line2, Pane parent) { 
     Point2D line1Start = new Point2D(line1.getStartX(), line1.getStartY()); 
     Point2D line1End = new Point2D(line1.getEndX(), line1.getEndY()); 
     Point2D line2Start = new Point2D(line2.getStartX(), line2.getStartY()); 
     Point2D line2End = new Point2D(line2.getEndX(), line2.getEndY()); 

     double line1Length = line1End.subtract(line1Start).magnitude(); 
     double line2Length = line2End.subtract(line2Start).magnitude(); 

     // average length: 
     double aveLength = (line1Length + line2Length)/2 ; 

     // extend line1 in direction of line1 for aveLength: 
     Point2D control1 = line1End.add(line1End.subtract(line1Start).normalize().multiply(aveLength)); 

     // extend line2 in (reverse) direction of line2 for aveLength: 
     Point2D control2 = line2Start.add(line2Start.subtract(line2End).normalize().multiply(aveLength)); 

     CubicCurve cc = new CubicCurve(
       line1End.getX(), line1End.getY(), 
       control1.getX(), control1.getY(), 
       control2.getX(), control2.getY(), 
       line2Start.getX(), line2Start.getY()); 

     cc.setStroke(Color.BLACK); 
     cc.setFill(null); 

     parent.getChildren().add(cc); 
    } 

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

enter image description here

Вы можете также включить кубическую кривую Безье в пути, используя элемент пути CubicCurveTo. Ниже приведен пример с использованием Path, с сегментами вертикальных линий, соединенных кубическими кривыми Безье (метод генерации пути будет работать для произвольных линейных сегментов):

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.layout.Pane; 
import javafx.scene.shape.CubicCurveTo; 
import javafx.scene.shape.LineTo; 
import javafx.scene.shape.MoveTo; 
import javafx.scene.shape.Path; 
import javafx.stage.Stage; 

public class SmoothPathWithCubicBezier extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     double[] points = new double[24]; 
     for (int i = 0; i < 24 ; i+=8) { 
      double x = (1 + i/8) * 200 ; 
      points[i] = x ; 
      points[i+1] = 200 ; 
      points[i+2] = x ; 
      points[i+3] = 400 ; 
      points[i+4] = x + 100 ; 
      points[i+5] = 400 ; 
      points[i+6] = x+ 100 ; 
      points[i+7] = 200 ; 
     } 
     Pane pane = new Pane(); 
     pane.getChildren().add(createPath(points)); 

     Scene scene = new Scene(pane, 800, 800); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 


    // points should be an array of length a multiple of four, 
    // defining a set of lines {startX1, startY1, endX1, endY1, startX2, ...} 
    // The path will consist of the straight line segments, joined by 
    // cubic beziers 
    private Path createPath(double[] points) { 
     Path path = new Path(); 
     for (int i = 0 ; i < points.length; i+=4) { 
      double startX = points[i]; 
      double startY = points[i+1]; 
      double endX = points[i+2]; 
      double endY = points[i+3]; 

      if (i==0) { 
       MoveTo moveTo = new MoveTo(startX, startY); 
       moveTo.setAbsolute(true); 
       path.getElements().add(moveTo); 
      } else { 

       double lastStartX = points[i-4]; 
       double lastStartY = points[i-3]; 
       double lastEndX = points[i-2]; 
       double lastEndY = points[i-1]; 

       double lastLength = Math.sqrt((lastEndX-lastStartX)*(lastEndX-lastStartX) 
         + (lastEndY-lastStartY)*(lastEndY-lastStartY)); 
       double length = Math.sqrt((endX-startX)*(endX-startX) 
         + (endY-startY)*(endY-startY)); 
       double aveLength = (lastLength+length)/2; 

       double control1X = lastEndX + (lastEndX-lastStartX)*aveLength/lastLength ; 
       double control1Y = lastEndY + (lastEndY-lastStartY)*aveLength/lastLength ; 

       double control2X = startX - (endX-startX)*aveLength/length ; 
       double control2Y = startY - (endY-startY)*aveLength/length ; 

       CubicCurveTo cct = new CubicCurveTo(control1X, control1Y, control2X, control2Y, startX, startY); 
       cct.setAbsolute(true); 
       path.getElements().add(cct); 

      } 
      LineTo lineTo = new LineTo(endX, endY); 
      lineTo.setAbsolute(true); 
      path.getElements().add(lineTo); 

     } 

     return path ; 
    } 

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

Это дает

enter image description here

Смежные вопросы