簡體   English   中英

如何在c ++中將此公式拆分為函數?

[英]How to split this formula into function in c++?

我的代碼使用公式來查找機器人聲納傳感器發現障礙的位置。 代碼如下所示:

 obstacleX = robot.x + robot.sensorReadings.at(i) * cos((robot.deg + i * angleBetweenSensors) * PI / 180);
 obstacleY = robot.y + robot.sensorReadings.at(i) * sin((robot.deg + i * angleBetweenSensors) * PI / 180);

而且我想讓它成為一個功能,不要多次重復這個公式(並使其更容易更改)。 我會做這樣的功能:

double calculateObstaclePosition(double robotX, double sesnorReading, double robotDegree, int angleBetweenSensors){
      return robotX + sesnorReading * cos((robotDegree + i * angleBetweenSensors) * PI / 180);
}

並經過

obstacleX = calculateObstaclePosition(robot.x, robot.sensorReadings.at(i), robot.deg, angleBetweenSensors);

但X和Y的公式幾乎相同,唯一的區別是使用竇,第二個使用cosinus。 我應該創建兩個幾乎相同的函數,還是可以在一個函數中完成?

可用選項:

(1)使用標志表示您是否要使用余弦或正弦:

double calculateObstaclePosition(double robotC, ..., bool useCos)
{
   double angle = (robotDegree + i * angleBetweenSensors) * PI / 180;
   return robotC + sensorReading * (useCos ? cos(angle) : sin(angle));
}

(2)創建一些2D矢量數據類型並一次返回兩個坐標

struct vec2D
{
   double x, y;
};
vec2D calculateObstaclePosition(double robotX, double robotY, ...)
{
   vec2D pos;   
   double angle = (robotDegree + i * angleBetweenSensors) * PI / 180;
   pos.x = robotX + sensorReadingX * cos(angle);
   pos.y = robotY + sensorReadingY * sin(angle);
   return pos;
}

或者使用課程或其他東西。 也可以轉換機器人類使用vec2D作為坐標。

(3)模糊一:傳遞要數值函數的指針。 不安全!

typedef double (*numfuncptr)(double a);
double calculateObstaclePosition(double robotC, ..., numfuncptr trig)
{
   double angle = ...;
   return robotC + sensorReading * trig(angle);
}

(4)不那么模糊,但是C風格,因此不是OOP-esque:傳遞變量的輸出指針。 (再次不安全)

void calculateObstaclePosition(double robotX, double robotY, ..., double* outX, double* outY)
{
   double angle = ...;
   *outX = robotX + ...
   *outY = robotY + ...;
}
struct Robot {
    double x;
    double y;
    double deg; // robotDegree
    double angle; // angleBetweenSensors

    std::vector<double> sensorReadings; // sensorReading
};

std::pair<double, double> calculateObstaclePosition(const Robot &robot, int i)
{
  double obstacleX = robot.x + robot.sensorReadings.at(i) * cos((robot.deg + i * robot.angle) * PI / 180);
  double obstacleY = robot.y + robot.sensorReadings.at(i) * sin((robot.deg + i * robot.angle) * PI / 180);

  return std::make_pair(obstacleX, obstacleY);
}

那個怎么樣? 您可以創建一些要傳遞的類,並將值傳遞給函數。

聲明如下:

std::array<double,2> calculateObstaclePosition(const Robot& robot, int angleBetweenSensors)
{
    return {
        robot.x + robot.sensorReadings.at(i) * cos((robot.deg + i * angleBetweenSensors) * PI / 180) ,
        robot.y + robot.sensorReadings.at(i) * sin((robot.deg + i * angleBetweenSensors) * PI / 180)
    };
}

並稱之為

std::array<double,2> obstacle = calculateObstaclePosition(robot,angleBetweenSensors);

它不會阻止你做兩次計算,但鑒於參數xysensorReadings.at(i)robot.deg不是很昂貴,你不應該太擔心。 如果成本很高,請將它們作為參數傳遞,而不是傳遞整個機器人或首先將它們計算為臨時變量並在返回語句中使用它。

這個聲明的好處是,它可以防止你聲明兩個不同的函數,並將x和y的值綁定在一起。 如果你喜歡.x.y更好的符號,請使用

 struct Coords{double x, doubley};

而不是std::array

在這個簡單函數的情況下,IMHO並不重要,但是在更復雜的函數的情況下,您可以使用函數指針來選擇更大函數中使用的特定函數:

// enum to define which arguyment is calculated - X or Y
enum XorYEnum  { X, Y  };

