判断点是否在有限长线段或直线上
// 判断点是否在有限长线段或直线上
const bool Geo::is_inside(const Point &point, const Line &line, const bool infinite)
{
return Geo::distance(point, line.front(), line.back(), infinite) < Geo::EPSILON;
}
// 判断点是否在有限长线段或直线上
const bool Geo::is_inside(const Point &point, const Point &start, const Point &end, const bool infinite)
{
return Geo::distance(point, start, end, infinite) < Geo::EPSILON;
}
判断点是否在多段线上
// 判断点是否在多段线上
const bool Geo::is_inside(const Point &point, const Polyline &polyline)
{
for (size_t i = 1, count = polyline.size(); i < count; ++i)
{
if (Geo::is_inside(point, polyline[i-1], polyline[i]))
{
return true;
}
}
return false;
}
判断点是否在多边形内
判断点是否在多边形内:coincide决定是否包含点在多边形上的情况。实现采用射线法。
// 判断点是否在多边形内,coincide决定是否包含点在多边形上的情况
const bool Geo::is_inside(const Point &point, const Polygon &polygon, const bool coincide)
{
if (!polygon.empty() && Geo::is_inside(point, polygon.bounding_rect(), coincide))
{
if (coincide)
{
for (size_t i = 1, len = polygon.size(); i < len; ++i)
{
if (Geo::is_inside(point, polygon[i-1], polygon[i]))
{
return true;
}
}
}
else
{
for (size_t i = 1, len = polygon.size(); i < len; ++i)
{
if (Geo::is_inside(point, polygon[i-1], polygon[i]))
{
return false;
}
}
}
double x = (-DBL_MAX);
std::vector<Geo::MarkedPoint> points;
for (const Geo::Point &p : polygon)
{
x = std::max(x, p.x);
points.emplace_back(p.x, p.y);
}
// if (polygon.area() < 0)
// {
// std::reverse(points.begin(), points.end());
// }
Geo::Point temp, end(x + 80, point.y); // 找到交点并计算其几何数
for (size_t i = 1, count = points.size(); i < count; ++i)
{
if (!Geo::is_parallel(point, end, points[i], points[i - 1]) &&
Geo::is_intersected(point, end, points[i], points[i - 1], temp))
{
points.insert(points.begin() + i++, MarkedPoint(temp.x, temp.y, false));
++count;
if (Geo::cross(temp, end, points[i], points[i - 1]) >= 0)
{
points[i - 1].value = -1;
}
else
{
points[i - 1].value = 1;
}
}
}
if (points.size() == polygon.size()) // 无交点
{
return false;
}
// 去除重复交点
for (size_t count, j, i = points.size() - 1; i > 0; --i)
{
count = points[i].original ? 0 : 1;
for (j = i; j > 0; --j)
{
if (std::abs(points[i].x - points[j - 1].x) > Geo::EPSILON ||
std::abs(points[i].y - points[j - 1].y) > Geo::EPSILON)
{
break;
}
if (!points[j - 1].original)
{
++count;
}
}
if (count < 2)
{
continue;
}
int value = 0;
for (size_t k = i; k > j; --k)
{
if (!points[k].original)
{
value += points[k].value;
}
}
if (!points[j].original)
{
value += points[j].value;
}
if (value == 0)
{
for (size_t k = i; k > j; --k)
{
if (!points[k].original)
{
points.erase(points.begin() + k);
}
}
if (!points[j].original)
{
points.erase(points.begin() + j);
}
}
else
{
bool flag = false;
for (size_t k = i; k > j; --k)
{
flag = (flag || points[k].original);
points.erase(points.begin() + k);
}
points[j].value = value;
points[j].original = (flag || points[j].original);
}
i = j > 0 ? j : 1;
}
// 处理重边上的交点
for (size_t i = 0, j = 1, count = points.size(); j < count; i = j)
{
while (i < count && points[i].value == 0)
{
++i;
}
j = i + 1;
while (j < count && points[j].value == 0)
{
++j;
}
if (j >= count)
{
break;
}
if (polygon.index(points[i]) == SIZE_MAX || polygon.index(points[j]) == SIZE_MAX)
{
continue;
}
if (points[i].value > 0 && points[j].value > 0)
{
points.erase(points.begin() + j);
--count;
}
else if (points[i].value < 0 && points[j].value < 0)
{
points.erase(points.begin() + i);
--count;
}
else
{
points.erase(points.begin() + j--);
points.erase(points.begin() + i);
--count;
--count;
}
}
return std::count_if(points.begin(), points.end(), [](const Geo::MarkedPoint &p) { return p.value != 0; }) % 2 == 1;
}
else
{
return false;
}
}
判断点是否在AABB矩形内
判断点是否在AABB矩形内:coincide决定是否包含点在AABB矩形上的情况。
// 判断点是否在AABB矩形内,coincide决定是否包含点在AABB矩形上的情况
const bool Geo::is_inside(const Point &point, const AABBRect &rect, const bool coincide)
{
if (rect.empty())
{
return false;
}
const double x = point.x, y = point.y;
if (coincide)
{
return rect.left() <= x && x <= rect.right() && rect.bottom() <= y && y <= rect.top();
}
else
{
return rect.left() < x && x < rect.right() && rect.bottom() < y && y < rect.top();
}
}
判断点是否在圆内
判断点是否在圆内:coincide决定是否包含点在圆上的情况。
// 判断点是否在圆内,coincide决定是否包含点在圆上的情况
const bool Geo::is_inside(const Point &point, const Circle &circle, const bool coincide)
{
if (circle.empty())
{
return false;
}
if (coincide)
{
return Geo::distance(point, circle.center()) <= circle.radius();
}
else
{
return Geo::distance(point, circle.center()) < circle.radius();
}
}
判断点是否在三角形内
判断点是否在三角形内:coincide决定是否包含点在三角形上的情况。实现采用同向法。
// 判断点是否在三角形内,coincide决定是否包含点在三角形上的情况
const bool Geo::is_inside(const Point &point, const Point &point0, const Point &point1, const Point &point2, const bool coincide)
{
if (coincide)
{
const bool a = (point2.x - point.x) * (point0.y - point.y) >= (point0.x - point.x) * (point2.y - point.y);
const bool b = (point0.x - point.x) * (point1.y - point.y) >= (point1.x - point.x) * (point0.y - point.y);
const bool c = (point1.x - point.x) * (point2.y - point.y) >= (point2.x - point.x) * (point1.y - point.y);
return a == b && b == c;
}
else
{
const bool a = (point2.x - point.x) * (point0.y - point.y) > (point0.x - point.x) * (point2.y - point.y);
const bool b = (point0.x - point.x) * (point1.y - point.y) > (point1.x - point.x) * (point0.y - point.y);
const bool c = (point1.x - point.x) * (point2.y - point.y) > (point2.x - point.x) * (point1.y - point.y);
return a == b && b == c;
}
}
// 判断点是否在三角形内,coincide决定是否包含点在三角形上的情况
const bool Geo::is_inside(const Point &point, const Triangle &triangle, const bool coincide)
{
return Geo::is_inside(point, triangle[0], triangle[1], triangle[2], coincide);
}
判断有限长线段是否完全在三角形内
判断有限长线段是否完全在三角形内:线段与三角形相交或有端点在三角形上均不算在三角形内部。
// 判断有限长线段是否完全在三角形内,线段与三角形相交或有端点在三角形上均不算在三角形内部
const bool Geo::is_inside(const Point &start, const Point &end, const Triangle &triangle)
{
return Geo::is_inside(start, triangle) && Geo::is_inside(end, triangle);
}
判断一个三角形是否完全在另一个三角形内部
判断一个三角形是否完全在另一个三角形内部:与三角形相交或有顶点在三角形上均不算在三角形内部。
// 判断一个三角形是否完全在另一个三角形内部,与三角形相交或有顶点在三角形上均不算在三角形内部
const bool Geo::is_inside(const Triangle &triangle0, const Triangle &triangle1)
{
return Geo::is_inside(triangle0[0], triangle1) && Geo::is_inside(triangle0[1], triangle1)
&& Geo::is_inside(triangle0[2], triangle1);
}