JavaFX Canvas : fill closed path composed of multiple geometries

标签 java canvas javafx graphics2d

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

enter image description here

但是我的代码产生了这个

enter image description here

您可能会注意到,这条弧线在左侧和右侧比在中间更细。不幸的是,仅使用具有一定笔划宽度的简单弧线对我来说不是一个选择。

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

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中路径的概念,但对我来说,我的方法是合理的:-)但它不起作用。 (我还读过这篇“Working with Canvas”)

最佳答案

您的代码存在一些问题。 GraphicsContext.arc 的参数与 GraphicsContext.strokeArc 不同.

strokeArc(double x,
          double y,
          double w,
          double h,
          double startAngle,
          double arcExtent,
          ArcType closure)
arc(double centerX,
    double centerY,
    double radiusX,
    double radiusY,
    double startAngle,
    double length)

区别是:strokeArc在位于点 (x, y) 的矩形中绘制属于椭圆形一部分的圆弧给定widthheightarc然而,构造了一条路径,该路径是以 (centerX, centerY) 为中心的椭圆形的一部分。半径 radiusXradiusY 。获取 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();

关于JavaFX Canvas : fill closed path composed of multiple geometries,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33369661/

相关文章:

java - 确定哪个方法触发了一个方面

ruby-on-rails - 如何将 Canvas 保存为矢量图像?

javascript - Canvas 漫画的自定义光标?

Javafx 更新对象属性上的 ListCell

java - 来自特定字节的 md5 文件校验和

java - Java中单例的其他方式

java - 使用场景构建器中创建的 fxml 文件从 java 添加图像

java - 缺少 Maven Shade JavaFX 运行时组件

java - MapStruct Mapper 作为 Spring Framework Converter - 可以惯用使用吗?

c# - 如何添加 Canvas 边框