double calculateObstaclePosition(double robotX, double sesnorReading, double robotDegree, int angleBetweenSensors, XorYEnum XorY)
{
    // Select the sin or cos function and assign function pointer
    double (* SinOrCosFunc)(double);
    if (XorY == X)
        SinOrCosFunc = cos;
    else
        SinOrCosFunc = sin;

    // Calculate
    return robotX + sesnorReading * SinOrCosFunc((robotDegree + i * angleBetweenSensors) * PI / 180);
}

如果你只想進行一次計算,你也可以使用函數指針並傳入sin或cos。

例如

double calculateObstaclePosition(double (*trigFunction)(double), double robotX, double sesnorReading, double robotDegree, int angleBetweenSensors){
      return robotX + sesnorReading * trigFunction((robotDegree + i * angleBetweenSensors) * PI / 180);
}

然后通過傳入sin或cos作為第一個參數來調用它

double posCur = calculateObstaclePosition(sin, param2, param3, param4, param5);

要么

double posCur = calculateObstaclePosition(cos, param2, param3, param4, param5);

我建議使用模板部分特化的解決方案,允許最小化寫入。 代碼中沒有條件,運行時沒有條件。 讓我們定義一些特殊函數,這些函數可以作為sin或cos依賴於X或Y.

定義要引用的X和Y的枚舉:

typedef enum { X, Y } xy_enum;

用於編譯時選擇的部分專用模板類:

template<xy_enum T>
struct _xcys // x cos y sin
{
    static double f( double t ) { return cos(t); }
};

template<>  // explicit specialization for T = Y
struct _xcys<Y> // x cos y sin
{
    static double f( double t ) { return sin(t); }
};

template<xy_enum T>
struct _xsyc // x sin y cos
{
    static double f( double t ) { return sin(t); }
};

template<>  // explicit specialization for T = Y
struct _xsyc<Y> // x sin y cos
{
    static double f( double t ) { return cos(t); }
};

定義作為sin或cos依賴於X或Y的xcys()因此xcys()對X的作用為cos,對Y作為sin。 並且xsyc()適用於X作為sin,而Y作為cos。

template<xy_enum T> // x sin y cos
double xcys ( double t ) { return _xcys<T>::f(t); }
template<xy_enum T> // x sin y cos
double xsyc ( double t ) { return _xsyc<T>::f(t); }

簡單的測試

std::cout << xcys<X>(0)      << " " << xcys<Y>(0) << std::endl;
std::cout << xcys<X>(M_PI/2) << " " << xcys<Y>(M_PI/2) << std::endl;
std::cout << xsyc<X>(0)      << " " << xsyc<Y>(0) << std::endl;
std::cout << xsyc<X>(M_PI/2) << " " << xsyc<Y>(M_PI/2) << std::endl;

結果輸出:

 1 0 ~0 1 0 1 1 ~0 

最后你的代碼有兩個這樣的函數:

double calculateObstaclePosition(double robotX, double sesnorReading, double robotDegree, int angleBetweenSensors){
      return robotX + sesnorReading * cos((robotDegree + i * angleBetweenSensors) * PI / 180);
}
double calculateObstaclePosition(double robotY, double sesnorReading, double robotDegree, int angleBetweenSensors){
      return robotY + sesnorReading * sin((robotDegree + i * angleBetweenSensors) * PI / 180);
}

可以使用一個模板函數重寫:

template< xy_enum T >
double calculateObstaclePosition(double robotXY, double sesnorReading, double robotDegree, int angleBetweenSensors){
      return robotXY + sesnorReading * xcys<T>((robotDegree + i * angleBetweenSensors) * PI / 180);
}

並為x和y調用單個函數兩次:

obstacleX = calculateObstaclePosition<X>(robot.x, robot.sensorReadings.at(i), robot.deg, angleBetweenSensors);
obstacleY = calculateObstaclePosition<Y>(robot.y, robot.sensorReadings.at(i), robot.deg, angleBetweenSensors);

計算障礙物X和障礙物的公式有一些重復。 您需要先簡化它們。 之后,您將在實現中看到非常少的代碼重復。 以下是我的代碼示例:

template <typename T>
std::vector<T> cal(Location<T> &robot, T angleBetweenSensors) {
    const size_t N = robot.sensorReadings.size();
    std::vector<T> results(2 * N, 0);

    // Precompute this value to improve performance.
    constexpr T angleScale = M_PI / 180;
    for (size_t i = 0; i < N; ++i) {
        // Main code
        T alpha = (robot.deg + i * angleBetweenSensors) * angleScale;
        T sensorVal = robot.sensorReadings.at(i);
        T obstacleX = robot.x + sensorVal * cos(alpha);
        T obstacleY = robot.y + sensorVal * sin(alpha);

        // Use obstacleX and obstacleY here
        results[2 * i] = obstacleX;
        results[2 * i + 1] = obstacleY;
    }
    return results;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM