将JavaFX中的ArcTo命令转换为一系列X、Y坐标点数组

import javafx.geometry.Point2D;
import javafx.scene.shape.ArcTo;
import java.util.ArrayList;
import java.util.List;

public class ArcToConverter {

    public static List<Point2D> convertArcToPoints(double startX, double startY, ArcTo arc, int numSegments) {
        List<Point2D> points = new ArrayList<>();
        double endX = arc.getX();
        double endY = arc.getY();
        double rx = Math.abs(arc.getRadiusX());
        double ry = Math.abs(arc.getRadiusY());
        double xAxisRotation = Math.toRadians(arc.getXAxisRotation());
        boolean largeArcFlag = arc.isLargeArcFlag();
        boolean sweepFlag = arc.isSweepFlag();

        // 处理半径为零的情况
        if (rx == 0 || ry == 0) {
            points.add(new Point2D(startX, startY));
            points.add(new Point2D(endX, endY));
            return points;
        }

        // 将端点转换到旋转后的坐标系
        double dx = (startX - endX) / 2.0;
        double dy = (startY - endY) / 2.0;
        double x1p = Math.cos(xAxisRotation) * dx + Math.sin(xAxisRotation) * dy;
        double y1p = -Math.sin(xAxisRotation) * dx + Math.cos(xAxisRotation) * dy;

        // 调整半径以防止椭圆过小
        double lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
        if (lambda > 1) {
            rx *= Math.sqrt(lambda);
            ry *= Math.sqrt(lambda);
        }

        // 计算中心点(cx', cy')
        double sign = (largeArcFlag == sweepFlag) ? -1 : 1;
        double denominator = (rx * rx * y1p * y1p) + (ry * ry * x1p * x1p);
        if (denominator == 0) {
            return points; // 避免除以零
        }
        double sqrtTerm = Math.sqrt(Math.max(0, (rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p) / denominator));
        double factor = sign * sqrtTerm;

        double cxp = factor * (rx * y1p) / ry;
        double cyp = factor * (-ry * x1p) / rx;

        // 转换回原始坐标系
        double midX = (startX + endX) / 2.0;
        double midY = (startY + endY) / 2.0;
        double cx = midX + Math.cos(xAxisRotation) * cxp - Math.sin(xAxisRotation) * cyp;
        double cy = midY + Math.sin(xAxisRotation) * cxp + Math.cos(xAxisRotation) * cyp;

        // 计算起始角度和结束角度
        double dxStart = startX - cx;
        double dyStart = startY - cy;
        double dxStartRot = Math.cos(xAxisRotation) * dxStart + Math.sin(xAxisRotation) * dyStart;
        double dyStartRot = -Math.sin(xAxisRotation) * dxStart + Math.cos(xAxisRotation) * dyStart;
        double theta1 = Math.atan2(dyStartRot / ry, dxStartRot / rx);

        double dxEnd = endX - cx;
        double dyEnd = endY - cy;
        double dxEndRot = Math.cos(xAxisRotation) * dxEnd + Math.sin(xAxisRotation) * dyEnd;
        double dyEndRot = -Math.sin(xAxisRotation) * dxEnd + Math.cos(xAxisRotation) * dyEnd;
        double theta2 = Math.atan2(dyEndRot / ry, dxEndRot / rx);

        // 计算角度差
        double deltaTheta = theta2 - theta1;
        if (sweepFlag) {
            if (deltaTheta < 0) deltaTheta += 2 * Math.PI;
        } else {
            if (deltaTheta > 0) deltaTheta -= 2 * Math.PI;
        }

        // 生成点
        for (int i = 0; i <= numSegments; i++) {
            double t = (double) i / numSegments;
            double theta = theta1 + t * deltaTheta;
            double xEllipse = rx * Math.cos(theta);
            double yEllipse = ry * Math.sin(theta);

            // 旋转并平移回原始坐标系
            double x = cx + Math.cos(xAxisRotation) * xEllipse - Math.sin(xAxisRotation) * yEllipse;
            double y = cy + Math.sin(xAxisRotation) * xEllipse + Math.cos(xAxisRotation) * yEllipse;
            points.add(new Point2D(x, y));
        }

        return points;
    }

    public static void main(String[] args) {
        // 示例用法
        ArcTo arc = new ArcTo();
        arc.setRadiusX(50);
        arc.setRadiusY(30);
        arc.setX(100);
        arc.setY(100);
        arc.setLargeArcFlag(true);
        arc.setSweepFlag(true);
        arc.setXAxisRotation(45);

        List<Point2D> points = convertArcToPoints(0, 0, arc, 100);
        for (Point2D p : points) {
            System.out.println(p.getX() + ", " + p.getY());
        }
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值