由MeshVS_DataSource派生自定义DataSource
OCC在DataExchange中提供了.stl数据格式的导入与导出方法。在该类型文件中,模型以三角网格形式存储,OCC为此定义了针对.stl格式文件的数据存储方式,即XSDRAWSTLVRML_DataSource。如下为导入.stl并为其定义显示生成器的方法:
CFileDialog dlg(TRUE,
NULL,
NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
L"stl Files (*.stl)|*.stl;|STL Files (*.STL)|*.STL;||",
NULL);
CString SHAREPATHValue;
SHAREPATHValue.GetEnvironmentVariable(L"CSF_OCCTDataPath");
CString initdir = (SHAREPATHValue + "\\stl");
dlg.m_ofn.lpstrInitialDir = initdir;
if (dlg.DoModal() != IDOK)
return;
// read the data and create a data source
TCollection_AsciiString aFileName((const wchar_t*)dlg.GetPathName());
Handle(Message_ProgressIndicator) aProgInd = Handle(Message_ProgressIndicator)();
Handle(Poly_Triangulation) aSTLMesh = RWStl::ReadFile(aFileName, aProgInd);
Handle(XSDRAWSTLVRML_DataSource) aDS = new XSDRAWSTLVRML_DataSource(aSTLMesh);
// create mesh
Handle(MeshVS_Mesh) aMesh = new MeshVS_Mesh();
aMesh->SetDataSource(aDS);
// use builder
Handle(MeshVS_MeshPrsBuilder) aBuilder = new MeshVS_MeshPrsBuilder(aMesh);
aMesh->GetDrawer()->SetColor(MeshVS_DA_EdgeColor, Quantity_NOC_YELLOW);
aMesh->AddBuilder(aBuilder, Standard_False);
myAISContext->Display(aMesh, Standard_True);
Fit();
如果不是读取STL文件,而是有三角网格的点坐标数据 std::vector< PointXYZ> CoordData 以及点之间的拓扑关系std::vector<std::vector> Ele2NodeData(比如三个点构成一个三角形的索引值),需要自己定义DataSource来显示网格。
struct PointXYZ
{
double X;
double Y;
double Z;
PointXYZ()
{
X = 0;
Y = 0;
Z = 0;
}
};
根据XSDRAWSTLVRML_DataSource派生方法,自定义myDataSource类。添加对应的 myDataSource.h 与myDataSource.cpp,参考XSDRAWSTLVRML_DataSource类,只需要构造函数。具体如下:
// myDataSource.h
#pragma once
#include <Standard.hxx>
#include <Standard_Type.hxx>
#include <Standard_Real.hxx>
#include <Standard_Address.hxx>
#include <Standard_Boolean.hxx>
#include <Standard_Integer.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <TColStd_HArray2OfInteger.hxx>
#include <TColStd_HArray2OfReal.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <MeshVS_EntityType.hxx>
#include <MeshVS_DataSource.hxx>
#include <Poly_Triangulation.hxx>
#include <vector>
class myDataSource;
DEFINE_STANDARD_HANDLE(myDataSource, MeshVS_DataSource)
class myDataSource: public MeshVS_DataSource
{
public:
myDataSource(std::vector< PointXYZ> CoordData, std::vector<std::vector<int>> Ele2NodeData);
//! Returns geometry information about node ( if IsElement is False ) or element ( IsElement is True )
//! by co-ordinates. For element this method must return all its nodes co-ordinates in the strict order: X, Y, Z and
//! with nodes order is the same as in wire bounding the face or link. NbNodes is number of nodes of element.
//! It is recommended to return 1 for node. Type is an element type.
Standard_Boolean GetGeom(const Standard_Integer ID, const Standard_Boolean IsElement, TColStd_Array1OfReal& Coords, Standard_Integer& NbNodes, MeshVS_EntityType& Type) const Standard_OVERRIDE;
//! This method is similar to GetGeom, but returns only element or node type. This method is provided for
//! a fine performance.
Standard_Boolean GetGeomType(const Standard_Integer ID, const Standard_Boolean IsElement, MeshVS_EntityType& Type) const Standard_OVERRIDE;
//! This method returns by number an address of any entity which represents element or node data structure.
Standard_Address GetAddr(const Standard_Integer ID, const Standard_Boolean IsElement) const Standard_OVERRIDE;
//! This method returns information about what node this element consist of.
virtual Standard_Boolean GetNodesByElement(const Standard_Integer ID, TColStd_Array1OfInteger& NodeIDs, Standard_Integer& NbNodes) const Standard_OVERRIDE;
//! This method returns map of all nodes the object consist of.
const TColStd_PackedMapOfInteger& GetAllNodes() const Standard_OVERRIDE;
//! This method returns map of all elements the object consist of.
const TColStd_PackedMapOfInteger& GetAllElements() const Standard_OVERRIDE;
//! This method calculates normal of face, which is using for correct reflection presentation.
//! There is default method, for advance reflection this method can be redefined.
virtual Standard_Boolean GetNormal(const Standard_Integer Id, const Standard_Integer Max, Standard_Real& nx, Standard_Real& ny, Standard_Real& nz) const Standard_OVERRIDE;
DEFINE_STANDARD_RTTIEXT(myDataSource, MeshVS_DataSource)
protected:
private:
TColStd_PackedMapOfInteger myNodes;
TColStd_PackedMapOfInteger myElements;
Handle(TColStd_HArray2OfInteger) myElemNodes;
Handle(TColStd_HArray2OfReal) myNodeCoords;
Handle(TColStd_HArray2OfReal) myElemNormals;
};
在构造函数myDataSource()中,需要赋值的主要有五个,即Private中所定义的参数。myNodes,myElements分别存储顶点、网格单元的索引号,要注意的是,起始序号从1开始。myNodeCoords是一个 CoordData.size() x 3 的矩阵,每一行为点的x,y,z坐标。myElemNodes存储每一个三角网格对应的顶点索引值。而myElemNormals为每一个三角网格的法向量,在需要区分三角网格正反面属性时有用。除了构造函数之外其他重写的函数不需要做改动。
// myDataSource.cpp
#include "myDataSource.h"
#include <vector>
#include <Precision.hxx>
#include <Standard_Type.hxx>
#include <TColgp_SequenceOfXYZ.hxx>
#include <TColStd_DataMapOfIntegerInteger.hxx>
#include <TColStd_DataMapOfIntegerReal.hxx>
IMPLEMENT_STANDARD_RTTIEXT(myDataSource, MeshVS_DataSource)
myDataSource::myDataSource(std::vector< PointXYZ> CoordData, std::vector<std::vector<int>> Ele2NodeData)
{
myNodeCoords = new TColStd_HArray2OfReal(1, CoordData.size(), 1, 3);
for (size_t i = 1; i <= CoordData.size(); i++)
{
myNodes.Add(i);
myNodeCoords->SetValue(i, 1, CoordData[i-1].X);
myNodeCoords->SetValue(i, 2, CoordData[i-1].Y);
myNodeCoords->SetValue(i, 3, CoordData[i-1].Z);
}
myElemNormals = new TColStd_HArray2OfReal(1, Ele2NodeData.size(), 1, 3);
myElemNodes = new TColStd_HArray2OfInteger(1, Ele2NodeData.size(), 1, 3);
for (size_t i = 1; i <= Ele2NodeData.size(); i++)
{
myElements.Add(i);
for (int j = 0; j < 3; j++)
{
Standard_Integer index = Ele2NodeData[i - 1][j];
myElemNodes->SetValue(i, j + 1, index);
}
myElemNormals->SetValue(i, 1, 0);
myElemNormals->SetValue(i, 2, 0);
myElemNormals->SetValue(i, 3, 1);
}
}
//================================================================
// Function : GetGeom
// Purpose :
//================================================================
Standard_Boolean myDataSource::GetGeom
(const Standard_Integer ID, const Standard_Boolean IsElement,
TColStd_Array1OfReal& Coords, Standard_Integer& NbNodes,
MeshVS_EntityType& Type) const
{
if (IsElement)
{
if (ID >= 1 && ID <= myElements.Extent())
{
Type = MeshVS_ET_Face;
NbNodes = 3;
for (Standard_Integer i = 1, k = 1; i <= 3; i++)
{
Standard_Integer IdxNode = myElemNodes->Value(ID, i);
for (Standard_Integer j = 1; j <= 3; j++, k++)
Coords(k) = myNodeCoords->Value(IdxNode, j);
}
return Standard_True;
}
else
return Standard_False;
}
else
if (ID >= 1 && ID <= myNodes.Extent())
{
Type = MeshVS_ET_Node;
NbNodes = 1;
Coords(1) = myNodeCoords->Value(ID, 1);
Coords(2) = myNodeCoords->Value(ID, 2);
Coords(3) = myNodeCoords->Value(ID, 3);
return Standard_True;
}
else
return Standard_False;
}
//================================================================
// Function : GetGeomType
// Purpose :
//================================================================
Standard_Boolean myDataSource::GetGeomType
(const Standard_Integer,
const Standard_Boolean IsElement,
MeshVS_EntityType& Type) const
{
if (IsElement)
{
Type = MeshVS_ET_Face;
return Standard_True;
}
else
{
Type = MeshVS_ET_Node;
return Standard_True;
}
}
//================================================================
// Function : GetAddr
// Purpose :
//================================================================
Standard_Address myDataSource::GetAddr
(const Standard_Integer, const Standard_Boolean) const
{
return NULL;
}
//================================================================
// Function : GetNodesByElement
// Purpose :
//================================================================
Standard_Boolean myDataSource::GetNodesByElement
(const Standard_Integer ID,
TColStd_Array1OfInteger& theNodeIDs,
Standard_Integer& /*theNbNodes*/) const
{
if (ID >= 1 && ID <= myElements.Extent() && theNodeIDs.Length() >= 3)
{
Standard_Integer aLow = theNodeIDs.Lower();
theNodeIDs(aLow) = myElemNodes->Value(ID, 1);
theNodeIDs(aLow + 1) = myElemNodes->Value(ID, 2);
theNodeIDs(aLow + 2) = myElemNodes->Value(ID, 3);
return Standard_True;
}
return Standard_False;
}
//================================================================
// Function : GetAllNodes
// Purpose :
//================================================================
const TColStd_PackedMapOfInteger& myDataSource::GetAllNodes() const
{
return myNodes;
}
//================================================================
// Function : GetAllElements
// Purpose :
//================================================================
const TColStd_PackedMapOfInteger& myDataSource::GetAllElements() const
{
return myElements;
}
//================================================================
// Function : GetNormal
// Purpose :
//================================================================
Standard_Boolean myDataSource::GetNormal
(const Standard_Integer Id, const Standard_Integer Max,
Standard_Real& nx, Standard_Real& ny, Standard_Real& nz) const
{
if (Id >= 1 && Id <= myElements.Extent() && Max >= 3)
{
nx = myElemNormals->Value(Id, 1);
ny = myElemNormals->Value(Id, 2);
nz = myElemNormals->Value(Id, 3);
return Standard_True;
}
else
return Standard_False;
}
前面所述为根据OCC提供源代码定义自己三角网格数据显示的方法,当需要显示体单元时,参考XSDRAWSTLVRML_DataSource3D类。