TC 3D模型绘图

来源:互联网 发布:官网pkpm软件多少钱 编辑:程序博客网 时间:2024/04/28 03:16

/*这个程序用于描述一个用户给定方程的3D物体,用户可以通过键盘控制这个3D体的
  运动来了解物体的表面细节,程序定义的控制键如下:
  a、s、w、d:是3D体左、后、前、右移动(默认)
  c:功能切换键,当奇数次按下这个键时,a、s、w、d:得功能为左、下、上、右以用户为中心旋转
  小键盘对应的数字键,使得3D体沿自己的体心对应旋转
  0:退出该程序
  其它任意键:使3D体保持当前状态静止*/

/*下面包含头文件*/
#include <math.h>
#include <stdio.h>
#include <graphics.h>

#define PI 3.1415926
#define MAXROW 32
#define MAXLINE 16

struct _3DPoint
{
 float x;
 float y;
 float z;
};

struct _3DObjPosition
{
 //空间位移坐标
 struct _3DPoint point;
 //观众姿态角
 double User_angelY;
 double User_angelZ;
 //自心姿态角
 double angelY;
 double angelZ;
};

struct _2DPoint
{
 float x;
 float y;
};

struct _ProccessBox
{
 struct _2DPoint point;
 int Longth;
 int Higth;
 int BackGColor;
 int MyColor;
 char MyText[13];
};

float GetResult(float r,float angel1,float angel2);
void GraphicsInit(int mode,int driver);       /*图像初始化的函数*/
void ProccessBoxInit(struct _ProccessBox *p);    /*进度条初始化函数*/
void ProccessBoxSet(int n,struct _ProccessBox *p); /*进度条设置函数*/
float HalfWay(float angel1,float angel2);      /*二分法求解方程函数*/
void Init3DObj(struct _3DObjPosition *p);      /*初始化物体的姿态数据*/
void Change3DObjPosition(char order,struct _3DObjPosition *p); /*3D物体姿态参数设置函数*/
void Change3dTO2D(struct _3DPoint SousePoint,struct _3DObjPosition P,struct _3DPoint *ArmPoint);/*3D数据转2D的函数*/
void ShowSmallMap(void);

void main(void)
{
 int i, j;                  /*循环变量*/
 int l, n, k=0;        /*程序中使用的状态标记变量*/
 char PressKey='6';
 float AngelArpha, AngelThetar; /*角度变量*/
 float r,SmallMap[2][2]={0};
 
 struct _ProccessBox Proccess;
 struct _3DPoint SourceData[MAXROW][MAXLINE];       /*记录物体空间点阵的原始计算数据*/
 struct _3DObjPosition Object;
 struct _3DPoint TempPoint;
  struct _3DPoint ChangedData[MAXROW][MAXLINE][2]={0};    /*记录经过用户空间变换后的点阵数据*/

 ProccessBoxInit(&Proccess);
 Init3DObj(&Object);
 
  GraphicsInit(VGAHI,VGA);    /*图形模式初始化*/  
 
 /*下面这段代码用于计算用户给出的曲面的空间点阵*/
 cleardevice();           /*清屏*/
 for(i=0; i<MAXROW; i++)        /*按角度开始求解方程*/
 {
  ProccessBoxSet(3*i, &Proccess);
  delay(60);
 
  for(j=0; j<MAXLINE; j++)
  {
   AngelThetar = (PI / (MAXLINE -1)) * (j- (MAXLINE -1)/2.0);
   AngelArpha = (PI / (MAXROW -1)) * i * 2;
   r=HalfWay(AngelThetar,AngelArpha);
   /*计算完成之后将点阵保存进数组*/
   SourceData[i][j].x = r * cos(AngelThetar) * cos(AngelArpha);
   SourceData[i][j].y = r * cos(AngelThetar) * sin(AngelArpha);
   SourceData[i][j].z = r * sin(AngelThetar);
  }
 }

 /*下面开始接受用户的空间在屏幕上显示动态的图像*/
 cleardevice();
 l = 0;
 AngelThetar = 0;

 for( ; ; ) /*开始处理用户的控制*/
 {
  if(kbhit()) PressKey = getch();/*判断用户是否有键入*/
  switch(PressKey)
  {
   case 'c': /*切换成转动或者移动,也就是改变l=0或者=1*/
   case 'C': {
         l = (l-1) * (l-1);
         PressKey = 'q';
         break;
        }
   case '0': {
         exit(0);
         break;
        }/*退出程序*/
    default: { if(PressKey < '0' || PressKey > '9')
         {//非数字
          if(l==1)
          {//小写
           if(PressKey<'a') PressKey += 'a' -'A';
          }else
          {//大写
           if(PressKey>='a') PressKey -= 'a' -'A';
          }
         }
         Change3DObjPosition(PressKey, &Object);
        }
  }
 
  /*下面一段为三维向二维转换*/
  k = (1 - k) * (1 - k);
  for(i=0; i<MAXROW; i++)   /*开始3D->2D的转换*/
  {
   for(j=0; j<MAXLINE; j++)
   {
    Change3dTO2D(SourceData[i][j], Object,&TempPoint);
      ChangedData[i][j][k].x = TempPoint.x + 320; /*计算完后进行3d->2d*/
    ChangedData[i][j][k].y = TempPoint.y + 240; /*这里的320和240是将原点放到屏幕中间*/
    ChangedData[i][j][k].z = TempPoint.z;
   }
  }
   
   n=(1-k) * (1-k);
   for(i=0; i<MAXROW; i++) /*开始作图*/
   {
   for(j=0; j<MAXLINE-1; j++)
   {
    if((ChangedData[i][j + 1][n].z > 0) && (ChangedData[i][j][n].z > 0))
    {
     setcolor(0);
     line(ChangedData[i][j][n].x, ChangedData[i][j][n].y, ChangedData[i][j+1][n].x, ChangedData[i][j + 1][n].y);
    }
    
    if((ChangedData[i][j+1][k].z > 0) && (ChangedData[i][j][k].z > 0))
    {
     setcolor(9);
     line(ChangedData[i][j][k].x, ChangedData[i][j][k].y, ChangedData[i][j+1][k].x, ChangedData[i][j + 1][k].y);
    }
    
    if(i < (MAXROW-1))
    {
     if((ChangedData[i+1][j][n].z > 0) && (ChangedData[i][j][n].z > 0))
     {
      setcolor(0);
      line(ChangedData[i][j][n].x, ChangedData[i][j][n].y, ChangedData[i + 1][j][n].x, ChangedData[i + 1][j][n].y);
     }
     if((ChangedData[i+1][j][k].z > 0) && (ChangedData[i][j][k].z > 0))
     {
      setcolor(9);
      line(ChangedData[i][j][k].x, ChangedData[i][j][k].y, ChangedData[i+1][j][k].x, ChangedData[i+1][j][k].y);
     }
    }
    
    if(i == MAXROW-1)
    {
     if((ChangedData[0][j][n].z > 0) && (ChangedData[i][j][n].z > 0))
     {
      setcolor(0);
      line(ChangedData[i][j][n].x, ChangedData[i][j][n].y, ChangedData[0][j][n].x, ChangedData[0][j][n].y);
     }
     if((ChangedData[0][j][k].z > 0) && (ChangedData[i][j][k].z > 0))
     {
      setcolor(9);
      line(ChangedData[i][j][k].x, ChangedData[i][j][k].y, ChangedData[0][j][k].x, ChangedData[0][j][k].y);
     }
    }
   }
  }
   /*插入左上角小地图*/
   SmallMap[k][0] = Object.point.x * cos(Object.User_angelZ) - Object.point.y * sin(Object.User_angelZ);
   SmallMap[k][1] = sin(Object.User_angelZ) * Object.point.x + cos(Object.User_angelZ) * Object.point.y;
   SmallMap[k][1] = SmallMap[k][1] * cos(Object.User_angelY);
   setcolor(0);
   circle (SmallMap[n][0] / 20 + 26 , 26 - SmallMap[n][1] / 20, 5);
   setcolor (12);
   circle (SmallMap[k][0] / 20 + 26, 26 - SmallMap[k][1] / 20, 5);
  ShowSmallMap();
 }
}
void ProccessBoxInit(struct _ProccessBox *p)
{
 //数据初始化
 (*p).point.x =230;
 (*p).point.y =240;
 (*p).Longth =100;
 (*p).Higth =10;
 (*p).BackGColor =0;
 (*p).MyColor =1;
 strcpy((*p).MyText,"complete   %");
}

