Michal Rama
Michal Rama

Reputation: 299

JavaFX - Is it possible to divide a shape into two or more shapes?

For example, I have this Path

import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;

public class DivideShape extends javafx.application.Application {

    @Override
    public void start(Stage primaryStage) {
        var path = new Path(new MoveTo(200, 380), new LineTo(0, 300),
            new ArcTo(300, 300, 0, 300, 0, false, true), new LineTo(380,
                    200), new ArcTo(180, 180, 0, 200, 380, false, false));
        path.setFill(Color.BLUE);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(new Scene(new Pane(path)));
        primaryStage.show();
    }

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

enter image description here

And I want to divide it into 5 parts (exactly the same as dividing pizza)

This can be done using Line.

However, this way it will look like 5 objects, but in reality it will still be 1 object.

Is it possible to divide the object into 5 Paths so that I don't have to create them all one by one, please?

Thank you

UPDATE:

Of course, when I modify the start method.

@Override
public void start(Stage primaryStage) {
    var pane = new Pane();
    var moveTo = new MoveTo(200, 380);
    var lineTo = new LineTo(0, 300);
    var arc_big = 300;
    var arc_small = 180;
    for (var deg = 198; deg <= 270; deg += 18) {
        var path = new Path(moveTo, lineTo);
        lineTo = new LineTo(300 + arc_big * Math.cos(Math.toRadians(deg)), 300 + arc_big * Math.sin(Math.toRadians(deg)));
        path.getElements().add(new ArcTo(arc_big, arc_big, 0, lineTo.getX(), lineTo.getY(), false, true));
        var move = new MoveTo(380 + arc_small * Math.cos(Math.toRadians(deg)), 380 + arc_small * Math.sin(Math.toRadians(deg)));
        path.getElements().addAll(new LineTo(move.getX(), move.getY()),
        new ArcTo(arc_small, arc_small, 0, moveTo.getX(), moveTo.getY(), false, false));
        moveTo = move;
        path.setFill(Color.color(Math.random(), Math.random(), Math.random()));
        pane.getChildren().add(path);
    }
    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(new Scene(pane));
    primaryStage.show();
}

enter image description here

So I'll create five separate Paths, but the code is too complicated. That's why I wanted to know if it could be divided (1 Object to 5 Objects), please?

Upvotes: 3

Views: 484

Answers (2)

c0der
c0der

Reputation: 18792

When a code becomes too complicated consider refactoring it into short single-responsibility reusable methods:

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class ConvinienceMethodsExample extends Application {

    private static final double OUTER_RADIUS =300, INNER_RADIUS = 180, ORIGIN_X = 300, ORIGIN_Y = 300;
    private static final double START_ANGLE =20, END_ANGLE = 70, STEP_ANGEL = 10;

    @Override
    public void start(Stage primaryStage) {

        Group group = new Group();

        for(double angle =  START_ANGLE; angle < END_ANGLE ; angle += STEP_ANGEL ){

            Point2D innerArcStart = getPoint(INNER_RADIUS, angle);
            Point2D innerArcEnd = getPoint(INNER_RADIUS, angle + STEP_ANGEL);
            Point2D outerArcStart = getPoint(OUTER_RADIUS, angle);
            Point2D outerArcEnd = getPoint(OUTER_RADIUS, angle + STEP_ANGEL);
            var path = getPath(innerArcStart, innerArcEnd, outerArcStart, outerArcEnd);
            group.getChildren().add(path);
        }
        primaryStage.setScene(new Scene(new Pane(group)));
        primaryStage.show();
    }

    private Point2D getPoint(double radius, double angle){

        double x = ORIGIN_X - radius * Math.cos(Math.toRadians(angle));
        double y = ORIGIN_Y - radius * Math.sin(Math.toRadians(angle));
        return new Point2D(x, y);
    }

    private Shape getPath(Point2D innerArcStart, Point2D innerArcEnd, Point2D outerArcStart, Point2D outerArcEnd){
        var path = new Path(
                new MoveTo(innerArcStart.getX(), innerArcStart.getY()),
                new LineTo(outerArcStart.getX(), outerArcStart.getY()), //left line
                new ArcTo(OUTER_RADIUS, OUTER_RADIUS, 0, outerArcEnd.getX(), outerArcEnd.getY(), false, true), //outer arc
                new LineTo(innerArcEnd.getX(),innerArcEnd.getY()), //right line
                new ArcTo(INNER_RADIUS, INNER_RADIUS, 0, innerArcStart.getX(), innerArcStart.getY(), false, false)
                );
        path.setFill(Color.color(Math.random(), Math.random(), Math.random()));
        return path;
    }

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

enter image description here

Upvotes: 5

Giovanni Contreras
Giovanni Contreras

Reputation: 2569

you can do it with Arc object instead of Path in this code i've made five arcs of 18 degrees each one and a fade animation to make transparent the path . when the animation ends i remove path from pane children
`

 package dividedshape;

 import javafx.animation.FadeTransition;
 import javafx.application.Application;
 import javafx.scene.Scene;
 import javafx.scene.layout.Pane;
 import javafx.scene.paint.Color;
 import javafx.scene.shape.*;
 import javafx.stage.Stage;
 import javafx.util.Duration;

 public class DivideShape extends Application {

@Override
public void start(Stage primaryStage) {
  Path path = new Path(new MoveTo(500, 500), new LineTo(0, 500),
            new ArcTo(500, 500, 0, 500, 0, false, true), new LineTo(500, 
    500));
    path.setFill(Color.BLUE);
    Arc arc1 = new Arc(500,500,500,500,90,18);
    arc1.setType(ArcType.ROUND);
    arc1.setFill(Color.BLUE);
    arc1.setStroke(Color.BLACK);

    Arc arc2 = new Arc(500,500,500,500,108,18);
    arc2.setType(ArcType.ROUND);
    arc2.setFill(Color.BLUE);
    arc2.setStroke(Color.BLACK);

    Arc arc3 = new Arc(500,500,500,500,126,18);
    arc3.setType(ArcType.ROUND);
    arc3.setFill(Color.BLUE);
    arc3.setStroke(Color.BLACK);

    Arc arc4 = new Arc(500,500,500,500,144,18);
    arc4.setType(ArcType.ROUND);
    arc4.setFill(Color.BLUE);
    arc4.setStroke(Color.BLACK);

    Arc arc5 = new Arc(500,500,500,500,162,18);
    arc5.setType(ArcType.ROUND);
    arc5.setFill(Color.BLUE);
    arc5.setStroke(Color.BLACK);

    primaryStage.setTitle("Hello World!");
    Pane pane = new Pane(arc1,arc2,arc3,arc4,arc5,path);
    primaryStage.setScene(new Scene(pane));
    primaryStage.show();

    FadeTransition fadePath = new FadeTransition(Duration.seconds(10), path);
    fadePath.setFromValue(10);
    fadePath.setToValue(0);
    fadePath.play();
    fadePath.setOnFinished(e->{ pane.getChildren().remove(path);});


   }

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

result after fade animation

Upvotes: 1

Related Questions