Fade2D Examples

Access And Draw Triangulation Elements – Example2

Developing geometry software is much easier when you can visualize your work.This article shows how you can access the individual geometric objects in Fade and also how you can draw them.

Triangulation of 7 points, created by example2_main()

Have a look at the code below:

  1. The vector vPoints is filled with 6 points on a circle plus the center point (Fade conveniently provides generators for circles and for random points, segments, polygons and surfaces).
  2. Now the points are labeled with custom indices. This feature is completely optional. You can use it to create a reference between the points and your own data structures.
  3. The points are inserted. Internally, Fade keeps a copy of the points and returns pointers to them (in the same order) in vVertexHandles. Inserting all points at once is most efficient. But there is also a method to insert the points one by one.
  4. The triangles are drawn with Fade_2D::show("")
int example2_main()
	std::cout<<"\nexample2: Access elements of a triangulation\n";
	// * 1 *   Create points on a circle
	std::vector<Point2> vPoints;
	int numPoints(6);
	double centerX(5),centerY(5),radiusX(5),radiusY(5);
	generateCircle( numPoints,centerX,centerY,radiusX,radiusY,vPoints);
	vPoints.push_back(Point2(centerX,centerY)); // Add the center point
	// * 2 *   Optional step: You can add custom indices to relate
	//         the points to your own data structures. But you do
	//         not need to use this feature.
	int myStartIndex(77); // An arbitrary value
	for(size_t i=0;i<vPoints.size();++i)
	// * 3 *   Insert the vertices
	Fade_2D dt; // The Delaunay triangulation
	std::vector<Point2*> vVertexHandles; // Pointers to the vertices inside Fade
	dt.insert(vPoints,vVertexHandles); // Fastest method: insert all points at once
	// * 4 *   Draw the triangulation"");

Accessing Elements

It is also important that you can access the elements a triangulation. For example, you may want to access the neighboring triangles of a particular triangle. And you may want to create a custom visualization instead of the ready-made visualization one. So have a look at the manualDraw() function:

Manual visualization created by manualDraw() of example2
void manualDraw(Fade_2D& dt)
	// * 1 *   Create a postscript visualizer and define some colors
	Visualizer2 vis("");
	Color cBlack(CBLACK);
	Color cBlue(CBLUE);
	Color cRed(CRED);
	Color cPurple(CPURPLE);
	vis.addObject(Label(Point2(1.5,12.4),"BLACK: triangle edges",false,15),cBlack);
	vis.addObject(Label(Point2(1.5,11.6),"RED: neighbor-triangle labels",false,15),cRed);
	vis.addObject(Label(Point2(1.5,10.8),"BLUE: intra-triangle-indices",false,15),cBlue);
	vis.addObject(Label(Point2(1.5,10.0),"PURPLE: custom vertex indices",false,15),cPurple);
	// * 2 *   Get and draw the vertices with their custom index
	std::vector<Point2*> vAllPoints;
	for(std::vector<Point2*>::iterator it(vAllPoints.begin());it!=vAllPoints.end();++it)
		Point2* currentPoint(*it);
		int customIndex(currentPoint->getCustomIndex());
		std::string text(toString(customIndex));
	// * 3 *   Get and draw the triangles
	std::vector<Triangle2*> vAllDelaunayTriangles;
	for(std::vector<Triangle2*>::iterator it=vAllDelaunayTriangles.begin();it!=vAllDelaunayTriangles.end();++it)
		Triangle2* pT(*it);
	// * 4 *   Choose one triangle and color it green
	Triangle2* pT(vAllDelaunayTriangles[0]);
	Color cGreenFill(CPALEGREEN,0.001f,true);
	// * 5 *   The corners of pT can be accessed through the so called intra-
	// triangle-indices 0,1,2. They are counterclockwise oriented (CCW).
	// Let's write intra-triangle-index labels beside the corners.
	for(int intraTriangleIndex=0;intraTriangleIndex<3;++intraTriangleIndex)
		Point2* pCorner(pT->getCorner(intraTriangleIndex));
		std::string text("\nidx="+toString(intraTriangleIndex));
	// * 6 *   Each triangle has three neighbor triangles (or NULL
	// pointers at border edges). They are accessed through the
	// intra-triangle-indices. The i'th opposite triangle of pT is
	// the one that is opposite to the i'th vertex. Let's draw that:
	Label label_pT(pT->getBarycenter()," pT",true,15);
	for(int intraTriangleIndex=0;intraTriangleIndex<3;++intraTriangleIndex)
		Triangle2* pNeigT(pT->getOppositeTriangle(intraTriangleIndex));
		if(pNeigT==NULL) continue; // No adjacent triangle at this edge
		// Compute the barycenter and write a label there
		Point2 barycenter(pNeigT->getBarycenter());
		std::string text(" =pT->getOppositeTriangle("+toString(intraTriangleIndex)+")");
		Label neigLabel(barycenter,text.c_str(),true,15);
	// Write the postscript file to disk
  1. Create a postscript visualizer and a few colors
  2. Retrieve pointers to the vertices of the triangulation and draw them along with the custom index set before. Label objects are added to the Visualizer for this purpose.
  3. Retrieve pointers to the triangles and draw the triangles by adding them to the Visualizer.
  4. Choose an arbitrary triangle pT and fill it with green color
  5. The corners of pT can be accessed through the so called intra-triangle-indices {0,1,2}. These are always counterclockwise. Write the intra-triangle-indices in blue color.
  6. Each triangle pT has three pointers to its neighboring triangles (or NULL in case of border edges). The i-th neighbor triangle is always the one opposite the vertex with index i. Red labels are drawn at the barycenters of the neighbor triangles.
  7. The writeFile() method is called to finalize the postscript drawing.

