Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Round Ended Lines  (Read 4100 times)

0 Members and 1 Guest are viewing this topic.

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Round Ended Lines
« on: September 10, 2012, 12:03:05 pm »
Hi there,
I'm trying to implement a class that draws round ended lines. For that I made a class that inherits from sf::Shape. First I thought I implement a class that draws lines. I did that and i works. But now I'm not sure how to put the rounded ends on it. I'm thinking that I have to compute half a circle and just put it on the two end points, but I'm not quiet sure how to compute the "rotation" of the circle. Can somebody point me in the right direction?

Here is my code so far.

Header File:
#ifndef ROUNDENDEDLINE_H
#define ROUNDENDEDLINE_H

#include <SFML/Graphics/Shape.hpp>
#include <cmath>
#include <iostream>


class CRoundendedLine : public sf::Shape
{
public:

    CRoundendedLine(const sf::Vector2f& endPoint = sf::Vector2f(0, 0), const float width = 1.0);

    void setEndPoint(const sf::Vector2f& endPoint);

    void setWidth(const float width);

    virtual unsigned int getPointCount() const;

    virtual sf::Vector2f getPoint(unsigned int index) const;

private :

    sf::Vector2f m_endPoint;
    float m_Width;
};

#endif //ROUNDENDEDLINE_H
 

Implementation:
#include "RoundendedLine.h"

CRoundendedLine::CRoundendedLine(const sf::Vector2f& endPoint, const float width) : m_endPoint (endPoint), m_Width (width)
{
    update();
}

void CRoundendedLine::setEndPoint(const sf::Vector2f& endPoint)
{
    m_endPoint = endPoint;
    update();
}

void CRoundendedLine::setWidth(const float width)
{
    m_Width = width;
    update();
}

unsigned int CRoundendedLine::getPointCount() const
{
    return 4;
}


// Compute the normal of a segment
sf::Vector2f computeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2)
{
    sf::Vector2f normal(p1.y - p2.y, p2.x - p1.x);
    float length = std::sqrt(normal.x * normal.x + normal.y * normal.y);
    if (length != 0.f)
        normal /= length;
    return normal;
}

sf::Vector2f CRoundendedLine::getPoint(unsigned int index) const
{
    sf::Vector2f P1(1.0, 0.0);
    sf::Vector2f P2(m_endPoint + sf::Vector2f(1.0, 0.0) - getPosition());

    // Compute the extrusion direction
    sf::Vector2f Normal = computeNormal(P1, P2);
    Normal *= m_Width / 2;

    switch (index)
    {
        default:
        case 0: return sf::Vector2f(P1 - Normal);
        case 1: return sf::Vector2f(P2 - Normal);
        case 2: return sf::Vector2f(P2 + Normal);
        case 3: return sf::Vector2f(P1 + Normal);
    }
}
 

