【技术碎片】【Java】计算椭圆的外接矩形坐标

这篇具有很好参考价值的文章主要介绍了【技术碎片】【Java】计算椭圆的外接矩形坐标。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【技术碎片】【Java】计算椭圆的外接矩形坐标

前言

遇到一个需要计算一般椭圆(斜椭圆)的外接矩形坐标的问题,在此记录一下

已知椭圆的中心点坐标centerX centerY,椭圆的长轴,短轴majorRadius minorRadius,和旋转角度 angle。

按理说java有原生的计算外接矩形的函数,先看看 java.awt.geom怎么实现的。

注:java.awt.geom 是 Java 2D 图形 API 中的一个包,它提供了用于处理几何图形和形状的类。这个包中的类可以用来创建、操作和分析各种复杂的二维图形,包括点、线段、矩形、椭圆、多边形以及自定义形状。

原生实现(错误方法)

java.awt.geom提供了 Ellipse2D对象,我们通过Ellipse2D对象的 setFrameFromCenter 方法可以直接创建相应尺寸的椭圆:

           
            // 一般椭圆的入参
            double majorRadius = 108;
            double minorRadius = 207;
            double centerX = 836;
            double centerY = 473;
            double angle = 45.5;
            
            // 创建椭圆 ellipse
            Ellipse2D ellipse = new Ellipse2D.Double();
            ellipse.setFrameFromCenter(centerX, centerY, centerX + majorRadius, centerY + minorRadius);
            

我们再创建AffineTransform对象,将ellipse进行旋转变换,就能得到最终的椭圆,再通过Shape对象的getBounds2D()方法,可以直接得到外接矩形。


            // 旋转椭圆得到 transformedEllipse
            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians(45.5), centerX, centerY);
            Shape transformedEllipse = transform.createTransformedShape(ellipse);
            Rectangle2D bounds2D = transformedEllipse.getBounds2D();

为了更直观展示,我们通过 Graphics2D 把图像画出来。

完整代码如下:


import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;

public class BoundingBoxUtil2 {


    /**
     * 绘图
     */
    static class DrawFrame extends JFrame {
        public DrawFrame() {
            add(new DrawComponent());
            pack();
        }
    }

    static class DrawComponent extends JComponent {

        // 绘图窗口的尺寸
        private static final int DEFAULT_WIDTH = 2000;
        private static final int DEFAULT_HEIGHT = 1000;

        // 绘图内容
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;

            // 一般椭圆的入参
            double majorRadius = 108;
            double minorRadius = 207;
            double centerX = 836;
            double centerY = 473;
            double angle = 45.5;
            
            // 创建椭圆 ellipse
            Ellipse2D ellipse = new Ellipse2D.Double();
            ellipse.setFrameFromCenter(centerX, centerY, centerX + 108, centerY + 207);
            g2.draw(ellipse);

            // 旋转椭圆得到 transformedEllipse
            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians(45.5), centerX, centerY);
            Shape transformedEllipse = transform.createTransformedShape(ellipse);
            // 绘制旋转后的椭圆
            g2.draw(transformedEllipse);
            // 绘制旋转后的椭圆的外接矩形
            g2.draw(transformedEllipse.getBounds2D());
        }

        public Dimension getPreferredSize() {
            return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        }
    }


    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            JFrame frame = new DrawFrame();
            frame.setTitle("DrawTest");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }

}



运行结果如下:

【技术碎片】【Java】计算椭圆的外接矩形坐标

可以看到这种方法是不行的。

