Les anneaux olympiques JavaFX se chevauchent dans le bon ordre


C'est la première fois que je poste ici. Je fais actuellement une mission où je dois créer les anneaux olympiques dans JavaFX et les faire se croiser aux bons endroits.

Voici à quoi il est censé ressembler:

Les anneaux Olympiques http://ksuweb.kennesaw.edu/~ashaw8/cs1302-07-Fall16/assignments/images/OlympicRings.png

Actuellement, les anneaux se croisent mais ils dominent dans l'ordre que j'ai créé les objets. Le bleu est couvert par le jaune quand ils se croisent, le jaune se couvre de noir quand ils se croisent, etc. Comme vous pouvez le voir dans l'image des anneaux olympiques, la première fois, le jaune et le bleu se croisent, jaune couvre bleu, mais bleu couvre jaune la deuxième fois. Chacun des anneaux est couvert par l'autre anneau une fois qu'ils se croisent, mais le couvre l'autre fois.

Si quelqu'un pouvait me diriger dans la bonne direction quant à la façon de faire s'entrecroiser correctement, ce serait fantastique.

Voici le code que j'ai donc loin:

package com.company;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class OlympicRings extends Application{

    public void start(Stage primaryStage) {

        //creates a new object, which will be the first circle
        Circle circle1 = new Circle();
        circle1.setCenterX(100); //sets the x coordinate for the center of the circle
        circle1.setCenterY(100); //sets the y coordinate for the center of the circle
        circle1.setRadius(50); //sets the radius of the circle to 50, makes the diameter 100
        circle1.setStroke(Color.BLUE); //sets the color of the circle
        circle1.setStrokeWidth(10); //sets the thickness of the lines
        circle1.setFill(null); //sets the color of the inside of the circle, set to null to enable overlap

        Circle circle2 = new Circle(); //creates additional circles
        circle2.setCenterX(160);
        circle2.setCenterY(150);
        circle2.setRadius(50);
        circle2.setStroke(Color.YELLOW);
        circle2.setStrokeWidth(10);
        circle2.setFill(null);

        Circle circle3 = new Circle();
        circle3.setCenterX(220);
        circle3.setCenterY(100);
        circle3.setRadius(50);
        circle3.setStroke(Color.BLACK);
        circle3.setStrokeWidth(10);
        circle3.setFill(null);

        Circle circle4 = new Circle();
        circle4.setCenterX(280);
        circle4.setCenterY(150);
        circle4.setRadius(50);
        circle4.setStroke(Color.GREEN);
        circle4.setStrokeWidth(10);
        circle4.setFill(null);

        Circle circle5 = new Circle();
        circle5.setCenterX(340);
        circle5.setCenterY(100);
        circle5.setRadius(50);
        circle5.setStroke(Color.RED);
        circle5.setStrokeWidth(10);
        circle5.setFill(null);

        //creating the pane that will display the circle
        Pane pane = new Pane();
        pane.getChildren().add(circle1); //each of these adds the various circles to the display of the pane
        pane.getChildren().add(circle2);
        pane.getChildren().add(circle3);
        pane.getChildren().add(circle4);
        pane.getChildren().add(circle5);

        Scene scene1 = new Scene(pane, 440, 250); //creates the parameters of the pane
        primaryStage.setTitle("Olympic Rings"); //names the pane
        primaryStage.setScene(scene1); //picks what will go in the pane
        primaryStage.show(); //shows the scene i've created
    }
}
Author: fabian, 2016-09-13

2 answers

Ceci est difficile à réaliser avec Circle s. Cela utiliserait beaucoup la propriété clip et le code résultant ne serait pas facilement lisible.

Au Lieu Arcs peut être utilisé pour dessiner des pièces des anneaux. Il suffit d'ajouter la partie couverte de l'anneau au parent avant d'ajouter la partie de couverture.

Exemple pour les 2 premiers anneaux:

private static Arc createArc(double radius,
                             double centerX, double centerY,
                             double fromAngle, double toAngle,
                             Paint stroke,
                             double strokeWidth) {
    Arc arc = new Arc(centerX, centerY, radius, radius, fromAngle, toAngle - fromAngle);
    arc.setFill(null);
    arc.setStroke(stroke);
    arc.setStrokeWidth(strokeWidth);

    return arc;
}

@Override
public void start(Stage primaryStage) {
    Pane pane = new Pane(
            createArc(50, 60, 60, 90, 315, Color.BLUE, 10), // part of the blue ring containing part covered by yellow
            createArc(50, 110, 110, 0, 360, Color.YELLOW, 10),
            createArc(50, 60, 60, -45, 90, Color.BLUE, 10) // part covering the yellow ring
    );

    Scene scene = new Scene(pane);

    primaryStage.setScene(scene);
    primaryStage.show();
}
 2
Author: fabian, 2016-09-12 23:27:58

Merci pour la question, j'ai eu beaucoup de plaisir à trouver la solution suivante, voir les Javadocs pour l'algorithme:

package olympicrings;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;

