您的位置:首页 > 其它

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

2008-11-09 21:07 197 查看
#include "stdio.h"

#include "graphics.h"

#include "malloc.h"

#include "conio.h"

#include "math.h"

/*******************************扫描线种子填充*********************/

#define LEFT 200

#define TOP 200

#define TRUE 1

#define FALSE 0

#define BOUND WHITE

#define DELAYTIME 10000

typedef struct

{

int x;

int y;

} Data;

typedef struct _Node

{

Data data;

struct _Node *next;

} Node, *List;

typedef struct _Stack

{

Node *top;

} Stack;

/* 初始化栈 */

void Init( Stack *s )

{

s->top = NULL;

}

/* 入栈 */

void Push( Stack *s, Data d )

{

Node *newN = ( Node * )malloc( sizeof( Node ) );

newN->data.x = d.x;

newN->data.y = d.y;

newN->next = s->top;

s->top = newN;

/*printf("Push %d, %d to Stack/n", s->top->data.x, s->top->data.y );*/

}

/* 出栈 */

Data Pop( Stack *s )

{

Node *toPop = s->top;

Data d = toPop->data;

s->top = s->top->next;

free (toPop);

/*printf("Pop %d, %d from Stack/n", d.x, d.y );*/

/*printf("p:%d,%d ", d.x-LEFT, d.y-TOP);*/

return d;

}

/* 检测栈是否为空 */

int Empty( Stack *s )

{

if ( s->top == NULL )

{

return TRUE;

}

else

{

return FALSE;

}

}

Data GetTop( Stack *s )

{

if ( Empty( s ) != 0 )

{

return s->top->data;

}

}

/* 扫描线种子填充 */

void SeedFill( int seedX, int seedY, int color )

{

Data seed, newSeed;

int xLeft, xRight, xCurrent, yCurrent;

int needFill = FALSE;

Stack seedStack;

Init( &seedStack );

seed.x = seedX;

seed.y = seedY;

/* 种子入栈 */

Push( &seedStack, seed );

while ( Empty( &seedStack ) == FALSE )

{

/* 种子出栈并给点上色 */

seed = Pop( &seedStack );

putpixel( seed.x, seed.y, color );

/* 填充当前扫描线位于种子左边的部分 */

xCurrent = seed.x - 1;

yCurrent = seed.y;

while ( getpixel( xCurrent, yCurrent ) != color &

getpixel( xCurrent, yCurrent ) != BOUND )

{

putpixel( xCurrent, yCurrent, color );

xCurrent -= 1;

}

/* 记录最左侧的内点 */

xLeft = xCurrent + 1;

/* 填充当前扫描线位于种子右边的部分 */

xCurrent = seed.x + 1;

yCurrent = seed.y;

while ( getpixel( xCurrent, yCurrent ) != color &

getpixel( xCurrent, yCurrent ) != BOUND )

{

putpixel( xCurrent, yCurrent, color );

xCurrent += 1;

}

/* 记录最右侧的内点 */

xRight = xCurrent - 1;

/*printf("left: %d, %d 's color is %d/n", xLeft, yCurrent, getpixel(xLeft, xRight));*/

/* 上移一条扫描线*/

yCurrent = seed.y - 1;

xCurrent = xLeft;

/* 从左向右检测非边界、未填充的象素 */

while ( xCurrent < xRight )

{

while ( getpixel( xCurrent, yCurrent ) != color &

getpixel( xCurrent, yCurrent ) != BOUND )

{

/* 存在未填充的像素,则需要填充 */

needFill = TRUE;

xCurrent += 1;

}

/* 最右侧像素入栈 */

if ( needFill == TRUE )

{

newSeed.x = xCurrent - 1;

newSeed.y = yCurrent;

Push( &seedStack, newSeed );

needFill = FALSE;

break;

}

xCurrent++;

}

delay(DELAYTIME);

needFill = FALSE;

/* 下移一条扫描线 */

yCurrent = seed.y + 1;

xCurrent = xLeft;

/* 从左向右检测非边界、未填充的象素 */

while ( xCurrent < xRight )

{

while ( getpixel( xCurrent, yCurrent ) != color &

getpixel( xCurrent, yCurrent ) != BOUND )

{

/* 存在未填充的像素,则需要填充 */

needFill = TRUE;

xCurrent += 1;

}

/* 最右侧像素入栈 */

if ( needFill == TRUE )

{

newSeed.x = xCurrent - 1;

newSeed.y = yCurrent;

Push( &seedStack, newSeed );

needFill = FALSE;

break;

}

xCurrent++;

}

delay(DELAYTIME);

}

}

