File Coverage

qtbase.c
Criterion Covered Total %
statement 170 175 97.1
branch 95 110 86.3
condition n/a
subroutine n/a
pod n/a
total 265 285 92.9


line stmt bran cond sub pod time code
1             #include "qtbase.h"
2             #include
3              
4             #define CHILDREN_PER_NODE 4
5              
6 128           Shape* create_shape()
7             {
8 128           Shape *s = malloc(sizeof *s);
9 128           return s;
10             }
11              
12 187           void prepare_rectangle(Shape *s, double x, double y, double x2, double y2)
13             {
14 187           s->type = shape_rectangle;
15 187           s->x = x;
16 187           s->y = y;
17 187           s->x2 = x2;
18 187           s->y2 = y2;
19 187           }
20              
21 15           void prepare_circle(Shape *s, double x0, double y0, double radius)
22             {
23 15           s->type = shape_circle;
24 15           s->x0 = x0;
25 15           s->y0 = y0;
26 15           s->radius = radius;
27 15           s->radius_sq = radius * radius;
28              
29 15           double contained_radius = s->radius / sqrt(2);
30 15           s->x = x0 - contained_radius;
31 15           s->x2 = x0 + contained_radius;
32 15           s->y = y0 - contained_radius;
33 15           s->y2 = y0 + contained_radius;
34 15           }
35              
36 128           void destroy_shape(Shape *s)
37             {
38 128           free(s);
39 128           }
40              
41 55           void adopt_object (QuadTreeRootNode *root, SV *value, Shape *s)
42             {
43 55           hv_store_ent(root->backref, value, newSViv((uintptr_t) s), 0);
44 55           }
45              
46 1           void disown_object (QuadTreeRootNode *root, SV *value)
47             {
48             /* NOTE: no shape destruction here, since "adopt_object" does not create it */
49 1           hv_delete_ent(root->backref, value, 0, 0);
50 1           }
51              
52 22           QuadTreeNode* create_nodes(int count)
53             {
54 22           QuadTreeNode *node = malloc(count * sizeof *node);
55              
56             int i;
57 95 100         for (i = 0; i < count; ++i) {
58 73           node[i].values = NULL;
59 73           node[i].children = NULL;
60 73           node[i].has_objects = false;
61             }
62              
63 22           return node;
64             }
65              
66             /* NOTE: does not actually free the node, but frees its children nodes */
67 73           void destroy_node(QuadTreeNode *node)
68             {
69 73           SvREFCNT_dec((SV*) node->values);
70 73           destroy_shape(node->dimensions);
71              
72 73 100         if (node->children != NULL) {
73             int i;
74 85 100         for (i = 0; i < CHILDREN_PER_NODE; ++i) {
75 68           destroy_node(&node->children[i]);
76             }
77              
78 17           free(node->children);
79             }
80 73           }
81              
82 5           QuadTreeRootNode* create_root()
83             {
84 5           QuadTreeRootNode *root = malloc(sizeof *root);
85 5           root->node = create_nodes(1);
86 5           root->backref = newHV();
87              
88 5           return root;
89             }
90              
91 73           void node_add_level(QuadTreeNode* node, double xmin, double ymin, double xmax, double ymax, int depth)
92             {
93 73           bool last = --depth == 0;
94              
95 73           node->dimensions = create_shape();
96 73           prepare_rectangle(node->dimensions, xmin, ymin, xmax, ymax);
97 73           node->values = newAV();
98              
99 73 100         if (!last) {
100 17           node->children = create_nodes(CHILDREN_PER_NODE);
101 17           double xmid = xmin + (xmax - xmin) / 2;
102 17           double ymid = ymin + (ymax - ymin) / 2;
103              
104 17           node_add_level(&node->children[0], xmin, ymin, xmid, ymid, depth);
105 17           node_add_level(&node->children[1], xmin, ymid, xmid, ymax, depth);
106 17           node_add_level(&node->children[2], xmid, ymin, xmax, ymid, depth);
107 17           node_add_level(&node->children[3], xmid, ymid, xmax, ymax, depth);
108             }
109 73           }
110              
111 1080           bool shape_contained (Shape *inner_s, Shape *s)
112             {
113 291 100         return (s->x <= inner_s->x && s->x2 >= inner_s->x2)
114 1371 100         && (s->y <= inner_s->y && s->y2 >= inner_s->y2);
    100          
    100          
115             }
116              
117 1084           bool shapes_overlap (Shape *s1, Shape *s2)
118             {
119 1084 100         if (s1->type == s2->type) {
120 1020           switch (s1->type) {
121 3           case shape_circle: {
122             /* circle vs circle */
123 3           double distance_x = s1->x0 - s2->x0;
124 3           double distance_y = s1->y0 - s2->y0;
125 3           double radius = s1->radius + s2->radius;
126              
127 3           return distance_x * distance_x + distance_y * distance_y
128 3           <= radius * radius;
129             }
130 1017           case shape_rectangle: {
131             /* rectangle vs rectangle */
132 1017 50         if (s1->type == shape_rectangle) {
133 815 100         return (s1->x <= s2->x2 && s1->x2 >= s2->x)
134 1832 100         && (s1->y <= s2->y2 && s1->y2 >= s2->y);
    100          
    100          
135             }
136             }
137             }
138             }
139              
140             /* circle vs rectangle - circle first */
141             /* circles first, if available */
142 64 50         if (s2->type == shape_circle) {
143             Shape *stemp;
144 0           stemp = s1;
145 0           s1 = s2;
146 0           s2 = stemp;
147             }
148              
149 128           double check_x = s1->x0 < s2->x
150 20           ? s2->x - s1->x0
151 108 100         : s1->x0 > s2->x2
152 7           ? s2->x2 - s1->x0
153 44 100         : 0
154             ;
155              
156 128           double check_y = s1->y0 < s2->y
157 20           ? s2->y - s1->y0
158 108 100         : s1->y0 > s2->y2
159 7           ? s2->y2 - s1->y0
160 44 100         : 0
161             ;
162              
163 64           return check_x * check_x + check_y * check_y <= s1->radius_sq;
164             }
165              
166 658           void find_nodes(QuadTreeNode *node, HV *ret, Shape *param, bool fully_contained)
167             {
168 658 100         if (!node->has_objects) return;
169              
170 618 100         fully_contained = fully_contained || shape_contained(node->dimensions, param);
    100          
171 618 100         if (!(fully_contained || shapes_overlap(param, node->dimensions))) return;
    100          
172              
173             int i;
174 452 100         for (i = 0; i < av_count(node->values); ++i) {
175 161           SV **fetched = av_fetch(node->values, i, 0);
176 161 50         if (fetched != NULL) {
177 161           SvREFCNT_inc(*fetched);
178 161           hv_store_ent(ret, *fetched, *fetched, 0);
179             }
180             }
181              
182 291 100         if (node->children != NULL) {
183 730 100         for (i = 0; i < CHILDREN_PER_NODE; ++i) {
184 584           find_nodes(&node->children[i], ret, param, fully_contained);
185             }
186             }
187             }
188              
189 475           bool fill_nodes (QuadTreeNode *node, SV *value, Shape *param)
190             {
191 475 50         if (shape_contained(node->dimensions, param)) {
192 0           av_push(node->values, SvREFCNT_inc(value));
193             }
194             else {
195 475 100         if (!shapes_overlap(param, node->dimensions)) return false;
196              
197 165 100         if (node->children == NULL) {
198 60           av_push(node->values, SvREFCNT_inc(value));
199             }
200             else {
201             int i;
202 525 100         for (i = 0; i < CHILDREN_PER_NODE; ++i) {
203 420           fill_nodes(&node->children[i], value, param);
204             }
205             }
206             }
207              
208             /* NOTE: only first level result is important, since if the object fits in
209             * the tree area at all, it must fit into one of the leaves */
210 165           node->has_objects = true;
211 165           return true;
212             }
213              
214 9           void delete_nodes(QuadTreeNode *node, SV *value, Shape *param, bool fully_contained)
215             {
216 9 50         if (!node->has_objects) return;
217              
218 9 50         fully_contained = fully_contained || shape_contained(node->dimensions, param);
    50          
219 9 50         if (!(fully_contained || shapes_overlap(param, node->dimensions))) return;
    100          
220              
221             int i;
222              
223              
224 3 100         if (av_count(node->values) > 0) {
225 1           AV* new_list = newAV();
226              
227 3 100         for (i = 0; i < av_count(node->values); ++i) {
228 2           SV **fetched = av_fetch(node->values, i, 0);
229 2 50         if (fetched != NULL && !sv_eq(*fetched, value)) {
    100          
230 1           av_push(new_list, SvREFCNT_inc(*fetched));
231             }
232             }
233              
234 1           SvREFCNT_dec((SV*) node->values);
235 1           node->values = new_list;
236 1           node->has_objects = av_count(new_list) > 0;
237             }
238              
239 3 100         if (node->children != NULL) {
240 10 100         for (i = 0; i < CHILDREN_PER_NODE; ++i) {
241 8           delete_nodes(&node->children[i], value, param, fully_contained);
242 8 50         node->has_objects = node->has_objects || node->children[i].has_objects;
    0          
243             }
244             }
245             }
246              
247 72           void clear_node(QuadTreeNode *node)
248             {
249 72 100         if (!node->has_objects) return;
250 59           node->has_objects = false;
251 59           av_clear(node->values);
252              
253 59 100         if (node->children != NULL) {
254             int i;
255 80 100         for (i = 0; i < CHILDREN_PER_NODE; ++i) {
256 64           clear_node(&node->children[i]);
257             }
258             }
259             }
260              
261 8           void clear_tree(QuadTreeRootNode *root)
262             {
263 8           clear_node(root->node);
264              
265             int i;
266             char *key;
267             I32 retlen;
268             SV *value;
269              
270 8           hv_iterinit(root->backref);
271 62 100         while ((value = hv_iternextsv(root->backref, &key, &retlen)) != NULL) {
272 54           destroy_shape((Shape*) SvIV(value));
273             }
274              
275 8           hv_clear(root->backref);
276 8           }
277              
278 6           void filter_geometry(HV* results, HV* shapes, Shape *s)
279             {
280             HE *he;
281              
282 6           hv_iterinit(results);
283 13 100         while ((he = hv_iternext(results)) != NULL) {
284             STRLEN len;
285 7 50         char *key = HePV(he, len);
286 7           SV **fetched = hv_fetch(shapes, key, len, 0);
287 7           Shape* s2 = (Shape*) SvIV(*fetched);
288              
289 7 100         if (!shapes_overlap(s, s2))
290 4           hv_delete(results, key, len, 0);
291             }
292 6           }
293              
294             /* XS helpers */
295              
296 237           SV* get_hash_key (HV* hash, const char* key, int len)
297             {
298 237           SV **value = hv_fetch(hash, key, len, 0);
299              
300 237 50         if (value == NULL) return NULL;
301 237           return *value;
302             }
303              
304 138           QuadTreeRootNode* get_root_from_perl(SV *self)
305             {
306 138           SV *value = get_hash_key((HV*) SvRV(self), "ROOT", 4);
307 138 50         if (value == NULL)
308 0           croak("quad tree root node is undefined");
309              
310 138           return (QuadTreeRootNode*) SvIV(value);
311             }
312              
313 74           AV* get_hash_values (HV* hash)
314             {
315 74           AV *ret = newAV();
316             HE *he;
317              
318 74           hv_iterinit(hash);
319 231 100         while ((he = hv_iternext(hash)) != NULL) {
320 157           SV *fetched = HeVAL(he);
321 157           SvREFCNT_inc(fetched);
322 157           av_push(ret, fetched);
323             }
324              
325 74           return ret;
326             }
327