/**
 * This helper class knows how to paint the next olympic ring into a {@code Pane}.
 * It is not limited to 5 olympic rings, it can draw as many (or few) as desired.
 * The algorithm it follows is:
 * <ol>
 *   <li>Each ring consists of 2 arcs (half-circles) of the same color, of course.
 *       Imagine the line connecting the center of the previous ring to the center
 *       of the current: we place one arc on the LEFT of this line and one arc on
 *       the RIGHT. Let's call them arcs L and R. These need to be added to the
 *       children {@code Node}s of the {@code Pane} at the correct order.</li>
 *   <li>The placement of arc L depends on whether the current ring is at the top
 *       row or at the bottom:
 *       <ul>
 *           <li>TOP: It goes below arc L of the previous ring</li>
 *           <li>BOTTOM: It goes below arc R of the previous ring</li>
 *       </ul>
 *   </li>
 *   <li>Arc R is always placed last in the list of the children of the {@code Pane}.</li>
 *   <li>Advance the position of the next ring, taking into account the desired
 *       ring radius and stroke width.</li>
 * </ol>
 * <p>
 * Usage:
 * <pre><code>
 * OlympicRingsPaintingContext ctx = new OlympicRingsPaintingContext(thePane, 50, 10);
 * ctx.paintNextRing(Color.BLUE);
 * ...
 * </code></pre>
 */
public class OlympicRingsPaintingContext {

    /**
     * A handy constant containing the standard olympic colors. Could be used as follows
     * to paint the standard olympic rings:
     * <pre><code>
     * OlympicRingsPaintingContext ctx = new OlympicRingsPaintingContext(thePane, 50, 10);
     * OlympicRingsPaintingContext.STANDARD_OLYMPIC_COLORS.forEach(ctx::paintNextRing);
     * </code></pre>
     */
    public static final List<Color> STANDARD_OLYMPIC_COLORS = Collections.unmodifiableList(Arrays.asList(Color.BLUE, Color.YELLOW, Color.BLACK, Color.GREEN, Color.RED));

    private static final double[] TOP_START_ANGLES = new double[] {45, 225};
    private static final double[] BOTTOM_START_ANGLES = new double[] {315, 135};

    private Pane pane;
    private double radius;
    private double strokeWidth;
    private double curx;
    private double cury;
    private double topy;
    private double bottomy;
    private double startAngleL;
    private double startAngleR;
    private int prevIndexL;
    private int prevIndexR;

    public OlympicRingsPaintingContext(Pane pane, double radius, double strokeWidth) {
        this.pane = pane;
        this.radius = radius;
        this.strokeWidth = strokeWidth;
        topy = 2*radius;
        bottomy = 3*radius;
        curx = 2*radius;
        cury = topy;
        startAngleL = TOP_START_ANGLES[0];
        startAngleR = TOP_START_ANGLES[1];
        prevIndexL = 0;
        prevIndexR = 0;
    }

    public void paintNextRing(Color color) {
        addArcL(color);
        addArcR(color);
        advance();
    }

    private void addArcL(Color color) {
        Arc arcL = makeArc(startAngleL, color);
        if( cury == topy ) {
            pane.getChildren().add(prevIndexL, arcL);
        }
        else {
            pane.getChildren().add(prevIndexR, arcL);
            prevIndexL = prevIndexR;
        }
    }

    private void addArcR(Color color) {
        Arc arcR = makeArc(startAngleR, color);
        pane.getChildren().add(arcR);
        prevIndexR = pane.getChildren().size() - 1;
    }

    private Arc makeArc(double startAngle, Color color) {
        Arc arc = new Arc(curx, cury, radius, radius, startAngle, 180);
        arc.setFill(null);
        arc.setStroke(color);
        arc.setStrokeWidth(strokeWidth);
        return arc;
    }

    private void advance() {
        curx += radius + strokeWidth;
        if( cury == topy ) {
            cury = bottomy;
            startAngleL = BOTTOM_START_ANGLES[0];
            startAngleR = BOTTOM_START_ANGLES[1];
        }
        else {
            cury = topy;
            startAngleL = TOP_START_ANGLES[0];
            startAngleR = TOP_START_ANGLES[1];
        }
    }
}

Exemple d'utilisation:

package olympicrings;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class OlympicRingsApplication extends Application {

    public void start(Stage primaryStage) {
        Pane pane = new Pane();
        OlympicRingsPaintingContext ctx = new OlympicRingsPaintingContext(pane, 50, 10);
        OlympicRingsPaintingContext.STANDARD_OLYMPIC_COLORS.forEach(ctx::paintNextRing);
// nobody stops you here though...
//      ctx.paintNextRing(javafx.scene.paint.Color.AQUA);

        Scene scene1 = new Scene(pane, 440, 250); // creates the parameters of the pane
        primaryStage.setTitle("Olympic Rings"); // names the pane
        primaryStage.setScene(scene1); // picks what will go in the pane
        primaryStage.show(); // shows the scene i've created
    }

    public static void main(String[] args) {
        launch(args);
    }
}
 1
Author: Nikos Paraskevopoulos, 2016-09-14 09:59:30