如果真的这么简单就好了,可以看到getBounds2D()得到的外接矩形并不是精确的,。我们看看源码描述:


    /**
     * Returns a high precision and more accurate bounding box of
     * the {@code Shape} than the {@code getBounds} method.
     * Note that there is no guarantee that the returned
     * {@link Rectangle2D} is the smallest bounding box that encloses
     * the {@code Shape}, only that the {@code Shape} lies
     * entirely within the indicated {@code Rectangle2D}.  The
     * bounding box returned by this method is usually tighter than that
     * returned by the {@code getBounds} method and never fails due
     * to overflow problems since the return value can be an instance of
     * the {@code Rectangle2D} that uses double precision values to
     * store the dimensions.
     *
     * <p>
     * Note that the
     * <a href="{@docRoot}/java.desktop/java/awt/Shape.html#def_insideness">
     * definition of insideness</a> can lead to situations where points
     * on the defining outline of the {@code shape} may not be considered
     * contained in the returned {@code bounds} object, but only in cases
     * where those points are also not considered contained in the original
     * {@code shape}.
     * </p>
     * <p>
     * If a {@code point} is inside the {@code shape} according to the
     * {@link #contains(Point2D p) contains(point)} method, then it must
     * be inside the returned {@code Rectangle2D} bounds object according
     * to the {@link #contains(Point2D p) contains(point)} method of the
     * {@code bounds}. Specifically:
     * </p>
     * <p>
     *  {@code shape.contains(p)} requires {@code bounds.contains(p)}
     * </p>
     * <p>
     * If a {@code point} is not inside the {@code shape}, then it might
     * still be contained in the {@code bounds} object:
     * </p>
     * <p>
     *  {@code bounds.contains(p)} does not imply {@code shape.contains(p)}
     * </p>
     * @return an instance of {@code Rectangle2D} that is a
     *                 high-precision bounding box of the {@code Shape}.
     * @see #getBounds
     * @since 1.2
     */
    public Rectangle2D getBounds2D();
    

大意为:

返回Shape的高精度且比getBounds方法更精确的边界框。请注意,不能保证返回的Rectangle2D是包围该形状的最小边界框,只能保证该形状完全位于指示的Rectangle 2D内。此方法返回的边界框通常比getBounds方法返回的更紧,并且从不因溢出问题而失败,因为返回值可以是使用双精度值来存储尺寸的Rectangle2D的实例。

事实上,如果直接生成不旋转的椭圆,通过getBounds2D()方法是可以找到准确的外接矩形的。

【技术碎片】【Java】计算椭圆的外接矩形坐标

但是java.awt.geom没有考虑到一般椭圆(斜椭圆)的情况。

精确实现(数学解)

其实椭圆的外接矩形有数学解,我们通过还原椭圆一般式的参数,从而可以直接求外接矩形坐标。

中心点位于原点时,椭圆一般方程为:Ax^2 + Bxy + Cy^2 + F=0

因此可以通过已知短轴,长轴,旋转角,确定一般方程的参数:


    /**
     * 计算一般椭圆(斜椭圆)的参数A,B,C,F
     * 中心点位于原点的椭圆一般方程为:Ax^2+Bxy+Cy^2+F=0
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角
     * @return
     */
    public static double[] getEllipseParam(double majorRadius, double minorRadius, double angle) {
        double a = majorRadius;
        double b = minorRadius;
        double sinTheta = Math.sin(-angle);
        double cosTheta = Math.cos(-angle);
        double A = Math.pow(a, 2) * Math.pow(sinTheta, 2) + Math.pow(b, 2) * Math.pow(cosTheta, 2);
        double B = 2 * (Math.pow(a, 2) - Math.pow(b, 2)) * sinTheta * cosTheta;
        double C = Math.pow(a, 2) * Math.pow(cosTheta, 2) + Math.pow(b, 2) * Math.pow(sinTheta, 2);
        double F = -1 * Math.pow(a, 2) * Math.pow(b, 2);
        return new double[]{A, B, C, F};
    }

因此可以计算中心点位于原点时,外接矩形的坐标:


    /**
     * 计算中心点位于原点的一般椭圆的外接矩形坐标
     * @param A
     * @param B
     * @param C
     * @param F
     * @return
     */
    public static Point2D[] calculateRectangle(double A, double B, double C, double F) {
        double y = Math.sqrt(4 * A * F / (Math.pow(B, 2) - 4 * A * C));
        double y1 = -1 * Math.abs(y);
        double y2 = Math.abs(y);

        double x = Math.sqrt(4 * C * F / (Math.pow(B, 2) - 4 * C * A));
        double x1 = -1 * Math.abs(x);
        double x2 = Math.abs(x);

        Point2D p1 = new Point2D.Double(x1, y1);
        Point2D p2 = new Point2D.Double(x2, y2);
        return new Point2D[]{p1, p2};
    }

