区域填充:扫描线种子填充和剖面线填充

  1. #include "stdio.h"
  2. #include "graphics.h"
  3. #include "malloc.h"
  4. #include "conio.h"
  5. #include "math.h"
  6. /*******************************扫描线种子填充*********************/
  7. #define LEFT 200
  8. #define TOP 200
  9. #define TRUE 1
  10. #define FALSE 0
  11. #define BOUND WHITE
  12. #define DELAYTIME 10000
  13. typedef struct
  14. {
  15.     int x;
  16.     int y;
  17. } Data;
  18. typedef struct _Node
  19. {
  20.     Data data;
  21.     struct _Node *next;
  22. } Node, *List;
  23. typedef struct _Stack
  24. {
  25.     Node *top;
  26. } Stack;
  27. /* 初始化栈 */
  28. void Init( Stack *s )
  29. {
  30.     s->top = NULL;
  31. }
  32. /* 入栈 */
  33. void Push( Stack *s, Data d )
  34. {
  35.     Node *newN = ( Node * )malloc( sizeof( Node ) );
  36.     newN->data.x = d.x;
  37.     newN->data.y = d.y;
  38.     newN->next = s->top;
  39.     s->top = newN;
  40.     /*printf("Push %d, %d to Stack/n", s->top->data.x, s->top->data.y );*/
  41. }
  42. /* 出栈 */
  43. Data Pop( Stack *s )
  44. {
  45.     Node *toPop = s->top;
  46.     Data d = toPop->data;
  47.     s->top = s->top->next;
  48.     free (toPop);
  49.     /*printf("Pop %d, %d from Stack/n", d.x, d.y );*/
  50.     /*printf("p:%d,%d ", d.x-LEFT, d.y-TOP);*/
  51.     return d;
  52. }
  53. /* 检测栈是否为空 */
  54. int Empty( Stack *s )
  55. {
  56.     if ( s->top == NULL )
  57.     {
  58.         return TRUE;
  59.     }
  60.     else
  61.     {
  62.         return FALSE;
  63.     }
  64. }
  65.   
  66. Data GetTop( Stack *s )
  67. {
  68.     if ( Empty( s ) != 0 )
  69.     {
  70.         return s->top->data;
  71.     }
  72. }
  73. /* 扫描线种子填充 */
  74. void SeedFill( int seedX, int seedY, int color )
  75. {
  76.     Data seed, newSeed;
  77.     int xLeft, xRight, xCurrent, yCurrent;
  78.     int needFill = FALSE;
  79.     Stack seedStack;
  80.     Init( &seedStack );
  81.     seed.x = seedX;
  82.     seed.y = seedY;
  83.     /* 种子入栈 */
  84.     Push( &seedStack, seed );
  85.     while ( Empty( &seedStack ) == FALSE )
  86.     {
  87.         /* 种子出栈并给点上色 */
  88.         seed = Pop( &seedStack );
  89.         putpixel( seed.x, seed.y, color );
  90.         /* 填充当前扫描线位于种子左边的部分 */
  91.         xCurrent = seed.x - 1;
  92.         yCurrent = seed.y;
  93.         while ( getpixel( xCurrent, yCurrent ) != color &
  94.                 getpixel( xCurrent, yCurrent ) != BOUND )
  95.         {
  96.             putpixel( xCurrent, yCurrent, color );
  97.             xCurrent -= 1;
  98.         }
  99.         /* 记录最左侧的内点 */
  100.         xLeft = xCurrent + 1;
  101.         /* 填充当前扫描线位于种子右边的部分 */
  102.         xCurrent = seed.x + 1;
  103.         yCurrent = seed.y;
  104.         while ( getpixel( xCurrent, yCurrent ) != color &
  105.                 getpixel( xCurrent, yCurrent ) != BOUND )
  106.         {
  107.             putpixel( xCurrent, yCurrent, color );
  108.             xCurrent += 1;
  109.         }
  110.         /* 记录最右侧的内点 */
  111.         xRight = xCurrent - 1;
  112.         /*printf("left: %d, %d 's color is %d/n", xLeft, yCurrent, getpixel(xLeft, xRight));*/
  113.         /* 上移一条扫描线*/
  114.         yCurrent = seed.y - 1;
  115.         xCurrent = xLeft;
  116.         /* 从左向右检测非边界、未填充的象素 */
  117.         while ( xCurrent < xRight )
  118.         {
  119.             while ( getpixel( xCurrent, yCurrent ) != color &
  120.                     getpixel( xCurrent, yCurrent ) != BOUND )
  121.             {
  122.                 /* 存在未填充的像素,则需要填充 */
  123.                 needFill = TRUE;
  124.                 xCurrent += 1;
  125.             }
  126.             /* 最右侧像素入栈 */
  127.             if ( needFill == TRUE )
  128.             {
  129.                 newSeed.x = xCurrent - 1;
  130.                 newSeed.y = yCurrent;
  131.                 Push( &seedStack, newSeed );
  132.                 needFill = FALSE;
  133.                 break;
  134.             }
  135.             xCurrent++;
  136.         }
  137.         delay(DELAYTIME);
  138.         needFill = FALSE;
  139.         /* 下移一条扫描线 */
  140.         yCurrent = seed.y + 1;
  141.         xCurrent = xLeft;
  142.         /* 从左向右检测非边界、未填充的象素 */
  143.         while ( xCurrent < xRight )
  144.         {
  145.             while ( getpixel( xCurrent, yCurrent ) != color &
  146.                     getpixel( xCurrent, yCurrent ) != BOUND )
  147.             {
  148.                 /* 存在未填充的像素,则需要填充 */
  149.                 needFill = TRUE;
  150.                 xCurrent += 1;
  151.             }
  152.             /* 最右侧像素入栈 */
  153.             if ( needFill == TRUE )
  154.             {
  155.                 newSeed.x = xCurrent - 1;
  156.                 newSeed.y = yCurrent;
  157.                 Push( &seedStack, newSeed );
  158.                 needFill = FALSE;
  159.                 break;
  160.             }
  161.             xCurrent++;
  162.         }
  163.         delay(DELAYTIME);
  164.     }
  165. }
  166. /*********************End of 扫描线种子填充*********************************/
  167. /**********************************剖面线种子填充******************************/
  168. #define BIG_PLUS_INT 65534
  169. #define K -1.0f
  170. #define DELTA_B 5.0f
  171. /* 顶点 */
  172. typedef struct _Vector
  173. {
  174.     int x, y;
  175. } Vector;
  176. /* 边 */              
  177. typedef struct _Edge
  178. {
  179.     Vector v1, v2;  
  180. } Edge;
  181. /******************************************************
  182. * summery
  183. *   求得剖面线的画线范围和总数,求得各条边的可相交范围
  184. * in
  185. *   e[] - 边信息
  186. *   numEdge - 图元的边数
  187. *   k - 剖面线的斜率
  188. *   bDelta - 相邻两条剖面线的距离
  189. * inout
  190. *   bMinMax[] - 剖面线的画线范围
  191. *   edgeMinMax[][2] - 各条边的可相交范围
  192. * out
  193. *   int - 剖面线的画线总数
  194. *******************************************************/    
  195. int CalcPrimitiveInfo( Edge e[], int numEdge, float k, float bDelta, float bMinMax[], float edgeMinMax[][2] )
  196. {
  197.     int i;
  198.     float tempF;
  199.     float bMin = BIG_PLUS_INT, bMax = -BIG_PLUS_INT;
  200.     int numHatching;
  201.                                                                                             
  202.     for ( i = 0; i < numEdge; i++ )
  203.     {
  204.         edgeMinMax[i][0] = e[i].v1.y - k * e[i].v1.x;
  205.         edgeMinMax[i][1] = e[i].v2.y - k * e[i].v2.x;
  206.         if ( edgeMinMax[i][0] > edgeMinMax[i][1] )
  207.         {
  208.             /* 交换 */
  209.             tempF = edgeMinMax[i][0];
  210.             edgeMinMax[i][0] = edgeMinMax[i][1];
  211.             edgeMinMax[i][1] = tempF;
  212.         }
  213.         if ( edgeMinMax[i][0] < bMin )
  214.         {
  215.             /* 替换Min */
  216.             bMin = edgeMinMax[i][0];
  217.         }
  218.         if ( edgeMinMax[i][1] > bMax )
  219.         {
  220.             /* 替换Max */
  221.             bMax = edgeMinMax[i][1];
  222.         }  
  223.     }
  224.     
  225.     bMinMax[0] = bMin;
  226.     bMinMax[1] = bMax;
  227.     numHatching = ( bMax - bMin ) / bDelta;
  228.     return numHatching;
  229. }
  230. /******************************************************
  231. * summery
  232. *   计算剖面线和边的交点
  233. * in
  234. *   e - 边信息
  235. *   k - 剖面线的斜率
  236. *   b - 当前剖面线的b值
  237. * out
  238. *   *point - 交点
  239. *******************************************************/
  240. void CalcIntersectPoint( Edge e, float k, float b, Vector *point)
  241. {
  242.     float m, n, t;
  243.     m = e.v1.x * e.v2.y - e.v1.y * e.v2.x + b * ( e.v2.x - e.v1.x );
  244.     n = e.v2.y - e.v1.y - k * ( e.v2.x - e.v1.x );
  245.     t = m / n;
  246.     point->x = floor( t + 0.5f );
  247.     point->y = floor( k * t + b + 0.5f );
  248. }
  249. /******************************************************
  250. * summery
  251. *   对交点按照交点的x值进行排序
  252. * inout
  253. *   points[] - 交点数组
  254. * in
  255. *   numPoints - 交点总数
  256. *******************************************************/
  257. void SortPoints( Vector points[], int numPoints )
  258. {
  259.     int i, j;
  260.     int tempX, tempY;
  261.     for ( i = 1; i <= numPoints - 1; i++ )
  262.     {
  263.         for ( j = 0; j < numPoints - i; j++ )
  264.         {
  265.             if ( points[j].x > points[j + 1].x )
  266.             {
  267.                 /* 交换points[j]和points[j + 1] */
  268.                 tempX = points[j].x;
  269.                 tempY = points[j].y;
  270.                 points[j].x = points[j + 1].x;
  271.                 points[j].y = points[j + 1].y;
  272.                 points[j + 1].x = tempX;
  273.                 points[j + 1].y = tempY;
  274.             }
  275.         }
  276.     }   
  277. }
  278. /******************************************************
  279. * summery
  280. *   画剖面线
  281. * in
  282. *   e[] - 边信息
  283. *   numEdge - 图元的边数
  284. *   k - 剖面线的斜率
  285. *   bDelta - 相邻两条剖面线的距离
  286. *   edgeMinMax[][2] - 各条边的可相交范围
  287. * out
  288. *   int - 剖面线的画线总数
  289. *******************************************************/
  290. void DrawHatching( Edge e[], int numEdges, float bMinMax[], float edgeMinMax[][2], float k, float b )
  291. {
  292.     int i, j, n = 0, nRealSectP = 0;
  293.     Vector *points = ( Vector* )malloc( numEdges * sizeof( Vector ) ); /* 一条剖面线与边的交点总数不可能超过边的总数 */
  294.     Vector v[2];
  295.     int numPoints = 0;
  296.     if ( b <= bMinMax[0] || b >= bMinMax[1] )
  297.     {
  298.         return;
  299.     }
  300.     
  301.     /* 计算剖面线与所有边的交点 */
  302.     for ( i = 0; i < numEdges; i++ )
  303.     {
  304.         if ( b >= edgeMinMax[i][0] && b <= edgeMinMax[i][1] )
  305.         {
  306.             /* 求交点 */
  307.             CalcIntersectPoint( e[i], k, b, &( points[numPoints] ) );
  308.             numPoints++; 
  309.         }
  310.     }
  311.     
  312.     /* 对这些交点进行排序 */
  313.     SortPoints( points, numPoints );
  314.     
  315.     /* 绘制剖面线 */
  316.     i = 0;
  317.     nRealSectP = 0;
  318.     while ( i < numPoints - 1 )
  319.     {
  320.         /*printf("i:%d, n:%d;", i, nRealSectP );*/
  321.         /* 有重合的点 */
  322.         if ( points[i].x == points[i + 1].x )
  323.         {
  324.             /* 找出共享该顶点的两条边的另外两个顶点 */
  325.             n = 0;
  326.             for ( j = 0; j < numEdges; j++ )
  327.             {
  328.                 if ( e[j].v1.x == points[i].x && e[j].v1.y == points[i].y )
  329.                 {
  330.                     v[n] = e[j].v2;
  331.                     n++;
  332.                 }
  333.                 if ( e[j].v2.x == points[i].x && e[j].v2.y == points[i].y )
  334.                 {
  335.                     v[n] = e[j].v1;
  336.                     n++;
  337.                 }
  338.                 if ( n >= 2 )
  339.                 {
  340.                     break;
  341.                 }
  342.             }
  343.             /* 判断这两个顶点在剖面线的同侧还是异侧 */
  344.             if ( ( v[0].y - k * v[0].x - b ) * ( v[1].y - k * v[1].x - b ) > 0 )
  345.             {
  346.                 /* 在同侧,计两个交点,故nRealSectP需要再加一 */
  347.                 nRealSectP++;
  348.             }
  349.             else
  350.             {
  351.                 /* 在异侧,计一个交点,故nRealSectP不需要改变 */
  352.             }
  353.         }
  354.         else
  355.         {
  356.             if ( nRealSectP % 2 == 0 )
  357.             {                                      
  358.                 line( points[i].x, points[i].y, points[i + 1].x, points[i + 1].y );
  359.             }
  360.             nRealSectP++;
  361.         }
  362.         i++;
  363.     }
  364.     free( points );
  365. /*************************End of 剖面线填充************************************/
  366. int main()
  367. {
  368.     int gdriver = VGA , gmode = VGAHI;
  369.     int polyPoints[6][2];
  370.     char cmd;
  371.     int i;
  372.     Vector v[9];
  373.     Edge e[9];
  374.     float bMinMax[2];
  375.     float edgeMinMax[9][2];
  376.     int numHatching;
  377.     float bCurrent;
  378.     initgraph ( &gdriver , &gmode , "d://" );
  379.     polyPoints[0][0] = 5 + LEFT;
  380.     polyPoints[0][1] = 20 + TOP;
  381.     polyPoints[1][0] = 35 + LEFT;
  382.     polyPoints[1][1] = 0 + TOP;
  383.     polyPoints[2][0] = 65 + LEFT;
  384.     polyPoints[2][1] = 20 + TOP;
  385.     polyPoints[3][0] = 85 + LEFT;
  386.     polyPoints[3][1] = 70 + TOP;
  387.     polyPoints[4][0] = 0 + LEFT;
  388.     polyPoints[4][1] = 70 + TOP;
  389.     polyPoints[5][0] = 5 + LEFT;
  390.     polyPoints[5][1] = 20 + TOP;
  391.     v[0].x = polyPoints[0][0];
  392.     v[0].y = polyPoints[0][1];
  393.     v[1].x = polyPoints[1][0];
  394.     v[1].y = polyPoints[1][1];
  395.     v[2].x = polyPoints[2][0];
  396.     v[2].y = polyPoints[2][1];
  397.     v[3].x = polyPoints[3][0];
  398.     v[3].y = polyPoints[3][1];
  399.     v[4].x = polyPoints[4][0];
  400.     v[4].y = polyPoints[4][1];
  401.     v[5].x = 15 + LEFT;
  402.     v[5].y = 20 + TOP;
  403.     v[6].x = 55 + LEFT;
  404.     v[6].y = 20 + TOP;
  405.     v[7].x = 55 + LEFT;
  406.     v[7].y = 40 + TOP;
  407.     v[8].x = 15 + LEFT;
  408.     v[8].y = 40 + TOP;
  409.     e[0].v1 = v[0];
  410.     e[0].v2 = v[1];
  411.     e[1].v1 = v[1];
  412.     e[1].v2 = v[2];
  413.     e[2].v1 = v[2];
  414.     e[2].v2 = v[3];
  415.     e[3].v1 = v[3];
  416.     e[3].v2 = v[4];
  417.     e[4].v1 = v[4];
  418.     e[4].v2 = v[0];
  419.     e[5].v1 = v[5];
  420.     e[5].v2 = v[6];
  421.     e[6].v1 = v[6];
  422.     e[6].v2 = v[7];
  423.     e[7].v1 = v[7];
  424.     e[7].v2 = v[8];
  425.     e[8].v1 = v[8];
  426.     e[8].v2 = v[5];
  427.     while ( TRUE )
  428.     {
  429.         cleardevice();
  430.         outtext( "Enter the key:" );
  431.         outtextxy( 20, 10, "'1': Fill with scanning line." );
  432.         outtextxy( 20, 20, "'2': Fill with hatching." );
  433.         outtextxy( 20, 30, "'q': Quit." );
  434.         setcolor( BOUND );
  435.         drawpoly( 6, *polyPoints );
  436.         rectangle( v[5].x, v[5].y, v[7].x, v[7].y );
  437.         cmd = getch();
  438.         if ( cmd == '1' )
  439.         {
  440.             SeedFill( LEFT + 35, TOP + 60, BLUE );
  441.             getch();
  442.         }
  443.         else if ( cmd == '2' )
  444.         {
  445.             numHatching = CalcPrimitiveInfo( e, 9, K, DELTA_B, bMinMax, edgeMinMax );
  446.             for ( i = 1; i <= numHatching; i++ )
  447.             {
  448.                 bCurrent = bMinMax[0] + DELTA_B * i;
  449.                 DrawHatching( e, 9, bMinMax, edgeMinMax, K, bCurrent );
  450.                 delay( DELAYTIME );
  451.             }
  452.             getch();
  453.         }
  454.         else if ( cmd == 'q' )
  455.         {
  456.             closegraph();
  457.             return 1;
  458.         }
  459.     }
  460.     /* should never be here */
  461.     getch();
  462.     closegraph () ;
  463. }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值