Usage:
#include <SFML/Graphics.hpp>
#include "RoundendedLine.h"
#include <iostream>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML works!");

    CRoundendedLine RoundendedLine;
    RoundendedLine.setPosition(200,200);
    RoundendedLine.setEndPoint(sf::Vector2f(270, 300));
    RoundendedLine.setWidth(11);

    sf::Vertex* startVertex =  new sf::Vertex(sf::Vector2f(200, 200), sf::Color::Red);
    sf::Vertex* endVertex =  new sf::Vertex(sf::Vector2f(270, 300), sf::Color::Blue);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close Event
            if (event.type == sf::Event::Closed)
                window.close();

            // Escape key pressed
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
                window.close();
        }

        window.clear();
        window.draw(RoundendedLine);
        window.draw(startVertex, 1, sf::Points);
        window.draw(endVertex, 1, sf::Points);
        window.display();
    }

    return 0;
}
 

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Round Ended Lines
« Reply #1 on: September 10, 2012, 12:58:19 pm »
You must first compute the angle of your line (std::atan2(dy, dx)). Then you compute circle points between -Pi/2 + angle and Pi/2 + angle, with a radius of width/2. And that's it :)
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Round Ended Lines
« Reply #2 on: September 10, 2012, 02:56:08 pm »
Aaah thank you very much, for the quick reply! This is what I thought it would be like. I just didn't know how exactly.
I tried to implement it using a vertex array, just to see if the algorithm works. But somehow i can't get it to work... Here is my code:
What am I doing wrong?
    float angle = atan2(0, 100);
    const float radius = 25;
    sf::VertexArray lines(sf::LinesStrip, 16);
    for (int i = 0; i < 15; i++)
    {
        angle = i * ((M_PI / 2 + angle) / 16) - (M_PI / 2 - angle);
        float x = std::cos(angle) * radius;
        float y = std::sin(angle) * radius;

        lines[i].position = sf::Vector2f(radius + x + 100, radius + y + 100);
    }
    lines[15] = lines[0];

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Round Ended Lines
« Reply #3 on: September 10, 2012, 03:11:26 pm »
Without testing, I'd say:
angle = i * M_PI / 15 - M_PI / 2 + angle;
« Last Edit: September 10, 2012, 03:13:17 pm by Laurent »
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Round Ended Lines
« Reply #4 on: September 10, 2012, 03:17:00 pm »
Hmm no that doesn't change anything at all. It still looks completely random...

edit: Well now it looks a little more like a semi circle, but it's still choppy and not round
« Last Edit: September 10, 2012, 03:23:32 pm by Foaly »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Round Ended Lines
« Reply #5 on: September 10, 2012, 03:25:14 pm »
Can you show a screenshot?
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Round Ended Lines
« Reply #6 on: September 10, 2012, 03:39:43 pm »
This is what it looks like:

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Round Ended Lines
« Reply #7 on: September 10, 2012, 03:50:55 pm »
Arf, you have two variables named "angle", that's why the result is messed up ;D

The following code works:
float start = atan2(0, 100);
const float radius = 25;
sf::VertexArray lines(sf::LinesStrip, 16);
for (int i = 0; i < 15; i++)
{
    float angle = i * M_PI / 14 - M_PI / 2 + start;
    float x = std::cos(angle) * radius;
    float y = std::sin(angle) * radius;

    lines[i].position = sf::Vector2f(radius + x + 100, radius + y + 100);
}
lines[15] = lines[0];
« Last Edit: September 10, 2012, 03:52:49 pm by Laurent »
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Round Ended Lines
« Reply #8 on: September 10, 2012, 05:53:54 pm »
Ah that makes sense... Alright it took me some time, but I got it work with my class. Everything is working like a charm now. Thanks again for the help.
Here is my working code:
sf::Vector2f CRoundendedLine::getPoint(unsigned int index) const
{
    sf::Vector2f P1(1.0, 0.0);
    sf::Vector2f P2(m_endPoint + sf::Vector2f(1.0, 0.0) - getPosition());

    sf::Vector2f offset;
    int iFlipDirection;

    if(index < 15)
    {
        offset = P2;
        iFlipDirection = 1;
    }
    else
    {
        offset = P1;
        iFlipDirection = -1;
        index -= 15;
    }

    float start = -atan2(P1.y - P2.y, P2.x - P1.x);

    float angle = index * M_PI / 14 - M_PI / 2 + start;
    float x = std::cos(angle) * m_Width / 2;
    float y = std::sin(angle) * m_Width / 2;

    return sf::Vector2f(offset.x + x * iFlipDirection, offset.y + y * iFlipDirection);
}
 

edit: Would this be something worth uploading to the wiki?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Round Ended Lines
« Reply #9 on: September 10, 2012, 08:17:20 pm »
Quote
Would this be something worth uploading to the wiki?
I think so :)
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Round Ended Lines
« Reply #10 on: September 10, 2012, 08:47:14 pm »
Great!
It's done! https://github.com/SFML/SFML/wiki/Round-Ended-Lines
I'm glad i was able to contribute something to the wiki :)

Also I made a new Drawable section on the Source Code Page, because a couple source codes seemed to be misplaced in the Game Engine category.