中心点位于原点的椭圆外接矩形能算了,原来的椭圆的外接矩形其实就是按照中心点平移罢了:


    /**
     * 计算一般椭圆的外接矩形实际坐标
     * 根据一般椭圆的实际中心点坐标,短轴,长轴,旋转角参数,计算一般椭圆的外接矩形实际坐标
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角
     * @param centerX 中心点横坐标
     * @param centerY 中心点纵坐标
     * @return
     */
    public static Point2D[] getCircumscribedRectangle(double majorRadius, double minorRadius, double angle, double centerX, double centerY) {
        double[] param = getEllipseParam(majorRadius, minorRadius, angle);
        Point2D[] points = calculateRectangle(param[0], param[1], param[2], param[3]);
        Point2D p1 = new Point2D.Double(centerX + points[0].getX(), centerY + points[0].getY());
        Point2D p2 = new Point2D.Double(centerX + points[1].getX(), centerY + points[1].getY());
        return new Point2D[] { p1, p2 };
    }


这样就能求得一般椭圆的外接矩形坐标了。

为了方便展示做一下绘图,完整代码如下:



import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;

public class BoundingBoxUtil2 {


    /**
     * 绘图
     */
    static class DrawFrame extends JFrame {
        public DrawFrame() {
            add(new DrawComponent());
            pack();
        }
    }

    static class DrawComponent extends JComponent {

        // 绘图窗口的尺寸
        private static final int DEFAULT_WIDTH = 2000;
        private static final int DEFAULT_HEIGHT = 1000;

        // 绘图内容
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;

            // 一般椭圆的入参
            double majorRadius = 108;
            double minorRadius = 207;
            double centerX = 836;
            double centerY = 473;
            double angle = 45.5;

            Point2D[] rectangle = getCircumscribedRectangle(majorRadius, minorRadius, Math.toRadians(angle), centerX, centerY);
            double x1 = rectangle[0].getX();
            double y1 = rectangle[0].getY();
            double x2 = rectangle[1].getX();
            double y2 = rectangle[1].getY();
            double width = x2 - x1;
            double height = y2 - y1;
            Rectangle2D circumscribedRectangle = new Rectangle2D.Double();
            circumscribedRectangle.setRect(x1, y1, width, height);


            // 创建椭圆 ellipse
            Ellipse2D ellipse = new Ellipse2D.Double();
            ellipse.setFrameFromCenter(centerX, centerY, centerX + majorRadius, centerY + minorRadius);
            g2.draw(ellipse);

            // 旋转椭圆得到 transformedEllipse
            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians(angle), centerX, centerY);
            Shape transformedEllipse = transform.createTransformedShape(ellipse);
            // 绘制旋转后的椭圆
            g2.draw(transformedEllipse);
            // 绘制旋转后的椭圆的外接矩形
//            g2.draw(transformedEllipse.getBounds2D());

            // 绘制真正的外接矩形
            g2.draw(circumscribedRectangle);
        }

        public Dimension getPreferredSize() {
            return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        }
    }

    /**
     * 计算一般椭圆(斜椭圆)的参数A,B,C,F
     * 中心点位于原点的椭圆一般方程为:Ax^2+Bxy+Cy^2+F=0
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角
     * @return
     */
    public static double[] getEllipseParam(double majorRadius, double minorRadius, double angle) {
        double a = majorRadius;
        double b = minorRadius;
        double sinTheta = Math.sin(-angle);
        double cosTheta = Math.cos(-angle);
        double A = Math.pow(a, 2) * Math.pow(sinTheta, 2) + Math.pow(b, 2) * Math.pow(cosTheta, 2);
        double B = 2 * (Math.pow(a, 2) - Math.pow(b, 2)) * sinTheta * cosTheta;
        double C = Math.pow(a, 2) * Math.pow(cosTheta, 2) + Math.pow(b, 2) * Math.pow(sinTheta, 2);
        double F = -1 * Math.pow(a, 2) * Math.pow(b, 2);
        return new double[]{A, B, C, F};
    }

    /**
     * 计算中心点位于原点的一般椭圆的外接矩形坐标
     * @param A
     * @param B
     * @param C
     * @param F
     * @return
     */
    public static Point2D[] calculateRectangle(double A, double B, double C, double F) {
        double y = Math.sqrt(4 * A * F / (Math.pow(B, 2) - 4 * A * C));
        double y1 = -1 * Math.abs(y);
        double y2 = Math.abs(y);

        double x = Math.sqrt(4 * C * F / (Math.pow(B, 2) - 4 * C * A));
        double x1 = -1 * Math.abs(x);
        double x2 = Math.abs(x);

        Point2D p1 = new Point2D.Double(x1, y1);
        Point2D p2 = new Point2D.Double(x2, y2);
        return new Point2D[]{p1, p2};
    }

    /**
     * 计算一般椭圆的外接矩形实际坐标
     * 根据一般椭圆的实际中心点坐标,短轴,长轴,旋转角参数,计算一般椭圆的外接矩形实际坐标
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角
     * @param centerX 中心点横坐标
     * @param centerY 中心点纵坐标
     * @return
     */
    public static Point2D[] getCircumscribedRectangle(double majorRadius, double minorRadius, double angle, double centerX, double centerY) {
        double[] param = getEllipseParam(majorRadius, minorRadius, angle);
        Point2D[] points = calculateRectangle(param[0], param[1], param[2], param[3]);
        Point2D p1 = new Point2D.Double(centerX + points[0].getX(), centerY + points[0].getY());
        Point2D p2 = new Point2D.Double(centerX + points[1].getX(), centerY + points[1].getY());
        return new Point2D[] { p1, p2 };
    }


    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            JFrame frame = new DrawFrame();
            frame.setTitle("DrawTest");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }

}


