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.

234 lines
7.5 KiB
C

1 month ago
#pragma once
#include "DrawOperator/CurveEx.h"
#include "clipper2/clipper.h"
#include <memory>
/**
* \brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Clipper2 <EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ù<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD> Clipper2 <EFBFBD>ij<EFBFBD><EFBFBD>ò<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (PathD) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (PathD) ֮<EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD> `CCurveEx` <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
class PolygonUtils
{
public:
/**
* \brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \param subject <EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \param clip <EFBFBD>ü<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \return <EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Intersect(const Clipper2Lib::PathD& subject, const Clipper2Lib::PathD& clip)
{
return Clipper2Lib::Intersect({ subject }, { clip }, Clipper2Lib::FillRule::NonZero);
}
/**
* \brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD>С<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD> `minGap` <EFBFBD>ļ<EFBFBD>϶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \warning ԭʼ<EFBFBD>߼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD>˷<EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> "<EFBFBD><EFBFBD>϶"<EFBFBD><EFBFBD>
* ԭʼ<EFBFBD>߼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `Difference(inflatedOverlap, inflatedUnion)`<EFBFBD><EFBFBD>
* <EFBFBD>ʼ<EFBFBD>շ<EFBFBD><EFBFBD>ؿռ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ `inflatedOverlap` <EFBFBD><EFBFBD><EFBFBD><EFBFBD> `inflatedUnion` <EFBFBD><EFBFBD><EFBFBD>Ӽ<EFBFBD><EFBFBD><EFBFBD>
*
* \param subject <EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \param clip <EFBFBD>ü<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \param minGap <EFBFBD><EFBFBD>Ϊ "<EFBFBD><EFBFBD>϶" <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \return <EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>϶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD FindGapRegions(const Clipper2Lib::PathD& subject, const Clipper2Lib::PathD& clip, double minGap)
{
double delta = minGap / 2.0;
Clipper2Lib::PathsD subjects = { subject };
Clipper2Lib::PathsD clips = { clip };
Clipper2Lib::PathsD inflatedSubjects = Clipper2Lib::InflatePaths(subjects, delta, Clipper2Lib::JoinType::Miter, Clipper2Lib::EndType::Polygon, 2.0);
Clipper2Lib::PathsD inflatedClips = Clipper2Lib::InflatePaths(clips, delta, Clipper2Lib::JoinType::Miter, Clipper2Lib::EndType::Polygon, 2.0);
// 2. <20><><EFBFBD>ͺ<EFBFBD><CDBA><EFBFBD><EFBFBD><EFBFBD>
Clipper2Lib::PathsD inflatedOverlap = Clipper2Lib::Intersect(inflatedSubjects, inflatedClips, Clipper2Lib::FillRule::NonZero);
if (inflatedOverlap.empty())
{
return {};
}
// 3. ԭʼ<D4AD><CABC><EFBFBD><EFBFBD>
Clipper2Lib::PathsD originalUnion = Clipper2Lib::Union(subjects, clips, Clipper2Lib::FillRule::NonZero);
// 4. <20>
return Clipper2Lib::Difference(inflatedOverlap, originalUnion, Clipper2Lib::FillRule::NonZero);
}
/**
* \brief <EFBFBD><EFBFBD> CCurveEx <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>Ϊ Clipper2Lib::PathD ·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* Clipper2 <EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><EFBFBD>պϵ<EFBFBD><EFBFBD>Ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD>˺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `curve->IsClosed()`<EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD><EFBFBD> curve <EFBFBD>DZպϵ<EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> == <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> *ʡ<EFBFBD><EFBFBD>* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD><EFBFBD> curve <EFBFBD>ǿ<EFBFBD><EFBFBD>ŵģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е
*
* \param curve Ҫת<EFBFBD><EFBFBD><EFBFBD><EFBFBD> CCurveEx ָ<EFBFBD>
* \return ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Clipper2Lib::PathD<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathD ConvertCurveToPath(CCurveEx* curve) // <20>Ż<EFBFBD>: pCurve -> curve
{
Clipper2Lib::PathD clipperPath;
clipperPath.reserve(curve->num);
for (int i = 0; i < curve->num; i++)
{
if (i != curve->num - 1)
{
clipperPath.push_back({ curve->x[i], curve->y[i] });
}
else
{
// Clipper2 ·<><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ظ<EFBFBD><D8B8>ıպϵ㡣
// <20><><EFBFBD><EFBFBD> curve <20>DZպϵ<D5BA> (<28><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD> == <20><>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʡ<EFBFBD><CAA1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>
// <20><><EFBFBD><EFBFBD> curve <20>ǿ<EFBFBD><C7BF>ŵģ<C5B5><C4A3><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е
if (!curve->IsClosed())
{
clipperPath.push_back({ curve->x[i], curve->y[i] });
}
}
}
return clipperPath;
}
/**
* \brief <EFBFBD><EFBFBD> Clipper2Lib::PathD ·<EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>Ϊһ<EFBFBD><EFBFBD> *<EFBFBD>պ<EFBFBD>* <EFBFBD><EFBFBD> CCurveEx <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \param clipperPath Ҫת<EFBFBD><EFBFBD><EFBFBD><EFBFBD> Clipper ·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \return ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> CCurveEx <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> `std::unique_ptr`<EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> `clipperPath` <EFBFBD>ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 3<EFBFBD><EFBFBD><EFBFBD>򷵻<EFBFBD> `nullptr`<EFBFBD><EFBFBD>
*/
static std::unique_ptr<CCurveEx> ConvertPathToClosedCurve(const Clipper2Lib::PathD& clipperPath) // <20>Ż<EFBFBD>: path -> clipperPath
{
if (clipperPath.size() < 3)
{
return nullptr;
}
auto curve = std::make_unique<CCurveEx>();
int closedPointCount = clipperPath.size() + 1;
curve->Create(closedPointCount);
curve->num = closedPointCount;
for (size_t i = 0; i < clipperPath.size(); ++i)
{
curve->x[i] = clipperPath[i].x;
curve->y[i] = clipperPath[i].y;
}
// <20><><EFBFBD>Ƶ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>㵽ĩβ<C4A9>Ապ<D4B1>
curve->x[clipperPath.size()] = clipperPath[0].x;
curve->y[clipperPath.size()] = clipperPath[0].y;
return curve;
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathD) <EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Intersect(const Clipper2Lib::PathD& subjects, const Clipper2Lib::PathD& clips, Clipper2Lib::FillRule fillRule)
{
return ClipGeometry({ subjects }, { clips }, Clipper2Lib::ClipType::Intersection, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD) <EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Intersect(const Clipper2Lib::PathsD& subjects, const Clipper2Lib::PathsD& clips, Clipper2Lib::FillRule fillRule) // <20>Ż<EFBFBD>: polygons1/2 -> subjects/clips
{
return ClipGeometry(subjects, clips, Clipper2Lib::ClipType::Intersection, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathD) <EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Union(const Clipper2Lib::PathD& subjects, const Clipper2Lib::PathD& clips, Clipper2Lib::FillRule fillRule)
{
return ClipGeometry({ subjects }, { clips }, Clipper2Lib::ClipType::Union, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD) <EFBFBD>IJ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Union(const Clipper2Lib::PathsD& subjects, const Clipper2Lib::PathsD& clips, Clipper2Lib::FillRule fillRule) // <20>Ż<EFBFBD>: polygons1/2 -> subjects/clips
{
return ClipGeometry(subjects, clips, Clipper2Lib::ClipType::Union, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathD) <EFBFBD>IJ (subjects - clips)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Difference(const Clipper2Lib::PathD& subjects, const Clipper2Lib::PathD& clips, Clipper2Lib::FillRule fillRule)
{
return ClipGeometry({ subjects }, { clips }, Clipper2Lib::ClipType::Difference, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD) <EFBFBD>IJ (subjects - clips)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Difference(const Clipper2Lib::PathsD& subjects, const Clipper2Lib::PathsD& clips, Clipper2Lib::FillRule fillRule) // <20>Ż<EFBFBD>: polygons1/2 -> subjects/clips
{
return ClipGeometry(subjects, clips, Clipper2Lib::ClipType::Difference, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathD) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (Xor)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Xor(const Clipper2Lib::PathD& subjects, const Clipper2Lib::PathD& clips, Clipper2Lib::FillRule fillRule)
{
return ClipGeometry({ subjects }, { clips }, Clipper2Lib::ClipType::Xor, fillRule);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD> (PathsD) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (Xor)<EFBFBD><EFBFBD>
*/
static Clipper2Lib::PathsD Xor(const Clipper2Lib::PathsD& subjects, const Clipper2Lib::PathsD& clips, Clipper2Lib::FillRule fillRule) // <20>Ż<EFBFBD>: polygons1/2 -> subjects/clips
{
return ClipGeometry(subjects, clips, Clipper2Lib::ClipType::Xor, fillRule);
}
/**
* \brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \param paths
* \param delta
* \return
*/
static Clipper2Lib::PathsD InflatePaths(const Clipper2Lib::PathsD& paths, double delta)
{
return Clipper2Lib::InflatePaths(paths, delta, Clipper2Lib::JoinType::Miter, Clipper2Lib::EndType::Polygon);
}
/**
* \brief (<EFBFBD><EFBFBD><EFBFBD>ĺ<EFBFBD><EFBFBD><EFBFBD>) ִ<EFBFBD><EFBFBD>ͨ<EFBFBD>õ<EFBFBD> Clipper2 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (Intersect, Union, Difference, Xor) <EFBFBD>ĺ<EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֡<EFBFBD>
*
* \param subjects <EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD>
* \param clips <EFBFBD>ü<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD>
* \param clipType <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (Intersection, Union, Difference, Xor)<EFBFBD><EFBFBD>
* \param fillRule <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϡ<EFBFBD>
*/
static Clipper2Lib::PathsD ClipGeometry(const Clipper2Lib::PathsD& subjects, const Clipper2Lib::PathsD& clips, Clipper2Lib::ClipType clipType, Clipper2Lib::FillRule fillRule)
{
Clipper2Lib::ClipperD clipper;
clipper.AddSubject(subjects);
clipper.AddClip(clips);
Clipper2Lib::PathsD solution;
clipper.Execute(clipType, fillRule, solution);
return solution;
}
};