diff --git a/Display.cpp b/Display.cpp index 0f712d0..7cf02e7 100644 --- a/Display.cpp +++ b/Display.cpp @@ -4,7 +4,6 @@ #include #include "Display.h" -//#include "Line.h" #include "Point.h" #include "Utility.h" @@ -26,17 +25,14 @@ Display::Display (const std::vector &pts, int stepSize) : m_stepSize(step { 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() - 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); @@ -44,7 +40,6 @@ Display::Display (const std::vector &pts, int stepSize) : m_stepSize(step label.setCharacterSize(12); label.setFillColor(sf::Color::Black); m_labels.push_back(label); - //m_points.append(label); } } @@ -109,6 +104,11 @@ void Display::update () // https://en.wikipedia.org/wiki/Convex_hull_algorithms#Akl%E2%80%93Toussaint_heuristic unsigned int curStep = (m_step > 5) ? ((m_step - 2) % 4 + 2) : (m_step % 6); // skip init and first step after first run + if (m_stepSize == 0 && curStep > 0) + { + std::cout << "any key to continue with next step..."; + std::cin.get(); + } std::string text = "(" + std::to_string(m_step) + ") step " + std::to_string(curStep) + ": "; if (curStep == 1) @@ -116,15 +116,6 @@ void Display::update () // first step: 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));*/ - // if use Akl–Toussaint heuristic bool useAkl = false; if (useAkl) @@ -146,16 +137,6 @@ void Display::update () 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(4); - convex.setPoint(0, topLeft); - convex.setPoint(1, topRight); - convex.setPoint(2, botRight); - convex.setPoint(3, botLeft);*/ - - //m_ hull as VertexArray - //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)); @@ -168,35 +149,45 @@ void Display::update () sf::Vector2f left(WIDTH, HEIGHT); sf::Vector2f right(0, 0); - for (auto& pt : m_points) + int i_left = WIDTH; + int i_right = 0; + + size_t points = m_points.size(); + for (size_t i = 0; i < points; ++i) { - sf::Vector2f pos = pt.getPosition(); + sf::Vector2f pos = m_points[i].getPosition(); float x = pos.x; - //float y = pos.y; - if (x < left.x) left = pos; - if (x > right.x) right = pos; + if (x < left.x) + { + i_left = i; + left = pos; + } + if (x > right.x) + { + i_right = i; + right = pos; + } } - //m_ hull as VertexArray - //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)); + // adding starting points from most x to left + if (i_left < i_right) + { + std::swap(i_left, i_right); + } + for (int i = 0; i < 2; ++i) + { + int pos = (i == 0) ? i_left : i_right; + m_points[pos].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[pos]); + m_points.erase(m_points.begin() + pos); + } m_lines.push_back(Line(Point(left.x, left.y), Point(right.x, right.y))); m_lines.push_back(Line(Point(right.x, right.y), Point(left.x, left.y))); // add first line in both directions to work with "right side" - m_curLine = &m_lines[1]; + m_curLineIdx = 1; + m_curLine = m_lines[1]; // TODO: split points and use map - - m_convex.setPointCount(2); - m_convex.setFillColor(sf::Color::Transparent); - m_convex.setOutlineColor(sf::Color::Red); - m_convex.setOutlineThickness(2); - m_convex.setPoint(0, left); - m_convex.setPoint(1, right); - - // TODO: could add here -> set color of points for current split } } else if (curStep == 2) @@ -204,38 +195,44 @@ void Display::update () // second step: split board m_textStatus.setString(text + "split board..."); - // TODO: get current line with points - if (m_curLine == nullptr) + // get current line with points + while (m_curLineIdx == -1) { size_t lines = m_lines.size(); if (lines < 1) // no more open lines -> fin { + std::cout << "## no more open lines -> fin!" << std::endl; m_points.clear(); - m_textStatus.setString(text + "finished calculating convex hull"); + m_textStatus.setString(text + "finished calculating convex hull in " + std::to_string(m_step / 5) + " cycles"); return; } - m_curLine = &m_lines[lines - 1]; - } + Line cand = m_lines[lines - 1]; + int positives = 0; + for (auto& pt : m_points) + { + positives += (sign(pt.getPosition().x, pt.getPosition().y, + cand.from().x(), cand.from().y(), + cand.to().x(), cand.to().y()) > 0) ? 1 : 0; + } - std::cout << "lines " << std::to_string(m_lines.size()) << std::endl; - for (auto& line : m_lines) - { - std::cout << " " << - std::to_string(line.from().x()) << ", " << - std::to_string(line.from().y()) << " - " << - std::to_string(line.to().x()) << ", " << - std::to_string(line.to().y()) << " " << std::endl; + if (positives > 0) + { + m_curLineIdx = lines - 1; + m_curLine = m_lines[lines - 1]; + } + else + { + m_lines.pop_back(); + } } for (auto& pt : m_points) { pt.setFillColor(sign( pt.getPosition().x, pt.getPosition().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); - m_curLine->from().x(), m_curLine->from().y(), - m_curLine->to().x(), m_curLine->to().y()) > 0 ? sf::Color::Red : sf::Color::Green); + m_lines[m_curLineIdx].from().x(), m_lines[m_curLineIdx].from().y(), + m_lines[m_curLineIdx].to().x(), m_lines[m_curLineIdx].to().y()) > 0 ? sf::Color::Red : sf::Color::Green); } } else if (curStep == 3) @@ -247,70 +244,40 @@ void Display::update () // third step: draw triangle, remove inner points m_textStatus.setString(text + "find furthest point and draw triangle..."); - sf::Vector2f pos = m_points[0].getPosition(); + sf::Vector2f pos; float maxDistance = 0; - for (auto& pt : m_points) + int i_cand = 0; + size_t points = m_points.size(); + for (size_t i = 0; i < points; ++i) { - /* - if (pt.getFillColor() == sf::Color::Green) - { - std::cout << "distance to green point " << pt.getPosition().x << ", " << pt.getPosition().y << ": " << distance << std::endl; - } - else if (pt.getFillColor() == sf::Color::Red) - { - std::cout << "distance to red point " << pt.getPosition().x << ", " << pt.getPosition().y << ": " << distance << std::endl; - } - */ - - if (pt.getFillColor() == sf::Color::Green) continue; + if (m_points[i].getFillColor() == sf::Color::Green) continue; + sf::Vector2f cand = m_points[i].getPosition(); float distance = pDistance( - pt.getPosition().x, pt.getPosition().y, - //m_hull[0].position.x, m_hull[0].position.y, - //m_hull[1].position.x, m_hull[1].position.y); - m_curLine->from().x(), m_curLine->from().y(), - m_curLine->to().x(), m_curLine->from().y()); + cand.x, cand.y, + m_lines[m_curLineIdx].from().x(), m_lines[m_curLineIdx].from().y(), + m_lines[m_curLineIdx].to().x(), m_lines[m_curLineIdx].from().y()); if (distance > maxDistance) { - pos = pt.getPosition(); + i_cand = i; + pos = cand; maxDistance = distance; } } if (maxDistance > 0) { - std::cout << "max point at " << pos.x << ", " << pos.y << std::endl; + // move point from all points to hull points + m_points[i_cand].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[i_cand]); + std::cout << "removing pt " << m_points[i_cand].getPosition().x << ", " << m_points[i_cand].getPosition().y << " at index " << std::to_string(i_cand) << " after inserted to hullpoints" << std::endl; + m_points.erase(m_points.begin() + i_cand); - // not append but insert between last line points - // -> append a point, then swap values - size_t vertices = m_hull.getVertexCount(); - m_hull.append(sf::Vertex(pos, sf::Color::Blue)); - m_hull[vertices] = m_hull[vertices - 1]; - m_hull[vertices - 1].position = pos; - - size_t points = m_convex.getPointCount(); - m_convex.setPointCount(points + 1); - m_convex.setPoint(points, pos); - - //m_lines.push_back(Line(m_curLine->from(), Point(pos.x, pos.y))); - //m_lines.push_back(Line(Point(pos.x, pos.y), m_curLine->to())); - - m_lines.push_back(Line(Point(pos.x, pos.y), m_curLine->to())); - //m_curLine->set_to(Point(pos.x, pos.y)); // only changes the value of the pointer - //(*m_curLine).set_to(Point(pos.x, pos.y)); // doesn't update list - //(*m_curLine) = Line(m_curLine->from(), Point(pos.x, pos.y)); // doesn't update list - m_lines[m_lines.size() - 2] = Line(m_curLine->from(), Point(pos.x, pos.y)); // updates list entry - - std::cout << "added to lines " << std::to_string(m_lines.size()) << std::endl; - for (auto& line : m_lines) - { - std::cout << " " << - std::to_string(line.from().x()) << ", " << - std::to_string(line.from().y()) << " - " << - std::to_string(line.to().x()) << ", " << - std::to_string(line.to().y()) << " " << std::endl; - } + Point to = m_lines[m_curLineIdx].to(); + Point from = m_lines[m_curLineIdx].from(); + m_lines.push_back(Line(Point(pos.x, pos.y),to)); + m_lines[m_lines.size() - 2] = Line(from, Point(pos.x, pos.y)); // updates list entry } else { @@ -322,39 +289,48 @@ void Display::update () // fourth step: remove inner points m_textStatus.setString(text + "remove inner points..."); - // TODO: wip - /*size_t lines = m_lines.size() - 1; - Point pt1 = m_lines[lines - 1].from(); - Point pt2 = m_lines[lines - 1].to(); - Point pt3 = m_lines[lines].to(); - for (size_t i = m_points.size(); i > 0; i--) + size_t lines = m_lines.size() - 1; + if (lines > 2) { - Point pt(m_points[i].getPosition().x, m_points[i].getPosition().y); - if (IsPointInTriangle(pt, pt1, pt2, pt3)) + // assure clockwise order + Point pt1 = m_lines[lines - 1].from(); + Point pt2 = m_lines[lines - 1].to(); + Point pt3 = m_lines[lines].to(); + if (sign(pt2, pt1, pt3) > 0) { - m_points.erase(m_points.begin() + i); + std::swap(pt1, pt2); } - }*/ - m_curLine = nullptr; + + size_t points = m_points.size(); + for (int i = points - 1; i >= 0; i--) + { + Point pt(m_points[i].getPosition().x, m_points[i].getPosition().y); + if (IsPointInTriangle(pt, pt1, pt2, pt3)) + { + std::cout << "remove pt inside triangle -> " << i << " with pos: " << pt.x() << ", " << pt.y() << std::endl; + m_points.erase(m_points.begin() + i); + } + else + { + m_points[i].setFillColor(sf::Color::Green); + } + } + } + //m_curLine = nullptr; + //m_curLineIdx = -1; } else if (curStep == 5) { // fifth step: adding new hull point - // TEMP: TEST check if ends - //if (m_step >= 10) m_points.clear(); + m_curLineIdx = -1; + //m_curLine = m_lines[lines - 1]; - if (m_points.size() == 0) m_textStatus.setString(text + "finished calculating convex hull"); + if (m_points.size() == 0) m_textStatus.setString(text + "finished calculating convex hull in " + std::to_string(m_step/5) + " cycles"); else m_textStatus.setString(text + "adding new hull point..."); } else if (m_step > 0) m_textStatus.setString(text + "invalid status!"); - if (m_stepSize == 0 && curStep > 0) - { - std::cout << "any key to continue with next step..."; - std::cin.get(); - } - if (curStep != 5 || m_points.size() > 0) m_step++; } @@ -362,42 +338,41 @@ void Display::render (sf::RenderWindow &window) { window.clear(sf::Color::White); - // draw already calculated hull - //if (step >= 1) + // draw already calculated hull points + size_t elements = m_hullPoints.size(); + for (size_t i = 0; i < elements; ++i) { - /*size_t vertices = m_hull.getVertexCount(); - for (size_t i = 0; i < vertices; ++i) - { - std::cout << "hull pt[" << i << "] color: " << std::to_string(m_hull[i].color.toInteger()) << " >> " << - std::to_string(m_hull[i].color.a) << ", " << - std::to_string(m_hull[i].color.r) << ", " << - std::to_string(m_hull[i].color.g) << ", " << - std::to_string(m_hull[i].color.b) << std::endl; - }*/ + window.draw(m_hullPoints[i]); - //window.draw(&m_hull[0], m_hull.size(), sf::Lines); - window.draw(&m_hull[0], m_hull.getVertexCount(), m_hull.getPrimitiveType()); + sf::Vertex ptTo; + if (i < elements - 1) ptTo = sf::Vertex(m_hullPoints[i + 1].getPosition(), sf::Color::Blue); + else ptTo = sf::Vertex(m_hullPoints[0].getPosition(), sf::Color::Blue); + sf::Vertex line[] = { sf::Vertex(sf::Vector2f(m_hullPoints[i].getPosition()), sf::Color::Blue), ptTo }; - // TODO: either insert points at correct location - // or only sort, then draw final hull - //window.draw(m_convex); + window.draw(line, 2, sf::Lines); } // always print remaining points - size_t points = m_points.size(); - for (size_t i = 0; i < points; ++i) + elements = m_points.size(); + for (size_t i = 0; i < elements; ++i) { window.draw(m_points[i]); + } + + // seperately print labels for points + elements = m_labels.size(); + for (size_t i = 0; i < elements; ++i) + { window.draw(m_labels[i]); } // draw line the algorithm is currently working on - if (m_curLine != nullptr) + if (m_curLineIdx != -1) { sf::Vertex line[] = { - sf::Vertex(sf::Vector2f(m_curLine->from().x(), m_curLine->from().y()), sf::Color::Red), - sf::Vertex(sf::Vector2f(m_curLine->to().x(), m_curLine->to().y()), sf::Color::Red) + sf::Vertex(sf::Vector2f(m_curLine.from().x(), m_curLine.from().y()), sf::Color::Red), + sf::Vertex(sf::Vector2f(m_curLine.to().x(), m_curLine.to().y()), sf::Color::Red) }; window.draw(line, 2, sf::Lines); } diff --git a/Display.h b/Display.h index 4247294..9a7f53a 100644 --- a/Display.h +++ b/Display.h @@ -5,6 +5,7 @@ // linux - sudo apt-get install libsfml-dev // windows - manual dl from https://www.sfml-dev.org/download.php #include +//#include #include "Line.h" @@ -29,12 +30,16 @@ private: //sf::VertexArray m_labels; //std::vector m_hull; + std::vector m_hullPoints; sf::VertexArray m_hull; - sf::ConvexShape m_convex; + //sf::ConvexShape m_convex; // shape for convex hull -> does not fit because points have to be aligned already //std::map > m_pointsForLine; std::vector m_lines; - Line *m_curLine = nullptr; + //std::list m_lines; + //Line *m_curLine = nullptr; // get any value if the underlying vector gets resized and moved in memory + Line m_curLine; // -> either make a copy + size_t m_curLineIdx = -1; // or just use index unsigned int m_step = 0; void update();