/*********************End of 扫描线种子填充*********************************/

/**********************************剖面线种子填充******************************/

#define BIG_PLUS_INT 65534

#define K -1.0f

#define DELTA_B 5.0f

/* 顶点 */

typedef struct _Vector

{

int x, y;

} Vector;

/* 边 */

typedef struct _Edge

{

Vector v1, v2;

} Edge;

/******************************************************

* summery

* 求得剖面线的画线范围和总数,求得各条边的可相交范围

* in

* e[] - 边信息

* numEdge - 图元的边数

* k - 剖面线的斜率

* bDelta - 相邻两条剖面线的距离

* inout

* bMinMax[] - 剖面线的画线范围

* edgeMinMax[][2] - 各条边的可相交范围

* out

* int - 剖面线的画线总数

*******************************************************/

int CalcPrimitiveInfo( Edge e[], int numEdge, float k, float bDelta, float bMinMax[], float edgeMinMax[][2] )

{

int i;

float tempF;

float bMin = BIG_PLUS_INT, bMax = -BIG_PLUS_INT;

int numHatching;

for ( i = 0; i < numEdge; i++ )

{

edgeMinMax[i][0] = e[i].v1.y - k * e[i].v1.x;

edgeMinMax[i][1] = e[i].v2.y - k * e[i].v2.x;

if ( edgeMinMax[i][0] > edgeMinMax[i][1] )

{

/* 交换 */

tempF = edgeMinMax[i][0];

edgeMinMax[i][0] = edgeMinMax[i][1];

edgeMinMax[i][1] = tempF;

}

if ( edgeMinMax[i][0] < bMin )

{

/* 替换Min */

bMin = edgeMinMax[i][0];

}

if ( edgeMinMax[i][1] > bMax )

{

/* 替换Max */

bMax = edgeMinMax[i][1];

}

}

bMinMax[0] = bMin;

bMinMax[1] = bMax;

numHatching = ( bMax - bMin ) / bDelta;

return numHatching;

}

/******************************************************

* summery

* 计算剖面线和边的交点

* in

* e - 边信息

* k - 剖面线的斜率

* b - 当前剖面线的b值

* out

* *point - 交点

*******************************************************/

void CalcIntersectPoint( Edge e, float k, float b, Vector *point)

{

float m, n, t;

m = e.v1.x * e.v2.y - e.v1.y * e.v2.x + b * ( e.v2.x - e.v1.x );

n = e.v2.y - e.v1.y - k * ( e.v2.x - e.v1.x );

t = m / n;

point->x = floor( t + 0.5f );

point->y = floor( k * t + b + 0.5f );

}

/******************************************************

* summery

* 对交点按照交点的x值进行排序

* inout

* points[] - 交点数组

* in

* numPoints - 交点总数

*******************************************************/

void SortPoints( Vector points[], int numPoints )

{

int i, j;

int tempX, tempY;

for ( i = 1; i <= numPoints - 1; i++ )

{

for ( j = 0; j < numPoints - i; j++ )

{

if ( points[j].x > points[j + 1].x )

{

/* 交换points[j]和points[j + 1] */

tempX = points[j].x;

tempY = points[j].y;

points[j].x = points[j + 1].x;

points[j].y = points[j + 1].y;

points[j + 1].x = tempX;

points[j + 1].y = tempY;

}

}

}

}

/******************************************************

* summery

* 画剖面线

* in

* e[] - 边信息

* numEdge - 图元的边数

* k - 剖面线的斜率

* bDelta - 相邻两条剖面线的距离

* edgeMinMax[][2] - 各条边的可相交范围

* out

* int - 剖面线的画线总数

*******************************************************/

void DrawHatching( Edge e[], int numEdges, float bMinMax[], float edgeMinMax[][2], float k, float b )

