算法原理:
分别计算原直线与四条边框延长线的四个交点,在中间的两个交点即为裁剪完成的两个点。
p1-p2黑色直线为原直线;
红色矩形为裁剪边框;
绿色线为裁剪边框的延长线;
紫色为原直线的延长线;
ABCD分别为原直线与四条边框的延长线的交点;
以求B点为例:
B点横坐标已知,若求出BF的长度,则可以用p1坐标表示B点坐标;
BF可用黄色三角形和小三角形 相似三角形求解;
求出系数u,即可求出点坐标。
#include<GL/glut.h>
#include<math.h>
#include<iostream>
#include<algorithm>
float startx = 0, starty = 0, endx = 0, endy = 0;
float xL = 100, xR = 400, yB = 400, yT = 100;
float u1, u2;
using namespace std;
void Breshham(int x0, int y0, int x1, int y1) {
double dx = x1 - x0, dy = y1 - y0;
//绘制垂线
if (fabs(x0 - x1) < 1e-6) {
if (y0 > y1) {
swap(y0, y1);
swap(x0, x1);
}
int x = round(x0), y = round(y0);
for (y = round(y0); y < round(y1); y++) {
glVertex2f(x, y);
}
}
double k, d;
k = dy / dx;
if (k >= 0.0 && k <= 1.0) {
if (x0 > x1) {
swap(x0, x1);
swap(y0, y1);
}
int x = round(x0), y = round(y0);
d = 0.5 - k;
for (x = round(x0); x < round(x1); x++) {
glVertex2f(x, y);
if (d < 0) {
y++;
d += 1 - k;
}
else {
d -= k;
}
}
}
else if (k > 1) {
if (y0 > y1) {
swap(y0, y1);
swap(x0, x1);
}
int x = round(x0), y = round(y0);
d = 1 - 0.5*k;
for (y = round(y0); y < round(y1); y++) {
glVertex2f(x, y);
if (d >= 0) {
x++;
d += 1 - k;
}
else {
d += 1;
}
}
}
else if (k >= -1.0 && k <= 0.0) {
if (x0 < x1) {
swap(x0, x1);
swap(y0, y1);
}
int x = round(x0), y = round(y0);
k = -k;
d = 0.5 - k;
for (x = round(x0); x > round(x1); x--) {
glVertex2f(x, y);
if (d < 0) {
y++;
d += 1 + k;
}
else {
d -= k;
}
}
}
else if (k < -1.0) {
if (y0 > y1) {
swap(x0, x1);
swap(y0, y1);
}
int x = round(x0), y = round(y0);
k = -k;
d = 1 - 0.5*k;
for (y = round(y0); y < round(y1); y++) {
glVertex2f(x, y);
if (d >= 0) {
x--;
d += 1 - k;
}
else {
d += 1;
}
}
}
}
void rectangle()
{
glColor4f(1.0, 1.0, 0.0, 0.75);
glBegin(GL_POLYGON);
glVertex2f(xL, yB);
glVertex2f(xR, yB);
glVertex2f(xR, yT);
glVertex2f(xL, yT);
glEnd();
}
bool ClipT(float p, float q)
{
float r;
if (p < 0)
{
r = q / p;
if (r > u2)
return false;
u1 = max(u1, r);
}
else if (p > 0)
{
r = q / p;
if (r < u1)
return false;
u2 = min(u2, r);
}
else return (q >= 0);
return true;
}
void L_B_lineClip(float x1, float y1, float x2, float y2)
{
float dx = x2 - x1, dy = y2 - y1;
u1 = 0, u2 = 1;
if (ClipT(-dx, x1 - xL))
if (ClipT(dx, xR - x1))
if (ClipT(-dy, y1 - yT))
if (ClipT(dy, yB - y1))
{
cout << u1 <<" "<< u2<<endl;
Breshham(x1 + u1 * dx, y1 + u1 * dy, x1 + u2 * dx, y1 + u2 * dy);
}
}
void solve() {
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_POINTS);
L_B_lineClip(startx, starty, endx, endy);
glEnd();
glFlush();
cout << "初始" << startx << " " << starty << endl << "末尾" << endx << " " << endy << endl << endl;
}
void mouseFunc(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
endx = x;
endy = y;
solve();
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
startx = x;
starty = y;
}
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
rectangle();
glFlush();
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowPosition(600, 250);
glutInitWindowSize(500, 500);
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
glutCreateWindow("jxl");
glClearColor(1.0, 1.0, 1.0, 1.0);
gluOrtho2D(0, 500, 500, 0);
glutDisplayFunc(&display);
glutMouseFunc(mouseFunc);
glutMainLoop();
return 0;
}