|
|
#include "stdafx.h"
|
|
|
#include "Util.h"
|
|
|
#include "VoronoiMap/InterfaceElements.h"
|
|
|
#include <algorithm>
|
|
|
|
|
|
bool IsEqual(const CCurveEx * first, const CCurveEx * second)
|
|
|
{
|
|
|
if (first->num != second->num)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < first->num; i++)
|
|
|
{
|
|
|
if (!IsEqual(first->x[i], second->x[i])
|
|
|
|| !IsEqual(first->y[i], second->y[i]))
|
|
|
{
|
|
|
return false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool IsEqual(const CPolyline & first, const CPolyline & second)
|
|
|
{
|
|
|
if (first.GetSize() != second.GetSize())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < first.GetSize(); i++)
|
|
|
{
|
|
|
CPointXYZ& p1 = const_cast<CPolyline&>(first).GetPoint(i);
|
|
|
CPointXYZ& p2 = const_cast<CPolyline&>(second).GetPoint(i);
|
|
|
if (!IsEqual(p1, p2))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool IsEqual(const CPointXYZ & first, const CPointXYZ & second)
|
|
|
{
|
|
|
return IsEqual(first.x0, second.x0)
|
|
|
&& IsEqual(first.y0, second.y0)
|
|
|
&& IsEqual(first.z0, second.z0);
|
|
|
}
|
|
|
|
|
|
bool CPolylinesContains(const std::list<CPolyline>& polylines, const CPolyline & polyline)
|
|
|
{
|
|
|
return AnyOf(polylines, [&polyline](const CPolyline &e)
|
|
|
{
|
|
|
return IsEqual(e, polyline);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
bool CPointXYZContains(const std::vector<CPointXYZ>& pointXYZs, const CPointXYZ &pointXYZ)
|
|
|
{
|
|
|
return AnyOf(pointXYZs, [&pointXYZ](const CPointXYZ &e)
|
|
|
{
|
|
|
return IsEqual(e, pointXYZ);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
std::list<COne*> PtrsToCOnes(const CPtrList& pList)
|
|
|
{
|
|
|
std::list<COne*> result;
|
|
|
|
|
|
CListForEach(pos, pList)
|
|
|
{
|
|
|
COne *pOne = (COne *)pList.GetAt(pos);
|
|
|
result.push_back(pOne);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
std::list<COne*> ConesFilter(const std::list<COne*> &cones, std::function<bool(COne*)> pred)
|
|
|
{
|
|
|
return Filter(cones, pred);
|
|
|
}
|
|
|
|
|
|
bool IsEqual(double a, double b)
|
|
|
{
|
|
|
constexpr double epsilon = std::numeric_limits<double>::epsilon(); // 取浮点精度
|
|
|
return std::fabs(a - b) < epsilon;
|
|
|
}
|
|
|
|
|
|
bool IsLessThan(double a, double b)
|
|
|
{
|
|
|
return !IsEqual(a, b) && a < b;
|
|
|
}
|
|
|
|
|
|
bool IsGreaterThan(double a, double b)
|
|
|
{
|
|
|
return !IsEqual(a, b) && a > b;
|
|
|
}
|
|
|
|
|
|
bool IsPolygon(const CCurveEx* pCurve)
|
|
|
{
|
|
|
// 多边形至少3条边
|
|
|
if (pCurve->num < 3)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
int last = pCurve->num - 1;
|
|
|
|
|
|
// 这里直接使用 = 判等是安全的,因为是拿同一曲线内部的点进行对比
|
|
|
return pCurve->x[0] == pCurve->x[last]
|
|
|
&& pCurve->y[0] == pCurve->y[last]
|
|
|
&& pCurve->z[0] == pCurve->z[last];
|
|
|
}
|
|
|
|
|
|
bool IsApproximatePolygon(const CCurveEx* pCurve)
|
|
|
{
|
|
|
// 多边形至少3条边
|
|
|
if (pCurve->num < 3)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if (IsPolygon(pCurve))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
int num = pCurve->num;
|
|
|
|
|
|
double x1 = pCurve->x[num - 2];
|
|
|
double y1 = pCurve->y[num - 2];
|
|
|
|
|
|
double x2 = pCurve->x[num - 1];
|
|
|
double y2 = pCurve->y[num - 1];
|
|
|
|
|
|
// 未闭合长度
|
|
|
double distance = CalcDistance(x1, y1, x2, y2);
|
|
|
// 曲线长度
|
|
|
double sum = CalcCurveDistance(pCurve);
|
|
|
|
|
|
return distance <= sum / 10;
|
|
|
}
|
|
|
|
|
|
CCurveEx* CreateCloseCurve(const CCurveEx* pCurve)
|
|
|
{
|
|
|
// 如果只有一条边或更少,无法闭合,直接返回 nullptr
|
|
|
if (pCurve->num < 2)
|
|
|
{
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
// 判断曲线是否闭合
|
|
|
bool isClosed = IsPolygon(pCurve);
|
|
|
|
|
|
// 创建新的 CCurveEx 对象,并根据闭合状态设置点的数量
|
|
|
int num = isClosed ? pCurve->num : pCurve->num + 1;
|
|
|
CCurveEx *pNewCurve = new CCurveEx();
|
|
|
pNewCurve->Create(num);
|
|
|
|
|
|
// 复制原始曲线的点
|
|
|
for (int i = 0; i < pCurve->num; i++)
|
|
|
{
|
|
|
pNewCurve->x[i] = pCurve->x[i];
|
|
|
pNewCurve->y[i] = pCurve->y[i];
|
|
|
pNewCurve->z[i] = pCurve->z[i];
|
|
|
}
|
|
|
|
|
|
// 如果曲线未闭合,添加首点作为最后一个点以闭合曲线
|
|
|
if (!isClosed)
|
|
|
{
|
|
|
pNewCurve->x[pCurve->num] = pCurve->x[0];
|
|
|
pNewCurve->y[pCurve->num] = pCurve->y[0];
|
|
|
pNewCurve->z[pCurve->num] = pCurve->z[0];
|
|
|
}
|
|
|
|
|
|
pNewCurve->GetLocation();
|
|
|
|
|
|
return pNewCurve;
|
|
|
}
|
|
|
|
|
|
double CalcDistance(double x1, double y1, double x2, double y2)
|
|
|
{
|
|
|
double a = x2 - x1;
|
|
|
double b = y2 - y1;
|
|
|
|
|
|
return sqrt(a * a + b * b);
|
|
|
}
|
|
|
|
|
|
double CalcCurveDistance(const CCurveEx* pCurve)
|
|
|
{
|
|
|
double sum = 0;
|
|
|
|
|
|
for (int i = 0; i < pCurve->num - 1; i++)
|
|
|
{
|
|
|
double x1 = pCurve->x[i];
|
|
|
double y1 = pCurve->y[i];
|
|
|
|
|
|
double x2 = pCurve->x[i + 1];
|
|
|
double y2 = pCurve->y[i + 1];
|
|
|
|
|
|
sum += CalcDistance(x1, y1, x2, y2);
|
|
|
}
|
|
|
|
|
|
return sum;
|
|
|
}
|
|
|
|
|
|
double CalcSlope(double x1, double y1, double x2, double y2)
|
|
|
{
|
|
|
assert(!IsEqual(x1, x2));
|
|
|
|
|
|
return (y2 - y1) / (x2 - x1);
|
|
|
}
|
|
|
|
|
|
bool SearchMatch(const CString& source, const CString& search, bool ignoreCase, bool matchWholeWord)
|
|
|
{
|
|
|
CString sourceText = source;
|
|
|
CString searchText = search;
|
|
|
|
|
|
if (ignoreCase)
|
|
|
{
|
|
|
sourceText.MakeLower();
|
|
|
searchText.MakeLower();
|
|
|
}
|
|
|
|
|
|
if (matchWholeWord)
|
|
|
{
|
|
|
return sourceText == searchText;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return sourceText.Find(searchText) == 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
CString GetParentLayerPath(const CString& pLayer)
|
|
|
{
|
|
|
int pos = pLayer.ReverseFind(_T('\\'));
|
|
|
if (pos == -1)
|
|
|
{
|
|
|
return _T("");
|
|
|
}
|
|
|
|
|
|
return pLayer.Left(pos);
|
|
|
}
|
|
|
|
|
|
bool IsSameLayerName(const CString& layerName1, const CString& layerName2)
|
|
|
{
|
|
|
return CLayerName(layerName1).GetFullPathNameA() == CLayerName(layerName2).GetFullPathNameA();
|
|
|
}
|
|
|
|
|
|
CString JoinStrings(const std::vector<CString>& strings, const CString& delimiter)
|
|
|
{
|
|
|
CString result;
|
|
|
for (size_t i = 0; i < strings.size(); ++i)
|
|
|
{
|
|
|
result += strings[i];
|
|
|
if (i != strings.size() - 1)
|
|
|
{
|
|
|
result += delimiter;
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
std::vector<CString> SplitString(const CString& string, const CString& delimiter)
|
|
|
{
|
|
|
std::vector<CString> result;
|
|
|
int start = 0;
|
|
|
int end = string.Find(delimiter, start);
|
|
|
|
|
|
while (end != -1)
|
|
|
{
|
|
|
result.push_back(string.Mid(start, end - start));
|
|
|
start = end + delimiter.GetLength();
|
|
|
end = string.Find(delimiter, start);
|
|
|
}
|
|
|
|
|
|
if (start < string.GetLength())
|
|
|
{
|
|
|
result.push_back(string.Mid(start));
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
bool IsValidPosition(CXy *pXy, POSITION position)
|
|
|
{
|
|
|
CPtrList* pValueList = pXy->GetValueList();
|
|
|
|
|
|
for (POSITION pos = pValueList->GetHeadPosition(); pos != nullptr; pValueList->GetNext(pos))
|
|
|
{
|
|
|
if (pos == position)
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
std::vector<POSITION> GetValidPositions(CXy* pXy, POSITION positions[], int count)
|
|
|
{
|
|
|
std::vector<POSITION > result;
|
|
|
|
|
|
CPtrList* pValueList = pXy->GetValueList();
|
|
|
|
|
|
for (POSITION pos = pValueList->GetHeadPosition(); pos != nullptr; pValueList->GetNext(pos))
|
|
|
{
|
|
|
for (int i = 0; i < count; i++)
|
|
|
{
|
|
|
if (positions[i] == pos)
|
|
|
{
|
|
|
result.push_back(positions[i]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
std::wstring StringToWString(const std::string& wstr)
|
|
|
{
|
|
|
std::wstring res;
|
|
|
int len = MultiByteToWideChar(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.size()), nullptr, 0);
|
|
|
if (len == 0)
|
|
|
{
|
|
|
throw std::runtime_error("Failed to convert string to wstring.");
|
|
|
}
|
|
|
|
|
|
std::vector<wchar_t> buffer(len + 1);
|
|
|
if (MultiByteToWideChar(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.size()), buffer.data(), len) == 0)
|
|
|
{
|
|
|
throw std::runtime_error("Failed to convert string to wstring.");
|
|
|
}
|
|
|
res.assign(buffer.begin(), buffer.end());
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
std::string WStringToString(const std::wstring &wstr)
|
|
|
{
|
|
|
std::string res;
|
|
|
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr);
|
|
|
if (len <= 0)
|
|
|
{
|
|
|
return res;
|
|
|
}
|
|
|
res.resize(len);
|
|
|
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(wstr.size()), &res[0], len, nullptr, nullptr);
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
std::string CStringToUtf8String(const CString& strValue)
|
|
|
{
|
|
|
if (strValue.IsEmpty())
|
|
|
{
|
|
|
return std::string();
|
|
|
}
|
|
|
|
|
|
std::wstring wbuffer;
|
|
|
#ifdef _UNICODE
|
|
|
wbuffer.assign(strValue.GetString(), strValue.GetLength());
|
|
|
#else
|
|
|
// Convert ANSI to UNICODE
|
|
|
int length = ::MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, (LPCTSTR)strValue, -1, NULL, 0);
|
|
|
wbuffer.resize(length);
|
|
|
MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strValue, -1, (LPWSTR)(wbuffer.data()), static_cast<int>(wbuffer.length()));
|
|
|
#endif
|
|
|
|
|
|
// Get the length after conversion
|
|
|
length = WideCharToMultiByte(CP_UTF8, 0, wbuffer.data(), static_cast<int>(wbuffer.size()), NULL, 0, NULL, NULL);
|
|
|
|
|
|
// Get the converted content
|
|
|
std::string buffer;
|
|
|
buffer.resize(length);
|
|
|
WideCharToMultiByte(CP_UTF8, 0, wbuffer.data(), -1, (LPSTR)(buffer.data()), length, NULL, NULL);
|
|
|
|
|
|
// FIXME: 这里的长度有 BUG,先特殊处理一下
|
|
|
buffer.resize(strlen(buffer.data()));
|
|
|
|
|
|
return buffer;
|
|
|
}
|
|
|
|
|
|
CString Utf8StringToCString(const std::string& utf8str)
|
|
|
{
|
|
|
// Pre-convert to get the required space size
|
|
|
int nLen = ::MultiByteToWideChar(CP_UTF8, NULL, utf8str.data(), static_cast<int>(utf8str.size()), NULL, 0);
|
|
|
|
|
|
// Convert to Unicode
|
|
|
std::wstring wbuffer;
|
|
|
wbuffer.resize(nLen);
|
|
|
::MultiByteToWideChar(CP_UTF8, NULL, utf8str.data(), static_cast<int>(utf8str.size()), (LPWSTR)(wbuffer.data()), static_cast<int>(wbuffer.length()));
|
|
|
|
|
|
#ifdef UNICODE
|
|
|
return CString(wbuffer.data(), wbuffer.length());
|
|
|
#else
|
|
|
// Convert to ANSI
|
|
|
nLen = WideCharToMultiByte(CP_ACP, 0, wbuffer.data(), static_cast<int>(wbuffer.length()), NULL, 0, NULL, NULL);
|
|
|
std::string ansistr;
|
|
|
ansistr.resize(nLen);
|
|
|
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)(wbuffer.data()), static_cast<int>(wbuffer.length()), (LPSTR)(ansistr.data()), static_cast<int>(ansistr.size()), NULL, NULL);
|
|
|
return CString(ansistr.data(), static_cast<int>(ansistr.length()));
|
|
|
#endif
|
|
|
}
|