目录

前言

一、MeshDataSource构建

1、网格点

2、单元

3、MeshDataSource

二、网格、云图加载

1.构建网格对象

2.加载云图数据

显示颜色标尺

3.显示网格、云图

三、形变、动画

总结



前言

在OpenCascade中的包MeshVS提供了网格的可视化功能。使用包MeshVS提供的类和简单函数可以实现网格的灵活显示: 

本文主要介绍OpenCascade中MeshVS的使用方法。用来展示网格、云图以及形变动画。

mesh切片数据_#include

mesh切片数据_mesh切片数据_02


位移动画


一、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提供了大量处理模型的方法还需要我去学习。