325 lines
8.2 KiB
C++
325 lines
8.2 KiB
C++
/**********************************************************************
|
|
*
|
|
* GEOS - Geometry Engine Open Source
|
|
* http://geos.osgeo.org
|
|
*
|
|
* Copyright (C) 2006 Refractions Research Inc.
|
|
*
|
|
* This is free software; you can redistribute and/or modify it under
|
|
* the terms of the GNU Lesser General Public Licence as published
|
|
* by the Free Software Foundation.
|
|
* See the COPYING file for more information.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <geos/export.h>
|
|
|
|
#include <geos/index/strtree/AbstractNode.h> // for inlines
|
|
|
|
#include <vector>
|
|
#include <list>
|
|
#include <memory> // for unique_ptr
|
|
#include <cassert> // for inlines
|
|
#include <algorithm>
|
|
|
|
// Forward declarations
|
|
namespace geos {
|
|
namespace index {
|
|
class ItemVisitor;
|
|
namespace strtree {
|
|
class Boundable;
|
|
class AbstractNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace geos {
|
|
namespace index { // geos::index
|
|
namespace strtree { // geos::index::strtree
|
|
|
|
/// A list of boundables. TODO: use a list
|
|
typedef std::vector<Boundable*> BoundableList;
|
|
|
|
/// list contains boundables or lists of boundables. The lists are owned by
|
|
/// this class, the plain boundables are held by reference only.
|
|
class ItemsList;
|
|
|
|
class ItemsListItem {
|
|
public:
|
|
enum type {
|
|
item_is_geometry,
|
|
item_is_list
|
|
};
|
|
|
|
ItemsListItem(void* item_)
|
|
: t(item_is_geometry)
|
|
{
|
|
item.g = item_;
|
|
}
|
|
ItemsListItem(ItemsList* item_)
|
|
: t(item_is_list)
|
|
{
|
|
item.l = item_;
|
|
}
|
|
|
|
type
|
|
get_type() const
|
|
{
|
|
return t;
|
|
}
|
|
|
|
void*
|
|
get_geometry() const
|
|
{
|
|
assert(t == item_is_geometry);
|
|
return item.g;
|
|
}
|
|
ItemsList*
|
|
get_itemslist() const
|
|
{
|
|
assert(t == item_is_list);
|
|
return item.l;
|
|
}
|
|
|
|
type t;
|
|
union {
|
|
void* g;
|
|
ItemsList* l;
|
|
} item;
|
|
};
|
|
|
|
class ItemsList : public std::vector<ItemsListItem> {
|
|
private:
|
|
typedef std::vector<ItemsListItem> base_type;
|
|
|
|
static void
|
|
delete_item(ItemsListItem& item)
|
|
{
|
|
if(ItemsListItem::item_is_list == item.t) {
|
|
delete item.item.l;
|
|
}
|
|
}
|
|
|
|
public:
|
|
~ItemsList()
|
|
{
|
|
std::for_each(begin(), end(), &ItemsList::delete_item);
|
|
}
|
|
|
|
// lists of items need to be deleted in the end
|
|
void
|
|
push_back(void* item)
|
|
{
|
|
this->base_type::push_back(ItemsListItem(item));
|
|
}
|
|
|
|
// lists of items need to be deleted in the end
|
|
void
|
|
push_back_owned(ItemsList* itemList)
|
|
{
|
|
this->base_type::push_back(ItemsListItem(itemList));
|
|
}
|
|
};
|
|
|
|
/** \brief
|
|
* Base class for STRtree and SIRtree.
|
|
*
|
|
* STR-packed R-trees are described in:
|
|
* P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With
|
|
* Application To GIS. Morgan Kaufmann, San Francisco, 2002.
|
|
*
|
|
* This implementation is based on Boundables rather than just AbstractNodes,
|
|
* because the STR algorithm operates on both nodes and
|
|
* data, both of which are treated here as Boundables.
|
|
*
|
|
*/
|
|
class GEOS_DLL AbstractSTRtree {
|
|
|
|
private:
|
|
bool built;
|
|
BoundableList* itemBoundables;
|
|
|
|
/**
|
|
* Creates the levels higher than the given level
|
|
*
|
|
* @param boundablesOfALevel
|
|
* the level to build on
|
|
* @param level
|
|
* the level of the Boundables, or -1 if the boundables are item
|
|
* boundables (that is, below level 0)
|
|
* @return the root, which may be a ParentNode or a LeafNode
|
|
*/
|
|
virtual AbstractNode* createHigherLevels(
|
|
BoundableList* boundablesOfALevel,
|
|
int level);
|
|
|
|
std::unique_ptr<BoundableList> sortBoundablesY(const BoundableList* input);
|
|
|
|
bool remove(const void* searchBounds, AbstractNode& node, void* item);
|
|
bool removeItem(AbstractNode& node, void* item);
|
|
|
|
ItemsList* itemsTree(AbstractNode* node);
|
|
|
|
AbstractSTRtree(const AbstractSTRtree&) = delete;
|
|
AbstractSTRtree& operator=(const AbstractSTRtree&) = delete;
|
|
|
|
protected:
|
|
|
|
/** \brief
|
|
* A test for intersection between two bounds, necessary because
|
|
* subclasses of AbstractSTRtree have different implementations of
|
|
* bounds.
|
|
*/
|
|
class GEOS_DLL IntersectsOp {
|
|
public:
|
|
/**
|
|
* For STRtrees, the bounds will be Envelopes; for
|
|
* SIRtrees, Intervals; for other subclasses of
|
|
* AbstractSTRtree, some other class.
|
|
* @param aBounds the bounds of one spatial object
|
|
* @param bBounds the bounds of another spatial object
|
|
* @return whether the two bounds intersect
|
|
*/
|
|
virtual bool intersects(const void* aBounds,
|
|
const void* bBounds) = 0;
|
|
|
|
virtual
|
|
~IntersectsOp() {}
|
|
};
|
|
|
|
AbstractNode* root;
|
|
|
|
std::vector <AbstractNode*>* nodes;
|
|
|
|
// Ownership to caller (TODO: return by unique_ptr)
|
|
virtual AbstractNode* createNode(int level) = 0;
|
|
|
|
/** \brief
|
|
* Sorts the childBoundables then divides them into groups of size M, where
|
|
* M is the node capacity.
|
|
*/
|
|
virtual std::unique_ptr<BoundableList> createParentBoundables(
|
|
BoundableList* childBoundables, int newLevel);
|
|
|
|
virtual AbstractNode*
|
|
lastNode(BoundableList* nodeList)
|
|
{
|
|
assert(!nodeList->empty());
|
|
// Cast from Boundable to AbstractNode
|
|
return static_cast<AbstractNode*>(nodeList->back());
|
|
}
|
|
|
|
virtual AbstractNode*
|
|
getRoot()
|
|
{
|
|
assert(built);
|
|
return root;
|
|
}
|
|
|
|
/// Also builds the tree, if necessary.
|
|
virtual void insert(const void* bounds, void* item);
|
|
|
|
/// Also builds the tree, if necessary.
|
|
void query(const void* searchBounds, std::vector<void*>& foundItems);
|
|
|
|
/// Also builds the tree, if necessary.
|
|
void query(const void* searchBounds, ItemVisitor& visitor);
|
|
|
|
void query(const void* searchBounds, const AbstractNode& node, ItemVisitor& visitor);
|
|
|
|
/// Also builds the tree, if necessary.
|
|
bool remove(const void* itemEnv, void* item);
|
|
|
|
std::unique_ptr<BoundableList> boundablesAtLevel(int level);
|
|
|
|
// @@ should be size_t, probably
|
|
std::size_t nodeCapacity;
|
|
|
|
/**
|
|
* @return a test for intersection between two bounds,
|
|
* necessary because subclasses
|
|
* of AbstractSTRtree have different implementations of bounds.
|
|
* @see IntersectsOp
|
|
*/
|
|
virtual IntersectsOp* getIntersectsOp() = 0;
|
|
|
|
|
|
public:
|
|
|
|
/** \brief
|
|
* Constructs an AbstractSTRtree with the specified maximum number of child
|
|
* nodes that a node may have.
|
|
*/
|
|
AbstractSTRtree(std::size_t newNodeCapacity)
|
|
:
|
|
built(false),
|
|
itemBoundables(new BoundableList()),
|
|
nodes(new std::vector<AbstractNode *>()),
|
|
nodeCapacity(newNodeCapacity)
|
|
{
|
|
assert(newNodeCapacity > 1);
|
|
}
|
|
|
|
virtual ~AbstractSTRtree();
|
|
|
|
/** \brief
|
|
* Creates parent nodes, grandparent nodes, and so forth up to the root
|
|
* node, for the data that has been inserted into the tree.
|
|
*
|
|
* Can only be
|
|
* called once, and thus can be called only after all of the data has been
|
|
* inserted into the tree.
|
|
*/
|
|
virtual void build();
|
|
|
|
/** \brief
|
|
* Returns the maximum number of child nodes that a node may have.
|
|
*/
|
|
virtual std::size_t
|
|
getNodeCapacity()
|
|
{
|
|
return nodeCapacity;
|
|
}
|
|
|
|
virtual void query(const void* searchBounds, const AbstractNode* node, std::vector<void*>* matches);
|
|
|
|
/**
|
|
* Iterate over all items added thus far. Explicitly does not build
|
|
* the tree.
|
|
*/
|
|
void iterate(ItemVisitor& visitor);
|
|
|
|
|
|
/**
|
|
* @param level -1 to get items
|
|
* @param top an AbstractNode
|
|
* @param boundables a BoundableList
|
|
*/
|
|
virtual void boundablesAtLevel(int level, AbstractNode* top,
|
|
BoundableList* boundables);
|
|
|
|
/** \brief
|
|
* Gets a tree structure (as a nested list) corresponding to the structure
|
|
* of the items and nodes in this tree.
|
|
*
|
|
* The returned Lists contain either Object items, or Lists which
|
|
* correspond to subtrees of the tree Subtrees which do not contain
|
|
* any items are not included.
|
|
*
|
|
* Builds the tree if necessary.
|
|
*
|
|
* @note The caller is responsible for releasing the list
|
|
*
|
|
* @return a List of items and/or Lists
|
|
*/
|
|
ItemsList* itemsTree();
|
|
};
|
|
|
|
|
|
} // namespace geos::index::strtree
|
|
} // namespace geos::index
|
|
} // namespace geos
|
|
|