276 lines
9.7 KiB
C++
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);
|
|
}
|
|
|
|
}
|