JavaFX画布:填充由多个几何体组成的闭合路径

JavaFX画布:填充由多个几何体组成的闭合路径,java,canvas,javafx,graphics2d,Java,Canvas,Javafx,Graphics2d,我想画和填充一个路径,由两个弧和两条线组成的特定颜色。我需要使用JavaFX中的画布,因为我需要绘制更多的画布。问题是,我创建的路径甚至没有被绘制或填充。我想要的是这个 但是我的代码产生了这个 正如你可能注意到的,这个圆弧在左边和右边比中间的更薄。不幸的是,对我来说,仅仅使用一个具有ceratin笔划宽度的简单圆弧是不可取的 这是我的代码,注释部分在其中生成第二个图像。我已经尝试使用绘制路径工具并填充它,但它不起作用 import javafx.application.Application

我想画和填充一个路径,由两个弧和两条线组成的特定颜色。我需要使用JavaFX中的画布,因为我需要绘制更多的画布。问题是,我创建的路径甚至没有被绘制或填充。我想要的是这个

但是我的代码产生了这个

正如你可能注意到的,这个圆弧在左边和右边比中间的更薄。不幸的是,对我来说,仅仅使用一个具有ceratin笔划宽度的简单圆弧是不可取的

这是我的代码,注释部分在其中生成第二个图像。我已经尝试使用绘制路径工具并填充它,但它不起作用

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcType;
import javafx.stage.Stage;

public final class CanvasTest extends Application {

    private static final int WIDTH = 400;
    private static final int HEIGHT = 300;
    private static final int RADIUS = 250;

    private static final int BRICK_HEIGHT = 15;
    private static final int RADIUSHALF = RADIUS / 2;
    private static GraphicsContext gc;

    @Override
    public void start(Stage stage) {
        final Group root = new Group();
        final Scene scene = new Scene(root, WIDTH, HEIGHT);
        final Canvas can = new Canvas(WIDTH, HEIGHT);
        gc = can.getGraphicsContext2D();

        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, WIDTH, HEIGHT);

        drawArc(WIDTH / 2, HEIGHT / 2);

        root.getChildren().add(can);
        stage.setScene(scene);
        stage.show();
    }

    private void drawArc(final int posX, final int posY) {
        gc.setStroke(Color.WHITE);
        gc.setLineWidth(1);
        gc.setFill(Color.WHITE);

        final double newRadius = RADIUSHALF - BRICK_HEIGHT;
        final double yOffsetLowerArc = Math.cos(Math.toRadians(45)) * newRadius;
        final double xOffsetLowerArc = Math.sin(Math.toRadians(45)) * newRadius;
        final double newAngleLowerArc = Math.toDegrees(Math.atan2(xOffsetLowerArc, yOffsetLowerArc + BRICK_HEIGHT));
        final double xOffsetUpperArc = Math.cos(Math.toRadians(45)) * RADIUSHALF;
        final double yOffsetUpperArc = Math.sin(Math.toRadians(45)) * RADIUSHALF;
        final double yOffsetNewLowerArc = Math.cos(Math.toRadians(newAngleLowerArc)) * RADIUSHALF;
        final double xOffsetNewLowerArc = Math.sin(Math.toRadians(newAngleLowerArc)) * RADIUSHALF;

        // this code produces the un-filled custom arc
        // gc.strokeArc(posX - RADIUSHALF, posY - RADIUSHALF, RADIUS, RADIUS, 45, 90, ArcType.OPEN);
        // gc.strokeArc(posX - RADIUSHALF, posY - RADIUSHALF + BRICK_HEIGHT, RADIUS, RADIUS, 90 - newAngleLowerArc, 2 * newAngleLowerArc, ArcType.OPEN);
        // gc.strokeLine(posX - xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc, posX - xOffsetUpperArc, posY - yOffsetUpperArc);
        // gc.strokeLine(posX + xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc, posX + xOffsetUpperArc, posY - yOffsetUpperArc);

        gc.beginPath();
        gc.arc(posX - RADIUSHALF, posY - RADIUSHALF, RADIUS, RADIUS, 45, 90/*, ArcType.OPEN*/);
        gc.arc(posX - RADIUSHALF, posY - RADIUSHALF + BRICK_HEIGHT, RADIUS, RADIUS, 90 - newAngleLowerArc, 2 * newAngleLowerArc/*, ArcType.OPEN*/);
        gc.moveTo(posX + xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc);
        gc.lineTo(posX + xOffsetUpperArc, posY - yOffsetUpperArc);
        gc.moveTo(posX - xOffsetNewLowerArc, posY + BRICK_HEIGHT - yOffsetNewLowerArc);
        gc.lineTo(posX - xOffsetUpperArc, posY - yOffsetUpperArc);
        gc.closePath();
        gc.fill();
    }

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

也许我也误解了JavaFX中路径的概念,但对我来说,我的方法是正确的:-)尽管如此,它仍然不起作用。(我也读了这个“”)

您的代码有一些问题。的参数与不相同

不同之处在于:
strokeArc
绘制位于点
(x,y)
的矩形中椭圆的一部分的弧,该点具有给定的
宽度和
高度<代码>圆弧
但是,它构造了一条路径,该路径是以
(centerX,centerY)
为中心的椭圆形的一部分,半径为
radiusX
radiusY
。要获得
arc
的适当参数,可以使用以下公式:

centerX = (x+w)/2
centerY = (y+h)/2
radiusX = w/2
radiusY = h/2
此外,您不需要调用
moveTo
来构建路径。2个圆弧足以构成路径。另外,请确保使用不同方向(一个顺时针方向,一个逆时针方向)的圆弧连接圆弧的最近端:

gc.beginPath();
gc.arc(posX, posY, RADIUSHALF, RADIUSHALF, 45, 90);

// next arc in opposite direction
gc.arc(posX, posY + BRICK_HEIGHT, RADIUSHALF, RADIUSHALF, 90 + newAngleLowerArc, -2 * newAngleLowerArc);
gc.closePath();

gc.fill();

以下问题的答案中有一些基于场景图的解决方案:。这些可能对您帮助不大,因为您正在寻找基于画布的解决方案,而不是基于场景图的解决方案。您还没有足够的时间来处理这些问题以获得完整的答案,但您希望您的路径能够跟踪形状的轮廓,就好像您没有从“纸”上取下“笔”。因此,您应该有类似于
gc.beginPath()
gc.arc(…)
gc.lineTo(…)
gc.arc(…)
gc.lineTo(…)
gc.closePath()
。然后,
gc.fill()
应该可以正常工作。我没有看到参数,编译器在删除“stroke”和最后一个参数后没有抱怨,所以我认为它可以
gc.beginPath();
gc.arc(posX, posY, RADIUSHALF, RADIUSHALF, 45, 90);

// next arc in opposite direction
gc.arc(posX, posY + BRICK_HEIGHT, RADIUSHALF, RADIUSHALF, 90 + newAngleLowerArc, -2 * newAngleLowerArc);
gc.closePath();

gc.fill();