RTree 3D 空间查询

22 篇文章 3 订阅

RTree 3D 空间查询

给定3D空间的包围盒,查询与包围盒符合特定空间关系的几何对象。
本文使用的是LibSpatialIndex 开源库。

自定义数据从 索引(int tileid) 到几何的映射

#ifndef RTREE_BUILDER_3D_HPP
#define RTREE_BUILDER_3D_HPP

#include <iostream>
#include <spatialindex/SpatialIndex.h>

/*3D 空间包围盒*/

struct mbb_3d {
	double low[3];
	double high[3];
};

/*结果集存储集合*/
class MyVisitor : public SpatialIndex::IVisitor
{
	public:
		std::vector<SpatialIndex::id_type> matches; // contains ids of matching objects

	public:	
		MyVisitor() {}

		~MyVisitor() {
			matches.clear();
		}

		void visitNode(const SpatialIndex::INode& n) {}
		void visitData(std::string &s) {}

		void visitData(const SpatialIndex::IData& d)
		{
			matches.push_back(d.getIdentifier());
		}

		void visitData(std::vector<const SpatialIndex::IData*>& v) {}
		void visitData(std::vector<uint32_t>& v){}
};

/* 自定义数据流从索引(tileid)到 geometry (box3D)的映射 */
class CustomDataStream : public SpatialIndex::IDataStream
{
	public:
		CustomDataStream(std::vector<struct mbb_3d *> *inputdata ) : m_pNext(0), len(0), m_id(0)
	{
		if (inputdata->empty())
			throw Tools::IllegalArgumentException("Input size is ZERO.");
		shapes = inputdata;
		len = inputdata->size();
		iter = shapes->begin();
		readNextEntry();
	}

		virtual ~CustomDataStream()
		{
			if (m_pNext != 0) delete m_pNext;
		}

		virtual SpatialIndex::IData* getNext()
		{
			if (m_pNext == 0) return 0;

			SpatialIndex::RTree::Data* ret = m_pNext;
			m_pNext = 0;
			readNextEntry();
			return ret;
		}

		virtual bool hasNext()
		{
			return (m_pNext != 0);
		}

		virtual uint32_t size()
		{
			return len;
			//throw Tools::NotSupportedException("Operation not supported.");
		}

		virtual void rewind()
		{
			if (m_pNext != 0)
			{
				delete m_pNext;
				m_pNext = 0;
			}

			m_id  = 0;
			iter = shapes->begin();
			readNextEntry();
		}

		void readNextEntry()
		{
			if (iter != shapes->end())
			{
				//std::cerr<< "readNextEntry m_id == " << m_id << std::endl;
				SpatialIndex::Region r((*iter)->low, (*iter)->high, 3);	
				m_pNext = new SpatialIndex::RTree::Data(sizeof(double), reinterpret_cast<uint8_t*>((*iter)->low), r, m_id);
				iter++;
				m_id++;
			}
		}

		SpatialIndex::RTree::Data* m_pNext;
		std::vector<struct mbb_3d*> * shapes; 
		std::vector<struct mbb_3d*>::iterator iter; 

		int len;
		SpatialIndex::id_type m_id;
};

class GEOSDataStreamFileTile : public SpatialIndex::IDataStream
{
	public:
		std::map<SpatialIndex::id_type, std::string> *id_tiles;
	
	public:
		GEOSDataStreamFileTile(char *input_file, 
			std::map<SpatialIndex::id_type, std::string> *id_tiles_ptr) : m_pNext(0)
	{
		m_fin.open(input_file);
		id_tiles = id_tiles_ptr;
		m_id = 0;
		if (! m_fin)
			throw Tools::IllegalArgumentException("Input file not found.");

		readNextEntry();
	}

		virtual ~GEOSDataStreamFileTile()
		{
			if (m_pNext != 0) delete m_pNext;
		}

		virtual SpatialIndex::IData* getNext()
		{
			if (m_pNext == 0) return 0;

			SpatialIndex::RTree::Data* ret = m_pNext;
			m_pNext = 0;
			readNextEntry();
			return ret;
		}

		virtual bool hasNext()
		{
			return (m_pNext != 0);
		}

		virtual uint32_t size()
		{
			throw Tools::NotSupportedException("Operation not supported.");
		}

		virtual void rewind()
		{
			if (m_pNext != 0)
			{
				delete m_pNext;
				m_pNext = 0;
			}

			m_fin.seekg(0, std::ios::beg);
			readNextEntry();
			m_id = 0;
		}

		void readNextEntry()
		{
			std::string tile_id;
			double low[3], high[3];


			m_fin >> tile_id >> low[0] >> low[1] >> low[2]  >>  high[0] >> high[1] >> high[2];
			/* store tile_id */

			if (m_fin.good())
			{
				SpatialIndex::Region r(low, high, 3);
				m_pNext = new SpatialIndex::RTree::Data(sizeof(double), reinterpret_cast<uint8_t*>(low), r, m_id);
				/* Use spatialproc struct */
				//stop.id_tiles[m_id] = tile_id;
				(*id_tiles)[m_id] = tile_id;
			}
			m_id++;
		}

		SpatialIndex::id_type m_id;
		std::ifstream m_fin;
		SpatialIndex::RTree::Data* m_pNext;
};

#endif


构建空间索引

#define FillFactor 0.9
#define IndexCapacity 10 
#define LeafCapacity 50

id_type  indexIdentifier;
GEOSDataStreamFileTile stream(cachefilename, id_tiles); 
IStorageManager* storage = StorageManager::createNewMemoryStorageManager();
ISpatialIndex* spidx = RTree::createAndBulkLoadNewRTree(RTree::BLM_STR, stream, *storage,
		FillFactor,
		IndexCapacity,
		LeafCapacity,
		3,
		RTree::RV_RSTAR, indexIdentifier);

进行空间查询

ISpatialIndex* spidx;
double low[3];
double high[3];

Region r(low, high, 3);
spidx->intersectsWithQuery(r, vis);
//spidx->containsWhatQuery(r, vis);
for (uint32_t i = 0; i < vis.matches.size(); i++) {
	cout <<"id:" << (*id_tiles)[vis.matches[i]] << endl;//tile id
}
vis.matches.clear();

构建项目

1

# exe project
add_executable(SpatialIndexDemo "")

# 自定义函数获取头文件和源文件
cplusplus_glob_files(SPATIAL_INDEX_DEMO_SOURCE src/*.cpp)
cplusplus_glob_files(SPATIAL_INDEX_DEMO_HEADERS src/*.h src/*.hpp)
cplusplus_glob_files(SPATIAL_INDEX_DEMO_PUBLIC_HEADERS include/*.h)

# 设置预处理定义
target_compile_definitions(
    SpatialIndexDemo
    PRIVATE
        SIDX_DLL_EXPORT=1
        DATA_FILE=\"${PROJECT_SOURCE_DIR}/Data/data.txt\"
)
# 设置源文件和头文件
target_sources(
    SpatialIndexDemo
    PRIVATE
        ${SPATIAL_INDEX_DEMO_SOURCE}
        ${SPATIAL_INDEX_DEMO_HEADERS}
    PUBLIC
        ${SPATIAL_INDEX_DEMO_PUBLIC_HEADERS}
)
# 包含头文件
target_include_directories(
    SpatialIndexDemo
    SYSTEM PUBLIC
        ${CMAKE_CURRENT_LIST_DIR}/include
        ${CMAKE_INSTALL_PREFIX}/include
    PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}/src/
)
# 链接库
target_link_libraries(SpatialIndexDemo
    PUBLIC
        spatialindex
)

测试数据

id lowx lowy lowz highx highy highz 模拟 {id,geometry}

2

空间查询结果

输入:lowx,lowy,lowz,highx,highy,highz
输出:符合对应空间关系几何对象的id。

intersectsWithQuery : 相交查询

3

containsWhatQuery:包含查询

4

参考

  1. libspatialindex 开源库
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值