Math 计算空间中圆弧边界坐标的公式

Math 计算空间中圆弧边界坐标的公式,math,formula,Math,Formula,我有两条线在一个已知坐标点相交 -x1,y1 -x2,y2 -x3,y3 根据这一点,我计算了两条线之间给定半径处的圆弧。所以我现在知道了 -2个圆弧端点x4、y4和x5、y5 -圆弧中心点Cx,Cy -弧半径r -相对于极轴X轴的起始角和终止角,以及线之间的角度 我想创建一个公式来计算圆弧的最大和最小X和Y值。即包围弧的框的坐标 在下面的示例中,我可以找出最小X值和最大Y值,它们是已知值,但我不确定如何计算最大X值和最小Y值 在其他情况下,圆弧可以是任何坐标,因此已知的最小值和最大值将发生变

我有两条线在一个已知坐标点相交 -x1,y1 -x2,y2 -x3,y3

根据这一点,我计算了两条线之间给定半径处的圆弧。所以我现在知道了 -2个圆弧端点x4、y4和x5、y5 -圆弧中心点Cx,Cy -弧半径r -相对于极轴X轴的起始角和终止角,以及线之间的角度

我想创建一个公式来计算圆弧的最大和最小X和Y值。即包围弧的框的坐标

在下面的示例中,我可以找出最小X值和最大Y值,它们是已知值,但我不确定如何计算最大X值和最小Y值

在其他情况下,圆弧可以是任何坐标,因此已知的最小值和最大值将发生变化

我知道如何以给定角度或间隔沿圆弧计算点,但不知道特定方向上的最大值和最小值,在本例中为X轴和Y轴


我将在编程中使用该公式。

首先查找端点位于哪个象限

如果它们位于同一象限,则圆弧是单调的,边界框很容易

否则,每次穿过象限时,都会得到一个端点,即水平或垂直直径的端点


编写这样的算法并不太复杂,尽管可能有几种情况需要考虑,包括弧的方向。

< P>我有一个可以尝试使用的算法解决方案。它包括扫描圆弧上已知起点和终点之间的极坐标空间,并跟踪最小值和最大值

以下是算法的基本步骤:

  • 将圆弧上的两个输入(笛卡尔)点转换为极坐标
  • 沿极坐标中的圆弧逆时针走
  • 在每个步骤中,转换回笛卡尔坐标并检查最小值/最大值
我利用以下两个方程将极坐标转换为笛卡尔坐标:

x = r*cosθ
y = r*sinθ
下面是一个将笛卡尔坐标转换为极角的方程式:

θ = tan-1(y / x)
你需要注意这个等式中的势能除以零。无穷大的反正切为
Pi/2
弧度

此解决方案假定圆弧从低弧度值开始并逆时针穿过高弧度值

// Input Parameters:
// (x1, y1) first point on arc
// (x2, y2) second point on arc
// (xc, yc) center point of circle

public void findMinMax(double x1, double x2, double y1, double y2, double xc, double yc) {
    double xMin, yMin, xMax, yMax;
    // compute radius of circle
    double radius = Math.sqrt(Math.pow((xc - x1), 2) + Math.pow((yc - y1), 2));

    // compute starting and ending points in polar coordinates
    double t1 = 0.0;
    if (x1 == 0.0) {
        t1 = Math.PI / 2;
    }
    else {
        t1 = Math.atan(y1 / x1);
    }

    double t2 = 0.0;
    if (x2 == 0.0) {
        t2 = Math.PI / 2;
    }
    else {
        t2 = Math.atan(y2 / x2);
    }

    // determine starting and ending polar angles
    double tStart, tEnd;
    if (t1 < t2) {
        tStart = t1;
        tEnd = t2;
    }
    else {
        tStart = t2;
        tEnd = t1;
    }

    // now scan the polar space at fixed radius and find
    // the minimum AND maximum Cartesian x and y values
    double delta = 0.01;

    // initialize min and max coordinates to first point
    xMin = radius * Math.cos(tStart);
    yMin = radius * Math.sin(tStart);
    xMax = xMin;
    yMax = yMin;

    for (double theta=tStart; theta < tEnd; theta += delta) {
        // compute coordinates
        double x = radius * Math.cos(theta);
        double y = radius * Math.sin(theta);

        if (x > xMax) {
            xMax = x;
        }
        if (x < xMin) {
            xMin = x;
        }
        if (y > yMax) {
            yMax = y;
        }
        if (y < yMin) {
            yMin = y;
        }
    }

    // display min and max values
    System.out.println("xMin = " + xMin + ", yMin = " + yMin);
    System.out.println("xMax = " + xMax + ", yMax = " + yMax);
}

