1. 程式人生 > >Qt--根據圓上的兩個點和半徑獲取圓心

Qt--根據圓上的兩個點和半徑獲取圓心

1.根據圓上的兩個點和半徑獲得兩個圓的演算法

#define MAXCOM_F(a, b) ((a)-(b)>0.00001) ? true : false
QVector<QRectF> EICWidget::getEllipseCoors(const QPointF &r1, const QPointF &r2, float r)
{
    double c1=0.0f, c2=0.0f, A=0.0f, B=0.0f, C=0.0f, x0=0.0f, y0=0.0f, x1=0.0f, y1=0.0f;
    if (MAXCOM_F(qAbs(r2.x()-r1.x()),0.0f)) {
        c1 = (pow(r2.x(),2)-pow(r1.x(),2)+pow(r2.y(),2)-pow(r1.y(),2))/2/(r2.x()-r1.x());
        c2 = (r2.y()-r1.y())/(r2.x()-r1.x());
        A = 1.0+pow(c2, 2);
        B = 2*(r1.x()-c1)*c2-2*r1.y();
        C = pow((r1.x()-c1), 2)+pow(r1.y(), 2)-pow(r, 2);
        //如何b^2-4ac <= 0,則賦值為0.0f
        double b_ac = sqrt(B*B-4*A*C);
        if (qIsNaN(b_ac)) b_ac = 0.0f;
        y0 = (-B+b_ac)/(2*A);
        x0 = c1-c2*y0;
        y1 = (-B-b_ac)/2/A;
        x1 = c1-c2*y1;
    } else {
        float d = sqrt(pow((r2.y()-r1.y()), 2)+pow((r2.x()-r1.x()), 2));
        d = sqrt(pow(r, 2)-pow(d/2, 2));
        y0 = (r1.y()+r2.y())/2;
        x0 = (r1.x()+d);
        y1 = (r1.y()+r2.y())/2;
        x1 = (r1.x()-d);
    }
    QVector<QRectF>rectf;
    rectf<<QRectF(QPointF(x0-r, y0+r), QPointF(x0+r, y0-r));
    rectf<<QRectF(QPointF(x1-r, y1+r), QPointF(x1+r, y1-r));
    return rectf;
}

已知兩點和半徑計算的圓有兩種可能的情況,其中x0,y0,x1,y1為兩個圓的圓心。

在開始寫這個計算的時候遇到了幾個問題:

  • 在最開始沒有判斷兩個點的x相等的情況,這就導致會出現分母為0的情況,使得剩下的的計算毫無意義。

  • 沒有對b^2-4ac做判斷,同樣的,當b^2-4ac<0的時候,開根號後結果將為nan,後續的計算也將變得都是錯誤的。

  • 這點是作為提醒自己,當浮點型資料沒有賦值後但是沒有經過計算的時候,是可以直接進行比較大小相等的,但是在經過計算之後就要在一定的精度內進行比較,不然比較的結果可能是不對的。

2.根據圓上的兩個點和這兩個點連線的線與直徑的角度可以確定唯一的一個圓

//根據圓上的兩個點和一個傾角確定一個圓
QRectF EICWidget::getEllipseCoor(const QPointF &r1, const QPointF &r2, float ang)
{
    //求出兩點之間的距離
    double d = sqrt(pow((r2.y()-r1.y()), 2)+pow((r2.x()-r1.x()), 2));
    //求出圓的半徑
    double r = qAbs(d/cos(ang*M_PI/180.0f))/2;
    //根據兩個點和半徑求出圓心的座標
    QVector<QRectF> rectfs = getEllipseCoors(r1, r2, r);
    //根據角度獲取唯一的圓
    if (MAXCOM_F(ang, 0.0f)) {
        return rectfs.at(0);
    } else {
        return rectfs.at(1);
    }
}

偏轉角為弦Z1-Z2相對於直徑的夾角,逆時針為正。

3.關於浮點型資料計算需要注意的事項:

    qDebug()<<"**************************";
    //開方下的值如果小於0.0f則會出現nan
    qDebug()<<sqrt(-0.00001);
    //如果有一個結果為nan則無論後面是什麼運算得到的都將是nan
    qDebug()<<1.0+sqrt(-1);
    qDebug()<<pow(sqrt(-1), 2);
    //分母為0時則會出現inf
    qDebug()<<1.0/0.0;
    //如果計算的數值過大也會出現inf,
    double C = 9999999999999999.0/0.0000000000001;
    qDebug()<<pow(C, 100);
    qDebug()<<"**************************";

輸出預覽:

可以總結為下面幾條,不太全面,以後隨時會補充:

  • 開方下的值如果小於0,則會出現nan
  • 如果在運算的過程中,有一個計算結果為nan則不論後面是什麼運算都會出現nan
  • 當分母為0時則計算的結果會出現inf
  • 如果計算的數值過大也會出現inf

要避免對計算結果的影響,在Qt下可以使用qIsNan()這個函式對nan進行判斷,使用qIsInf()函式對Inf進行判斷,然後對資料進行處理。

4.根據兩點和一個偏轉角的資料輸入:QPointF(1.0f, 1.0f), QPointF(1.0f, 0.0f), 60,得到的圖形為(兩個虛線圓中的實線為得到的圓形):