Improve testbed data file format

Data file format now has optional sections for holes polylines
and Steiner points identified with tokens "HOLE" and "STEINER".

Rework the data file dude.dat accordingly.

Add data file steiner.dat for an example with Steiner points.
This commit is contained in:
Pierre Dejoue 2020-11-11 22:04:39 +01:00
parent cf5f95d4e9
commit 8388a74a9f
3 changed files with 157 additions and 104 deletions

View File

@ -92,3 +92,15 @@
251.07143 621.11218 251.07143 621.11218
250.53571 649.1479 250.53571 649.1479
268.1955 654.36208 268.1955 654.36208
HOLE
325 437
320 423
329 413
332 423
HOLE
320.72342 480
338.90617 465.96863
347.99754 480.61584
329.8148 510.41534
339.91632 480.11077
334.86556 478.09046

9
testbed/data/steiner.dat Normal file
View File

@ -0,0 +1,9 @@
0 0
10 0
10 10
0 10
STEINER
2 2
8 2
8 8
2 8

View File

@ -33,12 +33,15 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <algorithm> #include <algorithm>
#include <cassert>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <exception>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <list> #include <list>
#include <numeric>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
@ -46,6 +49,12 @@
using namespace std; using namespace std;
using namespace p2t; using namespace p2t;
bool ParseFile(string filename, vector<Point*>& out_polyline, vector<vector<Point*>>& out_holes,
vector<Point*>& out_steiner);
void GenerateRandomPointDistribution(size_t num_points, double min, double max,
vector<Point*>& out_polyline,
vector<vector<Point*>>& out_holes,
vector<Point*>& out_steiner);
void Init(); void Init();
void ShutDown(int return_code); void ShutDown(int return_code);
void MainLoop(const double zoom); void MainLoop(const double zoom);
@ -56,10 +65,6 @@ double StringToDouble(const std::string& s);
double Random(double (*fun)(double), double xmin, double xmax); double Random(double (*fun)(double), double xmin, double xmax);
double Fun(double x); double Fun(double x);
/// Dude hole examples
vector<Point*> CreateHeadHole();
vector<Point*> CreateChestHole();
double rotate_y = 0.0, double rotate_y = 0.0,
rotate_z = 0.0; rotate_z = 0.0;
const double rotations_per_tick = 0.2; const double rotations_per_tick = 0.2;
@ -74,7 +79,9 @@ vector<Triangle*> triangles;
/// Triangle map /// Triangle map
list<Triangle*> map; list<Triangle*> map;
/// Polylines /// Polylines
vector< vector<Point*> > polylines; vector<Point*> polyline;
vector<vector<Point*>> holes;
vector<Point*> steiner;
/// Draw the entire triangle map? /// Draw the entire triangle map?
bool draw_map = false; bool draw_map = false;
@ -83,17 +90,17 @@ bool random_distribution = false;
GLFWwindow* window = NULL; GLFWwindow* window = NULL;
template <class C> void FreeClear( C & cntr ) { template <class C> void FreeClear(C& cntr)
for ( typename C::iterator it = cntr.begin(); {
it != cntr.end(); ++it ) { for (typename C::iterator it = cntr.begin(); it != cntr.end(); ++it) {
delete * it; delete *it;
} }
cntr.clear(); cntr.clear();
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
string filename;
size_t num_points = 0u; size_t num_points = 0u;
double max, min; double max, min;
double zoom; double zoom;
@ -105,58 +112,30 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
if(string(argv[1]) == "random") { if (string(argv[1]) == "random") {
num_points = atoi(argv[2]); num_points = atoi(argv[2]);
random_distribution = true; random_distribution = true;
char* pEnd; char* pEnd;
max = strtod(argv[3], &pEnd); max = strtod(argv[3], &pEnd);
min = -max; min = -max;
cx = cy = 0; cx = cy = 0.0;
zoom = atof(argv[4]); zoom = atof(argv[4]);
} else { } else {
zoom = atof(argv[4]); filename = string(argv[1]);
cx = atof(argv[2]); cx = atof(argv[2]);
cy = atof(argv[3]); cy = atof(argv[3]);
zoom = atof(argv[4]);
} }
vector<p2t::Point*> polyline; if (random_distribution) {
GenerateRandomPointDistribution(num_points, min, max, polyline, holes, steiner);
if(random_distribution) {
// Create a simple bounding box
polyline.push_back(new Point(min,min));
polyline.push_back(new Point(min,max));
polyline.push_back(new Point(max,max));
polyline.push_back(new Point(max,min));
} else { } else {
// Load pointset from file // Load pointset from file
if (!ParseFile(filename, polyline, holes, steiner)) {
// Parse and tokenize data file return 2;
string line;
ifstream myfile(argv[1]);
if (myfile.is_open()) {
while (!myfile.eof()) {
getline(myfile, line);
if (line.size() == 0) {
break;
}
istringstream iss(line);
vector<string> tokens;
copy(istream_iterator<string>(iss), istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
double x = StringToDouble(tokens[0]);
double y = StringToDouble(tokens[1]);
polyline.push_back(new Point(x, y));
num_points++;
}
myfile.close();
} else {
cout << "File not opened" << endl;
} }
} }
cout << "Number of constrained edges = " << polyline.size() << endl;
polylines.push_back(polyline);
Init(); Init();
/* /*
@ -173,29 +152,14 @@ int main(int argc, char* argv[])
CDT* cdt = new CDT(polyline); CDT* cdt = new CDT(polyline);
/* /*
* STEP 2: Add holes or Steiner points if necessary * STEP 2: Add holes or Steiner points
*/ */
for (const auto& hole : holes) {
string s(argv[1]); assert(!hole.empty());
if(s.find("dude.dat", 0) != string::npos) { cdt->AddHole(hole);
// Add head hole
vector<Point*> head_hole = CreateHeadHole();
num_points += head_hole.size();
cdt->AddHole(head_hole);
// Add chest hole
vector<Point*> chest_hole = CreateChestHole();
num_points += chest_hole.size();
cdt->AddHole(chest_hole);
polylines.push_back(head_hole);
polylines.push_back(chest_hole);
} else if (random_distribution) {
max-=(1e-4);
min+=(1e-4);
for(int i = 0; i < num_points; i++) {
double x = Random(Fun, min, max);
double y = Random(Fun, min, max);
cdt->AddPoint(new Point(x, y));
} }
for (const auto& s : steiner) {
cdt->AddPoint(s);
} }
/* /*
@ -207,27 +171,115 @@ int main(int argc, char* argv[])
triangles = cdt->GetTriangles(); triangles = cdt->GetTriangles();
map = cdt->GetMap(); map = cdt->GetMap();
const size_t points_in_holes =
std::accumulate(holes.cbegin(), holes.cend(), size_t(0),
[](size_t cumul, const vector<Point*>& hole) { return cumul + hole.size(); });
cout << "Number of points = " << num_points << endl; cout << "Number of primary constrained edges = " << polyline.size() << endl;
cout << "Number of holes = " << holes.size() << endl;
cout << "Number of constrained edges in holes = " << points_in_holes << endl;
cout << "Number of Steiner points = " << steiner.size() << endl;
cout << "Total number of points = " << (polyline.size() + points_in_holes + steiner.size())
<< endl;
cout << "Number of triangles = " << triangles.size() << endl; cout << "Number of triangles = " << triangles.size() << endl;
cout << "Elapsed time (ms) = " << dt*1000.0 << endl; cout << "Elapsed time (ms) = " << dt * 1000.0 << endl;
MainLoop(zoom); MainLoop(zoom);
// Cleanup // Cleanup
delete cdt; delete cdt;
FreeClear(polyline);
// Free points for (vector<Point*>& hole : holes) {
for(int i = 0; i < polylines.size(); i++) { FreeClear(hole);
vector<Point*> poly = polylines[i];
FreeClear(poly);
} }
FreeClear(steiner);
ShutDown(0); ShutDown(0);
return 0; return 0;
} }
bool ParseFile(string filename, vector<Point*>& out_polyline, vector<vector<Point*>>& out_holes,
vector<Point*>& out_steiner)
{
enum ParserState {
Polyline,
Hole,
Steiner,
};
ParserState state = Polyline;
vector<Point*>* hole = nullptr;
try {
string line;
ifstream myfile(filename);
if (myfile.is_open()) {
while (!myfile.eof()) {
getline(myfile, line);
if (line.empty()) {
break;
}
istringstream iss(line);
vector<string> tokens;
copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(tokens));
if (tokens.empty()) {
break;
} else if (tokens.size() == 1u) {
const auto token = tokens[0];
if (token == "HOLE") {
state = Hole;
out_holes.emplace_back();
hole = &out_holes.back();
} else if (token == "STEINER") {
state = Steiner;
} else {
throw runtime_error("Invalid token [" + token + "]");
}
} else {
double x = StringToDouble(tokens[0]);
double y = StringToDouble(tokens[1]);
switch (state) {
case Polyline:
out_polyline.push_back(new Point(x, y));
break;
case Hole:
assert(hole != nullptr);
hole->push_back(new Point(x, y));
break;
case Steiner:
out_steiner.push_back(new Point(x, y));
break;
default:
assert(0);
}
}
}
} else {
throw runtime_error("File not opened");
}
} catch (exception& e) {
cerr << "Error parsing file: " << e.what() << endl;
return false;
}
return true;
}
void GenerateRandomPointDistribution(size_t num_points, double min, double max,
vector<Point*>& out_polyline,
vector<vector<Point*>>& out_holes, vector<Point*>& out_steiner)
{
out_polyline.push_back(new Point(min, min));
out_polyline.push_back(new Point(min, max));
out_polyline.push_back(new Point(max, max));
out_polyline.push_back(new Point(max, min));
max -= (1e-4);
min += (1e-4);
for (int i = 0; i < num_points; i++) {
double x = Random(Fun, min, max);
double y = Random(Fun, min, max);
out_steiner.push_back(new Point(x, y));
}
}
void Init() void Init()
{ {
const int window_width = 800, const int window_width = 800,
@ -342,8 +394,13 @@ void Draw(const double zoom)
// green // green
glColor3f(0, 1, 0); glColor3f(0, 1, 0);
vector<vector<Point*>*> polylines;
polylines.push_back(&polyline);
for (vector<Point*>& hole : holes) {
polylines.push_back(&hole);
}
for(int i = 0; i < polylines.size(); i++) { for(int i = 0; i < polylines.size(); i++) {
vector<Point*> poly = polylines[i]; const vector<Point*>& poly = *polylines[i];
glBegin(GL_LINE_LOOP); glBegin(GL_LINE_LOOP);
for(int j = 0; j < poly.size(); j++) { for(int j = 0; j < poly.size(); j++) {
glVertex2d(poly[j]->x, poly[j]->y); glVertex2d(poly[j]->x, poly[j]->y);
@ -397,31 +454,6 @@ void ConstrainedColor(bool constrain)
} }
} }
vector<Point*> CreateHeadHole() {
vector<Point*> head_hole;
head_hole.push_back(new Point(325, 437));
head_hole.push_back(new Point(320, 423));
head_hole.push_back(new Point(329, 413));
head_hole.push_back(new Point(332, 423));
return head_hole;
}
vector<Point*> CreateChestHole() {
vector<Point*> chest_hole;
chest_hole.push_back(new Point(320.72342,480));
chest_hole.push_back(new Point(338.90617,465.96863));
chest_hole.push_back(new Point(347.99754,480.61584));
chest_hole.push_back(new Point(329.8148,510.41534));
chest_hole.push_back(new Point(339.91632,480.11077));
chest_hole.push_back(new Point(334.86556,478.09046));
return chest_hole;
}
double StringToDouble(const std::string& s) double StringToDouble(const std::string& s)