sftools  2.0 dev
Bunch of tools for SFML application development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
Curve.hpp
Go to the documentation of this file.
1 /*
2 
3  sftools - Copyright (c) 2012-2013 Marco Antognini <antognini.marco@gmail.com>
4 
5  This software is provided 'as-is', without any express or implied warranty. In
6  no event will the authors be held liable for any damages arising from the use
7  of this software.
8 
9  Permission is granted to anyone to use this software for any purpose, including
10  commercial applications, and to alter it and redistribute it freely, subject to
11  the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not claim
14  that you wrote the original software. If you use this software in a product,
15  an acknowledgment in the product documentation would be appreciated but is
16  not required.
17 
18  2. Altered source versions must be plainly marked as such, and must not be
19  misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source distribution.
22 
23  */
24 
31 #ifndef __SFTOOLS_CURVE_HPP__
32 #define __SFTOOLS_CURVE_HPP__
33 
34 #include <SFML/Graphics.hpp>
35 #include <cmath>
36 
37 namespace sftools
38 {
44  typedef std::function<sf::Vector2f(float)> CurveFunction;
45 
54  struct CurveInfo
55  {
56  public:
66  static CurveInfo elipse(float a, float b, float begin, float end, unsigned int pointCount)
67  {
68  auto f = [a, b](float t) -> sf::Vector2f {
69  return { a * std::cos(t), b * std::sin(t) };
70  };
71 
72  return { f, begin, end, pointCount };
73  }
74 
83  static CurveInfo circle(float r, float begin, float end, unsigned int pointCount)
84  {
85  return elipse(r, r, begin, end, pointCount);
86  }
87 
97  static CurveInfo sine(float a, float b, float begin, float end, unsigned int pointCount)
98  {
99  auto f = [a, b](float t) -> sf::Vector2f {
100  return { a * t, b * std::sin(t) };
101  };
102 
103  return { f, begin, end, pointCount };
104  }
105 
115  static CurveInfo cosine(float a, float b, float begin, float end, unsigned int pointCount)
116  {
117  auto f = [a, b](float t) -> sf::Vector2f {
118  return { a * t, b * std::cos(t) };
119  };
120 
121  return { f, begin, end, pointCount };
122  }
123 
132  static CurveInfo astroid(float a, float begin, float end, unsigned int pointCount)
133  {
134  auto f = [a](float t) -> sf::Vector2f {
135  return { a * std::pow(std::cos(t), 3), a * std::pow(std::sin(t), 3) };
136  };
137 
138  return { f, begin, end, pointCount };
139  }
140 
141  public:
143  float begin;
144  float end;
145  unsigned int pointCount;
146  };
147 
159  class Curve : public sf::Drawable,
160  public sf::Transformable
161  {
162  public:
170  Curve(CurveInfo info, sf::Color color = sf::Color::Black, float thickness = 1.f)
171  : m_vertices(sf::PrimitiveType::TrianglesStrip)
172  , m_info(info)
173  , m_color(color)
174  , m_thickness(thickness)
175  {
176  update();
177  }
178 
182  virtual ~Curve()
183  {
184  // Nothing to do here.
185  }
186 
198  sf::FloatRect getLocalBounds() const
199  {
200  return m_vertices.getBounds();
201  }
202 
214  sf::FloatRect getGlobalBounds() const
215  {
216  return getTransform().transformRect(getLocalBounds());
217  }
218 
224  CurveInfo const& getInfo() const
225  {
226  return m_info;
227  }
228 
234  void setInfo(CurveInfo const& info)
235  {
236  m_info = info;
237  update();
238  }
239 
245  sf::Color getColor() const
246  {
247  return m_color;
248  }
249 
255  void setColor(sf::Color color)
256  {
257  m_color = color;
258  updateColorOnly();
259  }
260 
266  float getThickness() const
267  {
268  return m_thickness;
269  }
270 
276  void setThickness(float thickness)
277  {
278  m_thickness = thickness;
279  update();
280  }
281 
282  protected:
289  virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
290  {
291  states.transform *= getTransform();
292  target.draw(m_vertices, states);
293  }
294 
295  private:
299  void update()
300  {
301  // Compute the normalised normal of [a, b] segment.
302  // Note: we do it here just to reduce a little bit the inter-dependencies.
303  auto const normalisedNormal = [](sf::Vector2f const& a, sf::Vector2f const& b) -> sf::Vector2f
304  {
305  sf::Vector2f const v = a - b;
306  sf::Vector2f const n = { v.y, -v.x };
307  float const length = std::sqrt(n.x * n.x + n.y * n.y);
308 
309  return length != 0.0 ? n / length : n;
310  };
311 
312  m_vertices.clear();
313  m_vertices.resize(m_info.pointCount * 2 - 1); // Count points for the curve and (count - 1) points for the outline
314  // (that is, one point for the outline between each point of the curve)
315 
316  // Compute the points of the curve
317  float const step = (m_info.end - m_info.begin) / m_info.pointCount;
318  for (unsigned int i = 0; i < m_info.pointCount; ++i) {
319  float const t = m_info.begin + step * i;
320  m_vertices[i * 2] = { m_info.f(t), m_color }; // one vertex over two because of the outline
321  }
322 
323  // Compute the points of the outline
324  for (unsigned int i = 1; i < m_info.pointCount * 2 - 1; i += 2) {
325  // Compute the normal of the two points (p0 and p2) of the curve that are next to this outline point (p1)
326  sf::Vector2f const& p0 = m_vertices[i - 1].position;
327  sf::Vector2f const& p2 = m_vertices[i + 1].position;
328  sf::Vector2f const n = normalisedNormal(p0, p2);
329  sf::Vector2f const m = (p0 + p2) / 2.f;
330  sf::Vector2f const p1 = m + n * m_thickness;
331 
332  m_vertices[i] = { p1, m_color };
333  }
334  }
335 
341  void updateColorOnly()
342  {
343  for (unsigned int i = 0; i < m_vertices.getVertexCount(); ++i) {
344  m_vertices[i].color = m_color;
345  }
346  }
347 
348  private:
349  sf::VertexArray m_vertices;
350  CurveInfo m_info;
351  sf::Color m_color;
352  float m_thickness;
353  };
354 }
355 
356 #endif // __SFTOOLS_CURVE_HPP__