void Init3DObj(struct _3DObjPosition *p)
{
 (*p).point.x =0;
 (*p).point.y =0;
 (*p).point.z =0;
 (*p).User_angelY =0;
 (*p).User_angelZ =0;
 (*p).angelY =0;
 (*p).angelZ =0;
}

void ShowSmallMap()
{
  setcolor (14);
  circle (26, 26, 25);
  line (21, 26, 31, 26);
  line (26, 21, 26, 31);
  line (310,240,330,240);
  line (320,230,320,250);
  setcolor (2);
  line (26, 26, 17, 5);
  line (26, 26, 35, 5);
}

void Change3dTO2D(struct _3DPoint SourcePoint,struct _3DObjPosition P,struct _3DPoint *ArmPoint)
{
 struct _3DPoint TempPoint[4];
 float Deep;
 TempPoint[0].x = SourcePoint.x;  /*承接求解数据*/
 TempPoint[0].y = SourcePoint.y;
 TempPoint[0].z = SourcePoint.z;
   
 TempPoint[1].x = TempPoint[0].x * cos(P.angelY) - TempPoint[0].z * sin(P.angelY);  /*延y轴的偏转计算*/
 TempPoint[1].z = sin(P.angelY) * TempPoint[0].x + cos(P.angelY) * TempPoint[0].z;
 TempPoint[1].y = TempPoint[0].y;
   
 TempPoint[2].x = TempPoint[1].x * cos(P.angelZ) - TempPoint[1].y * sin(P.angelZ) + P.point.x; /*延z轴的偏转计算*/
 TempPoint[2].y = sin(P.angelZ) * TempPoint[1].x + cos(P.angelZ) * TempPoint[1].y + P.point.y;
 TempPoint[2].z = TempPoint[1].z + P.point.z;
   
 TempPoint[3].x = TempPoint[2].x * cos(P.User_angelZ) - TempPoint[2].y * sin(P.User_angelZ);  /*实现定点转动*/
 TempPoint[1].y = sin(P.User_angelZ) * TempPoint[2].x + cos(P.User_angelZ) * TempPoint[2].y;
   
 TempPoint[3].y = TempPoint[1].y * cos(P.User_angelY) - TempPoint[2].z * sin(P.User_angelY);
 TempPoint[2].z = sin(P.User_angelY) * TempPoint[1].y + cos(P.User_angelY) * TempPoint[2].z;
   
 Deep =  1/ (0.1+0.001*pow (TempPoint[3].x*TempPoint[3].x+TempPoint[3].y*TempPoint[3].y+TempPoint[2].z*TempPoint[2].z,0.5)); /*这一行用于远小近大的透视效果计算*/

 TempPoint[2].x = TempPoint[3].x * Deep;
 TempPoint[2].z = TempPoint[2].z * Deep;
 
  (*ArmPoint).x=TempPoint[2].x;
  (*ArmPoint).y=TempPoint[2].z;
  (*ArmPoint).z=TempPoint[3].y;
}

