二维图形裁剪算法:
参考博客:
https://blog.csdn.net/m0_46359746/article/details/106392352
Liang-Barsky 线段裁剪算法:
//Liang-Barsky 线段裁剪算法
class wcPt2D {
public:
GLfloat x,y;
public:
/*
Default Constructor:initalize position 48(0.0,0.0).*/
wcPt2D(){
x=y=0.0;
}
wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}
wcPt2D(const wcPt2D& pCopy){
this->x=pCopy.x;
this->y=pCopy.y;
}
void setCoords(GLfloat xCoord,GLfloat yCoord){
x = xCoord;
y = yCoord;
return ;
}
wcPt2D& operator= (wcPt2D p2){
this->x=p2.getx ();
this->y=p2.gety ();
return *this;
}
GLfloat getx()const{
return x;
}
GLfloat gety ( ) const {
return y;
}
};
inline GLint round(const GLfloat a){
return GLint(a + 0.5);
}
GLint clipTest(GLfloat p, GLfloat q, GLfloat * u1, GLfloat *u2){
GLfloat r;
GLint returnValue=true;
if(p<0.0){
r=q/p;
if(r>*u2){
returnValue = false;
}else if(r>*u1){
*u1=r;
}
}else{
if(p>0.0){
r=q/p;
if(r<*u1){
returnValue=false;
}else if(r<*u2){
*u2=r;
}
}else{
if(q<0.0){
returnValue=false;
}
}
}
return (returnValue);
}
void lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2){
GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
dy=p2.gety ()-p1.gety ();
if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
if(u2<1.0){
p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
}
if(u1>0.0){
p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
}
lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
}
}
}
}
return ;
}
display:
// Liang-Barsky线段裁剪算法
//初始直线
glColor3f (0.0,0.0,1.0);
lineBres (0,100,400,300);
glFlush ();
//可视化边界:
glColor3f(1.0,0.0,0.0);
lineBres (100,100,100,300);
lineBres (100,100,300,100);
lineBres (300,300,100,300);
lineBres (300,300,300,100);
glColor3f (0.0,1.0,0.0);
lineClipLiangBrask (wcPt2D(100,100), wcPt2D(300, 300), wcPt2D(0,100),wcPt2D(400, 300));
glFlush ();
Liang-Barsky 多边形裁剪算法:
//-----------------------------------------
//Liang-Barsky 线段裁剪算法
class wcPt2D {
public:
GLfloat x,y;
public:
/*
Default Constructor:initalize position 48(0.0,0.0).*/
wcPt2D(){
x=y=0.0;
}
wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}
wcPt2D(const wcPt2D& pCopy){
this->x=pCopy.x;
this->y=pCopy.y;
}
void setCoords(GLfloat xCoord,GLfloat yCoord){
x = xCoord;
y = yCoord;
return ;
}
wcPt2D& operator= (wcPt2D p2){
this->x=p2.getx ();
this->y=p2.gety ();
return *this;
}
GLfloat getx()const{
return x;
}
GLfloat gety ( ) const {
return y;
}
};
inline GLint round(const GLfloat a){
return GLint(a + 0.5);
}
GLint clipTest(GLfloat p, GLfloat q, GLfloat * u1, GLfloat *u2){
GLfloat r;
GLint returnValue=true;
if(p<0.0){
r=q/p;
if(r>*u2){
returnValue = false;
}else if(r>*u1){
*u1=r;
}
}else{
if(p>0.0){
r=q/p;
if(r<*u1){
returnValue=false;
}else if(r<*u2){
*u2=r;
}
}else{
if(q<0.0){
returnValue=false;
}
}
}
return (returnValue);
}
void lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2){
GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
dy=p2.gety ()-p1.gety ();
if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
if(u2<1.0){
p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
}
if(u1>0.0){
p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
}
lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
// return 2;
}
}
}
}
return ;
}
int lineClipLiangBrask(wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2, wcPt2D pOut[]){
GLfloat u1=0.0, u2=1.0, dx=p2.getx ()-p1.getx (),dy;
if(clipTest (-dx, p1.getx ()-winMin.getx (),&u1, &u2)){
if(clipTest (dx, winMax.getx ()-p1.getx (),&u1, &u2)){
dy=p2.gety ()-p1.gety ();
if(clipTest (-dy, p1.gety ()-winMin.gety (), &u1, &u2)){
if(clipTest (dy,winMax.gety ()-p1.gety (),&u1, &u2)){
if(u2<1.0){
p2.setCoords(p1.getx ()+u2*dx,p1.gety ()+u2*dy);
}
if(u1>0.0){
p1.setCoords(p1.getx ()+u1*dx, p1.gety ()+u1*dy);
}
pOut[0]=p1;
pOut[1]=p2;
// lineDDA (round(p1.getx ()), round (p1.gety ()),round(p2.getx ()),round(p2.gety ()));
return 2;
}
}
}
}
return 0;
}
void display(){
glClear (GL_COLOR_BUFFER_BIT);
//可视化边界:
const int minX=100, minY=100, maxX=300, maxY=300;
glColor3f(1.0,0.0,0.0);
lineDDA (minX,minY,minX,maxY);
lineDDA (minX,minY,maxX,minY);
lineDDA (maxX,maxY,minX,maxY);
lineDDA (maxX,maxY,maxX,minY);
glColor3f(0.0,1.0,0.0);
GLint n=5;
wcPt2D pIn[n];
pIn[0].setCoords (0,200);
pIn[1].setCoords (150,250);
pIn[2].setCoords (250,250);
pIn[3].setCoords (400,200);
pIn[4].setCoords (200,50);
for(int i=0;i<n;++i){
lineDDA (pIn[i].x,pIn[i].y,pIn[(i+1)%n].x,pIn[(i+1)%n].y);
}
wcPt2D pOut[20];
wcPt2D tempPOut[2];
int outCount=0;
int flag=0;
for(int i=0;i<n;++i){
flag=lineClipLiangBrask (wcPt2D(minX,minY), wcPt2D(maxX, maxY), pIn[i],pIn[(i+1)%n],tempPOut);
if(flag==2){
for(int j=0;j<2;++j){
pOut[outCount++]=tempPOut[j];
}
}
}
glColor3f(0.0,0.0,1.0);
int i=1;
for(;i<=outCount;++i){
lineDDA (pOut[i-1].x,pOut[i-1].y,pOut[i%outCount].x,pOut[i%outCount].y);
}
glFlush ();
return ;
}
效果:
Sutherland-Hodgman多边形裁剪算法
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <windows.h>
#include <gl/glut.h>
#include <math.h>
#include <stdio.h>
const int windowWidge=600, windowHeight=600;
void setPixel(GLint xCoord, GLint yCoord){
glBegin (GL_POINTS);
glVertex2i (xCoord, yCoord);
glEnd();
}
//-----------------------------------------
void lineDDA (int x0, int y0, int xEnd, int yEnd){
int dx=xEnd-x0,dy=yEnd-y0,steps,k;
float xIncrement,yIncrement,x=x0,y=y0;
if(fabs(dx)> fabs(dy)){
steps = fabs(dx);
}else {
steps = fabs(dy);
}
xIncrement = float(dx)/float(steps);
yIncrement = float(dy)/ float(steps);
setPixel(round(x),round(y));
for(k = 0;k< steps;k++){
x += xIncrement;
y += yIncrement;
setPixel(round(x),round(y));
}
return ;
}
//---------------------------------------------
//Sutherland-Hodgman多边形裁剪算法
class wcPt2D {
public:
GLfloat x,y;
public:
/*
Default Constructor:initalize position 48(0.0,0.0).*/
wcPt2D(){
x=y=0.0;
}
wcPt2D(GLfloat nx, GLfloat ny): x(nx), y(ny){}
wcPt2D(const wcPt2D& pCopy){
this->x=pCopy.x;
this->y=pCopy.y;
}
void setCoords(GLfloat xCoord,GLfloat yCoord){
x = xCoord;
y = yCoord;
return ;
}
wcPt2D& operator= (wcPt2D p2){
this->x=p2.getx ();
this->y=p2.gety ();
return *this;
}
GLfloat getx()const{
return x;
}
GLfloat gety ( ) const {
return y;
}
};
//枚举类的替代, C++中enum的操作与C有很大不同
const int Left=0, Right=1, Bottom=2, Top=3;
//typedef enum{
// Left, Right, Bottom, Top
//} Boundary;
using namespace std;
const GLint nClip = 4;
//判断点p是否在显示框内
GLint inside(wcPt2D p, int b, wcPt2D wMin, wcPt2D wMax){
int flag=true;
switch(b){
case Left:{
if(p.getx ()<wMin.getx ()){
flag=false;
}
break;
}
case Right:{
if(p.getx ()>wMax.getx ()){
flag=false;
}
break;
}
case Bottom:{
if(p.gety ()<wMin.gety ()){
flag=false;
}
break;
}
case Top:{
if(p.gety ()>wMax.gety ()){
flag=false;
}
break;
}
}
return flag;
}
//判断向量(p1, p2)是否与边界相交
GLint cross(wcPt2D p1, wcPt2D p2, int winEdge, wcPt2D wMin, wcPt2D wMax){
if(inside (p1,winEdge,wMin,wMax)==inside (p2, winEdge, wMin, wMax)){
return false;
}else{
return true;
}
}
//返回向量(p1, p2)与相应边界的交点
wcPt2D intersect(wcPt2D p1, wcPt2D p2, int winEdge, wcPt2D wMin, wcPt2D wMax){
wcPt2D iPt;
GLfloat m;
if(p1.x!= p2.x){
m=(p1.gety ()-p2.gety ())/(p1.getx ()-p2.getx ());
}
switch (winEdge) {
case Left:{
iPt.x=wMin.x;
iPt.y=p2.y+(wMin.x-p2.x)*m;
break;
}
case Right:{
iPt.x=wMax.x;
iPt.y=p2.y+(wMax.x-p2.x)*m;
break;
}
case Bottom:{
iPt.y=wMin.y;
if(p1.x!=p2.x){
iPt.x=p2.x+(wMin.y-p2.y)/m;
}else{
iPt.x=p2.x;
}
break;
}
case Top:{
iPt.y=wMax.y;
if(p1.x!=p2.x){
iPt.x=p2.x+(wMax.y-p2.y)/m;
}else{
iPt.x=p2.x;
}
break;
}
}
return iPt;
}
void clipPoint(wcPt2D &p, int winEdge, wcPt2D wMin, wcPt2D wMax, wcPt2D * pOut,
int *cnt, wcPt2D first[], wcPt2D *s){
wcPt2D iPt;
//判断first[winEdge]为nullPtr
if(first[winEdge].x==0 && first[winEdge].y==0){
first[winEdge]=p;
}else{
if(cross(p,s[winEdge], winEdge, wMin, wMax)){
iPt=intersect (p, s[winEdge], winEdge, wMin, wMax);
if(winEdge<Top){
clipPoint (iPt, winEdge+1, wMin, wMax, pOut, cnt, first, s);
}else{
//存交点
pOut[*cnt] =iPt;
(*cnt)++;
}
}
}
s[winEdge]=p;
if(inside (p,winEdge, wMin, wMax)){
if(winEdge<Top){
clipPoint (p, winEdge+1, wMin, wMax, pOut, cnt, first, s);
}else{
pOut[*cnt]=p;
(*cnt)++;
}
}
}
void closeClip(wcPt2D wMin, wcPt2D wMax, wcPt2D *pOut, GLint *cnt,
wcPt2D first[],wcPt2D *s){
wcPt2D pt;
int winEdge;
for(winEdge=Left; winEdge<=Top;winEdge++){
if(cross(s[winEdge],first[winEdge],winEdge, wMin, wMax)){
pt=intersect (s[winEdge], first[winEdge], winEdge, wMin, wMax);
if(winEdge<Top){
clipPoint (pt, winEdge+1, wMin, wMax, pOut, cnt, first, s);
}else{
pOut[*cnt]=pt;
(*cnt)++;
}
}
}
}
GLint polygonClipSuthHodg(wcPt2D wMin, wcPt2D wMax, GLint n, wcPt2D *pIn, wcPt2D *pOut){
wcPt2D first[nClip] , s[nClip];
GLint k, cnt=0;
for(k=0;k<n;k++){
clipPoint (pIn[k],Left, wMin, wMax, pOut, &cnt, first, s);
}
closeClip (wMin, wMax, pOut, &cnt, first, s);
return cnt;
}
//---------------------------------------------
//绘制程序
void display(){
//Sutherland-Hodgman多边形裁剪算法
glClear (GL_COLOR_BUFFER_BIT);
//可视化边界:
const int minX=100, minY=100, maxX=300, maxY=300;
glColor3f(1.0,0.0,0.0);
lineDDA (minX,minY,minX,maxY);
lineDDA (minX,minY,maxX,minY);
lineDDA (maxX,maxY,minX,maxY);
lineDDA (maxX,maxY,maxX,minY);
//定义多边形的颜色和顶点
glColor3f(0.0,1.0,0.0);
GLint n=6;
wcPt2D pIn[n];
pIn[0].setCoords (50,200);
pIn[1].setCoords (150,250);
pIn[2].setCoords (250,250);
pIn[3].setCoords (350,200);
pIn[4].setCoords (250,50);
pIn[5].setCoords (150,50);
//绘制原始多边形
for(int i=0;i<n;++i){
lineDDA (pIn[i].x,pIn[i].y,pIn[(i+1)%n].x,pIn[(i+1)%n].y);
}
//获取裁剪后的点集
wcPt2D pOut[20];
int count=polygonClipSuthHodg (wcPt2D(minX,minY),wcPt2D(maxX,maxY),n,pIn,pOut);
//定义裁剪后的多边形颜色
glColor3f(0.0,0.0,1.0);
//绘制裁剪后的多边形
for(int i=1;i<=count;++i){
lineDDA (pOut[i-1].x,pOut[i-1].y,pOut[i%count].x,pOut[i%count].y);
}
glFlush ();
return ;
}
//初始化绘制
void init(){
glClearColor(1.0,1.0,1.0,0.0);//清除颜色设置
glMatrixMode(GL_PROJECTION);//设置投影方式
gluOrtho2D (0.0,windowWidge*1.0,0.0,windowHeight*1.0);
return ;
}
int main(int argc, char** argv){
glutInit(&argc, argv);//初始化glut
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置显示模式为单缓冲,RGB模式
glutInitWindowPosition(0,0);//设置窗口位置
glutInitWindowSize(windowWidge,windowHeight);//设置窗口大小
glutCreateWindow("lineClipLiangBrask");//设置窗口标题
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}