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.

240 lines
5.4 KiB
C

1 month ago
#pragma once
#include "DrawOperator/One.h"
#include "DrawOperator/Xy.h"
#include "DrawOperator/RTree.h"
1 month ago
#include "Util.h"
1 month ago
class CSpatialIndex
{
public:
CSpatialIndex(CXy& xy)
: m_xy(xy)
{
BuildRTree(xy);
}
/**
* <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \param searchCenter <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>
* \param searchRadius <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>Ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \return <EFBFBD><EFBFBD>Χ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>صĵ<EFBFBD>
*/
1 month ago
std::optional<NBase::CPoint2D> GetSnapPoint(const NBase::CPoint2D& searchCenter, double searchRadius, CCurveEx* pIgnoreCurve = nullptr) const
1 month ago
{
std::vector<POSITION> positions = FindElementsInRadius(searchCenter, searchRadius);
1 month ago
if (positions.empty())
{
return std::nullopt;
}
std::optional<NBase::CPoint2D> nearestPoint = FindNearestPoint(positions, searchCenter);
std::optional<NBase::CPoint2D> pointOnCurve = GetSnapPointOnCurve(positions, searchCenter, searchRadius, pIgnoreCurve);
if (nearestPoint && pointOnCurve)
{
if (DistanceSq(searchCenter, *nearestPoint) < DistanceSq(searchCenter, *pointOnCurve))
{
return nearestPoint;
}
return pointOnCurve;
}
return nearestPoint ? nearestPoint : pointOnCurve;
1 month ago
}
/**
* <EFBFBD><EFBFBD><EFBFBD>ҷ<EFBFBD>Χ<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
1 month ago
*
1 month ago
* \param rect <EFBFBD><EFBFBD>Χ
* \return <EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD>Χ<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
*/
std::vector<POSITION> FindElementsInRect(const NBase::CRect8& rect) const
1 month ago
{
double minX = min(rect.left, rect.right);
double maxX = max(rect.left, rect.right);
double minY = min(rect.top, rect.bottom);
double maxY = max(rect.top, rect.bottom);
double minValue[2]{ minX, minY };
double maxValue[2]{ maxX, maxY };
1 month ago
std::vector<POSITION> positions;
auto callback = [&positions](POSITION pos)
{
positions.push_back(pos);
return true;
};
m_tree.Search(minValue, maxValue, callback);
return positions;
}
/**
* <EFBFBD><EFBFBD><EFBFBD>ҷ<EFBFBD>Χ<EFBFBD>ڵ<EFBFBD>ͼԪ
1 month ago
*
1 month ago
* \param searchCenter <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>
* \param searchRadius <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>Ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
1 month ago
* \return
1 month ago
*/
std::vector<POSITION> FindElementsInRadius(const NBase::CPoint2D& searchCenter, double searchRadius) const
{
1 month ago
double r = searchRadius;
1 month ago
NBase::CRect8 rect(
1 month ago
searchCenter.x0 - r,
searchCenter.y0 - r,
searchCenter.x0 + r,
searchCenter.y0 + r
1 month ago
);
return FindElementsInRect(rect);
}
private:
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> RTree
1 month ago
*
1 month ago
*/
void BuildRTree(CXy& xy)
{
CPtrList& values = *(xy.GetValueList());
for (POSITION pos = values.GetHeadPosition(); pos != nullptr; values.GetNext(pos))
{
COne* pOne = reinterpret_cast<COne*>(values.GetAt(pos));
1 month ago
if (IsVisiblePointElement(pOne) || IsVisibleCurveElement(pOne))
1 month ago
{
NBase::CRect8 range(1e100, -1e100, -1e100, 1e100);
pOne->GetRange(range);
double minX = min(range.left, range.right);
double minY = min(range.top, range.bottom);
double maxX = max(range.left, range.right);
double maxY = max(range.top, range.bottom);
double minValue[2]{ minX, minY };
double maxValue[2]{ maxX, maxY };
m_tree.Insert(minValue, maxValue, pos);
}
}
}
/**
* <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>
1 month ago
*
1 month ago
* \param positions ͼԪ POSITION
* \param searchCenter <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> std::nullopt;
*/
std::optional<NBase::CPoint2D> FindNearestPoint(const std::vector<POSITION>& positions, const NBase::CPoint2D& searchCenter) const
{
#pragma push_macro("max")
#undef max
double minDistanceSquared = std::numeric_limits<double>::max();
NBase::CPoint2D nearestPoint; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
// <20>ӷ<EFBFBD>Χ<EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
for (POSITION pos : positions)
{
COne* pOne = m_xy.GetAt(pos);
if (!IsVisiblePointElement(pOne))
{
continue;
}
CPointNameEx* pPoint = pOne->GetValueSafe<CPointNameEx>();
if (pPoint == nullptr)
{
continue;
}
double dx = pPoint->x0 - searchCenter.x0;
double dy = pPoint->y0 - searchCenter.y0;
1 month ago
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵֻ<CAB5><D6BB>֪<EFBFBD><D6AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EBA3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFB2BB><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܿ<EFBFBD><DCBF><EFBFBD>
1 month ago
double distanceSquared = dx * dx + dy * dy;
if (distanceSquared < minDistanceSquared)
{
minDistanceSquared = distanceSquared;
nearestPoint = NBase::CPoint2D(pPoint->x0, pPoint->y0);
}
}
return (minDistanceSquared != std::numeric_limits<double>::max())
? std::optional(nearestPoint)
: std::nullopt;
#pragma pop_macro("max")
}
1 month ago
std::optional<NBase::CPoint2D> CSpatialIndex::GetSnapPointOnCurve(const std::vector<POSITION>& positions, const NBase::CPoint2D& searchCenter, double searchRadius, CCurveEx* pIgnoreCurve) const
{
double minDistanceSq = searchRadius * searchRadius;
std::optional<NBase::CPoint2D> result;
for (POSITION pos : positions)
{
COne* pOne = m_xy.GetAt(pos);
if (pOne == nullptr || pOne->GetType() != DOUBLEFOX_CURVE)
{
continue;
}
CCurveEx* pCurve = pOne->GetValueSafe<CCurveEx>();
if (pCurve->num < 2)
{
continue;
}
if (pCurve == pIgnoreCurve)
{
continue;
}
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];
NBase::CPoint2D point = GetClosestPointOnSegment(searchCenter, x1, y1, x2, y2);
double distSq = DistanceSq(searchCenter, point);
if (distSq < minDistanceSq)
{
minDistanceSq = distSq;
result = point;
}
}
}
return result;
}
1 month ago
bool IsVisiblePointElement(COne* pOne) const
{
return pOne != nullptr
&& pOne->GetType() == DOUBLEFOX_POINT
&& pOne->IsView();
}
1 month ago
bool IsVisibleCurveElement(COne* pOne) const
{
return pOne != nullptr
&& pOne->GetType() == DOUBLEFOX_CURVE
&& pOne->IsView();
}
1 month ago
RTree<POSITION, double, 2> m_tree;
CXy& m_xy;
};