File indexing completed on 2025-04-20 03:36:29
0001 /******************************************************************************* 0002 * Author : Angus Johnson * 0003 * Date : 28 January 2023 * 0004 * Website : http://www.angusj.com * 0005 * Copyright : Angus Johnson 2010-2023 * 0006 * Purpose : Minkowski Sum and Difference * 0007 * License : http://www.boost.org/LICENSE_1_0.txt * 0008 *******************************************************************************/ 0009 0010 #ifndef CLIPPER_MINKOWSKI_H 0011 #define CLIPPER_MINKOWSKI_H 0012 0013 #include <cstdlib> 0014 #include <vector> 0015 #include <string> 0016 #include "clipper.core.h" 0017 0018 namespace Clipper2Lib 0019 { 0020 0021 namespace detail 0022 { 0023 inline Paths64 Minkowski(const Path64& pattern, const Path64& path, bool isSum, bool isClosed) 0024 { 0025 size_t delta = isClosed ? 0 : 1; 0026 size_t patLen = pattern.size(), pathLen = path.size(); 0027 if (patLen == 0 || pathLen == 0) return Paths64(); 0028 Paths64 tmp; 0029 tmp.reserve(pathLen); 0030 0031 if (isSum) 0032 { 0033 for (const Point64& p : path) 0034 { 0035 Path64 path2(pattern.size()); 0036 std::transform(pattern.cbegin(), pattern.cend(), 0037 path2.begin(), [p](const Point64& pt2) {return p + pt2; }); 0038 tmp.push_back(path2); 0039 } 0040 } 0041 else 0042 { 0043 for (const Point64& p : path) 0044 { 0045 Path64 path2(pattern.size()); 0046 std::transform(pattern.cbegin(), pattern.cend(), 0047 path2.begin(), [p](const Point64& pt2) {return p - pt2; }); 0048 tmp.push_back(path2); 0049 } 0050 } 0051 0052 Paths64 result; 0053 result.reserve((pathLen - delta) * patLen); 0054 size_t g = isClosed ? pathLen - 1 : 0; 0055 for (size_t h = patLen - 1, i = delta; i < pathLen; ++i) 0056 { 0057 for (size_t j = 0; j < patLen; j++) 0058 { 0059 Path64 quad; 0060 quad.reserve(4); 0061 { 0062 quad.push_back(tmp[g][h]); 0063 quad.push_back(tmp[i][h]); 0064 quad.push_back(tmp[i][j]); 0065 quad.push_back(tmp[g][j]); 0066 }; 0067 if (!IsPositive(quad)) 0068 std::reverse(quad.begin(), quad.end()); 0069 result.push_back(quad); 0070 h = j; 0071 } 0072 g = i; 0073 } 0074 return result; 0075 } 0076 0077 inline Paths64 Union(const Paths64& subjects, FillRule fillrule) 0078 { 0079 Paths64 result; 0080 Clipper64 clipper; 0081 clipper.AddSubject(subjects); 0082 clipper.Execute(ClipType::Union, fillrule, result); 0083 return result; 0084 } 0085 0086 } // namespace internal 0087 0088 inline Paths64 MinkowskiSum(const Path64& pattern, const Path64& path, bool isClosed) 0089 { 0090 return detail::Union(detail::Minkowski(pattern, path, true, isClosed), FillRule::NonZero); 0091 } 0092 0093 inline PathsD MinkowskiSum(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2) 0094 { 0095 int error_code = 0; 0096 double scale = pow(10, decimalPlaces); 0097 Path64 pat64 = ScalePath<int64_t, double>(pattern, scale, error_code); 0098 Path64 path64 = ScalePath<int64_t, double>(path, scale, error_code); 0099 Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, true, isClosed), FillRule::NonZero); 0100 return ScalePaths<double, int64_t>(tmp, 1 / scale, error_code); 0101 } 0102 0103 inline Paths64 MinkowskiDiff(const Path64& pattern, const Path64& path, bool isClosed) 0104 { 0105 return detail::Union(detail::Minkowski(pattern, path, false, isClosed), FillRule::NonZero); 0106 } 0107 0108 inline PathsD MinkowskiDiff(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2) 0109 { 0110 int error_code = 0; 0111 double scale = pow(10, decimalPlaces); 0112 Path64 pat64 = ScalePath<int64_t, double>(pattern, scale, error_code); 0113 Path64 path64 = ScalePath<int64_t, double>(path, scale, error_code); 0114 Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, false, isClosed), FillRule::NonZero); 0115 return ScalePaths<double, int64_t>(tmp, 1 / scale, error_code); 0116 } 0117 0118 } // Clipper2Lib namespace 0119 0120 #endif // CLIPPER_MINKOWSKI_H