Last active
June 14, 2018 19:00
-
-
Save kim366/f204a2ecd53e305d525d1866a6077bb5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <cassert> | |
#include <array> | |
#include <algorithm> | |
// #define CATCH_CONFIG_MAIN | |
// #include <catch.hpp> | |
void draw_lines(const std::vector<sf::Vector2f>& vector_, sf::RenderTarget& target_, sf::Color color_ = sf::Color::White) | |
{ | |
for (auto it{vector_.cbegin()}; it != vector_.cend();) | |
{ | |
auto current_it{it}; | |
if (++it != vector_.cend()) | |
{ | |
sf::Vertex line[2] | |
{ | |
{*current_it, color_}, | |
{*it, color_} | |
}; | |
target_.draw(line, 2, sf::Lines); | |
} | |
} | |
} | |
float interpolate(float t, float a, float b) | |
{ | |
return (b - a) * t + a; | |
} | |
sf::Vector2f vinterpolate(float t, sf::Vector2f a, sf::Vector2f b) | |
{ | |
return {interpolate(t, a.x, b.x), interpolate(t, a.y, b.y)}; | |
} | |
class BezierCurve : public sf::Drawable | |
{ | |
public: | |
// template <typename... Vector2> | |
// BezierCurve(Vector2... points_) | |
// : _points{points_...} | |
// { | |
// } | |
BezierCurve() | |
{ | |
std::fill(_points.begin(), _points.end(), sf::Vector2f{-1, -1}); | |
} | |
sf::Vector2f getA() | |
{ | |
return _points[2] + (_points[2] - _points[1]); | |
} | |
void setA(sf::Vector2f a_) | |
{ | |
_points[2] = (a_ + _points[1]) / 2.f; | |
} | |
sf::Vector2f& operator[](size_t i_) | |
{ | |
return _points[i_]; | |
} | |
void makeCurve() | |
{ | |
// all points filled -> draw bezier curve | |
if (fullyInitialized()) | |
{ | |
for (float n{50}, t{0}; t <= 1.01; t += 1 / n) | |
{ | |
std::vector<sf::Vector2f> remaining_points; | |
remaining_points.resize(4); | |
std::copy(_points.begin(), _points.end(), remaining_points.begin()); | |
while (remaining_points.size() > 1) | |
{ | |
std::vector<sf::Vector2f> current_remaining_points; | |
for (auto it{remaining_points.cbegin()}; it != remaining_points.cend();) | |
{ | |
auto current_it{it}; | |
if (++it != remaining_points.cend()) | |
current_remaining_points.push_back(vinterpolate(t, *current_it, *it)); | |
} | |
remaining_points = current_remaining_points; | |
} | |
if (remaining_points.size() == 1) | |
_curve.push_back(remaining_points[0]); | |
} | |
} | |
} | |
void setNextPoint(sf::Vector2f point_) | |
{ | |
auto found{std::find(_points.begin(), _points.end(), sf::Vector2f{-1, -1})}; | |
assert(found != _points.end()); | |
*found = point_; | |
if (fullyInitialized()) | |
makeCurve(); | |
} | |
bool fullyInitialized() const | |
{ | |
return std::find(_points.begin(), _points.end(), sf::Vector2f{-1, -1}) == _points.end(); | |
} | |
private: | |
void draw(sf::RenderTarget& target_, sf::RenderStates states_) const override | |
{ | |
for (auto& point : _points) | |
{ | |
sf::CircleShape circle{2}; | |
circle.setOrigin(3, 3); | |
circle.setPosition(point); | |
circle.setFillColor({100, 100, 100}); | |
target_.draw(circle); | |
} | |
if (fullyInitialized()) | |
draw_lines(_curve, target_, sf::Color::Red); | |
} | |
private: | |
std::array<sf::Vector2f, 4> _points; | |
std::vector<sf::Vector2f> _curve; | |
}; | |
int main() | |
{ | |
const sf::ContextSettings aa_8x{0, 0, 8}; | |
sf::RenderWindow window({350, 350}, "SFML Bezier", sf::Style::Default, aa_8x); | |
std::vector<BezierCurve> curves; | |
while (true) | |
{ | |
sf::Event event; | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed || (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)) | |
return 0; | |
if (event.type == sf::Event::MouseButtonPressed) | |
{ | |
sf::Vector2f mpos{static_cast<float>(event.mouseButton.x), static_cast<float>(event.mouseButton.y)}; | |
if (curves.empty()) | |
{ | |
curves.emplace_back(); | |
curves.back()[0] = mpos; | |
} | |
else | |
{ | |
if (curves.back().fullyInitialized()) | |
{ | |
auto end_point{curves.back()[3]}; | |
curves.emplace_back(); | |
curves.back()[0] = end_point; | |
} | |
curves.back().setNextPoint(mpos); | |
} | |
} | |
} | |
window.clear(); | |
for (const auto& curve : curves) | |
window.draw(curve); | |
window.display(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment