paella/src/Animation/Click.cpp

276 lines
9.7 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// Paella
// Copyright (C) 2015 - Thomas FORGIONE, Emilie JALRAS, Marion LENFANT, Thierry MALON, Amandine PAILLOUX
// Authors :
// Thomas FORGIONE
// Emilie JALRAS
// Marion LENFANT
// Thierry MALON
// Amandine PAILLOUX
//
// This file is part of the project Paella
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
////////////////////////////////////////////////////////////////////////////////
#include <Animation/Click.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFMLTools/VectorFunctions.hpp>
namespace pae
{
std::pair<std::vector<geo::Segment<float,3>>, geo::Vector3<float>> click(Skeleton3D const& skel)
{
// Initialization of the window where clicks have to be done
sf::RenderWindow window{sf::VideoMode{800,600},"Click on the rotation points"};
std::vector<geo::Segment<float,3>> ret{};
std::vector<std::vector<sf::Vertex>> skelToDraw{};
std::vector<std::vector<sf::Vertex>> splines;
std::vector<std::vector<unsigned int>> pointsIndexes{};
for (auto const& spline : skel.splines)
{
auto pt1 = std::get<0>(spline(0));
auto pt2 = std::get<0>(spline(1));
skelToDraw.push_back({sf::Vertex(sf::Vector2f(pt1.x(), -pt1.y()), sf::Color::Red),
sf::Vertex(sf::Vector2f(pt2.x(), -pt2.y()), sf::Color::Red)});
splines.push_back({});
skelToDraw[skelToDraw.size()-1].push_back({});
pointsIndexes.push_back({0,202});
splines[splines.size()-1].push_back(sf::Vertex(sf::Vector2f(pt1.x(), -pt1.y())));
for (float t = 0; t <1; t+=0.01)
{
auto v = std::get<0>(spline(t));
splines[splines.size()-1].push_back(sf::Vertex(sf::Vector2f(v.x(),-v.y())));
splines[splines.size()-1].push_back(sf::Vertex(sf::Vector2f(v.x(),-v.y())));
}
}
// Compute the 2D bounding box of the skeleton
float xmin, xmax, ymin, ymax;
xmin = std::numeric_limits<float>::max();
xmax = std::numeric_limits<float>::min();
ymin = std::numeric_limits<float>::max();
ymax = std::numeric_limits<float>::min();
for (unsigned int i = 0; i < splines.size(); i++)
{
for (unsigned int j = 0; j < splines[i].size(); j++)
{
xmin = std::min(xmin, splines[i][j].position.x);
ymin = std::min(ymin, splines[i][j].position.y);
xmax = std::max(xmax, splines[i][j].position.x);
ymax = std::max(ymax, splines[i][j].position.y);
}
}
auto horizontalSize = xmax - xmin;
auto verticalSize = ymax - ymin;
xmin -= horizontalSize/10;
xmax += horizontalSize/10;
ymin -= verticalSize/10;
ymax += verticalSize/10;
// Setting the view
sf::View view;
view.setSize(xmax-xmin, ymax-ymin);
view.setCenter(0.5*(xmin+xmax),0.5*(ymin+ymax));
window.setView(view);
bool captureRequired = false;
bool running = true;
sf::Vector2f lastClick;
while (running)
{
sf::Event event;
while (window.pollEvent(event))
{
// End the program when the window is closed
if (event.type == sf::Event::Closed)
{
running = false;
window.close();
}
else if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::P)
{
captureRequired = true;
}
}
else if (event.type == sf::Event::MouseButtonReleased)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
auto ptx = event.mouseButton.x;
auto pty = event.mouseButton.y;
auto clicks = window.mapPixelToCoords(sf::Vector2i(ptx,pty));
float bestDistance = std::numeric_limits<float>::max();
unsigned int bestSpline;
unsigned int bestPoint;
for (unsigned int i = 0; i < splines.size(); i++)
{
for (unsigned int j = 0; j < splines[i].size(); j++)
{
float currentDistance = sft::norm2(clicks - splines[i][j].position);
if (currentDistance < bestDistance)
{
bestDistance = currentDistance;
bestSpline = i;
bestPoint = j;
}
}
}
if (std::find(pointsIndexes[bestSpline].begin(), pointsIndexes[bestSpline].end(), bestPoint) == pointsIndexes[bestSpline].end())
{
unsigned int k = 0;
while (k < pointsIndexes[bestSpline].size() && bestPoint > pointsIndexes[bestSpline][k])
{
k++;
}
pointsIndexes[bestSpline].insert(pointsIndexes[bestSpline].begin()+k, bestPoint);
skelToDraw[bestSpline].insert(skelToDraw[bestSpline].begin()+2*k-1,splines[bestSpline][bestPoint].position);
skelToDraw[bestSpline].insert(skelToDraw[bestSpline].begin()+2*k,splines[bestSpline][bestPoint].position);
skelToDraw[bestSpline][2*k-1].color = sf::Color::Red;
skelToDraw[bestSpline][2*k].color = sf::Color::Red;
}
}
else if (event.mouseButton.button == sf::Mouse::Right)
{
lastClick = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x,event.mouseButton.y));
running = false;
}
}
}
window.clear(sf::Color::Black);
for (unsigned int i = 0; i < splines.size(); i++)
{
window.draw(&splines[i][0], splines[i].size(), sf::Lines);
}
for (unsigned int i = 0; i < skelToDraw.size(); i++)
{
window.draw(&skelToDraw[i][0], skelToDraw[i].size(), sf::Lines);
}
if (captureRequired)
{
sf::Vector2u windowSize = window.getSize();
sf::Texture texture;
texture.create(windowSize.x, windowSize.y);
texture.update(window);
sf::Image screenshot = texture.copyToImage();
screenshot.saveToFile("capture.jpg");
captureRequired = false;
}
window.display();
}
std::cout << "Done" << std::endl;
for (unsigned int i = 0; i < splines.size(); i++)
{
for (unsigned int j = 0; j < skelToDraw[i].size()-1; j+=2)
{
ret.push_back({geo::Vector3<float>{skelToDraw[i][j].position.x, -skelToDraw[i][j].position.y, 0}, geo::Vector3<float>{skelToDraw[i][j+1].position.x, -skelToDraw[i][j+1].position.y, 0}});
}
}
geo::Vector3<float> mainPatella{0,0,0};
geo::Vector3<float> clickCoordinates{lastClick.x,-lastClick.y,0};
float bestDistance = std::numeric_limits<float>::max();
// Searching of the main patella point
for (auto const& elt : ret)
{
float currentDistance = (lastClick.x-elt.first.x())*(lastClick.x-elt.first.x()) + (-lastClick.y-elt.first.y())*(-lastClick.y-elt.first.y());
if (currentDistance < bestDistance)
{
mainPatella = elt.first;
bestDistance = currentDistance;
}
currentDistance = (lastClick.x-elt.second.x())*(lastClick.x-elt.second.x()) + (-lastClick.y-elt.second.y())*(-lastClick.y-elt.second.y());
if (currentDistance < bestDistance)
{
mainPatella = elt.second;
bestDistance = currentDistance;
}
}
return std::make_pair(ret, mainPatella);
}
geo::Tree<geo::Vector3<float>>& listToTree(std::list<geo::Segment<float,3>>& list, geo::Tree<geo::Vector3<float>>& tree)
{
constexpr float eps = 0.00001;
for (auto it = std::begin(list), end = std::end(list); it != end;)
{
if ((it->first - tree.node).norm2() < eps)
{
tree.children.push_back(geo::Tree<geo::Vector3<float>>{it->second});
it = list.erase(it);
continue;
}
else if ((it->second - tree.node).norm2() < eps)
{
tree.children.push_back(geo::Tree<geo::Vector3<float>>{it->first});
it = list.erase(it);
continue;
}
++it;
}
for (auto& child : tree.children)
{
listToTree(list, child);
}
return tree;
}
geo::Tree<geo::Vector3<float>>& listToTree(std::vector<geo::Segment<float,3>> const& vector, geo::Tree<geo::Vector3<float>>& tree)
{
std::list<geo::Segment<float,3>> list;
std::copy(std::begin(vector), std::end(vector), std::back_inserter(list));
return listToTree(list, tree);
}
}