A frequently asked question is how to export a triangulation as a list of points and indices. Up to now this could be done with the help of custom indices and it still works. But since Fade v1.84 there is an explicit solution for this task, which is also memory efficient, because it releases the data structures within Fade while it builds the index data structure FadeExport. This way, no memory usage peaks occur during the data export.
The FadeExport struct
FadeExport
is a fairly simple struct with a few methods for convenient usage and also for demonstration purposes. It is intentionally implemented entirely in the header so that you can adapt the code for your project.
struct FadeExport { void print() const; bool writeObj(const char* filename) const; void extractTriangleNeighborships(std::vector<std::pair<int,int> >& vNeigs) const; void getCornerIndices(int triIdx,int& vtxIdx0,int& vtxIdx1,int& vtxIdx2) const; void getCoordinates(int vtxIdx,double& x,double& y) const; // DATA double* aCoords; ///< Cartesian coordinates (dim*numPoints) int* aCustomIndices; ///< Custom indices of the points (only when exported) int* aTriangles; ///< 3 counterclockwise oriented vertex-indices per triangle (3*numTriangles) };
Data Export from Fade
- We create some points. But the order in which we will pass these points to Fade is not the same as the order in which we will get them back. Therefore we can optionally use
Point2::setCustomIndex()
to set our own indices in the points. - Insert the points into a Fade_2D object
- Use
Fade_2D::exportTriangulation()
to store the geometry data from in aFadeExport
struct. You can specify whether you also want to export the custom indices and whether you want to release theFade_2D
object bit by bit during the export. The latter is especially useful for large data, because otherwise the data would be duplicated in memory for a short time until theFade_2D
object can be deleted.
For demonstration purposes only, that is, to show you how to access the data in the FadeExport struct, the following code prints and draws the data.
- We iterate over the vertex indices and obtain the
x,y
coordinates (orx,y,z
in the 2.5D case). They are stored inFadeExport::aCoords
and you can access them via indices or conveniently via thegetCoordinates(vtxIdx,x,y)
method. - We output the triangles and draw them. For this purpose we determine the three vertex-indices per triangle-index and for each vertex-index we determine the associated coordinates. We could access the data structures directly for this purpose, but we spare ourselves the index calculation and use the
getCornerIndices()
andgetCoordinates()
methods for convenience. - The information which triangle is adjacent to which one does not occupy any additional memory in the
FadeExport
struct. If your data structure needs this information, it can be quickly determined in O(n*log(n)) time from the other stored data. TheextractTriangleNeighborships()
method is available for this purpose.
// * 1 * Create some points std::vector<Point2> vPoints; generateCircle(6,25.0,25.0,10.0,10.0,vPoints); for(size_t i=0;i<vPoints.size();++i) { // Optional: Set an arbitrary custom index vPoints[i].setCustomIndex(int(i)); } // * 2 * Triangulate Fade_2D dt; dt.insert(vPoints); // * 3 * Export (clears the Fade object) FadeExport fadeExport; bool bCustomIndices(true); // To retrieve custom indices also bool bClear(true); // Clear memory in $dt dt.exportTriangulation(fadeExport,bCustomIndices,bClear); ////////////////////////////////////////////////////// // The Fade object has been cleared to avoid memory // // peaks. Now verify if we have received all data...// ////////////////////////////////////////////////////// // * 4 * Vertex output Visualizer2 visExp("example8_exported.ps"); for(int vtxIdx=0;vtxIdx<fadeExport.numPoints;++vtxIdx) { double x,y; fadeExport.getCoordinates(vtxIdx,x,y); std::string s(" "+toString(vtxIdx)); // Are there custom indices? Then add if(fadeExport.numCustomIndices==fadeExport.numPoints) { int customIdx(fadeExport.aCustomIndices[vtxIdx]); s.append("(customIdx="+toString(customIdx)+")"); } std::cout<<"Vertex"<<s<<": "<<x<<" "<<y<<std::endl; Label label(Point2(x,y),s.c_str(),true,15); visExp.addObject(label,Color(CRED)); } // * 5 * Triangle output for(int triIdx=0;triIdx<fadeExport.numTriangles;++triIdx) { int vtxIdx0,vtxIdx1,vtxIdx2; fadeExport.getCornerIndices(triIdx,vtxIdx0,vtxIdx1,vtxIdx2); std::cout<<"Triangle "<<triIdx<<": "<<vtxIdx0<<" "<<vtxIdx1<<" "<<vtxIdx2<<std::endl; // Fetch also the coordinates and draw the edges double x0,y0; double x1,y1; double x2,y2; fadeExport.getCoordinates(vtxIdx0,x0,y0); fadeExport.getCoordinates(vtxIdx1,x1,y1); fadeExport.getCoordinates(vtxIdx2,x2,y2); Point2 p0(x0,y0); Point2 p1(x1,y1); Point2 p2(x2,y2); visExp.addObject(Segment2(p0,p1),Color(CBLACK)); visExp.addObject(Segment2(p1,p2),Color(CBLACK)); visExp.addObject(Segment2(p2,p0),Color(CBLACK)); double midX((x0+x1+x2)/3.0); double midY((y0+y1+y2)/3.0); std::string text("T"+toString(triIdx)); Label l(Point2(midX,midY),text.c_str(),true,15); visExp.addObject(l,Color(CBLUE)); } // * 6 * Neighbors output std::vector<std::pair<int,int> > vNeigs; fadeExport.extractTriangleNeighborships(vNeigs); for(size_t i=0;i<vNeigs.size();++i) { std::cout<<"Triangle "<<vNeigs[i].first<<" <-> Triangle "<<vNeigs[i].second<<std::endl; } visExp.writeFile(); // Write the postscript file // The above is for demonstration purposes, the easier way // to output FadeExport data is using its print() or writeObj() // function: //fadeExport.print(); //fadeExport.writeObj("out.obj"); return 0;
The output of example8 is:

Vertex 0(customIdx=4): 20 16.3398
Vertex 1(customIdx=3): 15 25
Vertex 2(customIdx=2): 20 33.6603
Vertex 3(customIdx=1): 30 33.6602
Vertex 4(customIdx=0): 35 25
Vertex 5(customIdx=5): 30 16.3397
Triangle 0: 0 2 1
Triangle 1: 3 2 0
Triangle 2: 5 3 0
Triangle 3: 5 4 3
Triangle 0 <-> Triangle 1
Triangle 1 <-> Triangle 2
Triangle 2 <-> Triangle 3
2 replies on “Exporting a Triangulation – Example 8”
Has the custom indices option any drawback like decreased performance?
No. The index field belongs to the point class anyway and exporting them is fast, you will not notice any difference.