blob: b7e7c75fce9df787ef35b5301d649fa13decd503 [file] [log] [blame]
/*
* RenderItemDistanceMetric.h
*
* Created on: Feb 16, 2009
* Author: struktured
*/
#ifndef RenderItemDISTANCEMETRIC_H_
#define RenderItemDISTANCEMETRIC_H_
#include "Common.hpp"
#include "Renderable.hpp"
#include <limits>
#include <functional>
#include <map>
/// Compares two render items and returns zero if they are virtually equivalent and large values
/// when they are dissimilar. If two render items cannot be compared, NOT_COMPARABLE_VALUE is returned.
class RenderItemDistanceMetric : public std::binary_function<const RenderItem*, const RenderItem*, double>
{
public:
const static double NOT_COMPARABLE_VALUE;
virtual double operator()(const RenderItem * r1, const RenderItem * r2) const = 0;
virtual TypeIdPair typeIdPair() const = 0;
};
// A base class to construct render item distance metrics. Just specify your two concrete
// render item types as template parameters and override the computeDistance() function.
template <class R1, class R2>
class RenderItemDistance : public RenderItemDistanceMetric
{
protected:
// Override to create your own distance fmetric for your specified custom types.
virtual double computeDistance(const R1 * r1, const R2 * r2) const = 0;
public:
inline virtual double operator()(const RenderItem * r1, const RenderItem * r2) const
{
if (supported(r1, r2))
return computeDistance(dynamic_cast<const R1*>(r1), dynamic_cast<const R2*>(r2));
else if (supported(r2,r1))
return computeDistance(dynamic_cast<const R1*>(r2), dynamic_cast<const R2*>(r1));
else
return NOT_COMPARABLE_VALUE;
}
// Returns true if and only if r1 and r2 are the same type as or derived from R1, R2 respectively
inline bool supported(const RenderItem * r1, const RenderItem * r2) const
{
return dynamic_cast<const R1*>(r1) && dynamic_cast<const R2*>(r2);
//return typeid(r1) == typeid(const R1 *) && typeid(r2) == typeid(const R2 *);
}
inline TypeIdPair typeIdPair() const
{
return TypeIdPair(typeid(const R1*).name(), typeid(const R2*).name());
}
};
class RTIRenderItemDistance : public RenderItemDistance<RenderItem, RenderItem>
{
public:
RTIRenderItemDistance() {}
virtual ~RTIRenderItemDistance() {}
protected:
virtual inline double computeDistance(const RenderItem * lhs, const RenderItem * rhs) const
{
if (typeid(*lhs) == typeid(*rhs)) {
//std::cerr << typeid(*lhs).name() << " and " << typeid(*rhs).name() << "are comparable" << std::endl;
return 0.0;
}
else {
//std::cerr << typeid(*lhs).name() << " and " << typeid(*rhs).name() << "not comparable" << std::endl;
return NOT_COMPARABLE_VALUE;
}
}
};
class ShapeXYDistance : public RenderItemDistance<Shape, Shape>
{
public:
ShapeXYDistance() {}
virtual ~ShapeXYDistance() {}
protected:
virtual inline double computeDistance(const Shape * lhs, const Shape * rhs) const
{
return (meanSquaredError(lhs->x, rhs->x) + meanSquaredError(lhs->y, rhs->y)) / 2;
}
};
class MasterRenderItemDistance : public RenderItemDistance<RenderItem, RenderItem>
{
typedef std::map<TypeIdPair, RenderItemDistanceMetric*> DistanceMetricMap;
public:
MasterRenderItemDistance() {}
virtual ~MasterRenderItemDistance() {}
inline void addMetric(RenderItemDistanceMetric * fun)
{
_distanceMetricMap[fun->typeIdPair()] = fun;
}
protected:
virtual inline double computeDistance(const RenderItem * lhs, const RenderItem * rhs) const
{
RenderItemDistanceMetric * metric;
TypeIdPair pair(typeid(lhs), typeid(rhs));
// If specialized metric exists, use it to get higher granularity
// of correctness
if (_distanceMetricMap.count(pair)) {
metric = _distanceMetricMap[pair];
} else if (_distanceMetricMap.count(pair = TypeIdPair(typeid(rhs), typeid(lhs)))) {
metric = _distanceMetricMap[pair];
} else { // Failing that, use rtti && shape distance if its a shape type
const double rttiError = _rttiDistance(lhs,rhs);
/// @bug This is a non elegant approach to supporting shape distance
if (rttiError == 0 && _shapeXYDistance.supported(lhs,rhs))
return _shapeXYDistance(lhs, rhs);
else
return rttiError;
}
return (*metric)(lhs, rhs);
}
private:
mutable RTIRenderItemDistance _rttiDistance;
mutable ShapeXYDistance _shapeXYDistance;
mutable DistanceMetricMap _distanceMetricMap;
};
#endif /* RenderItemDISTANCEMETRIC_H_ */