图形填充,主要是利用膨胀算法(flood fill 泛洪填充算法)来实现的,公式如下:
P(k+1) = (P(k) + B) ∩ A
A为图形,P(0) 为指定要填充图形内的一点,B 为模板,可以为点,为上下左右中点之类, 当 P(k+1) = P(k) 时算法结束,这里实现两个算法,
算法1:填充指定点,找指定点的上下左右的可填充点,压入栈,再取出栈点作为指定点,直到栈为空。
算法2:填充指定点所在行所有可填充点,再找指定点的上下行中所有的可填充线中的一点,压入栈,再取出栈点作为指定点,直到栈为空。
算法1与2,原理是一样的,都是上面公式的运用,算法1,栈太深空間復雜度過高,一般用算法2。
int draw_unit(unsigned char *data, unsigned char *p, width, int height, int color)
{
int i;
int size = width * height;
for(i = 0; i < size; i++){
if(p[i]){
data[i] = color;
}
}
return 0;
}
struct point{
int x;
int y;
};
struct point *point_init(int x, int y)
{
struct point *p = (struct point *)malloc(sizeof(*p));
//memset(p,0,sizeof(*p));
p->x = x;
p->y = y;
return p;
}
int point_exit(struct point *p)
{
free(p);
return 0;
}
int stack_point_push(struct stack *s, int x, int y)
{
assert(s);
//printf("x:%d y:%d\n", x, y);
struct point *p = point_init(x, y);
stack_push(s, p);
return 0;
}
int draw_point_is_vaild(unsigned char *data, unsigned char *p, int x, int y, int width, int height)
{
if(x < 0 || x >= width){
return 0;
}
if(y < 0 || y >= height){
return 0;
}
int offset = x + y*width;
if(data[offset]){
return 0;
}
if(p[offset]){
return -1;
}
return 1;
}
int draw_point_cmp(struct stack *s, unsigned char *data, unsigned char *p, int x, int y, int width, int height, int color)
{
int xup, yup;
int xdown, ydown;
int xleft, yleft;
int xright, yright;
xup = x;yup = y - 1;
xdown = x; ydown = y + 1;
xleft = x - 1;yleft = y;
xright = x + 1;yright = y;
int result = draw_point_is_vaild(data, p, x, y, width, height);
if(result <= 0){
return 0;
}
result = draw_point_is_vaild(data, p, xup, yup, width, height);
if(result > 0){
stack_point_push(s, xup, yup);
}
result = draw_point_is_vaild(data, p, xdown, ydown, width, height);
if(result > 0){
stack_point_push(s, xdown, ydown);
}
result = draw_point_is_vaild(data, p, xleft, yleft, width, height);
if(result > 0){
stack_point_push(s, xleft, yleft);
}
result = draw_point_is_vaild(data, p, xright, yright, width, height);
if(result > 0){
stack_point_push(s, xright, yright);
}
return 1;
}
int draw_point_line(struct stack *s, unsigned char *data, unsigned char *p, int x, int y, int width, int height, int color)
{
int i;
int begin = x;
int end = x;
for(i = x; i >= 0; i--){
int result = draw_point_is_vaild(data, p, i, y, width, height);
if(result == 0){
break;
}
begin = i;
draw_pixel(p, width, height, 0, 0, i, y, color);
}
for(i = x; i < width; i++){
int result = draw_point_is_vaild(data, p, i, y, width, height);
if(result == 0){
break;
}
end = i;
draw_pixel(p, width, height, 0, 0, i, y, color);
}
int x2, y2;
y2 = y - 1;
x2 = -1;
for(i = end; i >= begin; i--){
int result = draw_point_is_vaild(data, p, i, y2, width, height);
if(result > 0 && x2 < 0){
x2 = i;
stack_point_push(s, x2, y2);
}else if(result == 0){
x2 = -1;
}
}
y2 = y + 1;
x2 = -1;
for(i = end; i >=begin; i--){
int result = draw_point_is_vaild(data, p, i, y2, width, height);
if(result > 0 && x2 < 0){
x2 = i;
stack_point_push(s, x2, y2);
}else if(result == 0){
x2 = -1;
}
}
return 0;
}
int draw_fill2(unsigned char *data, unsigned char *p, int width, int height, int x, int y, int color)
{
int count = 0;
struct point *point;
struct stack *s = stack_init();
draw_point_cmp(s, data, p, x, y, width, height, color);
int n = 0;
int max = 0;
while((point = stack_pop(s))){
x = point->x;
y = point->y;
point_exit(point);
int result = draw_point_line(s, data, p, x, y, width, height, color);
int size = stack_size(s);
if(size > max){
max = size;
}
count++;
}
printf("count:%d -- %d stack max:%d\n", count, n, max);
stack_exit(s);
return 0;
}
int draw_fill(unsigned char *data, int width, int height, int *points, int size, int color)
{
int rowbytes = width;
unsigned char *p = (unsigned char *)malloc(rowbytes * height);
memset(p, 0, sizeof(rowbytes * height));
int i;
for(i = 0;i < size -1; i+=2){
int x, y;
x = points[i];
y = points[i+1];
draw_fill2(data, p, width, height, x, y, color);
}
draw_unit(data, p, width, height, color);
free(p);
return 0;
}
int draw_fill3(unsigned char *data, int width, int height, int color)
{
int rowbytes = width;
unsigned char *p = (unsigned char *)malloc(rowbytes * height);
memset(p, 0, sizeof(rowbytes * height));
int count = 0;
int x = 500;
int y = 500;
struct point *point;
struct stack *s = stack_init();
draw_point_cmp(s, data, p, x, y, width, height, color);
int n = 0;
int max = 0;
while((point = stack_pop(s))){
x = point->x;
y = point->y;
point_exit(point);
int result = draw_point_cmp(s, data, p, x, y, width, height, color);
if(result){
draw_pixel(p, width, height, 0, 0, x, y, color);
n++;
}
int size = stack_size(s);
if(size > max){
max = size;
}
count++;
}
printf("count:%d -- %d stack max:%d\n", count, n, max);
stack_exit(s);
draw_unit(data, p, width, height, color);
free(p);
return 0;
}
stack 加上代码:
//stack.c
#include "stack.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stack_node *stack_node_init(void *data){
struct stack_node *s = (struct stack_node *)malloc(sizeof(*s));
s->next = NULL;
s->data = data;
return s;
}
void stack_node_exit(struct stack_node *node){
if(node->data){
free(node->data);
}
free(node);
}
struct stack *stack_init(){
struct stack *s = (struct stack *)malloc(sizeof(*s));
s->next = NULL;
s->num = 0;
return s;
}
void *stack_push(struct stack *s, void *data){
struct stack_node *node = stack_node_init(data);
node->next = s->next;
s->next = node;
s->num++;
}
void *stack_pop(struct stack *s)
{
void *data;
struct stack_node *node;
if(s->next){
node = s->next;
s->next = node->next;
s->num--;
data = node->data;
node->data = NULL;
stack_node_exit(node);
return data;
}else{
return NULL;
}
}
int stack_size(struct stack *s)
{
return s->num;
}
void stack_exit(struct stack *s)
{
struct stack_node *node;
while((node = stack_pop(s)) != NULL){
stack_node_exit(node);
}
}
//stack.h
#ifndef STACK_H_H_
#define STACK_H_H_
struct stack_node{
void *data;
struct stack_node *next;
};
struct stack{
struct stack_node *next;
int num;
};
struct stack *stack_init();
void *stack_push(struct stack *s, void *data);
void *stack_pop(struct stack *s);
int stack_size(struct stack *s);
void stack_exit(struct stack *s);
#endif