首页 / 算法 / openGL实现图形学扫描线种子填充算法
openGL实现图形学扫描线种子填充算法
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了openGL实现图形学扫描线种子填充算法,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6419字,纯文字阅读大概需要10分钟。
内容图文
![openGL实现图形学扫描线种子填充算法](/upload/InfoBanner/zyjiaocheng/1174/982592a3e9644165a24e20b9d1f2f472.jpg)
title: "openGL实现图形学扫描线种子填充算法"
date: 2018-06-11T19:41:30+08:00
tags: ["图形学"]
categories: ["C++"]
先上效果图
白色的起始种子点
代码
#include <GL/glut.h>
#include <cmath>
#include <set>
#include <vector>
#include <unistd.h>
//sleep函数
#include <iostream>
#include <algorithm>
//find函数,查找vector中元素
#include <stack>
using
namespace std;
//规格化为0.05的倍数inline GLdouble normal(GLdouble x)
{
return (round(x * 20) / 20);
}
typedefstruct Point {
GLdouble x, y;
Point(GLdouble a = 0, GLdouble b = 0)
{
x = a, y = b;
}
// set会对插入的元素自动排序,需要重载运算符.定义排序规则////// 重载运算符的要求// 1. 若A<B为真,则B<A为假// 2. 若A<B,B<C --> A<C// 3. A<A永远为假// set中判断元素是否相等// if(!(A<B||B<A)) --> A=Bbooloperator<(const Point &a) const
{
return ((x - a.x) < -0.01 || ((x - a.x) < 0.01 && (y - a.y) < -0.01));
}
booloperator==(const Point &a) const
{
return (abs(x - a.x) < 0.01 && abs(y - a.y) < 0.01);
}
} point;
void drawGrid();
void initGraphBorder();
void drawGraphices();
void myDisplay();
void DDA(point A, point B);
void initGraphBorder();
point first_seed;
unsignedlong m;
staticint n = 40;
static GLfloat pointSize = 12.5;
set<point> graphBorder; // 图形边界数组<set>可以快速查找//set虽然可以快速查找,但却会打乱顺序,不方便实现填充动画
vector<point> graphFill; // 要填充的数组
vector<point> graphVertex; //存储图形定点数组,按顺序
stack<point> seed; //存储种子
GLdouble p = float(2.0 / n); // 每个格子的大小//画网格坐标void drawGrid()
{
glColor3d(1, 1, 1); //网格用白色表示
glLineWidth(1);
glBegin(GL_LINES);
for (int i = 0; i <= n; i++) {
//画竖线
glVertex2d(-1 + 1.0 / n + i * 2.0 / n, -1);
glVertex2d(-1 + 1.0 / n + i * 2.0 / n, 1);
//画横线
glVertex2d(-1, -1 + 1.0 / n + i * 2.0 / n);
glVertex2d(1, -1 + 1.0 / n + i * 2.0 / n);
}
glEnd();
}
//DDA算法void DDA(point A, point B)
{
cout << "连接(" << A.x << ',' << A.y << ") 到 (" << B.x << ',' << B.y << ")\n";
if (A.x > B.x) {
swap(A, B);
}
A.x = normal(A.x);
A.y = normal(A.y);
B.x = normal(B.x);
B.y = normal(B.y);
double delta_x = B.x - A.x;
double delta_y = B.y - A.y;
double k = delta_y / delta_x;
double x = A.x, y = A.y;
if (k > -1 && k < 1) {
//x是最大位移//cout << k << endl;while (true) {
if ((x - B.x) > 0.01)break;
graphBorder.insert(point(normal(x), normal(y)));
x += p;
y += (p * k);
}
}
elseif (k >= 1) {
//Y是最大位移while (true) {
if ((y - B.y) > 0.01) break;
graphBorder.insert(point(normal(x), normal(y)));
y += p;
x += (p / k);
}
}
else {
while (true) {
if ((B.y - y) > 0.01) break;
graphBorder.insert(point(normal(x), normal(y)));
y -= p;
x -= (p / k);
}
}
}
//初始化图形边界数组void initGraphBorder()
{
// graphVertex存储图形的顶点for (auto it = graphVertex.begin(); it != graphVertex.end(); it++) {
if (it == graphVertex.end() - 1) {
//最后一个点连接第一个点
DDA(*it, *graphVertex.begin());
}
else {
//连接it1和it2xr
DDA(*it, *(it + 1));
}
}
}
/********************************* * 1. 初始化:堆栈置空,将种子seed(x,y)入栈 * 2. 出栈: 若栈空则结束,否则将栈顶元素出栈,以y作为当前扫描线 * 3. 填充并确定新种子点所在区域:从当前种子点出发,沿y扫描线向左右方向填充 * 直到遇到边界像素。标记当前区段的左右端点坐标为Xl, Xr. * 4. 确定新种子点:检查[Xl-1,Xr]和[Xl+1,Xr]区域,若存在非边界,未填充的 * 像素,则把每一区间的最右像素作为种子点压栈。返回第2步**********************************/// 沿扫描线的区域填充// 从种子堆栈<stack>seed中取出种子点// 把要填充的点加入<vector>graphFillvoid floodFillSet()
{
while (!seed.empty()) {
point s = seed.top(); //当前种子点
seed.pop();
cout << "当前种子点 " << s.x << " " << s.y << endl;
//填充种子点及左右连续区域
point t = s, xl, xr;
//填充左侧连续区域,并找到区域最左边界while (true) {
//到达边界退出if (t.x < -1)break;
graphFill.push_back(t);
t.x -= p;
//查找是否已填充auto it1 = find(graphFill.begin(), graphFill.end(), t);
//查找是否是边界auto it2 = graphBorder.find(t);
if (it1 != graphFill.end() || it2 != graphBorder.end()) { //已填充或已达边界
xl = t;
xl.x += p;
break;
}
}
t = s;
//填充右侧区域while (true) {
if (t.x > 1)break;
graphFill.push_back(t);
t.x += p;
//查找是否已填充auto it1 = find(graphFill.begin(), graphFill.end(), t);
//查找是否是边界auto it2 = graphBorder.find(t);
if (it1 != graphFill.end() || it2 != graphBorder.end()) { //已填充或已达边界
xr = t;
xr.x -= p;
break;
}
}
//在下一行找种子点for (int d : { 1, -1 }) {//先上再下bool status = false; //标记一段空白区域的开始
t = xl;
t.y += (p * d); //移到下一行或上一行while ((t.x - xr.x) < 0.07) {
auto it1 = find(graphFill.begin(), graphFill.end(), t);
auto it2 = graphBorder.find(t);
//找空白区域开始点//如果当前点是空白区域,且空白区域未开始 则s=trueif (!status && it1 == graphFill.end() && it2 == graphBorder.end()) {
status = true;
}
//区域开始且遇到边界或填充区域if (status && (it1 != graphFill.end() || it2 != graphBorder.end())) { //到达边界或已填充颜色,且左侧有空白区域
status = false;
//添加左侧一点为种子点
seed.push(point(t.x - p, t.y));
}
// 到达最右区间xr,即便不是边界,只要s=true也应标注最右种子点if (status && abs(t.x - xr.x) < 0.01) { //注意浮点数比较大小
status = false;
seed.push(t);
}
t.x += p;
}
}
}
}
//画待填充的图形边界void drawGraphices()
{
glColor3f(0.5, 0.5, 0.2);
glBegin(GL_POINTS);
//C++11的新特性,可以遍历vector map list or {1,2,3}for (auto it : graphBorder) {
glVertex2d(it.x, it.y);
}
glEnd();
}
//画填充像素void drawFloodFill(unsignedlong m)
{
glColor3f(0.4, 0.8, 0.1);
glBegin(GL_POINTS);
for (unsignedlong i = 0; i < m && i < graphFill.size(); i++) {
glVertex2d(graphFill[i].x, graphFill[i].y);
//myDisplay();
}
glEnd();
}
//绘图void myDisplay()
{
glClearColor(0.1f, 0.3f, 0.33f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
//画图形边界
drawGraphices();
//画m个填充像素
drawFloodFill(m);
glColor3d(1, 0, 0);
glPointSize(pointSize);
//加个白点,起始种子点
glColor3d(1, 1, 1);
glBegin(GL_POINTS);
glVertex2d(first_seed.x, first_seed.y);
glEnd();
//画网格
drawGrid();
glFlush();
}
int main(int argc, char *argv[])
{
//存入要填充的图形顶点 8//(-0.7,0.6) (0.7,0.6) (0.7,0) (0.3,0) (0.3,-0.5) (-0.3,-0.5)// (-0.3,0) (-0.7,0)
cout << "请输入顶点坐标,(-1,1) 输入>1 结束 \n";
double x, y;
while (cin >> x) {
if (x > 1)
break;
else
cin >> y;
graphVertex.emplace_back(point(x, y));
}
cout << "输入初始种子点\n";
cin >> x >> y;
first_seed.x = x;
first_seed.y = y;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
//初始化边界集
initGraphBorder();
//扫描线种子填充
seed.push(first_seed);
floodFillSet();
glutCreateWindow("扫描线种子填充");
glutDisplayFunc(&myDisplay);
for (m = 0; m < graphFill.size(); m++) {
usleep(10000);
myDisplay();
}
glutMainLoop();
return0;
}
输入样例
-0.7 0.7
-0.35 0.7
-0.35 0
0.35 0
0.35 0.7
0.7 0.7
0.7 -0.7
-0.7 -0.7
2
0 -0.2
原文:https://www.cnblogs.com/lepeCoder/p/openGL_scan_line.html
内容总结
以上是互联网集市为您收集整理的openGL实现图形学扫描线种子填充算法全部内容,希望文章能够帮你解决openGL实现图形学扫描线种子填充算法所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。