443 lines
16 KiB
C++
443 lines
16 KiB
C++
/****************************************************************************
|
|
*
|
|
*
|
|
* Copyright 2010-2013, VizExpertsIndia Pvt. Ltd. (unpublished)
|
|
*
|
|
* All rights reserved. This notice is intended as a precaution against
|
|
* inadvertent publication and does not imply publication or any waiver
|
|
* of confidentiality. The year included in the foregoing notice is the
|
|
* year of creation of the work. No part of this work may be used,
|
|
* reproduced, or transmitted in any form or by any means without the prior
|
|
* written permission of Vizexperts India Pvt Ltd.
|
|
*
|
|
*
|
|
***************************************************************************
|
|
*/
|
|
|
|
/// \file ReaderWritterOpenCASCADE.cpp
|
|
/// \brief implementation file for osgdb plugin for IGES format
|
|
/// contains implementation of ReaderWritterOpenCASCADE class
|
|
/// \author Abhishek Bansal
|
|
|
|
#include "ReaderWriterOpenCASCADE.h"
|
|
|
|
#include <iostream>
|
|
|
|
// OpenCascade Headers
|
|
#include <TopTools_HSequenceOfShape.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
#include <Standard_ErrorHandler.hxx>
|
|
#include <Standard_CString.hxx>
|
|
#include <Standard_Macro.hxx>
|
|
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
|
|
#include <BRepMesh_IncrementalMesh.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepTools.hxx>
|
|
#include <BRepGProp_Face.hxx>
|
|
#include <BRepBuilderAPI_Sewing.hxx>
|
|
|
|
#include <ShapeFix_Shape.hxx>
|
|
|
|
#include <gp_Pnt2d.hxx>
|
|
#include <TColgp_Array1OfPnt2d.hxx>
|
|
|
|
#include <Poly_Triangulation.hxx>
|
|
#include <Poly_Array1OfTriangle.hxx>
|
|
|
|
#include <IGESControl_Reader.hxx>
|
|
#include <IGESControl_Writer.hxx>
|
|
#include <IGESControl_Controller.hxx>
|
|
|
|
#include <STEPCAFControl_Reader.hxx>
|
|
|
|
#include <TDocStd_Document.hxx>
|
|
#include <XCAFDoc_ColorTool.hxx>
|
|
#include <XCAFDoc_ShapeTool.hxx>
|
|
#include <XCAFDoc_Location.hxx>
|
|
#include <XCAFDoc_DocumentTool.hxx>
|
|
|
|
#include <XCAFApp_Application.hxx>
|
|
|
|
#include <IGESCAFControl_Reader.hxx>
|
|
|
|
#include <TDF_Label.hxx>
|
|
#include <TDF_LabelSequence.hxx>
|
|
#include <TDF_ChildIterator.hxx>
|
|
|
|
#include <Quantity_Color.hxx>
|
|
|
|
// osg headers
|
|
#include<osg/PrimitiveSet>
|
|
#include <osg/MatrixTransform>
|
|
|
|
#include <osgUtil/SmoothingVisitor>
|
|
|
|
//#define _LOG_DEBUG_
|
|
|
|
REGISTER_OSGPLUGIN(OpenCASCADE, ReaderWritterOpenCASCADE)
|
|
|
|
ReaderWritterOpenCASCADE::ReaderWritterOpenCASCADE()
|
|
{
|
|
OSG_NOTICE<<"ReaderWritterOpenCASCADE::ReaderWritterOpenCASCADE()"<<std::endl;
|
|
|
|
supportsExtension("IGES","IGES file format");
|
|
supportsExtension("iges","IGES file format");
|
|
supportsExtension("IGS","IGS file format");
|
|
supportsExtension("igs","IGS file format");
|
|
supportsExtension("stp","STEP file format");
|
|
supportsExtension("STP","STEP file format");
|
|
}
|
|
|
|
osgDB::ReaderWriter::ReadResult ReaderWritterOpenCASCADE::readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
|
|
{
|
|
// some error handling
|
|
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
|
|
if (!acceptsExtension(ext))
|
|
return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
std::string file = osgDB::findDataFile(fileName, options);
|
|
if (file.empty())
|
|
return ReadResult::FILE_NOT_FOUND;
|
|
|
|
OSG_INFO << "ReaderWritterOpenCASCADE::readNode(" << file.c_str() << ")\n";
|
|
|
|
OCCTKReader reader;
|
|
return reader.igesToOSGGeode(fileName);
|
|
}
|
|
|
|
osgDB::ReaderWriter::WriteResult ReaderWritterOpenCASCADE::writeNode(const osg::Node& /*node*/,const std::string& fileName /*fileName*/,const Options*) const
|
|
{
|
|
// some error handling
|
|
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
|
|
if (!acceptsExtension(ext))
|
|
return WriteResult::FILE_NOT_HANDLED;
|
|
|
|
std::cout << "File Writing not supported yet" << std::endl;
|
|
return WriteResult::FILE_NOT_HANDLED;
|
|
}
|
|
|
|
/// \brief heals a opencascade shape
|
|
/// \detail http://www.opencascade.org/org/forum/thread_12716/?forum=3
|
|
/// Usually IGES files suffer from precision problems (when transferring from
|
|
/// one CAD system to another).It might be the case that faces are not sewed
|
|
/// properly, or do not have the right precision, and so the tessellator does
|
|
/// not treat them like "sewed". this needs to be done for sewing
|
|
/// \param shape opencascade shape to be healed
|
|
void ReaderWritterOpenCASCADE::OCCTKReader::_healShape(TopoDS_Shape& shape)
|
|
{
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << std::endl << "Going to heal shape!!";
|
|
#endif
|
|
|
|
ShapeFix_Shape fixer(shape);
|
|
fixer.Perform();
|
|
shape = fixer.Shape();
|
|
|
|
BRepBuilderAPI_Sewing sew;
|
|
sew.Add(shape);
|
|
sew.Perform();
|
|
shape = sew.SewedShape();
|
|
}
|
|
|
|
/// \brief takes and OpenCascadeShape and returns OSG geometry(drawable), which further can be added to a geode
|
|
/// \detail it iterates shape and breaks it into faces, builds vertex list, color list and creates geometry
|
|
/// transformation is applied to each vertex before storing it into vertex list
|
|
/// all vertices are assigned same color
|
|
/// \param shape shape to be converted in geometry. Not a const because it needs to be modified if healing
|
|
/// is enabled
|
|
/// \param color color of geometry
|
|
/// \param transformation matrix with which vertex position has to be transformed
|
|
osg::ref_ptr<osg::Geometry> ReaderWritterOpenCASCADE::OCCTKReader::_createGeometryFromShape(TopoDS_Shape& shape, const osg::Vec3& geomColor, gp_Trsf& transformation)
|
|
{
|
|
// vector to save vertices
|
|
osg::ref_ptr<osg::Vec3Array> vertexList = new osg::Vec3Array();
|
|
|
|
|
|
osg::Array::Binding colorBinding = osg::Array::BIND_OVERALL;
|
|
|
|
// vector to save _colorTool
|
|
osg::ref_ptr<osg::Vec3Array> colorList = new osg::Vec3Array();
|
|
if (colorBinding==osg::Array::BIND_OVERALL)
|
|
{
|
|
colorList->push_back(geomColor);
|
|
}
|
|
|
|
// create one osg primitive set
|
|
osg::ref_ptr<osg::DrawElementsUInt> triangleStrip = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
|
|
unsigned int noOfTriangles = 0;
|
|
|
|
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
|
|
|
|
// large vertex datasets work best with VBO.
|
|
geom->setUseVertexBufferObjects(true);
|
|
|
|
if(!shape.IsNull())
|
|
{
|
|
// clean any previous triangulation
|
|
BRepTools::Clean(shape);
|
|
|
|
//_healShape(shape);
|
|
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << std::endl << "Building a Mesh !!" ;
|
|
#endif
|
|
|
|
/// call to incremental mesh on this shape
|
|
/// \todo not sure why this 1 is passed. Its called deflection BTW
|
|
/// need to find a way to calculate it
|
|
double linearDeflection = 1.0;
|
|
BRepMesh_IncrementalMesh(shape, linearDeflection);
|
|
|
|
///iterate faces
|
|
// this variable will help in keeping track of face indices
|
|
unsigned int index = 0;
|
|
for (TopExp_Explorer ex(shape, TopAbs_FACE); ex.More(); ex.Next())
|
|
{
|
|
TopoDS_Face face = TopoDS::Face(ex.Current());
|
|
TopLoc_Location location;
|
|
|
|
/// triangulate current face
|
|
Handle (Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);
|
|
if (!triangulation.IsNull())
|
|
{
|
|
int noOfNodes = triangulation->NbNodes();
|
|
|
|
// Store vertices. Build vertex array here
|
|
for(int j = 1; j <= triangulation->NbNodes(); j++)
|
|
{
|
|
// populate vertex list
|
|
// Ref: http://www.opencascade.org/org/forum/thread_16694/?forum=3
|
|
gp_Pnt pt = (triangulation->Nodes())(j).Transformed(transformation * location.Transformation());
|
|
vertexList->push_back(osg::Vec3(pt.X(), pt.Y(), pt.Z()));
|
|
|
|
// populate color list
|
|
if (colorBinding==osg::Array::BIND_PER_VERTEX)
|
|
{
|
|
colorList->push_back(geomColor);
|
|
}
|
|
}
|
|
|
|
/// now we need to get face indices for triangles
|
|
// get list of triangle first
|
|
const Poly_Array1OfTriangle& triangles = triangulation->Triangles();
|
|
|
|
//No of triangles in this triangulation
|
|
noOfTriangles = triangulation->NbTriangles();
|
|
|
|
Standard_Integer v1, v2, v3;
|
|
for (unsigned int j = 1; j <= noOfTriangles; j++)
|
|
{
|
|
/// If face direction is reversed then we add verticews in reverse order
|
|
/// order of vertices is important for normal calculation later
|
|
if (face.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
triangles(j).Get(v1, v3, v2);
|
|
}
|
|
else
|
|
{
|
|
triangles(j).Get(v1, v2, v3);
|
|
}
|
|
triangleStrip->push_back(index + v1 - 1);
|
|
triangleStrip->push_back(index + v2 - 1);
|
|
triangleStrip->push_back(index + v3 - 1);
|
|
}
|
|
index = index + noOfNodes;
|
|
}
|
|
}
|
|
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << "Creating a geometry.." << std::endl;
|
|
#endif
|
|
|
|
geom->setVertexArray(vertexList.get());
|
|
|
|
geom->setColorArray(colorList.get(), colorBinding);
|
|
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << "Adding Primitive set" << std::endl;
|
|
#endif
|
|
|
|
geom->addPrimitiveSet(triangleStrip.get());
|
|
}
|
|
|
|
return geom;
|
|
}
|
|
|
|
/// \brief this function is single point of contact for this class.
|
|
/// it takes path of IGES file and returns an OpenSceneGraph Geode
|
|
/// which directly can be used anywhere. It calculates normals using osgUtil::smoother
|
|
osg::ref_ptr<osg::Geode> ReaderWritterOpenCASCADE::OCCTKReader::igesToOSGGeode(const std::string& filePath)
|
|
{
|
|
// XDE: Extended Data Exchange
|
|
// OCAF: OpenCascade Application Technology Framework
|
|
/// Getting an XDE document
|
|
Handle(TDocStd_Document) doc;
|
|
XCAFApp_Application::GetApplication()->NewDocument("MDTV-XCAF", doc);
|
|
|
|
std::string ext = osgDB::getLowerCaseFileExtension(filePath);
|
|
if (ext=="stp" || ext=="step")
|
|
{
|
|
OSG_NOTICE<<"Using STEPCAFControl_Reader to read file : "<<filePath<<std::endl;
|
|
STEPCAFControl_Reader reader;
|
|
reader.SetColorMode(true);
|
|
reader.SetNameMode(true);
|
|
reader.SetLayerMode(true);
|
|
|
|
//IGESControl_Reader Reader;
|
|
reader.ReadFile( (Standard_CString)filePath.c_str() );
|
|
/// transfer data from reader to doc
|
|
if(!reader.Transfer(doc))
|
|
{
|
|
std::cout << "Cannot read any relevant data from the STEP file" << std::endl;
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OSG_NOTICE<<"Using IGESCAFControl_Reader to read file : "<<filePath<<std::endl;
|
|
IGESCAFControl_Reader reader;
|
|
reader.SetColorMode(true);
|
|
reader.SetNameMode(true);
|
|
reader.SetLayerMode(true);
|
|
|
|
//IGESControl_Reader Reader;
|
|
reader.ReadFile( (Standard_CString)filePath.c_str() );
|
|
/// transfer data from reader to doc
|
|
if(!reader.Transfer(doc))
|
|
{
|
|
std::cout << "Cannot read any relevant data from the IGES file" << std::endl;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// To get a node considered as an Assembly from an XDE structure, you can use the Label of the node.
|
|
_assembly = XCAFDoc_DocumentTool::ShapeTool(doc->Main());
|
|
|
|
// To query, edit, or initialize a Document to handle Colors of XCAF
|
|
_colorTool = XCAFDoc_DocumentTool::ColorTool(doc->Main());
|
|
|
|
// free shape sequence
|
|
// get sequence of free shape labels
|
|
TDF_LabelSequence freeShapes;
|
|
_assembly->GetFreeShapes(freeShapes);
|
|
|
|
if(freeShapes.Length() == 0)
|
|
{
|
|
std::cout << "No Shapes found" << std::endl;
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
std::cout << std::endl << "No of Free Shapes: " << freeShapes.Length();
|
|
}
|
|
|
|
_modelGeode = new osg::Geode();
|
|
/// send all root nodes for recursive traversing
|
|
/// find transformation as it will be needed for location calculation later
|
|
for (int i = 1; i <= freeShapes.Length(); i++)
|
|
{
|
|
Handle(XCAFDoc_Location) attribute;
|
|
gp_Trsf transformation;
|
|
freeShapes.Value(i).FindAttribute(XCAFDoc_Location::GetID(), attribute);
|
|
if(attribute.IsNull() == Standard_False)
|
|
{
|
|
TopLoc_Location location = attribute->Get();
|
|
transformation = location.Transformation();
|
|
}
|
|
_traverse(freeShapes.Value(i), transformation);
|
|
}
|
|
|
|
/// calculate normals
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << "Calculating Normals" << std::endl;
|
|
#endif
|
|
|
|
osgUtil::SmoothingVisitor sv;
|
|
sv.setCreaseAngle(osg::DegreesToRadians(20.0));
|
|
_modelGeode->accept(sv);
|
|
|
|
return _modelGeode;
|
|
}
|
|
|
|
/// \brief recursively traverse opencascade assembly structure and build a osg geode
|
|
/// this function also finds color for leaf node shapes and calculates transformation from parent
|
|
/// to leaf
|
|
/// \param shapeTree its a OCT(OpenCascade Technology) XDE document label which might contain children or referred shapes
|
|
/// \param transformation contains transformation matrix to be applied
|
|
/// \note Simple Shape: is a shape which is not a compound. Its can be a free or non free shape
|
|
/// \note Support Thread: http://www.opencascade.org/org/forum/thread_25512/?forum=3
|
|
void ReaderWritterOpenCASCADE::OCCTKReader::_traverse(const TDF_Label &shapeTree, gp_Trsf& transformation)
|
|
{
|
|
TDF_Label referredShape;
|
|
/// find if current shape referes some shape. if it does then traverse that
|
|
/// else it is a simple shape and do visualize that simple shape
|
|
if(_assembly->GetReferredShape(shapeTree, referredShape))
|
|
{
|
|
Handle(XCAFDoc_Location) attribute;
|
|
referredShape.FindAttribute(XCAFDoc_Location::GetID(), attribute);
|
|
if(attribute.IsNull() == Standard_False)
|
|
{
|
|
TopLoc_Location location = attribute->Get();
|
|
transformation *= location.Transformation();
|
|
}
|
|
|
|
/// if referred shape has children traverse them first else
|
|
/// traverse the shape itself
|
|
if(referredShape.HasChild())
|
|
{
|
|
TDF_ChildIterator it;
|
|
for(it.Initialize(referredShape); it.More(); it.Next())
|
|
{
|
|
_traverse(it.Value(), transformation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << std::endl << "No children found";
|
|
#endif
|
|
_traverse(referredShape, transformation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/// Find out if this simple shape has any color store that color as color of geometry
|
|
Quantity_Color color;
|
|
osg::Vec3 geomColor = osg::Vec3(.7, .7, .7);
|
|
if(_colorTool->GetColor(shapeTree, XCAFDoc_ColorGen, color) ||
|
|
_colorTool->GetColor(shapeTree, XCAFDoc_ColorSurf, color) ||
|
|
_colorTool->GetColor(shapeTree, XCAFDoc_ColorCurv, color) )
|
|
{
|
|
#ifdef _LOG_DEBUG_
|
|
std::cout << std::endl << "Free Shape has a color !! " << color.Red() << " " << color.Green() << " "<< color.Blue();
|
|
#endif
|
|
geomColor = osg::Vec3(color.Red(),color.Green(), color.Blue());
|
|
}
|
|
|
|
TopoDS_Shape shape = _assembly->GetShape(shapeTree);
|
|
|
|
Handle(XCAFDoc_Location) attribute;
|
|
shapeTree.FindAttribute(XCAFDoc_Location::GetID(), attribute);
|
|
if(attribute.IsNull() == Standard_False)
|
|
{
|
|
TopLoc_Location location = attribute->Get();
|
|
transformation *= location.Transformation();
|
|
}
|
|
|
|
osg::ref_ptr<osg::Geometry> geom = _createGeometryFromShape(shape, geomColor, transformation);
|
|
/// add this geometry to model geode
|
|
if(geom.valid())
|
|
{
|
|
_modelGeode->addDrawable(geom);
|
|
}
|
|
else
|
|
{
|
|
std::cout << std::endl << "Invalid Geometry found !!";
|
|
}
|
|
}
|
|
}
|