diff --git a/Display.cpp b/Display.cpp index f18b702..cd3f2c6 100644 --- a/Display.cpp +++ b/Display.cpp @@ -7,9 +7,7 @@ #include "Point.h" #include "Utility.h" -#define RADIUS 10.f - -Display::Display() +Display::Display (const std::vector &pts) { if (!m_font.loadFromFile("arial.ttf")) { @@ -21,26 +19,32 @@ Display::Display() m_textStatus.setString("initializing..."); m_textStatus.setCharacterSize(12); m_textStatus.setFillColor(sf::Color::Black); -} -void Display::drawPoint(sf::RenderWindow& window, size_t index) -{ - Point &pt = m_points[index]; - sf::CircleShape shape(RADIUS); - //shape.setOrigin(RADIUS, RADIUS); // handle with origin or manually calc position - shape.setPosition(pt.x() - RADIUS, pt.y() - RADIUS); - shape.setFillColor(sf::Color::Green); - shape.setOutlineThickness(1.f); - shape.setOutlineColor(sf::Color::Black); - window.draw(shape); + size_t points = pts.size(); + for (size_t i = 0; i < points; ++i) + { + const Point& pt = pts[i]; + sf::CircleShape shape(OFFSET); + //shape.setPosition(pt.x() - OFFSET, pt.y() - OFFSET); // handle with origin or manually calc position + shape.setOrigin(OFFSET, OFFSET); + shape.setPosition(pt.x(), pt.y()); + shape.setFillColor(sf::Color::Green); + shape.setOutlineThickness(1.f); + shape.setOutlineColor(sf::Color::Black); + m_points.push_back(shape); + //m_points.append(shape); - sf::Text label; - label.setPosition(pt.x() - RADIUS/2, pt.y() - RADIUS/2 - 3); - label.setFont(m_font); - label.setString(std::to_string(index)); - label.setCharacterSize(12); - label.setFillColor(sf::Color::Black); - window.draw(label); + sf::Text label; + //label.setPosition(pt.x() - OFFSET / 2, pt.y() - OFFSET / 2 - 3); + label.setOrigin(OFFSET / 2 - 1, OFFSET / 2 + 3); + label.setPosition(pt.x(), pt.y()); + label.setFont(m_font); + label.setString(std::to_string(i)); + label.setCharacterSize(12); + label.setFillColor(sf::Color::Black); + m_labels.push_back(label); + //m_points.append(label); + } } // multiple options possible: @@ -53,15 +57,15 @@ void Display::drawPoint(sf::RenderWindow& window, size_t index) void Display::show() { sf::ContextSettings settings; - settings.antialiasingLevel = 4; + settings.antialiasingLevel = 8; sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "ALGO Prog2: Quickhull - visualization", sf::Style::Default, settings); - // b) - //window.setFramerateLimit(0.2); + /* b) + window.setFramerateLimit(0.2); - //sf::Clock clock; - //sf::Time timeSinceLastUpdate = sf::Time::Zero; - //sf::Time frameTime = sf::seconds(2); //sf::seconds(1.f / 60.f) + sf::Clock clock; + sf::Time frameTime = sf::seconds(2); //sf::seconds(1.f / 60.f) + sf::Time timeSinceLastUpdate = frameTime; //sf::Time::Zero;*/ while (window.isOpen()) { sf::Event event; @@ -71,96 +75,176 @@ void Display::show() window.close(); } - std::cout << "entering gameloop" << std::endl; + // a) + //update(elapsed); + //render(window); /* b) timeSinceLastUpdate += clock.restart(); // only handle every few seconds because we need no animations - if (timeSinceLastUpdate > frameTime) + if (timeSinceLastUpdate >= frameTime) { + std::cout << "entering update and render" << std::endl; + // start by getting the most left and right point timeSinceLastUpdate -= frameTime; + + update(); + render(window); }*/ - // a) - //update(elapsed); - update(); - - window.clear(sf::Color::White); - - // TODO: refactor -> parse into sf::Vertices or Shapes - // always print remaining points - size_t points = m_points.size(); - for (size_t i = 0; i < points; ++i) - { - drawPoint(window, i); - } - - // draw already calculated hull - //if (step >= 1) - { - //window.draw(&m_hull[0], m_hull.size(), sf::Lines); - window.draw(&m_hull[0], m_hull.getVertexCount(), m_hull.getPrimitiveType()); - } - - window.draw(m_textStatus); - - window.display(); - // c) - // choose a simple sleep + // choose a simple sleep + update(); + render(window); std::this_thread::sleep_for(std::chrono::milliseconds(2000)); } } -void Display::update() +void Display::update () { // TODO: maybe include Akl–Toussaint heuristic first? // https://en.wikipedia.org/wiki/Convex_hull_algorithms#Akl%E2%80%93Toussaint_heuristic - if (m_curStep == 1) + + unsigned int curStep = (m_step > 5) ? ((m_step - 2) % 4 + 2) : (m_step % 6); // skip init and first step after first run + + std::string text = "(" + std::to_string(m_step) + ") step " + std::to_string(curStep) + ": "; + if (curStep == 1) { // first step: select min - max x coordinates - m_textStatus.setString("step " + std::to_string(m_curStep) + ": select min - max x coordinates..."); + m_textStatus.setString(text + "select min - max x coordinates..."); + + /* EDIT: manual iteration for combining x and x minmax; also need not previous sorting std::pair minmax = getMinMaxX(m_points); std::cout << "min: " << minmax.first.x() << ", " << minmax.first.y() << ", max: " << minmax.second.x() << ", " << minmax.second.y() << std::endl; m_hull.setPrimitiveType(sf::Lines); m_hull.append(sf::Vertex(sf::Vector2f(minmax.first.x(), minmax.first.y()), sf::Color::Blue)); - m_hull.append(sf::Vertex(sf::Vector2f(minmax.second.x(), minmax.second.y()), sf::Color::Blue)); + m_hull.append(sf::Vertex(sf::Vector2f(minmax.second.x(), minmax.second.y()), sf::Color::Blue));*/ + + // if use Akl–Toussaint heuristic + bool useAkl = false; + if (useAkl) + { + sf::Vector2f topLeft(WIDTH, HEIGHT); + sf::Vector2f topRight(0, HEIGHT); + sf::Vector2f botLeft(WIDTH, 0); + sf::Vector2f botRight(0, 0); + + for (auto& pt : m_points) + { + sf::Vector2f pos = pt.getPosition(); + float x = pos.x; + float y = pos.y; + if (x < topLeft.x && y < topLeft.y) topLeft = pos; + if (x > topRight.x && y < topLeft.y) topRight = pos; + if (x < botLeft.x && y > botLeft.y) botLeft = pos; + if (x > botRight.x && y > botRight.y) botRight = pos; + } + + /* TODO: use a convex shape? Or build from vertices in render? + sf::ConvexShape convex; + convex.setPointCount(5); + convex.setPoint(0, topLeft); + convex.setPoint(0, topRight); + convex.setPoint(0, botRight); + convex.setPoint(0, botLeft);*/ + + //m_hull.setPrimitiveType(sf::Lines); + m_hull.setPrimitiveType(sf::LineStrip); + m_hull.append(sf::Vertex(topLeft, sf::Color::Blue)); + m_hull.append(sf::Vertex(topRight, sf::Color::Blue)); + m_hull.append(sf::Vertex(botRight, sf::Color::Blue)); + m_hull.append(sf::Vertex(botLeft, sf::Color::Blue)); + m_hull.append(sf::Vertex(topLeft, sf::Color::Blue)); + } + else + { + sf::Vector2f left(WIDTH, HEIGHT); + sf::Vector2f right(0, 0); + + for (auto& pt : m_points) + { + sf::Vector2f pos = pt.getPosition(); + float x = pos.x; + float y = pos.y; + if (x < left.x) left = pos; + if (x > right.x) right = pos; + } + + //m_hull.setPrimitiveType(sf::Lines); + m_hull.setPrimitiveType(sf::LineStrip); + m_hull.append(sf::Vertex(left, sf::Color::Blue)); + m_hull.append(sf::Vertex(right, sf::Color::Blue)); + } } - else if (m_curStep == 2) + else if (curStep == 2) { // second step: split board and find furthest point - m_textStatus.setString("step " + std::to_string(m_curStep) + ": split board and find furthest point..."); + m_textStatus.setString(text + "split board and find furthest point..."); + + for (auto& pt : m_points) + { + sf::Vector2f pos = pt.getPosition(); + float x = pos.x; + float y = pos.y; + + pt.setFillColor(sign(x, y, m_hull[0].position.x, m_hull[0].position.y, m_hull[1].position.x, m_hull[1].position.y) > 0 ? sf::Color::Red : sf::Color::Green); + } } - else if (m_curStep == 3) + else if (curStep == 3) { // third step: draw triangle, remove inner points - m_textStatus.setString("step " + std::to_string(m_curStep) + ": draw triangle, remove inner points..."); + m_textStatus.setString(text + "find furthest point and draw triangle..."); } - else if (m_curStep == 4) + else if (curStep == 4) { // fourth step: remove inner points - m_textStatus.setString("step " + std::to_string(m_curStep) + ": remove inner points..."); + m_textStatus.setString(text + "remove inner points..."); } - else if (m_curStep == 5) + else if (curStep == 5) { - // fourth step: remove inner points - m_textStatus.setString("step " + std::to_string(m_curStep) + ": finished calculating convex hull"); - } + // fifth step: adding new hull point - m_curStep++; - // if finished removing inner points and there are still points left -> repeat from step 2 - // TODO: - if (m_curStep == 5 && m_points.size() > 0) - { - m_curStep = 2; - } + // TEMP: TEST check if ends + //if (m_step >= 10) m_points.clear(); + if (m_points.size() == 0) m_textStatus.setString(text + "finished calculating convex hull"); + else m_textStatus.setString(text + "adding new hull point..."); + } + else m_textStatus.setString(text + "invalid status!"); + + if (curStep != 5 || m_points.size() > 0) m_step++; } -void Display::setData(std::vector pts) +void Display::render (sf::RenderWindow &window) { - m_points = pts; + window.clear(sf::Color::White); + + // always print remaining points + /*size_t points = m_points.size(); + for (size_t i = 0; i < points; ++i) + { + drawPoint(window, i); + }*/ + + //for (auto& pt : m_points) // points and labels should have the same size -> combine in one loop + size_t points = m_points.size(); + for (size_t i = 0; i < points; ++i) + { + window.draw(m_points[i]); + window.draw(m_labels[i]); + } + + // draw already calculated hull + //if (step >= 1) + { + //window.draw(&m_hull[0], m_hull.size(), sf::Lines); + window.draw(&m_hull[0], m_hull.getVertexCount(), m_hull.getPrimitiveType()); + } + + window.draw(m_textStatus); + + window.display(); } \ No newline at end of file diff --git a/Display.h b/Display.h index a4cb5d4..76b53bd 100644 --- a/Display.h +++ b/Display.h @@ -8,7 +8,7 @@ class Point; -#define OFFSET 10 +#define OFFSET 10.f #define WIDTH 800 #define HEIGHT 600 @@ -18,20 +18,22 @@ private: sf::Font m_font; sf::Text m_textStatus; - std::vector m_points; + //std::vector m_points; + std::vector m_points; + std::vector m_labels; + //sf::VertexArray m_points; + //sf::VertexArray m_labels; + //std::vector m_hull; sf::VertexArray m_hull; - void drawPoint(sf::RenderWindow &, size_t); - - int m_curStep = 0; + unsigned int m_step = 0; void update(); + void render(sf::RenderWindow &); public: - Display(); + Display(const std::vector &); void show(); - - void setData (std::vector); }; #endif // DISPLAY_H \ No newline at end of file