void Change3DObjPosition(char order,struct _3DObjPosition *p)
{
  switch(order)
  {
   case 'w': {
         (*p).User_angelY -=0.002;      /*向下转动*/
         break;
        }
   case 'W': {
         if(pow ((*p).point.y-1, 2) + pow ((*p).point.x ,2) < 490000) (*p).point.y -= 1; /*向前平移*/
         break;
        }
   case 'a': {
         (*p).User_angelZ -= 0.002;      /*向右转动*/
         break;
        }
   case 'A': {
         if(pow ((*p).point.y, 2) + pow ((*p).point.x+1 ,2) < 490000) (*p).point.x += 1; /*向左平移*/
         break;
        }
   case 's': {
         (*p).User_angelY +=0.002;      /*向上转动*/
         break;
        }
   case 'S': {
         if(pow ((*p).point.y+1, 2) + pow ((*p).point.x ,2) < 490000) (*p).point.y += 1; /*向后平移*/
         break;
        }
   case 'd': {
         (*p).User_angelZ += 0.002;      /*向左转动*/
         break;
        }
   case 'D': {
         if(pow ((*p).point.y, 2) + pow ((*p).point.x-1 ,2) < 490000) (*p).point.x -= 1; /*向右平移*/
         break;
        }
   case '6': {
         (*p).angelZ += 0.01;
         break;
        }/*左转*/
   case '8': {
         (*p).angelY += 0.01;
         break;
        }/*上转*/
   case '2': {
         (*p).angelY -= 0.01;
         break;
        }/*下转*/
   case '4': {
         (*p).angelZ -= 0.01;
         break;
        }/*右转*/
   case '9': {
         (*p).angelZ += 0.01;
         (*p).angelY += 0.01;
         break;
        }/*右上*/
   case '1': {
         (*p).angelZ -= 0.01;
         (*p).angelY -= 0.01;
         break;
         }/*左下*/
   case '7': {
         (*p).angelZ -= 0.01;
         (*p).angelY += 0.01;
         break;
        }/*左上*/
   case '3': {
         (*p).angelZ += 0.01;
         (*p).angelY -= 0.01;
         break;
        }/*右下*/
    default: ; /*其它按键,为暂停*/
 }
}

float HalfWay(float angel1,float angel2)
{//该函数的求解范围为0到150
 float HeadData,MilldData,EndData;
 float r[3];
 r[0] =0;
  HeadData = GetResult(r[0],angel1,angel2);
 r[1] =150;
 EndData = GetResult(r[1],angel1,angel2);
 r[2] =150;
 if(HeadData * EndData <0)
 {
  for(;;)
  {
   r[2] = (r[0] + r[1]) / 2;
   MilldData = GetResult(r[2],angel1,angel2);
   if(MilldData * MilldData < 0.00001) break;
   if(MilldData * HeadData >= 0)
   {
    HeadData = MilldData;
    r[0] = r[2];
   }else
   {
    EndData = MilldData;
    r[1] = r[2];
   }
  }
 }
 return r[2];
}

void ProccessBoxSet(int n,struct _ProccessBox *p)
{
 rectangle((*p).point.x -1, (*p).point.y -1, (*p).point.x + (*p).Longth +1, (*p).point.y +(*p).Higth +1);
 setfillstyle(1, (*p).MyColor); 
  bar((*p).point.x, (*p).point.y, (*p).point.x + (*p).Longth*n /100, (*p).point.y +(*p).Higth);
  (*p).MyText[10] = n % 10 +48;
  (*p).MyText[9] = n / 10 +48;
  setfillstyle(1, (*p).BackGColor);
  bar ((*p).point.x + (*p).Longth +10, (*p).point.y, (*p).point.x + (*p).Longth +10+104, (*p).point.y +(*p).Higth);
  outtextxy ((*p).point.x + (*p).Longth +10, (*p).point.y, (*p).MyText);
}

void GraphicsInit(int mode,int driver)
{
 registerbgidriver(EGAVGA_driver);/*这一行代码是为了包含显示驱动,当程序编译在这一行出错时,请屏蔽这一行代码*/
 initgraph(&driver, &mode, "E://tc2//BGI");/* 需要正确的BGI路径*/   
}

/*下面的函数用于计算用户给出的曲面方程的三维坐标*/
float GetResult(float r,float angel1,float angel2)
{
 float result;
 struct _3DPoint point;
 point.x = r * cos(angel1) * cos(angel2);
 point.y = r * cos(angel1) * sin(angel2);
 point.z = r * sin(angel1);
/* result = point.x * point.x + point.y * point.y + 
      + point.z * point.z - 10000;*/
     
 result = point.x * point.x + point.y * point.y + 50 * point.x
     - 50 * pow(point.x * point.x + point.y * point.y,0.5)
      + point.z * point.z - 1;/*此处输入用户方程*/
 return result;
}

 

本文来自CSDN博客:http://blog.csdn.net/xiajia/archive/2005/04/14/347905.aspx

原创粉丝点击