gctl/lib/io/triangle_io.h
2025-04-23 12:39:44 +08:00

1278 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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 <http://www.gnu.org/licenses/>.
*
* 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_TRIANGLE_IO_H
#define _GCTL_TRIANGLE_IO_H
// library's head file
#include "../core/matrix.h"
#include "../poly/triangle2d.h"
#include "../poly/triangle2d2o.h"
#include "../poly/edge2d.h"
#include "file_io.h"
namespace gctl
{
/**
* @brief Read Triangle's .node file into a 2D vertex array.
* (从 Triangle 程序的 .node 文件读入二维顶点数组)
*
* First line: <# of vertices> <dimension (must be 2)> <# of attributes> <# of boundary markers (0 or 1)>
* Remaining lines: <vertex #> <x> <y> [attributes] [boundary marker]
* Blank lines and comments prefixed by `#' may be placed anywhere. Vertices must be numbered consecutively, starting from one or zero.
* The attributes, which are typically floating-point values of physical quantities
* (such as mass or conductivity) associated with the nodes of a finite element mesh,
* are copied unchanged to the output mesh. If -q, -a, -u, or -s is selected,
* each new Steiner point added to the mesh will have quantities assigned to it by linear interpolation.
* If the fourth entry of the first line is `1', the last column of the remainder of the file is
* assumed to contain boundary markers. Boundary markers are used to identify boundary vertices
* and vertices resting on PSLG segments. The .node files produced by Triangle contain boundary
* markers in the last column unless they are suppressed by the -B switch.
*
* @param[in] filename Input filename without any extensions.(文件名,无后缀)
* @param out_node Output 2D vertex array. Returned by quote.(返回的二维顶点数组)
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed..node 文件中顶点序号从 0 开始则为真,为 1 则为假)
* @param marker If the pointer is not null. Return an int array of vertexs' marker.(指针不为空时返回一个包含顶点标记的整形数组)
* @param attri If the pointer is not null. Return a 2D integer array that contains
* attributes of the vertice.(指针不为空时返回一个二维数组,表示对应点的属性值)
*/
template <typename A>
void read_Triangle_node(std::string filename, array<vertex<point2dc, A>> &out_node, index_packed_e packed = Packed,
array<int> *marker = nullptr, _2d_matrix *attri = nullptr)
{
std::ifstream tetin;
open_infile(tetin, filename, ".node");
std::string err_str, tmp_str;
std::stringstream tmp_ss;
int node_size = 0, node_dimen = 2, attri_num = 0, boundary_mark = 0;
// read head info
do
{
std::getline(tetin, tmp_str);
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> node_size >> node_dimen >> attri_num >> boundary_mark;
if (tmp_ss.fail() || node_dimen != 2 ||
(boundary_mark != 0 && boundary_mark != 1) ||
attri_num < 0)
{
err_str = "Wrong head-info found in " + filename +
".node. From void gctl::read_Triangle_node(...)";
throw runtime_error(err_str);
}
}
}
while (tmp_str[0] == '#');
if (attri_num != 0 && attri != nullptr)
{
attri->resize(node_size, attri_num);
}
//else if (attri_num == 0 && attri != nullptr)
//{
// err_str = "No attributes found in " + filename +
// ".node. From void gctl::read_Triangle_node(...)";
// throw runtime_error(err_str);
//}
if (boundary_mark != 0 && marker != nullptr)
{
marker->resize(node_size);
}
//else if (boundary_mark == 0 && marker != nullptr)
//{
// err_str = "No markers found in " + filename +
// ".node. From void gctl::read_Triangle_node(...)";
// throw runtime_error(err_str);
//}
vertex<point2dc, A> tmp_vert;
out_node.resize(node_size);
if (boundary_mark+attri_num)
{
array<double> attri_line(boundary_mark+attri_num);
_2d_matrix tmp_attri(node_size, boundary_mark+attri_num);
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_vert.id >> tmp_vert.x >> tmp_vert.y;
for (int a = 0; a < boundary_mark+attri_num; a++)
tmp_ss >> attri_line[a];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".node. From void gctl::read_Triangle_node(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked) tmp_vert.id -= 1;
out_node[tmp_vert.id] = tmp_vert;
for (int a = 0; a < boundary_mark+attri_num; a++)
tmp_attri[tmp_vert.id][a] = attri_line[a];
}
}
if (attri != nullptr && attri_num)
{
for (int i = 0; i < node_size; i++)
{
for (int a = 0; a < attri_num; a++)
{
attri->at(i, a) = tmp_attri[i][a];
}
}
}
if (marker != nullptr && boundary_mark)
{
for (int i = 0; i < node_size; i++)
{
marker->at(i) = (int) tmp_attri[i][attri_num];
}
}
}
else
{
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_vert.id >> tmp_vert.x >> tmp_vert.y;
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".node. From void gctl::read_Triangle_node(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked) tmp_vert.id -= 1;
out_node[tmp_vert.id] = tmp_vert;
}
}
}
tetin.close();
return;
}
/**
* @brief Read Triangle's .ele file into a 2D triangle array.
*
* First line: <# of triangles> <nodes per triangle> <# of attributes>
* Remaining lines: <triangle #> <node> <node> <node> ... [attributes]
* Blank lines and comments prefixed by `#' may be placed anywhere. Triangles must be numbered
* consecutively, starting from one or zero. Nodes are indices into the corresponding .node file.
* The first three nodes are the corner vertices, and are listed in counterclockwise order
* around each triangle. (The remaining nodes, if any, depend on the type of finite element used.)
* As in .node files, the attributes are typically floating-point values of physical quantities
* (such as mass or conductivity) associated with the elements (triangles) of a finite element mesh.
* Because there is no simple mapping from input to output triangles, an attempt is made to
* interpolate attributes, which may result in a good deal of diffusion of attributes among nearby
* triangles as the triangulation is refined. Attributes do not diffuse across segments,
* so attributes used to identify segment-bounded regions remain intact.
* In output .ele files, all triangles have three nodes each unless the -o2 switch is used, in
* which case subparametric quadratic elements with six nodes are generated. The fourth, fifth,
* and sixth nodes lie on the midpoints of the edges opposite the first, second, and third vertices.
*
* @param out_tri Output 2D triangle array. Returned by quote.
* @param[in] filename Input filename without any extensions.
* @param[in] in_node 2D vertex array which contains vertex's information of the triangles.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param attri If the pointer is not null. Return a 2D integer array that contains
* attributes of the vertice.
*/
template <typename E, typename A>
void read_Triangle_element(std::string filename, array<type_triangle2d<E>> &out_tri,
const array<vertex<point2dc, A>> &in_node, index_packed_e packed = Packed,
_2d_matrix *attri = nullptr)
{
std::ifstream tetin;
open_infile(tetin, filename, ".ele");
std::string err_str, tmp_str;
std::stringstream tmp_ss;
int ele_size = 0, node_per_ele = 0, attri_num = 0;
// read head info
do
{
std::getline(tetin, tmp_str);
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> ele_size >> node_per_ele >> attri_num;
if (tmp_ss.fail() || node_per_ele != 3 || attri_num < 0)
{
err_str = "Wrong head-info found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
}
}
while (tmp_str[0] == '#');
if (attri_num != 0 && attri != nullptr)
{
attri->resize(ele_size, attri_num);
}
//else if (attri_num == 0 && attri != nullptr)
//{
// err_str = "No attributes found in " + filename +
// ".ele. From void gctl::read_Triangle_element(...)";
// throw runtime_error(err_str);
//}
int tmp_int, tmp_order[3];
out_tri.resize(ele_size);
if (attri_num)
{
array<double> attri_line(attri_num);
_2d_matrix tmp_attri(ele_size, attri_num);
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_order[2];
for (int a = 0; a < attri_num; a++)
tmp_ss >> attri_line[a];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 3; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 3; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
for (int a = 0; a < attri_num; a++)
tmp_attri[tmp_int][a] = attri_line[a];
}
}
if (attri != nullptr)
{
for (int i = 0; i < ele_size; i++)
{
for (int a = 0; a < attri_num; a++)
{
attri->at(i, a) = tmp_attri[i][a];
}
}
}
}
else
{
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_order[2];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 3; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 3; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
}
}
}
tetin.close();
return;
}
/**
* @brief Read Triangle's .ele file into a second order 2D triangle array.
*
* First line: <# of triangles> <nodes per triangle> <# of attributes>
* Remaining lines: <triangle #> <node> <node> <node> ... [attributes]
* Blank lines and comments prefixed by `#' may be placed anywhere. Triangles must be numbered
* consecutively, starting from one or zero. Nodes are indices into the corresponding .node file.
* The first three nodes are the corner vertices, and are listed in counterclockwise order
* around each triangle. (The remaining nodes, if any, depend on the type of finite element used.)
* As in .node files, the attributes are typically floating-point values of physical quantities
* (such as mass or conductivity) associated with the elements (triangles) of a finite element mesh.
* Because there is no simple mapping from input to output triangles, an attempt is made to
* interpolate attributes, which may result in a good deal of diffusion of attributes among nearby
* triangles as the triangulation is refined. Attributes do not diffuse across segments,
* so attributes used to identify segment-bounded regions remain intact.
* In output .ele files, all triangles have three nodes each unless the -o2 switch is used, in
* which case subparametric quadratic elements with six nodes are generated. The fourth, fifth,
* and sixth nodes lie on the midpoints of the edges opposite the first, second, and third vertices.
*
* @param out_tri Output 2D triangle array. Returned by quote.
* @param[in] filename Input filename without any extensions.
* @param[in] in_node 2D vertex array which contains vertex's information of the triangles.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param attri If the pointer is not null. Return a 2D integer array that contains
* attributes of the vertice.
*/
template <typename E, typename A>
void read_Triangle_element(std::string filename, array<type_triangle2d2o<E>> &out_tri,
const array<vertex<point2dc, A>> &in_node, index_packed_e packed = Packed,
_2d_matrix *attri = nullptr)
{
std::ifstream tetin;
open_infile(tetin, filename, ".ele");
std::string err_str, tmp_str;
std::stringstream tmp_ss;
int ele_size = 0, node_per_ele = 0, attri_num = 0;
// read head info
do
{
std::getline(tetin, tmp_str);
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> ele_size >> node_per_ele >> attri_num;
if (tmp_ss.fail() || node_per_ele != 6 || attri_num < 0)
{
err_str = "Wrong head-info found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
}
}
while (tmp_str[0] == '#');
if (attri_num != 0 && attri != nullptr)
{
attri->resize(ele_size, attri_num);
}
else if (attri_num == 0 && attri != nullptr)
{
err_str = "No attributes found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
int tmp_int, tmp_order[6];
out_tri.resize(ele_size);
if (attri_num)
{
array<double> attri_line(attri_num);
_2d_matrix tmp_attri(ele_size, attri_num);
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_order[2]
>> tmp_order[3] >> tmp_order[4] >> tmp_order[5];
for (int a = 0; a < attri_num; a++)
tmp_ss >> attri_line[a];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 6; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 6; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
for (int a = 0; a < attri_num; a++)
tmp_attri[tmp_int][a] = attri_line[a];
}
}
if (attri != nullptr)
{
for (int i = 0; i < ele_size; i++)
{
for (int a = 0; a < attri_num; a++)
{
attri->at(i, a) = tmp_attri[i][a];
}
}
}
}
else
{
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_order[2]
>> tmp_order[3] >> tmp_order[4] >> tmp_order[5];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".ele. From void gctl::read_Triangle_element(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 6; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_tri[tmp_int].id = tmp_int;
for (int j = 0; j < 6; j++)
{
out_tri[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
}
}
}
tetin.close();
return;
}
/**
* @brief Read Triangle's .neigh file into an existing 2D triangle array.
*
* First line: <# of triangles> <# of neighbors per triangle (always 3)>
* Following lines: <triangle #> <neighbor> <neighbor> <neighbor>
* Blank lines and comments prefixed by `#' may be placed anywhere. Triangles are numbered
* consecutively, starting from one or zero. Neighbors are indices into the corresponding .ele file.
* An index of -1 indicates no neighbor (because the triangle is on an exterior boundary).
* The first neighbor of triangle i is opposite the first corner of triangle i, and so on.
* Triangle can produce .neigh files (use the -n switch), but cannot read them.
*
* @param out_tri Output 2D triangle array. Returned by quote. This array must be
* initialized before calling this function.
* @param[in] filename Input filename without any extensions.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
*/
template <typename A>
void read_Triangle_neighbor(std::string filename, array<type_triangle2d<A>> &out_tri, index_packed_e packed = Packed)
{
std::ifstream tetin;
open_infile(tetin, filename, ".neigh");
std::string err_str, tmp_str;
std::stringstream tmp_ss;
int ele_size, neigh_pre_ele;
// read head info
do
{
std::getline(tetin, tmp_str);
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> ele_size >> neigh_pre_ele;
if (tmp_ss.fail() || neigh_pre_ele != 3 || ele_size != out_tri.size())
{
err_str = "Wrong head-info found in " + filename +
".neigh. From void gctl::read_Triangle_neighbor(...)";
throw runtime_error(err_str);
}
}
}
while (tmp_str[0] == '#');
int tmp_int, tmp_order[3];
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_order[2];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".neigh. From void gctl::read_Triangle_neighbor(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
for (int j = 0; j < 3; j++)
{
if (tmp_order[j] > 0)
{
out_tri[tmp_int].neigh[j] = out_tri.get(tmp_order[j]-1);
}
}
}
else
{
for (int j = 0; j < 3; j++)
{
if (tmp_order[j] >= 0)
{
out_tri[tmp_int].neigh[j] = out_tri.get(tmp_order[j]);
}
}
}
}
}
tetin.close();
return;
}
/**
* @brief Read Triangle's .edge file into an 2D edge array.
*
* First line: <# of edges> <# of boundary markers (0 or 1)>
* Following lines: <edge #> <endpoint> <endpoint> [boundary marker]
* Blank lines and comments prefixed by `#' may be placed anywhere. Edges are numbered consecutively,
* starting from one or zero. Endpoints are indices into the corresponding .node file.
* Triangle can produce .edge files (use the -e switch), but cannot read them. The optional
* column of boundary markers is suppressed by the -B switch.
* In Voronoi diagrams, one also finds a special kind of edge that is an infinite ray with only
* one endpoint. For these edges, a different format is used:
* <edge #> <endpoint> -1 <direction x> <direction y>
* The `direction' is a floating-point vector that indicates the direction of the infinite ray.
*
* @param out_edge Output 2D edge array. Returned by quote.
* @param[in] filename Input filename without any extensions.
* @param[in] in_node 2D vertex array which contains vertex's information of the edges.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param marker If the pointer is not null. Return a int array of the vertice's marker
*/
template <typename E, typename A>
void read_Triangle_edge(std::string filename, array<type_edge2d<E>> &out_edge,
const array<vertex<point2dc, A>> &in_node, index_packed_e packed = Packed,
array<int> *marker = nullptr)
{
std::ifstream tetin;
open_infile(tetin, filename, ".edge");
std::string err_str, tmp_str;
std::stringstream tmp_ss;
int edge_size = 0, boundary_mark = 0;
// read head info
do
{
std::getline(tetin, tmp_str);
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> edge_size >> boundary_mark;
if (tmp_ss.fail() || (boundary_mark != 0 && boundary_mark != 1))
{
err_str = "Wrong head-info found in " + filename +
".edge. From void gctl::read_Triangle_edge(...)";
throw runtime_error(err_str);
}
}
}
while (tmp_str[0] == '#');
if (boundary_mark != 0 && marker != nullptr)
{
marker->resize(edge_size);
}
else if (boundary_mark == 0 && marker != nullptr)
{
err_str = "No boundary marks found in " + filename +
".edge. From void gctl::read_Triangle_edge(...)";
throw runtime_error(err_str);
}
int tmp_int, tmp_mark, tmp_order[2];
out_edge.resize(edge_size);
if (boundary_mark)
{
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1] >> tmp_mark;
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".edge. From void gctl::read_Triangle_edge(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_edge[tmp_int].id = tmp_int;
for (int j = 0; j < 2; j++)
{
out_edge[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_edge[tmp_int].id = tmp_int;
for (int j = 0; j < 2; j++)
{
out_edge[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
marker->at(tmp_int) = tmp_mark;
}
}
}
else
{
while (std::getline(tetin, tmp_str))
{
if (tmp_str[0] != '#')
{
str2ss(tmp_str, tmp_ss);
tmp_ss >> tmp_int >> tmp_order[0] >> tmp_order[1];
if (tmp_ss.fail())
{
err_str = "Wrong file format found in " + filename +
".edge. From void gctl::read_Triangle_edge(...)";
throw runtime_error(err_str);
}
if (packed == NotPacked)
{
tmp_int -= 1;
out_edge[tmp_int].id = tmp_int;
for (int j = 0; j < 2; j++)
{
out_edge[tmp_int].vert[j] = in_node.get(tmp_order[j]-1);
}
}
else
{
out_edge[tmp_int].id = tmp_int;
for (int j = 0; j < 2; j++)
{
out_edge[tmp_int].vert[j] = in_node.get(tmp_order[j]);
}
}
}
}
}
tetin.close();
return;
}
/**
* @brief Saves a Triangle node file.
*
* @param[in] filename Save name
* @param[in] out_node Output 2D vertice
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param[in] marker If the pointer is not null. Write a int array of the vertice's marker
* @param attri If the pointer is not null. Write a 2D integer array that contains
* attributes of the vertice.
*/
template <typename A>
void save_Triangle_node(std::string filename, const array<vertex<point2dc, A>> &out_node,
index_packed_e packed = Packed, const array<int> *marker = nullptr, const _2d_matrix *attri = nullptr)
{
std::ofstream triout;
open_outfile(triout, filename, ".node");
std::string err_str;
int attri_num = 0, boundary_mark = 0;
if (marker != nullptr)
{
boundary_mark = 1;
if (out_node.size() != marker->size())
{
err_str = "Size of the boundary marks does not match. From void gctl::save_Triangle_node(...)";
throw runtime_error(err_str);
}
}
if (attri != nullptr)
{
attri_num = attri->col_size();
if (out_node.size() != attri->row_size())
{
err_str = "Size of the attributes do not match. From void gctl::save_Triangle_node(...)";
throw runtime_error(err_str);
}
}
time_t now = time(0);
char *dt = ctime(&now);
triout << "# generated by the GCTL package on " << dt;
triout << "# node_num node_dimension attri_num boundary_mark" << std::endl;
triout << out_node.size() << " 2 " << attri_num << " " << boundary_mark << std::endl;
triout << "# node_index x y attributes mark" << std::endl;
if (attri != nullptr && marker != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y;
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << " " << marker->at(i) << std::endl;
}
}
else
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i+1 << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y;
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << " " << marker->at(i) << std::endl;
}
}
}
else if (attri != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y;
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i+1 << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y;
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
}
else if (marker != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y << " " << marker->at(i) << std::endl;
}
}
else
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i+1 << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y << " " << marker->at(i) << std::endl;
}
}
}
else
{
if (packed == Packed)
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y << std::endl;
}
}
else
{
for (int i = 0; i < out_node.size(); i++)
{
triout << i+1 << " " << std::setprecision(16) << out_node[i].x << " "
<< out_node[i].y << std::endl;
}
}
}
triout.close();
return;
}
/**
* @brief Saves a Triangle element file.
*
* @param[in] filename Save name.
* @param[in] out_tri Output 2D triangles.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param attri If the pointer is not null. Write a 2D integer array that contains
* attributes of the vertice.
*/
template <typename A>
void save_Triangle_element(std::string filename, const array<type_triangle2d<A>> &out_tri,
index_packed_e packed = Packed, const _2d_matrix *attri = nullptr)
{
std::ofstream triout;
open_outfile(triout, filename, ".ele");
std::string err_str;
int attri_num = 0;
if (attri != nullptr)
{
attri_num = attri->col_size();
if (out_tri.size() != attri->row_size())
{
err_str = "Size of the attributes do not match. From void gctl::save_Triangle_element(...)";
throw runtime_error(err_str);
}
}
time_t now = time(0);
char *dt = ctime(&now);
triout << "# generated by the GCTL package on " << dt;
triout << "# element_num index_num attri_num" << std::endl;
triout << out_tri.size() << " 3 " << attri_num << std::endl;
triout << "# element_index node_index attributes" << std::endl;
if (attri != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i;
for (int j = 0; j < 3; j++)
{
triout << " " << out_tri[i].vert[j]->id;
}
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 3; j++)
{
triout << " " << out_tri[i].vert[j]->id + 1;
}
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
}
else
{
if (packed == Packed)
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i;
for (int j = 0; j < 3; j++)
{
triout << " " << out_tri[i].vert[j]->id;
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 3; j++)
{
triout << " " << out_tri[i].vert[j]->id + 1;
}
triout << std::endl;
}
}
}
triout.close();
return;
}
/**
* @brief Saves a Triangle element file.
*
* @param[in] filename Save name.
* @param[in] out_tri Output 2D triangles.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param attri If the pointer is not null. Write a 2D integer array that contains
* attributes of the vertice.
*/
template <typename A>
void save_Triangle_element(std::string filename, const array<type_triangle2d2o<A>> &out_tri,
index_packed_e packed = Packed, const _2d_matrix *attri = nullptr)
{
std::ofstream triout;
open_outfile(triout, filename, ".ele");
std::string err_str;
int attri_num = 0;
if (attri != nullptr)
{
attri_num = attri->col_size();
if (out_tri.size() != attri->row_size())
{
err_str = "Size of the attributes do not match. From void gctl::save_Triangle_element(...)";
throw runtime_error(err_str);
}
}
time_t now = time(0);
char *dt = ctime(&now);
triout << "# generated by the GCTL package on " << dt;
triout << "# element_num index_num attri_num" << std::endl;
triout << out_tri.size() << " 6 " << attri_num << std::endl;
triout << "# element_index node_index attributes" << std::endl;
if (attri != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i;
for (int j = 0; j < 6; j++)
{
triout << " " << out_tri[i].vert[j]->id;
}
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 6; j++)
{
triout << " " << out_tri[i].vert[j]->id + 1;
}
for (int j = 0; j < attri_num; j++)
{
triout << " " << attri->at(i, j);
}
triout << std::endl;
}
}
}
else
{
if (packed == Packed)
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i;
for (int j = 0; j < 6; j++)
{
triout << " " << out_tri[i].vert[j]->id;
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 6; j++)
{
triout << " " << out_tri[i].vert[j]->id + 1;
}
triout << std::endl;
}
}
}
triout.close();
return;
}
/**
* @brief Saves a Triangle neighbor file.
*
* @param[in] filename Save name.
* @param[in] out_tri Output 2D triangles.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
*/
template <typename A>
void save_Triangle_neighbor(std::string filename, const array<type_triangle2d<A>> &out_tri,
index_packed_e packed = Packed)
{
std::ofstream triout;
open_outfile(triout, filename, ".neigh");
time_t now = time(0);
char *dt = ctime(&now);
triout << "# generated by the GCTL package on " << dt;
triout << "# element_num index_num" << std::endl;
triout << out_tri.size() << " 3" << std::endl;
triout << "# element_index element_index" << std::endl;
if (packed == Packed)
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i;
for (int j = 0; j < 3; j++)
{
if (out_tri[i].neigh[j] != nullptr)
triout << " " << out_tri[i].neigh[j]->id;
else triout << " -1";
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_tri.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 3; j++)
{
if (out_tri[i].neigh[j] != nullptr)
triout << " " << out_tri[i].neigh[j]->id + 1;
else triout << " -1";
}
triout << std::endl;
}
}
triout.close();
return;
}
/**
* @brief Saves a Triangle edge file.
*
* @param[in] filename Save name.
* @param[in] out_edge Output 2D edges.
* @param[in] packed Indicates whether the starting index of edges is zero or not. The
* edge's ordering is assumed to be start with one if this option is set to NotPacked.
* The default value is Packed.
* @param bound_mark If the pointer is not null. Write a int array of the vertice's marker
*/
template <typename A>
void save_Triangle_edge(std::string filename, const array<type_edge2d<A>> &out_edge,
index_packed_e packed = Packed, const array<int> *marker = nullptr)
{
std::ofstream triout;
open_outfile(triout, filename, ".edge");
std::string err_str;
int boundary_mark = 0;
if (marker != nullptr)
{
boundary_mark = 1;
if (out_edge.size() != marker->size())
{
err_str = "Size of the boundary marks does not match. From void gctl::save_Triangle_edge(...)";
throw runtime_error(err_str);
}
}
time_t now = time(0);
char *dt = ctime(&now);
triout << "# generated by the GCTL package on " << dt;
triout << "# edge_num index_num" << std::endl;
triout << out_edge.size() << " " << boundary_mark << std::endl;
triout << "# edge_index node_index boundary_mark" << std::endl;
if (marker != nullptr)
{
if (packed == Packed)
{
for (int i = 0; i < out_edge.size(); i++)
{
triout << i;
for (int j = 0; j < 2; j++)
{
triout << " " << out_edge[i].vert[j]->id;
}
triout << " " << marker->at(i) << std::endl;
}
}
else
{
for (int i = 0; i < out_edge.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 2; j++)
{
triout << " " << out_edge[i].vert[j]->id + 1;
}
triout << " " << marker->at(i) << std::endl;
}
}
}
else
{
if (packed == Packed)
{
for (int i = 0; i < out_edge.size(); i++)
{
triout << i;
for (int j = 0; j < 2; j++)
{
triout << " " << out_edge[i].vert[j]->id;
}
triout << std::endl;
}
}
else
{
for (int i = 0; i < out_edge.size(); i++)
{
triout << i + 1;
for (int j = 0; j < 2; j++)
{
triout << " " << out_edge[i].vert[j]->id + 1;
}
triout << std::endl;
}
}
}
triout.close();
return;
}
};
#endif //_GCTL_TRIANGLE_H