librtree 0.9.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/COPYING +21 -0
- data/README.md +87 -0
- data/ext/rtree/extconf.rb +37 -19
- data/ext/rtree/lib/README.md +9 -0
- data/ext/rtree/lib/bindex.c +157 -0
- data/ext/rtree/lib/bindex.h +31 -0
- data/ext/rtree/lib/bounds.h +21 -0
- data/ext/rtree/lib/branch.c +51 -0
- data/ext/rtree/lib/branches.c +17 -0
- data/ext/rtree/lib/bsrt.c +704 -0
- data/ext/rtree/lib/bsrt.h +16 -0
- data/ext/rtree/lib/constants.h +19 -0
- data/ext/rtree/lib/csv.c +81 -0
- data/ext/rtree/lib/csv.h +16 -0
- data/ext/rtree/lib/endianness.h +83 -0
- data/ext/rtree/lib/error.c +47 -0
- data/ext/rtree/lib/json.c +491 -0
- data/ext/rtree/lib/json.h +16 -0
- data/ext/rtree/lib/mk/Hdr.mk +3 -0
- data/ext/rtree/lib/mk/MakeDepend +25 -0
- data/ext/rtree/lib/mk/Obj.mk +3 -0
- data/ext/rtree/lib/node.c +736 -0
- data/ext/rtree/lib/package.c +11 -0
- data/ext/rtree/lib/page.c +47 -0
- data/ext/rtree/lib/page.h +13 -0
- data/ext/rtree/lib/postscript.c +543 -0
- data/ext/rtree/lib/rect.c +139 -0
- data/ext/rtree/lib/rectf.c +219 -0
- data/ext/rtree/lib/rtree/branch.h +105 -0
- data/ext/rtree/lib/rtree/branches.h +38 -0
- data/ext/rtree/lib/rtree/error.h +42 -0
- data/ext/rtree/lib/rtree/extent.h +20 -0
- data/ext/rtree/lib/rtree/node.h +96 -0
- data/ext/rtree/lib/rtree/package.h +14 -0
- data/ext/rtree/lib/rtree/postscript.h +66 -0
- data/ext/rtree/lib/rtree/rect.h +38 -0
- data/ext/rtree/lib/rtree/rectf.h +34 -0
- data/ext/rtree/lib/rtree/search.h +27 -0
- data/ext/rtree/lib/rtree/state.h +113 -0
- data/ext/rtree/lib/rtree/types.h +14 -0
- data/ext/rtree/lib/rtree-base.c +197 -0
- data/ext/rtree/lib/rtree.h +62 -0
- data/ext/rtree/lib/search.c +54 -0
- data/ext/rtree/lib/split.c +710 -0
- data/ext/rtree/lib/split.h +15 -0
- data/ext/rtree/lib/spvol.c +48 -0
- data/ext/rtree/lib/spvol.h +13 -0
- data/ext/rtree/lib/state.c +169 -0
- data/ext/rtree/rtree.c +11 -0
- data/lib/rtree.rb +4 -4
- metadata +65 -3
data/ext/rtree/lib/csv.c
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#ifdef HAVE_CONFIG_H
|
2
|
+
#include "config.h"
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#include "csv.h"
|
6
|
+
|
7
|
+
#include "rtree/error.h"
|
8
|
+
#include "rtree/types.h"
|
9
|
+
|
10
|
+
#include <errno.h>
|
11
|
+
#include <string.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
|
14
|
+
#define LINE_LEN 0x1000
|
15
|
+
|
16
|
+
static int parse(FILE *stream, rtree_t *rtree)
|
17
|
+
{
|
18
|
+
const size_t dims = state_dims(rtree->state);
|
19
|
+
rtree_coord_t rect[2 * dims];
|
20
|
+
char line[LINE_LEN];
|
21
|
+
|
22
|
+
/*
|
23
|
+
Note that fgets(3) reads from the stream up to LINE_LEN - 1,
|
24
|
+
or if an EOF or line-ending \n is found. That's behaviour
|
25
|
+
required by the C standard. CSV files should really have
|
26
|
+
CRLF line semantics, i.e., each line is terminated by \r\n,
|
27
|
+
in that case, fgets will still read up to the \n, so the \r
|
28
|
+
will be the last character written to the buffer. That's OK.
|
29
|
+
But, a line with just \r line endings will not be handled
|
30
|
+
correctly by this code, fgets(3) will not see a line ending
|
31
|
+
and so will read multiple lines into the buffer. Such files
|
32
|
+
might be found as output from old Macs, they are pretty rare,
|
33
|
+
so probably not worth the hassle of handling this case.
|
34
|
+
*/
|
35
|
+
|
36
|
+
while (fgets(line, LINE_LEN, stream) != NULL)
|
37
|
+
{
|
38
|
+
char *tok;
|
39
|
+
|
40
|
+
if ((tok = strtok(line, ",")) == NULL)
|
41
|
+
continue;
|
42
|
+
|
43
|
+
rtree_id_t id = strtoul(tok, NULL, 0);
|
44
|
+
|
45
|
+
for (size_t i = 0 ; i < 2 * dims - 1 ; i++)
|
46
|
+
{
|
47
|
+
if ((tok = strtok(NULL, ",")) == NULL)
|
48
|
+
return RTREE_ERR_CSVPARSE;
|
49
|
+
rect[i] = strtod(tok, NULL);
|
50
|
+
}
|
51
|
+
|
52
|
+
if ((tok = strtok(NULL, ",\n\r")) == NULL)
|
53
|
+
return RTREE_ERR_CSVPARSE;
|
54
|
+
rect[2 * dims - 1] = strtod(tok, NULL);
|
55
|
+
|
56
|
+
if (rtree_add_rect(rtree, id, rect) != 0)
|
57
|
+
return RTREE_ERR_CSVPARSE;
|
58
|
+
}
|
59
|
+
|
60
|
+
return RTREE_OK;
|
61
|
+
}
|
62
|
+
|
63
|
+
rtree_t* csv_rtree_read(FILE *stream, size_t dims, state_flags_t flags)
|
64
|
+
{
|
65
|
+
if (stream == NULL)
|
66
|
+
{
|
67
|
+
errno = EINVAL;
|
68
|
+
return NULL;
|
69
|
+
}
|
70
|
+
|
71
|
+
rtree_t *rtree;
|
72
|
+
|
73
|
+
if ((rtree = rtree_new(dims, flags)) != NULL)
|
74
|
+
{
|
75
|
+
if (parse(stream, rtree) == RTREE_OK)
|
76
|
+
return rtree;
|
77
|
+
rtree_destroy(rtree);
|
78
|
+
}
|
79
|
+
|
80
|
+
return NULL;
|
81
|
+
}
|
data/ext/rtree/lib/csv.h
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
/*
|
2
|
+
endian.h
|
3
|
+
|
4
|
+
This is an "internal" header, it is not used by any public headers
|
5
|
+
and not installed; it handles the messing around that you need to
|
6
|
+
do to get endinannes functions even close to portable.
|
7
|
+
|
8
|
+
This is largely from https://github.com/mikepb/endian.h which is
|
9
|
+
based on a Gist by Mathias Panzenböck, those are both released into
|
10
|
+
the public domain. It differs in that
|
11
|
+
|
12
|
+
- it uses autoconf to determine the existence of headers and
|
13
|
+
declarations, rather than "OS sniffing"
|
14
|
+
|
15
|
+
- it is only interested in the little-endian versions of the macros
|
16
|
+
since that's the only ones we use (one could add those in a fairly
|
17
|
+
obvious fashion though)
|
18
|
+
|
19
|
+
Copyright (c) J.J. Green 2020
|
20
|
+
*/
|
21
|
+
|
22
|
+
#ifndef ENDIANNESS_H
|
23
|
+
#define ENDIANNESS_H
|
24
|
+
|
25
|
+
#ifdef HAVE_CONFIG_H
|
26
|
+
#include "config.h"
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#if defined HAVE_ENDIAN_H
|
30
|
+
|
31
|
+
#include <endian.h>
|
32
|
+
|
33
|
+
#elif defined HAVE_SYS_ENDIAN_H
|
34
|
+
|
35
|
+
#include <sys/endian.h>
|
36
|
+
|
37
|
+
#ifndef HAVE_DECL_LE16TOH
|
38
|
+
#define le16toh(x) letoh16(x)
|
39
|
+
#endif
|
40
|
+
#ifndef HAVE_DECL_LE32TOH
|
41
|
+
#define le32toh(x) letoh32(x)
|
42
|
+
#endif
|
43
|
+
#ifndef HAVE_DECL_LE64TOH
|
44
|
+
#define le64toh(x) letoh64(x)
|
45
|
+
#endif
|
46
|
+
|
47
|
+
#elif defined HAVE_LIBKERN_OSBYTEORDER_H
|
48
|
+
|
49
|
+
#include <libkern/OSByteOrder.h>
|
50
|
+
#define htole16(x) OSSwapHostToLittleInt16(x)
|
51
|
+
#define le16toh(x) OSSwapLittleToHostInt16(x)
|
52
|
+
#define htole32(x) OSSwapHostToLittleInt32(x)
|
53
|
+
#define le32toh(x) OSSwapLittleToHostInt32(x)
|
54
|
+
#define htole64(x) OSSwapHostToLittleInt64(x)
|
55
|
+
#define le64toh(x) OSSwapLittleToHostInt64(x)
|
56
|
+
|
57
|
+
#elif defined HAVE_WINSOCK2_H
|
58
|
+
|
59
|
+
#include <winsock2.h>
|
60
|
+
#include <sys/param.h>
|
61
|
+
#if BYTE_ORDER == LITTLE_ENDIAN
|
62
|
+
#define htole16(x) (x)
|
63
|
+
#define le16toh(x) (x)
|
64
|
+
#define htole32(x) (x)
|
65
|
+
#define le32toh(x) (x)
|
66
|
+
#define htole64(x) (x)
|
67
|
+
#define le64toh(x) (x)
|
68
|
+
#elif BYTE_ORDER == BIG_ENDIAN
|
69
|
+
#define htole16(x) __builtin_bswap16(x)
|
70
|
+
#define le16toh(x) __builtin_bswap16(x)
|
71
|
+
#define htole32(x) __builtin_bswap32(x)
|
72
|
+
#define le32toh(x) __builtin_bswap32(x)
|
73
|
+
#define htole64(x) __builtin_bswap64(x)
|
74
|
+
#define le64toh(x) __builtin_bswap64(x)
|
75
|
+
#endif
|
76
|
+
|
77
|
+
#else
|
78
|
+
|
79
|
+
#error No compatible endianness header available
|
80
|
+
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#endif
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#ifdef HAVE_CONFIG_H
|
2
|
+
#include "config.h"
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#include <stdlib.h>
|
6
|
+
|
7
|
+
#include "rtree/error.h"
|
8
|
+
|
9
|
+
const char* strerror_rtree(int err)
|
10
|
+
{
|
11
|
+
static const char nomsg[] = "unimplemented message";
|
12
|
+
struct
|
13
|
+
{
|
14
|
+
int err;
|
15
|
+
const char *msg;
|
16
|
+
} *m, mtab[] =
|
17
|
+
{
|
18
|
+
{ RTREE_OK, "Success" },
|
19
|
+
{ RTREE_ERR_INVAL, "Invalid argument" },
|
20
|
+
{ RTREE_ERR_DOM, "Argument outside domain" },
|
21
|
+
{ RTREE_ERR_NOMEM, "Out of memory" },
|
22
|
+
{ RTREE_ERR_CSVPARSE, "Error parsing CSV" },
|
23
|
+
{ RTREE_ERR_NOCSV, "Compiled without CSV support" },
|
24
|
+
{ RTREE_ERR_JANSSON, "Error from the Jansson library" },
|
25
|
+
{ RTREE_ERR_NOJSON, "Compiled without JSON support" },
|
26
|
+
{ RTREE_ERR_NOJSON, "Compiled without BSRT support" },
|
27
|
+
{ RTREE_ERR_GETBRANCH, "Error getting branch" },
|
28
|
+
{ RTREE_ERR_GETCHILD, "Error getting child node" },
|
29
|
+
{ RTREE_ERR_NODECLONE, "Error cloning node" },
|
30
|
+
{ RTREE_ERR_PICKBRANCH, "Error picking branch" },
|
31
|
+
{ RTREE_ERR_ADDRECT, "Error adding rectangle" },
|
32
|
+
{ RTREE_ERR_NOSUCHSPLIT, "No such splitting method" },
|
33
|
+
{ RTREE_ERR_DIMS, "Bad R-tree dimension" },
|
34
|
+
{ RTREE_ERR_EMPTY, "Empty R-tree" },
|
35
|
+
{ RTREE_ERR_BUFFER, "Buffer to small" },
|
36
|
+
{ RTREE_ERR_POSTSCRIPT, "Error generating PostScript" },
|
37
|
+
{ RTREE_ERR_USER, "User abort" },
|
38
|
+
{ RTREE_ERR_FWRITE, "Failed write" },
|
39
|
+
{ RTREE_ERR_SPLIT, "Error in split" },
|
40
|
+
{ -1, NULL }
|
41
|
+
};
|
42
|
+
|
43
|
+
for (m = mtab ; m->msg ; m++)
|
44
|
+
if (m->err == err) return m->msg;
|
45
|
+
|
46
|
+
return nomsg;
|
47
|
+
}
|
@@ -0,0 +1,491 @@
|
|
1
|
+
#ifdef HAVE_CONFIG_H
|
2
|
+
#include "config.h"
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#include "json.h"
|
6
|
+
#include "bounds.h"
|
7
|
+
|
8
|
+
#include "rtree/error.h"
|
9
|
+
#include "rtree/branches.h"
|
10
|
+
|
11
|
+
#include <errno.h>
|
12
|
+
|
13
|
+
#ifdef WITH_JSON
|
14
|
+
|
15
|
+
#include <jansson.h>
|
16
|
+
|
17
|
+
/*
|
18
|
+
This module exports json_rtree_read(), json_rtree_write() but
|
19
|
+
we make a change in our usual naming conventions in having all
|
20
|
+
static functions prefixed "jr/w_" (for JSON reed/write) since
|
21
|
+
the Jansson library uses the "json_" prefix, so to avoid a clash
|
22
|
+
with that namespace
|
23
|
+
*/
|
24
|
+
|
25
|
+
static json_t* jw_leaf(const state_t *state, const branch_t *branch)
|
26
|
+
{
|
27
|
+
json_t *jb = json_object(), *jr = json_array();
|
28
|
+
const rtree_coord_t *rect = branch_get_rect((branch_t*)branch);
|
29
|
+
const size_t dims = state_dims(state);
|
30
|
+
const unsigned long id = branch_get_id(branch);
|
31
|
+
|
32
|
+
for (size_t i = 0 ; i < 2 * dims ; i++)
|
33
|
+
json_array_append_new(jr, json_real(rect[i]));
|
34
|
+
|
35
|
+
json_object_set_new(jb, "rect", jr);
|
36
|
+
json_object_set_new(jb, "id", json_integer(id));
|
37
|
+
|
38
|
+
return jb;
|
39
|
+
}
|
40
|
+
|
41
|
+
static int jw_leaf_f(const state_t *state, const branch_t *branch, void *arg)
|
42
|
+
{
|
43
|
+
json_t *ja = (json_t*)arg, *jb;
|
44
|
+
|
45
|
+
if ((jb = jw_leaf(state, branch)) != NULL)
|
46
|
+
{
|
47
|
+
json_array_append_new(ja, jb);
|
48
|
+
return 0;
|
49
|
+
}
|
50
|
+
|
51
|
+
return 1;
|
52
|
+
}
|
53
|
+
|
54
|
+
static json_t* jw_node(const state_t*, const node_t*);
|
55
|
+
|
56
|
+
static int jw_branch_f(const state_t *state, const branch_t *branch, void *arg)
|
57
|
+
{
|
58
|
+
const size_t dims = state_dims(state);
|
59
|
+
|
60
|
+
json_t *jr;
|
61
|
+
if ((jr = json_array()) != NULL)
|
62
|
+
{
|
63
|
+
const rtree_coord_t *rect;
|
64
|
+
if ((rect = branch_get_rect((branch_t*)branch)) != NULL)
|
65
|
+
{
|
66
|
+
for (size_t i = 0 ; i < 2 * dims ; i++)
|
67
|
+
json_array_append_new(jr, json_real(rect[i]));
|
68
|
+
|
69
|
+
const node_t *child;
|
70
|
+
if ((child = branch_get_child(branch)) != NULL)
|
71
|
+
{
|
72
|
+
json_t *jb;
|
73
|
+
if ((jb = json_object()) != NULL)
|
74
|
+
{
|
75
|
+
json_t *jn;
|
76
|
+
if ((jn = jw_node(state, child)) != NULL)
|
77
|
+
{
|
78
|
+
json_object_set_new(jb, "rect", jr);
|
79
|
+
json_object_set_new(jb, "node", jn);
|
80
|
+
json_array_append_new((json_t*)arg, jb);
|
81
|
+
|
82
|
+
return 0;
|
83
|
+
}
|
84
|
+
json_decref(jb);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
json_decref(jr);
|
89
|
+
}
|
90
|
+
|
91
|
+
return 1;
|
92
|
+
}
|
93
|
+
|
94
|
+
static json_t* jw_branch(const state_t *state, const node_t *node)
|
95
|
+
{
|
96
|
+
json_t *json;
|
97
|
+
nbe_cb_t *json_f;
|
98
|
+
|
99
|
+
if (node_level(node) == 0)
|
100
|
+
json_f = jw_leaf_f;
|
101
|
+
else
|
102
|
+
json_f = jw_branch_f;
|
103
|
+
|
104
|
+
if ((json = json_array()) != NULL)
|
105
|
+
{
|
106
|
+
if (node_branch_each(state, node, json_f, json) == 0)
|
107
|
+
return json;
|
108
|
+
json_decref(json);
|
109
|
+
}
|
110
|
+
|
111
|
+
return NULL;
|
112
|
+
}
|
113
|
+
|
114
|
+
static json_t* jw_node(const state_t *state, const node_t *node)
|
115
|
+
{
|
116
|
+
json_t *json;
|
117
|
+
|
118
|
+
if ((json = json_object()) == NULL)
|
119
|
+
return NULL;
|
120
|
+
|
121
|
+
json_object_set_new(json, "level", json_integer(node_level(node)));
|
122
|
+
json_object_set_new(json, "count", json_integer(node_count(node)));
|
123
|
+
json_object_set_new(json, "branches", jw_branch(state, node));
|
124
|
+
|
125
|
+
return json;
|
126
|
+
}
|
127
|
+
|
128
|
+
static json_t* jw_state(const state_t *state)
|
129
|
+
{
|
130
|
+
json_t *json;
|
131
|
+
|
132
|
+
if ((json = json_object()) == NULL)
|
133
|
+
return NULL;
|
134
|
+
|
135
|
+
const size_t
|
136
|
+
dims = state_dims(state),
|
137
|
+
page_size = state_page_size(state),
|
138
|
+
branch_size = state_branch_size(state),
|
139
|
+
node_size = state_node_size(state),
|
140
|
+
rect_size = state_rect_size(state),
|
141
|
+
float_size = sizeof(rtree_coord_t);
|
142
|
+
|
143
|
+
json_object_set_new(json, "dims", json_integer(dims));
|
144
|
+
json_object_set_new(json, "page_size", json_integer(page_size));
|
145
|
+
json_object_set_new(json, "float_size", json_integer(float_size));
|
146
|
+
json_object_set_new(json, "rect_size", json_integer(rect_size));
|
147
|
+
json_object_set_new(json, "branch_size", json_integer(branch_size));
|
148
|
+
json_object_set_new(json, "node_size", json_integer(node_size));
|
149
|
+
|
150
|
+
return json;
|
151
|
+
}
|
152
|
+
|
153
|
+
static json_t* jw_rtree(const rtree_t *rtree)
|
154
|
+
{
|
155
|
+
json_t *json;
|
156
|
+
|
157
|
+
if ((json = json_object()) == NULL)
|
158
|
+
return NULL;
|
159
|
+
|
160
|
+
json_object_set_new(json, "root", jw_node(rtree->state, rtree->root));
|
161
|
+
json_object_set_new(json, "state", jw_state(rtree->state));
|
162
|
+
|
163
|
+
return json;
|
164
|
+
}
|
165
|
+
|
166
|
+
int json_rtree_write(const rtree_t *rtree, FILE *stream)
|
167
|
+
{
|
168
|
+
json_t *json;
|
169
|
+
int err = 0;
|
170
|
+
|
171
|
+
if ((json = jw_rtree(rtree)) != NULL)
|
172
|
+
{
|
173
|
+
if (json_dumpf(json, stream, JSON_INDENT(2)) != 0)
|
174
|
+
err++;
|
175
|
+
json_decref(json);
|
176
|
+
}
|
177
|
+
else
|
178
|
+
err++;
|
179
|
+
|
180
|
+
return err ? RTREE_ERR_JANSSON : RTREE_OK;
|
181
|
+
}
|
182
|
+
|
183
|
+
/* reader */
|
184
|
+
|
185
|
+
static bool jr_value_equal(json_t *object, const char *key, size_t value)
|
186
|
+
{
|
187
|
+
json_t *json_value = json_object_get(object, key);
|
188
|
+
|
189
|
+
if ((json_value == NULL) || (json_is_integer(json_value) == false))
|
190
|
+
return false;
|
191
|
+
|
192
|
+
json_int_t int_value = json_integer_value(json_value);
|
193
|
+
|
194
|
+
return (int_value >= 0) && ((size_t)int_value == value);
|
195
|
+
}
|
196
|
+
|
197
|
+
static bool jr_state_is_consistent(json_t *json_state, state_t *state)
|
198
|
+
{
|
199
|
+
return
|
200
|
+
jr_value_equal(json_state, "dims", state_dims(state)) &&
|
201
|
+
jr_value_equal(json_state, "page_size", state_page_size(state)) &&
|
202
|
+
jr_value_equal(json_state, "float_size", sizeof(rtree_coord_t)) &&
|
203
|
+
jr_value_equal(json_state, "rect_size", state_rect_size(state)) &&
|
204
|
+
jr_value_equal(json_state, "branch_size", state_branch_size(state)) &&
|
205
|
+
jr_value_equal(json_state, "node_size", state_node_size(state));
|
206
|
+
}
|
207
|
+
|
208
|
+
static state_t* jr_state(json_t *json)
|
209
|
+
{
|
210
|
+
json_t *json_state;
|
211
|
+
|
212
|
+
if ((json_state = json_object_get(json, "state")) == NULL)
|
213
|
+
return NULL;
|
214
|
+
|
215
|
+
if (! json_is_object(json_state))
|
216
|
+
return NULL;
|
217
|
+
|
218
|
+
size_t dims;
|
219
|
+
|
220
|
+
{
|
221
|
+
json_t *json_dims;
|
222
|
+
|
223
|
+
if ((json_dims = json_object_get(json_state, "dims")) == NULL)
|
224
|
+
return NULL;
|
225
|
+
|
226
|
+
if (! json_is_integer(json_dims))
|
227
|
+
return NULL;
|
228
|
+
|
229
|
+
dims = json_integer_value(json_dims);
|
230
|
+
|
231
|
+
if (dims > RTREE_DIMS_MAX)
|
232
|
+
return NULL;
|
233
|
+
}
|
234
|
+
|
235
|
+
size_t page_size;
|
236
|
+
|
237
|
+
{
|
238
|
+
json_t *json_page_size;
|
239
|
+
|
240
|
+
if ((json_page_size = json_object_get(json_state, "page_size")) == NULL)
|
241
|
+
return NULL;
|
242
|
+
|
243
|
+
if (! json_is_integer(json_page_size))
|
244
|
+
return NULL;
|
245
|
+
|
246
|
+
page_size = json_integer_value(json_page_size);
|
247
|
+
}
|
248
|
+
|
249
|
+
size_t node_size;
|
250
|
+
|
251
|
+
{
|
252
|
+
json_t *json_node_size;
|
253
|
+
|
254
|
+
if ((json_node_size = json_object_get(json_state, "node_size")) == NULL)
|
255
|
+
return NULL;
|
256
|
+
|
257
|
+
if (! json_is_integer(json_node_size))
|
258
|
+
return NULL;
|
259
|
+
|
260
|
+
node_size = json_integer_value(json_node_size);
|
261
|
+
}
|
262
|
+
|
263
|
+
const size_t node_page = page_size / node_size;
|
264
|
+
|
265
|
+
state_t *state;
|
266
|
+
|
267
|
+
if ((state = state_new(dims, RTREE_NODE_PAGE(node_page))) != NULL)
|
268
|
+
{
|
269
|
+
if (jr_state_is_consistent(json_state, state))
|
270
|
+
return state;
|
271
|
+
else
|
272
|
+
errno = EINVAL;
|
273
|
+
state_destroy(state);
|
274
|
+
}
|
275
|
+
|
276
|
+
return NULL;
|
277
|
+
}
|
278
|
+
|
279
|
+
static node_t* jr_node(state_t*, json_t*);
|
280
|
+
|
281
|
+
static int jr_branch_leaf(json_t *json, branch_t *branch)
|
282
|
+
{
|
283
|
+
const json_t *json_id = json_object_get(json, "id");
|
284
|
+
if ((json_id == NULL) || (json_is_integer(json_id) == false))
|
285
|
+
return 1;
|
286
|
+
|
287
|
+
branch_set_id(branch, json_integer_value(json_id));
|
288
|
+
|
289
|
+
return 0;
|
290
|
+
}
|
291
|
+
|
292
|
+
static int jr_branch_internal(state_t *state, json_t *json, branch_t *branch)
|
293
|
+
{
|
294
|
+
json_t *json_node = json_object_get(json, "node");
|
295
|
+
if ((json_node == NULL) || (json_is_object(json_node) == false))
|
296
|
+
return RTREE_ERR_JANSSON;
|
297
|
+
|
298
|
+
node_t *node = jr_node(state, json_node);
|
299
|
+
if (node == NULL)
|
300
|
+
return RTREE_ERR_JANSSON;
|
301
|
+
|
302
|
+
branch_set_child(branch, node);
|
303
|
+
|
304
|
+
return RTREE_OK;
|
305
|
+
}
|
306
|
+
|
307
|
+
static int jr_node_recurse(state_t *state, node_t *node, json_t *json_branches)
|
308
|
+
{
|
309
|
+
const size_t dims = state_dims(state);
|
310
|
+
const node_level_t level = node_level(node);
|
311
|
+
size_t i;
|
312
|
+
void *branches = node_get_branches(node);
|
313
|
+
json_t *json_branch;
|
314
|
+
|
315
|
+
if (json_array_size(json_branches) > state_branching_factor(state))
|
316
|
+
return RTREE_ERR_INVAL;
|
317
|
+
|
318
|
+
json_array_foreach(json_branches, i, json_branch)
|
319
|
+
{
|
320
|
+
if (json_is_object(json_branch) == false)
|
321
|
+
return RTREE_ERR_JANSSON;
|
322
|
+
|
323
|
+
branch_t *branch = branches_get(state, branches, i);
|
324
|
+
|
325
|
+
{
|
326
|
+
int err = branch_init(state, branch);
|
327
|
+
if (err != RTREE_OK)
|
328
|
+
return err;
|
329
|
+
}
|
330
|
+
|
331
|
+
json_t *json_rect = json_object_get(json_branch, "rect");
|
332
|
+
|
333
|
+
if ( (json_rect == NULL) ||
|
334
|
+
(json_is_array(json_rect) == false) ||
|
335
|
+
(json_array_size(json_rect) != 2 * dims) )
|
336
|
+
return RTREE_ERR_JANSSON;
|
337
|
+
|
338
|
+
rtree_coord_t coord[2 * dims];
|
339
|
+
json_t *json_coord;
|
340
|
+
size_t j;
|
341
|
+
|
342
|
+
json_array_foreach(json_rect, j, json_coord)
|
343
|
+
{
|
344
|
+
if (json_is_real(json_coord) == false)
|
345
|
+
return RTREE_ERR_JANSSON;
|
346
|
+
coord[j] = json_real_value(json_coord);
|
347
|
+
}
|
348
|
+
|
349
|
+
branch_set_rect(state, branch, coord);
|
350
|
+
node_count_increment(node);
|
351
|
+
|
352
|
+
if (level == 0)
|
353
|
+
{
|
354
|
+
int err = jr_branch_leaf(json_branch, branch);
|
355
|
+
if (err != RTREE_OK)
|
356
|
+
return err;
|
357
|
+
}
|
358
|
+
else
|
359
|
+
{
|
360
|
+
int err = jr_branch_internal(state, json_branch, branch);
|
361
|
+
if (err != RTREE_OK)
|
362
|
+
return err;
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
return RTREE_OK;
|
367
|
+
}
|
368
|
+
|
369
|
+
static node_t* jr_node(state_t *state, json_t *json_node)
|
370
|
+
{
|
371
|
+
json_int_t count;
|
372
|
+
{
|
373
|
+
json_t *json = json_object_get(json_node, "count");
|
374
|
+
if ( (json == NULL) || (json_is_integer(json) == false) )
|
375
|
+
return NULL;
|
376
|
+
count = json_integer_value(json);
|
377
|
+
if ((count < 0) || (state_branching_factor(state) < (size_t)count))
|
378
|
+
return NULL;
|
379
|
+
}
|
380
|
+
|
381
|
+
json_int_t level;
|
382
|
+
{
|
383
|
+
json_t *json = json_object_get(json_node, "level");
|
384
|
+
if ( (json == NULL) || (json_is_integer(json) == false) )
|
385
|
+
return NULL;
|
386
|
+
level = json_integer_value(json);
|
387
|
+
if ((level < 0) || (NODE_LEVEL_MAX < level))
|
388
|
+
return NULL;
|
389
|
+
}
|
390
|
+
|
391
|
+
json_t *json_branches = json_object_get(json_node, "branches");
|
392
|
+
|
393
|
+
if ( (json_branches == NULL) ||
|
394
|
+
(json_is_array(json_branches) == false) ||
|
395
|
+
(json_array_size(json_branches) != (size_t)count) )
|
396
|
+
return NULL;
|
397
|
+
|
398
|
+
node_t *node;
|
399
|
+
|
400
|
+
if ((node = node_new(state)) != NULL)
|
401
|
+
{
|
402
|
+
node_set_level(node, level);
|
403
|
+
|
404
|
+
int err = jr_node_recurse(state, node, json_branches);
|
405
|
+
if (err == 0)
|
406
|
+
return node;
|
407
|
+
|
408
|
+
node_destroy(state, node);
|
409
|
+
}
|
410
|
+
|
411
|
+
return NULL;
|
412
|
+
}
|
413
|
+
|
414
|
+
static node_t* jr_root(state_t *state, json_t *json)
|
415
|
+
{
|
416
|
+
json_t *json_root;
|
417
|
+
|
418
|
+
if ((json_root = json_object_get(json, "root")) == NULL)
|
419
|
+
return NULL;
|
420
|
+
|
421
|
+
return jr_node(state, json_root);
|
422
|
+
}
|
423
|
+
|
424
|
+
static rtree_t* jr_rtree(json_t *json)
|
425
|
+
{
|
426
|
+
if (! json_is_object(json))
|
427
|
+
return NULL;
|
428
|
+
|
429
|
+
state_t *state;
|
430
|
+
|
431
|
+
if ((state = jr_state(json)) != NULL)
|
432
|
+
{
|
433
|
+
node_t *root;
|
434
|
+
|
435
|
+
if ((root = jr_root(state, json)) != NULL)
|
436
|
+
{
|
437
|
+
rtree_t *rtree;
|
438
|
+
|
439
|
+
if ((rtree = rtree_alloc()) == NULL)
|
440
|
+
errno = ENOMEM;
|
441
|
+
else
|
442
|
+
{
|
443
|
+
rtree->state = state;
|
444
|
+
rtree->root = root;
|
445
|
+
|
446
|
+
return rtree;
|
447
|
+
}
|
448
|
+
node_destroy(state, root);
|
449
|
+
}
|
450
|
+
state_destroy(state);
|
451
|
+
}
|
452
|
+
|
453
|
+
return NULL;
|
454
|
+
}
|
455
|
+
|
456
|
+
rtree_t* json_rtree_read(FILE *stream)
|
457
|
+
{
|
458
|
+
const size_t flags = JSON_REJECT_DUPLICATES;
|
459
|
+
json_t *json;
|
460
|
+
|
461
|
+
if ((json = json_loadf(stream, flags, NULL)) != NULL)
|
462
|
+
{
|
463
|
+
rtree_t *rtree = jr_rtree(json);
|
464
|
+
json_decref(json);
|
465
|
+
return rtree;
|
466
|
+
}
|
467
|
+
|
468
|
+
return NULL;
|
469
|
+
}
|
470
|
+
|
471
|
+
#else
|
472
|
+
|
473
|
+
#pragma GCC diagnostic push
|
474
|
+
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
475
|
+
int json_rtree_write(const rtree_t *rtree, FILE *stream)
|
476
|
+
{
|
477
|
+
errno = ENOSYS;
|
478
|
+
return RTREE_ERR_NOJSON;
|
479
|
+
}
|
480
|
+
#pragma GCC diagnostic pop
|
481
|
+
|
482
|
+
#pragma GCC diagnostic push
|
483
|
+
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
484
|
+
rtree_t* json_rtree_read(FILE *stream)
|
485
|
+
{
|
486
|
+
errno = ENOSYS;
|
487
|
+
return NULL;
|
488
|
+
}
|
489
|
+
#pragma GCC diagnostic pop
|
490
|
+
|
491
|
+
#endif
|