裁剪算法—— 中点分割裁剪算法

实验环境:VC6.0

算法思想:

中点分割算法与cohen sutherland算法一样,首先对线段端点进行编码,并把线段与窗口关系分为三种情况:全在窗口内、完全不在窗口内和线段与窗口有交。对前两种情况作一样处理。对第三种情况,用中点分割的方法求出线段与窗口的交点,即从P0点出发找出距P0点最近的可见点B,两个可见点之间的连线即为线段P0P1的可见部分。

采用中点分割算法从P0出发找最近可见点:先求出P0P1的中点Pm,若P0Pm不是显然不可见的,并且P0P1在窗口中有可见部分,则距P0最近的可见点一定落在P0Pm上,所以用P0Pm代替P0P1,否则取PmP1代替P0P1;再对新的P0P1求中点Pm。重复上述过程,直到PmP1长度小于给定的控制常数为止,此时Pm收敛于交点。

程序实现:

#include "stdafx.h"
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
#include<math.h>
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
void midpointLine(int x0,int y0,int x1,int y1,int color)//中点画线算法
{
    int a,b,d1,d2,d,x,y;
    a=y0-y1;
    b=x1-x0;
    d=2*a+b;
    d1=2*a;
    d2=2*(a+b);
    x=x0;
    y=y0;
    putpixel(x,y,color);
    while(x<x1)
    {
        if(d<0)
        {
            x++;
            y++;
            d+=d2;
        }
        else
        {
            x++;
            d+=d1;
        }
        putpixel(x,y,color);
    }
}
int encode(int x,int y,int XL,int XR,int YB,int YT)//编码
{
    int c=0;
    if(x<XL) c|=LEFT;
    if(x>XR) c|=RIGHT;
    if(y<YB) c|=BOTTOM;
    if(y>YT) c|=TOP;
    return c;
}
void MidLineClip(int x1,int y1,int x2,int y2,int XL,int XR,int YB,int YT)
{
    int code1,code2,code3;//
    float x,y,d;
    int x3,x4=x2,y3,y4=y2;
    code1=encode(x1,y1,XL,XR,YB,YT);
    code2=encode(x2,y2,XL,XR,YB,YT);
    if((code1 & code2) != 0) 
    {
        midpointLine(x1,y1,x2,y2,RGB(0,0,255));//如果直线在裁剪窗口外就用蓝色画出
        printf("线段在窗口外!");
        return;
    }
    while(1)//在线段与窗口有交的情况中,求出离P0最近的可见点
    {
        x=(x1+x2)/2.0;
        y=(y1+y2)/2.0;
        d=sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
        if(d<=1)//精度为1个像素
        {
            x1=x; y1=y;break;
        }
        code3=encode(x,y,XL,XR,YB,YT);
        if((code1 & code3) != 0) 
        {
            x1=x; y1=y; code1=encode(x1,y1,XL,XR,YB,YT);
        }
        else
        {
            x2=x; y2=y; 
        }
    }
    x3=x1;y3=y1;//保存求出的交点坐标
    x2=x4;y2=y4;//恢复P1的初值
    while(1) //在线段与窗口有交的情况中,求出离P1最近的可见点
    {
        x=(x1+x2)/2.0;
        y=(y1+y2)/2.0;
        d=sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
        if(d<=1)
        {
            x2=x; y2=y;break;
        }
        code3=encode(x,y,XL,XR,YB,YT);
        if((code2 & code3) != 0) 
        {
            x2=x; y2=y; code2=encode(x2,y2,XL,XR,YB,YT);
        }
        else
        {
            x1=x; y1=y; 
        }
    }
    x1=x3;y1=y3;
    midpointLine(x1,y1,x2,y2,RGB(255,0,0));//将裁减的直线用红色标注
    return;
}
int main(int argc, char* argv[])
{
    int gdriver=DETECT,gmode;
    int x1=20,y1=30,x2=250,y2=300,XL=10,XR=200,YT=400,YB=30;
    initgraph(&gdriver,&gmode,"c:\\tc");
    cleardevice();
    midpointLine(x1,y1,x2,y2,RGB(0,255,0));//将被裁剪直线用绿色画出
    rectangle(10,400,200,30);//rectangle(int left,int top,int right,int bottom);//裁剪窗口
    MidLineClip(x1,y1,x2,y2,XL,XR,YB,YT);
    getch();
    closegraph();
    return 0;
}

显示效果:

换一组参数后,出现偏差:

posted @ 2017-10-29 14:53  奇热行  阅读(2220)  评论(0)    收藏  举报