• <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>

            SoRoMan

            人若無(wú)名,便可專心練劍.

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              12 隨筆 :: 1 文章 :: 41 評(píng)論 :: 0 Trackbacks

            2006年9月20日 #

            http://www.cnblogs.com/soroman
            posted @ 2006-09-20 14:55 SoRoMan 閱讀(281) | 評(píng)論 (0)編輯 收藏

            2006年9月19日 #

            3D空間中的旋轉(zhuǎn)可用旋轉(zhuǎn)矩陣、歐拉角或四元數(shù)等形式來(lái)表示,他們不過(guò)都是數(shù)學(xué)工具,其中在繞任意向量的旋轉(zhuǎn)方面,旋轉(zhuǎn)矩陣和四元數(shù)兩種工具用的較多,歐拉角由于存在萬(wàn)向節(jié)死鎖等問(wèn)題,使用存在限制。

            (本文假設(shè)坐標(biāo)系為左手坐標(biāo)系中,旋轉(zhuǎn)方向?yàn)轫槙r(shí)針。)

            所求問(wèn)題:

            給定任意單位軸q(向量),求向量p(x,y,z)(或點(diǎn)p)饒q旋轉(zhuǎn)theta角度的變換后的新向量p'(或點(diǎn)p'):

            1.用四元數(shù)工具:
            -------------------------------------------------------------------------
            結(jié)論:構(gòu)造四元數(shù)變換p'= q*p*q-1,(p,q是由向量p,q擴(kuò)展成的四元數(shù))。那么,p'轉(zhuǎn)換至對(duì)應(yīng)的向量(或點(diǎn))就是變換后的新向量p'(或點(diǎn)p')。

            其中,p',q,p,q-1均為四元數(shù)。q由向量q擴(kuò)展,為q=(cos(theta/2),sin(theta/2)*q),p由向量p擴(kuò)展,為p=(0,x,y,z),q-1為q的逆,因?yàn)閝為單位四元數(shù),所以q-1=q*=(cos(theta/2),-sin(theta/2)*q)。
            -------------------------------------------------------------------------

            (這個(gè)結(jié)論的證明過(guò)程可以在網(wǎng)上找到。這里略去。)
            下面看其時(shí)間復(fù)雜度:

            首先有個(gè)三角函數(shù)的計(jì)算時(shí)間,這個(gè)可以預(yù)先計(jì)算好,花費(fèi)時(shí)間不計(jì)。考慮n個(gè)四元數(shù)相乘需進(jìn)行4*4*(n-1)=16*(n-1)次乘法,15*(n-1)次加法,因?yàn)榧臃ɑM(fèi)時(shí)間較少,這里僅考慮乘法。這里涉及到三個(gè)四元數(shù)的乘法,設(shè)一次乘法的時(shí)間為T(mén),故花費(fèi)16*2=32T

            2.旋轉(zhuǎn)矩陣工具:
            -------------------------------------------------------------------------
            結(jié)論:構(gòu)造旋轉(zhuǎn)矩陣變換Trot,則變換后的新向量p'(或點(diǎn)p')為p'= p*Trot

            其中,p'(x',y',z',1),p(x,y,z,1)為向量p',p的4D齊次坐標(biāo)表示,Trot =

            |t*x*x + c,???????t*x*y + s*z,??????t*x*z - s*y,???? 0|
            |t*x*y - s*z,????t*y*y + c,??????????t*y*z + s*x,????0|
            |t*x*z + s*y,?? t*y*z - s*x,???????t*z*z + c,????????0|
            |0,????????????????????0,???????????????????????0,????????????????????1|???

            c=cos(theta), s=sin(theta),t=1-c.
            -------------------------------------------------------------------------
            (這個(gè)結(jié)論的證明過(guò)程可以在網(wǎng)上找到。這里略去。)

            下面看其時(shí)間復(fù)雜度:

            三角函數(shù)的計(jì)算時(shí)間不計(jì)。矩陣本身的元素乘法主要是計(jì)算t*x和s*x之類,需進(jìn)行12+3=15次乘法。兩個(gè)矩陣相乘的需進(jìn)行n*n*n次乘法,這里n=4,所以花費(fèi)4*4*4=64次乘法時(shí)間,但這里有個(gè)注意的地方就是旋轉(zhuǎn)矩陣的第4維無(wú)須考慮,即可簡(jiǎn)化為3X3的矩陣。故花費(fèi)3*3*3=27次乘法時(shí)間,總共的時(shí)間為15+27=42次乘法時(shí)間。cost=42T.

            比較來(lái)看,還是使用四元數(shù)的效率要高出一些,這在要變換的點(diǎn)的數(shù)目越大時(shí),體現(xiàn)的越明顯。實(shí)際上,有很多3D引擎為了利用四元數(shù)運(yùn)算的高效率性,一般先將矩陣轉(zhuǎn)換成四元數(shù)后進(jìn)行運(yùn)算再轉(zhuǎn)回為矩陣后,再傳給DirectX或OpenGL庫(kù)函數(shù)。

            關(guān)于四元數(shù)和矩陣在向量(方向)之間的進(jìn)行插值的效率比較,見(jiàn)下篇:
            探討:物體繞任意向量的旋轉(zhuǎn)-四元數(shù)法VS.旋轉(zhuǎn)矩陣法的性能比較

            posted @ 2006-09-19 17:11 SoRoMan 閱讀(22073) | 評(píng)論 (0)編輯 收藏

            2006年9月17日 #

            感覺(jué)很多書(shū)上都沒(méi)講清楚透視投影變換的推導(dǎo)過(guò)程,自己推導(dǎo)了下,以前一直含糊的關(guān)于方形/非方形的視平面和屏幕的寬高比的問(wèn)題也有了答案.本文組織如下:

            1.相機(jī)空間到視平面的變換
            2.視平面到屏幕的變換
            3.綜合
            4.一般情形

            1.相機(jī)空間到視平面的變換


            ?????????????????????? * p (xc,0, zc)
            ???????????????????? ?/ |
            ??????????????????? ?/? |
            ?????????????????? ?/?? |
            ?????????? X??? |/???? |
            ?????????? ^???? *p' |(xp,0,zp)
            ?????????? |?? / |????? |
            ?????????? |? /? |???? ?|
            ?????????? | /?? |???? ?|
            C(cam)?|/??? |???? ?|
            --------*----|----*------------->Z
            ?????????? 0??? dx?? zc
            ???? (X-Z平面的投影示圖)

            a.透視投影一般的視景體為棱臺(tái),相機(jī)空間的物體會(huì)投影到視平面z=d,這里考慮左手坐標(biāo)系,矩陣使用行優(yōu)先方式。如圖所示,由相似三角形知識(shí)可知相機(jī)空間中的物體投影到視平面上的坐標(biāo)為:

            xp = xc*(dx/zc)
            yp = yc*(dy/zc)

            其中,xc,yc,zc為相機(jī)空間坐標(biāo),xp,yp,zp為視平面坐標(biāo),dx,dy為x,y軸向的視距view distance,視平面到camera的距離,
            故相機(jī)空間投影到視平面上的矩陣Tcp為:

            |dx 0? 0 0? |

            |0? dy 0 0? |

            |0? 0?? 1 1? |

            |0? 0?? 0 0? |

            (驗(yàn)證:Tcp右乘點(diǎn)p(xc,yc,zc,1)得點(diǎn)p'(xc*dx, yc*dy, zc, zc),轉(zhuǎn)換為3D坐標(biāo)為(xc*dx/zc, yc*dy/zc, 1),正確。)

            ********************************************************************
            注:因?yàn)檗D(zhuǎn)換過(guò)程中點(diǎn)使用的是4D齊次坐標(biāo),所以最后需轉(zhuǎn)換為3D坐標(biāo)。4D齊次坐標(biāo)(x,y,z,w)轉(zhuǎn)換為3D坐標(biāo)的方法為除以w分量,即對(duì)應(yīng)3D坐標(biāo)為(x/w,y/w,z/w)。
            ********************************************************************


            考慮dx/zc和dy/zc項(xiàng),如果dx != dy,則投影后x,y的比例會(huì)發(fā)生變化(原因:投影前坐標(biāo)比例為xc/yc,投影后為xp/yp = xc*(dx/zc)/yc*(dy/zc) = xc*dx/yc*dy),從而投影后的圖像的x,y比例會(huì)發(fā)生變形。

            ---------------------------------------------
            結(jié)論1:所以,一般都會(huì)令d=dx=dy,即x,y向的視距相同。否則,圖像失真。
            ---------------------------------------------

            考慮視角(view angle,或視野filed of view)的問(wèn)題,視角的大小不會(huì)影響到物體投影后的坐標(biāo),只會(huì)影響可視的范圍。

            在視距一樣的情況下,x,y軸的視角可以不一樣。如果一樣,那么視平面就是一個(gè)正方形的。于是有:

            tan(theta_x/2) = width_p/d
            tan(theta_y/2) = height_p/d?

            其中,theta_x,theta_y為x,y軸向的視角,width_p,height_p為視平面z=d的寬度(x軸)和高度(y軸)。
            ----------------------------------------------------------------
            結(jié)論2:視平面的寬高比rp=width_p/height_p = tan(theta_x/2)/tan(theta_y/2)。
            ----------------------------------------------------------------

            2.視平面到屏幕的變換

            下面就是視平面到屏幕的變換了,這是一個(gè)2D到2D的變換(視平面的坐標(biāo)需伸縮以填滿整個(gè)屏幕空間,即在視平面中出現(xiàn)的所有的點(diǎn)要變換到屏幕上去,同時(shí)x,y軸向的比例還要維持和變換前一樣,以免比例失真,同時(shí)視平面的坐標(biāo)原點(diǎn)和屏幕中心點(diǎn)(x0=(width_s)/2, y0=(height_s)/2)對(duì)應(yīng)),其實(shí),就是一個(gè)坐標(biāo)縮放加平移的過(guò)程:

            xs = xp*kx + x0
            ys = -yp*ky + y0
            ?
            矩陣Tps為:

            |kx???? 0??????0 0? |

            |0????? -ky????0 0? |

            |0????? 0?????? 1 0? |

            |x0?? y0??????0 1? |

            (驗(yàn)證:Tps右乘點(diǎn)p(xp,yp,zp,1)得點(diǎn)p'(xp*kx + x0, -yp*ky + y0, zp, 1),轉(zhuǎn)換為3D坐標(biāo)為(xp*kx + x0, -yp*ky + y0, zp),正確。)

            其中,kx,ky(kx>0,ky>0)為x,y軸向的縮放因子(kx=(width_s)/(width_p), ky = (height_s)/(height_p),和視距相同,kx,ky的值必須一樣,否則圖像的x,y比例又會(huì)發(fā)生變形。這里-yp*ky是因?yàn)橐话闫聊坏膟軸是向下的,跟相機(jī)空間和視平面坐標(biāo)系中的y軸方向相反。
            ------------------------------------------------------------------------------------------------
            結(jié)論3: 一般令k=kx=ky,即x,y向的縮放因子相同。否則,圖像失真。
            于是有,width_s/width_p = height_s/height_p,變化等式得,rp = width_p/height_p = width_s/height_s = rs
            所以,在x,y軸視距一樣的情況下,要想最后變換到屏幕上的圖像x,y比例不失真,必須rp=rs,即視平面的寬高比和屏幕的寬高比一樣。

            -----------------------------------------------------------------------------------------------

            ********************************************************************
            注:若屏幕寬高為W,H,當(dāng)W != H,即屏幕不為方形的時(shí)候,要確保投影到屏幕上的圖像x,y比例不失真,則x,y軸視角(或視野FOV)肯定不能相等。
            原因: 由結(jié)論2,3知,rp=width_p/height_p = tan(theta_x/2)/tan(theta_y/2)=width_s/height_s=rs=W/H。 故由W/H != 1 => theta_x != theta_Y.
            ********************************************************************

            3.綜合:

            相機(jī)空間點(diǎn)p轉(zhuǎn)換到屏幕空間點(diǎn)p',變換公式為:

            xs = xc*(dx/zc)*kx + x0 = xc*(d/zc)*k + x0
            ys = -yc*(dy/zc)*ky + y0 = -yc*(d/zc)*k + y0

            綜合變換矩陣(相機(jī)空間到屏幕空間)Tcs為:
            ?
            Tcs = Tcp*Tps =

            |d*k??? 0?????? 0 0? |

            |0????? -d*k??? 0 0? |

            |x0???? y0????? 1 1? |

            |0????? 0???????? 0? 0|

            ?其中,d為視距,k為屏幕寬高比或視平面寬高比,x0,y0為屏幕中心,注:最后需轉(zhuǎn)換為3D坐標(biāo)。

            (驗(yàn)證:Tcs右乘點(diǎn)p(xc,yc,zc,1)得點(diǎn)p'(xc*d*k + x0*zc, -yc*d*k + y0*zc, zc, zc),轉(zhuǎn)換為3D坐標(biāo)為(xc*(d/zc)*k + x0, -yc*(d/zc)*k + y0, 1),正確。)

            4.一般情形:
            ?************************************
            視距為1,x軸視角為90度,屏幕寬高為W,H.
            ************************************
            ?
            代入d=1,theta_x = PI/2,x0= W/2,y0=H/2,則視平面寬高為width_p = 2。
            要確保屏幕上的圖像x,y比例不失真,即rs=rp,有
            height_p = 2/rp=2/rs=2H/W,
            k=kx=ky=width_s/width_p = W/2.

            于是,矩陣為:

            Tcs1 =?

            |W/2??? 0?????? 0 0? |

            |0????? -W/2??? 0 0? |

            |W/2??? H/2?? 1 1? |

            |0????? 0???????? 0 0? |



            ?? |W/2??? 0????????????????? 0 0? |

            |0????? -H/2*(W/H)??? 0 0? |

            |W/2??? H/2????????????? 1 1? |

            |0????? 0?????????????????? ?0 0? |

            (可以看到,y軸的縮放因子中乘上了寬高比(aspect ratio))
            ?這個(gè)矩陣較常用。

            ---------------------
            有什么問(wèn)題,歡迎探討.
            ?

            posted @ 2006-09-17 00:34 SoRoMan 閱讀(8374) | 評(píng)論 (4)編輯 收藏

            2006年8月9日 #

            今天看到一個(gè)網(wǎng)友在談?wù)撘粋€(gè)關(guān)于The Tower of Babylon的, 見(jiàn)http://www.shnenglu.com/sicheng/archive/2006/08/09/11024.html,感覺(jué)其實(shí)就是個(gè)按關(guān)鍵字面積插入排序的問(wèn)題。于是用插入排序算法實(shí)現(xiàn)如下。

            簡(jiǎn)單測(cè)試了下,應(yīng)該沒(méi)問(wèn)題。
            We have 4 kinds of blocks, they are:
            (1,1,1)
            (1,2,3)
            (2,3,4)
            (2,3,2)
            Building the tower of babylon...
            The max height of tower is: 18.
            Totally 7 blocks are used, they are:
            (1) block (1,1,1), area = 1
            (2) block (1,2,3), area = 2
            (3) block (1,2,3), area = 3
            (4) block (2,3,2), area = 4
            (5) block (2,3,4), area = 6
            (6) block (2,3,4), area = 8
            (7) block (2,3,4), area = 12

            ------------------------------------
            TowerOfBabylon.cpp:
            ------------------------------------
            //
            // File: [TowerOfBabylon.cpp]
            // Description:[This program illustrates how to get the Tower Of Babylon. the Tower Of Babylon: Given N kinds of blocks,
            // you need to buid the tower under the condition that every upper block's area should less than the lower one.]
            // Author:[SoRoMan]
            // Date:[2006-08-08]
            // Version:[2.0]
            // History: [1.0: initial draft.
            // 2.0: add a new type TOWER
            // 3.0: chnage the sequence data structure to list structure to avoid memory access violation.]
            //

            // INCLUDES //////////////////////////////////////////////////////////////////////////
            #include "stdio.h"
            #include "malloc.h"

            // DEFINES //////////////////////////////////////////////////////////////////////////
            #define N 4

            // TYPES //////////////////////////////////////////////////////////////////////////
            typedef struct BLOCK_TYP
            {
            ?int x,y,z;
            ?int area;
            ?int height;
            ?
            ?BLOCK_TYP *pNext;
            } BLOCK, *BLOCK_PTR;

            typedef struct TOWER_TYP
            {
            ?int height;
            ?int num_block;

            ?BLOCK_PTR pTowerTop;
            } TOWER, *TOWER_PTR;

            // PROTOTYPES //////////////////////////////////////////////////////////////////////////
            TOWER_PTR BuildTower(BLOCK_PTR pBlock, int n);

            // FUNCTIONS //////////////////////////////////////////////////////////////////////////
            int main(int argc, wchar_t* argv[])
            {
            ?BLOCK blocks[N] = {{1,1,1},{2,2,2},{3,3,3},{4,4,4}};

            ?printf("We have %d kinds of blocks, they are:\n", N);
            ?int i;
            ?for(i = 0; i < N; i++)
            ?{
            ? printf("(%d,%d,%d)\n", blocks[i].x, blocks[i].y, blocks[i].z);
            ?}
            ?printf("Building the tower of babylon...\n");

            ?TOWER_PTR pT = BuildTower(blocks, N);
            ?printf("The max height of tower is: %d.\nTotally %d blocks are used, they are:\n", pT->height, pT->num_block );

            ?BLOCK_PTR pBlock = pT->pTowerTop;
            ?for(i = 0; i < pT->num_block; i++)
            ?{
            ??????? printf("(%d) block (%d,%d,%d), area = %d, height = %d\n", i+1, pBlock->x, pBlock->y, pBlock->z, pBlock->area, pBlock->height);?
            ??pBlock = pBlock->pNext;
            ?}

            ?getchar();

            ?return 0;
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Algorithm of building the Tower Of Babylon.
            // Input Parameters: pBlock: pointer variable that identifies blocks sequence.
            // n: int variable that identifies how many kinds of blocks.
            // Output Parameters: None.
            // Return: pointer variable that identifies the built tower.
            ////////////////////////////////////////////////////////////////////////////////
            TOWER_PTR BuildTower(BLOCK_PTR pBlock, int n)
            {
            ?int index_block = 0;
            ?TOWER_PTR pTower = new TOWER();
            ?BLOCK_PTR pTop = new BLOCK();?
            ?pTower->pTowerTop = pTop;

            ?// initialize tower
            ?pTower->pTowerTop->x = pBlock->x;
            ?pTower->pTowerTop->y = pBlock->y;
            ?pTower->pTowerTop->z = pBlock->z;

            ?pTower->pTowerTop->area = (pBlock->x)*(pBlock->y);
            ?pTower->pTowerTop->height = pBlock->z;
            ?pTower->height = pTower->pTowerTop->height;
            ?pTower->num_block = 1;
            ???
            ?for(int i = 1; i < 3*n; i++)
            ?{
            ? index_block = i/3;
            ? if (i%3 == 0) // condition 1, area = x*y, height = z.
            ? {
            ?? (pBlock+index_block)->area = ((pBlock+index_block)->x)*((pBlock+index_block)->y);
            ?? (pBlock+index_block)->height = (pBlock+index_block)->z;
            ? }
            ? else if (i%3 == 1) // condition 2, area = x*z, height = y.
            ? {
            ?? (pBlock+index_block)->area = ((pBlock+index_block)->x)*((pBlock+index_block)->z);
            ?? (pBlock+index_block)->height = (pBlock+index_block)->y;
            ? }
            ? else // condition 3, area = y*z, height = z.
            ? {
            ?? (pBlock+index_block)->area = ((pBlock+index_block)->y)*((pBlock+index_block)->z);
            ?? (pBlock+index_block)->height = (pBlock+index_block)->x;
            ? }
            ?
            ? bool bNeedToBeAdded = true;?

            ? BLOCK_PTR pB = pTower->pTowerTop;
            ? BLOCK_PTR pPrev = pTower->pTowerTop;
            ? while(pB != NULL)
            ? {
            ?? if ((pBlock+index_block)->area < (pB->area))
            ?? {
            ?// insert new block
            ?BLOCK_PTR pNewBlock = new BLOCK();?
            ??? *pNewBlock = *(pBlock+index_block);

            ?if(pB == pPrev)
            ?{
            ??pNewBlock->pNext = pB;
            ??pTower->pTowerTop = pNewBlock;
            ?}
            ?else
            ?{
            ??pNewBlock->pNext = pPrev->pNext;
            ??pPrev->pNext = pNewBlock;
            ?}
            ?
            ??? // increase number of blocks
            ??? pTower->num_block++;
            ??? // increase height of tower
            ??? pTower->height += (pBlock+index_block)->height;
            ???
            ??? bNeedToBeAdded = false;
            ??? break;
            ?? }
            ?? else if ((pBlock+index_block)->area == (pB->area))
            ?? {
            ??? if (pB->height < ((pBlock+index_block)->height))
            ??? {
            ???? // increase height of tower
            ???? pTower->height += (pBlock+index_block)->height - pB->height;
            ???? // replace blocks
            ? BLOCK_PTR pNewBlock = new BLOCK();?
            ? *pNewBlock = *(pBlock+index_block);

            ? if (pB == pPrev)
            ? {
            ??pNewBlock->pNext = pB->pNext;
            ??pTower->pTowerTop = pNewBlock;
            ? }
            ? else
            ? {
            ?? pNewBlock->pNext = pB->pNext;
            ?? pPrev->pNext = pNewBlock;
            ? }
            ??? }

            ??? bNeedToBeAdded = false;
            ??? break;
            ?? }

            ?? pPrev = pB;
            ?? pB = pB->pNext;
            ? }
            ?
            ? if(bNeedToBeAdded)
            ? {
            ?? // add new block at the end
            ?? BLOCK_PTR pNewBlock = new BLOCK();?
            ?? *pNewBlock = *(pBlock+index_block);
            ??
            ?? pPrev->pNext = pNewBlock;
            ?? pNewBlock->pNext = NULL;

            ?? // increase number of blocks
            ?? pTower->num_block++;
            ?? // increase height of tower
            ?? pTower->height += (pBlock+index_block)->height;
            ? }
            ?}

            ?return pTower;
            }

            ?

            ?

            ?

            ?

            posted @ 2006-08-09 17:32 SoRoMan 閱讀(2597) | 評(píng)論 (2)編輯 收藏

            2006年8月8日 #

            本文只是讀者的一些關(guān)于左右坐標(biāo)系的探討,有待繼續(xù)挖掘。
            參考資料:Real-Time Rendering second edtion

            一般左右坐標(biāo)系的定義是這樣說(shuō)的:
            在左手坐標(biāo)系中,坐標(biāo)軸的定義符合左手法則:左手四個(gè)手指的旋轉(zhuǎn)方向從X軸到Y(jié)軸,大拇指的指向就是Z軸。但是沒(méi)有給出數(shù)學(xué)上的定義。參考一些資料,關(guān)于左右坐標(biāo)系的定義,涉及到向量叉積與左右坐標(biāo)系的關(guān)系。

            從基說(shuō)起:
            基是n維的歐式空間中的一組線性無(wú)關(guān)的向量V0,V1,...,Vn-1。關(guān)于線性無(wú)關(guān)向量組的定義可以去參考其他資料。

            基與坐標(biāo)系的關(guān)系:
            如果一個(gè)基的行列式為正,那么它就可以形成一個(gè)右手坐標(biāo)系。如果為負(fù)則形成左手坐標(biāo)系。

            向量叉積與三維左右坐標(biāo)系的關(guān)系:
            那么向量叉積與左右坐標(biāo)系的關(guān)系有什么關(guān)系呢?由基與坐標(biāo)系的關(guān)系可以推知,比如在三維歐式空間中,設(shè)有一個(gè)基(向量組)(Vx,Vy,Vz)存在,那么我們知道行列式的表達(dá)式|Vx,Vy,Vz|=(Vx*Vy).Vz,可以得知,當(dāng)向量Vz的方向與向量Vx*Vy(Vx與Vy的叉積)的夾角在0-PI/2之間的時(shí)候,就一定會(huì)有(Vx*Vy).Vz>0,那么由基(向量組)Vx,Vy,Vz組成的坐標(biāo)系就為右手坐標(biāo)系。其實(shí),說(shuō)白了,就是向量叉積的方向規(guī)定了左右坐標(biāo)系的定義。

            三維x,y,z左右手坐標(biāo)系特例:
            令三維歐式空間空存在三向量Vx=(x,0,0)(x>0),Vy=(0,y,0)(y>0),Vz=(0,0,z)(注:這里規(guī)定z軸的正方向和向量Vx*Vy的方向一致。)此時(shí),向量Vx*Vy的方向是符合右手坐標(biāo)系的,因?yàn)橄蛄縑x*Vy的方向與其自身的夾角為0,由(Vx*Vy).Vz = xyz可知,當(dāng)z>0時(shí),該向量組((x,0,0),(0,y,0),(0,0,z))構(gòu)成右手坐標(biāo)系。反之,若z<0,那么由(Vx*Vy).Vz = xyz<0可知,該向量組((x,0,0),(0,y,0),(0,0,z))構(gòu)成左手坐標(biāo)系。特例:(1,0,0),(0,1,0),(0,0,1)構(gòu)成右手坐標(biāo)系,(1,0,0),(0,1,0),(0,0,-1)構(gòu)成左手坐標(biāo)系。

            posted @ 2006-08-08 12:53 SoRoMan 閱讀(4792) | 評(píng)論 (0)編輯 收藏

            2006年7月31日 #

            //
            // File: [TestSort.cpp]
            // Description:[This file illustrate the sort methods. Make sure the length of the sequence consistent with its contents!]?
            // Author:[SoRoMan]
            // Date:[07/31/2006]
            // Version:[1.0]
            // History: []
            //?

            // INCLUDES ///////////////////////////////////////////////
            #include "stdio.h"

            // DEFINES ////////////////////////////////////////////////
            #define N 11

            // PROTOTYPES /////////////////////////////////////////////
            void QuickSort(int *seq, int lenght);
            void InsertSort(int *seq, int lenght);
            void InsertSort2(int *seq, int lenght);
            void ShellSort(int *seq, int lenght);
            void IncrementInsertSort(int *seq, int length, int increment);
            void HeapSort(int *seq, int length);
            void SelectionSort(int *seq, int length);
            void BubbleSort(int *seq, int length);
            void BiBubbleSort(int *seq, int length);
            void AdjustHeap(int *seq, int startIndex, int endIndex);

            // GLOBALS ////////////////////////////////////////////////
            int nAssignmentOperation = 0; // assignment counter
            int nComparsionOperation = 0; // comparsion counter

            // FUNCTIONS //////////////////////////////////////////////

            int main(int argc, char* argv[])
            {
            ?printf("0: Original Sequence\n");
            ?printf("1: Quick Sort\n");
            ?printf("2: Insert Sort\n");
            ?printf("3: Shell Sort\n");
            ?printf("4: Insert Sort2\n");
            ?printf("5: Heap Sort\n");
            ?printf("6: Selection Sort\n");
            ?printf("7: Bubble Sort\n");
            ?printf("8: Bi-Bubble Sort\n");
            ?printf("-1: Exit\n");?

            ?int cat = 0;?
            ?while (cat != -1)
            ?{
            ??// clear counter
            ??nAssignmentOperation = 0;
            ??nComparsionOperation = 0;

            ??//int array[N] = {600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,
            ??//600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1,600, 64,6,78,246,445,345,445,7,4885,1};
            ??int array[N] = {600, 64,6,78,246,445,345,445,7745,4885,1};

            ??printf("\nPlease select sort method:");
            ??scanf("%d", &cat);
            ??printf("-------------------------------------------------\n");

            ??switch(cat)
            ??{
            ???case 0:printf("No Sort. The Original Sequence is\n");
            ????break;
            ???case 1:printf("Quick Sort\n"); QuickSort(array, N);
            ????break;
            ???case 2:printf("Insert Sort\n"); InsertSort(array, N);
            ????break;
            ???case 3:printf("Shell Sort\n"); ShellSort(array, N);
            ????break;
            ???case 4:printf("Insert Sort2\n"); InsertSort2(array, N);
            ????break;
            ???case 5:printf("Heap Sort\n"); HeapSort(array, N);
            ????break;
            ???case 6:printf("Selection Sort\n"); SelectionSort(array, N);
            ????break;
            ???case 7:printf("Bubble Sort\n"); BubbleSort(array, N);
            ????break;
            ???case 8:printf("Bi-Bubble Sort\n"); BiBubbleSort(array, N);
            ????break;
            ???default:printf("Exit...\n");
            ????return 0;
            ??}

            ??for(int i = 0; i < N; i++)
            ??{
            ???printf("int = %d\n", array[i]);
            ??}

            ??printf("Count of comparsion operation? = %d\n", nComparsionOperation);
            ??printf("Count of assignment operation? = %d\n", nAssignmentOperation);
            ??printf("-------------------------------------------------\n");
            ?}

            ?return 0;
            }

            inline void Swap(int *pCurrPost, int *pCurrKey)
            {
            ?nAssignmentOperation += 3;
            ?int temp;

            ?//swap value
            ?temp = *pCurrPost;
            ?*pCurrPost = *pCurrKey;
            ?*pCurrKey = temp;
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Quick Sort algorithm.? (By SoRoMan, 2006.7.31)
            // 快速排序的基本思想是基于分治策略的。對(duì)于輸入的子序列L[p..r],如果規(guī)模足夠小則直接進(jìn)行排序(比如用前述的冒泡、選擇、插入排序均可),否則分三步處理:
            // 1.分解(Divide):將待排序列L[p..r]劃分為兩個(gè)非空子序列L[p..q]和L[q+1..r],使L[p..q]中任一元素的值不大于L[q+1..r]中任一元素的值。具體可通過(guò)這樣的途徑實(shí)現(xiàn):在序列L[p..r]中選擇數(shù)據(jù)元素L[q],經(jīng)比較和移動(dòng)后,L[q]將處于L[p..r]中間的適當(dāng)位置,使得數(shù)據(jù)元素L[q]的值小于L[q+1..r]中任一元素的值。
            // 2.遞歸求解(Conquer):通過(guò)遞歸調(diào)用快速排序算法,分別對(duì)L[p..q]和L[q+1..r]進(jìn)行排序。
            // 3.合并(Merge):由于對(duì)分解出的兩個(gè)子序列的排序是就地進(jìn)行的,所以在L[p..q]和L[q+1..r]都排好序后不需要執(zhí)行任何計(jì)算L[p..r]就已排好序,即自然合并。
            // 這個(gè)解決流程是符合分治法的基本步驟的。因此,快速排序法是分治法的經(jīng)典應(yīng)用實(shí)例之一。
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void QuickSort(int *seq, int length)
            {
            ?if(length <= 1)
            ?{
            ??return;
            ?}
            ?else
            ?{
            ??int post = *seq; // set post
            ??int *pCurrPost = seq; // set current position of post
            ??int *pCurrKey; // current position of key

            ??for(int j = length - 1, i = 1; i <= j;)
            ??{
            ???// handle the right sub-sequence
            ???while(i <= j)
            ???{
            ????pCurrKey = seq + j;

            ????if(*pCurrKey < post)
            ????{
            ?????Swap(pCurrPost, pCurrKey);
            ?????pCurrPost = pCurrKey;

            ?????break;
            ????}
            ????else
            ????{
            ?????j--;
            ????}

            ????nComparsionOperation ++;
            ???}

            ???// handle the left sub-sequence
            ???while(i <= j)
            ???{
            ????pCurrKey = seq + i;

            ????if(*pCurrKey > post)
            ????{
            ?????Swap(pCurrPost, pCurrKey);
            ?????pCurrPost = pCurrKey;

            ?????break;
            ????}
            ????else
            ????{
            ?????i++;
            ????}

            ????nComparsionOperation ++;
            ???}
            ??}
            ??// handle two sub sequences recursively
            ??int lleng = pCurrPost - seq; // left sub sequence
            ??int rleng = length - lleng - 1; // right sub sequence
            ??QuickSort(seq, lleng);
            ??QuickSort(seq + lleng + 1, rleng);
            ?}
            }


            ////////////////////////////////////////////////////////////////////////////////
            // Insert Sort algorithm (A special increment insert sort, increment = 1).? (By SoRoMan, 2006.7.31)
            //插入排序的基本思想是,經(jīng)過(guò)i-1遍處理后,L[1..i-1]己排好序。第i遍處理僅將L[i]插入L[1..i-1]的適當(dāng)位置,使得L[1..i]又是排好序的序列。要達(dá)到這個(gè)目的,我們可以用順序比較的方法。首先比較L[i]和L[i-1],如果L[i-1]≤ L[i],則L[1..i]已排好序,第i遍處理就結(jié)束了;否則交換L[i]與L[i-1]的位置,繼續(xù)比較L[i-1]和L[i-2],直到找到某一個(gè)位置j(1≤j≤i-1),使得L[j] ≤L[j+1]時(shí)為止。
            //簡(jiǎn)言之,插入排序就是每一步都將一個(gè)待排數(shù)據(jù)按其大小插入到已經(jīng)排序的數(shù)據(jù)中的適當(dāng)位置,直到全部插入完畢。插入排序方法分直接插入排序和折半插入排序兩種,這里只介紹直接插入排序,折半插入排序留到“查找”內(nèi)容中進(jìn)行
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void InsertSort(int *seq, int length)
            {
            ?IncrementInsertSort(seq, length, 1);
            }

            void InsertSort2(int *seq, int length)
            {
            ?for(int i = 1; i < length; i++)
            ?{
            ??for (int j = 0; j < i; j++)
            ??{
            ???if(*(seq + i) < *(seq + j))
            ???{?
            ????int temp = *(seq + i);
            ????nAssignmentOperation ++;

            ????// insert, move (i-j) items
            ????for(int k = i; k > j; k-- )
            ????{
            ?????*(seq + k) = *(seq + k - 1);
            ?????nAssignmentOperation ++;
            ????}

            ????*(seq + k) = temp;
            ????nAssignmentOperation ++;

            ????nComparsionOperation ++;

            ????break;
            ???}
            ??}
            ?}
            }

            void IncrementInsertSort(int *seq, int length, int increment)
            {
            ?for(int k = 0; k < increment; k++)
            ?{
            ??for (int i = increment + k; i < length; i+=increment + k)
            ??{
            ???int temp = *(seq + i);
            ???for (int j = i; j > increment - 1;)
            ???{
            ????nComparsionOperation ++;

            ????if(temp > *(seq + j - increment))
            ????{????
            ?????*(seq + j) = *(seq + j - increment);
            ?????nAssignmentOperation ++;
            ?????j-=increment;
            ????}
            ????else
            ????{
            ?????break;
            ????}
            ???}

            ???*(seq + j) = temp;
            ???nAssignmentOperation ++;????
            ??}
            ?}?
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Shell Sort algorithm (Increment insert sort, increment = increment/3 + 1.).? (By SoRoMan, 2006.7.31)
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void ShellSort(int *seq, int length)
            {
            ?for(int increment = length; increment > 1;)
            ?{
            ??increment = increment/3 + 1;
            ??IncrementInsertSort(seq, length, increment);
            ?}
            }


            ////////////////////////////////////////////////////////////////////////////////
            // Heap Sort algorithm.? (SoRoMan, 2006.7.31)
            //
            //1.堆的概念:
            //堆是一個(gè)關(guān)鍵字序列{k1,k2,…,kn},它具有如下特性:
            //ki ≤k2i, ki ≤ k2i+1
            //或ki ≥ k2i,ki ≥ k2i+1(i=1,2,…, └n/2┘)
            //堆的特性在完全二叉樹(shù)中解釋為:完全二叉樹(shù)中任一結(jié)點(diǎn)的關(guān)鍵字都小于等于(或大于等于)它的左右孩子的關(guān)鍵字。
            //如下列關(guān)鍵字序列均是堆: {5,23,16,68,94,72,71,73} (小頂堆) {96,83,27,38,11,9} (大頂堆) 由堆的定義可知:若關(guān)鍵字序列{k1,k2,…,kn}是堆,則堆頂元素是n個(gè)元素序列中的最小(或最大)元素。

            //2.基本思想:
            //首先將初始待排序記錄序列建堆,則堆頂元素必為含最大關(guān)鍵字或最小關(guān)鍵字的記錄,輸出該記錄,然后將剩余記錄再調(diào)整為堆,如此反復(fù),直至排序結(jié)束。
            //在堆排序主要需解決兩個(gè)問(wèn)題:
            //① 如何建堆? 在完全二叉樹(shù)中,所有序號(hào)i>└n/2┘的結(jié)點(diǎn)都是葉子,因此,以這些結(jié)點(diǎn)為根的子樹(shù)均已是堆,這樣只需將以序號(hào)為└n/2┘, └n/2┘-1, └n/2┘-2,…,1的結(jié)點(diǎn)為根、的子樹(shù)都調(diào)整為堆即可。在按此次序調(diào)整每個(gè)結(jié)點(diǎn)時(shí),其左、右子樹(shù)均已是堆。
            //② 若ki的左、右子樹(shù)已經(jīng)是堆,如何將以ki為根的完全二叉樹(shù)也調(diào)整為堆? 因ki的左、右子樹(shù)已經(jīng)是堆,所以必須在ki 和它的左、右孩子中選出最小(或最大)的結(jié)點(diǎn)放到ki的位置上,不妨設(shè)k2I關(guān)鍵字最小,將ki與k2I交換位置,而交換之后有可能導(dǎo)致以k2I為根的子樹(shù)不再為堆,于是可重復(fù)上述過(guò)程,將以k2I為根的子樹(shù)調(diào)整為堆,……,如此逐層下去,最多可能一直調(diào)整到樹(shù)葉,此方法稱為"篩選法"。

            //3.性能分析:
            //堆排序的時(shí)間主要由建立初始堆和不斷重復(fù)建堆這兩部分的時(shí)間開(kāi)銷構(gòu)成。其中:建立初始堆時(shí),總共需進(jìn)行的關(guān)鍵字比較次數(shù) ≤ 4n =O(n) ;排序過(guò)程中進(jìn)行n-1次重建堆所進(jìn)行的總比較次數(shù)不超過(guò)下式: 2*(└ log2(n-1) ┘+└ log2(n-2) ┘+…+ └ log22 ┘) < 2n └ log2n ┘=O(n log2n)因此堆排序總的時(shí)間復(fù)雜度是 O(n+ n log2n)= O(n log2n)。
            //堆排序在最壞情況下的時(shí)間復(fù)雜度也是O(nlog2n),相對(duì)于快速排序來(lái)說(shuō),這是堆排序的最大優(yōu)點(diǎn)。
            //另外,堆排序僅需一個(gè)記錄大小供交換用的輔助空間。由于建初始堆所需的比較次數(shù)較多,所以堆排序不適宜于記錄較少的文件,但對(duì)n較大的文件還是很有效的。
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void HeapSort(int *seq, int length)
            {
            ?for(int n = length; n > 0; n--)
            ?{
            ??for(int j = n/2; j > 0; j--)
            ??{
            ???AdjustHeap(seq, j, n);
            ??}

            ??Swap(seq, seq+n-1);??
            ?}?
            }

            void AdjustHeap(int *seq, int startIndex, int endIndex)
            {
            ?while(2*startIndex <= endIndex)
            ?{
            ??int i =? startIndex - 1;
            ??startIndex = startIndex*2;

            ??nComparsionOperation ++;
            ??if (startIndex < endIndex && *(seq + startIndex -1) < *(seq + startIndex))
            ??{
            ???startIndex++;
            ??}

            ??nComparsionOperation ++;
            ??if(*(seq + startIndex -1) > *(seq + i))
            ??{
            ???Swap(seq + startIndex - 1, seq + i);
            ??}??
            ??else
            ??{
            ???break;
            ??}
            ?}
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Selection Sort algorithm.? (SoRoMan, 2006.7.31)
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void SelectionSort(int *seq, int length)
            {
            ?for(int i = 0; i < length; i++)
            ?{
            ??int k = i;
            ??for(int j = i+1; j < length; j++)
            ??{
            ???nComparsionOperation ++;
            ???if (*(seq + j) < *(seq + k))
            ???{
            ????k = j;
            ???}
            ??}

            ??Swap(seq + k, seq + i);
            ?}
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Bubble Sort algorithm.? (SoRoMan, 2006.7.31)
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void BubbleSort(int *seq, int length)
            {
            ?for(int i = 0; i < length; i++)
            ?{
            ??for(int j = length-1; j > i; j--)
            ??{
            ???nComparsionOperation ++;
            ???if (*(seq + j) < *(seq + j - 1))
            ???{
            ????Swap(seq + j, seq + j - 1);
            ???}
            ??}
            ?}
            }

            ////////////////////////////////////////////////////////////////////////////////
            // Bi-Directinal Bubble Sort algorithm.? (SoRoMan, 2006.7.31)
            //思想:
            //基于在一趟排序中,位于最后一次交換關(guān)鍵字的的后面的關(guān)鍵字序列已經(jīng)是有序的,所以不用再排序。
            //相對(duì)于一般的冒泡排序,可以減少關(guān)鍵字比較次數(shù),但交換次數(shù)不變。
            // Input Parameters: seq: pointer variable that identifies which sequence will be sorted.
            // length: int that identifies the length of the sequence.
            // Output Parameters: None.
            // Return: None.
            ////////////////////////////////////////////////////////////////////////////////
            void BiBubbleSort(int *seq, int length)
            {
            ?int k,low,up;
            ?low = 0;
            ?up = length-1;
            ?while (up > low)
            ?{
            ??k = low;??

            ??for(int i = low; i < up; i++)
            ??{
            ???nComparsionOperation ++;
            ???if (*(seq + i) > *(seq + i + 1))
            ???{
            ????Swap(seq + i, seq + i + 1);

            ????k = i;
            ???}
            ??}

            ??up = k;

            ??for(int j = up; j > low; j--)
            ??{
            ???nComparsionOperation ++;
            ???if (*(seq + j) < *(seq + j - 1))
            ???{
            ????Swap(seq + j, seq + j - 1);

            ????k = j;
            ???}
            ??}?

            ??low = k;
            ?}

            }

            ?

            ?


            ?

            posted @ 2006-07-31 15:14 SoRoMan 閱讀(1241) | 評(píng)論 (0)編輯 收藏

            2006年7月27日 #

            以前看到Bresenham畫(huà)線算法,直接拿來(lái)用,沒(méi)有去推導(dǎo)它,近日,參考一些資料,特整理其算法推導(dǎo)過(guò)程如下。各位大蝦如果知道其細(xì)節(jié),趕緊閃過(guò),不用浪費(fèi)時(shí)間了。

            基本上Bresenham畫(huà)線算法的思路如下:

            // 假設(shè)該線段位于第一象限內(nèi)且斜率大于0小于1,設(shè)起點(diǎn)為(x1,y1),終點(diǎn)為(x2,y2).
            // 根據(jù)對(duì)稱性,可推導(dǎo)至全象限內(nèi)的線段.
            1.畫(huà)起點(diǎn)(x1,y1).
            2.準(zhǔn)備畫(huà)下個(gè)點(diǎn)。x坐標(biāo)增1,判斷如果達(dá)到終點(diǎn),則完成。否則,由圖中可知,下個(gè)要畫(huà)的點(diǎn)要么為當(dāng)前點(diǎn)的右鄰接點(diǎn),要么是當(dāng)前點(diǎn)的右上鄰接點(diǎn).
            2.1.如果線段ax+by+c=0與x=x1+1的交點(diǎn)的y坐標(biāo)大于M點(diǎn)的y坐標(biāo)的話,下個(gè)點(diǎn)為U(x1+1,y1+1)
            2.2.否則,下個(gè)點(diǎn)為B(x1+1,y1+1)
            3.畫(huà)點(diǎn)(U或者B).
            4.跳回第2步.
            5.結(jié)束.


            這里需要細(xì)化的是怎么判斷下個(gè)要畫(huà)的點(diǎn)為當(dāng)前點(diǎn)的右鄰接點(diǎn)還是當(dāng)前點(diǎn)的右上鄰接點(diǎn).

            設(shè)線段方程:ax+by+c=0(x1<x<x2,y1<y<y2)
            令dx=x2-x1,dy=y2-y1
            則:斜率-a/b = dy/dx.

            從第一個(gè)點(diǎn)開(kāi)始,我們有F(x,1,y1) = a*x1+b*y1+c=0
            下面求線段ax+by+c=0與x=x1+1的交點(diǎn):
            由a*(x1+1)+b*y+c = 0, 求出交點(diǎn)坐標(biāo)y=(-c-a(x1+1))/b
            所以交點(diǎn)與M的y坐標(biāo)差值Sub1 = (-c-a(x1+1))/b - (y1+0.5) = -a/b-0.5,即Sub1的處始值為-a/b-0.5。

            則可得條件當(dāng) Sub1 = -a/b-0.5>0時(shí)候,即下個(gè)點(diǎn)為U.
            反之,下個(gè)點(diǎn)為B.
            代入a/b,則Sub1 = dy/dx-0.5.

            因?yàn)槭莻€(gè)循環(huán)中都要判斷Sub,所以得求出循環(huán)下的Sub表達(dá)式,我們可以求出Sub的差值的表達(dá)式.下面求x=x1+2時(shí)的Sub,即Sub2
            1.如果下下個(gè)點(diǎn)是下個(gè)點(diǎn)的右上鄰接點(diǎn),則
            Sub2 = (-c-a(x1+2))/b - (y1+1.5) = -2a/b - 1.5
            故Sub差值Dsub = Sub2 - Sub1 = -2a/b - 1.5 - (-a/b-0.5) = -a/b - 1.代入a/b得Dsub = dy/dx -1;
            2.如果下下個(gè)點(diǎn)是下個(gè)點(diǎn)的右鄰接點(diǎn),
            Sub2 = (-c-a(x1+2))/b - (y1+0.5) = -2a/b - 0.5
            故Sub差值Dsub = Sub2 - Sub1 = -2a/b - 0.5 - (-a/b-0.5) = -a/b. 代入a/b得Dsub = dy/dx;

            于是,我們有了Sub的處始值Sub1 = -a/b-0.5 = dy/dx-0.5,又有了Sub的差值的表達(dá)式Dsub = dy/dx -1 (當(dāng)Sub1 > 0)或 dy/dx(當(dāng)Sub1 < 0).細(xì)化工作完成。

            于是pcode可以細(xì)化如下:

            // Pcode for Bresenham Line
            // By SoRoMan
            x=x1;
            y=y1;
            dx = x2-x1;
            dy = y2-y1;
            Sub = dy/dx-0.5; // 賦初值,下個(gè)要畫(huà)的點(diǎn)與中點(diǎn)的差值

            DrawPixel(x, y); // 畫(huà)起點(diǎn)
            while(x<x2)
            {
            ?x++;
            ?if(Sub > 0) // 下個(gè)要畫(huà)的點(diǎn)為當(dāng)前點(diǎn)的右上鄰接點(diǎn)
            ?{
            ? Sub += dy/dx - 1; //下下個(gè)要畫(huà)的點(diǎn)與中點(diǎn)的差值
            ? y++; // 右上鄰接點(diǎn)y需增1
            ?}
            ?else// 下個(gè)要畫(huà)的點(diǎn)為當(dāng)前點(diǎn)的右鄰接點(diǎn)
            ?{
            ? Sub += dy/dx;?
            ?}
            // 畫(huà)下個(gè)點(diǎn)
            DrawPixel(x,y);
            }

            PS:一般優(yōu)化:
            為避免小數(shù)轉(zhuǎn)整數(shù)以及除法運(yùn)算,由于Sub只是用來(lái)進(jìn)行正負(fù)判斷,所以可以令Sub = 2*dx*Sub = 2dy-dx,則
            相應(yīng)的DSub = 2dy - 2dx或2dy.

            思考1:如果Sub = 0時(shí),會(huì)產(chǎn)生取兩個(gè)點(diǎn)都可以的問(wèn)題。這個(gè)問(wèn)題還沒(méi)深入。

            posted @ 2006-07-27 11:07 SoRoMan 閱讀(24399) | 評(píng)論 (4)編輯 收藏

            2006年7月26日 #

            思考:計(jì)算機(jī)圖形學(xué)中的左上像素填充約定(top-left filling convention for filling geometry)

            我們知道目前顯示器顯示的原理,光柵化顯示最小的單元是pixel(或者說(shuō)精度為piexl),一個(gè)pixel所占的區(qū)域一般是個(gè)正方形,顯示器上的畫(huà)面就由一個(gè)或多個(gè)這樣的小方格組成。如果以每個(gè)小方格為一個(gè)單元來(lái)制定屏幕坐標(biāo)的話,問(wèn)題就來(lái)了,因?yàn)榉礁癖旧碛写笮。皇且粋€(gè)嚴(yán)格意義上的"點(diǎn)"。

            問(wèn)題來(lái)源:屏幕坐標(biāo)點(diǎn)的選取以及像素方格本身的大小
            如果以方格中心點(diǎn)為基準(zhǔn)制定坐標(biāo)點(diǎn)(即對(duì)于任意一整數(shù)坐標(biāo)點(diǎn)p(x,y),p必為某個(gè)像素方格的中心),以一個(gè)方格為跨度來(lái)制定屏幕坐標(biāo)系的話。如圖,屏幕上3X3的方格組成一個(gè)正方形的畫(huà)面,如果按照方格中心點(diǎn)為基準(zhǔn)制定坐標(biāo)點(diǎn),其區(qū)域屏幕坐標(biāo)為(0,0,2,2)(注意:0,1,2都位于方格中心,其中,左上角坐標(biāo)為(0,0),右下角坐標(biāo)為(2,2)),而按照數(shù)學(xué)運(yùn)算,其上下跨距就是2-0 = 2 pixels,左右跨距2-0 = 2 pixels,即總共包含2X2=4個(gè)方格.而實(shí)際畫(huà)面中的跨距是3X3,即共包含9個(gè)方格(從最左上端到最右下端),問(wèn)題來(lái)了,前后矛盾了。左上像素填充約定可以解決這個(gè)問(wèn)題。

            問(wèn)題解決:左上像素填充約定
            還是舉剛才的例子,如果給定左上角坐標(biāo)為(0,0),右下角坐標(biāo)為(2,2)的矩形區(qū)域,叫顯示設(shè)備去繪制的話,按照左上像素填充約定,在屏幕上填充的像素點(diǎn)將是:(0,0),(0,1),(1,0),(1,0)這個(gè)2X2區(qū)域,而非圖中所示的3X3區(qū)域。反過(guò)來(lái)說(shuō)圖中所示的3X3區(qū)域要用坐標(biāo)表示的話應(yīng)該是(0,0,3,3)。簡(jiǎn)單來(lái)說(shuō),在左上像素填充約定下,要填充(x1,y1,x2,y2)(x1,y1,x2,y2為整數(shù))的矩形,實(shí)際填充的區(qū)域會(huì)是(x1-0.5,y1-0.5,x2-0.5,y2-0.5),這個(gè)區(qū)域的左上角像素坐標(biāo)為(x1,y1),右下角像素坐標(biāo)為(x2-1,y2-1),即實(shí)際的填充區(qū)域會(huì)向左和向上各偏移0.5個(gè)像素。故稱左上像素填充約定。

            ? 0 1?2
            ?? 0 口口口
            ?? 1 口口口
            ?? 2 口口口

            D3D, GDI, OpenGL等圖形庫(kù)使用左上填充約定的,如果接觸過(guò)這些圖形庫(kù),你可能會(huì)知道這個(gè)約定。還記得畫(huà)一個(gè)全屏幕的矩形吧:DrawRectangle(0, 0, Screen_Width-1, Screen_Height-1)。

            想法一:想到別的填充約定,比如右上,左下,右下等,這些不知道有哪些系統(tǒng)使用。

            想法二:如果以像素方格的左上角為基準(zhǔn)制定坐標(biāo)點(diǎn)(即對(duì)于任意一整數(shù)坐標(biāo)點(diǎn)p(x,y),p必為某個(gè)像素方格的左上角),情況怎么樣?這時(shí),給定(0,0,2,2),則填充時(shí)可以還會(huì)遇到一樣的問(wèn)題,填充(0,0),(0,1),(1,0),(1,0),(2,0),(2,1),(0,2),(1,2),(2,2),最后還是包含了3X3= 9個(gè)像素。

            想法三:
            to be continued...

            posted @ 2006-07-26 16:55 SoRoMan 閱讀(2129) | 評(píng)論 (7)編輯 收藏

            2006年7月24日 #


            Self Training-Rendering
            Tool
            ???Maya Basic
            ???Maya Rendering Basic
            ???Maya API/SDK
            Library
            ???OpenGL Basic
            Theory
            ???Computering Geometry
            ???Real-Time Rendering
            ??????Graphic Algorithm
            ?????????Draw
            ????????????Draw Line
            ????????????Draw Circle
            ?????????Clip
            ????????????Object Space
            ????????????Image Space
            ???Linear Math

            To be continued...
            posted @ 2006-07-24 17:33 SoRoMan 閱讀(386) | 評(píng)論 (1)編輯 收藏

            2006年7月16日 #

                 摘要: <轉(zhuǎn)貼-To Me>概述 Singleton模式? 五種實(shí)現(xiàn) ...  閱讀全文
            posted @ 2006-07-16 23:12 SoRoMan 閱讀(1552) | 評(píng)論 (3)編輯 收藏

            僅列出標(biāo)題  下一頁(yè)
            久久久久久久久久久久久久| 99久久精品免费国产大片| 日韩亚洲国产综合久久久| 久久精品国产男包| 国产亚洲美女精品久久久2020| 精品久久人妻av中文字幕| 精品国产综合区久久久久久| 久久久久亚洲AV无码观看| 久久99精品久久久久久| 狠狠色丁香婷婷久久综合五月| 国产高潮国产高潮久久久| 无码任你躁久久久久久老妇| 国内精品久久久人妻中文字幕| 人人狠狠综合88综合久久| 精品少妇人妻av无码久久| 污污内射久久一区二区欧美日韩 | 国产偷久久久精品专区 | 97久久超碰国产精品旧版| 国产午夜精品久久久久九九| 99久久无色码中文字幕人妻| 久久久精品国产Sm最大网站| 精品久久久久久成人AV| 欧洲人妻丰满av无码久久不卡| 亚洲?V乱码久久精品蜜桃| 四虎国产永久免费久久| 精品久久久无码人妻中文字幕豆芽| 一级a性色生活片久久无少妇一级婬片免费放 | 久久亚洲国产成人影院网站| 国产精品久久久久影院色| 亚洲乱码中文字幕久久孕妇黑人| 久久久精品久久久久久| 国产精品免费久久久久久久久| 国产精品久久影院| 久久91精品国产91久久户| 国产亚洲综合久久系列| 潮喷大喷水系列无码久久精品| 日韩人妻无码一区二区三区久久 | 爱做久久久久久| 久久青青草原综合伊人| 88久久精品无码一区二区毛片| 国产精品一久久香蕉国产线看|