• 矩形内与边界折线填充问题


    近日,有搞数控与CAD的朋友遇到此问题,与本人谈及,遂有兴趣完成此程序。

    程序的目标,是从矩形一角出发,沿边界前进,到一个距离后,斜向拐弯,然后遇到边界,沿边界前进一个距离,再拐弯,依次前进,直到最后一个矩形边界。

    效果图如下:

    该程序看上去很简单,但具体实现起来,需要考虑的细节不少,本人的方法,是直线矩形裁剪算法+绘图起点两侧的vector存储交点,同时交点结构体中有一个标志与下一点是否连线的变量。

    上代码了 。。。。。

    首先,依然是那个坑爹的stdafx.h

    #pragma once
    #include "targetver.h"
    
    #define WIN32_LEAN_AND_MEAN             //从Windows头中排除极少使用的资料
    
    //C++标准库头文件
    #include<vector>
    using namespace std;
    
    //Windows 头文件:
    #include <windows.h>
    
    //C运行时头文件
    #include<stdlib.h>
    #include<malloc.h>
    #include<memory.h>
    #include<tchar.h>
    #include<math.h>
    
    //TODO:在此处引用程序需要的其他头文件
    #include"myconst.h"
    #include"mygraph.h"

    紧跟着就是stdafx.cpp

    // stdafx.cpp : 只包括标准包含文件的源文件
    // sdkRectfill.pch 将作为预编译头
    // stdafx.obj 将包含预编译类型信息
    
    #include "stdafx.h"
    
    // TODO: 在 STDAFX.H 中
    // 引用任何所需的附加头文件,而不是在此文件中引用

    然后是一直使用但似乎没见到太大作用的targetver.h

    #pragma once
    
    // 以下宏定义要求的最低平台。要求的最低平台
    // 是具有运行应用程序所需功能的 Windows、Internet Explorer 等产品的
    // 最早版本。通过在指定版本及更低版本的平台上启用所有可用的功能,宏可以
    // 正常工作。
    
    // 如果必须要针对低于以下指定版本的平台,请修改下列定义。
    // 有关不同平台对应值的最新信息,请参考 MSDN。
    #ifndef WINVER                          // 指定要求的最低平台是 Windows Vista。
    #define WINVER 0x0600           // 将此值更改为相应的值,以适用于 Windows 的其他版本。
    #endif
    
    #ifndef _WIN32_WINNT            // 指定要求的最低平台是 Windows Vista。
    #define _WIN32_WINNT 0x0600     // 将此值更改为相应的值,以适用于 Windows 的其他版本。
    #endif
    
    #ifndef _WIN32_WINDOWS          // 指定要求的最低平台是 Windows 98。
    #define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以适用于 Windows Me 或更高版本。
    #endif
    
    #ifndef _WIN32_IE                       // 指定要求的最低平台是 Internet Explorer 7.0。
    #define _WIN32_IE 0x0700        // 将此值更改为相应的值,以适用于 IE 的其他版本。
    #endif

    一行语句,包含了资源文件声明的sdkRectfill.h

    #pragma once
    
    #include "resource.h"

    资源声明的h文件(这个忽略了,因为在VC中新建Win32Application后,自然就有这个了,不必理会)

    **来正题了**

    定义了一堆常量的myconst.h,这里大部分是在GUI时由用户输入的。

    #ifndef _myconst_h_
    #define _myconst_h_
    
    //函数执行是否成功的标识
    const int INTOK=1;
    const int INTERR=0;
    
    const float PI=3.14159265f;
    
    //设置初始边界变量
    const int LEFT=0x0001;
    const int RIGHT=0x0010;
    const int BOTTOM=0x0100;
    const int TOP=0x1000;
    
    //本部分数值实际工程中可由用户输入
    /******Begin******/
    //测试用初始线段的两端点
    const int LINE_START_X=20;
    const int LINE_START_Y=10;
    const int LINE_END_X=800;
    const int LINE_END_Y=400;
    
    //初始矩形的两顶点
    const int REC_X_LEFT=40;
    const int REC_Y_BOTTOM=50;
    const int REC_X_RIGHT=600;
    const int REC_Y_TOP=500;
    
    //起始直线倾角
    //倾角与绘制起始点也有范围关系,本次暂不做校验
    const int ARG_ANGLE=60;
    const int ARG_NULL=90;
    
    //在矩形上可选的绘制起点(暂定为自左上角启动)
    const int REC_LEFTBOTTOM=1;
    const int REC_LEFTTOP=2;
    const int REC_RIGHTBOTTOM=3;
    const int REC_RIGHTTOP=4;
    
    //直线间距
    const int LINE_DIST=30;
    
    //边界填充的初始坐标选择
    const int EDGE_X=1;
    const int EDGE_Y=2;
    
    /******End******/
    
    #endif

    绘图处理函数的声明mygraph.h

    #ifndef _mygraph_h_
    #define _mygraph_h_
    
    struct newPoint
    {
        int x;
        int y;
        int intNextForward;
    }myPointStruct;
    
    typedef struct newPoint myPoint; 
    
    
    //初始化函数
    extern int intInitSet(int *,int);
    
    //依据倾角计算斜率的函数声明
    extern float flaKCalc(int);
    
    //线段的端点赋值函数声明
    extern int intLineset(int *,int *,int *,int *,int,int,int,int);
    
    //判别XY轴增长方向的函数
    //暂未考虑倾角的合理性校验
    extern int intXYFoward(int *,int *,int);
    
    //根据起始点标志变量计算矩形起始点实际坐标函数声明
    extern int intXYStart(int *,int *,int);
    
    //PI/2-倾角的正负校验
    extern int intYAngleStepCalc(int);
    
    //对角点坐标计算函数声明
    extern int intXYDig(int *,int *,int);
    
    //对角点到起始直线的距离计算函数声明
    extern int intPt2LineStartCalc(int,int,int,int,float);
    
    //边界绘制时初始XY两轴交点是否连接的处理函数声明
    extern int intXYEdge(int *,int *,int);
    
    //Cohen-Sutherland编码函数声明
    extern int cohenCode(int,int);
    
    //Cohen-Sutherland处理函数声明
    extern int cohenProcess(int *,int *,int *,int *,int,int,int,int);
    
    #endif

    绘图处理函数的实现mygraph.cpp

    #include<stdafx.h>
    
    //初始化函数
    int intInitSet(int *iDst,int iSrc)
    {
        *iDst=iSrc;
        return INTOK;
    }
    
    //依据倾角计算斜率
    float flaKCalc(int intArg)
    {
        if((intArg+ARG_NULL)%ARG_NULL)
        {
            return tan(intArg*PI/180);
            
        }
        else
            return (float)INTERR;
    }
    
    //线段两端点值的赋值函数
    int intLineset(int *pintXNewStart,int *pintYNewStart,int *pintXNewEnd,int *pintYNewEnd,int intXStart,int intYStart,int intXEnd,int intYEnd)
    {
        
        *pintXNewStart=intXStart;
        *pintYNewStart=intYStart;
        *pintXNewEnd=intXEnd;
        *pintYNewEnd=intYEnd;
        
        return INTOK;    
    }
    
    //判别批量绘制直线时XY轴增长方向的函数
    int intXYFoward(int *iXStep,int *iYStep,int intRecStartSet)
    {
        switch(intRecStartSet)
        {
        case REC_LEFTBOTTOM:
            *iXStep=1;
            *iYStep=1;
            return INTOK;
        case REC_LEFTTOP:
            *iXStep=1;
            *iYStep=-1;
            return INTOK;
        case REC_RIGHTBOTTOM:
            *iXStep=-1;
            *iYStep=1;
            return INTOK;
        case REC_RIGHTTOP:
            *iXStep=-1;
            *iYStep=-1;
            return INTOK;
        default:
            *iXStep=0;
            *iYStep=0;
            return INTERR;
        }
    }
    
    //根据起始点标志变量计算矩形起始点实际坐标函数
    int intXYStart(int *iXRecStart,int *iYRecStart,int intPtRecStart)
    {
        switch(intPtRecStart)
        {
        case REC_LEFTBOTTOM:
            *iXRecStart=REC_X_LEFT;
            *iYRecStart=REC_Y_BOTTOM;
            return INTOK;
        case REC_LEFTTOP:
            *iXRecStart=REC_X_LEFT;
            *iYRecStart=REC_Y_TOP;
            return INTOK;
        case REC_RIGHTBOTTOM:
            *iXRecStart=REC_X_RIGHT;
            *iYRecStart=REC_Y_BOTTOM;
            return INTOK;
        case REC_RIGHTTOP:
            *iXRecStart=REC_X_RIGHT;
            *iYRecStart=REC_Y_TOP;
            return INTOK;
        default:
            *iXRecStart=0;
            *iYRecStart=0;
            return INTERR;
        }
    }
    
    //PI/2-倾角的正负校验
    int intYAngleStepCalc(int intRecStartSet)
    {
        switch(intRecStartSet)
        {
        case REC_LEFTBOTTOM:
            return -1;
        case REC_LEFTTOP:
            return 1;
        case REC_RIGHTBOTTOM:
            return 1;
        case REC_RIGHTTOP:
            return -1;
        default:
            return INTERR;
        }    
    }
    
    //对角点坐标计算函数
    int intXYDig(int *iXDig,int *iYDig,int intPtRecStart)
    {
        switch(intPtRecStart)
        {
        case REC_LEFTBOTTOM:
            *iXDig=REC_X_RIGHT;
            *iYDig=REC_Y_TOP;
            return INTOK;
        case REC_LEFTTOP:
            *iXDig=REC_X_RIGHT;
            *iYDig=REC_Y_BOTTOM;
            return INTOK;
        case REC_RIGHTBOTTOM:
            *iXDig=REC_X_LEFT;
            *iYDig=REC_Y_TOP;
            return INTOK;
        case REC_RIGHTTOP:
            *iXDig=REC_X_LEFT;
            *iYDig=REC_Y_BOTTOM;
            return INTOK;
        default:
            *iXDig=0;
            *iYDig=0;
            return INTERR;
        }
    }
    
    //对角点到起始直线的距离计算
    //intXPt:对角点X坐标
    //intYPt:对角点Y坐标
    //intXInLine:点斜式中所用在直线上的点X坐标
    //intYInLine:点斜式中所用在直线上的点Y坐标
    //k:直线斜率
    int intPt2LineStartCalc(int intXPt,int intYPt,int intXInLine,int intYInLine,float k)
    {
        if(k)
        {
            return (int)(fabs(k*intXPt+(-1)*intYPt+intYInLine-k*intXInLine)/sqrt(k*k+1));
        }
        else
            return INTERR;
    }
    
    //边界绘制时初始XY两轴交点是否连接的处理函数声明
    //iXEdge对应mpAdd一侧的初始状态
    //iYEdge对应mpSub一侧的初始状态
    int intXYEdge(int *iXEdge,int *iYEdge,int iEdgeForward)
    {
        switch(iEdgeForward)
        {
        case EDGE_X:
            *iXEdge=-1;
            *iYEdge=1;
            return INTOK;
        case EDGE_Y:
            *iXEdge=1;
            *iYEdge=-1;
            return INTOK;
        default:
            return INTERR;
        }
    }
    
    
    //Cohen编码函数定义
    int cohenCode(int x,int y)
    {
        int c=0;
        if(x<REC_X_LEFT)
            c|=LEFT;
        if(x>REC_X_RIGHT)
            c|=RIGHT;
        if(y<REC_Y_BOTTOM)
            c|=BOTTOM;
        if(y>REC_Y_TOP)
            c|=TOP;
        return c;
    }
    
    //Cohen裁剪算法处理函数
    int cohenProcess(int *pintXNewStart,int *pintYNewStart,int *pintXNewEnd,int *pintYNewEnd,int xs,int ys,int xe,int ye)
    {
        int intCode1,intCode2,intCode;
        int x,y;
     
        intCode1=cohenCode(xs,ys);
        intCode2=cohenCode(xe,ye);
     
        while(intCode1!=0||intCode2!=0)
        {
            if((intCode1 & intCode2)!=0)
                return INTERR;
            intCode=intCode1;
            if(intCode1==0)
            {
                intCode=intCode2;
            }
            if((LEFT & intCode)!=0)
            {
                x=REC_X_LEFT;
                y=ys+(ye-ys)*(REC_X_LEFT-xs)/(xe-xs);
            }
            else if((RIGHT & intCode)!=0)
            {
                x=REC_X_RIGHT;
                y=ys+(ye-ys)*(REC_X_RIGHT-xs)/(xe-xs);
            }
            else if((BOTTOM & intCode)!=0)
            {
                y=REC_Y_BOTTOM;
                x=xs+(xe-xs)*(REC_Y_BOTTOM-ys)/(ye-ys);
            }
            else if((TOP & intCode)!=0)
            {
                y=REC_Y_TOP;
                x=xs+(xe-xs)*(REC_Y_TOP-ys)/(ye-ys);
            }
     
            if(intCode==intCode1)
            {
                xs=x;
                ys=y;
                intCode1=cohenCode(x,y);
            }
            else
            {
                xe=x;
                ye=y;
                intCode2=cohenCode(x,y);
            }
        }
        intLineset(pintXNewStart,pintYNewStart,pintXNewEnd,pintYNewEnd,xs,ys,xe,ye); //用处理完毕的xs,ys,xe,ye对线段两端点进行赋值
        return INTOK;
    }

    最终,主文件(sdkRectfill.cpp)出场了,因为有不少是WindowsSDK自动生成的,比较长,默认折叠吧,需要看的朋友请展开。

    主要功能,在CREATE和PAINT消息当中完成。

    View Code
    //sdkRectfill.cpp:定义应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include "sdkRectfill.h"
    
    /******以下各全局变量最后将检查并进行局部化******/
    //Cohen算法处理结果是否成功的标识
    int intCohenPro=0;
    
    //线段两个端点变量
    int intXLineStart,intYLineStart,intXLineEnd,intYLineEnd;
    
    //交点坐标
    int intXAddCross,intYAddCross,intXSubCross,intYSubCross;
    
    //矩形两个定义点变量
    int intXRecLeft,intYRecBottom,intXRecRight,intYRecTop;
    
    //绘制直线的倾角与斜率(同时完成初始化)
    int intArgAngle=0;
    float flaK=0.0f;
    
    //批量绘制工作在矩形上的启动点与方向标识变量
    int intPtRecStart=0;
    
    //矩形起始点坐标
    int intXRecStart=0;
    int intYRecStart=0;
    
    //矩形对角线长度变量
    int intRecDiag=0;
    
    //矩形绘制起始点对角点坐标
    int intXDig=0;
    int intYDig=0;
    
    //绘制过程中直线的间距
    int intLineDist=0;
    
    //对角点到起始直线的距离
    int intPt2LineStart=0;
    
    //需要绘制的直线个数变量
    int intLineCount=0;
    
    //绘制时xy两轴的坐标变化方向变量(将取值为1或-1)
    int intXStep=0;
    int intYStep=0;
    
    //PI/2-倾角的正负标志变量
    int intYAngleStep=0;
    
    //存储批量绘制直线的交点坐标
    vector<myPoint>vecAddCross;
    vector<myPoint>vecSubCross;
    
    //最终从启动点开始沿XY某坐标轴方向的选择标志变量
    int intEdgeForward=0;
    int intXEdge=0;
    int intYEdge=0;
    
    //**如下部分为Windows程序自有声明及定义**
    #define MAX_LOADSTRING 100
    
    HINSTANCE hInst;                                // 当前实例
    TCHAR szTitle[MAX_LOADSTRING];                    // 标题栏文本
    TCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名
    
    //若干基本的函数声明
    ATOM MyRegisterClass(HINSTANCE hInstance);
    BOOL InitInstance(HINSTANCE,int);
    LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
    INT_PTR CALLBACK About(HWND,UINT,WPARAM,LPARAM);
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
        MSG msg;
        HACCEL hAccelTable;
    
        //初始化全局字符串
        LoadString(hInstance,IDS_APP_TITLE,szTitle,MAX_LOADSTRING);
        LoadString(hInstance,IDC_SDKRECTFILL,szWindowClass,MAX_LOADSTRING);
        MyRegisterClass(hInstance);
    
        //执行应用程序初始化:
        if (!InitInstance (hInstance,nCmdShow))
        {
            return FALSE;
        }
    
        hAccelTable=LoadAccelerators(hInstance,MAKEINTRESOURCE(IDC_SDKRECTFILL));
    
        //主消息循环:
        while(GetMessage(&msg,NULL,0,0))
        {
            if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return (int) msg.wParam;
    }
    
    
    //函数MyRegisterClass():注册窗口类。
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEX wcex;
        wcex.cbSize=sizeof(WNDCLASSEX);
        wcex.style=CS_HREDRAW|CS_VREDRAW;
        wcex.lpfnWndProc=WndProc;
        wcex.cbClsExtra=0;
        wcex.cbWndExtra=0;
        wcex.hInstance=hInstance;
        wcex.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_SDKRECTFILL));
        wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
        wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName=MAKEINTRESOURCE(IDC_SDKRECTFILL);
        wcex.lpszClassName=szWindowClass;
        wcex.hIconSm=LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_SMALL));
    
        return RegisterClassEx(&wcex);
    }
    
    //函数InitInstance(HINSTANCE, int)保存实例句柄并创建主窗口
    BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
    {
       HWND hWnd;
       hInst=hInstance; // 将实例句柄存储在全局变量中
    
       hWnd=CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
       if(!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd,nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    
    //函数WndProc: 处理主窗口的消息
    LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
        //int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
        
        switch (message)
        {
        case WM_CREATE:
            /******初始化工作Begin******/
            //矩形坐标初始化
            intInitSet(&intXRecLeft,REC_X_LEFT);
            intInitSet(&intYRecBottom,REC_Y_BOTTOM);
            intInitSet(&intXRecRight,REC_X_RIGHT);
            intInitSet(&intYRecTop,REC_Y_TOP);
            
            //完成绘制直线倾角与启动点及画线间距
            intInitSet(&intArgAngle,ARG_ANGLE);
            intInitSet(&intLineDist,LINE_DIST);
    
            //初始化批量绘制直线的起始点
            intInitSet(&intPtRecStart,REC_LEFTTOP);
            
            //初始化矩形边界的绘制方向及连接变量
            intInitSet(&intEdgeForward,EDGE_X);
            //intInitSet(&intEdgeForward,EDGE_Y);
    
            /******End初始化工作******/
    
            //斜率计算
            flaK=flaKCalc(intArgAngle);
            
            //矩形对角线长度
            intRecDiag=(int)sqrt((float)(intXRecRight-intXRecLeft)*(intXRecRight-intXRecLeft)+(float)(intYRecTop-intYRecBottom)*(intYRecTop-intYRecBottom));
    
            //完成xy两个坐标轴增长方向的判断
            intXYFoward(&intXStep,&intYStep,intPtRecStart);
            
            //根据绘图的起始点计算出起始点与对角点坐标
            intXYStart(&intXRecStart,&intYRecStart,intPtRecStart);
            intXYDig(&intXDig,&intYDig,intPtRecStart);
            
            //矩形边界绘制初始变量的判断
            intXYEdge(&intXEdge,&intYEdge,intEdgeForward);
    
            //计算对角点到起始直线的距离
            intPt2LineStart=intPt2LineStartCalc(intXDig,intYDig,intXRecStart,intYRecStart,flaK);
                            
            //结合间距计算直线绘制数量
            intLineCount=intPt2LineStart/intLineDist;
            
            //准备一批待绘制直线的两个端点
            //****步骤*****
            //a-算出从矩形起始点向绘制方向延伸点的坐标
            //b-算出从延伸点向绘制的垂直方向两侧各延伸出对角线长的点坐标
            //c-计算结果存入vector
            vecAddCross.clear();
            vecSubCross.clear();
            
            //垂线中点坐标的初始化
            int intXCenter,intYCenter;
            intXCenter=intXRecStart;
            intYCenter=intYRecStart;
            
            //垂线两侧点的初始化
            myPoint mpAdd;
            myPoint mpSub;
            mpAdd.x=intXCenter;
            mpAdd.y=intYCenter;
            mpSub.x=intXCenter;
            mpSub.y=intYCenter;
                    
            //交点坐标结构体变量的声明
            myPoint mpAddCross;
            myPoint mpSubCross;
            for(int i=0;i<intLineCount;i++)
            {
                //先计算在绘制直线的垂线上的中点
                //不同的启动点决定了PI/2-intArgAngle角度正负差异,故使用intYStepAngle校正sin(cos因偶函数性质不需校正)
                intYAngleStep=intYAngleStepCalc(intPtRecStart);
                
                //垂线上各点计算
                intXCenter=(int)(intXRecStart+intXStep*(i+1)*intLineDist*cos((float)(PI/2-intArgAngle*PI/180)));
                intYCenter=(int)(intYRecStart+intYAngleStep*intYStep*(i+1)*intLineDist*sin((float)(PI/2-intArgAngle*PI/180)));
    
                //计算两侧坐标
                //Add方向更靠近X轴一侧
                //Y增长方向一定与垂线的Y增长方向相反,故*(-1)
                mpAdd.x=(int)(intXCenter+intXStep*intRecDiag*cos(intArgAngle*PI/180));
                mpAdd.y=(int)(intYCenter+(-1)*intYStep*intRecDiag*sin(intArgAngle*PI/180));
                mpSub.x=(int)(intXCenter-intXStep*intRecDiag*cos(intArgAngle*PI/180));
                mpSub.y=(int)(intYCenter-(-1)*intYStep*intRecDiag*sin(intArgAngle*PI/180));
                
                //根据两侧坐标计算裁剪后与矩形的交点
                intXAddCross=mpAdd.x;
                intYAddCross=mpAdd.y;
                intXSubCross=mpSub.x;
                intYSubCross=mpSub.y;
                intCohenPro=cohenProcess(&intXAddCross,&intYAddCross,&intXSubCross,&intYSubCross,intXAddCross,intYAddCross,intXSubCross,intYSubCross);
                
                //Add与Sub获得两个交点坐标
                mpAddCross.x=intXAddCross;
                mpAddCross.y=intYAddCross;
                mpSubCross.x=intXSubCross;
                mpSubCross.y=intYSubCross;
    
                //分别设定mpAdd与mpSub每一点与下一点是否连接的标志变量
                //直线绘制的起始点为intPtRecStart,故Vector中的第一点实为绘制时的第二点
                //因最后循环时mpSub与mpAdd反方向,故mpAdd与mpSub为配对相等关系
                mpAddCross.intNextForward=intXEdge;
                mpSubCross.intNextForward=intYEdge;
                
                //将两侧裁剪所得交点存入相应的Vector
                vecAddCross.push_back(mpAddCross);
                vecSubCross.push_back(mpSubCross);
    
                //下次是否连接必然与此次相反
                intXEdge=-intXEdge;
                intYEdge=-intYEdge;
            }
            break;
    
        case WM_PAINT:
            hdc=BeginPaint(hWnd,&ps);
                
            //绘制矩形
            Rectangle(hdc,intXRecLeft,intYRecBottom,intXRecRight,intYRecTop);
            
            //设定初始及裁剪后线段绘图画笔
            HGDIOBJ hgBlackPen,hgRedPen;
            hgBlackPen=(HGDIOBJ)GetStockObject(BLACK_PEN);
            hgRedPen=CreatePen(PS_SOLID,2,RGB(255,0,0));
                
            //主工作流程
            //(1)-批量绘制直线        
            //绘制裁剪结果之前的画笔准备
            SelectObject(hdc,hgRedPen);
                    
            //沿矩形外周循环一圈完成边界交错连接绘制
            //首先需要完成的是启动点和指定坐标轴上第一点的连接
            MoveToEx(hdc,intXRecStart,intYRecStart,NULL);
            if(EDGE_X==intEdgeForward)
            {
                LineTo(hdc,vecAddCross[0].x,vecAddCross[0].y);
            }
            else if(EDGE_Y==intEdgeForward)
            {
                LineTo(hdc,vecSubCross[0].x,vecSubCross[0].y);
            }
            else
            {
                //错误提醒处理
            }
            
            //(2)-分别沿XY两坐标轴方向完成Add与Sub两个方向的交错绘制
    
            //矩形边角上的直角拐弯处理
            //Add一侧一定是从X相等变到Y相等
            //Sub一侧一定是从Y相等变到X相等        
            for(int i=0;i<intLineCount-1;i++)
            {
                if(1==vecAddCross[i].intNextForward)
                {
                    if(vecAddCross[i].y==vecAddCross[i+1].y)
                    {
                        MoveToEx(hdc,vecAddCross[i].x,vecAddCross[i].y,NULL);
                        LineTo(hdc,vecAddCross[i+1].x,vecAddCross[i+1].y);
                    }
                    else
                    {
                        MoveToEx(hdc,vecAddCross[i].x,vecAddCross[i].y,NULL);
                        LineTo(hdc,vecAddCross[i+1].x,vecAddCross[i].y);
                        MoveToEx(hdc,vecAddCross[i+1].x,vecAddCross[i].y,NULL);
                        LineTo(hdc,vecAddCross[i+1].x,vecAddCross[i+1].y);
                    }
    
                }
                if(1==vecSubCross[i].intNextForward)
                {
                    if(vecSubCross[i].x==vecSubCross[i+1].x)
                    {
                        MoveToEx(hdc,vecSubCross[i].x,vecSubCross[i].y,NULL);
                        LineTo(hdc,vecSubCross[i+1].x,vecSubCross[i+1].y);
                    }
                    else
                    {
                        MoveToEx(hdc,vecSubCross[i].x,vecSubCross[i].y,NULL);
                        LineTo(hdc,vecSubCross[i].x,vecSubCross[i+1].y);
                        MoveToEx(hdc,vecSubCross[i].x,vecSubCross[i+1].y,NULL);
                        LineTo(hdc,vecSubCross[i+1].x,vecSubCross[i+1].y);
                    }
                }
            }
    
    
            //(3)-批量矩形内部对直线的裁剪结果绘制
            for(int i=0;i<intLineCount;i++)
            {
                //绘制裁剪后的结果
                MoveToEx(hdc,vecAddCross[i].x,vecAddCross[i].y,NULL);
                LineTo(hdc,vecSubCross[i].x,vecSubCross[i].y);
            }
    
            //清除各种GDI资源
            DeleteObject(hgBlackPen);
            DeleteObject(hgRedPen);
    
            //绘图代码结束
            EndPaint(hWnd, &ps);
            break;
            //return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd,message,wParam,lParam);
        }
        return 0;
    }

    附:上述程序,在Windows7x64,VS2008(关闭增量编译)环境下编译调试通过。

  • 相关阅读:
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    Oracle分析函数-排序排列(rank、dense_rank、row_number、ntile)
  • 原文地址:https://www.cnblogs.com/vbspine/p/2748916.html
Copyright © 2020-2023  润新知