利用鼠标点击绘制出三棱锥

作者: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: ?ú′?ìí?ó???¢′|àí3ìDò′ú??oí/?òμ÷ó???è??μ

    CView::OnLButtonDown(nFlags, point);
    start=point;
    if(count==4){
        count=0;
    }
}

void CMy3View::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: ?ú′?ìí?ó???¢′|àí3ìDò′ú??oí/?òμ÷ó???è??μ

    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,进行整个三棱锥的投影。

程序的不足:

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

 补充:

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

原文地址:https://www.cnblogs.com/feiquan/p/8213913.html

时间: 2024-10-31 21:20:27

利用鼠标点击绘制出三棱锥的相关文章

基于jQuery鼠标点击弹出登陆框效果

基于jQuery鼠标点击弹出登陆框效果.这是一款扁平样式风格的jQuery弹出层登陆框特效.效果图如下: 在线预览   源码下载 实现的代码. html代码: <input type="button" class="one" value="点击我查看效果" /> <div class="box"> <div class="box2"> <div class=&quo

工作当中实际运用(3)——js原生实现鼠标点击弹出div层 在点击隐藏

function onmou(){ var divs=document.getElementById('kefuDV');//获取到你要操作的div if (divs.style.display=="none") {//下面就简单了 不一一赘述了 divs.style.display="block" }else{ divs.style.display="none" } } js原生代码实现 鼠标点击 弹出 隐藏 div隐藏

用鼠标左键绘制折线,利用鼠标中键或右键终止绘制

用鼠标左键绘制折线,同时在鼠标左键点中的位置输出一个含有该位置信息的字符串,利用鼠标中键或右键终止绘制. 解:建立一个Untitled.m文件 MATLAB指令: clf;axis([0,10,0,5]);hold on x=[];y=[]; for i=1:100 [x1,y1,button]=ginput(1); chstr=['(',num2str(x1),',',num2str(y1),')'];text(x1,y1,chstr); x=[x,x1];y=[y,y1];line(x,y)

原生js日期时间插件鼠标点击文本框弹出日期时间表格选择日期时间

原文出处 (这是我从互联网上搜来的,感觉能满足各方面的需求.个人感觉挺不错的,所以后期修改了一下向大家推荐!) 效果图: html代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org

JavaScript鼠标事件,点击鼠标右键,弹出div

document.oncontextmenu = function(){return false}; //禁止鼠标右键菜单显示 var res = document.getElementById('box'); //找到id为box的div document.body.onmouseup = function(e){ //在body里点击触发事件 if(e.button===2){ //如果button=1(鼠标左键),button=2(鼠标右键),button=0(鼠标中间键) console

利用WPF建立自己的3d gis软件(非axhost方式)(五)在鼠标点击的位置增加UI

原文:利用WPF建立自己的3d gis软件(非axhost方式)(五)在鼠标点击的位置增加UI 先下载SDK:https://pan.baidu.com/s/1M9kBS6ouUwLfrt0zV0bPew 密码:1te1 地图数据包(sqlserver2008R2版本,也可以不下载):? https://pan.baidu.com/s/1PjcNamad7OVpCrsVJ7dwFQ密码:uw9r 下载 核心SDK升级包:https://pan.baidu.com/s/1Q3dlM-Va-RmlE

在几何画板中切割三棱锥的方法

很多的老师在使用几何画板的时候发现,几何画板不仅可以画一些静态的图,还可以根据教学需要画出一些动态的图.比如,在对三棱锥的学习过程中,老师就可以利用几何画板实现三棱锥旋转和侧面展开动画过程,这让课程变的更加有趣,也更容易让学生接受理解.本几何画板教程就来给大家介绍介绍在几何画板中切割三棱锥的方法? 具体的操作步骤如下: 步骤一 绘制三棱锥.关于在几何画板中画三棱锥的方法这里就不再多作介绍了,大家可以参考教程:如何用几何画板画三棱锥.  在几何画板中绘制三棱锥示例 步骤二 在三棱锥上确定一个面.

利用javascript和WebGL绘制地球 【翻译】

利用javascript和WebGL绘制地球 [翻译] 原翻译:利用javascript和WebGL绘制地球 [翻译] 在我们所有已知的HTML5API中,WebGL可能是最有意思的一个,利用这个API我们能够在浏览器中创造出炫酷3D场景的能力.本文将完整的向你展示一些炫酷是如何实现的. 需要特别指出的是,这篇教程我们将会构建一个地球行星模型,这个模型可以像一个兴奋的人一样环绕的旋转,另外,它可能使我们可以获得一些其他程序员的称赞,好吧,就这么多了. 准备 这篇教程我们将会用到一个令人着迷的We

CAD技巧,怎么在CAD中绘制出一个表格?

CAD技巧,怎么在CAD中绘制出一个表格?当我们在日常的工作中绘制CAD图纸的时候,遇到比较复杂的图纸就需要在CAD图纸中添加一些数据说明,一般编辑CAD图纸都是借助CAD编辑器来进行绘制的,那怎么在CAD中绘制出一个表格?具体要怎么来进行操作?今天小编就通过这篇文章来告诉大家怎么在CAD中绘制出一个表格?下面就一起来看看具体操作步骤吧! 第一步:首先如果小伙伴们电脑上没有安装CAD编辑器的,可以在浏览器中搜索迅捷CAD编辑器(标准版),进入到官网,根据提示步骤来下载安装最新版本的CAD编辑器.