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.

160 lines
3.7 KiB
C

1 month ago
#pragma once
#include "DrawOperator/One.h"
#include "DrawOperator/Xy.h"
#include "DrawOperator/RTree.h"
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>
*/
std::optional<NBase::CPoint2D> GetSnapPoint(const NBase::CPoint2D& searchCenter, double searchRadius) const
{
std::vector<POSITION> positions = FindElementsInRadius(searchCenter, searchRadius);
return positions.empty() ? std::nullopt : FindNearestPoint(positions, searchCenter);
}
/**
* <EFBFBD><EFBFBD><EFBFBD>ҷ<EFBFBD>Χ<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
*
* \param rect <EFBFBD><EFBFBD>Χ
* \return <EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD>Χ<EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
*/
std::vector<POSITION> FindElementsInRect(const NBase::CRect8& rect) const
{
double minValue[2]{ rect.left, rect.top };
double maxValue[2]{ rect.right, rect.bottom };
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>ͼԪ
*
* \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
*/
std::vector<POSITION> FindElementsInRadius(const NBase::CPoint2D& searchCenter, double searchRadius) const
{
NBase::CRect8 rect(
searchCenter.x0 - searchRadius / 2,
searchCenter.y0 - searchRadius / 2,
searchCenter.x0 + searchRadius / 2,
searchCenter.y0 + searchRadius / 2
);
return FindElementsInRect(rect);
}
private:
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD> RTree
*
*/
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));
if (IsVisiblePointElement(pOne))
{
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>
*
* \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;
// <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><D4B2><EFBFBD><EFB2BB><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܿ<EFBFBD><DCBF><EFBFBD>
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")
}
bool IsVisiblePointElement(COne* pOne) const
{
return pOne != nullptr
&& pOne->GetType() == DOUBLEFOX_POINT
&& pOne->IsView();
}
RTree<POSITION, double, 2> m_tree;
CXy& m_xy;
};