diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index 4566857..7f3d7b2 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -32,4 +32,5 @@ add_example(process_ex OFF)
add_example(array_ex OFF)
add_example(gmt_ex OFF)
add_example(gnuplot_ex OFF)
-add_example(stl_io_ex OFF)
\ No newline at end of file
+add_example(stl_io_ex OFF)
+add_example(ply_io_ex ON)
\ No newline at end of file
diff --git a/example/ply_io_ex.cpp b/example/ply_io_ex.cpp
new file mode 100644
index 0000000..d402110
--- /dev/null
+++ b/example/ply_io_ex.cpp
@@ -0,0 +1,44 @@
+/********************************************************
+ * ██████╗ ██████╗████████╗██╗
+ * ██╔════╝ ██╔════╝╚══██╔══╝██║
+ * ██║ ███╗██║ ██║ ██║
+ * ██║ ██║██║ ██║ ██║
+ * ╚██████╔╝╚██████╗ ██║ ███████╗
+ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
+ * 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.
+ ******************************************************/
+
+ #include "../lib/core.h"
+ #include "../lib/io.h"
+
+ using namespace gctl;
+
+ int main(int argc, char const *argv[]) try
+ {
+ array nodes;
+ array tris;
+ read_ply_binary("tmp_binary", nodes, tris);
+ save_ply_ascii("tmp", nodes, tris);
+ return 0;
+ }
+ catch(std::exception &e)
+ {
+ GCTL_ShowWhatError(e.what(), GCTL_ERROR_ERROR, 0, 0, 0);
+ }
\ No newline at end of file
diff --git a/lib/io.h b/lib/io.h
index 40b9e7b..cc994aa 100644
--- a/lib/io.h
+++ b/lib/io.h
@@ -39,5 +39,6 @@
#include "io/triangle_io.h"
#include "io/off_io.h"
#include "io/stl_io.h"
+#include "io/ply_io.h"
#endif // _GCTL_IO_H
\ No newline at end of file
diff --git a/lib/io/off_io.h b/lib/io/off_io.h
index 6d6d4b9..b9cb56f 100644
--- a/lib/io/off_io.h
+++ b/lib/io/off_io.h
@@ -36,7 +36,7 @@
namespace gctl
{
template
- void read_Geomview_off(std::string filename, array> &nodes,
+ void read_off_acsii(std::string filename, array> &nodes,
array> &facets)
{
std::ifstream infile;
@@ -120,7 +120,7 @@ namespace gctl
}
template
- void save_Geomview_off(std::string filename, const array> &nodes,
+ void save_off_ascii(std::string filename, const array> &nodes,
const array> &facets)
{
std::ofstream outfile;
diff --git a/lib/io/ply_io.h b/lib/io/ply_io.h
new file mode 100644
index 0000000..be70d0c
--- /dev/null
+++ b/lib/io/ply_io.h
@@ -0,0 +1,216 @@
+/********************************************************
+ * ██████╗ ██████╗████████╗██╗
+ * ██╔════╝ ██╔════╝╚══██╔══╝██║
+ * ██║ ███╗██║ ██║ ██║
+ * ██║ ██║██║ ██║ ██║
+ * ╚██████╔╝╚██████╗ ██║ ███████╗
+ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
+ * 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_PLY_IO_H
+#define _GCTL_PLY_IO_H
+
+// library's head file
+#include "../core.h"
+#include "../utility.h"
+#include "../geometry.h"
+
+namespace gctl
+{
+ template
+ void read_ply_ascii(std::string filename, array> &nodes,
+ array> &facets)
+ {
+ std::ifstream infile;
+ open_infile(infile, filename, ".ply");
+
+ int n, f;
+ std::string line;
+ std::stringstream ss;
+ while (std::getline(infile, line))
+ {
+ if (sscanf(line.c_str(), "element vertex %d", &n)==1) nodes.resize(n);
+ if (sscanf(line.c_str(), "element face %d", &f)==1) facets.resize(f);
+ if (line == "end_header")
+ {
+ if (nodes.empty() || facets.empty())
+ {
+ infile.close();
+ throw std::runtime_error("[gctl::read_ply_ascii] Invalid node or facet sizes.");
+ }
+
+ for (size_t i = 0; i < nodes.size(); ++i)
+ {
+ std::getline(infile, line);
+ sscanf(line.c_str(), "%lf %lf %lf", &nodes[i].x, &nodes[i].y, &nodes[i].z);
+ nodes[i].id = i;
+ }
+
+ for (size_t i = 0; i < facets.size(); ++i)
+ {
+ std::getline(infile, line);
+ int d, v1, v2, v3;
+ sscanf(line.c_str(), "%d %d %d %d", &d, &v1, &v2, &v3);
+ facets[i].vert[0] = &nodes[v1];
+ facets[i].vert[1] = &nodes[v2];
+ facets[i].vert[2] = &nodes[v3];
+ facets[i].id = i;
+ }
+ break;
+ }
+ }
+
+ infile.close();
+ return;
+ }
+
+ template
+ void save_ply_ascii(std::string filename, const array> &nodes,
+ const array> &facets)
+ {
+ time_t now = time(0);
+ char* dt = ctime(&now);
+
+ std::ofstream outfile;
+ open_outfile(outfile, filename, ".ply");
+
+ outfile << "ply" << std::endl;
+ outfile << "format ascii 1.0" << std::endl;
+ outfile << "comment Created by GCTL at " << dt;
+ outfile << "element vertex " << nodes.size() << std::endl;
+ outfile << "property float x" << std::endl;
+ outfile << "property float y" << std::endl;
+ outfile << "property float z" << std::endl;
+ outfile << "element face " << facets.size() << std::endl;
+ outfile << "property list uchar int vertex_indices" << std::endl;
+ outfile << "end_header" << std::endl;
+
+ for (size_t i = 0; i < nodes.size(); ++i)
+ {
+ outfile << nodes[i].x << " " << nodes[i].y << " " << nodes[i].z << std::endl;
+ }
+
+ for (size_t i = 0; i < facets.size(); ++i)
+ {
+ outfile << "3 " << facets[i].vert[0]->id << " " << facets[i].vert[1]->id << " " << facets[i].vert[2]->id << std::endl;
+ }
+ outfile.close();
+ return;
+ }
+
+ template
+ void read_ply_binary(std::string filename, array> &nodes,
+ array> &facets)
+ {
+ std::ifstream infile;
+ open_infile(infile, filename, ".ply", std::ios::binary);
+
+ int n, f;
+ std::string line;
+ std::stringstream ss;
+ while (std::getline(infile, line))
+ {
+ if (sscanf(line.c_str(), "element vertex %d", &n)==1) nodes.resize(n);
+ if (sscanf(line.c_str(), "element face %d", &f)==1) facets.resize(f);
+ if (line == "end_header")
+ {
+ if (nodes.empty() || facets.empty())
+ {
+ infile.close();
+ throw std::runtime_error("[gctl::read_ply_ascii] Invalid node or facet sizes.");
+ }
+
+ float x, y, z;
+ for (size_t i = 0; i < nodes.size(); ++i)
+ {
+ infile.read((char*)&x, sizeof(float));
+ infile.read((char*)&y, sizeof(float));
+ infile.read((char*)&z, sizeof(float));
+ nodes[i].x = x;
+ nodes[i].y = y;
+ nodes[i].z = z;
+ nodes[i].id = i;
+ }
+
+ unsigned char num_vertices;
+ int v1, v2, v3;
+ for (size_t i = 0; i < facets.size(); ++i)
+ {
+ infile.read((char*)&num_vertices, sizeof(unsigned char));
+ infile.read((char*)&v1, sizeof(int));
+ infile.read((char*)&v2, sizeof(int));
+ infile.read((char*)&v3, sizeof(int));
+ facets[i].vert[0] = &nodes[v1];
+ facets[i].vert[1] = &nodes[v2];
+ facets[i].vert[2] = &nodes[v3];
+ facets[i].id = i;
+ }
+ break;
+ }
+ }
+
+ infile.close();
+ return;
+ }
+
+ template
+ void save_ply_binary(std::string filename, const array> &nodes,
+ const array> &facets)
+ {
+ std::ofstream outfile;
+ open_outfile(outfile, filename, ".ply", std::ios::binary);
+
+ outfile << "ply\n"
+ << "format binary_little_endian 1.0\n"
+ << "comment Created by GCTL\n"
+ << "element vertex " << nodes.size() << "\n"
+ << "property float x\n"
+ << "property float y\n"
+ << "property float z\n"
+ << "element face " << facets.size() << "\n"
+ << "property list uchar int vertex_indices\n"
+ << "end_header\n";
+
+ float x, y, z;
+ for (size_t i = 0; i < nodes.size(); ++i)
+ {
+ x = nodes[i].x;
+ y = nodes[i].y;
+ z = nodes[i].z;
+ outfile.write((char*)&x, sizeof(float));
+ outfile.write((char*)&y, sizeof(float));
+ outfile.write((char*)&z, sizeof(float));
+ }
+
+ unsigned char num_vertices = 3;
+ for (size_t i = 0; i < facets.size(); ++i)
+ {
+ outfile.write((char*)&num_vertices, sizeof(unsigned char));
+ outfile.write((char*)&facets[i].vert[0]->id, sizeof(int));
+ outfile.write((char*)&facets[i].vert[1]->id, sizeof(int));
+ outfile.write((char*)&facets[i].vert[2]->id, sizeof(int));
+ }
+ outfile.close();
+ return;
+ }
+};
+
+#endif // _GCTL_PLY_IO_H
\ No newline at end of file