1. Overview
This tutorial provides the basic usage of using AMCAXMeshing for triangle mesh algorithm.
1.1 Trianlge Soup
AMCAXMeshing uses triangle soup to store mesh data. Triangle soup mainly contains the coordinates of mesh points and the index information of faces, and is a template parameter that mesh algorithms rely on.
class TriSoupTraits_Coord
{
public:
using PointT = VecProxy<3, double>;
using VecT = VecProxy<3, double>;
using NormalT = VecProxy<3, double>;
using Tex3D = VecProxy<3, double>;
using Color = VecProxy<3, float>;
using Triangle = VecProxy<3, int>;
using Points = std::vector<PointT>;
using Normals = std::vector<NormalT>;
using Tex3Ds = std::vector<Tex3D>;
using Colors = std::vector<Color>;
using Triangles = std::vector<Triangle>;
};
1.2 Using namespace
For clarity in the example code, using namespace
Namespace of all interface in the AMCAX Meshing module.
Definition misc.docu:35
Namespace of all interface in the AMCAX kernel.
Definition misc.docu:8
1.3 Mesh IO
AMCAXMeshing currently provides reading and writing of commonly used mesh file formats such as obj and stl.
mesh IO header file
write "example_utils.h" to set input and output paths
#pragma once
#include <filesystem>
#include <fstream>
#include <stack>
#include <string>
#include <vector>
inline bool make_file_writable(const std::string &filename)
{
std::filesystem::path filepath(filename);
if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath))
return true;
std::filesystem::path parent_path = filepath.parent_path();
if (std::filesystem::exists(parent_path) && std::filesystem::is_directory(parent_path))
return true;
std::filesystem::create_directories(parent_path);
return false;
}
inline bool make_dir_writable(const std::string &dirname)
{
std::filesystem::path dirpath(dirname);
if (std::filesystem::exists(dirpath) && std::filesystem::is_directory(dirpath))
return true;
std::filesystem::create_directories(dirpath);
return false;
}
#define OUTPUT_DIRECTORY(TEST_SUIT_NAME, TEST_NAME) \
std::string outdir = \
"./data/test_output/" #TEST_SUIT_NAME "/" #TEST_NAME "/"; \
make_dir_writable(outdir)
2. Algorithm Examples
2.1 Mesh Simplify
#include "example_utils.h"
#include <cfloat>
#include <thread>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
void Remeshing_FastQEM()
{
OUTPUT_DIRECTORY(Remeshing,
FastQEM);
bool first = true;
int stage, current, total;
[&first, &stage, ¤t, &total](int _stage, int _current, int _total,
AMCAXMeshing_UNUSED bool &cancel) -> void
{
stage = _stage;
current = _current;
total = _total;
if (!first)
std::cout << "\r\033[K";
std::cout << "stage: " << _stage << "/"
<< FastQEM<TriSoupTraits_Coord>::Total << ", process: " << current
<< "/" << total;
first = false;
if (stage == FastQEM<TriSoupTraits_Coord>::Stage::Total)
std::cout << std::endl;
};
io_options.vertex_has_point = true;
std::string filename = "32770_sf";
obj_reader.
read(
"./data/" + filename +
".obj", io_options);
for (double ratio : {0.01, 0.1, 0.3, 0.6})
{
first = true;
std::thread simplify_thread(
[&]()
{
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio),
0.1f, 20, pro_fn);
});
simplify_thread.join();
Logger::info("FastQEM: ratio " + std::to_string(ratio) + "; time " +
std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename =
outdir + filename + "_FastQEM_" + std::to_string(ratio) + ".obj";
obj_writer.
write(out_filename, io_options, 10);
}
}
Fast QEM simplification algorithm.
static AMCAXMeshing_API void elapse_reset()
reset elapsed time.
AMCAXMeshing_NODISCARD static AMCAXMeshing_API std::chrono::duration< double > elapsed()
return the elapsed time since the last reset.
Options about pre-described properties in mesh IO.
Definition IOOptions.hpp:19
Read triangle soup from an OBJ file.
Definition OBJReader.hpp:38
Points m_points
point position
Definition OBJReader.hpp:125
Triangles m_triangles
triangle faces
Definition OBJReader.hpp:130
AMCAXMeshing_API bool read(const std::string &filename, IOOptions &opt)
Read triangle soup from the file. results will be stored in member variables of reader,...
Write triangle soup to an OBJ file.
Definition OBJWriter.hpp:38
AMCAXMeshing_API void clear()
Clear data stored in writer.
Triangles m_triangles
triangle faces
Definition OBJWriter.hpp:131
AMCAXMeshing_API bool write(const std::string &filename, IOOptions &opt, std::streamsize precision)
Write triangle soup to file with given options and precison.
Points m_points
point position
Definition OBJWriter.hpp:126
Implement a fast QEM simplification algorithm based on triangle soup.
Definition TriSoup_FastQEM.hpp:32
std::function< void(int stage, int current, int total, bool &cancel)> ProFn
function that reports process
Definition TriSoup_FastQEM.hpp:87
Click here example1 to get the complete source code for the above example, which you can download according to your learning needs.
2.2 Mesh Boolean
#include "example_utils.h"
using EIAC = AMCAX::Meshing::Geometry::EIAC;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
using Points = typename TriSoupTraits::Points;
using Triangles = typename TriSoupTraits::Triangles;
void read_mesh(const std::string &filename, Points &points,
)
{
if (AMCAX::Meshing::ends_with(filename, ".obj"))
{
reader.
read(filename, io_options);
}
else if (AMCAX::Meshing::ends_with(filename, ".stl"))
{
reader.
read(filename, io_options);
}
}
void write_mesh(const std::string &filename, const Points &points,
const Triangles &triangles,
IOOptions &io_options)
{
writer.
write(filename, io_options, 10);
};
void MeshBoolean_MeshBoolean()
{
OUTPUT_DIRECTORY(Boolean, Boolean);
io_options.vertex_has_point = true;
Points points1, points2, result_points;
Triangles triangles1, triangles2, result_triangles;
read_mesh("./data/boolean_data/bunny25k.obj", points1, triangles1, io_options);
read_mesh("./data/boolean_data/cow.obj", points2, triangles2, io_options);
MeshBoolean boolean(true);
boolean.addTriMeshAsInput(points1, triangles1);
boolean.addTriMeshAsInput(points2, triangles2);
boolean.setTriMeshAsOutput(result_points, result_triangles);
boolean.computeLabels();
{
boolean.Union();
make_file_writable(outdir + "AMCAXMeshing_Union.obj");
write_mesh(outdir + "AMCAXMeshing_Union.obj", result_points,
result_triangles, io_options);
}
{
boolean.Intersection();
make_file_writable(outdir + "AMCAXMeshing_Intersection.obj");
write_mesh(outdir + "AMCAXMeshing_Intersection.obj", result_points,
result_triangles, io_options);
}
{
boolean.Xor();
make_file_writable(outdir + "AMCAXMeshing_Xor.obj");
write_mesh(outdir + "AMCAXMeshing_Xor.obj", result_points, result_triangles,
io_options);
}
{
boolean.Subtraction();
make_file_writable(outdir + "AMCAXMeshing_Subtraction.obj");
write_mesh(outdir + "AMCAXMeshing_Subtraction.obj", result_points,
result_triangles, io_options);
}
}
reader triangle soup from STL file.
This file implement writer for STL file.
Repair triangle mesh to clean mesh.
Definition MeshBoolean.hpp:48
Read triangle soup from an STL file.
Definition STLReader.hpp:33
AMCAXMeshing_API bool read(const std::string &filename, IOOptions &opt)
Read triangle soup from the file.
Points m_points
vertex position
Definition STLReader.hpp:67
Triangles m_triangles
triangles
Definition STLReader.hpp:68
Write mesh to an STL file.
Definition STLWriter.hpp:33
Click here example2 to get the complete source code for the above example, which you can download according to your learning needs.
2.3 Mesh Repair
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::MeshTools;
void MeshRepair_MeshRepair()
{
OUTPUT_DIRECTORY(MeshRepair, MeshRepair);
bool first = true;
int stage;
[&first, &stage](int _stage, AMCAXMeshing_UNUSED bool &cancel) -> void
{
stage = _stage;
if (!first)
std::cout << "\r\033[K";
std::cout
<< "stage: " << _stage << "/"
<< AMCAX::Meshing::MeshTools::TriMeshRepair<TriSoupTraits_Coord>::Total;
first = false;
TriSoupTraits_Coord>::Stage::Total)
std::cout << std::endl;
};
io_options.vertex_has_point = true;
io_options.face_has_normal = true;
std::string modelname = "CamelBox";
TriSoupTraits_Coord::Points result_points;
TriSoupTraits_Coord::Triangles result_triangles;
stl_reader.
read(
"./data/repair_data/" + modelname +
".stl", io_options);
repair.repair(true, pro_fn);
make_file_writable(outdir + modelname + "_repaired.stl");
io_options.stl_binary = true;
stl_writer.
write(outdir + modelname +
"_repaired.stl", io_options, 10);
make_file_writable(outdir + modelname + "_repaired.obj");
obj_writer.
write(outdir + modelname +
"_repaired.obj", io_options, 10);
}
Interfaces of mesh arrangements.
Triangles m_triangles
triangles
Definition STLWriter.hpp:90
AMCAXMeshing_API bool write(const std::string &filename, IOOptions &opt, std::streamsize precision=6)
Write mesh to file with given options and precison.
Points m_points
vertex position
Definition STLWriter.hpp:89
Click here example3 to get the complete source code for the above example, which you can download according to your learning needs.
2.4 Mesh Subdivision
2.4.1 ButterFly Subdivision
#include "example_utils.h"
#include <cfloat>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Subdivision;
using namespace AMCAX::Meshing::Remeshing;
void Subdivision_TriSoup_ButterFly()
{
OUTPUT_DIRECTORY(Subdivision, TriSoup_ButterFly);
io_options.vertex_has_point = true;
std::string filename = "kelan";
obj_reader.
read(
"./data/subdivision_data/" + filename +
".obj", io_options);
for (double ratio : {2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.})
{
size_t sub_times = size_t(std::ceil(ratio / 4.0) + 0.1);
for (size_t i = 0; i < sub_times; i++)
subdivider.subdivide();
std::move(subdivider.m_triangles));
fast_qem.m_triangles.size() * 0.01) <
fast_qem.m_triangles.size())
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio), FLT_MAX,
20);
Logger::info("ButterFly: ratio " + std::to_string(ratio) + "; time " +
std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename = outdir + filename +
"_TriSoupModifiedButterFly_" +
std::to_string(ratio) + ".obj";
make_file_writable(out_filename);
obj_writer.
write(out_filename, io_options, 10);
}
}
Implement ButterFly subdivision algorithm.
Modified butterfly subdivision for triangle mesh. Interpolating subdivision for meshes with arbitrary...
Definition TriSoup_ButterFlySubdivision.hpp:35
Click here example4 to get the complete source code for the above example, which you can download according to your learning needs.
2.4.2 Loop Subdivision
#include "example_utils.h"
#include <cfloat>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
using namespace AMCAX::Meshing::Subdivision;
void Subdivision_TriSoup_LoopSubdivision()
{
io_options.vertex_has_point = true;
std::string filename = "kelan";
obj_reader.
read(
"./data/subdivision_data/" + filename +
".obj", io_options);
for (double ratio : {2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.})
{
size_t sub_times = size_t(std::ceil(ratio / 4.0) + 0.1);
for (size_t i = 0; i < sub_times; i++)
subdivider.subdivide();
std::move(subdivider.m_triangles));
fast_qem.m_triangles.size() * 0.01) <
fast_qem.m_triangles.size())
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio), FLT_MAX,
12);
Logger::info("Loop: ratio " + std::to_string(ratio) + "; time " +
std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename =
outdir + filename + "_TriSoupLoopSub_" + std::to_string(ratio) + ".obj";
make_file_writable(out_filename);
obj_writer.
write(out_filename, io_options, 10);
}
}
Implement loop subdivision algorithm.
Loop subdivision for triangle mesh.
Definition TriSoup_LoopSubdivision.hpp:78
Click here example5 to get the complete source code for the above example, which you can download according to your learning needs.
2.5 Remeshing
2.5.1 Incremental Remeshing
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
void incremental_remesh_test()
{
std::string inputfilename = "./data/remesh_data/filename_1.obj";
io_options.vertex_has_point = true;
TriSoupTraits::Points input_points, output_points;
TriSoupTraits::Triangles input_triangles, output_triangles;
reader.
read(inputfilename, io_options);
input_points = std::move(reader.
m_points);
output_points = input_points;
output_triangles = input_triangles;
params.featurePreserved = true;
params.isAdaptive = true;
params.iterNum = 10;
params.Max_error = 0.0005;
params.targetEdgeLength = 0.1;
params.tolAngle = 30. / 180. * M_PI;
std::string outputfilename =
"./data/" + std::to_string(params.iterNum) + ".obj";
writer.
m_points = std::move(output_points);
writer.
write(outputfilename, io_options, 15);
}
Interfaces of triMesh incremental remeshing.
Definition TriMesh_IncrementalRemeshing.hpp:24
AMCAXMeshing_API void setReferenceMesh(const iPoints &points, const iTriangles &triangles)
add a triangle mesh (triangle soup) as one input.
AMCAXMeshing_API void setVariableMesh(iPoints &points, iTriangles &triangles)
Set the triangle mesh (triangle soup) as output destination.
AMCAXMeshing_API void remesh(Params params)
Adaptive/Isotropic remeshing controled by the control parameters.
the parameters that control the remeshing
Definition TriMesh_IncrementalRemeshing.hpp:40
Click here example6 to get the complete source code for the above example, which you can download according to your learning needs.
2.6 Mesh parameterisation algorithm
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
void Parameterization_Bijective()
{
OUTPUT_DIRECTORY(Parameterization, Bijective);
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/parameterization_data/cow.obj", io_options);
para.parameterization();
std::string out_filename = outdir + "res_parameterization.obj";
obj_writer.
write(out_filename, io_options, 10);
}
Bijective parameterization algorithm.
Definition MeshParameterization.hpp:23
Click here example7 to get the complete source code for the above example, which you can download according to your learning needs.
2.7 Mesh Cutting Algorithm
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
using Points = typename TriSoupTraits::Points;
using Triangles = typename TriSoupTraits::Triangles;
void Parameterization_With_MeshCut()
{
OUTPUT_DIRECTORY(Parameterization, Bijective_With_MeshCut);
io_options.vertex_has_point = true;
std::string in_filename = "./data/boolean_data/bunny25k.obj";
std::string out_cut_filename = outdir + "bunny_cut.obj";
std::string out_para_filename = outdir + "bunny_parameterization.obj";
obj_reader.
read(in_filename, io_options);
Points i_points = std::move(obj_reader.
m_points);
Triangles i_triangles = std::move(obj_reader.
m_triangles);
i_points, i_triangles, true);
Points cut_points;
Triangles cut_triangles;
mesh_cut.cut(cut_points, cut_triangles);
obj_writer.
write(out_cut_filename, io_options, 10);
Points para_points;
cut_points, cut_triangles, para_points, true);
para.parameterization();
obj_writer.
m_points = std::move(para_points);
obj_writer.
write(out_para_filename, io_options, 10);
}
Greedy cut algorithm for triangle mesh.
Definition TriMeshCut.hpp:24
Click here example8 to get the complete source code for the above example, which you can download according to your learning needs.