OpenGL - 帮助限制曲线永远不会超出范围

时间:2014-04-18 17:44:03

标签: c++ opengl bezier curves

我有以下程序使用Bézier曲线绘制弧线:

#include <GL/gl.h>
#include <GL/glu.h>
#include <stdlib.h>
#include <GL/openglut.h>
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <time.h>
#include <ctime>
#include <cstdlib>
#include <fstream>
#include <sstream>


std::ofstream nul("/dev/null");
std::ostream * err=&std::cerr;

class Point {
public:
int _id;
GLfloat _x;
GLfloat _y;
GLfloat _z;

Point(int id, GLfloat x, GLfloat y, GLfloat z) :
    _id(id),
    _x(x),
    _y(y),
    _z(z) {
}

void PrintPoint() {
    printf("Point %d = <%f, %f, %f>\n", _id, _x, _y, _z);
}
};

Point getControl(Point a, Point b){

if(a._x < b._x && a._y < b._y){
    Point ctrl(10, ((a._x+b._x)/2)+(0.25*(b._x-a._x)), ((a._y+b._y)/2)-(0.25*(b._x-a._x)), 0.0);
    return ctrl;
} else if(a._x < b._x && a._y > b._y){
    Point ctrl(10, ((a._x+b._x)/2)+(0.25*(b._x-a._x)), ((a._y+b._y)/2)-(0.25*(b._x-a._x)), 0.0);
    return ctrl;
} else if(b._x < a._x && b._y < a._y){
    Point ctrl(10, ((a._x+b._x)/2)+(0.25*(b._x-a._x)), ((a._y+b._y)/2)-(0.25*(b._x-a._x)), 0.0);
    return ctrl;
} else if(b._x < a._x && b._y > a._y){
    Point ctrl(10, ((a._x+b._x)/2)+(0.25*(b._x-a._x)), ((a._y+b._y)/2)-(0.25*(b._x-a._x)), 0.0);
    return ctrl;
} else if(a._x == b._x && a._y != b._y){
    Point ctrl(10, ((a._x+b._x)/2) + (0.25*a._x), (a._y+b._y)/2, 0.0);
    return ctrl;
} else if(a._x != b._x && a._y == b._y){
    Point ctrl(10, ((a._x+b._x)/2), ((a._y+b._y)/2) + (0.25*a._y), 0.0);
    return ctrl;
}
return a;
}

GLfloat bezierP(float t, GLfloat P0, GLfloat P1, GLfloat P2, GLfloat P3) {
GLfloat point = (pow((1-t), 3.0) * P0) +
    (3 * pow((1-t),2) * t * P1) +
    (3 * (1-t) * t * t * P2) +
    (pow(t, 3) * P3);
return point;
}

void drawBezierArc(Point start, Point end){

Point ctrl = getControl(start, end);
start.PrintPoint();
end.PrintPoint();
ctrl.PrintPoint();

int i;

glColor3f(1.0, 1.0, 0.0);
glBegin(GL_LINE_STRIP);
    int t = 60;
    for (i = 0; i <= t; i++) {
        float pos = (float) i / (float) t;
        GLfloat x = bezierP(pos, start._x, ctrl._x, ctrl._x, end._x);
        GLfloat y = bezierP(pos, start._y, ctrl._y, ctrl._y, end._y);
        GLfloat z = bezierP(pos, start._z, ctrl._z, ctrl._z, end._z);

        glVertex3f(x, y, z);
    }
glEnd();

glFlush();
}

void display(void) {

Point start1(0, 6, -2, 0);
Point end1(0, 6, 4, 0);

Point start2(0, 0, 2, 0);
Point end2(0, 4, 3, 0);

Point start3(0, -2, 0, 0);
Point end3(0, 1, 0, 0);

Point start4(0, -4, 3, 0);
Point end4(0, -4, -2, 0);

drawBezierArc(start1, end1);
drawBezierArc(start2, end2);
drawBezierArc(start3, end3);
drawBezierArc(start4, end4);

glFlush();
}

void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

if (w <= h) {
    glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
} else {
    glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
}

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

int main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (640, 480);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);

glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glShadeModel(GL_FLAT);

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}

Problem

这里的曲线是用Bézier曲线制作的,所以每条曲线都是一系列直线,使它看起来像弧/曲线。正如你在最右边的弧线所看到的那样,它超越了窗户界限。当这样的事情发生时,我想限制它并将超出的线保持在窗口内(或者至少沿着窗口的边缘)。

我对这个问题的看法是减去超出点距离窗口边缘的距离,但这似乎不起作用。它是这样的:

double dist = exceedingPoint - boundaryValue;
exceedingPoint = exceedingPoint - dist;

谢谢!

1 个答案:

答案 0 :(得分:0)

我不确定这是否真的有资格作为OpenGL问题 - 但更多的是解决问题。

取决于您的需求(以及查看上述评论) -

1)您可以评估贝塞尔曲线的大小(找出矩形的大小,如果它包含曲线),然后查看它是否会超出窗口大小。调整大小或移动曲线以使其适应。

2)在计算点时评估点。如果它们看起来像是在窗口之外,那么将点的坐标设置为窗口的边缘。

3)学习GLSL并弄清楚Vertex Shader如何能够做到#2。

基本上,你可以做很多事情。再试一次!