Overview
This tutorial provides a series of repair methods for addressing geometric issues in a helicopter model. By utilizing GeomE's API, we perform geometric editing operations to fix the model.
Namespaces
For code clarity, we use the following namespaces:
Namespace of all interface in the AMCAX GeomE module.
Definition misc.docu:21
Namespace of all interface in the AMCAX kernel.
Definition misc.docu:8
helicopter model Issues
The current helicopter model exhibits several problems including fragmented surfaces and gap holes as shown below:
Fragmented faces
Two fragmented faces exist beneath the wings (highlighted areas).
Gap Holes
Several gap holes appear at the nose and tail sections (marked in red).
Repair Methods
Helper Functions
To maintain clean code structure and focus on core logic, we've encapsulated common operations:
bool readtopo(
TopoShape& s,
const string& mfile)
{
if (!std::filesystem::exists(mfile)) {
cout << "File not found!" << endl;
return false;
}
string suffix = mfile.substr(mfile.find_last_of('.') + 1);
std::transform(suffix.begin(), suffix.end(), suffix.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (suffix == "stp" || suffix == "step") {
}
else if (suffix == "brep") {
}
else {
std::cout << "Unsupported file format!" << endl;
return false;
}
}
bool writetopo(
const TopoShape& s,
const string& outfile)
{
string suffix = outfile.substr(outfile.find_last_of('.') + 1);
transform(suffix.begin(), suffix.end(), suffix.begin(), [](unsigned char c) {
return tolower(c);
});
if (suffix == "stp" || suffix == "step")
else if (suffix == "brep")
else {
cout << "Unsupported output file format: " << suffix << endl;
return false;
}
}
Base class of shape, containing an underlying shape with a location and an orientation.
Definition TopoShape.hpp:15
Face Merging
The fuselage contains fragmented faces on both left and right sides, which we merge using:
{
FaceEditor faceEditor;
{
set.insert(edges[111 - 1]);
set.insert(edges[109 - 1]);
set.insert(edges[28 - 1]);
set.insert(edges[27 - 1]);
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[18 - 1]));
setdown.
insert(edges[114 - 1]);
setdown.
insert(edges[115 - 1]);
setdown.
insert(edges[116 - 1]);
setdown.
insert(edges[35 - 1]);
faceEditor.BuildFaceFromSurface(shape, setdown,
TopoCast::Face(faces[18 - 1]));
}
{
set.insert(edges[138 - 1]);
set.insert(edges[61 - 1]);
set.insert(edges[60 - 1]);
set.insert(edges[135 - 1]);
set.insert(edges[190 - 1]);
set.insert(edges[137 - 1]);
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[25 - 1]));
setdown.
insert(edges[130 - 1]);
setdown.
insert(edges[131 - 1]);
setdown.
insert(edges[132 - 1]);
setdown.
insert(edges[53 - 1]);
faceEditor.BuildFaceFromSurface(shape, setdown,
TopoCast::Face(faces[25 - 1]));
}
writetopo(result, "combineFaces.brep");
return result;
}
Template class of indexed set.
Definition IndexSet.hpp:20
int insert(T &&key)
Insert a new key.
Definition IndexSet.hpp:117
static AMCAX_API const TopoFace & Face(const TopoShape &s)
Cast shape to face.
Results showing merged faces:
In the above code, index references like faces[17 - 1] are obtained through FreeCAD software, representing topological object indices. The inspection method is as follows:
- Install FreeCAD software
- Import the model file
- Click on topological objects
- View the indices in the left panel as shown:
Important Note: After model modification, original object indices will change. To obtain target object indices again, you must re-query based on the latest modified model - never reuse indices from the initial model.
Gap Stitching
After face merging, we stitch the gaps:
void sewEdges(
TopoShape& shape,
const string& filePath,
int e1,
int e2,
double tolerance)
{
cout << "Applying auto fix (tolerance = " << tolerance << ") to file: " << filePath << endl;
try {
EdgeEditor editor;
editor.SewEdges(shape, edge1, edge2, tolerance);
}
catch (const exception& e) {
cout << "Auto fix failed for file " << filePath << ". Exception: " << e.what() << endl;
return;
}
filesystem::path p(filePath);
string stem = p.stem().string();
string extension = p.extension().string();
extension = ".step";
string outFile = (p.parent_path() / (stem + "_autosew" + extension)).string();
if (writetopo(shape, outFile))
cout << "Auto fix succeeded, output saved to: " << outFile << endl;
else
cout << "Failed to write output file: " << outFile << endl;
cout << "success auto fix" << endl;
}
sewEdges(shape, "./combineFaces.step", 187 - 1, 247 - 1, 0.007);
static AMCAX_API const TopoEdge & Edge(const TopoShape &s)
Cast shape to edge.
Class of edge.
Definition TopoEdge.hpp:12
The result is shown in the following figure, demonstrating that the gap formed by the two edges has been successfully repaired.
Hole Patching
Constructs new extended surfaces to fill slender triangular voids at the cockpit window area.
{
set.insert(edges[16 - 1]);
set.insert(edges[88 - 1]);
FaceEditor faceEditor;
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[3 - 1]));
writetopo(result, "fillhole_with_newface.step");
return result;
}
The results shown in the figures below demonstrate successful elimination of the slender triangular void.
Click here example04 to get the full source code of the helicopter model repair and enhancement example. Everyone can download it as needed.
Appendix
#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
bool readtopo(
TopoShape& s,
const string& mfile)
{
if (!std::filesystem::exists(mfile)) {
cout << "File not found!" << endl;
return false;
}
string suffix = mfile.substr(mfile.find_last_of('.') + 1);
std::transform(suffix.begin(), suffix.end(), suffix.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (suffix == "stp" || suffix == "step") {
}
else if (suffix == "brep") {
}
else {
std::cout << "Unsupported file format!" << endl;
return false;
}
}
bool writetopo(
const TopoShape& s,
const string& outfile)
{
string suffix = outfile.substr(outfile.find_last_of('.') + 1);
transform(suffix.begin(), suffix.end(), suffix.begin(), [](unsigned char c) {
return tolower(c);
});
if (suffix == "stp" || suffix == "step")
else if (suffix == "brep")
else {
cout << "Unsupported output file format: " << suffix << endl;
return false;
}
}
{
FaceEditor faceEditor;
{
set.insert(edges[111 - 1]);
set.insert(edges[109 - 1]);
set.insert(edges[28 - 1]);
set.insert(edges[27 - 1]);
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[18 - 1]));
setdown.
insert(edges[114 - 1]);
setdown.
insert(edges[115 - 1]);
setdown.
insert(edges[116 - 1]);
setdown.
insert(edges[35 - 1]);
faceEditor.BuildFaceFromSurface(shape, setdown,
TopoCast::Face(faces[18 - 1]));
}
{
set.insert(edges[138 - 1]);
set.insert(edges[61 - 1]);
set.insert(edges[60 - 1]);
set.insert(edges[135 - 1]);
set.insert(edges[190 - 1]);
set.insert(edges[137 - 1]);
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[25 - 1]));
setdown.
insert(edges[130 - 1]);
setdown.
insert(edges[131 - 1]);
setdown.
insert(edges[132 - 1]);
setdown.
insert(edges[53 - 1]);
faceEditor.BuildFaceFromSurface(shape, setdown,
TopoCast::Face(faces[25 - 1]));
}
writetopo(result, "combineFaces.brep");
return result;
}
void sewEdges(
TopoShape& shape,
const string& filePath,
int e1,
int e2,
double tolerance)
{
cout << "Applying auto fix (tolerance = " << tolerance << ") to file: " << filePath << endl;
try {
EdgeEditor editor;
editor.SewEdges(shape, edge1, edge2, tolerance);
}
catch (const exception& e) {
cout <<
"Auto fix failed for file " << filePath <<
". Exception: " <<
e.what() << endl;
return;
}
filesystem::path p(filePath);
string stem = p.stem().string();
string extension = p.extension().string();
extension = ".step";
string outFile = (p.parent_path() / (stem + "_autosew" + extension)).string();
if (writetopo(shape, outFile))
cout << "Auto fix succeeded, output saved to: " << outFile << endl;
else
cout << "Failed to write output file: " << outFile << endl;
cout << "success auto fix" << endl;
}
{
set.insert(edges[16 - 1]);
set.insert(edges[88 - 1]);
FaceEditor faceEditor;
faceEditor.BuildFaceFromSurface(shape, set,
TopoCast::Face(faces[3 - 1]));
writetopo(result, "fillhole_with_newface.step");
return result;
}
int main(int argc, char* argv[])
{
try {
std::cout << "start work" << endl;
readtopo(shape, "./data/helicopter-2025.stp");
shape = combineFaces(shape);
sewEdges(shape, "./combineFaces.step", 187 - 1, 247 - 1, 0.007);
shape = fillhole_with_newface(shape);
writetopo(shape, "./outshape.brep");
}
catch (const std::exception& e) {
std::cout <<
"Sorry, there was an exception: " <<
e.what() << endl;
}
catch (...) {
std::cout << "Unknown exception" << endl;
}
return 0;
}
The class of removing feature faces from the shape.
constexpr double e
Base of natural logarithm (also known as Napier's constant / Euler's number)
Definition Constants.hpp:18