• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評論-2670  文章-0  trackbacks-0

                終于完成了相當于GDI中Arc函數的功能了。這次仍然跟API有點誤差,不多這里的誤差是GDI的問題。這里貼出截圖和代碼。觀看圖2和圖3,我們知道橢圓是對稱的,但是GDI并沒有做到這一點。我的算法也不能精確對稱,但是左右兩邊僅相差1個像素。Arc是橢圓的子集,所以Arc在這個局部(橢圓的最上方)中也應該左右對稱。圖1中我先用GDI繪制黑色Arc,然后使用我的算法繪制紅色Arc。這里的自適應步長算法跟上一篇的Bezier曲線的算法是一樣的。

                圖1:運行結果


                圖2:GDI局部放大

                圖3: 我的結果圖放大

             


                代碼:
              1 #include "..\..\..\..\Library\Windows\VL_WinMain.h"
              2 #include "..\..\..\..\Library\Windows\VL_WinGDI.h"
              3 
              4 using namespace vl;
              5 using namespace vl::windows;
              6 
              7 class Evaluator : public VL_Base
              8 {
              9 protected:
             10     VL_WinDIB*    FBuffer;
             11     VDouble FX1,FY1,FX2,FY2,FStart,FEnd;
             12     VDouble FCenX,FCenY,FA,FB;
             13 public:
             14     Evaluator(VL_WinDIB* Buffer)
             15     {
             16         FBuffer=Buffer;
             17     }
             18 
             19     void SetEllipse(VDouble X1 , VDouble Y1 , VDouble X2 , VDouble Y2 , VDouble Start , VDouble End)
             20     {
             21         FX1=X1;
             22         FY1=Y1;
             23         FX2=X2;
             24         FY2=Y2;
             25         FStart=Start;
             26         FEnd=End;
             27 
             28         FCenX=(FX1+FX2)/2;
             29         FCenY=(FY1+FY2)/2;
             30         FA=(FX2-FX1)/2;
             31         FB=(FY2-FY1)/2;
             32     }
             33 
             34     void GetP(VDouble T , VDouble& X , VDouble& Y)
             35     {
             36         VDouble Angle=FStart+T*(FEnd-FStart);
             37         VDouble Sin=-sin(Angle);
             38         VDouble Cos=cos(Angle);
             39         if(abs(Sin)<0.5)
             40         {
             41             VDouble X2=1/(1/(FA*FA)+(Sin*Sin)/(FB*FB*Cos*Cos));
             42             if(Pi_f/2<=Angle && Angle<=Pi_f*3/2)
             43             {
             44                 X=-sqrt(X2);
             45             }
             46             else
             47             {
             48                 X=sqrt(X2);
             49             }
             50             Y=X*Sin/Cos;
             51         }
             52         else
             53         {
             54             VDouble Y2=1/(1/(FB*FB)+(Cos*Cos)/(FA*FA*Sin*Sin));
             55             if(0<=Angle && Angle<=Pi_f)
             56             {
             57                 Y=-sqrt(Y2);
             58             }
             59             else
             60             {
             61                 Y=sqrt(Y2);
             62             }
             63             X=Y*Cos/Sin;
             64         }
             65         X+=FCenX;
             66         Y+=FCenY;
             67     }
             68 
             69     void SetColor(VInt X , VInt Y , VInt Color)
             70     {
             71         VByte R=Color%256;
             72         VByte G=(Color>>8)%256;
             73         VByte B=(Color>>16)%256;
             74         if(X>=0 && X<FBuffer->GetWidth() && Y>=0 && Y<FBuffer->GetHeight())
             75         {
             76             ((VInt32u*)(FBuffer->ScanLines[Y]))[X]=(R<<16)+(G<<8)+B;
             77         }
             78     }
             79 
             80     POINT GetStartPoint()
             81     {
             82         VDouble X,Y;
             83         GetP(0,X,Y);
             84         POINT P;
             85         P.x=Round(X);
             86         P.y=Round(Y);
             87         return P;
             88     }
             89 
             90     POINT GetEndPoint()
             91     {
             92         VDouble X,Y;
             93         GetP(1,X,Y);
             94         POINT P;
             95         P.x=Round(X);
             96         P.y=Round(Y);
             97         return P;
             98     }
             99 
            100     void DrawCurve()
            101     {
            102         POINT StartPoint=GetStartPoint();
            103         POINT EndPoint=GetEndPoint();
            104 
            105         VDouble T=0.0001;
            106         VBool Finished=false;
            107         VDouble OldX=StartPoint.x;
            108         VDouble OldY=StartPoint.y;
            109         VDouble X1,Y1;
            110         VDouble X2=EndPoint.x;
            111         VDouble Y2=EndPoint.y;
            112 
            113         VInt OldX1=StartPoint.x;
            114         VInt OldY1=StartPoint.y;
            115         VInt OldX2=0;
            116         VInt OldY2=0;
            117         VBool Old2Available=false;
            118         SetColor(OldX1,OldY1,RGB(255,0,0));
            119         while(!Finished)
            120         {
            121             /*初始步長為當前t到結束點*/
            122             VDouble dT=(1-T);
            123             GetP(T+dT,X1,Y1);
            124             VBool AtTail=true;
            125             while(true)
            126             {
            127                 /*取半步,檢查目標點與當前點的長度*/
            128                 VDouble dTHalf=dT/2;
            129                 GetP(T+dTHalf,X2,Y2);
            130                 VDouble Length=sqrt((X1-OldX)*(X1-OldX)+(Y1-OldY)*(Y1-OldY));
            131                 VDouble LengthHalf=sqrt((X2-OldX)*(X2-OldX)+(Y2-OldY)*(Y2-OldY));
            132                 /*如果半步長大于一步則取半步,繼續迭代*/
            133                 if(LengthHalf>Length)
            134                 {
            135                     dT=dTHalf;
            136                     X1=X2;
            137                     Y1=Y2;
            138                 }
            139                 else
            140                 {
            141                     /*否則,如果全步長產生的距離<=1則繪制*/
            142                     if(Length<=1.001)
            143                     { 
            144                         if(AtTail)
            145                         {
            146                             Finished=true;
            147                         }
            148                         break;
            149                     }
            150                     /*否則進行近似測量*/
            151                     else
            152                     {
            153                         dT*=1/Length;
            154                         GetP(T+dT,X1,Y1);
            155                     }
            156                 }
            157                 AtTail=false;
            158             }
            159             /*計算像素位置*/
            160             VInt X=Round(X1);
            161             VInt Y=Round(Y1);
            162             VInt dX_I=(OldX1-X)*(OldX1-X);
            163             VInt dY_I=(OldY1-Y)*(OldY1-Y);
            164             /*讓線條長度保持1*/
            165             if(Old2Available)
            166             {
            167                 if(dX_I==1 && dY_I==1)
            168                 {
            169                     OldX1=X;
            170                     OldY1=Y;
            171                     SetColor(OldX1,OldY1,RGB(255,0,0));
            172                 }
            173                 else
            174                 {
            175                     OldX1=X;
            176                     OldY1=Y;
            177                     SetColor(OldX1,OldY1,RGB(255,0,0));
            178                     SetColor(OldX2,OldY2,RGB(255,0,0));
            179                 }
            180                 Old2Available=false;
            181             }
            182             else
            183             {
            184                 if(dX_I==1 && dY_I==1)
            185                 {
            186                     OldX1=X;
            187                     OldY1=Y;
            188                     SetColor(OldX1,OldY1,RGB(255,0,0));
            189                 }
            190                 else if(dX_I==1 || dY_I==1)
            191                 {
            192                     OldX2=X;
            193                     OldY2=Y;
            194                     Old2Available=true;
            195                 }
            196             }
            197             OldX=X1;
            198             OldY=Y1;
            199             T+=dT;
            200         }
            201         if(Old2Available)
            202         {
            203             SetColor(OldX2,OldY2,RGB(255,0,0));
            204         }
            205     }
            206 };
            207 
            208 class MyForm : public VL_WinForm
            209 {
            210 protected:
            211     VL_WinDIB*        FBuffer;
            212     VL_WinDC*        FBufferDC;
            213     VL_WinDC*        FFormDC;
            214     Evaluator*        FEvaluator;
            215 
            216 public:
            217     MyForm():VL_WinForm(true)
            218     {
            219         FBuffer=new VL_WinDIB(800,600);
            220         FBufferDC=&FBuffer->DC;
            221         FFormDC=new VL_WinControlDC(GetHandle());
            222         FBufferDC->FillRect(0,0,800,600);
            223         FEvaluator=new Evaluator(FBuffer);
            224 
            225         VDouble Start=Pi_f*3/18;
            226         VDouble End=Pi_f*27/18;
            227         FBufferDC->Arc(200,200,600,400,Round(100*cos(Start))+400,Round(100*-sin(Start))+300,Round(100*cos(End))+400,Round(100*-sin(End))+300);
            228         FEvaluator->SetEllipse(200,200,600,400,Start,End);
            229         FEvaluator->DrawCurve();
            230 
            231         SetMaximizeBox(false);
            232         SetMinimizeBox(false);
            233         SetBorder(vwfbSingle);
            234         SetClientWidth(800);
            235         SetClientHeight(600);
            236         SetText(L"Vczh Ellipse");
            237         MoveCenter();
            238 
            239         OnPaint.Bind(this,&MyForm::Form_OnPaint);
            240 
            241         Show();
            242     }
            243 
            244     ~MyForm()
            245     {
            246         delete FEvaluator;
            247         delete FFormDC;
            248         delete FBuffer;
            249     }
            250 
            251     void Form_OnPaint(VL_Base* Sender)
            252     {
            253         FFormDC->Draw(0,0,FBuffer);
            254     }
            255 };
            256 
            257 void main()
            258 {
            259     new MyForm();
            260     GetApplication()->Run();
            261 }
            posted on 2008-06-12 06:02 陳梓瀚(vczh) 閱讀(2349) 評論(5)  編輯 收藏 引用 所屬分類: 2D

            評論:
            # re: 橢圓段掃描完成 2008-06-12 06:06 | 陳梓瀚(vczh)
            這個算法把里面的魔術數字“1”改成其他長度的話,可以實現比較精確的等長取樣。不過需要的迭代次數我還沒去研究,這個算法還是比較慢的。把橢圓當成未知曲線來掃描事實上是為了偷懶,嘿嘿。

            經過自己的不嚴密的論證,這個自適應步長算法可以正確掃描Bezier和橢圓,但是不能適應一切曲線。  回復  更多評論
              
            # re: 橢圓段掃描完成 2008-06-30 21:07 | lll
            const REAL& C1 = 0.552285f;
            const REAL& rx = width / 2;
            const REAL& ry = height / 2;
            const REAL& cx = x + rx;
            const REAL& cy = y + ry;



            cx + rx, cy,
            cx + rx, cy + C1 * ry,
            cx + C1 * rx, cy + ry,
            cx, cy + ry

            cx - C1 * rx, cy + ry,
            cx - rx, cy + C1 * ry,
            cx - rx, cy,
            cx - rx, cy - C1 * ry,
            cx - C1 * rx, cy - ry,
            cx, cy - ry,
            cx + C1 * rx, cy - ry,
            cx + rx, cy - C1 * ry,
            cx + rx, cy,   回復  更多評論
              
            # re: 橢圓段掃描完成 2009-01-07 16:26 | baili35
            是不是GDI所繪制的圖形都向左上放縮小一個像素的原因才導致所繪制的橢圓不是對稱的。  回復  更多評論
              
            # re: 橢圓段掃描完成[未登錄] 2009-08-08 09:00 | Jcily
            不對稱是因為默認情況GDI為了保證包圍矩形的寬高數字,而將右下角的實際繪制點使用bottomright-1.

            比如如下矩形
            ptTopLeft(1,1),ptBottomRight(2,2)
            實際畫出來只占一個像素,因為這個矩形寬高為1.與我們潛意識認為效果的不一樣。

            而GDI+卻不是這樣。
              回復  更多評論
              
            # re: 橢圓段掃描完成 2009-08-09 01:57 | 陳梓瀚(vczh)
            @Jcily
            你這個論斷在他不對稱接近10個像素(看圖)的時候是不成立的,我不知道他用的是什么算法,不過根據小道消息,GDI里面的很多曲線都使用bezier去模擬的。  回復  更多評論
              
            国产成人精品久久| 国产99精品久久| 99久久精品久久久久久清纯| 色综合久久无码中文字幕| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 久久本道综合久久伊人| 久久精品国产亚洲AV电影| 天堂久久天堂AV色综合| 一本一本久久A久久综合精品| 合区精品久久久中文字幕一区| 三级片免费观看久久| 久久综合久久伊人| 免费久久人人爽人人爽av| 国产精品久久新婚兰兰| 伊人久久大香线蕉综合Av| 久久久久久久久无码精品亚洲日韩 | 欧美日韩成人精品久久久免费看 | 伊人久久大香线蕉AV色婷婷色| 久久久久久免费视频| 亚洲综合伊人久久大杳蕉| 少妇久久久久久被弄高潮| 国产精品天天影视久久综合网| 国产午夜精品理论片久久影视| 国产成人久久精品麻豆一区| 久久精品国产第一区二区| 久久综合鬼色88久久精品综合自在自线噜噜 | 久久伊人中文无码| 中文字幕精品久久久久人妻| 久久久国产打桩机| 国产欧美久久久精品| 午夜精品久久影院蜜桃| 久久国产精品99精品国产| 精品水蜜桃久久久久久久| 久久综合亚洲色HEZYO社区| 久久er99热精品一区二区| 精品视频久久久久| 7777精品久久久大香线蕉| 精品久久久久久99人妻| 久久丫精品国产亚洲av不卡 | 精品少妇人妻av无码久久| 久久久久国产视频电影|