Загрузка данных
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <iostream>
struct Point
{
float x, y;
Point() = default;
Point(float X, float Y)
: x(X), y(Y)
{
}
Point operator+(const Point& other) const
{
return {x + other.x, y + other.y};
}
Point operator-(const Point& other) const
{
return {x - other.x, y - other.y};
}
Point operator*(float v) const
{
return {x * v, y * v};
}
};
float cross(const Point& a, const Point& b)
{
return a.x * b.y - a.y * b.x;
}
bool segmentIntersection(
Point p1,
Point p2,
Point q1,
Point q2,
Point& intersection)
{
Point r = p2 - p1;
Point s = q2 - q1;
float rxs = cross(r, s);
if (fabs(rxs) < 1e-6f)
return false;
float t = cross(q1 - p1, s) / rxs;
float u = cross(q1 - p1, r) / rxs;
if (t >= 0 && t <= 1 && u >= 0 && u <= 1)
{
intersection = p1 + r * t;
return true;
}
return false;
}
bool inside(Point p, sf::FloatRect rect)
{
return p.x >= rect.left &&
p.x <= rect.left + rect.width &&
p.y >= rect.top &&
p.y <= rect.top + rect.height;
}
std::vector<Point> clipPolygon(
const std::vector<Point>& poly,
sf::FloatRect rect)
{
std::vector<Point> output = poly;
auto clipEdge = [&](auto insideFunc, auto intersectFunc)
{
std::vector<Point> input = output;
output.clear();
if (input.empty())
return;
Point S = input.back();
for (auto& E : input)
{
bool Ein = insideFunc(E);
bool Sin = insideFunc(S);
if (Ein)
{
if (!Sin)
output.push_back(intersectFunc(S, E));
output.push_back(E);
}
else if (Sin)
{
output.push_back(intersectFunc(S, E));
}
S = E;
}
};
clipEdge(
[&](Point p)
{
return p.x >= rect.left;
},
[&](Point s, Point e)
{
float t = (rect.left - s.x) / (e.x - s.x);
return Point(
rect.left,
s.y + (e.y - s.y) * t);
});
clipEdge(
[&](Point p)
{
return p.x <= rect.left + rect.width;
},
[&](Point s, Point e)
{
float x = rect.left + rect.width;
float t = (x - s.x) / (e.x - s.x);
return Point(
x,
s.y + (e.y - s.y) * t);
});
clipEdge(
[&](Point p)
{
return p.y >= rect.top;
},
[&](Point s, Point e)
{
float t = (rect.top - s.y) / (e.y - s.y);
return Point(
s.x + (e.x - s.x) * t,
rect.top);
});
clipEdge(
[&](Point p)
{
return p.y <= rect.top + rect.height;
},
[&](Point s, Point e)
{
float y = rect.top + rect.height;
float t = (y - s.y) / (e.y - s.y);
return Point(
s.x + (e.x - s.x) * t,
y);
});
return output;
}
sf::ConvexShape makeShape(
const std::vector<Point>& pts,
sf::Color color)
{
sf::ConvexShape shape;
shape.setPointCount(pts.size());
for (size_t i = 0; i < pts.size(); ++i)
{
shape.setPoint(i, sf::Vector2f(pts[i].x, pts[i].y));
}
shape.setFillColor(sf::Color::Transparent);
shape.setOutlineThickness(2);
shape.setOutlineColor(color);
return shape;
}
int main()
{
sf::RenderWindow window(
sf::VideoMode(1000, 700),
"Weiler-Atherton");
std::vector<Point> plus =
{
{300, 100},
{400, 100},
{400, 250},
{550, 250},
{550, 350},
{400, 350},
{400, 500},
{300, 500},
{300, 350},
{150, 350},
{150, 250},
{300, 250}
};
sf::FloatRect clipRect(250, 180, 300, 220);
bool dragging = false;
sf::Vector2f dragOffset;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
sf::Vector2f mouse(
event.mouseButton.x,
event.mouseButton.y);
if (clipRect.contains(mouse))
{
dragging = true;
dragOffset =
mouse -
sf::Vector2f(
clipRect.left,
clipRect.top);
}
}
}
if (event.type == sf::Event::MouseButtonReleased)
{
dragging = false;
}
if (event.type == sf::Event::MouseMoved)
{
if (dragging)
{
clipRect.left =
event.mouseMove.x - dragOffset.x;
clipRect.top =
event.mouseMove.y - dragOffset.y;
}
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Delete)
{
clipRect = sf::FloatRect(0,0,0,0);
}
}
}
auto clipped = clipPolygon(plus, clipRect);
window.clear(sf::Color::White);
auto originalShape =
makeShape(plus, sf::Color::Blue);
window.draw(originalShape);
if (clipRect.width > 0 && clipRect.height > 0)
{
sf::RectangleShape rectShape(
sf::Vector2f(
clipRect.width,
clipRect.height));
rectShape.setPosition(
clipRect.left,
clipRect.top);
rectShape.setFillColor(
sf::Color::Transparent);
rectShape.setOutlineThickness(2);
rectShape.setOutlineColor(
sf::Color::Red);
window.draw(rectShape);
}
if (!clipped.empty())
{
auto clippedShape =
makeShape(clipped, sf::Color::Green);
clippedShape.setFillColor(
sf::Color(0,255,0,80));
window.draw(clippedShape);
}
window.display();
}
return 0;
}