运行一下:

【技术碎片】【Java】计算椭圆的外接矩形坐标

可以看到,数学解是成功的。

最小外接矩形

最小外接矩形其实很简单

假设椭圆没有旋转时,外接矩形四个点的坐标其实就是椭圆中心点,按照分别像左上,右上,右下,左下四个方向平移的结果,其中x平移短轴的距离,y平移长轴的距离。

如果椭圆旋转angle角度了,那么相应的四个点也跟着旋转四个角度就行

核心代码如下:


    /**
     * 计算获取椭圆的最小外接矩形的实际坐标
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角(弧度制)
     * @param centerX 中心点横坐标
     * @param centerY 中心点纵坐标
     * @return
     */
    public static Point2D.Double[] getMinimumBoundingRectangle(double majorRadius, double minorRadius, double angle, double centerX, double centerY) {
        // 矩形的宽长
        double width = majorRadius * 2;
        double height = minorRadius * 2;

        // 计算椭圆旋转前的最小外接矩形的四个顶点坐标
        double x1 = centerX - (width / 2);
        double y1 = centerY - (height / 2);
        double x2 = centerX + (width / 2);
        double y2 = centerY - (height / 2);
        double x3 = centerX + (width / 2);
        double y3 = centerY + (height / 2);
        double x4 = centerX - (width / 2);
        double y4 = centerY + (height / 2);

        // 计算椭圆旋转后的最小外接矩形的四个顶点坐标
        double rotatedX1 = centerX + (x1 - centerX) * Math.cos(angle) - (y1 - centerY) * Math.sin(angle);
        double rotatedY1 = centerY + (x1 - centerX) * Math.sin(angle) + (y1 - centerY) * Math.cos(angle);
        double rotatedX2 = centerX + (x2 - centerX) * Math.cos(angle) - (y2 - centerY) * Math.sin(angle);
        double rotatedY2 = centerY + (x2 - centerX) * Math.sin(angle) + (y2 - centerY) * Math.cos(angle);
        double rotatedX3 = centerX + (x3 - centerX) * Math.cos(angle) - (y3 - centerY) * Math.sin(angle);
        double rotatedY3 = centerY + (x3 - centerX) * Math.sin(angle) + (y3 - centerY) * Math.cos(angle);
        double rotatedX4 = centerX + (x4 - centerX) * Math.cos(angle) - (y4 - centerY) * Math.sin(angle);
        double rotatedY4 = centerY + (x4 - centerX) * Math.sin(angle) + (y4 - centerY) * Math.cos(angle);

        Point2D.Double point1 = new Point2D.Double(rotatedX1, rotatedY1);
        Point2D.Double point2 = new Point2D.Double(rotatedX2, rotatedY2);
        Point2D.Double point3 = new Point2D.Double(rotatedX3, rotatedY3);
        Point2D.Double point4 = new Point2D.Double(rotatedX4, rotatedY4);

        return new Point2D.Double[] { point1, point2, point3, point4 };
    }


