21
21
import java .util .function .Predicate ;
22
22
23
23
import org .tinspin .index .*;
24
+ import org .tinspin .index .util .MathTools ;
24
25
import org .tinspin .index .util .StringBuilderLn ;
25
26
26
27
/**
@@ -94,7 +95,9 @@ public void insert(double[] key, T value) {
94
95
PointEntry <T > e = new PointEntry <>(key , value );
95
96
if (root == null ) {
96
97
// We calculate a better radius when adding a second point.
97
- root = new QNode <>(key .clone (), INITIAL_RADIUS );
98
+ // We align the center to a power of two. That reduces precision problems when
99
+ // creating subnode centers.
100
+ root = new QNode <>(MathTools .floorPowerOfTwoCopy (key ), INITIAL_RADIUS );
98
101
}
99
102
if (root .getRadius () == INITIAL_RADIUS ) {
100
103
adjustRootSize (key );
@@ -113,10 +116,17 @@ private void adjustRootSize(double[] key) {
113
116
return ;
114
117
}
115
118
if (root .getRadius () == INITIAL_RADIUS ) {
116
- // We just use Euclidean here, that should be good enough in all cases.
117
- double dist = PointDistance .L2 .dist (key , root .getCenter ());
118
- if (dist > 0 ) {
119
- root .adjustRadius (2 * dist );
119
+ // Root size has not been initialized yet.
120
+ // We start by getting the maximum horizontal distance between the node center and any point in the node
121
+ double dMax = MathTools .maxDelta (key , root .getCenter ());
122
+ for (int i = 0 ; i < root .getEntries ().size (); i ++) {
123
+ dMax = Math .max (dMax , MathTools .maxDelta (root .getEntries ().get (i ).point (), root .getCenter ()));
124
+ }
125
+ // We calculate the minimum required radius that is also a power of two.
126
+ // This radius can be divided by 2 many times without precision problems.
127
+ double radius = MathTools .ceilPowerOfTwo (dMax + QUtil .EPS_MUL );
128
+ if (radius > 0 ) {
129
+ root .adjustRadius (radius );
120
130
} else if (root .getEntries ().size () >= maxNodeSize - 1 ) {
121
131
// we just set an arbitrary radius here
122
132
root .adjustRadius (1000 );
0 commit comments