diff --git a/Display.cpp b/Display.cpp index 11e8242..1bddb43 100644 --- a/Display.cpp +++ b/Display.cpp @@ -98,6 +98,60 @@ void Display::show() } } +void Display::setCurrentLine() +{ + 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(); + + if (m_points.size() == 0) + { + 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) + ": "; + m_textStatus.setString(text + "finished calculating convex hull in " + std::to_string((m_step / 4 + 1)) + " cycles"); + } + return; + } + + Line cand = m_lines[lines - 1]; + int positives = 0; + for (auto& pt : m_points) + { + if (cand.is_point_right(Point(pt.getPosition().x, pt.getPosition().y))) + { + positives++; + break; // sufficient as candidate if at least one point is right + } + /*positives += (sign(pt.getPosition().x, pt.getPosition().y, + cand.from().x(), cand.from().y(), + cand.to().x(), cand.to().y()) > 0) ? 1 : 0;*/ + } + + 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_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); + } +} + void Display::update () { unsigned int curStep = (m_step > 5) ? ((m_step - 2) % 4 + 2) : (m_step % 6); // skip init and first step after first run @@ -116,29 +170,88 @@ void Display::update () // if use Akl–Toussaint heuristic if (m_useAkl) { - sf::Vector2f topLeft(WIDTH, HEIGHT); - sf::Vector2f topRight(0, HEIGHT); - sf::Vector2f botLeft(WIDTH, 0); - sf::Vector2f botRight(0, 0); + sf::Vector2f left(WIDTH, HEIGHT); + sf::Vector2f right(0, HEIGHT); + sf::Vector2f bot(0, 0); + sf::Vector2f top(0, HEIGHT); - for (auto& pt : m_points) + // index to find points + int i_left = WIDTH; + int i_right = 0; + int i_top = HEIGHT; + int i_bot = 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; - // TODO: only check explicit x and y seperate! - 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; + if (x < left.x) + { + left = pos; + i_left = i; + } + if (x > right.x) + { + right = pos; + i_right = i; + } + if (y < top.y) + { + top = pos; + i_top = i; + } + if (y > bot.y) + { + bot = pos; + i_bot = i; + } } - 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)); + // adding edge points to hull + m_points[i_left].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[i_left]); + + m_points[i_top].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[i_top]); + + m_points[i_right].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[i_right]); + + m_points[i_bot].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[i_bot]); + + // building lines between edge points + Point pt1(left.x, left.y); + Point pt2(top.x, top.y); + Point pt3(right.x, right.y); + Point pt4(bot.x, bot.y); + m_lines.push_back(Line(pt1, pt2)); + m_lines.push_back(Line(pt2, pt3)); + m_lines.push_back(Line(pt3, pt4)); + m_lines.push_back(Line(pt4, pt1)); + + // remove points in calculated rectangle + for (int i = points - 1; i >= 0; i--) + { + Point pt(m_points[i].getPosition().x, m_points[i].getPosition().y); + if (IsPointInRectangle(pt, pt1, pt2, pt3, pt4)) + { + std::cout << "remove pt inside triangle -> " << i << " with pos: " << pt.x() << ", " << pt.y() << std::endl; + m_points.erase(m_points.begin() + i); + } + // TODO: ugly workaround - remove hull points + else if ((pt.x() == pt1.x() && pt.y() == pt1.y()) || + (pt.x() == pt2.x() && pt.y() == pt2.y()) || + (pt.x() == pt3.x() && pt.y() == pt3.y()) || + (pt.x() == pt4.x() && pt.y() == pt4.y())) + { + m_points.erase(m_points.begin() + i); + } + } + + setCurrentLine(); } else { @@ -165,6 +278,7 @@ void Display::update () } } + // TODO: split points and use map // adding starting points from most x to left if (i_left < i_right) { @@ -172,18 +286,18 @@ void Display::update () } 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); + int idx = (i == 0) ? i_left : i_right; + m_points[idx].setFillColor(sf::Color::Blue); + m_hullPoints.push_back(m_points[idx]); + m_points.erase(m_points.begin() + idx); } 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" + + // set current line just by taking the only one (in one direction) m_curLineIdx = 1; m_curLine = m_lines[1]; - - // TODO: split points and use map } } else if (curStep == 2) @@ -192,49 +306,7 @@ void Display::update () m_textStatus.setString(text + "split board..."); // 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(); - if (m_points.size() == 0) m_textStatus.setString(text + "finished calculating convex hull in " + std::to_string((m_step / 4 + 1)) + " cycles"); - return; - } - - Line cand = m_lines[lines - 1]; - int positives = 0; - for (auto& pt : m_points) - { - if (cand.is_point_right(Point(pt.getPosition().x, pt.getPosition().y))) - { - positives++; - break; // sufficient as candidate if at least one point is right - } - /*positives += (sign(pt.getPosition().x, pt.getPosition().y, - cand.from().x(), cand.from().y(), - cand.to().x(), cand.to().y()) > 0) ? 1 : 0;*/ - } - - 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_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); - } + setCurrentLine(); } else if (curStep == 3) { diff --git a/Display.h b/Display.h index abd2cfb..b0c0503 100644 --- a/Display.h +++ b/Display.h @@ -33,7 +33,7 @@ private: //std::vector m_hull; std::vector m_hullPoints; - sf::VertexArray m_hull; + //sf::VertexArray m_hull; //sf::ConvexShape m_convex; // shape for convex hull -> does not fit because points have to be aligned already //std::map > m_pointsForLine; @@ -44,6 +44,8 @@ private: int m_curLineIdx = -1; // or just use index unsigned int m_step = 0; + + void setCurrentLine(); void update(); void render(sf::RenderWindow &); diff --git a/Utility.h b/Utility.h index 3719d34..a48073e 100644 --- a/Utility.h +++ b/Utility.h @@ -22,4 +22,17 @@ static bool IsPointInTriangle(const Point &pt, const Point &p1, const Point &p2, return !(has_neg && has_pos); } + +static bool IsPointInRectangle(const Point& pt, const Point& p1, const Point& p2, const Point& p3, const Point& p4) +{ + float d1 = sign(pt, p1, p2); + float d2 = sign(pt, p2, p3); + float d3 = sign(pt, p3, p4); + float d4 = sign(pt, p4, p1); + + bool has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0) || (d4 < 0); + bool has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0) || (d4 > 0); + + return !(has_neg && has_pos); +} #endif // UTILITY_H \ No newline at end of file