《OpenNURBS》part1 3DMViewer

来源:互联网 发布:js设置请求头解决跨域 编辑:程序博客网 时间:2024/05/16 12:37

《OpenNURBS》part1 3DMViewer

最近在做曲线拟合、曲线动态编辑,多段线、Spline、B-Spline、NURBS等资料蛮多,眼花缭乱,能看懂的同时能使用的不多,很多时候需要自己重新写。

这里使用的是OpenNURBS库,Rhino出的,Rhino自不用解释,大学时机械设计时的神器之一。言归正传,该库可以去官网上下载,是一个VS2010版的解决方案,VS2010以上版本都可以编译通过,github上的貌似需要openthread支持。目前最好使用官网提供的源码和素材,能够轻松编译通过。

1、VS2010及以上版本编译,编译很简单,不详细说。

2、配置环境,编译好了,自己建一个文件夹,老三样:include、lib、bin。

3、测试用例:

1)openNURBS自带的有五个样例,还有一个gl的,但是没有加入到项目中,可以自己试着调试看看。自带的五个都能编译通过,可以自行测试,看看能不能用。

2)我用的GitHub上的一个例子,3DMViewer,该例子需要OpenNURBS和OSG3.3.1的支持了,没有编译OSG的童鞋留心了,要不自己编译,要不止步在上条就可以了。

4、调试3DMViewer,前提是三方库和路径、lib、dll都配置好了。三个文件,如下:

(1)RhinoReader.h

#ifndef _RHINOREADER_H_#define _RHINOREADER_H_#include <osg/Group>#include <opennurbs.h>/*** @breif Rhino opennurbs 3DM file reader.*/class RhinoReader{public:    RhinoReader(const std::string& theFileName);    ~RhinoReader(void);    osg::Node* GetRhinoModel(void);    void SetEdgePrecision(double thePrecision);    void SetFacePrecision(double thePrecision);private:    void Read3DM(const std::string& theFileName);    osg::Node* BuildBrep(const ON_Brep* theBrep);    osg::Node* BuildEdge(const ON_Brep* theBrep);    osg::Node* BuildWireFrameFace(const ON_BrepFace* theFace);    osg::Node* BuildShadedFace(const ON_BrepFace* theFace);private:    double mEdgePrecision;    double mFacePrecision;    ONX_Model mRhinoModel;    osg::Node* mRhinoNode;};#endif // _RHINOREADER_H_

(2)RhinoReader.cpp