我们完整代码如下:

package org.example.project_fragments.cv;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.List;

public class BoundingBoxUtil2 {

    /**
     * 绘图
     */
    static class DrawFrame extends JFrame {
        public DrawFrame() {
            add(new DrawComponent());
            pack();
        }
    }

    static class DrawComponent extends JComponent {

        // 绘图窗口的尺寸
        private static final int DEFAULT_WIDTH = 2000;
        private static final int DEFAULT_HEIGHT = 1000;

        // 绘图内容
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;

            // 模拟图像尺寸
            Rectangle2D image = new Rectangle2D.Double();
            image.setRect(1, 1, 1440, 1000);
            g2.draw(image);

            // 一般椭圆的入参
            int majorRadius = 108;
            int minorRadius = 207;
            int centerX = 836;
            int centerY = 473;
            double angle = 45.5;

            // 外接矩形
            Point2D.Double[] rectangle = getCircumscribedRectangle(majorRadius, minorRadius, Math.toRadians(angle), centerX, centerY);
            double x1 = rectangle[0].getX();
            double y1 = rectangle[0].getY();
            double x2 = rectangle[1].getX();
            double y2 = rectangle[1].getY();
            double width = x2 - x1;
            double height = y2 - y1;
            Rectangle2D circumscribedRectangle = new Rectangle2D.Double();
            circumscribedRectangle.setRect(x1, y1, width, height);
            // 绘制真正的外接矩形
            g2.draw(circumscribedRectangle);

            // 2023/5/11 最小外接矩形
            Point2D.Double[] minimumBoundingRectangle = getMinimumBoundingRectangle(majorRadius, minorRadius, Math.toRadians(angle), centerX, centerY);
            Polygon polygon = new Polygon();
            for (Point2D.Double point : minimumBoundingRectangle) {
                polygon.addPoint((int) point.getX(), (int) point.getY());
            }
            // 2023/5/11 最小外接矩形
            g2.drawPolygon(polygon);

            // 创建椭圆 ellipse
            Ellipse2D ellipse = new Ellipse2D.Double();
            ellipse.setFrameFromCenter(centerX, centerY, centerX + majorRadius, centerY + minorRadius);
//            g2.draw(ellipse);

            // 旋转椭圆得到 transformedEllipse
            AffineTransform transform = new AffineTransform();
            transform.rotate(Math.toRadians(angle), centerX, centerY);
            Shape transformedEllipse = transform.createTransformedShape(ellipse);
            // 绘制旋转后的椭圆
            g2.draw(transformedEllipse);
            // 绘制旋转后的椭圆的伪外接矩形
//            g2.draw(transformedEllipse.getBounds2D());

        }

