mirea-projects/Third term/Industrial programming technologies/3_Calculator/calculator.cpp

213 lines
6.8 KiB
C++
Raw Normal View History

2024-09-27 05:31:03 +00:00
#include <cmath>
#include <stdexcept>
#include "calculator.h"
#include "./ui_calculator.h"
Calculator::Calculator(QWidget *parent)
: QMainWindow(parent), ui(new Ui::Calculator)
{
ui->setupUi(this);
connect(ui->buttonAdd, &QPushButton::clicked, this, &Calculator::operationClicked);
connect(ui->buttonSubtract, &QPushButton::clicked, this, &Calculator::operationClicked);
connect(ui->buttonMultiply, &QPushButton::clicked, this, &Calculator::operationClicked);
connect(ui->buttonDivide, &QPushButton::clicked, this, &Calculator::operationClicked);
connect(ui->buttonSin, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonCos, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonTan, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonCot, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonArcsin, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonArccos, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
connect(ui->buttonArctan, &QPushButton::clicked, this, &Calculator::trigonometricOperationClicked);
}
Calculator::~Calculator()
{
delete ui;
}
double Calculator::performOperation(double num1, double num2, const string &operation)
{
if (operation == "+")
return num1 + num2;
if (operation == "-")
return num1 - num2;
if (operation == "*")
return num1 * num2;
if (operation == "/")
{
if (num2 == 0)
{
throw invalid_argument("Деление на ноль.");
}
return num1 / num2;
}
throw invalid_argument("Неизвестная операция.");
}
double Calculator::validateTrigonometricInput(double value, const string &function)
{
if (function == "ARCSIN" || function == "ARCCOS" || function == "ARCTAN")
{
if (value < -1 || value > 1)
{
throw invalid_argument("Ввод вне диапазона для arcsin/arccos/arctan.");
}
}
return value;
}
double Calculator::convertToRadians(double value)
{
return value * M_PI / 180.0;
}
double Calculator::convertToDegrees(double value)
{
return value * 180.0 / M_PI;
}
bool Calculator::useRadians()
{
return ui->radioButtonRadians->isChecked();
}
double Calculator::handleSpecialAngles(double value, const string &function)
{
if (useRadians())
{
value = convertToDegrees(value);
}
if (fmod(value, 360.0) == 0.0)
{
if (function == "SIN") return 0.0;
if (function == "COS") return 1.0;
if (function == "TAN") return 0.0;
if (function == "COT") throw invalid_argument("Котангенс не определен.");
}
else if (fmod(value, 90.0) == 0.0 && fmod(value, 180.0) != 0.0)
{
if (function == "SIN") return 1.0;
if (function == "COS") return 0.0;
if (function == "TAN") throw invalid_argument("Тангенс не определен.");
if (function == "COT") return 0.0;
}
else if (fmod(value, 180.0) == 0.0)
{
if (function == "SIN") return 0.0;
if (function == "COS") return -1.0;
if (function == "TAN") return 0.0;
if (function == "COT") throw invalid_argument("Котангенс не определен.");
}
else if (fmod(value, 270.0) == 0.0)
{
if (function == "SIN") return -1.0;
if (function == "COS") return 0.0;
if (function == "TAN") throw invalid_argument("Тангенс не определен.");
if (function == "COT") return 0.0;
}
return nan("");
}
void Calculator::operationClicked()
{
QPushButton *clickedButton = qobject_cast<QPushButton *>(sender());
string operation = clickedButton->text().toStdString();
double num1 = ui->firstNumberInput->text().toDouble();
double num2 = ui->secondNumberInput->text().toDouble();
try
{
double result = performOperation(num1, num2, operation);
if (std::isnan(result))
{
ui->plainTextEdit->setText("Не число (NaN).");
}
else if (std::isinf(result))
{
ui->plainTextEdit->setText("Бесконечность.");
}
else
{
ui->plainTextEdit->setText(QString::number(result));
}
}
catch (const invalid_argument &e)
{
ui->plainTextEdit->setText(e.what());
}
}
void Calculator::trigonometricOperationClicked()
{
QPushButton *clickedButton = qobject_cast<QPushButton *>(sender());
string function = clickedButton->text().toStdString();
double value = ui->firstNumberInput->text().toDouble();
try
{
double specialValue = handleSpecialAngles(value, function);
if (!std::isnan(specialValue))
{
ui->plainTextEdit->setText(QString::number(specialValue));
return;
}
if (!useRadians() && function != "ARCSIN" && function != "ARCCOS" && function != "ARCTAN")
{
value = convertToRadians(value);
}
if (function == "SIN")
value = sin(value);
else if (function == "COS")
value = cos(value);
else if (function == "TAN")
{
if (fmod(value, M_PI / 2) == 0 && fmod(value, M_PI) != 0)
{
throw invalid_argument("Тангенс не определен.");
}
value = tan(value);
}
else if (function == "COT")
{
if (fmod(value, M_PI) == 0)
{
throw invalid_argument("Котангенс не определен.");
}
value = 1 / tan(value);
}
else if (function == "ARCSIN")
value = asin(validateTrigonometricInput(value, function));
else if (function == "ARCCOS")
value = acos(validateTrigonometricInput(value, function));
else if (function == "ARCTAN")
value = atan(validateTrigonometricInput(value, function));
else
throw invalid_argument("Неизвестная тригонометрическая функция.");
if (!useRadians() && (function == "ARCSIN" || function == "ARCCOS" || function == "ARCTAN"))
{
value = convertToDegrees(value);
}
if (std::isnan(value))
{
ui->plainTextEdit->setText("Не число (NaN).");
}
else if (std::isinf(value))
{
ui->plainTextEdit->setText("Бесконечность.");
}
else
{
ui->plainTextEdit->setText(QString::number(value));
}
}
catch (const invalid_argument &e)
{
ui->plainTextEdit->setText(e.what());
}
}