当前位置: 首页 > 工具软件 > OpenNURBS > 使用案例 >

《OpenNURBS》part1 3DMViewer

贡可人
2023-12-01

《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")
#endif


int 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、运行结果
在另外一台没联网的电脑上调试通过的,自己的电脑没有环境配置。那么结果图略了。


 类似资料:

相关阅读

相关文章

相关问答