using System.Collections;
using GeoAPI.Geometries;
namespace GisSharpBlog.NetTopologySuite.Index.Quadtree
{
///
/// The base class for nodes in a Quadtree.
///
public abstract class NodeBase
{
///
/// Returns the index of the subquad that wholly contains the given envelope.
/// If none does, returns -1.
///
///
///
public static int GetSubnodeIndex(IEnvelope env, ICoordinate centre)
{
int subnodeIndex = -1;
if (env.MinX >= centre.X)
{
if (env.MinY >= centre.Y)
subnodeIndex = 3;
if (env.MaxY <= centre.Y)
subnodeIndex = 1;
}
if (env.MaxX <= centre.X)
{
if (env.MinY >= centre.Y)
subnodeIndex = 2;
if (env.MaxY <= centre.Y)
subnodeIndex = 0;
}
return subnodeIndex;
}
///
///
///
protected IList items = new ArrayList();
///
/// subquads are numbered as follows:
/// 2 | 3
/// --+--
/// 0 | 1
///
protected Node[] subnode = new Node[4];
///
///
///
public NodeBase() { }
///
///
///
public IList Items
{
get
{
return items;
}
}
///
///
///
public bool HasItems
{
get
{
// return !items.IsEmpty;
if (items.Count == 0)
return false;
return true;
}
}
///
///
///
///
public void Add(object item)
{
items.Add(item);
}
///
/// Removes a single item from this subtree.
///
/// The envelope containing the item.
/// The item to remove.
/// true if the item was found and removed.
public bool Remove(IEnvelope itemEnv, object item)
{
// use envelope to restrict nodes scanned
if (!IsSearchMatch(itemEnv))
return false;
bool found = false;
for (int i = 0; i < 4; i++)
{
if (subnode[i] != null)
{
found = subnode[i].Remove(itemEnv, item);
if (found)
{
// trim subtree if empty
if (subnode[i].IsPrunable)
subnode[i] = null;
break;
}
}
}
// if item was found lower down, don't need to search for it here
if (found)
return found;
// otherwise, try and remove the item from the list of items in this node
if(items.Contains(item))
{
items.Remove(item);
found = true;
}
return found;
}
///
///
///
public bool IsPrunable
{
get
{
return !(HasChildren || HasItems);
}
}
///
///
///
public bool HasChildren
{
get
{
for (int i = 0; i < 4; i++)
{
if (subnode[i] != null)
return true;
}
return false;
}
}
///
///
///
public bool IsEmpty
{
get
{
bool isEmpty = true;
if(items.Count != 0)
isEmpty = false;
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
if (!subnode[i].IsEmpty)
isEmpty = false;
return isEmpty;
}
}
///
/// Insert items in this into the parameter!
///
/// IList for adding items.
/// Parameter IList with this items.
public IList AddAllItems(ref IList resultItems)
{
// this node may have items as well as subnodes (since items may not
// be wholely contained in any single subnode
// resultItems.addAll(this.items);
foreach (object o in this.items)
resultItems.Add(o);
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
subnode[i].AddAllItems(ref resultItems);
return resultItems;
}
///
///
///
///
///
protected abstract bool IsSearchMatch(IEnvelope searchEnv);
///
///
///
///
///
public void AddAllItemsFromOverlapping(IEnvelope searchEnv, ref IList resultItems)
{
if (!IsSearchMatch(searchEnv))
return;
// this node may have items as well as subnodes (since items may not
// be wholely contained in any single subnode
foreach (object o in this.items)
resultItems.Add(o);
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
subnode[i].AddAllItemsFromOverlapping(searchEnv, ref resultItems);
}
///
///
///
///
///
public void Visit(IEnvelope searchEnv, IItemVisitor visitor)
{
if (!IsSearchMatch(searchEnv))
return;
// this node may have items as well as subnodes (since items may not
// be wholely contained in any single subnode
VisitItems(searchEnv, visitor);
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
subnode[i].Visit(searchEnv, visitor);
}
///
///
///
///
///
private void VisitItems(IEnvelope searchEnv, IItemVisitor visitor)
{
// would be nice to filter items based on search envelope, but can't until they contain an envelope
for (IEnumerator i = items.GetEnumerator(); i.MoveNext(); )
visitor.VisitItem(i.Current);
}
///
///
///
public int Depth
{
get
{
int maxSubDepth = 0;
for (int i = 0; i < 4; i++)
{
if (subnode[i] != null)
{
int sqd = subnode[i].Depth;
if (sqd > maxSubDepth)
maxSubDepth = sqd;
}
}
return maxSubDepth + 1;
}
}
///
///
///
public int Count
{
get
{
int subSize = 0;
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
subSize += subnode[i].Count;
return subSize + items.Count;
}
}
///
///
///
public int NodeCount
{
get
{
int subSize = 0;
for (int i = 0; i < 4; i++)
if (subnode[i] != null)
subSize += subnode[i].Count;
return subSize + 1;
}
}
}
}