zoukankan      html  css  js  c++  java
  • 利用鼠标点击绘制出三棱锥

    作者:feiquan
    
    出处:http://www.cnblogs.com/feiquan/
    
    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    
    大家写文都不容易,请尊重劳动成果~ 这里谢谢大家啦(*/ω\*)

    大家可以先看下我的上一篇文章:对于单个模型(长方体为例)进行面投影时的消隐           http://www.cnblogs.com/feiquan/p/8213875.html

    这两篇有相同的地方。

    要求:

    使用鼠标左键,按下,再抬起,连续3次绘制出三棱锥的地面,再按下左键抬起绘制出三棱锥的顶点,并绘制出三棱锥。(利用背面检测法)

    思路:

    和上一篇中立方体的投影一样,我们要先获取并存储三棱锥的相关信息,只不过这里是使用了鼠标来获得。剩下的就和之前的差不多了,我在之前的程序上修改后得到的。

    相关类定义:

    //3V_Point三维点
    class Point_3V{
    public:
        double x,y,z;
        bool v;
    
        Point_3V(){
            x=0;y=0;z=0;
            v=false;
        }
        Point_3V(double a,double b,double c){
            x=a;y=b;z=c;
            v=false;
        }
        Point_3V(double a,CPoint p){
            x=a;y=p.x;z=p.y;
            v=false;
        }
        Point_3V(CPoint p,double a){
            x=p.x;y=p.y;z=a;
            v=false;
        }
        void set_Point(double a,double b,double c){
            x=a;y=b;z=c;
        }
        void set_Point(Point_3V p){
            x=p.x;y=p.y;z=p.z;
        }
        void set_Point(Point_3V *p){
            x=p->x;y=p->y;z=p->z;
        }
        //投影一个三维点,返回投影点
        CPoint reflect_Point_3V(Point_3V v,CPoint move){
            CPoint p2;
            double  a,b;
            a=this->x-v.x/v.z*this->z+move.x;
            b=this->y-v.y/v.z*this->z+move.y;
            p2.x=(int)a;
            p2.y=(int)b;
            //p2.SetPoint((int)a,(int)b);
            return p2;
        }
    };
    
    //二维线
    class Line_2V{
    public :
        CPoint start,end;
        Line_2V(){
            start.x=0;start.y=0;
            end.x=0,end.y=0;
            //start.SetPoint(0,0);
            //end.SetPoint(0,0);
        }
        Line_2V(CPoint x,CPoint y ){
            start=x;end=y;
        }
        void fill(CDC *p){ 
            p->MoveTo(start);
            p->LineTo(end);
        }
    
        void fill_CClientDC(CClientDC *p){ 
            p->MoveTo(start);
            p->LineTo(end);
        }
    };
    
    //基于点填充线(不会开辟新空间)
    class Line :public Point_3V 
    {
    public :
        Point_3V *start;
        Point_3V end;
        bool v;
        Line(){
            start=new Point_3V[1];
            v=false;
        }
        Line(Line *p){
            this->start=p->start;
            this->end=p->end;
            v=false;
        }
        //三维线投影
        Line_2V reflect_Line(Point_3V v,CPoint move,bool draw,CDC  *p){
            CPoint s=start->reflect_Point_3V(v,move);
            CPoint e=end.reflect_Point_3V(v,move);
            Line_2V temp(s,e);
            if(draw)temp.fill(p);
            return temp;
        }
    
        //三维线投影
        Line_2V reflect_Line_CClientDC(Point_3V v,CPoint move,bool draw,CClientDC   *p){
            CPoint s=start->reflect_Point_3V(v,move);
            CPoint e=end.reflect_Point_3V(v,move);
            Line_2V temp(s,e);
            if(draw)temp.fill_CClientDC(p);
            return temp;
        }
    
        void set_Line(int s_x,int s_y,int s_z,int e_x,int e_y,int e_z){
            this->start->set_Point(s_x,s_y,s_z);
            this->end.set_Point(e_x,e_y,e_z);
        }
        void set_Line(Point_3V s,Point_3V e){
            this->x=s.x;
            this->y=s.y;
            this->z=s.z;
            this->v=s.v;
            this->start->set_Point(s);
            this->end.set_Point(e);
        }
    };
    
    class face_2V{
    public :
        //逆时针
        Line_2V a,b,c;
        face_2V(){
    
        }
        face_2V(Line_2V i,Line_2V j,Line_2V k ){
            a=i;b=j;c=k;
        }
    
        void B(int x,int y,int c1_fill,int c2,CDC *p){
            
            //种子填充
            long center=p->GetPixel(x,y);
            if(center!=c1_fill&&center!=c2){
                p->SetPixel(x,y,c1_fill);
                B(x+1,y,c1_fill,c2,p);B(x-1,y,c1_fill,c2,p);
                B(x,y+1,c1_fill,c2,p);B(x,y-1,c1_fill,c2,p);
            }
        }
    
        void B_CClientDC(int x,int y,int c1_fill,int c2,CClientDC *p){
            
            //种子填充
            long center=p->GetPixel(x,y);
            if(center!=c1_fill&&center!=c2){
                p->SetPixel(x,y,c1_fill);
                B(x+1,y,c1_fill,c2,p);B(x-1,y,c1_fill,c2,p);
                B(x,y+1,c1_fill,c2,p);B(x,y-1,c1_fill,c2,p);
            }
        }
    
        void fill(int c1_fill,int c2,CDC *p){
            a.fill(p);b.fill(p);c.fill(p);
            CPoint a_cent((a.start.x+a.end.x)/2,(a.start.y+a.end.y)/2),c_cent((c.start.x+c.end.x)/2,(c.start.y+c.end.y)/2);
            CPoint cent((a_cent.x+c_cent.x)/2,(a_cent.y+c_cent.y)/2);
            B(cent.x,cent.y, c1_fill, c2,p);
        }
    
        void fill_CClientDC(int c1_fill,int c2,CClientDC *p){
            a.fill(p);b.fill(p);c.fill(p);
            CPoint a_cent((a.start.x+a.end.x)/2,(a.start.y+a.end.y)/2),c_cent((c.start.x+c.end.x)/2,(c.start.y+c.end.y)/2);
            CPoint cent((a_cent.x+c_cent.x)/2,(a_cent.y+c_cent.y)/2);
            B_CClientDC(cent.x,cent.y, c1_fill, c2,p);
        }
    };
    
    //基于点填充面(不会开辟新空间)
    class face :public Line{
    public :
        Point_3V *p;//逆时针
        Line *l1,l2,l3;//l1只能是指针,为了是其与点公用一个存储空间
        bool v;
        face(){
            p=new Point_3V[3];
            l1=new Line[1];
            v=false;
        }
        face(Point_3V *q[3]){
            this->start=q[0];
            this->end=*q[1];
    
            p=new Point_3V[3];
            l1=new Line[1];
            
            v=false;
            l1->set_Line(p[0],p[1]);
            l2.set_Line(p[1],p[2]);
            l3.set_Line(p[2],p[3]);
        }
        face(Point_3V a,Point_3V b,Point_3V c,Point_3V d){
            p=new Point_3V[3];
            l1=new Line[1];
            p[0]=a;p[0]=b,p[0]=c,p[0]=d;
            v=false;
    
            l1->set_Line(p[0],p[1]);
            l2.set_Line(p[1],p[2]);
            l3.set_Line(p[2],p[3]);
        }
        face( face *p1){
            p=new Point_3V[3];
            l1=new Line[1];
            this->start=p1->start;
            this->end=p1->end;
    
            p[0]=p1->p[0];
            p[1]=p1->p[1];
    
            l1->set_Line(p[0],p[1] );
            v=false;
        }
        void set_Point(Point_3V q[3]){
            for(int i=0;i<3;i++){
                p[i]=q[i];
            }
        }
    
        void set_Face(Point_3V q[3]){
            for(int i=0;i<3;i++){
                p[i]=q[i];
            }
            l1->set_Line(p[0],p[1]);
            l2.set_Line(p[1],p[2]);
            l3.set_Line(p[2],p[3]);
        }
        void set_Face(Point_3V q1,Point_3V q2,Point_3V q3){
            p[0]=q1;
            p[1]=q2;
            p[2]=q3;
    
            l1->set_Line(p[0],p[1]);
            l2.set_Line(p[1],p[2]);
            l3.set_Line(p[2],p[0]);
        }
        //三维向量的向量积
        Point_3V xiangliangji( Point_3V a ,Point_3V b){
            //矩阵形式,和i,j,k是否为偶数或奇数有关,切记
            return Point_3V(a.y*b.z-a.z*b.y,-(a.x*b.z-a.z*b.x),a.x*b.y-a.y*b.x);
        }
    
        //三维向量的点乘
        double diancheng( Point_3V a ,Point_3V b){
            double temp=a.x*b.x+a.y*b.y+a.z*b.z;
            return temp;
        }
    
        //求一个面的法向量,输入一个面按逆时针方向的所有点的数组
        Point_3V n( face *one_face){
            Point_3V a,b,n;
            if(one_face->p!=NULL){
                a.set_Point(one_face->p[1].x-one_face->p[0].x,one_face->p[1].y-one_face->p[0].y,one_face->p[1].z-one_face->p[0].z);
                b.set_Point(one_face->p[2].x-one_face->p[0].x,one_face->p[2].y-one_face->p[0].y,one_face->p[2].z-one_face->p[0].z);
                n=xiangliangji(a,b);
                return n;
            }else{
                return n;
            }
        }
    
        //判断一个面是否可见,如果一个面可见,则这个面上的四个点也可见
        bool view_face(face *one_face, Point_3V v){
                double cos,a_mo,b_mo;
    
                //求一个面的法向量
                Point_3V fa;
                fa=n(one_face);
    
                double a_temp=pow((double)fa.x,2)+pow((double)fa.y,2)+pow((double)fa.z,2);
                a_mo=sqrt(a_temp);
                double b_temp=pow(v.x,2)+pow(v.y,2)+pow(v.z,2);
                b_mo=sqrt(b_temp);
                double fz=diancheng(fa,v);
                double fm=a_mo*b_mo;
                cos=fz/fm;
                if(cos<=0){
                    one_face->v=true;
                    //判断这个多边形体的各个点是否可见
                    for(int j=0;j<4;j++){
                        one_face->p[j].v=true;
                    }
                    return true;
                }else{
                    return false;
                }
        }
        
        //3V面投影
        void reflect_Face(Point_3V v,CPoint move,bool draw_Line,bool fill_face,int c1_fill,int c2,CDC  *p){
            if(view_face(this,v)){
                Line_2V l2_1=l1->reflect_Line(v,move,draw_Line,p);
                Line_2V l2_2=l2.reflect_Line(v,move,draw_Line,p);
                Line_2V l2_3=l3.reflect_Line(v,move,draw_Line,p);
                if(fill_face){
                    face_2V f2(l2_1,l2_2,l2_3);
                    f2.fill(c1_fill,c2,p);
                }
            }
        }
    
        //3V面投影
        void reflect_Face_CClientDC(Point_3V v,CPoint move,bool draw_Line,bool fill_face,int c1_fill,int c2,CClientDC *p){
            if(view_face(this,v)){
                Line_2V l2_1=l1->reflect_Line_CClientDC(v,move,draw_Line,p);
                Line_2V l2_2=l2.reflect_Line_CClientDC(v,move,draw_Line,p);
                Line_2V l2_3=l3.reflect_Line_CClientDC(v,move,draw_Line,p);
                if(fill_face){
                    face_2V f2(l2_1,l2_2,l2_3);
                    f2.fill_CClientDC(c1_fill,c2,p);
                }
            }
        }
    
    };
    
    
    //多边形 p+f-l=2
    class cube{
    private:
        bool isCube;
    public :
        int point_num,face_num,line_num;
        Point_3V p[4];
        Line l[6];
        face f[4];
        cube(){
            point_num=0;
            face_num=0;
            line_num=0;
        }
        cube(int point_nums,int line_nums,int face_nums){
            if(point_nums+face_nums-line_nums==2){//公式
                point_num=point_nums;
                face_num=face_nums;
                line_num=line_nums;
                /*p=new Point_3V[point_num];
    
                l=new Line[line_num];
    
                f=new face[face_num];*/
    
                isCube=true;
            }else{
            cube();
            isCube=false;
            }
        }
    
        void set_Point(Point_3V *point){
            for(int i=0;i<point_num;i++){
                p[i]=point[i];
            }
    
        }
    
        void set_cube(Point_3V *point){
            set_Point(point);
    
            //上下 左右 前后 
            f[0].set_Face(p[0],p[1],p[2]);//
            f[1].set_Face( p[0],p[3],p[1]);//四周 
    
            f[2].set_Face(p[0],p[2],p[3]);//四周
            f[3].set_Face(p[3],p[2],p[1]);//四周
    
    
        }
        
        void reflect_Cube(Point_3V v,CPoint move,bool draw_Line,bool fill_face,int *c1_fill,int c2,CDC  *p){
            f[0].reflect_Face(v,move,draw_Line,fill_face,c1_fill[0],c2,p);
            f[1].reflect_Face(v,move,draw_Line,fill_face,c1_fill[1],c2,p);
    
            f[2].reflect_Face(v,move,draw_Line,fill_face,c1_fill[2],c2,p);
            f[3].reflect_Face(v,move,draw_Line,fill_face,c1_fill[3],c2,p);
    
        }
    
        void reflect_Cube_CClientDC(Point_3V v,CPoint move,bool draw_Line,bool fill_face,int *c1_fill,int c2,CClientDC  *p){
            f[0].reflect_Face_CClientDC(v,move,draw_Line,fill_face,c1_fill[0],c2,p);
            f[1].reflect_Face_CClientDC(v,move,draw_Line,fill_face,c1_fill[1],c2,p);
    
            f[2].reflect_Face_CClientDC(v,move,draw_Line,fill_face,c1_fill[2],c2,p);
            f[3].reflect_Face_CClientDC(v,move,draw_Line,fill_face,c1_fill[3],c2,p);
    
        }
    
        void fill( int p){
            switch(p){
            case 0: {point_num=2+line_num-face_num;} break; //已知其它两个,求点
            case 1:{line_num=point_num+face_num-2;}break;//已知其它两个,求线
            case 2:{face_num=2+line_num-point_num;}break;//已知其它两个,求面
            }
        }
    
    };

    定义全局变量:

    //判断鼠标左键次数
        int count=0;
    
        //鼠标左键的点
        CPoint start,end;
    
        //临时面
        face di;
    
        //
        Point_3V  p[4];
    
        //偏移量
        CPoint move;
    
        //视点
        Point_3V v(1,1.2,1);
    
        //颜色
        int color[4]={RGB(255,0,0),RGB(0,255,0),RGB(0,0,255),RGB(255,255,0)};
    
        //cube
        int point_num=4,face_num=6,line_num=4;
        cube cb(point_num,face_num,line_num);

    鼠标事件:

    void CMy3View::OnLButtonDown(UINT nFlags, CPoint point)
    {
        // TODO: ÔÚ´ËÌí¼ÓÏûÏ¢´¦Àí³ÌÐò´úÂëºÍ/»òµ÷ÓÃĬÈÏÖµ
    
        CView::OnLButtonDown(nFlags, point);
        start=point;
        if(count==4){
            count=0;
        }
    }
    
    
    void CMy3View::OnLButtonUp(UINT nFlags, CPoint point)
    {
        // TODO: ÔÚ´ËÌí¼ÓÏûÏ¢´¦Àí³ÌÐò´úÂëºÍ/»òµ÷ÓÃĬÈÏÖµ
    
        double  z=0;
    
        //偏移量
        move.x=0;
        move.y=0;
        //move.SetPoint(200,200);
    
        CClientDC dc(this); 
    
        CView::OnLButtonUp(nFlags, point);
        end=point;
        switch(count){
        case 0:{
                    p[0].set_Point(start.x,start.y,z);
               }break;
        case 1:{
                    p[1].set_Point(start.x,start.y,z);
                    
               }break;
        case 2:{
                    p[2].set_Point(start.x,start.y,z);
                    di.set_Face(p[0],p[1],p[2]);
                    di.reflect_Face_CClientDC(v,move,true,false,color[0],0,&dc);
               }break;
        case 3: {
                    p[3].set_Point(start.x,start.y,z);
    
                    //擦除
                    CPen mypen,*oldpen;
                    mypen.CreatePen(1,2,RGB(255,255,255));
                    oldpen=dc.SelectObject(&mypen);
                    di.reflect_Face_CClientDC(v,move,true,false,color[0],0,&dc);
    
                    dc.SelectObject(oldpen);
                    //cube
                    cb.set_cube(p);
                    //cb.reflect_Cube_CClientDC(v,move,true,false,color,0,&dc);
                    cb.reflect_Cube_CClientDC(v,move,true,true,color,0,&dc);
                }break;
        }
        count++;
    }

    实验结果:

     

    (1)

    实验总结:

    l  这个程序的实现主要使用同第一题一样的思路,只是将立方体换成了三棱锥。

    l  对这个三棱锥的数据的填充主要是靠鼠标的点击来获取,由于三棱锥只有4个点所以使用了count来计数,当其达到4时归零,重新计数。使用switch语句实现,当count的数不同时执行不同的语句。Count=1、2计数,count=3,判断底面是否可见并画线,count=4,进行整个三棱锥的投影。

    程序的不足:

    在三棱锥的数据填充时,没有对填充的点进行排序,来保证前三个点构成的面一定是底面,这个程序只是构建了三棱锥并投影(大家如果有好的方法来解决这个问题,请联系我:2283320260@qq.com)。

     补充:

    建议大家在使用种子填充时,使用VC6.0,不要用VS,VS会报错:(大家如果有好的方法来解决这个问题,请联系我:2283320260@qq.com

  • 相关阅读:
    更好一点的:Vue 利用指令实现禁止反复发送请求
    实现一个深度比较
    Zrender:实现波浪纹效果
    Echarts:实现拖拽效果
    找到树中指定id的所有父节点
    Vue 利用指令实现禁止反复发送请求
    我对组件化的一点细琐的想法
    转盘式旋转抽奖
    信息系统与信息化
    跳出牢笼,逃出生天
  • 原文地址:https://www.cnblogs.com/feiquan/p/8213913.html
Copyright © 2011-2022 走看看