|
|
|
|
|
#include <memory>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include "DrawOperator/CurveEx.h"
|
|
|
|
|
|
#include "clipper2/clipper.h"
|
|
|
|
|
|
#include "PolygonUtils.h"
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* <EFBFBD><EFBFBD>϶<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
*/
|
|
|
|
|
|
class GapDetection
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
GapDetection() = default;
|
|
|
|
|
|
~GapDetection() = default;
|
|
|
|
|
|
|
|
|
|
|
|
struct Gap
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_ptr<CCurveEx> pArea;
|
|
|
|
|
|
CCurveEx* pFirstCurve;
|
|
|
|
|
|
CCurveEx* pSecondCurve;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
double GetGapValue() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return minGap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SetGapValue(double value)
|
|
|
|
|
|
{
|
|
|
|
|
|
minGap = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<Gap> DetectGaps(const std::vector<CCurveEx*>& curves) const
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<Gap> allGaps;
|
|
|
|
|
|
const size_t numCurves = curves.size();
|
|
|
|
|
|
|
|
|
|
|
|
if (numCurves < 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
return allGaps;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<Clipper2Lib::PathD> cachedPaths;
|
|
|
|
|
|
cachedPaths.reserve(numCurves);
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numCurves; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
cachedPaths.push_back(PolygonUtils::ConvertCurveToPath(curves[i]));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numCurves; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (size_t j = i + 1; j < numCurves; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
const Clipper2Lib::PathD& path1 = cachedPaths[i];
|
|
|
|
|
|
const Clipper2Lib::PathD& path2 = cachedPaths[j];
|
|
|
|
|
|
|
|
|
|
|
|
if (path1.size() < 3 || path2.size() < 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Clipper2Lib::PathsD solution = PolygonUtils::FindGapRegions(path1, path2, minGap);
|
|
|
|
|
|
|
|
|
|
|
|
auto result = SolutionToGap(solution, curves[i], curves[j]);
|
|
|
|
|
|
allGaps.insert(allGaps.end(),
|
|
|
|
|
|
std::make_move_iterator(result.begin()),
|
|
|
|
|
|
std::make_move_iterator(result.end()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return allGaps;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
std::vector<Gap> SolutionToGap(Clipper2Lib::PathsD& solution, CCurveEx* pFirst, CCurveEx* pSecond) const
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<Gap> result;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& solutionPath : solution)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_ptr<CCurveEx> pGapArea = PolygonUtils::ConvertPathToClosedCurve(solutionPath);
|
|
|
|
|
|
|
|
|
|
|
|
if (pGapArea)
|
|
|
|
|
|
{
|
|
|
|
|
|
Gap overlap;
|
|
|
|
|
|
overlap.pArea = std::move(pGapArea);
|
|
|
|
|
|
overlap.pFirstCurve = pFirst;
|
|
|
|
|
|
overlap.pSecondCurve = pSecond;
|
|
|
|
|
|
|
|
|
|
|
|
result.push_back(std::move(overlap));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double minGap = 20.0;
|
|
|
|
|
|
};
|