diff --git a/testbed/data/dude.dat b/testbed/data/dude.dat index 7e43f9c..bd8c4e0 100644 --- a/testbed/data/dude.dat +++ b/testbed/data/dude.dat @@ -92,3 +92,15 @@ 251.07143 621.11218 250.53571 649.1479 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 diff --git a/testbed/data/steiner.dat b/testbed/data/steiner.dat new file mode 100644 index 0000000..8a3ecee --- /dev/null +++ b/testbed/data/steiner.dat @@ -0,0 +1,9 @@ +0 0 +10 0 +10 10 +0 10 +STEINER +2 2 +8 2 +8 8 +2 8 diff --git a/testbed/main.cc b/testbed/main.cc index 37f2f40..007721b 100644 --- a/testbed/main.cc +++ b/testbed/main.cc @@ -33,12 +33,15 @@ #include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -46,6 +49,12 @@ using namespace std; using namespace p2t; +bool ParseFile(string filename, vector& out_polyline, vector>& out_holes, + vector& out_steiner); +void GenerateRandomPointDistribution(size_t num_points, double min, double max, + vector& out_polyline, + vector>& out_holes, + vector& out_steiner); void Init(); void ShutDown(int return_code); void MainLoop(const double zoom); @@ -56,13 +65,9 @@ double StringToDouble(const std::string& s); double Random(double (*fun)(double), double xmin, double xmax); double Fun(double x); -/// Dude hole examples -vector CreateHeadHole(); -vector CreateChestHole(); - -float rotate_y = 0, - rotate_z = 0; -const float rotations_per_tick = .2; +double rotate_y = 0.0, + rotate_z = 0.0; +const double rotations_per_tick = 0.2; /// Screen center x double cx = 0.0; @@ -74,7 +79,9 @@ vector triangles; /// Triangle map list map; /// Polylines -vector< vector > polylines; +vector polyline; +vector> holes; +vector steiner; /// Draw the entire triangle map? bool draw_map = false; @@ -83,18 +90,18 @@ bool random_distribution = false; GLFWwindow* window = NULL; -template void FreeClear( C & cntr ) { - for ( typename C::iterator it = cntr.begin(); - it != cntr.end(); ++it ) { - delete * it; - } - cntr.clear(); +template void FreeClear(C& cntr) +{ + for (typename C::iterator it = cntr.begin(); it != cntr.end(); ++it) { + delete *it; + } + cntr.clear(); } int main(int argc, char* argv[]) { - - int num_points = 0; + string filename; + size_t num_points = 0u; double max, min; double zoom; @@ -105,58 +112,30 @@ int main(int argc, char* argv[]) return 1; } - if(string(argv[1]) == "random") { + if (string(argv[1]) == "random") { num_points = atoi(argv[2]); random_distribution = true; char* pEnd; max = strtod(argv[3], &pEnd); min = -max; - cx = cy = 0; + cx = cy = 0.0; zoom = atof(argv[4]); } else { - zoom = atof(argv[4]); + filename = string(argv[1]); cx = atof(argv[2]); cy = atof(argv[3]); + zoom = atof(argv[4]); } - vector polyline; - - 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)); + if (random_distribution) { + GenerateRandomPointDistribution(num_points, min, max, polyline, holes, steiner); } else { // Load pointset from file - - // Parse and tokenize data file - 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 tokens; - copy(istream_iterator(iss), istream_iterator(), - back_inserter >(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; + if (!ParseFile(filename, polyline, holes, steiner)) { + return 2; } } - cout << "Number of constrained edges = " << polyline.size() << endl; - polylines.push_back(polyline); - Init(); /* @@ -173,29 +152,14 @@ int main(int argc, char* argv[]) CDT* cdt = new CDT(polyline); /* - * STEP 2: Add holes or Steiner points if necessary + * STEP 2: Add holes or Steiner points */ - - string s(argv[1]); - if(s.find("dude.dat", 0) != string::npos) { - // Add head hole - vector head_hole = CreateHeadHole(); - num_points += head_hole.size(); - cdt->AddHole(head_hole); - // Add chest hole - vector 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& hole : holes) { + assert(!hole.empty()); + cdt->AddHole(hole); + } + for (const auto& s : steiner) { + cdt->AddPoint(s); } /* @@ -207,27 +171,115 @@ int main(int argc, char* argv[]) triangles = cdt->GetTriangles(); map = cdt->GetMap(); + const size_t points_in_holes = + std::accumulate(holes.cbegin(), holes.cend(), size_t(0), + [](size_t cumul, const vector& 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 << "Elapsed time (ms) = " << dt*1000.0 << endl; + cout << "Elapsed time (ms) = " << dt * 1000.0 << endl; MainLoop(zoom); // Cleanup - delete cdt; - - // Free points - for(int i = 0; i < polylines.size(); i++) { - vector poly = polylines[i]; - FreeClear(poly); + FreeClear(polyline); + for (vector& hole : holes) { + FreeClear(hole); } + FreeClear(steiner); ShutDown(0); return 0; } +bool ParseFile(string filename, vector& out_polyline, vector>& out_holes, + vector& out_steiner) +{ + enum ParserState { + Polyline, + Hole, + Steiner, + }; + ParserState state = Polyline; + vector* 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 tokens; + copy(istream_iterator(iss), istream_iterator(), 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& out_polyline, + vector>& out_holes, vector& 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() { const int window_width = 800, @@ -267,7 +319,7 @@ void MainLoop(const double zoom) // calculate time elapsed, and the amount by which stuff rotates double current_time = glfwGetTime(), - delta_rotate = (current_time - old_time) * rotations_per_tick * 360; + delta_rotate = (current_time - old_time) * rotations_per_tick * 360.0; old_time = current_time; // escape to quit, arrow keys to rotate view @@ -306,8 +358,8 @@ void ResetZoom(double zoom, double cx, double cy, double width, double height) glLoadIdentity(); // Reset ortho view - glOrtho(left, right, bottom, top, 1, -1); - glTranslatef(-cx, -cy, 0); + glOrtho(left, right, bottom, top, 1.0, -1.0); + glTranslated(-cx, -cy, 0.0); glMatrixMode(GL_MODELVIEW); glDisable(GL_DEPTH_TEST); glLoadIdentity(); @@ -333,20 +385,25 @@ void Draw(const double zoom) glColor3f(1, 0, 0); glBegin(GL_LINE_LOOP); - glVertex2f(a.x, a.y); - glVertex2f(b.x, b.y); - glVertex2f(c.x, c.y); + glVertex2d(a.x, a.y); + glVertex2d(b.x, b.y); + glVertex2d(c.x, c.y); glEnd(); } // green glColor3f(0, 1, 0); + vector*> polylines; + polylines.push_back(&polyline); + for (vector& hole : holes) { + polylines.push_back(&hole); + } for(int i = 0; i < polylines.size(); i++) { - vector poly = polylines[i]; + const vector& poly = *polylines[i]; glBegin(GL_LINE_LOOP); for(int j = 0; j < poly.size(); j++) { - glVertex2f(poly[j]->x, poly[j]->y); + glVertex2d(poly[j]->x, poly[j]->y); } glEnd(); } @@ -368,20 +425,20 @@ void DrawMap(const double zoom) ConstrainedColor(t.constrained_edge[2]); glBegin(GL_LINES); - glVertex2f(a.x, a.y); - glVertex2f(b.x, b.y); + glVertex2d(a.x, a.y); + glVertex2d(b.x, b.y); glEnd( ); ConstrainedColor(t.constrained_edge[0]); glBegin(GL_LINES); - glVertex2f(b.x, b.y); - glVertex2f(c.x, c.y); + glVertex2d(b.x, b.y); + glVertex2d(c.x, c.y); glEnd( ); ConstrainedColor(t.constrained_edge[1]); glBegin(GL_LINES); - glVertex2f(c.x, c.y); - glVertex2f(a.x, a.y); + glVertex2d(c.x, c.y); + glVertex2d(a.x, a.y); glEnd( ); } } @@ -397,31 +454,6 @@ void ConstrainedColor(bool constrain) } } -vector CreateHeadHole() { - - vector 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 CreateChestHole() { - - vector 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)