假设我们有起始角θ1,终止角θ2(均以弧度表示),半径r,弧的方向逆时针。我们希望找到XmaxYmaxXminYmin。把这个值看作象限Q=f(Th)的函数:

Xmax=f(q1,q2,r),Ymax=f(q1,q2,r),Xmin=f(q1,q2,r),Ymin=f(q1,q2,r)

与其写大量的“if”语句,不如将此函数表示为“极值矩阵”。计算函数f(q1,q2,r),我们将得到

下面是算法:

  • 找到θ1θ2的象限(q1q2
  • θ1θ2r转换为笛卡尔坐标
  • 查找不包括极值点的边界框
  • 建立极值矩阵
  • 根据此矩阵中的q1q2选择XmaxYmaxXminYmin
  • 下面是我的C#6实现:

    using System;
    using System.Windows;
    using static System.Math;
    
    public static class GeomTools
    {
        public static Byte GetQuadrant(this Double angle)
        {
            var trueAngle = angle%(2*PI);
            if (trueAngle >= 0.0 && trueAngle < PI/2.0)
                return 1;
            if (trueAngle >= PI/2.0 && trueAngle < PI)
                return 2;
            if (trueAngle >= PI && trueAngle < PI*3.0/2.0)
                return 3;
            if (trueAngle >= PI*3.0/2.0 && trueAngle < PI*2)
                return 4;
            return 0;
        }
        public static Rect GetBounds(Double startAngle, Double endAngle, Double r)
        {
            var startQuad = startAngle.GetQuadrant() - 1;
            var endQuad = endAngle.GetQuadrant() - 1;
    
            // Convert to Cartesian coordinates.
            var stPt = new Point(Round(r*Cos(startAngle), 14), Round(r*Sin(startAngle), 14));
            var enPt = new Point(Round(r*Cos(endAngle), 14), Round(r*Sin(endAngle), 14));
    
            // Find bounding box excluding extremum.
            var minX = stPt.X;
            var minY = stPt.Y;
            var maxX = stPt.X;
            var maxY = stPt.Y;
            if (maxX < enPt.X) maxX = enPt.X;
            if (maxY < enPt.Y) maxY = enPt.Y;
            if (minX > enPt.X) minX = enPt.X;
            if (minY > enPt.Y) minY = enPt.Y;
    
            // Build extremum matrices.
            var xMax = new[,] {{maxX, r, r, r}, {maxX, maxX, r, r}, {maxX, maxX, maxX, r}, {maxX, maxX, maxX, maxX}};
            var yMax = new[,] {{maxY, maxY, maxY, maxY}, {r, maxY, r, r}, {r, maxY, maxY, r}, {r, maxY, maxY, maxY}};
            var xMin = new[,] {{minX, -r, minX, minX}, {minX, minX, minX, minX}, {-r, -r, minX, -r}, {-r, -r, minX, minX}};
            var yMin = new[,] {{minY, -r, -r, minY}, {minY, minY, -r, minY}, {minY, minY, minY, minY}, {-r, -r, -r, minY}};
    
            // Select desired values
            var startPt =new Point(xMin[endQuad, startQuad], yMin[endQuad, startQuad]);
            var endPt=new Point(xMax[endQuad, startQuad], yMax[endQuad, startQuad]);
            return new Rect(startPt,endPt);
        }
    }
    
    使用系统;
    使用System.Windows;
    使用静态系统。数学;
    公共静态类几何工具
    {
    公共静态象限(此双角度)
    {
    var-trueAngle=角度%(2*PI);
    如果(trueAngle>=0.0&&trueAngle=PI/2.0&&trueAngle=PI&&trueAngle=PI*3.0/2.0&&trueAngleenPt.X)minX=enPt.X;
    如果(minY>enPt.Y)minY=enPt.Y;
    //建立极值矩阵。
    var xMax=new[,]{maxX,r,r,r},{maxX,maxX,r,r},{maxX,maxX,maxX,r},{maxX,maxX,maxX,maxX};
    var yMax=new[,]{maxY,maxY,maxY,maxY},{r,maxY,r,r},{r,maxY,maxY,r},{r,maxY,maxY,maxY};
    var xMin=new[,]{minX,-r,minX,minX},{minX,minX,minX},{-r,-r,minX,-r},{-r,-r,minX,minX};
    var yMin=new[,]{{minY,-r,-r,minY},{minY,minY,-r,minY},{minY,minY,minY,minY},{-r,-r,minY};
    //选择所需的值
    var startPt=新点(xMin[endQuad,startQuad],yMin[endQuad,startQuad]);
    var endPt=新点(xMax[endQuad,startQuad],yMax[endQuad,startQuad]);
    返回新的Rect(开始、结束);
    }
    }
    
    弧中心点在(0,0)是公平的,但您可以轻松地将生成的边界框移动到Cx,Cy

    与的近似解决方案不同,此解决方案是精确的,但内存可能会稍微贵一点。

    的答案是用Javascript实现的:

    const PI = Math.PI;
    const HALF_PI = Math.PI / 2;
    const TWO_PI = Math.PI * 2;
    const DEG_TO_RAD = Math.PI / 180;
    const RAD_TO_DEG = 180 / Math.PI;
    
    const getQuadrant = (_angle) => {
        const angle = _angle % (TWO_PI);
    
        if (angle > 0.0 && angle < HALF_PI) return 0;
        if (angle >= HALF_PI && angle < PI) return 1;
        if (angle >= PI && angle < PI + HALF_PI) return 2;
        return 3;
    };
    
    const getArcBoundingBox = (ini, end, radius, margin = 0) => {
        const iniQuad = getQuadrant(ini);
        const endQuad = getQuadrant(end);
    
        const ix = Math.cos(ini) * radius;
        const iy = Math.sin(ini) * radius;
        const ex = Math.cos(end) * radius;
        const ey = Math.sin(end) * radius;
    
        const minX = Math.min(ix, ex);
        const minY = Math.min(iy, ey);
        const maxX = Math.max(ix, ex);
        const maxY = Math.max(iy, ey);
    
        const r = radius;
        const xMax = [[maxX, r, r, r], [maxX, maxX, r, r], [maxX, maxX, maxX, r], [maxX, maxX, maxX, maxX]];
        const yMax = [[maxY, maxY, maxY, maxY], [r, maxY, r, r], [r, maxY, maxY, r], [r, maxY, maxY, maxY]];
        const xMin = [[minX, -r, minX, minX], [minX, minX, minX, minX], [-r, -r, minX, -r], [-r, -r, minX, minX]];
        const yMin = [[minY, -r, -r, minY], [minY, minY, -r, minY], [minY, minY, minY, minY], [-r, -r, -r, minY]];
    
        const x1 = xMin[endQuad][iniQuad];
        const y1 = yMin[endQuad][iniQuad];
        const x2 = xMax[endQuad][iniQuad];
        const y2 = yMax[endQuad][iniQuad];
    
        const x = x1 - margin;
        const y = y1 - margin;
        const w = x2 - x1 + margin * 2;
        const h = y2 - y1 + margin * 2;
    
        return { x, y, w, h };
    };
    
    const PI=Math.PI;
    常数HALF_PI=Math.PI/
    
    const PI = Math.PI;
    const HALF_PI = Math.PI / 2;
    const TWO_PI = Math.PI * 2;
    const DEG_TO_RAD = Math.PI / 180;
    const RAD_TO_DEG = 180 / Math.PI;
    
    const getQuadrant = (_angle) => {
        const angle = _angle % (TWO_PI);
    
        if (angle > 0.0 && angle < HALF_PI) return 0;
        if (angle >= HALF_PI && angle < PI) return 1;
        if (angle >= PI && angle < PI + HALF_PI) return 2;
        return 3;
    };
    
    const getArcBoundingBox = (ini, end, radius, margin = 0) => {
        const iniQuad = getQuadrant(ini);
        const endQuad = getQuadrant(end);
    
        const ix = Math.cos(ini) * radius;
        const iy = Math.sin(ini) * radius;
        const ex = Math.cos(end) * radius;
        const ey = Math.sin(end) * radius;
    
        const minX = Math.min(ix, ex);
        const minY = Math.min(iy, ey);
        const maxX = Math.max(ix, ex);
        const maxY = Math.max(iy, ey);
    
        const r = radius;
        const xMax = [[maxX, r, r, r], [maxX, maxX, r, r], [maxX, maxX, maxX, r], [maxX, maxX, maxX, maxX]];
        const yMax = [[maxY, maxY, maxY, maxY], [r, maxY, r, r], [r, maxY, maxY, r], [r, maxY, maxY, maxY]];
        const xMin = [[minX, -r, minX, minX], [minX, minX, minX, minX], [-r, -r, minX, -r], [-r, -r, minX, minX]];
        const yMin = [[minY, -r, -r, minY], [minY, minY, -r, minY], [minY, minY, minY, minY], [-r, -r, -r, minY]];
    
        const x1 = xMin[endQuad][iniQuad];
        const y1 = yMin[endQuad][iniQuad];
        const x2 = xMax[endQuad][iniQuad];
        const y2 = yMax[endQuad][iniQuad];
    
        const x = x1 - margin;
        const y = y1 - margin;
        const w = x2 - x1 + margin * 2;
        const h = y2 - y1 + margin * 2;
    
        return { x, y, w, h };
    };