I am trying to make a line between two points, I am using sf::VertexArray shape(sf::Quads, 4);
for this.
This is my entire draw
function:
void Stick::draw(sf::RenderTarget& target, sf::RenderStates states) const {
sf::VertexArray shape(sf::Quads, 4);
sf::Vector2f p1Pos = this->p1->getPosition();
sf::Vector2f p2Pos = this->p2->getPosition();
shape[0].position = sf::Vector2f(p1Pos.x 10.f, p1Pos.y 10.f);
shape[1].position = sf::Vector2f(p1Pos.x - 10.f, p1Pos.y - 10.f);
shape[2].position = sf::Vector2f(p2Pos.x - 10.f, p2Pos.y - 10.f);
shape[3].position = sf::Vector2f(p2Pos.x 10.f, p2Pos.y 10.f);
shape[0].color = sf::Color::Green;
shape[1].color = sf::Color::Green;
shape[2].color = sf::Color::Green;
shape[3].color = sf::Color::Green;
target.draw(shape, states);
}
p1Pos
and p2Pos
are the center coordinates of the points.
What this gets me is a line which obviously won't work with moving objects, since the corner points of the rectangles are fixed, here's some examples: (the red dot isn't moving while the white one is in this example)
I would like to implement a solution so that the 'Stick' (rectangle) works regardless of the positions of the two points, and I will later on be adding some sort of onClick event for the sticks, so that I can delete them by clicking on them, so the solution would need to be compatible with that as well... Thanks!
CodePudding user response:
You can find the normal of the line. This can be done by subtracting the positions p1Pos
and p2Pos
(and flipping either sign of x or y to get a 90° rotation) and dividing that by the length of the line. The length of the line can be found via Pythagoras theorem, since it can be thought of as the hypotenuse of a right triangle.
auto diff = p1Pos - p2Pos;
auto length = std::sqrt(diff.x * diff.x diff.y * diff.y);
auto normal = sf::Vector2f(p1Pos.y - p2Pos.y, p2Pos.x - p1Pos.x) / length;
auto thickness = 15.0f;
shape[0].position = sf::Vector2f(p1Pos.x normal.x * thickness, p1Pos.y normal.y * thickness);
shape[1].position = sf::Vector2f(p1Pos.x - normal.x * thickness, p1Pos.y - normal.y * thickness);
shape[2].position = sf::Vector2f(p2Pos.x - normal.x * thickness, p2Pos.y - normal.y * thickness);
shape[3].position = sf::Vector2f(p2Pos.x normal.x * thickness, p2Pos.y normal.y * thickness);
CodePudding user response:
If you need to connect points (x1, y1) and (x2, y2) with a "thick line" (i.e. a rectangle), the vertices can be found by first calculating the line connecting points 1, 2. Then you calculate the normals to that line, passing from points 1 and 2. Your connecting line has an angular coefficient of (y2-y1)/(x2-x1), the normals will have (x2-x1)/(y2-y1).
Your four vertices are then on those two lines, at d/2 distance from points 1 and 2 respectively (d being the thickness of the rectangle). The cases where x1 = x2 or y1 = y2 are special since either the connecting line or its normals will have infinite angular coefficient.
There are several questions related to this problem - this is one.
CodePudding user response:
The concept you are looking for is a normal vector:
sf::Vector2f p1ToP2{p1Pos - p2Pos};
sf::Vector2f normal{p1ToP2.y, -p1ToP2.x}; // normal is now perpendicular to p1ToP2
normal /= sqrt(pow(normal.x, 2) pow(normal.y, 2)); // normal is now of magnitude 1
normal *= 5; // ten pixels on each side
and then your four corners are: { p1Pos normal, p1Pos - normal, p2Pos - normal, p2Pos normal }
CodePudding user response:
If you’re able to get the rectangle with square corners, you may need to include the corner calculation every time your points will move, relative to one another
So for each movement your calculations would look something like:
- Step 1: figure out the angle between points A,B (using trigonometry) -> call it theta.
- Step 2: the new corners will be at /- 90 deg. from theta, 2r from the respective points.
So for example:
- If theta is 45 (like your first example), your ends will extend towards -45(or 315) and 135.
- if theta is 102.5, your ends will extend towards 12.5 and 192.5.