创建结构体,用于储存三角形顶点和重心信息
struct TriangleSelf
{
public:
osg::Vec3f _p0;
osg::Vec3f _p1;
osg::Vec3f _p2;
osg::Vec3f _centre;
TriangleSelf(osg::Vec3f p0,osg::Vec3f p1,osg::Vec3f p2,osg::Vec3f centre)
{
_p0 = p0;
_p1 = p1;
_p2 = p2;
_centre = centre;
}
TriangleSelf()
{
}
};
//创建结构体,用于储存格子编号和三角形
struct Classification
{
public:
int _gridIndex;
std::vector<TriangleSelf> _triangleselfList;
Classification(int &gridIndex)
{
_gridIndex=gridIndex;
}
};
//创建nodevisitor,用于遍历节点,得到所有三角形的顶点
class MeshNodeVisitor : public osg::NodeVisitor
{
public:
//构造函数
MeshNodeVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
m_TriPoints=new osg::Vec3Array; //定义数组,用于保存索引号对应的顶点
}
//重载MatrixTransform节点的apply函数
virtual void apply(osg::MatrixTransform &node)
{
traverse(node);
}
//重载group的apply()函数
virtual void apply(osg::Group &group)
{
traverse(group);
}
//重载Geode的apply()函数,获取对应索引号的顶点数组m_TriPoints,三角形索引数组triangle和三角形中心数组centerPoint
virtual void apply(osg::Geode &geode)
{
unsigned int drwnum = geode.getNumDrawables();
for ( unsigned int i = 0; i < drwnum; i++ )
{
osg::ref_ptr<osg::Geometry>geometry= geode.getDrawable( i )->asGeometry();
if ( !geometry )
continue;
for ( unsigned int n = 0; n < geometry->getNumPrimitiveSets(); ++n )
{
osg::PrimitiveSet* ps =geometry->getPrimitiveSet( n );
if ( !ps )
continue;
osg::ref_ptr<osg::Vec3Array> va = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());//获取顶点数组
if((osg::PrimitiveSet::DrawElementsUIntPrimitiveType==ps->getType())&&(osg::PrimitiveSet::TRIANGLES==ps->getMode()))
{
osg::ref_ptr<osg::DrawElementsUInt>deui = new osg::DrawElementsUInt; //定义deui用于接收索引数组
deui = dynamic_cast<osg::DrawElementsUInt*>(ps);
const unsigned indexNum = deui->getNumIndices(); //indexNum获取了索引的个数
for (unsigned int m=0; m<indexNum; m++)
{
m_TriPoints->push_back(va->at(deui->at(m)));//获取索引位置的顶点
}
}
else
{
std::cout<<"模型绘制方式不是三角形!!"<<std::endl;
}
}
}
traverse(geode);
}
public:
//创建函数用于将m_TriPoints传出去
osg::ref_ptr<osg::Vec3Array> getTriPoints()
{
return m_TriPoints.release();
}
private:
osg::ref_ptr<osg::DrawElementsUInt>deui;
osg::ref_ptr<osg::Vec3Array> m_TriPoints;
};
//创建函数,用于绘制划分网格
osg::ref_ptr<osg::Group>CreateGrids(const osg::Vec3f oriPoint,float lengthx,float lengthy,int &row, int &col, int&pace)
{ //申请一个叶子节点
osg::ref_ptr<osg::Group>pGroup =new osg::Group();
//申请变量用于表示各顶点所在的行、列以及顶点之间的间隔
row=0;
col=0;
pace=0;
//输出模型包围盒的大小,便于设置行列数。
std::cout<<"包围盒x方向大小为:"<<lengthx<<", "<<"y方向的大小为:"<<lengthy<<std::endl;
std::cout<<"enter the col,row and the pace : "<<std::endl;
std::cin>>col>>row>>pace;
for(int i=0;i<row;i++)
{
//获取起始点坐标且赋值
float x_ori = oriPoint.x();
float y_ori = oriPoint.y();
float z_ori = oriPoint.z();
for(int j=0;j<col;j++)
{
osg::ref_ptr<osg::Vec3Array>vertexs = new osg::Vec3Array;
//计算出任意一个四边形顶点的坐标值
vertexs->push_back(osg::Vec3f(x_ori+j*pace,y_ori-i*pace,z_ori));
vertexs->push_back(osg::Vec3f(x_ori+(j+1)*pace,y_ori-i*pace,z_ori));
vertexs->push_back(osg::Vec3f(x_ori+(j+1)*pace,y_ori-(i+1)*pace,z_ori));
vertexs->push_back(osg::Vec3f(x_ori+j*pace,y_ori-(i+1)*pace,z_ori));
//绘制格子
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
osg::ref_ptr<osg::Geometry>geom=new osg::Geometry();
geom->setVertexArray(vertexs);
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
osg::ref_ptr<osg::Vec4Array> colors2 = new osg::Vec4Array;
colors2->push_back(osg::Vec4(0,0,0,0.1));
geom->setColorArray(colors2);
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
geode->addDrawable(geom.get());
geode->getOrCreateStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON);
int gridIndex = i*col+j;
std::ostringstream oss;//创建一个流
oss<<gridIndex;//把值传递如流中
std::string gridName = oss.str();
geode->setName(gridName);
osg::ref_ptr<osg::Geode> geode2 = new osg::Geode;
osg::ref_ptr<osg::Geometry>geom2=new osg::Geometry();
geom2->setVertexArray(vertexs);
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
colors->push_back(osg::Vec4(1,1,1,1));
geom2->setColorArray(colors);
geom2->setColorBinding(osg::Geometry::BIND_OVERALL);
geom2->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4));
geode2->addDrawable(geom2.get());
osg::LineWidth* lw = new osg::LineWidth;
lw->setWidth(1);
geode2->getOrCreateStateSet()->setAttributeAndModes(lw,osg::StateAttribute::ON);
pGroup->addChild(geode);
pGroup->addChild(geode2);
}
}
//函数返回geode
return pGroup.release();
}
//创建函数,用于绘制包围盒,从而获取划分网格的参考位置以及参考大小
osg::ref_ptr<osg::Geode> createboundingbox(osg::Node *node,osg::Vec3f &oriPoint,float &lengthx,float &lengthy)
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
osg::ComputeBoundsVisitor boundvisitor ;
node->accept(boundvisitor);
osg::BoundingBox bb = boundvisitor.getBoundingBox();
//获取包围盒的长宽高和中点
lengthx = bb.xMax()-bb.xMin();
lengthy = bb.yMax()-bb.yMin();
float lengthz = bb.zMax()-bb.zMin();
osg::Vec3f pcenter=bb.center();
//获取包围盒左后上方顶点
oriPoint.set(bb.xMin(),bb.yMax(),bb.zMin());
//绘制包围盒
osg::ref_ptr<osg::ShapeDrawable>drawable = new osg::ShapeDrawable(new osg::Box(pcenter,lengthx,lengthy,lengthz));
//设置包围盒样式
osg::ref_ptr<osg::StateSet>stateset = new osg::StateSet;
stateset= drawable->getOrCreateStateSet();
osg::ref_ptr<osg::PolygonMode>polygon = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE);
stateset->setAttributeAndModes(polygon);
//设置线宽
osg::ref_ptr<osg::LineWidth>linewidth = new osg::LineWidth(3.0);
stateset->setAttribute(linewidth);
//设置包围盒颜色
drawable->setColor(osg::Vec4(1.0,1.0,0.0,1.0));
geode->addDrawable(drawable);
return geode.get();
}
//创建函数,用于判断一个点是否在矩形内部
bool isPointinPolygon(osg::Vec2f p,osg::ref_ptr<osg::Vec2Array> pPoly)
{
float xMin=pPoly->at(3).x();//此处顶点的编号与后续本程序中网格顶点顺序有关
float xMax=pPoly->at(1).x();
float yMin=pPoly->at(3).y();
float yMax=pPoly->at(1).y();
if(xMin<=p.x()&&p.x()<xMax&&yMin<=p.y()&&p.y()<yMax)
return true;
else
return false;
}
//创建PickHandler类,用于编写自定义的事件响应器
class PickHandler : public osgGA::GUIEventHandler
{
public:
PickHandler(osgViewer::Viewer*viewer,std::vector<Classification> classFications):mViewer(viewer),lastselect(0)
{
mClassifications = classFications;
pRoot = viewer->getSceneData()->asSwitch();
pTriGeode = new osg::Geode();
}//定义构造函数,有两个参数,mViewer和lastselect,分别初始化为viewer和0
//在handle中实现的功能有双击鼠标左键调用pick函数
virtual bool handle(const osgGA::GUIEventAdapter&ea,osgGA::GUIActionAdapter& aa)
{
osg::ref_ptr<osgViewer::Viewer>viewer=dynamic_cast<osgViewer::Viewer*>(&aa);
if(viewer=NULL)
return false;
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::DOUBLECLICK):
{
if(ea.getButton()==1)
Pick(ea.getX(),ea.getY());
}
return true;
}
return false;
}
private:
//pick函数用于选择对象
void Pick(float x,float y)
{
osg::ref_ptr<osg::Node>node=new osg::Node;
osg::ref_ptr<osg::Group>parent=new osg::Group;
/*** 进行相交测试,几种测试方法见osgUtil::LineSegmentIntersector,结果保留在lsi里面***/
osgUtil::LineSegmentIntersector* lsi=new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::WINDOW,x,y);
osgUtil::IntersectionVisitor ivsec(lsi);
mViewer->getCamera()->accept(ivsec);
if (lsi->containsIntersections())
{
if (!(lsi->getFirstIntersection().nodePath.empty()))
{
osg::NodePath np= lsi->getFirstIntersection().nodePath;
osg::ref_ptr<osg::Geode> pGeode = dynamic_cast<osg::Geode*>(np[np.size()-1]);
if(pGeode.valid())
{
std::string gridName = pGeode->getName();
int num = atoi(gridName.c_str());
std::vector<TriangleSelf> triList = mClassifications[num]._triangleselfList;
//更新三角形
if(pTriGeode->getNumDrawables()>0)
{
pRoot->removeChild(pTriGeode);
pTriGeode->removeDrawables(0,pTriGeode->getNumDrawables());
}
for (int j = 0 ;j<triList.size();j++)
{
TriangleSelf tri = triList[j];
osg::ref_ptr<osg::Geometry> pTriGeom = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> pTriVerts = new osg::Vec3Array;
pTriVerts->push_back(osg::Vec3(tri._p0));
pTriVerts->push_back(osg::Vec3(tri._p1));
pTriVerts->push_back(osg::Vec3(tri._p2));
pTriGeom->setVertexArray(pTriVerts);
pTriGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,pTriVerts->size()));
pTriGeode->addDrawable(pTriGeom);
}
pRoot->addChild(pTriGeode);
}
}
}
return;
}
osgViewer::Viewer *mViewer;
osg::Node *lastselect;
std::vector<Classification> mClassifications;
osg::ref_ptr<osg::Switch> pRoot;
osg::ref_ptr<osg::Geode> pTriGeode;
};
int main ()
{
osg::ref_ptr<osgViewer::Viewer>viewer=new osgViewer::Viewer;
osg::ref_ptr<osg::Switch>root=new osg::Switch;
osg::ref_ptr<osg::Node>mesh=osgDB::readNodeFile("mesh_2.osg");
MeshNodeVisitor mnv;
mesh->accept(mnv);
//获取模型三角形信息
osg::ref_ptr<osg::Vec3Array>pVerts = mnv.getTriPoints();
std::vector<TriangleSelf> triangleVector;
for (unsigned int i = 0;i<pVerts->size();i+=3)
{
osg::Vec3f p0 = pVerts->at(i);
osg::Vec3f p1 = pVerts->at(i+1);
osg::Vec3f p2 = pVerts->at(i+2);
osg::Vec3f centre = (p0+p1+p2)/3.0;
TriangleSelf _triangle(p0,p1,p2,centre);
triangleVector.push_back(_triangle);
}
//调用函数createboundingbox()和CreateGrids(),用于绘制网格
osg::Vec3f oriPoint;
float lengthx,lengthy;
int row,col,pace;
osg::ref_ptr<osg::Node> node = createboundingbox(mesh,oriPoint,lengthx,lengthy);
osg::ref_ptr<osg::Group> geode=CreateGrids(oriPoint,lengthx,lengthy,row,col,pace);
//判断三角形和网格的关系,将三角形进行按网格划分
std::vector<Classification> classification;
int gridNum = (col) * (row);
for (int i = 0 ;i<gridNum;++i)
{
Classification _classfi(i);
classification.push_back(_classfi);
}
bool isNextTri = false;
for(unsigned int n=0,k = 0;n<pVerts->size();++k,n+=3)
{
for(int i=0;i<row;++i)
{
if(isNextTri)
{
isNextTri = false;
break;
}
for(int j=0;j<col;++j)
{
osg::Vec2 p(triangleVector[k]._centre.x(),triangleVector[k]._centre.y());
osg::ref_ptr<osg::Vec2Array> pPoly = new osg::Vec2Array;
pPoly->push_back(osg::Vec2f(oriPoint.x()+j*pace,oriPoint.y()-i*pace));
pPoly->push_back(osg::Vec2f(oriPoint.x()+(j+1)*pace,oriPoint.y()-i*pace));
pPoly->push_back(osg::Vec2f(oriPoint.x()+(j+1)*pace,oriPoint.y()-(i+1)*pace));
pPoly->push_back(osg::Vec2f(oriPoint.x()+j*pace,oriPoint.y()-(i+1)*pace));
if(isPointinPolygon(p,pPoly))
{
int gridIndex=i*col+j;
classification[gridIndex]._triangleselfList.push_back(triangleVector[k]);
isNextTri = true;
break;
}
}
}
}
//输出每个格子内有多少三角形
for(int i=0;i<gridNum;i++)
{
int selTriCount=classification[i]._triangleselfList.size();
std::cout<<"第"<<i<<"个格子里有"<<selTriCount<<"个三角形"<<std::endl;
}
//输出每个格子的三角形(输出为osg格式)
for(int m=0;m<gridNum;m++)
{
osg::Group*triGroup=new osg::Group;
for(int n=0;n<classification[m]._triangleselfList.size();n++)
{
osg::ref_ptr<osg::Vec3Array>griVertex=new osg::Vec3Array;
griVertex->push_back(classification[m]._triangleselfList[n]._p0);
griVertex->push_back(classification[m]._triangleselfList[n]._p1);
griVertex->push_back(classification[m]._triangleselfList[n]._p2);
osg::ref_ptr<osg::Geometry>triGeometry=new osg::Geometry;
triGeometry->setVertexArray(griVertex);
triGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,3));
osg::ref_ptr<osg::Geode>triGeode=new osg::Geode;
triGeode->addDrawable(triGeometry);
triGroup->addChild(triGeode.get());
}
std::ostringstream oss;//创建一个流
oss<<m;//把值传递如流中
std::string fileName = oss.str() + ".osg";
osg::Node* triNode=dynamic_cast<osg::Node*>(triGroup);//在使用writeNodeFile时,节点始终是Node指针,故需要将其转换成Node
osgDB::writeNodeFile(*triNode,fileName);
}
root->addChild(geode.get());
//root->addChild(mesh.get(),true);
viewer->setSceneData(root);
viewer->addEventHandler(new PickHandler(viewer,classification));
//viewer->setUpViewInWindow(500,500,800,600);
return viewer->run();
}
osg网格划分
最新推荐文章于 2024-08-23 09:09:08 发布