利用鼠标点击绘制出三棱锥
大家可以先看下我的上一篇文章:對于單個模型(長方體為例)進行面投影時的消隱? ? ? ? ? ?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&¢er!=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&¢er!=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)};//cubeint 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,進行整個三棱錐的投影。
程序的不足:
在三棱錐的數據填充時,沒有對填充的點進行排序,來保證前三個點構成的面一定是底面,這個程序只是構建了三棱錐并投影(大家如果有好的方法來解決這個問題,請聯系我:2283320260@qq.com)。
?補充:
建議大家在使用種子填充時,使用VC6.0,不要用VS,VS會報錯:(大家如果有好的方法來解決這個問題,請聯系我:2283320260@qq.com)
?
轉載于:https://www.cnblogs.com/feiquan/p/8213913.html
總結
以上是生活随笔為你收集整理的利用鼠标点击绘制出三棱锥的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gcc编译器用法
- 下一篇: netcore 获取本地网络IP地址