提交 289e69de authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent multi-version map: move to the main source tree

上级 bd50328e
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.dev.store.rtree;
import java.util.Arrays;
/**
* A unique spatial key.
*/
public class SpatialKey {
private final long id;
private final float[] minMax;
/**
* Create a new key.
*
* @param id the id
* @param minMax min x, max x, min y, max y, and so on
*/
public SpatialKey(long id, float... minMax) {
this.id = id;
this.minMax = minMax;
}
/**
* Get the minimum value for the given dimension.
*
* @param dim the dimension
* @return the value
*/
public float min(int dim) {
return minMax[dim + dim];
}
/**
* Set the minimum value for the given dimension.
*
* @param dim the dimension
* @param x the value
*/
public void setMin(int dim, float x) {
minMax[dim + dim] = x;
}
/**
* Get the maximum value for the given dimension.
*
* @param dim the dimension
* @return the value
*/
public float max(int dim) {
return minMax[dim + dim + 1];
}
/**
* Set the maximum value for the given dimension.
*
* @param dim the dimension
* @param x the value
*/
public void setMax(int dim, float x) {
minMax[dim + dim + 1] = x;
}
public long getId() {
return id;
}
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append(id).append(": (");
for (int i = 0; i < minMax.length; i += 2) {
if (i > 0) {
buff.append(", ");
}
buff.append(minMax[i]).append('/').append(minMax[i + 1]);
}
return buff.append(")").toString();
}
public int hashCode() {
return (int) ((id >>> 32) ^ id);
}
public boolean equals(Object other) {
if (!(other instanceof SpatialKey)) {
return false;
}
SpatialKey o = (SpatialKey) other;
return Arrays.equals(minMax, o.minMax);
}
}
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.dev.store.rtree;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import org.h2.dev.store.btree.DataUtils;
import org.h2.dev.store.type.DataType;
/**
* A spatial data type. This class supports up to 255 dimensions. Each dimension
* can have a minimum and a maximum value of type float. For each dimension, the
* maximum value is only stored when it is not the same as the minimum.
*/
public class SpatialType implements DataType {
private final int dimensions;
public SpatialType(int dimensions) {
if (dimensions <= 0 || dimensions > 255) {
throw new IllegalArgumentException("Dimensions: " + dimensions);
}
this.dimensions = dimensions;
}
/**
* Read a value from a string.
*
* @param s the string
* @return the value
*/
public static SpatialType fromString(String s) {
return new SpatialType(Integer.parseInt(s.substring(1)));
}
@Override
public int compare(Object a, Object b) {
long la = ((SpatialKey) a).getId();
long lb = ((SpatialKey) b).getId();
return la < lb ? -1 : la > lb ? 1 : 0;
}
/**
* Check whether two spatial values are equal.
*
* @param a the first value
* @param b the second value
* @return true if they are equal
*/
public boolean equals(Object a, Object b) {
long la = ((SpatialKey) a).getId();
long lb = ((SpatialKey) b).getId();
return la == lb;
}
@Override
public int getMaxLength(Object obj) {
return 1 + dimensions * 8 + DataUtils.MAX_VAR_LONG_LEN;
}
@Override
public int getMemory(Object obj) {
return 40 + dimensions * 4;
}
@Override
public void write(ByteBuffer buff, Object obj) {
SpatialKey k = (SpatialKey) obj;
int flags = 0;
for (int i = 0; i < dimensions; i++) {
if (k.min(i) == k.max(i)) {
flags |= 1 << i;
}
}
DataUtils.writeVarInt(buff, flags);
for (int i = 0; i < dimensions; i++) {
buff.putFloat(k.min(i));
if ((flags & (1 << i)) == 0) {
buff.putFloat(k.max(i));
}
}
DataUtils.writeVarLong(buff, k.getId());
}
@Override
public Object read(ByteBuffer buff) {
int flags = DataUtils.readVarInt(buff);
float[] minMax = new float[dimensions * 2];
for (int i = 0; i < dimensions; i++) {
float min = buff.getFloat();
float max;
if ((flags & (1 << i)) != 0) {
max = min;
} else {
max = buff.getFloat();
}
minMax[i + i] = min;
minMax[i + i + 1] = max;
}
long id = DataUtils.readVarLong(buff);
return new SpatialKey(id, minMax);
}
@Override
public String asString() {
return "s" + dimensions;
}
/**
* Check whether the two objects overlap.
*
* @param objA the first object
* @param objB the second object
* @return true if they overlap
*/
public boolean isOverlap(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
for (int i = 0; i < dimensions; i++) {
if (a.max(i) < b.min(i) || a.min(i) > b.max(i)) {
return false;
}
}
return true;
}
/**
* Increase the bounds in the given spatial object.
*
* @param bounds the bounds (may be modified)
* @param add the value
*/
public void increaseBounds(Object bounds, Object add) {
SpatialKey b = (SpatialKey) bounds;
SpatialKey a = (SpatialKey) add;
for (int i = 0; i < dimensions; i++) {
b.setMin(i, Math.min(b.min(i), a.min(i)));
b.setMax(i, Math.max(b.max(i), a.max(i)));
}
}
/**
* Get the area increase by extending a to contain b.
*
* @param objA the bounding box
* @param objB the object
* @return the area
*/
public float getAreaIncrease(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
float min = a.min(0);
float max = a.max(0);
float areaOld = max - min;
min = Math.min(min, b.min(0));
max = Math.max(max, b.max(0));
float areaNew = max - min;
for (int i = 1; i < dimensions; i++) {
min = a.min(i);
max = a.max(i);
areaOld *= max - min;
min = Math.min(min, b.min(i));
max = Math.max(max, b.max(i));
areaNew *= max - min;
}
return areaNew - areaOld;
}
/**
* Get the combined area of both objects.
*
* @param objA the first object
* @param objB the second object
* @return the area
*/
float getCombinedArea(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
float area = 1;
for (int i = 0; i < dimensions; i++) {
float min = Math.min(a.min(i), b.min(i));
float max = Math.max(a.max(i), b.max(i));
area *= max - min;
}
return area;
}
/**
* Check whether a contains b.
*
* @param objA the bounding box
* @param objB the object
* @return the area
*/
public boolean contains(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
for (int i = 0; i < dimensions; i++) {
if (a.min(i) > b.min(i) || a.max(i) < b.max(i)) {
return false;
}
}
return true;
}
/**
* Check whether a is completely inside b and does not touch the
* given bound.
*
* @param objA the object to check
* @param objB the bounds
* @return true if a is completely inside b
*/
public boolean isInside(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
for (int i = 0; i < dimensions; i++) {
if (a.min(i) <= b.min(i) || a.max(i) >= b.max(i)) {
return false;
}
}
return true;
}
/**
* Create a bounding box starting with the given object.
*
* @param objA the object
* @return the bounding box
*/
Object createBoundingBox(Object objA) {
float[] minMax = new float[dimensions * 2];
SpatialKey a = (SpatialKey) objA;
for (int i = 0; i < dimensions; i++) {
minMax[i + i] = a.min(i);
minMax[i + i + 1] = a.max(i);
}
return new SpatialKey(0, minMax);
}
/**
* Get the most extreme pair (elements that are as far apart as possible).
* This method is used to split a page (linear split). If no extreme objects
* could be found, this method returns null.
*
* @param list the objects
* @return the indexes of the extremes
*/
public int[] getExtremes(ArrayList<Object> list) {
SpatialKey bounds = (SpatialKey) createBoundingBox(list.get(0));
SpatialKey boundsInner = (SpatialKey) createBoundingBox(bounds);
for (int i = 0; i < dimensions; i++) {
float t = boundsInner.min(i);
boundsInner.setMin(i, boundsInner.max(i));
boundsInner.setMax(i, t);
}
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
increaseBounds(bounds, o);
increaseMaxInnerBounds(boundsInner, o);
}
double best = 0;
int bestDim = 0;
for (int i = 0; i < dimensions; i++) {
float inner = boundsInner.max(i) - boundsInner.min(i);
if (inner < 0) {
continue;
}
float outer = bounds.max(i) - bounds.min(i);
float d = inner / outer;
if (d > best) {
best = d;
bestDim = i;
}
}
if (best <= 0) {
return null;
}
float min = boundsInner.min(bestDim);
float max = boundsInner.max(bestDim);
int firstIndex = -1, lastIndex = -1;
for (int i = 0; i < list.size() && (firstIndex < 0 || lastIndex < 0); i++) {
SpatialKey o = (SpatialKey) list.get(i);
if (firstIndex < 0 && o.max(bestDim) == min) {
firstIndex = i;
} else if (lastIndex < 0 && o.min(bestDim) == max) {
lastIndex = i;
}
}
return new int[] { firstIndex, lastIndex };
}
private void increaseMaxInnerBounds(Object bounds, Object add) {
SpatialKey b = (SpatialKey) bounds;
SpatialKey a = (SpatialKey) add;
for (int i = 0; i < dimensions; i++) {
b.setMin(i, Math.min(b.min(i), a.max(i)));
b.setMax(i, Math.max(b.max(i), a.min(i)));
}
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, Version 1.0,
and under the Eclipse Public License, Version 1.0
(http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
An R-tree implementation
</p></body></html>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论