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++
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;
|
|
}
|
|
};
|