# Equilateral triangular grid generator

I've implemented a equilateral triangular grid generator, with the capability to output the grid to a vtk file, it does the generation according to the answer of this post.

I am putting the code here for you to review, all the improvement and critiques are welcome. I am planing to make it run in parallel using MPI or threads. About the part of code that does the rendering, if someone could help me to make it 2D rendering and put the camera in the XY plane and center the grid, that'd will be really great.

#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <fstream>
#define vtkRenderingCore_AUTOINIT 4(vtkInteractionStyle,vtkRenderingFreeType,vtkRenderingFreeTypeOpenGL,vtkRenderingOpenGL)
#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL)
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkPolyDataWriter.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

using namespace std;

struct Node {
unsigned id;
double x,y,z;
};
typedef vector<Node> Nodes;

struct Edge {
unsigned id,i,j;
};
typedef vector<Edge> Edges;

int main(int argc, char **argv)
{
// this program is intended to generate an equilateral grid by specifying
// the number of points in both plan direction and the edge length of the
// triangles of this grid.

/* variable definition: */
Nodes grid_points;
Edges connectivity;
double edge_length = 0;
unsigned nbr_point_hor = 0, nbr_point_ver = 0;
bool show = false;
string output_file("mesh.vtk");

/* parsing command line argument */
int opt;
while((opt = getopt(argc,argv,"lhvso")) != -1){
switch(opt){
case 'l':{
edge_length = stod(string(argv[optind]));       // get the edge lenght of the equilateral triagles in the grid
}break;
case 'h':{
nbr_point_hor = stoi(string(argv[optind]));     // get the number of points in the horizontal direction
}break;
case 'v':{
nbr_point_ver = stoi(string(argv[optind]));     // get the number of points in the vertical direction
}break;
case 's':{
show = true;                    // either to show the grid or not
}break;
case 'o':{
output_file = string(argv[optind]);         // the ouput file name where the grid data will be saved
}break;
}
}

/*---------------------------------------------------- generating the grid point coordinates ---------------------------------------------------------*/

// grid point generation is done line by line starting from the bottom
for(unsigned i = 0; i < nbr_point_ver; i++)
for(unsigned j = 0; j < nbr_point_hor; j++){
Node p;
p.id = j + i*nbr_point_hor;
p.x  = j * edge_length;
p.y  = i * edge_length;
grid_points.push_back(p);
}

/*---------------------------------------------------- connectivity setting up  -----------------------------------------------------------------------*/

// the connectivity between nodes are straightforward because of the structure of the grid
// every node i is connected with i+1,i+n,i+n+1 ( --- , | , / ) assuming that n is the
// number of nodes per line.
// the last node on every line and the top line will recieve special treatement
unsigned id = 0;
for(unsigned i = 0; i < nbr_point_ver-1; i++){
for(unsigned j = 0; j < nbr_point_hor-1; j++){
Edge e;
e.i = grid_points[j+i*nbr_point_hor].id;
e.id = id++; e.j = grid_points[j+1+i*nbr_point_hor].id;      connectivity.push_back(e);
e.id = id++; e.j = grid_points[j+(i+1)*nbr_point_hor].id;    connectivity.push_back(e);
e.id = id++; e.j = grid_points[j+1+(i+1)*nbr_point_hor].id;  connectivity.push_back(e);
}
// the last point of line is treated separatly because of his connectivity pattern (connected only to the node
// that is directly above him)
Edge e;
e.id = id++;
e.i = grid_points[nbr_point_hor-1+i*nbr_point_hor].id; e.j = grid_points[nbr_point_hor-1+(i+1)*nbr_point_hor].id;
connectivity.push_back(e);
}
// the last line is treated separatly because of the connectivity pattern (nodes on this line has only one connection)
for(unsigned i = nbr_point_hor*(nbr_point_ver-1); i < grid_points.size()-1; i++){
Edge e; e.id = id++;
e.i = grid_points[i].id; e.j = grid_points[i+1].id;
connectivity.push_back(e);
}

/*---------------- applying point transformation to get an equilateral triangular grid (Thanks to Rolf Sievers (name from stackexchange)) --------------*/

vtkPoints *grid_points_vtk = vtkPoints::New();
grid_points_vtk->Allocate(grid_points.size());
for(unsigned i = 0; i < grid_points.size(); i++){
grid_points_vtk->InsertPoint(grid_points[i].id,
grid_points[i].x-0.5*grid_points[i].y,
grid_points[i].y*0.8660254038,
0);
}
vtkCellArray *edges = vtkCellArray::New();
edges->Allocate(connectivity.size());
for(unsigned i = 0; i < connectivity.size(); i++){
vtkIdType l[2];
l[0] = connectivity[i].i;
l[1] = connectivity[i].j;
edges->InsertNextCell(2, l);
}

vtkPolyData *grid = vtkPolyData::New();
grid->SetPoints(grid_points_vtk);
grid->SetLines(edges);

grid_points_vtk->Delete();
edges->Delete();

/*----------------------------- Writing to vtk file --------------------------------------------------------------------------------------------------*/

vtkPolyDataWriter *writer = vtkPolyDataWriter::New();
writer->SetFileName(output_file.c_str());
writer->SetInputData(grid);
writer->Update();
writer->Write();
writer->Delete();

/*------------------------------------------------- Show data if the show flag is set to true ----------------------------------------------------------*/
if(show){
vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
mapper->SetInputData(grid);

vtkActor *actor = vtkActor::New();
actor->SetMapper(mapper);

vtkRenderer *rendrer = vtkRenderer::New();
vtkRenderWindow *window = vtkRenderWindow::New();

vtkRenderWindowInteractor *interac = vtkRenderWindowInteractor::New();
interac->SetRenderWindow(window);

rendrer->SetBackground(0,0,0);

window->Render();
interac->Start();
}

return 0;
}


The qbs file used to compile the code:

import qbs

CppApplication {
type: "application" // To suppress bundle generation on Mac
consoleApplication: true
files: "main.cpp"

Group {     // Properties for the produced executable
fileTagsFilter: product.type
qbs.install: true
}
Depends { name: "cpp" }
cpp.cxxFlags: ["-march=core-avx2", "-mtune=core-avx2", "-O2", "-pipe", "-std=c++11"]
cpp.libraryPaths: ["/usr/lib64"]
cpp.includePaths: ["/usr/include/vtk-6.1"]
cpp.dynamicLibraries: ["vtkCommonCore-6.1", "vtkIOLegacy-6.1",
"vtkCommonDataModel-6.1", "vtkIOCore-6.1",
"vtkRenderingCore-6.1", "vtkRenderingFreeTypeOpenGL-6.1",
"vtkRenderingFreeType-6.1", "vtkRenderingOpenGL-6.1",
"vtkInteractionStyle-6.1"]
}

• Welcome to Code Review. About that part of your question : About the part of code that does the rendering, if someone could help me to make it 2D rendering and put the camera in the XY plane and center the grid, that'd will be really great. Do know that asking for a new feature to add to your code is off-topic. The rest of your question is on-topic. Form more information look at the help center. – Marc-Andre Feb 17 '15 at 16:48
• thank you for the info I will consideret in the next post. – Houssem Ghiat Feb 17 '15 at 18:02