        public Dimension getPreferredSize() {
            return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        }
    }

    /**
     * 计算一般椭圆(斜椭圆)的参数A,B,C,F
     * 中心点位于原点的椭圆一般方程为:Ax^2+Bxy+Cy^2+F=0
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角
     * @return
     */
    public static double[] getEllipseParam(double majorRadius, double minorRadius, double angle) {
        double a = majorRadius;
        double b = minorRadius;
        double sinTheta = Math.sin(-angle);
        double cosTheta = Math.cos(-angle);
        double A = Math.pow(a, 2) * Math.pow(sinTheta, 2) + Math.pow(b, 2) * Math.pow(cosTheta, 2);
        double B = 2 * (Math.pow(a, 2) - Math.pow(b, 2)) * sinTheta * cosTheta;
        double C = Math.pow(a, 2) * Math.pow(cosTheta, 2) + Math.pow(b, 2) * Math.pow(sinTheta, 2);
        double F = -1 * Math.pow(a, 2) * Math.pow(b, 2);
        return new double[]{A, B, C, F};
    }

    /**
     * 计算中心点位于原点的一般椭圆的外接矩形坐标
     * @param A
     * @param B
     * @param C
     * @param F
     * @return
     */
    public static Point2D.Double[] calculateRectangle(double A, double B, double C, double F) {
        double y = Math.sqrt(4 * A * F / (Math.pow(B, 2) - 4 * A * C));
        double y1 = -1 * Math.abs(y);
        double y2 = Math.abs(y);

        double x = Math.sqrt(4 * C * F / (Math.pow(B, 2) - 4 * C * A));
        double x1 = -1 * Math.abs(x);
        double x2 = Math.abs(x);

        Point2D.Double p1 = new Point2D.Double(x1, y1);
        Point2D.Double p2 = new Point2D.Double(x2, y2);
        return new Point2D.Double[]{p1, p2};
    }

    /**
     * 计算一般椭圆的外接矩形实际坐标
     * 根据一般椭圆的实际中心点坐标,短轴,长轴,旋转角参数,计算一般椭圆的外接矩形实际坐标
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角(弧度制)
     * @param centerX 中心点横坐标
     * @param centerY 中心点纵坐标
     * @return
     */
    public static Point2D.Double[] getCircumscribedRectangle(double majorRadius, double minorRadius, double angle, double centerX, double centerY) {
        double[] param = getEllipseParam(majorRadius, minorRadius, angle);
        Point2D.Double[] points = calculateRectangle(param[0], param[1], param[2], param[3]);
        Point2D.Double p1 = new Point2D.Double(centerX + points[0].getX(), centerY + points[0].getY());
        Point2D.Double p2 = new Point2D.Double(centerX + points[1].getX(), centerY + points[1].getY());
        return new Point2D.Double[] { p1, p2 };
    }


    /**
     * 计算获取椭圆的最小外接矩形的实际坐标
     * @param majorRadius 长轴
     * @param minorRadius 短轴
     * @param angle 旋转角(弧度制)
     * @param centerX 中心点横坐标
     * @param centerY 中心点纵坐标
     * @return
     */
    public static Point2D.Double[] getMinimumBoundingRectangle(double majorRadius, double minorRadius, double angle, double centerX, double centerY) {
        // 矩形的宽长
        double width = majorRadius * 2;
        double height = minorRadius * 2;

        // 计算椭圆旋转前的最小外接矩形的四个顶点坐标
        double x1 = centerX - (width / 2);
        double y1 = centerY - (height / 2);
        double x2 = centerX + (width / 2);
        double y2 = centerY - (height / 2);
        double x3 = centerX + (width / 2);
        double y3 = centerY + (height / 2);
        double x4 = centerX - (width / 2);
        double y4 = centerY + (height / 2);

        // 计算椭圆旋转后的最小外接矩形的四个顶点坐标
        double rotatedX1 = centerX + (x1 - centerX) * Math.cos(angle) - (y1 - centerY) * Math.sin(angle);
        double rotatedY1 = centerY + (x1 - centerX) * Math.sin(angle) + (y1 - centerY) * Math.cos(angle);
        double rotatedX2 = centerX + (x2 - centerX) * Math.cos(angle) - (y2 - centerY) * Math.sin(angle);
        double rotatedY2 = centerY + (x2 - centerX) * Math.sin(angle) + (y2 - centerY) * Math.cos(angle);
        double rotatedX3 = centerX + (x3 - centerX) * Math.cos(angle) - (y3 - centerY) * Math.sin(angle);
        double rotatedY3 = centerY + (x3 - centerX) * Math.sin(angle) + (y3 - centerY) * Math.cos(angle);
        double rotatedX4 = centerX + (x4 - centerX) * Math.cos(angle) - (y4 - centerY) * Math.sin(angle);
        double rotatedY4 = centerY + (x4 - centerX) * Math.sin(angle) + (y4 - centerY) * Math.cos(angle);

        Point2D.Double point1 = new Point2D.Double(rotatedX1, rotatedY1);
        Point2D.Double point2 = new Point2D.Double(rotatedX2, rotatedY2);
        Point2D.Double point3 = new Point2D.Double(rotatedX3, rotatedY3);
        Point2D.Double point4 = new Point2D.Double(rotatedX4, rotatedY4);

        return new Point2D.Double[] { point1, point2, point3, point4 };
    }


    /**
     * 可以自己测试椭圆在图像的情况
     */
    public static void main(String[] args) {
        // 图像展示
        EventQueue.invokeLater(() -> {
            JFrame frame = new DrawFrame();
            frame.setTitle("DrawTest");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });

    }
}


