added Akl-Toussaint heuristic for vis (lil wonky atm but works)

This commit is contained in:
incredibleLeitman 2020-11-30 17:02:52 +01:00
parent 5729315c09
commit 2b299060f9
3 changed files with 154 additions and 67 deletions

View File

@ -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 () 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 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 AklToussaint heuristic // if use AklToussaint heuristic
if (m_useAkl) if (m_useAkl)
{ {
sf::Vector2f topLeft(WIDTH, HEIGHT); sf::Vector2f left(WIDTH, HEIGHT);
sf::Vector2f topRight(0, HEIGHT); sf::Vector2f right(0, HEIGHT);
sf::Vector2f botLeft(WIDTH, 0); sf::Vector2f bot(0, 0);
sf::Vector2f botRight(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 x = pos.x;
float y = pos.y; float y = pos.y;
// TODO: only check explicit x and y seperate! if (x < left.x)
if (x < topLeft.x && y < topLeft.y) topLeft = pos; {
if (x > topRight.x && y < topLeft.y) topRight = pos; left = pos;
if (x < botLeft.x && y > botLeft.y) botLeft = pos; i_left = i;
if (x > botRight.x && y > botRight.y) botRight = pos; }
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); // adding edge points to hull
m_hull.append(sf::Vertex(topLeft, sf::Color::Blue)); m_points[i_left].setFillColor(sf::Color::Blue);
m_hull.append(sf::Vertex(topRight, sf::Color::Blue)); m_hullPoints.push_back(m_points[i_left]);
m_hull.append(sf::Vertex(botRight, sf::Color::Blue));
m_hull.append(sf::Vertex(botLeft, sf::Color::Blue)); m_points[i_top].setFillColor(sf::Color::Blue);
m_hull.append(sf::Vertex(topLeft, 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 else
{ {
@ -165,6 +278,7 @@ void Display::update ()
} }
} }
// TODO: split points and use map
// adding starting points from most x to left // adding starting points from most x to left
if (i_left < i_right) if (i_left < i_right)
{ {
@ -172,18 +286,18 @@ void Display::update ()
} }
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
int pos = (i == 0) ? i_left : i_right; int idx = (i == 0) ? i_left : i_right;
m_points[pos].setFillColor(sf::Color::Blue); m_points[idx].setFillColor(sf::Color::Blue);
m_hullPoints.push_back(m_points[pos]); m_hullPoints.push_back(m_points[idx]);
m_points.erase(m_points.begin() + pos); 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(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_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_curLineIdx = 1;
m_curLine = m_lines[1]; m_curLine = m_lines[1];
// TODO: split points and use map
} }
} }
else if (curStep == 2) else if (curStep == 2)
@ -192,49 +306,7 @@ void Display::update ()
m_textStatus.setString(text + "split board..."); m_textStatus.setString(text + "split board...");
// get current line with points // get current line with points
while (m_curLineIdx == -1) setCurrentLine();
{
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);
}
} }
else if (curStep == 3) else if (curStep == 3)
{ {

View File

@ -33,7 +33,7 @@ private:
//std::vector<sf::Vertex> m_hull; //std::vector<sf::Vertex> m_hull;
std::vector<sf::CircleShape> m_hullPoints; std::vector<sf::CircleShape> 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 //sf::ConvexShape m_convex; // shape for convex hull -> does not fit because points have to be aligned already
//std::map<Line, std::vector<Point> > m_pointsForLine; //std::map<Line, std::vector<Point> > m_pointsForLine;
@ -44,6 +44,8 @@ private:
int m_curLineIdx = -1; // or just use index int m_curLineIdx = -1; // or just use index
unsigned int m_step = 0; unsigned int m_step = 0;
void setCurrentLine();
void update(); void update();
void render(sf::RenderWindow &); void render(sf::RenderWindow &);

View File

@ -22,4 +22,17 @@ static bool IsPointInTriangle(const Point &pt, const Point &p1, const Point &p2,
return !(has_neg && has_pos); 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 #endif // UTILITY_H