Pico Headers
Loading...
Searching...
No Matches
pico_qt.h
Go to the documentation of this file.
1
66#ifndef PICO_QT_H
67#define PICO_QT_H
68
69#include <stdbool.h>
70#include <stdint.h>
71
72#ifdef __cplusplus
73extern "C" {
74#endif
75
76#ifdef PICO_QT_USE_DOUBLE
80typedef double qt_float;
81#else
85typedef float qt_float;
86#endif
87
88// Node value default type
89#ifndef PICO_QT_VALUE_TYPE
90#define PICO_QT_VALUE_TYPE uint32_t
91#endif
92
97
101typedef struct qt_t qt_t;
102
106typedef struct
107{
108 qt_float x, y, w, h;
109} qt_rect_t;
110
115
124qt_t* qt_create(qt_rect_t bounds, int max_depth, void* mem_ctx);
125
130void qt_destroy(qt_t* qt);
131
136void qt_reset(qt_t* qt);
137
145void qt_insert(qt_t* qt, qt_rect_t bounds, qt_value_t value);
146
157bool qt_remove(qt_t* qt, qt_value_t value);
158
170qt_value_t* qt_query(const qt_t* qt, qt_rect_t area, int* size);
171
185qt_rect_t* qt_grid_rects(const qt_t* qt, int* size);
186
193void qt_free(qt_t* qt, void* array);
194
205void qt_clear(qt_t* qt);
206
217void qt_clean(qt_t* qt);
218
219#ifdef __cplusplus
220}
221#endif
222
223#endif // PICO_QT_H
224
225#ifdef PICO_QT_IMPLEMENTATION
226
227/*=============================================================================
228 * Macros and constants
229 *============================================================================*/
230
231#ifdef NDEBUG
232 #define PICO_QT_ASSERT(expr) ((void)0)
233#else
234 #ifndef PICO_QT_ASSERT
235 #include <assert.h>
236 #define PICO_QT_ASSERT(expr) (assert(expr))
237 #endif
238#endif
239
240#if !defined(PICO_QT_MALLOC) || !defined(PICO_QT_REALLOC) || !defined(PICO_QT_FREE)
241 #include <stdlib.h>
242 #define PICO_QT_MALLOC(size, ctx) (malloc(size))
243 #define PICO_QT_REALLOC(ptr, size, ctx) (realloc(ptr, size))
244 #define PICO_QT_FREE(ptr, ctx) (free(ptr))
245#endif
246
247#ifndef PICO_QT_MEMCPY
248 #include <string.h>
249 #define PICO_QT_MEMCPY memcpy
250#endif
251
252#ifndef PICO_QT_MEMSET
253 #include <string.h>
254 #define PICO_QT_MEMSET memset
255#endif
256
257#ifndef PICO_QT_BLOCK_SIZE
258 #define PICO_QT_BLOCK_SIZE 128
259#endif
260
261/*=============================================================================
262 * Internal aliases
263 *============================================================================*/
264
265#define QT_ASSERT PICO_QT_ASSERT
266#define QT_MEMCPY PICO_QT_MEMCPY
267#define QT_MEMSET PICO_QT_MEMSET
268#define QT_MALLOC PICO_QT_MALLOC
269#define QT_REALLOC PICO_QT_REALLOC
270#define QT_FREE PICO_QT_FREE
271
272/*=============================================================================
273 * Internal data structures
274 *============================================================================*/
275
276// An optional empty macro used to markup dynamic arrays. This is useful to help remind
277// us that a particular pointer is a dynamic array, and not merely a pointer.
278#define qt_array
279
280typedef struct qt_node_t qt_node_t;
281
282typedef struct qt_array_header_t
283{
284 int capacity;
285 int size;
286 char* data;
287 uint32_t cookie;
288} qt_array_header_t;
289
290typedef struct
291{
292 qt_rect_t bounds;
293 qt_value_t value;
294} qt_item_t;
295
296struct qt_node_t
297{
298 int depth;
299 int max_depth;
300 qt_rect_t bounds[4];
301 qt_node_t* nodes[4];
302 qt_array qt_item_t* items;
303};
304
305typedef union qt_unode_t
306{
307 qt_node_t node;
308 union qt_unode_t* next;
309} qt_unode_t;
310
311typedef struct qt_node_allocator_t
312{
313 qt_unode_t* free_list;
314 qt_array qt_unode_t** blocks;
315} qt_node_allocator_t;
316
317struct qt_t
318{
319 qt_rect_t bounds;
320 qt_node_t* root;
321 void* mem_ctx;
322
323 // A custom allocator is used here to allocate individual nodes.
324 // This attempts to pack all the nodes together in memory to try and
325 // keep them in similar cache lines. This is slightly superior to calling
326 // `QT_MALLOC` once per node, where traversing the tree (if cold and not
327 // currently in the CPU cache) would incur a cache miss for every single
328 // node no matter what.
329 qt_node_allocator_t allocator;
330};
331
332/*=============================================================================
333 * Internal macros
334 *============================================================================*/
335
336// Fetches the header `qt_array_header_t` of a dynamic array.
337#define qt_hdr(a) ((qt_array_header_t*)a - 1)
338
339// Helper to assert this pointer is indeed a dynamic array.
340// Like a "canary in the coal mine".
341#ifdef NDEBUG
342 #define QT_ARRAY_CANARY(a) ((void)0)
343#else
344 #define QT_ARRAY_CANARY(a) ((a) ? QT_ASSERT(qt_hdr(a)->cookie == QT_ARRAY_COOKIE) : (void)0)
345#endif
346
347// A magic number for `QT_ARRAY_CANARY`.
348#define QT_ARRAY_COOKIE 0xE6F7E359
349
350// Returns the number of elements in the array.
351// This is a proper l-value, so you can do e.g. qt_array_size(a)--
352#define qt_array_len(a) (qt_hdr(a)->size)
353
354// Returns the number of elements in the array.
355// Passing in NULL will return 0.
356#define qt_array_size(a) (QT_ARRAY_CANARY(a), a ? qt_hdr(a)->size : 0)
357
358// Returns the capacity of the array.
359#define qt_array_capacity(a) (QT_ARRAY_CANARY(a), (a) ? qt_hdr(a)->capacity : 0)
360
361// Makes sure the capacity of the array can fit `n` elements.
362#define qt_array_fit(ctx, a, n) ((n) <= qt_array_capacity(a) ? 0 : (*(void**)&(a) = qt_array_fit_impl((a), (n), sizeof(*a), (ctx))))
363
364// Pushes an element onto the array. Will resize itself as necessary.
365#define qt_array_push(ctx, a , ...) (QT_ARRAY_CANARY(a), qt_array_fit((ctx), (a), 1 + ((a) ? qt_array_size(a) : 0)), (a)[qt_array_len(a)++] = (__VA_ARGS__))
366
367// Clears the array.
368#define qt_array_clear(a) (QT_ARRAY_CANARY(a), a ? (void)(qt_array_len(a) = 0) : (void)0)
369
370// Free's up a dynamic array.
371#define qt_array_destroy(ctx, a) (QT_ARRAY_CANARY(a), a ? QT_FREE(qt_hdr(a), (ctx)) : (void)0, a = NULL)
372
373// Overwrites the item at the index with the item at the end of the array.
374// This is fast, but it changes the order of the array Fortunately, order
375// doesn't matter in this case.
376#define qt_array_remove(a, i) (QT_ARRAY_CANARY(a), a[i] = a[--qt_array_len(a)])
377
378/*=============================================================================
379 * Internal function declarations
380 *============================================================================*/
381
382static bool qt_rect_contains(const qt_rect_t* r1, const qt_rect_t* r2);
383static bool qt_rect_overlaps(const qt_rect_t* r1, const qt_rect_t* r2);
384
385static void* qt_array_fit_impl(const void* array, int new_size, size_t element_size, void* mem_ctx);
386
387static qt_node_t* qt_node_alloc(qt_t* qt);
388static void qt_node_free(qt_t* qt, qt_node_t* node);
389
390static qt_node_t* qt_node_create(qt_t* qt, qt_rect_t bounds, int depth, int max_depth);
391static void qt_node_destroy(qt_t* qt, qt_node_t* node);
392static void qt_node_insert(qt_t* qt, qt_node_t* node, const qt_rect_t* bounds, qt_value_t value);
393static bool qt_node_remove(qt_node_t* node, qt_value_t value);
394
395static qt_array qt_value_t* qt_node_query(const qt_t* qt, const qt_node_t* node, const qt_rect_t* area, qt_array qt_value_t* values);
396static void qt_node_clear(qt_node_t* node);
397
398static qt_array qt_item_t* qt_node_all_items(const qt_t* qt, const qt_node_t* node, qt_array qt_item_t* items);
399static qt_array qt_value_t* qt_node_all_values(const qt_t* qt, const qt_node_t* node, qt_array qt_value_t* values);
400static qt_array qt_rect_t* qt_node_all_grid_rects(const qt_t* qt, const qt_node_t* node, qt_array qt_rect_t* rects);
401
402/*=============================================================================
403 * Public API implementation
404 *============================================================================*/
405
406qt_t* qt_create(qt_rect_t bounds, int max_depth, void* mem_ctx)
407{
408 qt_t* qt = (qt_t*)QT_MALLOC(sizeof(qt_t), mem_ctx);
409
410 QT_MEMSET(qt, 0, sizeof(*qt));
411
412 if (!qt)
413 return NULL;
414
415 qt->bounds = bounds;
416 qt->root = qt_node_create(qt, bounds, 0, max_depth);
417
418 qt->mem_ctx = mem_ctx;
419
420 return qt;
421}
422
423void qt_destroy(qt_t* qt)
424{
425 QT_ASSERT(qt);
426
427 qt_node_destroy(qt, qt->root);
428
429 for (int i = 0; i < qt_array_size(qt->allocator.blocks); i++)
430 {
431 QT_FREE(qt->allocator.blocks[i], qt->mem_ctx);
432 }
433
434 qt_array_destroy(qt->mem_ctx, qt->allocator.blocks);
435 QT_FREE(qt, qt->mem_ctx);
436}
437
438void qt_reset(qt_t* qt)
439{
440 QT_ASSERT(qt);
441
442 int max_depth = qt->root->max_depth;
443
444 qt_node_destroy(qt, qt->root);
445
446 qt->root = qt_node_create(qt, qt->bounds, 0, max_depth);
447}
448
449void qt_insert(qt_t* qt, qt_rect_t bounds, qt_value_t value)
450{
451 QT_ASSERT(qt);
452 qt_node_insert(qt, qt->root, &bounds, value);
453}
454
455bool qt_remove(qt_t* qt, qt_value_t value)
456{
457 QT_ASSERT(qt);
458 return qt_node_remove(qt->root, value);
459}
460
461qt_value_t* qt_query(const qt_t* qt, qt_rect_t area, int* size)
462{
463 QT_ASSERT(qt);
464 QT_ASSERT(size);
465
466 // Size must be valid
467 if (!size)
468 return NULL;
469
470 // Start query the root node
471 qt_array qt_value_t* values = qt_node_query(qt, qt->root, &area, NULL);
472
473 // If no results then return NULL
474 if (!values)
475 {
476 *size = 0;
477 return NULL;
478 }
479
480 // Set size and return
481 *size = qt_array_size(values);
482
483 return values;
484}
485
486qt_rect_t* qt_grid_rects(const qt_t* qt, int* size)
487{
488 QT_ASSERT(qt);
489 QT_ASSERT(size);
490
491 // Size must be valid
492 if (!size)
493 return NULL;
494
495 qt_array qt_rect_t* rects = qt_node_all_grid_rects(qt, qt->root, NULL);
496
497 // If no results then return NULL
498 if (!rects)
499 {
500 *size = 0;
501 return NULL;
502 }
503
504 // Set size and return
505 *size = qt_array_size(rects);
506
507 return rects;
508}
509
510void qt_free(qt_t* qt, void* array)
511{
512 (void)qt;
513
514 if (!array)
515 return;
516
517 qt_array_destroy(qt->mem_ctx, array);
518}
519
520void qt_clear(qt_t* qt)
521{
522 QT_ASSERT(qt);
523 qt_node_clear(qt->root);
524}
525
526void qt_clean(qt_t* qt)
527{
528 QT_ASSERT(qt);
529
530 qt_array qt_item_t* items = qt_node_all_items(qt, qt->root, NULL);
531
532 qt_reset(qt);
533
534 for (int i = 0; i < qt_array_size(items); i++)
535 {
536 qt_insert(qt, items[i].bounds, items[i].value);
537 }
538
539 qt_array_destroy(qt->mem_ctx, items);
540}
541
542/*=============================================================================
543 * Internal function definitions
544 *============================================================================*/
545
546static int qt_max(int a, int b)
547{
548 return a > b ? a : b;
549}
550
551// Don't call this directly -- use `qt_array_fit` instead.
552static void* qt_array_fit_impl(const void* array, int new_size, size_t element_size, void* mem_ctx)
553{
554 (void)mem_ctx;
555
556 QT_ARRAY_CANARY(array);
557
558 // Double the old capacity, or pick at least 16 for the starting size.
559 // This helps unnecessarily numerous realloc's for low capacities when starting out.
560 int new_capacity = qt_max(2 * qt_array_capacity(array), qt_max(new_size, 16));
561
562 QT_ASSERT(new_size <= new_capacity);
563
564 // Total size of the header struct `qt_array_header_t` along with the size of all
565 // elements packed together in a single allocation.
566 size_t total_size = sizeof(qt_array_header_t) + new_capacity * element_size;
567
568 qt_array_header_t* hdr;
569
570 if (array)
571 {
572 // Realloc of the header isn't new.
573 // This expands the capacity.
574 hdr = (qt_array_header_t*)QT_REALLOC(qt_hdr(array), total_size, mem_ctx);
575 }
576
577 else
578 {
579 // Create a new array if the pointer passed in was NULL, as NULL means an empty array.
580 hdr = (qt_array_header_t*)QT_MALLOC(total_size, mem_ctx);
581 hdr->size = 0;
582 }
583
584 hdr->cookie = QT_ARRAY_COOKIE; // For sanity checks with `QT_ARRAY_CANARY`.
585 hdr->capacity = new_capacity;
586 hdr->data = (char*)(hdr + 1); // For debugging convenience.
587
588 return (void*)(hdr + 1);
589}
590
592{
593 qt_rect_t r = { x, y, w, h }; return r;
594}
595
596static bool qt_rect_contains(const qt_rect_t* r1, const qt_rect_t* r2)
597{
598 QT_ASSERT(r1);
599 QT_ASSERT(r2);
600
601 return r1->x <= r2->x &&
602 r1->y <= r2->y &&
603 r1->x + r1->w >= r2->x + r2->w &&
604 r1->y + r1->h >= r2->y + r2->h;
605}
606
607static bool qt_rect_overlaps(const qt_rect_t* r1, const qt_rect_t* r2)
608{
609 QT_ASSERT(r1);
610 QT_ASSERT(r2);
611
612 return r1->x + r1->w >= r2->x &&
613 r1->y + r1->h >= r2->y &&
614 r2->x + r2->w >= r1->x &&
615 r2->y + r2->h >= r1->y;
616}
617
618static qt_node_t* qt_node_create(qt_t* qt, qt_rect_t bounds, int depth, int max_depth)
619{
620 qt_node_t* node = qt_node_alloc(qt);
621
622 node->depth = depth;
623 node->max_depth = max_depth;
624
625 // Calculate subdivided bounds
626 bounds.w /= 2.0f;
627 bounds.h /= 2.0f;
628
629 // Calculates bounds of subtrees
630 node->bounds[0] = qt_make_rect(bounds.x,
631 bounds.y,
632 bounds.w,
633 bounds.h);
634
635 node->bounds[1] = qt_make_rect(bounds.x + bounds.w,
636 bounds.y,
637 bounds.w,
638 bounds.h);
639
640 node->bounds[2] = qt_make_rect(bounds.x,
641 bounds.y + bounds.h,
642 bounds.w,
643 bounds.h);
644
645 node->bounds[3] = qt_make_rect(bounds.x + bounds.w,
646 bounds.y + bounds.h,
647 bounds.w,
648 bounds.h);
649
650 return node;
651}
652
653static void qt_node_destroy(qt_t* qt, qt_node_t* node)
654{
655 QT_ASSERT(node);
656
657 qt_array_destroy(qt->mem_ctx, node->items);
658
659 // Recursively destroy nodes
660 for (int i = 0; i < 4; i++)
661 {
662 if (node->nodes[i])
663 qt_node_destroy(qt, node->nodes[i]);
664 }
665
666 // Free current node by pushing it onto the free list
667 qt_node_free(qt, node);
668}
669
670static void qt_node_insert(qt_t* qt, qt_node_t* node, const qt_rect_t* bounds, qt_value_t value)
671{
672 QT_ASSERT(node);
673 QT_ASSERT(bounds);
674
675 // The purpose of this function is to optimally fit the item into a subtree.
676 // This occurs when the item is no longer fully contained within a subtree,
677 // or the depth limit has been reached.
678
679 // Checks to see if the depth limit has been reached. If it hasn't, try to
680 // fit the item into a subtree
681 if (node->depth + 1 < node->max_depth)
682 {
683 // Loop over child nodes
684 for (int i = 0; i < 4; i++)
685 {
686 // Check if subtree contains the bounds
687 if (qt_rect_contains(&node->bounds[i], bounds))
688 {
689 // If child node does not exist, then create it
690 if (!node->nodes[i])
691 {
692 node->nodes[i] = qt_node_create(qt,
693 node->bounds[i],
694 node->depth + 1,
695 node->max_depth);
696 }
697
698 // Recursively try to insert the item into the subtree
699 qt_node_insert(qt, node->nodes[i], bounds, value);
700 return;
701 }
702 }
703 }
704
705 // If none of the children fully contain the bounds, or the maximum depth
706 // has been reached, then the item belongs to this node
707 qt_array_push(qt->mem_ctx, node->items, (qt_item_t){ *bounds, value });
708}
709
710static bool qt_node_remove(qt_node_t* node, qt_value_t value)
711{
712 QT_ASSERT(node);
713
714 // Searches the items in this node and, if found, removes the item with the
715 // specified value
716 for (int i = 0; i < qt_array_size(node->items); i++)
717 {
718 // If value is found, then remove it and it's bounds from the node
719 if (node->items[i].value == value)
720 {
721 qt_array_remove(node->items, i);
722 return true;
723 }
724 }
725
726 // If the item wasn't found, recursively search the subtrees of this node
727 for (int i = 0; i < 4; i++)
728 {
729 if (node->nodes[i])
730 {
731 if (qt_node_remove(node->nodes[i], value))
732 return true;
733 }
734 }
735
736 // Value wasn't found
737 return false;
738}
739
740static qt_array qt_item_t* qt_node_all_items(const qt_t* qt, const qt_node_t* node, qt_array qt_item_t* items)
741{
742 QT_ASSERT(node);
743
744 // Add all values in this node into the array
745 for (int i = 0; i < qt_array_size(node->items); i++)
746 {
747 qt_array_push(qt->mem_ctx, items, node->items[i]);
748 }
749
750 // Recursively add all values found in the subtrees
751 for (int i = 0; i < 4; i++)
752 {
753 if (node->nodes[i])
754 items = qt_node_all_items(qt, node->nodes[i], items);
755 }
756
757 return items;
758}
759
760static qt_array qt_value_t* qt_node_all_values(const qt_t* qt, const qt_node_t* node, qt_array qt_value_t* values)
761{
762 QT_ASSERT(node);
763
764 // Add all values in this node into the array
765 for (int i = 0; i < qt_array_size(node->items); i++)
766 {
767 qt_array_push(qt->mem_ctx, values, node->items[i].value);
768 }
769
770 // Recursively add all values found in the subtrees
771 for (int i = 0; i < 4; i++)
772 {
773 if (node->nodes[i])
774 values = qt_node_all_values(qt, node->nodes[i], values);
775 }
776
777 return values;
778}
779
780static qt_array qt_rect_t* qt_node_all_grid_rects(const qt_t* qt, const qt_node_t* node, qt_array qt_rect_t* rects)
781{
782 QT_ASSERT(node);
783
784 // Add all grid bounds in this node into the array
785 for (int i = 0; i < 4; i++)
786 {
787 if (node->nodes[i])
788 qt_array_push(qt->mem_ctx, rects, node->bounds[i]);
789 }
790
791 // Recursively add all grid bounds found in the subtrees
792 for (int i = 0; i < 4; i++)
793 {
794 if (node->nodes[i])
795 rects = qt_node_all_grid_rects(qt, node->nodes[i], rects);
796 }
797
798 return rects;
799}
800
801static qt_array qt_value_t* qt_node_query(const qt_t* qt, const qt_node_t* node, const qt_rect_t* area, qt_array qt_value_t* values)
802{
803 QT_ASSERT(node);
804 QT_ASSERT(area);
805
806 // Searches for items in this node that intersect the area and adds them to
807 // the array
808 for (int i = 0; i < qt_array_size(node->items); i++)
809 {
810 const qt_item_t* item = &node->items[i];
811
812 if (qt_rect_overlaps(area, &item->bounds))
813 qt_array_push(qt->mem_ctx, values, node->items[i].value);
814 }
815
816 // Loop over subtrees
817 for (int i = 0; i < 4; i++)
818 {
819 if (node->nodes[i])
820 {
821 // If the area contains the the entire subtree, all items in the
822 // subtree match and are recursively added to the array
823 if (qt_rect_contains(area, &node->bounds[i]))
824 {
825 values = qt_node_all_values(qt, node->nodes[i], values);
826 }
827 else
828 {
829 // Otherwise, if the area intersects the bounds of the subtree,
830 // the subtree is recursively searched for items intersecting
831 // or contained within the area
832 if (qt_rect_overlaps(area, &node->bounds[i]))
833 {
834 values = qt_node_query(qt, node->nodes[i], area, values);
835 }
836 }
837 }
838 }
839
840 return values;
841}
842
843static void qt_node_clear(qt_node_t* node)
844{
845 qt_array_clear(node->items);
846
847 for (int i = 0; i < 4; i++)
848 {
849 if (node->nodes[i])
850 qt_node_clear(node->nodes[i]);
851 }
852}
853
854static void qt_freelist_push(qt_t* qt, qt_unode_t *unode)
855{
856 qt_node_allocator_t* allocator = &qt->allocator;
857 unode->next = allocator->free_list;
858 allocator->free_list = unode;
859}
860
861static qt_unode_t* qt_freelist_pop(qt_t* qt)
862{
863 qt_node_allocator_t* allocator = &qt->allocator;
864 qt_unode_t* unode = allocator->free_list;
865 allocator->free_list = allocator->free_list->next;
866 return unode;
867}
868
869static void qt_block_alloc(qt_t* qt)
870{
871 // Allocate space for more nodes and add them to the free list.
872
873 qt_node_allocator_t* allocator = &qt->allocator;
874
875 const int block_count = PICO_QT_BLOCK_SIZE;
876
877 qt_unode_t* nodes = (qt_unode_t*)QT_MALLOC(sizeof(qt_unode_t) * block_count, qt->mem_ctx);
878
879 for (int i = 0; i < block_count; i++)
880 {
881 qt_freelist_push(qt, &nodes[i]);
882 }
883
884 qt_array_push(qt->mem_ctx, allocator->blocks, nodes);
885}
886
887static qt_node_t* qt_node_alloc(qt_t* qt)
888{
889 qt_node_allocator_t* allocator = &qt->allocator;
890
891 if (!allocator->free_list)
892 {
893 qt_block_alloc(qt);
894 }
895
896 // Pop a node off of the free list.
897 qt_unode_t* unode = qt_freelist_pop(qt);
898 QT_MEMSET(unode, 0, sizeof(qt_unode_t));
899
900 qt_node_t* result = &unode->node;
901
902 return result;
903}
904
905static void qt_node_free(qt_t* qt, qt_node_t* node)
906{
907 qt_freelist_push(qt, (qt_unode_t*)node);
908}
909
910#endif // PICO_QT_IMPLEMENTATION
911
912/*
913 ----------------------------------------------------------------------------
914 This software is available under two licenses (A) or (B). You may choose
915 either one as you wish:
916 ----------------------------------------------------------------------------
917
918 (A) The zlib License
919
920 Copyright (c) 2022 James McLean
921
922 This software is provided 'as-is', without any express or implied warranty.
923 In no event will the authors be held liable for any damages arising from the
924 use of this software.
925
926 Permission is granted to anyone to use this software for any purpose,
927 including commercial applications, and to alter it and redistribute it
928 freely, subject to the following restrictions:
929
930 1. The origin of this software must not be misrepresented; you must not
931 claim that you wrote the original software. If you use this software in a
932 product, an acknowledgment in the product documentation would be appreciated
933 but is not required.
934
935 2. Altered source versions must be plainly marked as such, and must not be
936 misrepresented as being the original software.
937
938 3. This notice may not be removed or altered from any source distribution.
939
940 ----------------------------------------------------------------------------
941
942 (B) Public Domain (www.unlicense.org)
943
944 This is free and unencumbered software released into the public domain.
945
946 Anyone is free to copy, modify, publish, use, compile, sell, or distribute
947 this software, either in source code form or as a compiled binary, for any
948 purpose, commercial or non-commercial, and by any means.
949
950 In jurisdictions that recognize copyright laws, the author or authors of
951 this software dedicate any and all copyright interest in the software to the
952 public domain. We make this dedication for the benefit of the public at
953 large and to the detriment of our heirs and successors. We intend this
954 dedication to be an overt act of relinquishment in perpetuity of all present
955 and future rights to this software under copyright law.
956
957 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
958 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
959 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
960 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
961 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
962 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
963*/
void qt_clean(qt_t *qt)
Resets the tree and reinserts all items.
void qt_insert(qt_t *qt, qt_rect_t bounds, qt_value_t value)
Inserts a value with the specified bounds into a quadtree.
qt_t * qt_create(qt_rect_t bounds, int max_depth, void *mem_ctx)
Creates a quadtree with the specified global bounds.
qt_value_t * qt_query(const qt_t *qt, qt_rect_t area, int *size)
Returns all values associated with items that are either overlapping or contained within the search a...
struct qt_t qt_t
Quadtree data structure.
Definition pico_qt.h:101
PICO_QT_VALUE_TYPE qt_value_t
Node value type (default: uint32_t)
Definition pico_qt.h:96
bool qt_remove(qt_t *qt, qt_value_t value)
Searches for and removes a value in a quadtree.
void qt_free(qt_t *qt, void *array)
Function for deallocating arrays.
void qt_destroy(qt_t *qt)
Destroys a quadtree.
void qt_clear(qt_t *qt)
Removes all items in the tree.
void qt_reset(qt_t *qt)
Removes all nodes in the tree.
#define PICO_QT_VALUE_TYPE
Definition pico_qt.h:90
qt_rect_t qt_make_rect(qt_float x, qt_float y, qt_float w, qt_float h)
Utility function for creating a rectangle.
float qt_float
Single precision floating point type.
Definition pico_qt.h:85
qt_rect_t * qt_grid_rects(const qt_t *qt, int *size)
Returns all bounds associated with the quadtree's recursive grid structure.
Rectangle for representing bounds.
Definition pico_qt.h:107
qt_float x
Definition pico_qt.h:108
qt_float y
Definition pico_qt.h:108
qt_float h
Definition pico_qt.h:108
qt_float w
Definition pico_qt.h:108