熟悉直线算法的人请进!

shijinchen 2001-12-25 12:51:55
/******************************Public*Routine******************************* BOOL bLines3D(ppdev, pptfxFirst, pptfxBuf, cptfx, pls,
* prclClip, apfn[], flStart)
*
* Computes the DDA for the line and gets ready to draw it. Puts the
* pixel data into an array of strips, and calls a strip routine to
* do the actual drawing.
*
* Doing NT Lines Right
* --------------------
*
* In NT, all lines are given to the device driver in fractional
* coordinates, in a 28.4 fixed point format. The lower 4 bits are
* fractional for sub-pixel positioning.
*
* Note that you CANNOT! just round the coordinates to integers
* and pass the results to your favorite integer Bresenham routine!!
* (Unless, of course, you have such a high resolution device that
* nobody will notice -- not likely for a display device.) The
* fractions give a more accurate rendering of the line -- this is
* important for things like our Bezier curves, which would have 'kinks'
* if the points in its polyline approximation were rounded to integers.
*
* Unfortunately, for fractional lines there is more setup work to do
* a DDA than for integer lines. However, the main loop is exactly
* the same (and can be done entirely with 32 bit math).
*
* If You've Got Hardware That Does Bresenham
* ------------------------------------------
*
* A lot of hardware limits DDA error terms to 'n' bits. With fractional
* coordinates, 4 bits are given to the fractional part, letting
* you draw in hardware only those lines that lie entirely in a 2^(n-4)
* by 2^(n-4) pixel space.
*
* And you still have to correctly draw those lines with coordinates
* outside that space! Remember that the screen is only a viewport
* onto a 28.4 by 28.4 space -- if any part of the line is visible
* you MUST render it precisely, regardless of where the end points lie.
* So even if you do it in software, somewhere you'll have to have a
* 32 bit DDA routine.
*
* Our Implementation
* ------------------
*
* We employ a run length slice algorithm: our DDA calculates the
* number of pixels that are in each row (or 'strip') of pixels.
*
* We've separated the running of the DDA and the drawing of pixels:
* we run the DDA for several iterations and store the results in
* a 'strip' buffer (which are the lengths of consecutive pixel rows of
* the line), then we crank up a 'strip drawer' that will draw all the
* strips in the buffer.
*
* We also employ a 'half-flip' to reduce the number of strip
* iterations we need to do in the DDA and strip drawing loops: when a
* (normalized) line's slope is more than 1/2, we do a final flip
* about the line y = (1/2)x. So now, instead of each strip being
* consecutive horizontal or vertical pixel rows, each strip is composed
* of those pixels aligned in 45 degree rows. So a line like (0, 0) to
* (128, 128) would generate only one strip.
*
* We also always draw only left-to-right.
*
* Styled lines may have arbitrary style patterns. We specially
* optimize the default patterns (and call them 'masked' styles).
*
* The DDA Derivation
* ------------------
*
* Here is how I like to think of the DDA calculation.
*
* We employ Knuth's "diamond rule": rendering a one-pixel-wide line
* can be thought of as dragging a one-pixel-wide by one-pixel-high
* diamond along the true line. Pixel centers lie on the integer
* coordinates, and so we light any pixel whose center gets covered
* by the "drag" region (John D. Hobby, Journal of the Association
* for Computing Machinery, Vol. 36, No. 2, April 1989, pp. 209-229).
*
* We must define which pixel gets lit when the true line falls
* exactly half-way between two pixels. In this case, we follow
* the rule: when two pels are equidistant, the upper or left pel
* is illuminated, unless the slope is exactly one, in which case
* the upper or right pel is illuminated. (So we make the edges
* of the diamond exclusive, except for the top and left vertices,
* which are inclusive, unless we have slope one.)
*
* This metric decides what pixels should be on any line BEFORE it is
* flipped around for our calculation. Having a consistent metric
* this way will let our lines blend nicely with our curves. The
* metric also dictates that we will never have one pixel turned on
* directly above another that's turned on. We will also never have
* a gap; i.e., there will be exactly one pixel turned on for each
* column between the start and end points. All that remains to be
* done is to decide how many pixels should be turned on for each row.
*
* So lines we draw will consist of varying numbers of pixels on
* successive rows, for example:
*
* ******
* *****
* ******
* *****
*
* We'll call each set of pixels on a row a "strip".
*
* (Please remember that our coordinate space has the origin as the
* upper left pixel on the screen; postive y is down and positive x
* is right.)
*
* Device coordinates are specified as fixed point 28.4 numbers,
* where the first 28 bits are the integer coordinate, and the last
* 4 bits are the fraction. So coordinates may be thought of as
* having the form (x, y) = (M/F, N/F) where F is the constant scaling
* factor F = 2^4 = 16, and M and N are 32 bit integers.
*
* Consider the line from (M0/F, N0/F) to (M1/F, N1/F) which runs
* left-to-right and whose slope is in the first octant, and let
* dM = M1 - M0 and dN = N1 - N0. Then dM >= 0, dN >= 0 and dM >= dN.
*
* Since the slope of the line is less than 1, the edges of the
* drag region are created by the top and bottom vertices of the
* diamond. At any given pixel row y of the line, we light those
* pixels whose centers are between the left and right edges.
*
* Let mL(n) denote the line representing the left edge of the drag
* region. On pixel row j, the column of the first pixel to be
* lit is
*
* iL(j) = ceiling( mL(j * F) / F)
*
* Since the line's slope is less than one:
*
* iL(j) = ceiling( mL([j + 1/2] F) / F )
*
* Recall the formula for our line:
*
* n(m) = (dN / dM) (m - M0) + N0
*
* m(n) = (dM / dN) (n - N0) + M0
*
* Since the line's slope is less than one, the line representing
* the left edge of the drag region is the original line offset
* by 1/2 pixel in the y direction:
*
* mL(n) = (dM / dN) (n - F/2 - N0) + M0
*
* From this we can figure out the column of the first pixel that
* will be lit on row j, being careful of rounding (if the left
* edge lands exactly on an integer point, the pixel at that
* point is not lit because of our rounding convention):
*
* iL(j) = floor( mL(j F) / F ) + 1
*
* = floor( ((dM / dN) (j F - F/2 - N0) + M0) / F ) + 1
*
* = floor( F dM j - F/2 dM - N0 dM + dN M0) / F dN ) + 1
*
* F dM j - [ dM (N0 + F/2) - dN M0 ]
* = floor( ---------------------------------- ) + 1
* F dN
*
* dM j - [ dM (N0 + F/2) - dN M0 ] / F
* = floor( ------------------------------------ ) + 1 (1)
* dN
*
* = floor( (dM j + alpha) / dN ) + 1
*
* where
*
* alpha = - [ dM (N0 + F/2) - dN M0 ] / F
*
* We use equation (1) to calculate the DDA: there are iL(j+1) - iL(j)
* pixels in row j. Because we are always calculating iL(j) for
* integer quantities of j, we note that the only fractional term
* is constant, and so we can 'throw away' the fractional bits of
* alpha:
*
* beta = floor( - [ dM (N0 + F/2) - dN M0 ] / F ) (2)
*
* so
*
* iL(j) = floor( (dM j + beta) / dN ) + 1 (3)
*
* for integers j.
*
* Note if iR(j) is the line's rightmost pixel on row j, that
* iR(j) = iL(j + 1) - 1.
*
* Similarly, rewriting equation (1) as a function of column i,
* we can determine, given column i, on which pixel row j is the line
* lit:
*
* dN i + [ dM (N0 + F/2) - dN M0 ] / F
* j(i) = ceiling( ------------------------------------ ) - 1
* dM
*
* Floors are easier to compute, so we can rewrite this:
*
* dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F
* j(i) = floor( ----------------------------------------------- ) - 1
* dM
*
* dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F - dM
* = floor( ---------------------------------------------------- )
* dM
*
* dN i + [ dM (N0 + F/2) - dN M0 - 1 ] / F
* = floor( ---------------------------------------- )
* dM
*
* We can once again wave our hands and throw away the fractional bits
* of the remainder term:
*
* j(i) = floor( (dN i + gamma) / dM ) (4)
*
* where
*
* gamma = floor( [ dM (N0 + F/2) - dN M0 - 1 ] / F ) (5)
*
* We now note that
*
* beta = -gamma - 1 = ~gamma (6)
*
* To draw the pixels of the line, we could evaluate (3) on every scan
* line to determine where the strip starts. Of course, we don't want
* to do that because that would involve a multiply and divide for every
* scan. So we do everything incrementally.
*
* We would like to easily compute c , the number of pixels on scan j:
* j
*
* c = iL(j + 1) - iL(j)
* j
*
* = floor((dM (j + 1) + beta) / dN) - floor((dM j + beta) / dN) (7)
*
* This may be rewritten as
*
* c = floor(i + r / dN) - floor(i + r / dN) (8)
* j j+1 j+1 j j
*
* where i , i are integers and r < dN, r < dN.
* j j+1 j j+1
*
* Rewriting (7) again:
*
* c = floor(i + r / dN + dM / dN) - floor(i + r / dN)
* j j j j j
*
*
* = floor((r + dM) / dN) - floor(r / dN)
* j j
*
* This may be rewritten as
*
* c = dI + floor((r + dR) / dN) - floor(r / dN)
* j j j
*
* where dI + dR / dN = dM / dN, dI is an integer and dR < dN.
*
* r is the remainder (or "error") term in the DDA loop: r / dN
* j j
* is the exact fraction of a pixel at which the strip ends. To go
* on to the next scan and compute c we need to know r .
* j+1 j+1
*
* So in the main loop of the DDA:
*
* c = dI + floor((r + dR) / dN) and r = (r + dR) % dN
* j j j+1 j
*
* and we know r < dN, r < dN, and dR < dN.
* j j+1
*
* We have derived the DDA only for lines in the first octant; to
* handle other octants we do the common trick of flipping the line
* to the first octant by first making the line left-to-right by
* exchanging the end-points, then flipping about the lines y = 0 and
* y = x, as necessary. We must record the transformation so we can
* undo them later.
*
* We must also be careful of how the flips affect our rounding. If
* to get the line to the first octant we flipped about x = 0, we now
* have to be careful to round a y value of 1/2 up instead of down as
* we would for a line originally in the first octant (recall that
* "In the case where two pels are equidistant, the upper or left
* pel is illuminated...").
*
* To account for this rounding when running the DDA, we shift the line
* (or not) in the y direction by the smallest amount possible. That
* takes care of rounding for the DDA, but we still have to be careful
* about the rounding when determining the first and last pixels to be
* lit in the line.
*
* Determining The First And Last Pixels In The Line
* -------------------------------------------------
*
* Fractional coordinates also make it harder to determine which pixels
* will be the first and last ones in the line. We've already taken
* the fractional coordinates into account in calculating the DDA, but
* the DDA cannot tell us which are the end pixels because it is quite
* happy to calculate pixels on the line from minus infinity to positive
* infinity.
*
* The diamond rule determines the start and end pixels. (Recall that
* the sides are exclusive except for the left and top vertices.)
* This convention can be thought of in another way: there are diamonds
* around the pixels, and wherever the true line crosses a diamond,
* that pel is illuminated.
*
* Consider a line where we've done the flips to the first octant, and the
* floor of the start coordinates is the origin:
*
* +-----------------------> +x
* |
* | 0 1
* | 0123456789abcdef
* |
* | 0 00000000?1111111
* | 1 00000000 1111111
* | 2 0000000 111111
* | 3 000000 11111
* | 4 00000 ** 1111
* | 5 0000 ****1
* | 6 000 1***
* | 7 00 1 ****
* | 8 ? ***
* | 9 22 3 ****
* | a 222 33 ***
* | b 2222 333 ****
* | c 22222 3333 **
* | d 222222 33333
* | e 2222222 333333
* | f 22222222 3333333
* |
* | 2 3
* v
* +y
*
* If the start of the line lands on the diamond around pixel 0 (shown by
* the '0' region here), pixel 0 is the first pel in the line. The same
* is true for the other pels.
*
* A little more work has to be done if the line starts in the
* 'nether-land' between the diamonds (as illustrated by the '*' line):
* the first pel lit is the first diamond crossed by the line (pixel 1 in
* our example). This calculation is determined by the DDA or slope of
* the line.
*
* If the line starts exactly half way between two adjacent pixels
* (denoted here by the '?' spots), the first pixel is determined by our
* round-down convention (and is dependent on the flips done to
* normalize the line).
*
* Last Pel Exclusive
* ------------------
*
* To eliminate repeatedly lit pels between continuous connected lines,
* we employ a last-pel exclusive convention: if the line ends exactly on
* the diamond around a pel, that pel is not lit. (This eliminates the
* checks we had in the old code to see if we were re-lighting pels.)
*
* The Half Flip
* -------------
*
* To make our run length algorithm more efficient, we employ a "half
* flip". If after normalizing to the first octant, the slope is more
* than 1/2, we subtract the y coordinate from the x coordinate. This
* has the effect of reflecting the coordinates through the line of slope
* 1/2. Note that the diagonal gets mapped into the x-axis after a half
* flip.
*
* How Many Bits Do We Need, Anyway?
* ---------------------------------
*
* Note that if the line is visible on your screen, you must light up
* exactly the correct pixels, no matter where in the 28.4 x 28.4 device
* space the end points of the line lie (meaning you must handle 32 bit
* DDAs, you can certainly have optimized cases for lesser DDAs).
*
* We move the origin to (floor(M0 / F), floor(N0 / F)), so when we
* calculate gamma from (5), we know that 0 <= M0, N0 < F. And we
* are in the first octant, so dM >= dN. Then we know that gamma can
* be in the range [(-1/2)dM, (3/2)dM]. The DDI guarantees us that
* valid lines will have dM and dN values at most 31 bits (unsigned)
* of significance. So gamma requires 33 bits of significance (we store
* this as a 64 bit number for convenience).
*
* When running through the DDA loop, r + dR can have a value in the
* j
* range 0 <= r < 2 dN; thus the result must be a 32 bit unsigned value.
* j
*
* Testing Lines
* -------------
*
* To be NT compliant, a display driver must exactly adhere to GIQ,
* which means that for any given line, the driver must light exactly
* the same pels as does GDI. This can be tested using the Guiman tool
* provided elsewhere in the DDK, and 'ZTest', which draws random lines
* on the screen and to a bitmap, and compares the results.
*
* If You've Got Line Hardware
* ---------------------------
*
* If your hardware already adheres to GIQ, you're all set. Otherwise
* you'll want to look at the S3 sample code and read the following:
*
* 1) You'll want to special case integer-only lines, since they require
* less processing time and are more common (CAD programs will probably
* only ever give integer lines). GDI does not provide a flag saying
* that all lines in a path are integer lines; consequently, you will
* have to explicitly check every line.
*
* 2) You are required to correctly draw any line in the 28.4 device
* space that intersects the viewport. If you have less than 32 bits
* of significance in the hardware for the Bresenham terms, extremely
* long lines would overflow the hardware. For such (rare) cases, you
* can fall back to strip-drawing code (or if your display is a frame
* buffer, fall back to the engine).
*
* 3) If you can explicitly set the Bresenham terms in your hardware, you
* can draw non-integer lines using the hardware. If your hardware has
* 'n' bits of precision, you can draw GIQ lines that are up to 2^(n-5)
* pels long (4 bits are required for the fractional part, and one bit is
* used as a sign bit). Note that integer lines don't require the 4
* fractional bits, so if you special case them as in 1), you can do
* integer lines that are up to 2^(n - 1) pels long. See the S3's
* fastline.asm for an example.
*
\**************************************************************************/

