| /* |
| * 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_ */ |