You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已知方位参数的旋转矩形中心及顶点坐标计算(Java)技术问询

我来帮你梳理一下这个问题的解法,其实不需要绕到先计算蓝色坐标轴的矩形再旋转,直接通过向量偏移就能算出中心和顶点坐标,逻辑清晰还不容易出错。

解题思路

首先明确几个关键定义(避免歧义):

  • 朝向角度theta:以x轴正方向为0度,逆时针旋转的角度(如果你的角度定义是顺时针,后面代码里调整符号即可)
  • dBow:点p到矩形艏边(前端面)的垂直距离
  • dStern:点p到矩形艉边(后端面)的垂直距离
  • dPort:点p到矩形左舷边的垂直距离
  • dStarboard:点p到矩形右舷边的垂直距离

核心步骤分为两步:计算矩形中心,再推导四个顶点坐标。

1. 计算矩形中心

矩形的中心相对于点p的偏移,由两个方向的分量组成:

  • 艏-艉方向:中心到艏边和艉边的距离相等,所以中心在这个方向上离p的距离是(dStern - dBow)/2,方向与艏方向一致(如果结果为负,说明中心在p的艉侧)
  • 左-右舷方向:同理,中心在这个方向上离p的距离是(dPort - dStarboard)/2,方向与右舷方向一致(结果为负则在左舷侧)

接下来把这两个方向转换成笛卡尔坐标系的单位向量:

  • 艏方向单位向量:(cos(thetaRad), sin(thetaRad))(thetaRad是角度转弧度后的值)
  • 右舷方向单位向量:(sin(thetaRad), -cos(thetaRad))(垂直于艏方向顺时针转90度,对应船舶右舷的方向)

把偏移量和单位向量相乘,加到p的坐标上,就得到中心坐标。

2. 计算四个顶点

首先算出矩形的半长(中心到艏/艉边的垂直距离)和半宽(中心到左/右舷边的垂直距离):

  • 半长:(dBow + dStern)/2
  • 半宽:(dPort + dStarboard)/2

然后通过中心加上/减去半长的艏方向向量,加上/减去半宽的左舷方向向量(左舷是右舷的反方向),就能得到四个顶点:

  • 艏左顶点:中心 + 半长×艏方向 + 半宽×左舷方向
  • 艏右顶点:中心 + 半长×艏方向 - 半宽×左舷方向
  • 艉左顶点:中心 - 半长×艏方向 + 半宽×左舷方向
  • 艉右顶点:中心 - 半长×艏方向 - 半宽×左舷方向
Java实现代码

这里用Java的Point2D.Double来表示坐标,代码里包含完整的计算逻辑,你可以直接复用:

import java.awt.geom.Point2D;

public class RotatedRectangleCalculator {

    /**
     * 计算旋转矩形的中心和四个顶点
     * @param x1 已知点p的x坐标
     * @param y1 已知点p的y坐标
     * @param dBow p到艏边的垂直距离
     * @param dStern p到艉边的垂直距离
     * @param dPort p到左舷边的垂直距离
     * @param dStarboard p到右舷边的垂直距离
     * @param thetaDeg 矩形朝向角度(度,x轴正方向逆时针为正)
     * @return 返回包含中心和四个顶点的数组,顺序为:中心、艏左、艏右、艉左、艉右
     */
    public static Point2D.Double[] calculateRectangle(double x1, double y1,
                                                      double dBow, double dStern,
                                                      double dPort, double dStarboard,
                                                      double thetaDeg) {
        // 角度转弧度
        double thetaRad = Math.toRadians(thetaDeg);

        // 计算单位向量
        double bowDirX = Math.cos(thetaRad);
        double bowDirY = Math.sin(thetaRad);
        double starboardDirX = Math.sin(thetaRad);
        double starboardDirY = -Math.cos(thetaRad);
        // 左舷方向是右舷的反方向
        double portDirX = -starboardDirX;
        double portDirY = -starboardDirY;

        // 计算中心相对于p的偏移
        double deltaBowStern = (dStern - dBow) / 2.0;
        double deltaPortStarboard = (dPort - dStarboard) / 2.0;

        // 中心坐标
        double cx = x1 + deltaBowStern * bowDirX + deltaPortStarboard * starboardDirX;
        double cy = y1 + deltaBowStern * bowDirY + deltaPortStarboard * starboardDirY;
        Point2D.Double center = new Point2D.Double(cx, cy);

        // 计算半长和半宽
        double halfLength = (dBow + dStern) / 2.0;
        double halfWidth = (dPort + dStarboard) / 2.0;

        // 计算四个顶点
        Point2D.Double bowLeft = new Point2D.Double(
                cx + halfLength * bowDirX + halfWidth * portDirX,
                cy + halfLength * bowDirY + halfWidth * portDirY
        );
        Point2D.Double bowRight = new Point2D.Double(
                cx + halfLength * bowDirX - halfWidth * portDirX,
                cy + halfLength * bowDirY - halfWidth * portDirY
        );
        Point2D.Double sternLeft = new Point2D.Double(
                cx - halfLength * bowDirX + halfWidth * portDirX,
                cy - halfLength * bowDirY + halfWidth * portDirY
        );
        Point2D.Double sternRight = new Point2D.Double(
                cx - halfLength * bowDirX - halfWidth * portDirX,
                cy - halfLength * bowDirY - halfWidth * portDirY
        );

        return new Point2D.Double[]{center, bowLeft, bowRight, sternLeft, sternRight};
    }

    // 测试示例
    public static void main(String[] args) {
        // 测试参数:p(0,0),艏距1,艉距3,左舷距1,右舷距1,朝向90度(艏朝上)
        Point2D.Double[] result = calculateRectangle(0, 0, 1, 3, 1, 1, 90);
        System.out.println("中心坐标:(" + result[0].x + ", " + result[0].y + ")");
        System.out.println("艏左顶点:(" + result[1].x + ", " + result[1].y + ")");
        System.out.println("艏右顶点:(" + result[2].x + ", " + result[2].y + ")");
        System.out.println("艉左顶点:(" + result[3].x + ", " + result[3].y + ")");
        System.out.println("艉右顶点:(" + result[4].x + ", " + result[4].y + ")");
        // 预期结果:中心(0, -1),艏左(-1,0),艏右(1,0),艉左(-1,-2),艉右(1,-2)
    }
}
注意事项
  1. 角度定义:如果你的朝向角度是顺时针为正(比如某些船舶坐标系),只需要把thetaRad改成Math.toRadians(-thetaDeg)即可调整方向。
  2. 距离的正负:如果p在矩形外部,距离值会是正的,代码依然能正确计算中心和顶点,因为逻辑是基于垂直距离的相对关系。
  3. 精度问题:如果需要更高精度,可以用BigDecimal代替double,但一般场景下double足够。

内容的提问来源于stack exchange,提问作者Braveness

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 07:47:43