You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
3.4 KiB
C++

#include "SigmaView.h"
#include "ItemCurveArc.h"
#include "ItemCurveEdit.h"
#include "ItemSelect.h"
#include "clipper2/clipper.h"
enum class BooleanOp
{
Difference = 0,
Intersect = 1,
Union = 2,
Xor = 3,
};
/**
* 多边形处理类
*/
class PolygonCombiner
{
public:
/**
* 差集
*
* \param first 第一条闭合曲线
* \param second 第二条闭合曲线
* \return 返回合并后的曲线
*/
static std::vector<std::unique_ptr<CCurveEx>> Difference(const std::vector<CCurveEx*>& first, const std::vector<CCurveEx*>& second)
{
return Execute(first, second, BooleanOp::Difference);
}
/**
* 交集
*
* \param first 第一条闭合曲线
* \param second 第二条闭合曲线
* \return 返回合并后的曲线
*/
static std::vector<std::unique_ptr<CCurveEx>> Intersect(const std::vector<CCurveEx*>& first, const std::vector<CCurveEx*>& second)
{
return Execute(first, second, BooleanOp::Intersect);
}
/**
* 并集
*
* \param first 第一条闭合曲线
* \param second 第二条闭合曲线
* \return 返回合并后的曲线
*/
static std::vector<std::unique_ptr<CCurveEx>> Union(const std::vector<CCurveEx*>& first, const std::vector<CCurveEx*>& second)
{
return Execute(first, second, BooleanOp::Union);
}
/**
* 异或
*
* \param first 第一条闭合曲线
* \param second 第二条闭合曲线
* \return 返回合并后的曲线
*/
static std::vector<std::unique_ptr<CCurveEx>> Xor(const std::vector<CCurveEx*>& first, const std::vector<CCurveEx*>& second)
{
return Execute(first, second, BooleanOp::Xor);
}
static Clipper2Lib::PathD CurveToPathD(const CCurveEx* curve)
{
Clipper2Lib::PathD path;
path.reserve(curve->num);
for (int i = 0; i < curve->num; i++)
{
path.push_back({ curve->x[i], curve->y[i] });
}
return path;
}
static Clipper2Lib::PathsD CurvesToPathsD(const std::vector<CCurveEx*>& curves)
{
Clipper2Lib::PathsD path;
path.reserve(curves.size());
for (auto* pCurve : curves)
{
if (pCurve == nullptr)
{
continue;
}
path.emplace_back(CurveToPathD(pCurve));
}
return path;
}
static std::unique_ptr<CCurveEx> PathDToCurve(const Clipper2Lib::PathD& path)
{
auto pCurve = std::make_unique<CCurveEx>();
pCurve->Create(path.size() + 1);
size_t i = 0;
for (; i < path.size(); i++)
{
pCurve->x[i] = path[i].x;
pCurve->y[i] = path[i].y;
}
pCurve->x[i] = path[0].x;
pCurve->y[i] = path[0].y;
return pCurve;
}
static std::vector<std::unique_ptr<CCurveEx>> Execute(const std::vector<CCurveEx*>& first, const std::vector<CCurveEx*>& second, BooleanOp op)
{
auto firstPaths = CurvesToPathsD(first);
auto secondPaths = CurvesToPathsD(second);
auto solution = Clipper2Lib::PathsD();
switch (op)
{
case BooleanOp::Difference:
solution = Clipper2Lib::Difference(firstPaths, secondPaths, Clipper2Lib::FillRule::NonZero);
break;
case BooleanOp::Intersect:
solution = Clipper2Lib::Intersect(firstPaths, secondPaths, Clipper2Lib::FillRule::NonZero);
break;
case BooleanOp::Union:
solution = Clipper2Lib::Union(firstPaths, secondPaths, Clipper2Lib::FillRule::NonZero);
break;
case BooleanOp::Xor:
solution = Clipper2Lib::Xor(firstPaths, secondPaths, Clipper2Lib::FillRule::NonZero);
break;
default:
break;
}
if (solution.empty())
{
return {};
}
std::vector<std::unique_ptr<CCurveEx>> result;
for (auto& path : solution)
{
result.push_back(PathDToCurve(path));
}
return result;
}
};