/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see .
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#ifndef _GCTL_MESH_IO_H
#define _GCTL_MESH_IO_H
// library's head files
#include "../core.h"
#include "../geometry.h"
#include "../utility.h"
#include "triangle_io.h"
#include "tetgen_io.h"
#include "gmsh_io.h"
#include "map"
namespace gctl
{
/**
* @brief 无效的索引缺省值。
*/
#define DEFAULT_INVALID_TAG -9999
/**
* @brief 网格单元体名称枚举类型。
*/
enum element_type_enum
{
NotSet,
_2NodeLine,
_3NodeTriangle,
_4NodeQuadrangle,
_4NodeTetrahedron,
_8NodeHexahedron,
_6NodePrism,
_5NodePyramid,
_3NodeSecondOrderLine,
_6NdoeSecondOrderLine,
_9NodeSecondOrderQuadrangle,
_10NodeSecondOrderTetrahedron,
_27NodeSecondOrderHexahedron,
_18NodeSecondOrderPrism,
_14NodeSecondOrderPyramid,
_1NodePoint,
_8NodeSecondOrderQuadrangle,
_20NdoeSecondOrderHexahedron,
_15NodeSecondOrderPrism,
_13NodeSecondOrderPyramid,
_9NodeThirdOrderIncompleteTriangle,
_10NdoeThirdOrderTriangle,
_12NodeFourthOrderIncompleteTriangle,
_15NodeFourthOrderTriangle,
_15NodeFifthOrderCompleteTriangle,
_21NodeFifthOrderCompleteTriangle,
_4NodeThirdOrderEdge,
_5NodeFourthOrderEdge,
_6NodeFifthOrderEdge,
_20NodeThirdOrderTetrahedron,
_35NodeFourthOrderTetrahedron,
_56NodeFifithOrderTetrahedron,
_64NodeThirdOrderHexahedron,
_125NodeFourthOrderHexahedron,
};
/**
* @brief 网格单元体标签类型枚举类型
*
*/
enum element_tag_enum
{
PhysicalTag, // 元素的物理分组标签
GeometryTag, // 元素的几何分组标签
PartitionTag, // 元素的剖分分组标签
NodeTag, // 顶点的标签(仅用于输出顶点标签数据)
};
/**
* @brief 网格单元体结构体
*
*/
struct meshio_element
{
bool enabled; // 单元体是否有效
int id; // 单元体编号
element_type_enum type; // 单元体类型
array vert_ptrs; // 顶点指针数组
array neigh_ptrs; // 相邻单元体指针数组
meshio_element();
};
/**
* @brief 网格数据结构体
*
*/
struct meshio_data
{
bool enabled; // 数据体是否有效
mesh_data_type_e d_type; // 数据类型
array str_tag; // 字符串类型的标签(默认为一个,即为数据的名称)
array real_tag; // 实数类型的标签(默认为一个,等于0.0)
array int_tag; // 整数类型的标签(最少三个,最后一个为数据的长度)
array vert_ptrs; // 两者只能存在一个
array elem_ptrs; // 两者只能存在一个
array val; // 数据值
meshio_data();
/**
* @brief 清空数组并重置变量。
*
*/
void clear();
/**
* @brief 检查数据体是否合规
*
*/
bool pass_check();
};
/**
* @brief 网格单元体分组结构体。
*
*/
struct meshio_element_group
{
bool enabled; // 组是否有效
element_type_enum type; // 组内单元体类型
int phys_group; // 物理分组标签
int geom_group; // 几何分组标签
int part_group; // 剖分分组标签
std::string name; // 组名
std::vector elem_ptrs; // 组内单元体指针数组
meshio_element_group();
/**
* @brief 将组内所有单元体设置为有效状态。
*
*/
void enable_elements();
/**
* @brief 将组内所有单元体设置为无效状态。
*
*/
void disable_elements();
};
/**
* @brief 网格读写类,这个类实现了多种数据格式的网格文件的读写操作。并具备简单的单元体操作功能。
*
*/
class mesh_io
{
public:
mesh_io();
virtual ~mesh_io();
/**
* @brief 重置(清空)网格数据。
*
*/
void reset();
/**
* @brief 输出网格数据信息至指定流。
*
* @param ss 指定流(默认为clog)
*/
void info(std::ostream &ss = std::clog);
/**
* @brief 编辑网格数据状态。
*
* @param swt 使能类型(Enable或Disable)
* @param dataname 数据名称(缺省值为null,表示对所有数据进行操作)。
*/
void edit_data(switch_type_e swt, std::string dataname = "null");
/**
* @brief 按单元体类型编辑网格单元体组。
*
* @param swt 使能类型(Enable或Disable)
* @param e_type 单元体类型(缺省值值NotSet,表示对所有单元体组进行操作)。
*/
void edit_group(switch_type_e swt, element_type_enum e_type = NotSet);
/**
* @brief 按单元体组名称编辑网格单元体组。
*
* @param swt 使能类型(Enable或Disable)。
* @param grp_name 单元体组名称。
*/
void edit_group(switch_type_e swt, std::string grp_name);
/**
* @brief 按单元体组标签编辑网格单元体组。
*
* @param swt 使能类型(Enable或Disable)。
* @param tag_type 标签类型(PhysicalTag,GeometryTag或者PartitionTag)。
* @param tag 标签值。
*/
void edit_group(switch_type_e swt, element_tag_enum tag_type, int tag);
/**
* @brief 按单元体组标签编辑网格单元体组的名称。
*
* @param anchor_type 搜索的标签类型(PhysicalTag,GeometryTag或者PartitionTag)。
* @param anchor_group 搜索的标签值。
* @param new_name 单元体组的新名称。
*/
void edit_group(element_tag_enum anchor_type, int anchor_group, std::string new_name);
/**
* @brief 按单元体组标签搜索并编辑网格单元体组的标签。
*
* @param anchor_type 搜索的标签类型(PhysicalTag,GeometryTag或者PartitionTag)。
* @param anchor_group 搜索的标签值
* @param tar_type 更改的标签类型(PhysicalTag,GeometryTag或者PartitionTag)。
* @param tar_group 更改的标签值
*/
void edit_group(element_tag_enum anchor_type, int anchor_group, element_tag_enum tar_type, int tar_group);
/**
* @brief 返回顶点标签数组的引用。
*
* @return 整型数组的引用。
*/
const array &get_node_tag();
/**
* @brief 返回指定类型与名称的标签值
*
* @param anchor_type 查找的标签类型(PhysicalTag,GeometryTag或者PartitionTag)。
* @param anchor_name 查找的元素组名称。
* @return 标签值
*/
int get_tag(element_tag_enum anchor_type, std::string anchor_name);
/**
* @brief 返回所有顶点数组的引用。
*
* @return 顶点数组的引用。
*/
const array &get_nodes();
/**
* @brief 返回所有单元体数组的引用。
*
* @return 单元体数组的引用。
*/
const array &get_elems();
/**
* @brief 返回对应类型单元体的数量(注意只会统计有效的单元体组)。
*
* @param e_type 单元体类型(缺省为NotSet,返回所有单元体类型的总和)。
* @return 整型大小。
*/
size_t element_size(element_type_enum e_type = NotSet);
/**
* @brief 返回对应标签类型与标签值的单元体数量(注意只会统计有效的单元体组)。
*
* @param tag_type 标签类型。
* @param tag 标签值。
* @return 整型大小。
*/
size_t element_size(element_tag_enum tag_type, int tag);
/**
* @brief 返回对应名称的单元体数量(注意只会统计有效的单元体组)。
*
* @param phys_name 单元体组名称
* @return 整型大小。
*/
size_t element_size(std::string phys_name);
/**
* @brief 将对应标签类型转换为网格数据类型
*
* @param tag_type 标签类型。
*/
void convert_tags_to_data(element_tag_enum tag_type);
/**
* @brief 输出对应名称的单元体组到三角形数组。
*
* @param tris 输出的三角形数组的引用。
* @param phys_name 单元体组的名称。
*/
void export_elements_to(array &tris, std::string phys_name = "All");
/**
* @brief 输出对应标签类型与标签值的单元体组到三角形数组。
*
* @param tris 输出的三角形数组的引用。
* @param tag_type 标签类型。
* @param tag 标签值。
*/
void export_elements_to(array &tris, element_tag_enum tag_type, int tag);
/**
* @brief 输出对应名称的单元体组到四面体数组。
*
* @param tets 输出的四面体数组的引用。
* @param phys_name 单元体组的名称。
*/
void export_elements_to(array &tets, std::string phys_name = "All");
/**
* @brief 输出对应标签类型与标签值的单元体组到四面体数组。
*
* @param tris 输出的四面体数组的引用。
* @param tag_type 标签类型。
* @param tag 标签值。
*/
void export_elements_to(array &tets, element_tag_enum tag_type, int tag);
/**
* @brief 获取gmsh格式分组表
*
* @param g_groups gmsh格式表
*/
void get_gmsh_physical_groups(std::vector &g_groups);
/**
* @brief 检查是否存在名为name的数据
*
* @param name 数据名称
* @param type 数据类型
*
* @return 存在则返回数据索引,不存在则返回-1。
*/
int if_saved_data(std::string name, mesh_data_type_e type);
/**
* @brief 获取数据对象的引用
*
* @param name 数据名称
* @param type 数据类型
* @return 数据引用
*/
meshio_data &get_data(std::string name, mesh_data_type_e type);
/**
* @brief 获取数据对象的指针
*
* @param name 数据名称
* @param type 数据类型
* @return 数据指针
*/
meshio_data *get_data_ptr(std::string name, mesh_data_type_e type);
/**
* @brief 添加一个顶点数据对象。数据将依次添加到所有顶点位置。
*
* @note 若对应名称的数据已经存在则会覆盖
*
* @param data 输入的数据数组,长度与网格所有顶点数据相同。
* @param name 新建的数据名称。
*/
void add_node_data(std::string name, const array &data);
/**
* @brief 添加一个顶点数据对象。数据将依次添加到布尔为真的顶点位置。
*
* @note 若对应名称的数据已经存在则会覆盖
*
* @param data 输入的数据数组,长度与网格所有顶点数据相同。
* @param boolen 输入的布尔,只有为真元素位置的顶点数据将被保存。
* @param name 新建的数据名称。
*/
void add_node_data(std::string name, const array &data, const array &boolen);
/**
* @brief 按单元体类型筛选创建一个单元体数据对象。数据将依次添加到所选元素位置。
*
* @note 若对应名称的数据已经存在则会覆盖
*
* @param data 输入的数据数组。
* @param name 新建数据名称。
* @param e_type 新建数据的单元体类型(缺省值为NotSet,表示选择所有有效的单元体)。
*/
void add_element_data(std::string name, const array &data, element_type_enum e_type = NotSet);
/**
* @brief 按单元体标签值筛选创建一个单元体数据对象。
*
* @note 若对应名称的数据已经存在则会追加
*
* @param data 输入的数据数组。
* @param name 新建数据名称。
* @param tag_type 标签类型。
* @param tag 标签值。
*/
void add_element_data(std::string name, const array &data, element_tag_enum tag_type, int tag);
/**
* @brief 按单元体组的名称筛选创建一个单元体数据对象。
*
* @note 若对应名称的数据已经存在则会追加
*
* @param data 输入的数据数组。
* @param name 新建数据名称。
* @param phys_name 单元体组的名称。
*/
void add_element_data(std::string name, std::string phys_name, const array &data);
/**
* @brief 按单元体组的名称筛选创建一个单元体数据对象。
*
* @note 若对应名称的数据已经存在则会追加
*
* @param phys_val 数据初始值
* @param name 新建数据名称。
* @param phys_name 单元体组的名称。
*/
void add_element_data(std::string name, std::string phys_name, double phys_val);
/**
* @brief 读入triangle软件输出的网格剖分文件。
*
* @param filename 文件名(.node和.ele文件必须在同一路径下,.neigh文件不是必须的,文件名不包含后缀名)。
* @param is_packed 输入文件的索引值是否从0开始。
*/
void read_triangle_ascii(std::string filename, index_packed_e is_packed = Packed);
/**
* @brief 读入tetgen软件输出的网格剖分文件。
*
* @param filename 文件名(.node和.ele文件必须在同一路径下,.neigh文件不是必须的,文件名不包含后缀名)。
* @param is_packed 输入文件的索引值是否从0开始。
*/
void read_tetgen_ascii(std::string filename, index_packed_e is_packed = Packed);
/**
* @brief 读入Gmsh软件输出的网格剖分文件(只支持v2.2的ASCII文件)。
*
* @param filename 文件名
* @param is_packed 输入文件的索引值是否从0开始。
*/
void read_gmsh_v2_ascii(std::string filename, index_packed_e is_packed = NotPacked);
/**
* @brief 保存Gmsh软件格式的网格剖分文件(只支持v2.2的ASCII文件)。
*
* @param filename 文件名
* @param is_packed 输入文件的索引值是否从0开始。
*/
void save_gmsh_v2_ascii(std::string filename, index_packed_e is_packed = NotPacked);
/**
* @brief 保存Paraview软件格式的网格剖分文件
*
* @param filename 文件名
*/
void save_vtk_legacy_ascii(std::string filename);
/**
* @brief 导出数据到点云文件
*
* @param filename 输出文件名
* @param dataname 数据名称
* @param out_coor 数据的坐标系(Cartesian或Spherical)
* @param refr 参考椭球的短半径(out_coor为Cartesian时无效)
* @param refR 参考椭球的长半径(out_coor为Cartesian时无效)
*/
void save_data_to_xyz(std::string filename, std::string dataname = "null", coordinate_system_e out_coor = Cartesian, double refr = GCTL_Earth_Radius, double refR = GCTL_Earth_Radius);
protected:
bool initialized_; // 类型是否已经初始化完成
// 有效的顶点、单元体和单元体组的数量
size_t valid_node_size_, valid_elem_size_, valid_group_size_;
array nodes_; // 网格顶点 当顶点索引为无效值时将不会被输出
array elems_; // 网格元素
std::vector datas_; // 网格数据
std::vector groups_; // 网格单元体组
array nodes_tag_; // 顶点标签
element_type_enum elem_gmshcode2type_[94]; // gmsh的单元体类型数组 数组索引为gmsh的单元体类型码值
element_type_enum elem_vtkcode2type_[14]; // vtk的单元体类型数组 数组索引为vtk的单元体类型码值
std::map elem_type2gmshcode_; // 单元体类型到gmsh类型码值的映射
std::map elem_type2vtkcode_; // 单元体类型到vtk类型码值的映射
std::map elem_type2size_; // 单元体类型到单元体顶点数量的映射
std::map elem_type2name_; // 单元体类型到单元体名称的映射
std::string elem_name(element_type_enum e_type); // 获取单元体名称字符串
int elem_gmsh_code(element_type_enum e_type); // 获取单元体gmsh类型码值
int elem_vtk_code(element_type_enum e_type); // 获取单元体vtk类型码值
int elem_size(element_type_enum e_type); // 获取单元体顶点数量
element_type_enum elem_gmsh_type(int code); // 获取对应gmsh类型码的单元体类型
element_type_enum elem_vtk_type(int code); // 获取对应vtk类型码的单元体类型
void update_indexing(); // 更新索引(对网格的元素进行操作后需调用)
void sort_groups(); // 对单元体组进行梳理(对网格的元素进行操作后需调用)
};
}
#endif // _GCTL_MESH_IO_H