#include "RhinoReader.h"#include <osg/Geode>#include <osg/Geometry>#include <osgUtil/SmoothingVisitor>#include <osgUtil/DelaunayTriangulator>const double TOLERANCE_EDGE = 1e-6;const double TOLERANCE_FACE = 1e-6;RhinoReader::RhinoReader(const std::string& theFileName): mRhinoNode(NULL){    Read3DM(theFileName);}RhinoReader::~RhinoReader(void){}osg::Node* RhinoReader::GetRhinoModel(){    return mRhinoNode;}void RhinoReader::Read3DM(const std::string& theFileName){    if (!mRhinoModel.Read(theFileName.c_str()))    {        return ;    }    osg::Group* aRoot = new osg::Group();    for (int i = 0; i < mRhinoModel.m_object_table.Count(); ++i)    {        ONX_Model_Object anObject = mRhinoModel.m_object_table[i];        const ON_Brep* aBrep = dynamic_cast<const ON_Brep*> (anObject.m_object);        if (aBrep)        {            aRoot->addChild(BuildBrep(aBrep));        }    }    mRhinoNode = aRoot;}osg::Node* RhinoReader::BuildBrep(const ON_Brep* theBrep){    osg::ref_ptr<osg::Group> aGroup = new osg::Group();    //aGroup->addChild(BuildEdge(theBrep));    for (int i = 0; i < theBrep->m_F.Count(); ++i)    {        ON_BrepFace* aFace = theBrep->Face(i);        aGroup->addChild(BuildWireFrameFace(aFace));        //aGroup->addChild(BuildShadedFace(aFace));    }    //theBrep->Dump(ON_TextLog());    return aGroup.release();}osg::Node* RhinoReader::BuildEdge(const ON_Brep* theBrep){    osg::ref_ptr<osg::Geode> aGeode = new osg::Geode();    for (int i = 0; i < theBrep->m_E.Count(); ++i)    {        osg::ref_ptr<osg::Geometry> aGeometry = new osg::Geometry();        osg::ref_ptr<osg::Vec3Array> aVertices = new osg::Vec3Array();        ON_BrepEdge* anEdge = theBrep->Edge(i);        double t0 = 0.0;        double t1 = 0.0;        double d = 0.0;        anEdge->GetDomain(&t0, &t1);        d = (t1 - t0) / 5.0;        for (double t = t0; (t - t1) < TOLERANCE_EDGE; t += d)        {            ON_3dPoint aPoint = anEdge->PointAt(t);            aVertices->push_back(osg::Vec3(aPoint.x, aPoint.y, aPoint.z));        }        aGeometry->setVertexArray(aVertices);        aGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, aVertices->size()));        aGeode->addDrawable(aGeometry);    }    return aGeode.release();}osg::Node* RhinoReader::BuildWireFrameFace(const ON_BrepFace* theFace){    osg::ref_ptr<osg::Geode> aGeode = new osg::Geode();        ON_NurbsSurface aSurface;    if (theFace->GetNurbForm(aSurface) == 0)    {        return NULL;    }    double u0 = aSurface.Domain(0).Min();    double u1 = aSurface.Domain(0).Max();    double v0 = aSurface.Domain(1).Min();    double v1 = aSurface.Domain(1).Max();    double d0 = 0.0;    double d1 = 0.0;    d0 = (u1 - u0) / 10.0;    d1 = (v1 - v0) / 10.0;    for (double u = u0; (u - u1) < TOLERANCE_FACE; u += d0)    {        osg::ref_ptr<osg::Geometry> aGeometry = new osg::Geometry();        osg::ref_ptr<osg::Vec3Array> aVertices = new osg::Vec3Array();        for (double v = v0; (v - v1) < TOLERANCE_FACE; v += d1)        {            ON_3dPoint aPoint = aSurface.PointAt(u, v);            aVertices->push_back(osg::Vec3(aPoint.x, aPoint.y, aPoint.z));        }        aGeometry->setVertexArray(aVertices);        aGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, aVertices->size()));        aGeode->addDrawable(aGeometry);    }    for (double v = v0; (v - v1) < TOLERANCE_FACE; v += d1)    {        osg::ref_ptr<osg::Geometry> aGeometry = new osg::Geometry();        osg::ref_ptr<osg::Vec3Array> aVertices = new osg::Vec3Array();        for (double u = u0; (u - u1) < TOLERANCE_FACE; u += d0)        {            ON_3dPoint aPoint = aSurface.PointAt(u, v);            aVertices->push_back(osg::Vec3(aPoint.x, aPoint.y, aPoint.z));        }        aGeometry->setVertexArray(aVertices);        aGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, aVertices->size()));        aGeode->addDrawable(aGeometry);    }    return aGeode.release();}osg::Node* RhinoReader::BuildShadedFace(const ON_BrepFace* theFace){    osg::ref_ptr<osg::Geode> aGeode = new osg::Geode();        ON_NurbsSurface aSurface;    if (theFace->GetNurbForm(aSurface) == 0)    {        return NULL;    }    osg::ref_ptr<osg::Geometry> aGeometry = new osg::Geometry();    osg::ref_ptr<osg::Vec3Array> aUVPoints = new osg::Vec3Array();    osg::ref_ptr<osg::Vec3Array> aPoints = new osg::Vec3Array();    osg::ref_ptr<osg::Vec3Array> aBounds = new osg::Vec3Array();    osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator();    osg::ref_ptr<osgUtil::DelaunayConstraint> dc = new osgUtil::DelaunayConstraint();    // add loop for the face.    for (int i = 0; i < theFace->LoopCount(); ++i)    {        ON_BrepLoop* aLoop = theFace->Loop(i);        if (aLoop->m_type == ON_BrepLoop::outer)        {            for (int j = 0; j < aLoop->TrimCount(); ++j)            {                ON_BrepTrim* aTrim = aLoop->Trim(j);                const ON_Curve* aPCurve = aTrim->TrimCurveOf();                if (aPCurve)                {                    ON_3dPoint aStartPoint = aPCurve->PointAtStart();                    ON_3dPoint aEndPoint = aPCurve->PointAtEnd();                    aUVPoints->push_back(osg::Vec3(aStartPoint.x, aStartPoint.y, 0.0));                    aUVPoints->push_back(osg::Vec3(aEndPoint.x, aEndPoint.y, 0.0));                }            }        }        else if (aLoop->m_type == ON_BrepLoop::inner)        {            for (int j = 0; j < aLoop->TrimCount(); ++j)            {            }        }    }    dc->setVertexArray(aBounds);    dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, aBounds->size()));    // triangulate the parametric space.    //dt->addInputConstraint(dc);    dt->setInputPointArray(aUVPoints);    dt->triangulate();    //dt->removeInternalTriangles(dc);    for (osg::Vec3Array::const_iterator j = aUVPoints->begin(); j != aUVPoints->end(); ++j)    {        // evaluate the point on the surface        ON_3dPoint aPoint = aSurface.PointAt((*j).x(), (*j).y());        aPoints->push_back(osg::Vec3(aPoint.x, aPoint.y, aPoint.z));    }    //aGeometry->setVertexArray(aUVPoints);    aGeometry->setVertexArray(aPoints);    aGeometry->addPrimitiveSet(dt->getTriangles());    aGeode->addDrawable(aGeometry);    // use smoothing visitor to set the average normals    //osgUtil::SmoothingVisitor sv;    //sv.apply(*aGeode);    return aGeode.release();}


(3)main.cpp

#include <iostream>// OpenSceneGraph library.#include <osgGA/StateSetManipulator>#include <osgViewer/Viewer>#include <osgViewer/ViewerEventHandlers>#include "RhinoReader.h"#ifdef _DEBUG    #pragma comment(lib, "osgd.lib")    #pragma comment(lib, "osgGAd.lib")    #pragma comment(lib, "osgUtild.lib")    #pragma comment(lib, "osgViewerd.lib")    // OpenNURBS toolkit.    #pragma comment(lib, "opennurbs_d.lib")#else    #pragma comment(lib, "osg.lib")    #pragma comment(lib, "osgGA.lib")    #pragma comment(lib, "osgUtil.lib")    #pragma comment(lib, "osgViewer.lib")    // OpenNURBS toolkit.    #pragma comment(lib, "opennurbs.lib")#endifint main(int argc, char* argv[]){    //if (argc < 2)    //{     //   std::cout << "please input the 3dm file..." << std::endl;     //   return 0;    //}    ON::Begin();    RhinoReader aReader(/*argv[1]*/"v1");    osgViewer::Viewer viewer;    viewer.setSceneData(aReader.GetRhinoModel());    viewer.addEventHandler(new osgViewer::StatsHandler());    viewer.addEventHandler(new osgViewer::WindowSizeHandler());    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));    ON::End();    return viewer.run();}

注:此处的main函数被我注释了,调试时尽量使用上面的方法按F5进入调试,直接ctrl+F5会出错。

5、运行结果
在另外一台没联网的电脑上调试通过的,自己的电脑没有环境配置。那么结果图略了。