osg网格划分

创建结构体,用于储存三角形顶点和重心信息
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();
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值