目录
前言
一、MeshDataSource构建
1、网格点
2、单元
3、MeshDataSource
二、网格、云图加载
1.构建网格对象
2.加载云图数据
显示颜色标尺
3.显示网格、云图
三、形变、动画
总结
前言
在OpenCascade中的包MeshVS提供了网格的可视化功能。使用包MeshVS提供的类和简单函数可以实现网格的灵活显示:
本文主要介绍OpenCascade中MeshVS的使用方法。用来展示网格、云图以及形变动画。
位移动画
一、MeshDataSource构建
MeshDataSource包含顶点node和元素element,由三角网格的点坐标数据 std::vector< PointXYZ> CoordData 以及点之间的拓扑关系std::vector<std::vector> Ele2NodeData(比如三个点构成一个三角形的索引值),需要自己定义DataSource来显示网格。
这里参考了Open CASCADE自定义MeshVS_DataSource yuleaf的博客
由于需要显示形变,和位移动画,所以在这基础上修改一些内容
1、网格点
增加了位移属性
struct PointXYZ
{
int NodeID;
double X;
double Y;
double Z;
double Ux = 0;
double Uy = 0;
double Uz = 0;
PointXYZ()
{
X = 0;
Y = 0;
Z = 0;
}
PointXYZ(int id ,double x,double y,double z)
{
NodeID = id;
X = x;
Y = y;
Z = z;
}
void setUnknowns(double ux,double uy,double uz)
{
Ux = ux;
Uy = uy;
Uz = uz;
}
};
2、单元
struct Element
{
int G1;
int G2;
int G3;
Element()
{
G1 = 0;
G2 = 0;
G3 = 0;
}
Element(int g1 ,int g2,int g3)
{
G1 = g1;
G2 = g2;
G3 = g3;
}
};
3、MeshDataSource
这里增加两个参数,ampFactory形变比例系数,例如0到1变化,模型从初始位置位移到最终位置;ampDistRadio最大位移比例参数,比如真实位移数据不太明显,则需要根据模型尺寸进行放大缩小最大位移,让显示效果更加好看一点。
.h文件
#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 MeshDataSource;
DEFINE_STANDARD_HANDLE(MeshDataSource, MeshVS_DataSource)
class MeshDataSource: public MeshVS_DataSource
{
public:
explicit MeshDataSource(std::vector<PointXYZ> CoordData, std::vector<Element> Ele2NodeData);
void setAmplificationFactor(double amp)
{
ampFactor = amp;
}
void setDistRadio(double amp)
{
ampDistRadio = amp;
}
Standard_Boolean GetGeom(const Standard_Integer ID, const Standard_Boolean IsElement, TColStd_Array1OfReal& Coords, Standard_Integer& NbNodes, MeshVS_EntityType& Type) const Standard_OVERRIDE;
Standard_Boolean GetGeomType(const Standard_Integer ID, const Standard_Boolean IsElement, MeshVS_EntityType& Type) const Standard_OVERRIDE;
Standard_Address GetAddr(const Standard_Integer ID, const Standard_Boolean IsElement) const Standard_OVERRIDE;
virtual Standard_Boolean GetNodesByElement(const Standard_Integer ID, TColStd_Array1OfInteger& NodeIDs, Standard_Integer& NbNodes) const Standard_OVERRIDE;
const TColStd_PackedMapOfInteger& GetAllNodes() const Standard_OVERRIDE;
const TColStd_PackedMapOfInteger& GetAllElements() const Standard_OVERRIDE;
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(MeshDataSource, MeshVS_DataSource)
protected:
private:
TColStd_PackedMapOfInteger myNodes;
TColStd_PackedMapOfInteger myElements;
Handle(TColStd_HArray2OfInteger) myElemNodes;
Handle(TColStd_HArray2OfReal) myNodeCoords;
Handle(TColStd_HArray2OfReal) myNodeDisps;
Handle(TColStd_HArray2OfReal) myElemNormals;
double ampFactor = 1;
double ampDistRadio = 1;
};
.cpp文件
#include <Precision.hxx>
#include <TColgp_SequenceOfXYZ.hxx>
#include <TColStd_DataMapOfIntegerInteger.hxx>
#include <TColStd_DataMapOfIntegerReal.hxx>
#include <QFile>
#include <QTextStream>
IMPLEMENT_STANDARD_RTTIEXT(MeshDataSource, MeshVS_DataSource)
MeshDataSource::MeshDataSource(std::vector<PointXYZ> CoordData, std::vector<Element> Ele2NodeData)
{
myNodeCoords = new TColStd_HArray2OfReal(1, CoordData.size(), 1, 3);
myNodeDisps = 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);
myNodeDisps->SetValue(i, 1, CoordData[i-1].Ux);
myNodeDisps->SetValue(i, 2, CoordData[i-1].Uy);
myNodeDisps->SetValue(i, 3, CoordData[i-1].Uz);
}
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);
myElemNodes->SetValue(i, 1, Ele2NodeData[i - 1].G1+1);
myElemNodes->SetValue(i, 2, Ele2NodeData[i - 1].G2+1);
myElemNodes->SetValue(i, 3, Ele2NodeData[i - 1].G3+1);
myElemNormals->SetValue(i, 1, 0);
myElemNormals->SetValue(i, 2, 0);
myElemNormals->SetValue(i, 3, 1);
}
}
Standard_Boolean MeshDataSource::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)+myNodeDisps->Value(IdxNode, j)*ampFactor*ampDistRadio;
}
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)+myNodeDisps->Value(ID, 1)*ampFactor*ampDistRadio;
Coords(2) = myNodeCoords->Value(ID, 2)+myNodeDisps->Value(ID, 2)*ampFactor*ampDistRadio;
Coords(3) = myNodeCoords->Value(ID, 3)+myNodeDisps->Value(ID, 3)*ampFactor*ampDistRadio;
return Standard_True;
}
else
return Standard_False;
}
Standard_Boolean MeshDataSource::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;
}
}
Standard_Address MeshDataSource::GetAddr(const Standard_Integer, const Standard_Boolean) const
{
return NULL;
}
Standard_Boolean MeshDataSource::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;
}
const TColStd_PackedMapOfInteger& MeshDataSource::GetAllNodes() const
{
return myNodes;
}
const TColStd_PackedMapOfInteger& MeshDataSource::GetAllElements() const
{
return myElements;
}
Standard_Boolean MeshDataSource::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;
}
二、网格、云图加载
1.构建网格对象
Handle(MeshVS_Mesh) MeshBuild::CreateMesh(std::vector<PointXYZ> coordData, std::vector<Element> ele2NodeData){
Handle(MeshVS_Mesh) mesh = new MeshVS_Mesh();
Handle(MeshDataSource) data = new MeshDataSource(coordData,ele2NodeData);
mesh->SetData(data);
mesh->GetDrawer()->SetColor(MeshVS_DA_EdgeColor,Quantity_NOC_BLACK);//线颜色
mesh->GetDrawer()->SetColor(MeshVS_DA_VectorColor,Quantity_NOC_BLACK);//点颜色
mesh->GetDrawer()->SetColor(MeshVS_DA_InteriorColor, Quantity_NOC_GRAY);//体颜色
mesh->GetDrawer()->SetBoolean(MeshVS_DA_ShowEdges, Standard_True);//显示线
mesh->GetDrawer()->SetBoolean(MeshVS_DA_DisplayNodes, Standard_False);//显示点
mesh->SetDisplayMode(MeshVS_DMF_Shading);//显示模式
mesh->SetMeshSelMethod(MeshVS_MSM_PRECISE);//选择模式
//mesh->SetHilightMode(MeshVS_DMF_Shading);
return mesh;
}
2.加载云图数据
MeshVS_MeshPrsBuilder:基本显示生成器,只可用来显示网格;
MeshVS_TextPrsBuilder:文本显示生成器,可以用来在网格中显示文本;
MeshVS_VectorPrsBuilder:向量显示生成器,可以用来在网格中显示箭头;
MeshVS_NodalColorPrsBuilder:顶点颜色生成器,可以给网格中每个顶点设置不同颜色;
MeshVS_ElementalColorPrsBuilder:元素颜色生成器,可以给网格中每个三角面片设置不同的颜色;
当前选择使用MeshVS_NodalColorPrsBuilder:顶点颜色生成器
Handle(FemMesh) mesh = CreateMesh(coordData, ele2NodeData);
MeshVS_DataMapOfIntegerColor colormap = getMeshDataMap(tt, max, min);
Handle(MeshVS_NodalColorPrsBuilder) nodal = new MeshVS_NodalColorPrsBuilder(mesh, MeshVS_DMF_NodalColorDataPrs | MeshVS_DMF_OCCMask);
nodal->SetColors(colormap);
mesh->setDistRadio(distRadio);
mesh->AddBuilder(nodal);
//根据数据最大值最小值映射到颜色红到蓝,转换网格点对应颜色
MeshVS_DataMapOfIntegerColor getMeshDataMap(std::vector<double> tt, double max, double min)
{
double a, r, g, b = 0;
MeshVS_DataMapOfIntegerColor colormap;
int index = 0;
for (double t : tt)
{
a = (t - min) / (max - min);
r = a;
b = 1 - a;
g = 1 - ((r - b) < 0 ? b - r : r - b);
colormap.Bind(index + 1, Quantity_Color(r, g, b, Quantity_TOC_RGB));
index++;
}
return colormap;
}
显示颜色标尺
参数:标题,最小值,最大值,颜色反转(默认颜色是从蓝到红数据依次增大)
Handle(AIS_ColorScale) OccView::ShowColorScale(Standard_CString str, double min, double max,bool isRedToBlue)
{
TCollection_ExtendedString tostr(str,true);
Handle(AIS_ColorScale) aColorScale = new AIS_ColorScale();
aColorScale->SetFormat(TCollection_AsciiString("%E"));
aColorScale->SetSize(100, 400);
aColorScale->SetRange(min, max);//设置颜色条区间
// aColorScale->SetColorType(Aspect_TOCSD_AUTO);
aColorScale->SetNumberOfIntervals(9);
//aColorScale->SetSmoothTransition(Standard_True);//颜色平衡过度
aColorScale->SetLabelPosition(Aspect_TOCSP_RIGHT);
aColorScale->SetTextHeight(14);
aColorScale->SetColor(Quantity_Color(Quantity_NOC_BLACK));
aColorScale->SetTitle(tostr);
if(isRedToBlue){
aColorScale->SetColorRange(Quantity_Color(Quantity_NOC_RED),Quantity_Color(Quantity_NOC_BLUE1));
}
aColorScale->SetLabelType(Aspect_TOCSD_AUTO);
aColorScale->SetZLayer(Graphic3d_ZLayerId_TopOSD);
Graphic3d_Vec2i anoffset(0, Standard_Integer(400));
//aColorScale->SetTransformPersistence(Graphic3d_TMF_2d,gp_Pnt(-1,0,0));
mContext->SetTransformPersistence(aColorScale, new Graphic3d_TransformPers(Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER, anoffset));
mContext->SetDisplayMode(aColorScale, 1, Standard_False);
mContext->Display(aColorScale, Standard_True);
return aColorScale;
}
3.显示网格、云图
mMesh->GetDrawer()->SetBoolean(MeshVS_DA_ShowEdges, IsShowMesh);//显示线
mView->GetContext()->Display(mMesh, Standard_True);
mView->V3dView_fitAll();
三、形变、动画
ampFactory参数默认为1,网格点设置上初始数据则会产生形变,这里产生动画是将整个位移周期分割为n份,定时器根据步进刷新云图来达到动画的效果。
void setAmplificationFactor(double amp)
{
if (!mMesh)
{
return;
}
mMesh->setAmplificationFactor(amp);
mView->GetContext()->Remove(mMesh, Standard_False);
mView->GetContext()->Display(mMesh, Standard_True);
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了OpenCascade中MeshVS的使用方法,而occ提供了大量处理模型的方法还需要我去学习。