这是一段浮点数的直线算法,帮我看一下是什么意思!
...全文
156 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
shijinchen 2001-12-30
  • 打赏
  • 举报
回复
很高兴,我自己已经解决了! 不过还是要给分.
sayu_yangyou 2001-12-29
  • 打赏
  • 举报
回复
小数也可以归整嘛。
shijinchen 2001-12-29
  • 打赏
  • 举报
回复
sayu_yangyou(萨虞.扬尤):可以吗?如果可以的话,上面那段英文的东西就没用了!
shijinchen 2001-12-28
  • 打赏
  • 举报
回复
starfish(海星):它这里是有小数的,图形学书里是没有小数的!相比之下图形书里面是比较简单的。
wangqiqi 2001-12-27
  • 打赏
  • 举报
回复
so 长!
starfish 2001-12-27
  • 打赏
  • 举报
回复
说的是生成直线的DDA算法和Bresenham算法
随便找本图形学的书上第一章就有。
shijinchen 2001-12-27
  • 打赏
  • 举报
回复
不会吧!算法不好的人是看不懂的。
shijinchen 2001-12-27
  • 打赏
  • 举报
回复
如果不是那么长的话,我自己也可以看懂了!
longj 2001-12-25
  • 打赏
  • 举报
回复
都忘了 , 才畢業半年 , 唉!
leojay 2001-12-25
  • 打赏
  • 举报
回复
搞程序不自己看英文怎么行?自己看吧,对你有好处的。

33,028

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