-1

Below is the script for the quadtree... I'm relatively new to the concept of pointers, so my guess is that I have done something wrong with a double pointer, or something along those lines!

#include "BoidQuadTree.h"
#include <iostream>

Quad::Quad(float boundary_TL_x, float boundary_TL_y, float boundary_BR_x, float boundary_BR_y, unsigned short max_Nodes, unsigned short max_Depth)
{
    this->max_Depth = new unsigned short(max_Depth);
    this->max_Nodes = new unsigned short(max_Nodes);
    this->nodes_Remaining = new unsigned short(max_Nodes);

    this->boundary_TL = new Vector(boundary_TL_x, boundary_TL_y);
    this->boundary_BR = new Vector(boundary_BR_x, boundary_BR_y);

    this->TL = nullptr; // no need to allocate memory yet
    this->TR = nullptr;
    this->BL = nullptr;
    this->BR = nullptr;

    this->boids = new Boid*[max_Nodes]; // Intitialise all pointers to nullptr
}

Quad::~Quad()
{
    if (this->TL == nullptr) { // only deleted if not branched
        delete this->max_Depth;
        delete this->max_Nodes;
        delete[] this->boids;
    }

    delete this->boundary_TL; // always deleted
    delete this->boundary_BR;
    delete this->TL;
    delete this->TR;
    delete this->BL;
    delete this->BR;
    delete this->nodes_Remaining;
}

bool Quad::Insert(Boid* boid)
{
    if (boid != nullptr) {
        if (this->InBoundary(boid->position)) {
            if (this->TL == nullptr) {
                if ((*this->nodes_Remaining) > 0) { // if there is a free position
                    this->boids[(*(this->max_Nodes)) - (*(this->nodes_Remaining))] = boid;
                    (*(this->nodes_Remaining)) -= 1;
                    std::cout << "inserted" << std::endl;
                    return true; // successfully inserted boid pointer
                }
                else { // no free positions in current quad...
                    if (*this->max_Depth > 1) { // Further depth still avaliable, therefore branch all boid pointers into new quads! (can delete boid data from this after branching to free space)
                        this->TL = new Quad(this->boundary_TL->x, this->boundary_TL->y, this->boundary_TL->x + (this->boundary_BR->x / 2), this->boundary_TL->y + (this->boundary_BR->y / 2), *(this->max_Nodes), *(this->max_Depth) - 1);
                        this->TR = new Quad(this->boundary_TL->x + (this->boundary_BR->x / 2), this->boundary_TL->y, this->boundary_BR->x, this->boundary_TL->y + (this->boundary_BR->y / 2), *(this->max_Nodes), *(this->max_Depth) - 1);
                        this->BL = new Quad(this->boundary_TL->x, this->boundary_TL->y + (this->boundary_BR->y / 2), this->boundary_TL->x + (this->boundary_BR->x / 2), this->boundary_BR->y, *(this->max_Nodes), *(this->max_Depth) - 1);
                        this->BR = new Quad(this->boundary_TL->x + (this->boundary_BR->x / 2), this->boundary_TL->y + (this->boundary_BR->y / 2), this->boundary_BR->x, this->boundary_BR->y, *(this->max_Nodes), *(this->max_Depth) - 1);

                        std::cout << "Branched!" << std::endl;

                        for (unsigned short i = 0; i < *(this->max_Nodes); i++) {
                            this->PushToBranch(this->boids[i]);
                        }
                        this->PushToBranch(boid);

                        delete[] this->boids; // Delete now unneeded data
                        delete this->max_Nodes;
                        delete this->max_Depth;

                        return true;
                    }
                    else {
                        std::cout << "FUNC LOCATION : Quad::Insert() ERROR! Not enough depth to insert boid pointer! Returning false." << std::endl;
                        std::cout << boid->position->x << " " << boid->position->y << std::endl;
                        return false;
                    }
                }
            }
            else { // this quad has branched
                this->PushToBranch(boid);
                std::cout << "inserted into branch" << std::endl;
            }
        }
        else {
            std::cout << "FUNC LOCATION : Quad::Insert() ERROR! Boid not inside the valid range of the quadtree! Returning false." << std::endl;
            return false;
        }
    }
    else {
        std::cout << "FUNC LOCATION : Quad::Insert() ERROR! Attempted to insert a nullptr! Returning false." << std::endl;
        return false;
    }
}

void Quad::Insert(Boid** boids_Array, unsigned int number_Of_Boids)
{
    for (unsigned int i = 0; i < number_Of_Boids; i++) {
        this->Insert(boids_Array[i]);
    }
}

bool Quad::InBoundary(Vector* position)
{
    if (position->x >= this->boundary_TL->x && position->x <= this->boundary_BR->x && position->y >= this->boundary_TL->y && position->y <= this->boundary_BR->y) {
        return true;
    }
    else {
        return false;
    }
}

void Quad::PushToBranch(Boid* boid) // determines where to insert() boid (to be used on boids that are already checked to be in radius!), and 
{
    if (boid->position->x <= this->boundary_TL->x + (this->boundary_BR->x / 2)) {
        if (boid->position->y <= this->boundary_TL->y + (this->boundary_BR->y / 2)) { // TL
            this->TL->Insert(boid);
        }
        else { // BL
            this->BL->Insert(boid);
        }
    }
    else {
        if (boid->position->y <= this->boundary_TL->y + (this->boundary_BR->y / 2)) { // TR
            this->TR->Insert(boid);
        }
        else { // BR
            this->BR->Insert(boid);
        }
    }
}

The main issue is that it works fine for a very small number of boids, but if i Insert() even 10 (with different randomised positions that are well within the scope of the tree) to a quadtree with a max_Depth of 100 and a max_Nodes value of 1 or 2, i end up with hundreds of branches and around 20 depth errors which makes no sense? Any help would be much appreciated! I am losing my mind ;-;

  • 1
    I believe you have much trouble along [these lines](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). Also why are you using pointers for simple data types like `unsigned short`? That doesn't make any sense for me. – πάντα ῥεῖ Oct 25 '22 at 21:29
  • Ah... mostly because i want to be super efficient with memory! Is this not the best way to go about it? – Oscar James Pope-Lenkowiec Oct 25 '22 at 21:32
  • 2
    No, just the opposite. Generally you should avoid any manual memory management using `new` and `delete` yourself. Its just naive to believe you can do that more efficient and less error prone than the developers of your compilers c++ standard library. – πάντα ῥεῖ Oct 25 '22 at 21:40
  • @πάνταῥεῖ ok! Thank you for the response :) I will change my simple data types as you recommended and see if maybe that is causing the issues? I had a look at the post you linked, where am I copying objects? Sorry if it is super obvious! I just can't see where I copied anything :/ – Oscar James Pope-Lenkowiec Oct 25 '22 at 21:42
  • @πάνταῥεῖ I tried to not allocate them using new... but instantly this resulted in stack overflow xD are you sure when working with complex data structures like a quadtree it isn't best to keep all data stored on the heap? I don't see how I can avoid this otherwise, as I need to delete specific data before branching into new nodes! (to prevent excess memory usage) - also, i am 17... so im very sorry if i don't have the depth of knowledge of those you may be used to helping out... – Oscar James Pope-Lenkowiec Oct 25 '22 at 22:26
  • C++ is an hard language... Either read a book or select a more modern language that is less error-prone if you don't want to put adequate effort in learning. – Phil1970 Oct 25 '22 at 23:10
  • managed to get it working :D wow i'm so dumb... it was just to do with how i was calculating the boundaries of the child nodes xD – Oscar James Pope-Lenkowiec Oct 25 '22 at 23:18
  • @Phil1970 i know? i came here because i want to expand my knowledge around c++! if i'm honest its my favourite language! :)) (also having experience using python, c# and javascript) if you have any good book recommendations then I would love to read them! I did watch a 31 hour course on the language when i was starting out, so i have a little knowledge of the basics... I have mostly been using c++ in conjunction with opengl because i wanted to try some lower level graphical programing! – Oscar James Pope-Lenkowiec Oct 25 '22 at 23:23
  • You don't need to type `this->` everywhere. Calling `new` allocates from heap whereas using native types allocates memory from the stack. Dereferencing pointers everywhere is against optimization. Try going over basic tutorials like https://www.w3schools.com/cpp/. Your code seems like written in Java :) – Burak Oct 28 '22 at 18:32

1 Answers1

0

I was calculating the boundaries of the branches incorrectly! Thanks for all the help and feedback :)

updated calculation

this->TL = new Quad(this->boundary_TL->x, this->boundary_TL->y, (this->boundary_TL->x + this->boundary_BR->x) / 2, (this->boundary_TL->y + this->boundary_BR->y) / 2, *(this->max_Nodes), *(this->max_Depth) - 1);
this->TR = new Quad((this->boundary_TL->x + this->boundary_BR->x) / 2, this->boundary_TL->y, this->boundary_BR->x, (this->boundary_TL->y + this->boundary_BR->y) / 2, *(this->max_Nodes), *(this->max_Depth) - 1);
this->BL = new Quad(this->boundary_TL->x, (this->boundary_TL->y + this->boundary_BR->y) / 2, (this->boundary_TL->x + this->boundary_BR->x) / 2, this->boundary_BR->y, *(this->max_Nodes), *(this->max_Depth) - 1);
this->BR = new Quad((this->boundary_TL->x + this->boundary_BR->x) / 2, (this->boundary_TL->y + this->boundary_BR->y) / 2, this->boundary_BR->x, this->boundary_BR->y, *(this->max_Nodes), *(this->max_Depth) - 1);
Burak
  • 2,251
  • 1
  • 16
  • 33