前言
遇到一个需要计算一般椭圆(斜椭圆)的外接矩形坐标的问题,在此记录一下
已知椭圆的中心点坐标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);
});
}
}
运行结果如下:
可以看到这种方法是不行的。
如果真的这么简单就好了,可以看到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.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);
});
}
}
运行一下:
可以看到,数学解是成功的。
最小外接矩形
最小外接矩形其实很简单
假设椭圆没有旋转时,外接矩形四个点的坐标其实就是椭圆中心点,按照分别像左上,右上,右下,左下四个方向平移的结果,其中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);
});
}
}
运行:
可以看到我们得到了最小外接矩形。文章来源:https://www.toymoban.com/news/detail-480424.html
参考
https://zhuanlan.zhihu.com/p/82184417文章来源地址https://www.toymoban.com/news/detail-480424.html
到了这里,关于【技术碎片】【Java】计算椭圆的外接矩形坐标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!