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

Author Topic: [SOLVED] overlapping circle shapes  (Read 8362 times)

0 Members and 2 Guests are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
[SOLVED] overlapping circle shapes
« on: July 14, 2016, 05:15:46 am »
Hi Folks,

I am trying to setup a hexGrid type game and I am currently playing with different ways to do it.
Right now I got a simple class which has a sf::CircleShape that has 6 points to make it a Hexagon. I also have a vector of the sf::CircleShape for the grid.

Now I got the grid drawing fine and I am now trying to detect the hex that the mouse is in. I've written a simple method that is called each time the mouse is moved. It basically checks the globalBounds of each sf::Circleshape to see if the mouse position is contained within that circleShape. If yes then it changes the fillColour of the sf::Circleshape.

Now this is working ok, except when the mouse is hovering near the edge of some grids, then both get highlighted white, i.e. the mouse is within both circleshapes.

Is this because there is a bounding box around the sf::CircleShape which is larger that the displayed shape? Is there a way to resolve this?

I have put down a full working example that should be able to be compile and run on it's own.

hexGrid.h
#ifndef HEXGRID_HPP
#define HEXGRID_HPP

#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>

using namespace std;

class hexgrid : public sf::Drawable
{
        public:
                hexgrid(sf::RenderWindow& window);
                ~hexgrid();

                void draw(sf::RenderTarget& target, sf::RenderStates states) const;

                bool chkHexGridWithMousePos(sf::Vector2f passed_mousePos);
                bool isMouseContainsHexagaon(sf::CircleShape *hexPtr, sf::Vector2f passed_mousePos);

                enum hexStyle
                {
                        translucent,
                        colorful,
                        green,
                        cyan
                };

        private:
                sf::CircleShape hexagon;
                std::vector<sf::CircleShape> hexaGrid;
};


#endif // HEXGRID_HPP
 

hexGrid.cpp
#include "hexgrid.h"

hexgrid::hexgrid(sf::RenderWindow& window)
{
        //set up background elements
        hexagon.setRadius(window.getSize().x / 16.f);
        hexagon.setPointCount(6);
        hexagon.setFillColor(sf::Color(150, 50, 250));
        hexagon.setOutlineThickness(2);
        hexagon.setOutlineColor(sf::Color(250, 150, 100));
        hexagon.setOrigin(hexagon.getGlobalBounds().width / 2.f, hexagon.getGlobalBounds().height / 2.f);

        std::vector<sf::ConvexShape>::iterator hexit;
        float xpos = 0, ypos = 0;

        for (int y = 0; y < 12; y++)
        {
                if (y == 0)
                {
                        ypos = y * hexagon.getGlobalBounds().height;
                }
                else
                {
                        ypos = ypos + (hexagon.getGlobalBounds().height - (hexagon.getGlobalBounds().height * 0.25f));
                }

                for (int x = 0; x < 12; x++)
                {
                        if (y % 2 == 0)
                        {
                                xpos = x * hexagon.getGlobalBounds().width;
                        }
                        else
                        {
                                xpos = (x * hexagon.getGlobalBounds().width) + (hexagon.getGlobalBounds().width * 0.5f);
                        }
                        hexagon.setPosition(xpos, ypos);
                        hexaGrid.push_back(hexagon);
                }
        }
}

hexgrid::~hexgrid()
{

}

void hexgrid::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        std::vector<sf::CircleShape>::const_iterator hexit;
        for (hexit = hexaGrid.begin(); hexit != hexaGrid.end(); ++hexit)
        {
                target.draw(*hexit, states);
        }
}

bool hexgrid::chkHexGridWithMousePos(sf::Vector2f passed_mousePos)
{
        bool returnVal = false;
       
        for (int i = 0; i < hexaGrid.size(); i++)
        {
                if (isMouseContainsHexagaon(&hexaGrid[i], passed_mousePos))
                {
                        returnVal = true;
                }
        }

        return returnVal;
}

bool hexgrid::isMouseContainsHexagaon(sf::CircleShape *hexPtr, sf::Vector2f passed_mousePos)
{
        if (hexPtr->getGlobalBounds().contains(passed_mousePos))
        {
                hexPtr->setFillColor(sf::Color(255, 255, 255));
                return true;
        }
        else
        {
                hexPtr->setFillColor(sf::Color(150, 50, 250));
                return false;
        }
}
 

main
#include <iostream>
#include <SFML/Graphics.hpp>
#include "hexgrid.h"

