1、创建工程
启动VC6.0,创建新的工程,File | New | Projects | MFC AppWizard (exe)。假设工程名为"SDIshow3D"。对向导使用默认配置,可以创建单文档或多文档程序。
2、为SoWin和Coin添加代码
u 打开SDIshow3D.cpp文件。
1) 包含头文件:
#include <Inventor/Win/SoWin.h>
2) 编辑函数CSDIshow3DApp::InitInstance(),在第一行中添加:
SoWin::init("");
上述用于初始化SoWin和Coin库,在使用这些函数库之前必须被调用。
u 打开SDIshow3DView.h文件。
1) 在预编译头之后(#ifdef/#pragma once/#endif sequence)添加包含文件:
#include <Inventor/Win/SoWin.h>
#include<Inventor/Win/viewers/SoWinExaminerViewer.h>
2) 添加公共数据成员:
SoWinExaminerViewer * viewer;
ExaminerViewer用于渲染场景,且用于交互显示(旋转,选择部分场景等)
u 打开文件SDIshow3DView.cpp。
1) 修改构造函数如下:
CSDIshow3DView::CMFCViewerView()
{
viewer = NULL;
}
2) 修改析构函数如下:
CSDIshow3DView::CMFCViewerView()
{
if (viewer != NULL)
delete viewer;
}
3) 修改方法CSDIshow3DView::OnDraw(CDC*pDC) 如下:
void CSDIshow3DView::OnDraw(CDC* pDC)
{
CSDIshow3DDoc* pDoc =GetDocument();
ASSERT_VALID(pDoc);
if (viewer == NULL)
{
viewer = newSoWinExaminerViewer( m_hWnd );
viewer->setDecoration(FALSE);
}
SoSeparator*root = GetDocument()->GetScene(); //与文档类的Getscene()联系起来
viewer->setSceneGraph(root);//设置场景图的顶部节点为root
WINDOWPLACEMENTp; //包含关于屏幕上窗口的位置的信息。
memset(&p,0, sizeof(p));
p.length =sizeof(WINDOWPLACEMENT);
p.showCmd =SW_SHOWMAXIMIZED;
SetWindowPlacement(&p);
}
这会将ExaminerViewer嵌入到CSDIshow3DView窗口中。
u 打开文件SDIshow3DDoc.h。
1) 添加包含文件:
#include <Inventor/Win/SoWin.h>
#include <Inventor/Win/viewers/SoWinExaminerViewer.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoDrawStyle.h>
#include <Inventor/nodes/SoPointSet.h>
#include <Inventor/SbBox.h>
#include <Inventor/SbVec3f.h>
#include <Inventor/nodes/SoTriangleStripSet.h>
#include <Inventor/nodes/SoNormal.h>
#include <Inventor/nodes/SoNormalBinding.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/nodes/SoSphere.h>
#include <vector>
#include <math.h>
using namespace std ;
2) 添加类:
class SoSeparator; //通知编译器,将使用SoSeparator类。
class Point
{
public:
int pt_ID;
float X;
float Y;
float Z;
};
3) 添加方法:
public:
voidCreateCoordinates();
int Read_PtsFile(char*filename);
SoSeparator *GetScene();
4) 添加数据成员:
private:
vector<float>X,Y,Z;
vector<Point> m_Points; //原始点坐标
SoSeparator * m_pScene;
public:
SbVec3f * coord;
bool m_PtsRead;
SoSeparator * root; //场景图的最高结点
u 打开文件SDIshow3DDoc.cpp。
1) 为读取点云菜单添加消息响应函数
void CSDIshow3DDoc::OnReadPoints()
{
// TODO: Add yourcommand handler code here
CString szFilter ="(*.pts;*.txt;*.iv)|*.pts;*.txt;*.iv||"; //过滤显示该类文件
CFileDialog dlg(TRUE,"", "", NULL, szFilter, NULL);
if(dlg.DoModal() ==IDOK)
{
CString str;
str =dlg.GetPathName();
char * p;
p =str.GetBuffer(0); //获取str字符串的指针
int nump =Read_PtsFile(p); //调用Read_PtsFile函数,返回读取到的点的个数
//str.Format("文件读取完毕,共计点%d个",nump);
//MessageBox(NULL,str,"三维坐标读取",0);
UpdateAllViews(NULL);
return;
}
else
{
return;
}
}
2) 添加函数,用于读取点云文件:
int CSDIshow3DDoc::Read_PtsFile(char *filename)
{
FILE * f = fopen(filename,"r");
float num;
int sum = 0;
while (!feof(f)) //读取点坐标,如果文件不为空则继续读
{
fscanf(f,"%f",&num); //将文件指针f指向的文件以浮点型格式保存到num中
sum++; //每次从文件中读取一个数则sum加1
if (sum%3 == 1) //将坐标分别存入XYZ矢量中
{
X.push_back(num); //在矢量X尾部插入数字num
}
if (sum%3 == 2)
{
Y.push_back(num);
}
if (sum%3 == 0)
{
Z.push_back(num);
}
}
fclose(f);
m_PtsRead = true;
CreateCoordinates(); //调用该函数创建点的坐标
return X.size() - 1; //返回点的个数
}
3) 添加函数,用于创建点云对于的3D坐标
void CSDIshow3DDoc::CreateCoordinates()//将XYZ矢量中的值保存到3D点中
{
int num_p = X.size() -1;
coord = newSbVec3f[num_p];
for (int i = 0; i<num_p; i++)
{
coord[i].setValue(X[i],Y[i],Z[i]);
float x,y,z;
coord[i].getValue(x,y,z);
Point temp;
temp.pt_ID = i;
temp.X = x;
temp.Y = y;
temp.Z = z;
m_Points.push_back(temp);
}
}
4) 将点云添加到场景中
SoSeparator * CSDIshow3DDoc::GetScene()
{
if (m_PtsRead)
{
if (m_pScene !=NULL)
{
m_pScene->unref();
}
m_pScene = newSoSeparator;
m_pScene->ref();
SoLightModel *lightmodel = new SoLightModel;
lightmodel->model= SoLightModel::BASE_COLOR; //关闭默认光源
m_pScene->addChild(lightmodel);
SoCoordinate3 *coord3 = new SoCoordinate3;
coord3->point.setValues(0,X.size()-1, coord);
m_pScene->addChild(coord3);
SoMaterial *mat_p = new SoMaterial;
mat_p->diffuseColor.setValue(0,1,0);
m_pScene->addChild(mat_p);
SoDrawStyle *drawstyle = new SoDrawStyle;
drawstyle->pointSize= 1.5;
drawstyle->style= SoDrawStyle::LINES;
m_pScene->addChild(drawstyle);
SoPointSet *pointset = new SoPointSet;
m_pScene->addChild(pointset);
SoSeparator *temp = new SoSeparator;
SoMaterial * mat= new SoMaterial;
mat->diffuseColor.setValue(1,1,0);
temp->addChild(mat);
m_pScene->addChild(temp);
SoSeparator *instructsep = new SoSeparator; //加载操作指令说明
m_pScene->addChild(instructsep);
SoMaterial *myMaterial = new SoMaterial;
instructsep->addChild(myMaterial);
myMaterial->diffuseColor.setValue(0.5,1.0, 1.0);
SoTranslation *instructtrans = new SoTranslation;
instructtrans->translation= SbVec3f(-2.0f, 1.3f, 2.0f);
instructsep->addChild(instructtrans);
SoText2 *instructions = new SoText2;
const char *str[] = {
"Instructionsfor the MFCViewer tutorial",
"",
"Leftmouse button = rotate",
"Middlemouse button = move",
"CTRL+ middle mouse button = zoom",
"Rightmouse button = options"
};
instructions->string.setValues(0,sizeof(str) / sizeof(char *), str);
instructions->justification= SoText2::LEFT;
instructsep->addChild(instructions);
}
return m_pScene;
}