opengl算法學習---圓弧繪制


opengl算法學習--圓弧繪制

整圓的繪制算法有逐點比較法、Bresenham算法和中點畫圓法,這些算法可以在生成1/4象限圓弧或者1/8象限圓弧的基礎上通過已生成的象限對稱而繪制出其他象限的圓弧,稱為4路對稱或8路對稱。

4/8路對稱

根據圓弧在多個象限上的對稱性,我們就可以通過一個象限上的點來推出其他象限上的點,以4路對稱為例,若知道一個點在第一象限上的坐標(x,y),即可通過x軸,y軸以及圓心對稱,得知該點在其它象限上得坐標

根據4路對稱,我們可以通過角度cos與sin的性質,推出8路對稱,如下圖所示

代碼實現(8路對稱)

int ar[4][2]={{1,1},{-1,1},{1,-1},{-1,-1}};

void circledrew(int x,int y,int ox,int oy)
{
    for(int i=0;i<4;i++) Setpoint(ox+x*ar[i][0],oy+y*ar[i][1]);
    for(int i=0;i<4;i++) Setpoint(ox+y*ar[i][0],oy+x*ar[i][1]);
}

Bresenham畫圓算法

Bresenham畫圓算法適合於生成整圓,它使用8路對稱法,只需計算出90°~45°內的點,沿着右下方向(+x,-y)逐點掃描。

方法概述
設點P\((x_{i},y_{i})\),為第i步選定的坐標,由於計算區間為90°~45°,所以下一個候選點必定為T\((x_{i}+1,y_{i})\)或者S\((x_{i}+1,y_{i}-1)\)

令D(T)為T點到原點距離的與半徑的平方差,D(S)為S點到原點距離的與半徑的平方差。
可知

\[D(T)=(x_{i}+1)^{2}+y_{i}^{2}-r^{2}>0 \]

\[D(s)=(x_{i}+1)^{2}+(y_{i}-1)^{2}-r^{2}<0 \]

定義

\[d_{i}=D(T)+D(s)=2(x_{i}+1)^{2}+y_{i}^{2}+(y_{i}-1)^{2}-2r^{2} \]

可推出

\[d_{i+1}=2(x_{i+1}+1)^{2}+y_{i+1}^{2}+(y_{i+1}-1)^{2}-2r^{2} \]

\[=2(x_{i}+1)^{2}+4x_{i}+6+y_{i+1}^{2}+(y_{i+1}-1)^{2}+y_{i}^{2}+(y_{i}-1)^{2}-y_{i}^{2}-(y_{i}-1)^{2}-2r^{2} \]

\[=d_{i}+4x_{i}+6+y_{i+1}^{2}-y_{i}^{2}+(y_{i+1}-1)^{2}-(y_{i}-1)^{2} \]

\(d_{i}>0\)\(y_{i+1}=y_{i}-1\)
\(d_{i}\leq 0\)\(y_{i+1}=y_{i}\)

\[\Rightarrow d_{i+1}= \left\{\begin{matrix} d_{i}+4(x_{i}-y_{i})+10 & d_{i}>0 \\ d_{i}+4x_{i}+6 & d_{i}\leq 0 \end{matrix}\right. \]

因為起點坐標為(0,r)
所以

\[d_{1}=2+r^{2}+(r-1)^{2}-2r^{2} \]

\[=3-2r \]

代碼實現

void Bresenham(int ox,int oy,int r)
{
    int x=0,y=r,d=3-(r<<1);
    circledrew(x,y,ox,oy);
    while (x<=y)
    {
        if(d<0) d+=(x<<2)+6;
        else 
        {
            d+=((x-y)<<2)+10;
            --y;
        } 
        ++x;
        circledrew(x,y,ox,oy);
    }
}

中點畫圓法

中點畫圓法與Bresenham畫圓法類似,通過對預測點的中點,計算下一個點的位置

方法概述
設點\(P(x_{i},y_{i})\)為當前點亮像素,接下來的候選像素點為\(T(x_{i}+1,y_{i})\)\(S(x_{i}+1,y_{i}-1)\),線段ST的中點\(M(x_{i}+1,y_{i}-0.5)\)
構造函數\(F(x,y)=x^{2}+y^{2}-r^{2}\)
\(F(M)<0\),說明M在圓內,選取T點
\(F(M)\geq 0\),說明M在圓外,選取S點

\[d_{i}=F(M)=F(x_{i}+1,y_{i}-0.5) \]

\(d_{i}<0\),則下個點選擇T

\[\Rightarrow d_{i+1}=(x_{i}+2)^{2}+(y_{i}-0.5)^{2}-r^{2}=d_{i}+2x_{i}+3 \]

\(d_{i}\geq 0\),則下個點選擇S

\[\Rightarrow d_{i+1}=(x_{i}+2)^{2}+(y_{i}-1.5)^{2}-r^{2}=d_{i}+2(x_{i}-y_{i})+5 \]

\[\Rightarrow d_{i+1}= \left\{\begin{matrix} d_{i}+2x_{i}+3 & d_{i}<0 \\ d_{i}+2(x_{i}-y_{i})+5 & d_{i}\geq 0 \end{matrix}\right. \]

因為起點坐標為(0,r)
所以

\[d_{1}=1+(r-0.5)^{2}-r^{2} \]

\[=1.25-r \]

由於在實際實現中,之后的遞推式中並不會出現浮點運算,所以0.25並不會影響之后的正負關系,因此可以將d1簡化為1-r,可提高該算法效率
代碼實現

void midpointcircle(int ox,int oy,int r)
{
    int x=0,y=r,d=1-r;
    circledrew(x,y,ox,oy);
    while (x<=y)
    {
        if(d<0) d+=(x<<1)+3;
        else 
        {
            d+=((x-y)<<1)+5;
            --y;
        }
        ++x;
        circledrew(x,y,ox,oy);
    }
}

角度離散法

角度離散法利用已有的直線算法來分段繪制圓弧或橢圓弧,即借助與參數方程繪制曲線,並采用“以直代曲”的策略。采用這種方式的優點在於靈活性強(自由控制所繪制的弧角),而不足之處在於計算效率不高。

方法概述
若已知圓心坐標\((x_{c},y_{c})\),半徑 r ,則該圓以角度t為參數的參數方程為

\[\left\{\begin{matrix} x=x_{c}+rcost \\ y=y_{c}+rsint \end{matrix}\right. \]

通過離散化參數t對圓的參數方程進行離散化,離散步長\(\delta t\)通常根據半徑的大小經驗確定,半徑越大,步長\(\delta t\) 適當取小;半徑較小時,步長\(\delta t\) 適當取大。以逆時針方向為正,當參數t從\(t_{s}\)變化至\(t_{e}\)時,表示繪制一段圓弧。

代碼實現

void arccircle(int ox,int oy,double r,double angs,double ange)
{
    if(ange<angs) ange+=2*PI;
    double dt=0.4/r;
    int n=(int)((ange-angs)/dt);
    int x=Round(ox+r*cos(angs));
    int y=Round(oy+r*sin(ange));
    glVertex2i(x,y);
    glBegin(GL_LINE_STRIP);
    for(int i=0;i<n;i++)
    {
        glVertex2i(Round(x+r*cos(angs+i*dt)),Round(y+r*sin(angs+i*dt)));
    }
    glEnd();
    glFlush();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM