using System;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
namespace GisSharpBlog.NetTopologySuite.Index.Quadtree
{
///
/// A Key is a unique identifier for a node in a quadtree.
/// It contains a lower-left point and a level number. The level number
/// is the power of two for the size of the node envelope.
///
public class Key
{
///
///
///
///
///
public static int ComputeQuadLevel(IEnvelope env)
{
double dx = env.Width;
double dy = env.Height;
double dMax = dx > dy ? dx : dy;
int level = DoubleBits.GetExponent(dMax) + 1;
return level;
}
// the fields which make up the key
private ICoordinate pt = new Coordinate();
private int level = 0;
// auxiliary data which is derived from the key for use in computation
private IEnvelope env = null;
///
///
///
///
public Key(IEnvelope itemEnv)
{
ComputeKey(itemEnv);
}
///
///
///
public ICoordinate Point
{
get
{
return pt;
}
}
///
///
///
public int Level
{
get
{
return level;
}
}
///
///
///
public IEnvelope Envelope
{
get
{
return env;
}
}
///
///
///
public ICoordinate Centre
{
get
{
return new Coordinate((env.MinX + env.MaxX) / 2, (env.MinY + env.MaxY) / 2);
}
}
///
/// Return a square envelope containing the argument envelope,
/// whose extent is a power of two and which is based at a power of 2.
///
///
public void ComputeKey(IEnvelope itemEnv)
{
level = ComputeQuadLevel(itemEnv);
env = new Envelope();
ComputeKey(level, itemEnv);
// MD - would be nice to have a non-iterative form of this algorithm
while (!env.Contains(itemEnv))
{
level += 1;
ComputeKey(level, itemEnv);
}
}
///
///
///
///
///
private void ComputeKey(int level, IEnvelope itemEnv)
{
double quadSize = DoubleBits.PowerOf2(level);
pt.X = Math.Floor(itemEnv.MinX / quadSize) * quadSize;
pt.Y = Math.Floor(itemEnv.MinY / quadSize) * quadSize;
env.Init(pt.X, pt.X + quadSize, pt.Y, pt.Y + quadSize);
}
}
}