Program Listing for File CRSSTDistance.h

Return to documentation for file (include/gwmodelpp/spatialweight/CRSSTDistance.h)

#ifndef CRSSTDISTANCE_H
#define CRSSTDISTANCE_H

#include "CRSDistance.h"
#include "OneDimDistance.h"
#include <math.h>

namespace gwm
{

class CRSSTDistance : public Distance
{
public:

    typedef arma::vec (*CalculatorType)(const std::unique_ptr<Distance>&, const std::unique_ptr<OneDimDistance>&, arma::uword, double, double);

    static arma::vec OrthogonalSTDistance(const std::unique_ptr<Distance>& spatial, const std::unique_ptr<OneDimDistance>& temporal, arma::uword focus, double lambda, double angle);

    static arma::vec ObliqueSTDistance(const std::unique_ptr<Distance>& spatial, const std::unique_ptr<OneDimDistance>& temporal, arma::uword focus, double lambda, double angle);

public:

    CRSSTDistance() :
        mSpatialDistance(nullptr),
        mTemporalDistance(nullptr),
        mLambda(0.0),
        mAngle(arma::datum::pi / 2.0)
    {
        mCalculator = &OrthogonalSTDistance;
    };

    explicit CRSSTDistance(const Distance& spatialDistance, const OneDimDistance& temporalDistance, double lambda):
        mSpatialDistance(spatialDistance.clone()),
        mTemporalDistance(static_cast<OneDimDistance*>(temporalDistance.clone().release())),
        mLambda(lambda),
        mAngle(arma::datum::pi / 2.0),
        mCalculator(&OrthogonalSTDistance)
    {}

    explicit CRSSTDistance(const Distance& spatialDistance, const OneDimDistance& temporalDistance, double lambda, double angle):
        CRSSTDistance(spatialDistance, temporalDistance, lambda)
    {
        mAngle = atan(tan(angle)),
        mCalculator = (abs(mAngle - arma::datum::pi / 2.0) < 1e-15) ? &OrthogonalSTDistance : &ObliqueSTDistance;
    }

    explicit CRSSTDistance(Distance&& spatialDistance, OneDimDistance&& temporalDistance, double lambda):
        mSpatialDistance(spatialDistance.clone()),
        mTemporalDistance(static_cast<OneDimDistance*>(temporalDistance.clone().release())),
        mLambda(lambda),
        mAngle(arma::datum::pi / 2.0),
        mCalculator(&OrthogonalSTDistance)
    {}

    explicit CRSSTDistance(Distance&& spatialDistance, OneDimDistance&& temporalDistance, double lambda, double angle):
        CRSSTDistance(spatialDistance, temporalDistance, lambda)
    {
        mAngle = atan(tan(angle)),
        mCalculator = (abs(mAngle - arma::datum::pi / 2.0) < 1e-15) ? &OrthogonalSTDistance : &ObliqueSTDistance;
    }

    explicit CRSSTDistance(const std::unique_ptr<Distance>& spatialDistance, const std::unique_ptr<OneDimDistance>& temporalDistance, double lambda):
        mSpatialDistance(spatialDistance->clone()),
        mTemporalDistance(static_cast<OneDimDistance*>(temporalDistance->clone().release())),
        mLambda(lambda),
        mAngle(arma::datum::pi / 2.0),
        mCalculator(&OrthogonalSTDistance)
    {}

    explicit CRSSTDistance(const std::unique_ptr<Distance>& spatialDistance, const std::unique_ptr<OneDimDistance>& temporalDistance, double lambda, double angle):
        CRSSTDistance(spatialDistance, temporalDistance, lambda)
    {
        mAngle = atan(tan(angle)),
        mCalculator = (abs(mAngle - arma::datum::pi / 2.0) < 1e-15) ? &OrthogonalSTDistance : &ObliqueSTDistance;
    }

    explicit CRSSTDistance(std::unique_ptr<Distance>&& spatialDistance, std::unique_ptr<OneDimDistance>&& temporalDistance, double lambda):
        mSpatialDistance(std::move(spatialDistance)),
        mTemporalDistance(std::move(temporalDistance)),
        mLambda(lambda),
        mAngle(arma::datum::pi / 2.0),
        mCalculator(&OrthogonalSTDistance)
    {}

    explicit CRSSTDistance(std::unique_ptr<Distance>&& spatialDistance, std::unique_ptr<OneDimDistance>&& temporalDistance, double lambda, double angle):
        CRSSTDistance(std::move(spatialDistance), std::move(temporalDistance), lambda)
    {
        mAngle = atan(tan(angle)),
        mCalculator = (abs(mAngle - arma::datum::pi / 2.0) < 1e-15) ? &OrthogonalSTDistance : &ObliqueSTDistance;
    }

    CRSSTDistance(const CRSSTDistance& distance):
        mSpatialDistance(distance.mSpatialDistance->clone()),
        mTemporalDistance(static_cast<OneDimDistance*>(distance.mTemporalDistance->clone().release())),
        mAngle(distance.mAngle),
        mCalculator(distance.mCalculator)
    {
        if (distance.mLambda >= 0 && distance.mLambda <= 1)
        {
            mLambda = distance.mLambda;
        }
        else throw std::runtime_error("The lambda must be in [0,1].");
    }

    std::unique_ptr<Distance> clone() const override
    {
        return std::make_unique<CRSSTDistance>(*this);
    }

    DistanceType type() override { return DistanceType::CRSSTDistance; }

    void makeParameter(std::initializer_list<DistParamVariant> plist) override;

    arma::vec distance(arma::uword focus) override
    {
        return mCalculator(mSpatialDistance, mTemporalDistance, focus, mLambda, mAngle);
    }

    double minDistance() override;

    double maxDistance() override;

public:

    //const gwm::CRSDistance* spatialDistance() const { return mSpatialDistance; }

    const std::unique_ptr<Distance>& spatialDistance() const { return mSpatialDistance; }

    const std::unique_ptr<OneDimDistance>& temporalDistance() const { return mTemporalDistance; }

    // unused code to set lambda
    const double lambda(){ return mLambda; }
    void setLambda(const double lambda)    {
        if (lambda >= 0 && lambda <= 1)
        {
            mLambda = lambda;
        }
        else
            throw std::runtime_error("The lambda must be in [0,1].");
    }

    const double angle() { return mAngle; }
    void setAngle(const double angle)    {
        mAngle = angle;
    }

protected:
    std::unique_ptr<Distance> mSpatialDistance = nullptr;
    std::unique_ptr<OneDimDistance> mTemporalDistance = nullptr;

    double mLambda = 0.0;
    double mAngle = arma::datum::pi / 2;

private:
    std::unique_ptr<Parameter> mParameter;
    CalculatorType mCalculator = &OrthogonalSTDistance;
};

}

#endif // CRSSTDISTANCE_H