1 | 'use strict';
|
2 | var utils = require('./utils');
|
3 | var uuid = require('node-uuid');
|
4 | var checkNew = require('./checkNew');
|
5 | module.exports = insert;
|
6 |
|
7 | function insert(self, id, bbox, nodeID, height, store) {
|
8 | store = store || self.store;
|
9 | if (!nodeID) {
|
10 | if (!self.root) {
|
11 | return store.batch([
|
12 | {
|
13 | key:'root',
|
14 | value: {
|
15 | bbox: bbox,
|
16 | id: 'root',
|
17 | level: 1,
|
18 | children: [{
|
19 | id: id,
|
20 | bbox: bbox,
|
21 | leaf:true
|
22 | }]
|
23 | }
|
24 | },
|
25 | {
|
26 | key:'$' + id,
|
27 | value:[bbox]
|
28 | }
|
29 | ]).then(function (resp){
|
30 | self.root = 'root';
|
31 | return resp;
|
32 | });
|
33 | } else {
|
34 | return insert(self, id, bbox, self.root, height, store);
|
35 | }
|
36 | }
|
37 | return choosePath(store, bbox, nodeID, [], height).then(function (path) {
|
38 | var leaf = path[path.length - 1];
|
39 | if (height) {
|
40 | leaf.children.push({
|
41 | id: id,
|
42 | bbox: bbox
|
43 | });
|
44 | } else {
|
45 | leaf.children.push({
|
46 | id: id,
|
47 | bbox: bbox,
|
48 | leaf: true
|
49 | });
|
50 | }
|
51 | leaf.bbox = utils.enlarge(bbox, leaf.bbox);
|
52 | if (leaf.children.length >= self.MAX) {
|
53 | splitLeaf(self, path);
|
54 | }
|
55 | return updatePath(store, path);
|
56 | });
|
57 | }
|
58 |
|
59 |
|
60 | function splitLeaf(self, path) {
|
61 | var i = path.length;
|
62 | var newNode, splitedNode;
|
63 | while (--i && path[i].children.length >= self.MAX) {
|
64 | newNode = utils.splitNode(path[i], self.MIN);
|
65 | path[i - 1].children.push({
|
66 | id: newNode.id,
|
67 | bbox: newNode.bbox
|
68 | });
|
69 | path.push(newNode);
|
70 | }
|
71 | if (i === 0 && path[0].children.length >= self.MAX) {
|
72 | newNode = {
|
73 | id: uuid.v4(),
|
74 | bbox: [path[0].bbox[0].slice(), path[0].bbox[1].slice()],
|
75 | children: path[0].children,
|
76 | level: path[0].level
|
77 | };
|
78 | path.push(newNode);
|
79 | splitedNode = utils.splitNode(newNode, self.MIN);
|
80 | path.push(splitedNode);
|
81 | path[0].level++;
|
82 | path[0].children = [{
|
83 | id: newNode.id,
|
84 | bbox: newNode.bbox
|
85 | }, {
|
86 | id: splitedNode.id,
|
87 | bbox: splitedNode.bbox
|
88 | }];
|
89 | }
|
90 | }
|
91 |
|
92 |
|
93 | function updatePath (store, path) {
|
94 | return store.batch(path.map(function (item) {
|
95 | return {
|
96 | type: 'put',
|
97 | key: item.id,
|
98 | value: item
|
99 | };
|
100 | }));
|
101 | }
|
102 | function choosePath(store, bbox, rootID, path, height) {
|
103 | path = path || [];
|
104 | return store.get(rootID).then(function (node) {
|
105 | path.push(node);
|
106 | if (node.children[0].leaf || node.height < height) {
|
107 | return path;
|
108 | }
|
109 | var bestFit = findBestFit(bbox, node.children);
|
110 | node.children[bestFit.index].bbox = bestFit.bbox;
|
111 | node.bbox = utils.enlarge(bbox, node.bbox);
|
112 | return choosePath(store, bbox, bestFit.id, path);
|
113 | });
|
114 | }
|
115 |
|
116 | function findBestFit(bbox, children) {
|
117 | var i = 0;
|
118 | var bestFitNode = children[0];
|
119 | var lastEnlargment = utils.enlarge(bbox, children[0].bbox);
|
120 | var bestArea = utils.area(lastEnlargment);
|
121 | var index = 0;
|
122 | var len = children.length;
|
123 | var area, enlarged;
|
124 | while (++i < len) {
|
125 | enlarged = utils.enlarge(bbox, children[i].bbox);
|
126 | area = utils.area(enlarged);
|
127 | if (area < bestArea) {
|
128 | index = i;
|
129 | bestFitNode = children[i];
|
130 | bestArea = area;
|
131 | }
|
132 | }
|
133 | return {
|
134 | id: bestFitNode.id,
|
135 | bbox: lastEnlargment,
|
136 | index: index
|
137 | };
|
138 | } |
\ | No newline at end of file |