int main()
{
        sf::ContextSettings settings;
        settings.antialiasingLevel = 8;

        sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Hexgrid Example", sf::Style::Default, settings);

        hexgrid grid(window);
               
        sf::Event e;
        bool running = true;
        while (running)
        {
                while (window.pollEvent(e))
                {
                        if (e.type == sf::Event::Closed)
                        {
                                window.close();
                                return 0;
                        }

                        if (e.type == sf::Event::MouseMoved)
                        {
                               
                                grid.chkHexGridWithMousePos(sf::Vector2f(e.mouseMove.x, e.mouseMove.y));
                        }
                }
                window.clear();
                window.draw(grid);
                window.display();
               
        }
        return 0;
}
 
« Last Edit: July 29, 2016, 12:45:46 am by starkhorn »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: overlapping circle shapes
« Reply #1 on: July 14, 2016, 08:31:26 am »
Quote
Is this because there is a bounding box around the sf::CircleShape which is larger that the displayed shape?
getGlobalBounds() returns a bounding rectangle, so yes it is larger than your hexagon.

Quote
Is there a way to resolve this?
Implement your own "point in hexagon" test. There are two common ways of finding if a point is inside a convex polygon, you should easily find them with Google ;)
Laurent Gomila - SFML developer

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: overlapping circle shapes
« Reply #2 on: July 28, 2016, 12:27:05 am »
Implement your own "point in hexagon" test. There are two common ways of finding if a point is inside a convex polygon, you should easily find them with Google ;)

Ok thanks. I see the easiest one is the ray casting algorithm, i.e. check how many times a straight line from that point intersects the polygon's edge.

And there is the first stumbling block that I hit, how can I determine the edges of a sf::Circleshape? I am assuming there is no getEdges method in sf::circleshape or even getAllPixels method? (I could not see anything in documentation).

I've gone through each point of the shape and worked out the angle between each connecting point as below.

However I am confused as to how I then determine all of the the points along the edge. Without being able to determine that then I do not see how I can implement a ray casting algorithm

bool hexgrid::isMouseWithinHexagon(sf::CircleShape *hexPtr, sf::Vector2f passed_mousePos)
{
        bool returnVal = true;
        sf::Vector2f point, nextPoint;
        const sf::Transform transformedVals = hexPtr->getTransform();
        float angle = 0;
       
        for (int i = 0; i < hexPtr->getPointCount(); i++)
        {
                point = transformedVals.transformPoint(hexPtr->getPoint(i));
               
                if (i + 1 < hexPtr->getPointCount())
                {
                        nextPoint = transformedVals.transformPoint(hexPtr->getPoint(i + 1));
                }
                else
                {
                        nextPoint = transformedVals.transformPoint(hexPtr->getPoint(0));
                }              
               
                angle = atan2(point.y - nextPoint.y, point.x - nextPoint.x);
                angle = (angle * 180) / PI;    
        }

        return returnVal;
}
 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: overlapping circle shapes
« Reply #3 on: July 28, 2016, 01:01:23 am »
Are you testing to see if a point is inside a circle, not a hexagon? Testing a circle is incredibly simple: test the distance between the point and the circle's centre - if that distance is greater than the circle's radius, it's outside.

p.s I just realised that you might be using circle with a low number of points to represent a hexagon. You might find what you need here:
http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1CircleShape.php#ac7452005d91cefd5c6805281a8fbc1b3
« Last Edit: July 28, 2016, 01:03:46 am by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: overlapping circle shapes
« Reply #4 on: July 28, 2016, 01:04:08 am »
Are you testing to see if a point is inside a circle, not a hexagon? Testing a circle is incredibly simple: test the distance between the point and the circle's centre - if that distance is greater than the circle's radius, it's outside.

I am trying to test if the point is inside a hexagon. So code from first post you see I have a sf::CircleShape defined with 6 points.

sf::CircleShape hexagon;
....
....
....
hexagon.setPointCount(6);
 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: overlapping circle shapes
« Reply #5 on: July 28, 2016, 02:07:44 am »
I am trying to test if the point is inside a hexagon. So code from first post you see I have a sf::CircleShape defined with 6 points.
Yes, I realised that (within the same post!):
I just realised that you might be using circle with a low number of points to represent a hexagon. You might find what you need here:
http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1CircleShape.php#ac7452005d91cefd5c6805281a8fbc1b3

how can I determine the edges of a sf::Circleshape? I am assuming there is no getEdges method in sf::circleshape or even getAllPixels method? (I could not see anything in documentation).
[nobbc][...]
However I am confused as to how I then determine all of the the points along the edge.
Are you splitting an edge into multiple points? You only need two points (which you can get from the circle) to define a line and you use this line to see if the testing line crosses that line.