运行:

【技术碎片】【Java】计算椭圆的外接矩形坐标
可以看到我们得到了最小外接矩形。

参考

https://zhuanlan.zhihu.com/p/82184417文章来源地址https://www.toymoban.com/news/detail-480424.html

到了这里,关于【技术碎片】【Java】计算椭圆的外接矩形坐标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 苹果正在研发具备智能家居显示功能的外接显示器,具备低功耗模式

    据彭博社记者 Mark Gurman 在他最新一期的 Power On 时事通讯中报道,苹果公司正致力于研发一款新的 Mac 外接显示器,具备智能家居设备显示器的低功耗模式功能。 根据了解,这款显示器将集成iOS设备芯片,与Studio Display不同的是,它不仅能利用芯片实现Center Stage人物居中和空间

    2024年02月11日
    浏览(40)
  • android:绘制圆角矩形,椭圆形

    一、前言:在我们工作中会有绘制不同圆角的按钮图形,具体该怎么做之前也只是了解个大概,今天看了一节课,听完老师讲的我自己又写了一遍,记录一下。 二、代码展示: 首先先创建一个DrawableShapeActivity 相对应的xml 以及两个形状xml:shape_oval_rose.xml shape_ract_gold.xml

    2024年02月06日
    浏览(42)
  • Halcon画矩形框(正矩形和最小外接矩形)

    1.正矩形框 正矩形框,指的是没有发生倾斜,竖直的矩形框。 该矩形框,不仅能够完全覆盖region区域,而且还不发生倾斜,可以用在一些特定的瑕疵标定。 具体代码如下: 其中,smallest_rectangle1 算子的作用是,获取region的最小外接正矩形。输出Row1(左上y坐标),Column1(左

    2024年02月11日
    浏览(63)
  • 【Python】【OpenCV】绘制外接矩形、外接圆

     外接矩形、外接圆:   1、cv2.boundingRect() Method 和 cv2.minAreaRect() Merhod:前者只寻找和 x、y轴 平行的矩形,后者则可以出现旋转角度。 2、cv2.drawContours() Method:第二个参数接收的是轮廓信息,但是这个轮廓信息需要以 tuple or list or set类型(或者说是iterable)才可以传入。 请注

    2024年02月05日
    浏览(42)
  • OpenCV——最小外接矩形

      emspminAreaRect 函数用于计算给定点集的最小外接矩形。该矩形的长和宽是可以任意旋转的,因此被称为旋转矩形。 points :是一个包含点集的 Mat 对象。点集可以是二维点集或三维点集,但是只有前两个坐标被使用。返回值是一个 RotatedRect 对象,表示最小外接矩形。 该函数

    2024年02月05日
    浏览(54)
  • OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆

    函数说明:基于最小二乘法(least-squares sense)计算围绕一组(个数大于等于5个)给定的点集拟合一个椭圆。返回该椭圆的最小外接矩形(如果给定的点是在一条直线上,该矩形的最小边为0)。注意返回的数值可能有负数(大边界之外)。 参数 说明 InputArray points IEnumerablePoint points IE

    2024年02月10日
    浏览(46)
  • 【无标题】Matlab之annotation函数——创建图形注释(箭头、椭圆、矩形)

    应用1:创建文本箭头注释 创建一个简单线图并向图窗添加文本箭头。用归一化的 图窗坐标 指定文本箭头位置,起点为 (0.3,0.6),终点为 (0.5,0.5)。通过设置 String 属性指定文本说明。 备注1:annotation(lineType,x,y) 创建一个在当前图窗中的两个点之间延伸的线条或箭头注释。将

    2024年02月19日
    浏览(39)
  • OpenCV(十三):图像中绘制直线、圆形、椭圆形、矩形、多边形和文字

    目录 1.绘制直线line() 2.绘制圆形circle() 3.绘制椭圆形ellipse()  4.绘制矩形rectangle() 5.绘制多边形 fillPoly()  6.绘制文字putText() 7.例子 1.绘制直线line() img:绘制圆形的图像 ptl:直线起始点在图像中的坐标 pt2: 直线终点在图像中的坐标 color:圆形的颜色,用三通道表示 thickness:轮廓的宽

    2024年02月09日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包