{

int i, j, n = 0, nRealSectP = 0;

Vector *points = ( Vector* )malloc( numEdges * sizeof( Vector ) ); /* 一条剖面线与边的交点总数不可能超过边的总数 */

Vector v[2];

int numPoints = 0;

if ( b <= bMinMax[0] || b >= bMinMax[1] )

{

return;

}

/* 计算剖面线与所有边的交点 */

for ( i = 0; i < numEdges; i++ )

{

if ( b >= edgeMinMax[i][0] && b <= edgeMinMax[i][1] )

{

/* 求交点 */

CalcIntersectPoint( e[i], k, b, &( points[numPoints] ) );

numPoints++;

}

}

/* 对这些交点进行排序 */

SortPoints( points, numPoints );

/* 绘制剖面线 */

i = 0;

nRealSectP = 0;

while ( i < numPoints - 1 )

{

/*printf("i:%d, n:%d;", i, nRealSectP );*/

/* 有重合的点 */

if ( points[i].x == points[i + 1].x )

{

/* 找出共享该顶点的两条边的另外两个顶点 */

n = 0;

for ( j = 0; j < numEdges; j++ )

{

if ( e[j].v1.x == points[i].x && e[j].v1.y == points[i].y )

{

v
= e[j].v2;

n++;

}

if ( e[j].v2.x == points[i].x && e[j].v2.y == points[i].y )

{

v
= e[j].v1;

n++;

}

if ( n >= 2 )

{

break;

}

}

/* 判断这两个顶点在剖面线的同侧还是异侧 */

if ( ( v[0].y - k * v[0].x - b ) * ( v[1].y - k * v[1].x - b ) > 0 )

{

/* 在同侧,计两个交点,故nRealSectP需要再加一 */

nRealSectP++;

}

else

{

/* 在异侧,计一个交点,故nRealSectP不需要改变 */

}

}

else

{

if ( nRealSectP % 2 == 0 )

{

line( points[i].x, points[i].y, points[i + 1].x, points[i + 1].y );

}

nRealSectP++;

}

i++;

}

free( points );

}

/*************************End of 剖面线填充************************************/

int main()

{

int gdriver = VGA , gmode = VGAHI;

int polyPoints[6][2];

char cmd;

int i;

Vector v[9];

Edge e[9];

float bMinMax[2];

float edgeMinMax[9][2];

int numHatching;

float bCurrent;

initgraph ( &gdriver , &gmode , "d://" );

polyPoints[0][0] = 5 + LEFT;

polyPoints[0][1] = 20 + TOP;

polyPoints[1][0] = 35 + LEFT;

polyPoints[1][1] = 0 + TOP;

polyPoints[2][0] = 65 + LEFT;

polyPoints[2][1] = 20 + TOP;

polyPoints[3][0] = 85 + LEFT;

polyPoints[3][1] = 70 + TOP;

polyPoints[4][0] = 0 + LEFT;

polyPoints[4][1] = 70 + TOP;

polyPoints[5][0] = 5 + LEFT;

polyPoints[5][1] = 20 + TOP;

v[0].x = polyPoints[0][0];

v[0].y = polyPoints[0][1];

v[1].x = polyPoints[1][0];

v[1].y = polyPoints[1][1];

v[2].x = polyPoints[2][0];

v[2].y = polyPoints[2][1];

v[3].x = polyPoints[3][0];

v[3].y = polyPoints[3][1];

v[4].x = polyPoints[4][0];

v[4].y = polyPoints[4][1];

v[5].x = 15 + LEFT;

v[5].y = 20 + TOP;

v[6].x = 55 + LEFT;

v[6].y = 20 + TOP;

v[7].x = 55 + LEFT;

v[7].y = 40 + TOP;

v[8].x = 15 + LEFT;

v[8].y = 40 + TOP;

e[0].v1 = v[0];

e[0].v2 = v[1];

e[1].v1 = v[1];

e[1].v2 = v[2];

e[2].v1 = v[2];

e[2].v2 = v[3];

e[3].v1 = v[3];

e[3].v2 = v[4];

e[4].v1 = v[4];

e[4].v2 = v[0];

e[5].v1 = v[5];

e[5].v2 = v[6];

e[6].v1 = v[6];

e[6].v2 = v[7];

e[7].v1 = v[7];

e[7].v2 = v[8];

e[8].v1 = v[8];

e[8].v2 = v[5];

while ( TRUE )

{

cleardevice();

outtext( "Enter the key:" );

outtextxy( 20, 10, "'1': Fill with scanning line." );

outtextxy( 20, 20, "'2': Fill with hatching." );

outtextxy( 20, 30, "'q': Quit." );

setcolor( BOUND );

drawpoly( 6, *polyPoints );

rectangle( v[5].x, v[5].y, v[7].x, v[7].y );

cmd = getch();

if ( cmd == '1' )

{

SeedFill( LEFT + 35, TOP + 60, BLUE );

getch();

}

else if ( cmd == '2' )

{

numHatching = CalcPrimitiveInfo( e, 9, K, DELTA_B, bMinMax, edgeMinMax );

for ( i = 1; i <= numHatching; i++ )

{

bCurrent = bMinMax[0] + DELTA_B * i;

DrawHatching( e, 9, bMinMax, edgeMinMax, K, bCurrent );

delay( DELAYTIME );

}

getch();

}

else if ( cmd == 'q' )

{

closegraph();

return 1;

}

}

/* should never be here */

getch();

closegraph () ;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