More Visualization

It is unlikely that you will need it soon, but for completeness, ex2_access_draw.cpp also includes the moreDraw() function, which demonstrates additional functions of the Visualizer2 class. It’s source code for this is self-explanatory.

Postscript demo made by the moreDraw() function
void moreDraw()
	// * 1 *   Defining color
	// Define red by values (red,green,blue,linewidth,bFill)
	Color cRed(1,0,0,0.001,false);
	// Or simply use a color name and the defaults linewidth=0.001 and bFill=false
	Color cBlue(CBLUE);
	Color cGreen(CGREEN);
	Color cPurple(CPURPLE);
	// Specify a bolt green color (linewidth=1.0) and another one with
	// bFill=true to fill the area of an object which is drawn using
	// that color. In case that a segment is drawn with bFill=true,
	// marks for its endpoints are added.
	Color cGreenBolt(CGREEN,1.0,false);
	Color cGreenFill(CGREEN,.001f,true);
	// Postscript writer
	Visualizer2 vis("");
	// Create a label and add it to the Visualizer
	Label headLabel(Point2(20,60),	// Position
					"This is the Fade2D\nPostscript Visualizer",
					false,			// Don't write an x-mark
					30);			// Font size
	vis.addObject(headLabel,cRed); 	// Add the label
	// Add a row of points
	for(int x=0;x<100;x+=5)
		Point2 p(x,50);
		vis.addObject(p,cPurple); // Add the point
	// Draw a segment with cGreen
	Point2 p0(0,0);
	Point2 p1(100,0);
	Segment2 seg0(p0,p1);
	vis.addObject(seg0,cGreen); // Add the segment
	// Draw a segment with cGreenFill (with marks at the endpoints)
	Point2 p2(0,10);
	Point2 p3(100,10);
	Segment2 seg1(p2,p3);
	vis.addObject(seg1,cGreenFill); // Add the segment
	// Draw a segment with cGreenBolt
	Point2 p4(0,20);
	Point2 p5(100,20);
	Segment2 seg2(p4,p5);
	vis.addObject(seg2,cGreenBolt); // Add the segment
	// Draw labels
	Label lab0(Point2(20,2),"Segment in cGreen",false,15);
	vis.addObject(lab0,cBlue); // Add the label
	Label lab1(Point2(20,12),"Segment in cGreenFill",false,15);
	vis.addObject(lab1,cBlue); // Add the label
	Label lab2(Point2(20,22),"Segment in cGreenBolt",false,15);
	vis.addObject(lab2,cBlue); // Add the label
	// Add three circles with radius=4 (squared radius 16)
	double sqRadius(4.0*4.0);
	Circle2 circ0(50,40,sqRadius);
	Circle2 circ1(60,40,sqRadius);
	Circle2 circ2(70,40,sqRadius);
	vis.addObject(circ0,cGreen);	// Add the circle
	vis.addObject(circ1,cGreenBolt);// Add the circle
	vis.addObject(circ2,cGreenFill);// Add the circle
	// The postscript file is only written when writeFile() is called.

This is all you need to know to traverse a Fade triangulation. Make sure you fully understand this example, play around with the source code, adapt it and see what happens. Then proceed to Example3 – Constraint Edges which treats triangulation of segments.

Leave a Reply

Your email address will not be published. Required fields are marked *