librtree 0.9.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|