This question is related to this other one. I'm trying to implement the virtual method
approach suggested in one of the answers.
I have an abstract base class representing an object described by a Level-Set function
class LevelSetObject
{
public:
virtual double SDF(double x, double y, double z) const = 0;
/** @brief Union of two LevelSetObjects */
CompositeLevelSetObject operator+(LevelSetObject& other);
virtual ~LevelSetObject() = default;
};
The first implementation I had with std::function
was working more or less as expected. The difference now is that I return a CompositeLevelSetObject
when adding up two generic LevelSetObjects
CompositeLevelSetObject LevelSetObject::operator+(LevelSetObject& other) {
CompositeFun* fun = [] (double sdf_value1, double sdf_value2) {
return std::min(sdf_value1, sdf_value2);
};
auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));
auto second = std::unique_ptr<LevelSetObject>(new LevelSetObject(other));
return { std::move(first), std::move(second), fun };
}
A CompositeLevelSetObject
, at least in my mind :), is an object that takes as input pointers
the two objects it's composed by, plus a function pointer that computes the resulting distance function (Primitive combinations of LevelSetObjects
are encoded by operations between the two single distance function of the objects ref ("Primitive Combinations"))
/** @brief This is the function that is called on the two single SDF function of the objects */
using CompositeFun = double (double, double);
/**
* @brief A class representing a composite LevelSetObject coming out of operation between two other LevelSetObjects
*
* This class stores pointers to the two LevelSetObject and executes a given function on both of them
*/
class CompositeLevelSetObject : public LevelSetObject
{
using LevelSetObjectPtr = std::unique_ptr<LevelSetObject>;
private:
LevelSetObjectPtr m_first;
LevelSetObjectPtr m_second;
CompositeFun* m_fun;
public:
CompositeLevelSetObject() = default;
CompositeLevelSetObject(LevelSetObjectPtr first, LevelSetObjectPtr second, CompositeFun* m_fun);
CompositeLevelSetObject(CompositeLevelSetObject&&);
double SDF(double x, double y, double z) const override;
// :: Operators ::
CompositeLevelSetObject& operator=(CompositeLevelSetObject&&);
};
}
double CompositeLevelSetObject::SDF(double x, double y, double z) const {
return m_fun(m_first->SDF(x, y, z), m_second->SDF(x, y, z));
}
This clearly does not work, because in the LevelSetObject::operator+
, I'm creating the pointers instantiating an abstract class.
allocating an object of abstract class type 'hgve::LevelSetObject'
auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));
So I tried to switch the LevelSetObject::SDF
method to be non-pure, returning 0
. But clearly doesn't work because then everything returns 0.
I'm missing something in my conceptual organisation of the data structure, probably due to my dynamic languages background, but I can't see it. Any help is appreciated.
An example of usage:
// Vector containing a list of LevelSetSpheres
static std::vector<LevelSetSphere> elements = {
LevelSetSphere{radius, {radius, 0.25, 0.25}},
LevelSetSphere{radius, {radius + interDistance, 0.25, 0.25}},
LevelSetSphere{radius, {radius + 2*interDistance, 0.25, 0.25}}
};
int main(int argc, char* argv[]) {
// Sum first two elements
CompositeLevelSetObject soot = elements[0] + elements[1];
for(auto el = std::next(elements.begin(), 2); el != elements.end(); ++el) {
// Combine elements
soot = soot + *el;
}
}
LevelSetSphere
is a derived class from LevelSetObject
.
class LevelSetSphere : public LevelSetObject
{
private:
double m_R; /**< The radius of the sphere */
SimpleVector m_C; /**< The center of the sphere */
public:
/** @brief Constructor
*
* @param radius The radius of the sphere
*/
LevelSetSphere(double radius, SimpleVector center);
double SDF(double x, double y, double z) const override;
};