I see the easiest one is the ray casting algorithm, i.e. check how many times a straight line from that point intersects the polygon's edge.
It might be worth considering specific hexagon detection algorithms. One of those being splitting the hexagon into triangles as they're pretty easy to test if a point is inside it.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: overlapping circle shapes
« Reply #6 on: July 28, 2016, 02:28:11 am »
Are you splitting an edge into multiple points? You only need two points (which you can get from the circle) to define a line and you use this line to see if the testing line crosses that line.

No the edges are not split into multiple points. Yeah I am going through the output of sf::CircleShape->getPoint method to get points of the hexagon. (see below)

I get the points that are next to each other and work out the angle and distance between those two points.

My question/problem is I don't know how to get all of the x,y co-ordinates of the line/edge between those two points. So how can I determine the edge between those two points when I have the distance and angle?


bool hexgrid::isMouseWithinHexagon(sf::CircleShape *hexPtr, sf::Vector2f passed_mousePos)
{
    bool returnVal = true;
    sf::Vector2f point, nextPoint;
    const sf::Transform transformedVals = hexPtr->getTransform();
    float angle = 0;
   
    for (int i = 0; i < hexPtr->getPointCount(); i++)
    {
        point = transformedVals.transformPoint(hexPtr->getPoint(i));
       
        if (i + 1 < hexPtr->getPointCount())
        {
            nextPoint = transformedVals.transformPoint(hexPtr->getPoint(i + 1));
        }
        else
        {
            nextPoint = transformedVals.transformPoint(hexPtr->getPoint(0));
        }      
       
        angle = atan2(point.y - nextPoint.y, point.x - nextPoint.x);
        angle = (angle * 180) / PI;
    }

    return returnVal;
}

 

It might be worth considering specific hexagon detection algorithms. One of those being splitting the hexagon into triangles as they're pretty easy to test if a point is inside it.

Hmm ok, won't I have the same issue? how to determine the edge of the sf::CircleShape that has 3 points ?

Oh ok, I see what you mean, I guess I should have googled more before replying. :) So I will try to to do something like the below link to calc the area of the triangle?

http://www.geeksforgeeks.org/check-whether-a-given-point-lies-inside-a-triangle-or-not/
« Last Edit: July 28, 2016, 02:54:48 am by starkhorn »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: overlapping circle shapes
« Reply #7 on: July 28, 2016, 02:51:39 pm »
Yes, the point-in-triangle method was one of the ones I was suggesting.

how to get all of the x,y co-ordinates of the line/edge between those two points.
This is splitting the edge into multiple points (it looks like you're aiming to split into points for each drawn pixel). However, you don't need those points to calculate if a line crosses another. Remember also that the line/edge isn't made up of pixels; it's a mathematical line of infinite resolution between two specified points that is only turned into pixels (rendered) so that we can see a visual representation of that line.

By the way, if you were using my Plinth library, this would be a lot simpler; it has functions for calculating if lines cross and for calculating if a point is inside a polygon ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: overlapping circle shapes
« Reply #8 on: July 28, 2016, 10:12:17 pm »
However, you don't need those points to calculate if a line crosses another.

Oh ok, I guess that is what I am trying to achieve then. I just assumed to implement ray casting algorithm that I would need to know the pixels of the edge of the polygon.

By the way, if you were using my Plinth library, this would be a lot simpler; it has functions for calculating if lines cross and for calculating if a point is inside a polygon ;)

Oh wow, ok - I obviously had no idea about this library. I will download and check it out.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: overlapping circle shapes
« Reply #9 on: July 29, 2016, 12:44:31 am »
Ok thanks Hapax, the Plinth lib works perfectly. I am currently stepping through the methods now to try to understand the CCW method.....as you can probably tell geometry was never my strong point. :)

Thanks again.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: [SOLVED] overlapping circle shapes
« Reply #10 on: July 29, 2016, 02:57:35 pm »
You're welcome!

"CCW" = Counter-clockwise ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

jackhunting

  • Newbie
  • *
  • Posts: 1
  • Loves compound bow hunting
    • View Profile
    • Hunting Activity Blog
    • Email
Re: [SOLVED] overlapping circle shapes
« Reply #11 on: July 30, 2016, 11:20:40 am »
a useful topic for me. I'm starting to learn.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: [SOLVED] overlapping circle shapes
« Reply #12 on: July 30, 2016, 05:52:30 pm »
I suppose I should mention that it's technically only anti-clockwise in a standard co-ordinate system, not one with an inverted y axis as SFML uses it so the code may not make full sense if you expect it to be working with certain directions.

There are other methods to check if lines cross; this is just the one that I decided to implement. Remember that you could just use the library; it saves time learning everything about stuff you might not specifically need to know  ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything