attcs / Octree

Octree/Quadtree/N-dimensional linear tree
MIT License
113 stars 13 forks source link

Abstract class as point #7

Closed AmirMFarhang closed 1 year ago

AmirMFarhang commented 1 year ago

Hello,

How can we use an abstract class as a point?

This is our block class :

class Block
{
public:
    float x{}, y{}, z{};
    virtual ~Block() = default;
    virtual void addFace(int) = 0;
    virtual void removeFace(int) = 0;
    virtual glm::vec3 getCoords() = 0;
    virtual void setupMesh() = 0;
    virtual void draw(Program&) = 0;
};

I want my custom point to be block pointer, and i believe you are default constructing the point type in the octree. which would not work with the point type that im trying to use.

Thank you for the awesome source code, and help.

attcs commented 1 year ago

Hi,

The primary issue is around the std containers. The current solution is based on iterable containers (now, it is definitely specialized to std::span), which cannot contain abstract classes (Block). To make it independent from the std::span it would need too much modification and compatibility issues: 2 new container types (one for vector_type-s and one for box_type-s) should be used, which are iterable and dereference the abstraction itself, and these container- and iterator-types must be implemented in your case also. It does not seem ideal.

A lazy example of this idea:

struct BlockContainer
{
  std::vector<std::unique_ptr<Block>> blocks; // question of containment/ownership...
  // ... begin(), end()
};

struct BlockContainerIteratorWrapper
{
private:
    std::vector<std::unique_ptr<Block>>::iterator m_it;
public:  
    Block& operator*() const { return *(m_it->get()); } // question of dereference
    Block* operator->() { return m_it->get(); }
// ... ctor, input iterator requirements, etc.
}

Therefore, I think you have three options:

  1. The above-mentioned, which requires both Orthotree modification and non-trivial container implementation
  2. Adaptor for the concrete Block classes (but if the Block abstraction is reasonable this is not what you want)
  3. Composition: the point part of the Block class could be a concrete BlockPoint class, and you can extract these points before octree creation (or during octree usage), in a std container (E.g. std::vector). This would require an index-based management of the original object: the Core is specially designed in this aspect.

I recommend the 3. way.

struct BlockPoint
{
  float x{}, y{}, z{};
};

class Block
{
public:
    BlockPoint point;
    virtual ~Block() = default;
    virtual void addFace(int) = 0;
    virtual void removeFace(int) = 0;
    virtual glm::vec3 getCoords() = 0;
    virtual void setupMesh() = 0;
    virtual void draw(Program&) = 0;
};

// ... adaptor for BlockPoint