/*
Nome: Mario
Cognome: Montanari

Esercizio sui numeri complessi
*/

#include <iostream>
#include <iomanip>
#include <cmath>

#define PI 3.1415926535

using namespace std;

typedef struct {
	int re, im;
} complx;

complx add(complx z1, complx z2); // Calcola la somma dei due numeri complessi
complx sub(complx z1, complx z2); // Calcola la differenza dei due numeri complessi
complx mul(complx z1, complx z2); // Calcola il prodotto tra i due numeri complessi
complx pow(complx z, int esp); // Calcola la potenza dei due numeri complessi specificando in input il valore dell'esponente
float mod(complx z); // Calcola il modulo dei due numeri complessi
float arg(complx z); // Calcola l'argomento dei due numeri complessi
float rad2deg(float x); // Converte il risultato in radianti dell'argomento in gradi
float real(complx z); // Calcola il valore della coordinata polare sull'asse reale
float imag(complx z); // Calcola il valore della coordinata polare sull'asse immaginario
void print(complx z); // Funzione che stampa

int main(void) {
	complx z1, z2;
	int esp1, esp2;
	
	cout << "Parte reale del primo numero complesso (x1): "; // Specifichiamo la parte reale del primo numero complesso
	cin >> z1.re;
	
	cout << "Parte immaginaria del primo numero complesso (y1): i"; // Specifichiamo la parte immaginaria del primo numero complesso
	cin >> z1.im;
	
	cout << endl;
	
	cout << "Parte reale del secondo numero complesso (x2): "; // Specifichiamo la parte reale del secondo numero complesso
	cin >> z2.re;
	
	cout << "Parte immaginaria del secondo numero complesso (y2): i"; // Specifichiamo la parte immaginaria del secondo numero complesso
	cin >> z2.im;
	
	cout << endl;
	sleep(1);
	
	cout << "Primo numero complesso (z1): "; // Ricapitoliamo il valore del primo numero complesso
	print(z1);
	
	cout << "Secondo numero complesso (z2): "; // Ricapitoliamo il valore del primo numero complesso
	print(z2);
	
	cout << endl;
	sleep(1);
	
	cout << "Somma dei due numeri complessi: "; // Calcola la somma dei due numeri complessi
	print(add(z1, z2));
	
	cout << endl;
	sleep(1);
	
	cout << "Differenza dei due numeri complessi: "; // Calcola la differenza dei due numeri complessi
	print(sub(z1, z2));
	
	cout << endl;
	sleep(1);
	
	cout << "Prodotto dei due numeri complessi: "; // Calcola il prodotto dei due numeri complessi
	print(mul(z1, z2));
	
	cout << endl;
	sleep(1);
	
	cout << "Esponente della potenza del primo numero complesso: "; // Chiede in input di specificare il valore dell'esponente della potenza del primo numero complesso
	cin >> esp1;
	
	cout << "Potenza del primo numero complesso: "; // Calcola la potenza del primo numero complesso per l'esponente da noi specificato in input
	print(pow(z1, esp1));
	
	cout << endl;
	sleep(1);
	
	cout << "Esponente della potenza del secondo numero complesso: "; // Chiede in input di specificare il valore dell'esponente della potenza del secondo numero complesso
	cin >> esp2;
	
	cout << "Potenza del secondo numero complesso: "; // Calcola la potenza del secondo numero complesso per l'esponente da noi specificato in input
	print(pow(z2, esp2));
	
	cout << endl;
	sleep(1);
	
	cout << "Modulo (o ipotenusa) del primo numero complesso: "; // Calcola il modulo del primo numero complesso
	cout << mod(z1);
	
	cout << endl;
	
	cout << "Modulo (o ipotenusa) del secondo numero complesso: "; // Calcola il modulo del secondo numero complesso
	cout << mod(z2);
	
	cout << endl << endl;
	sleep(1);
	
	cout << "Argomento (in gradi) del primo numero complesso: "; // Calcola l'argomento del primo numero complesso
	cout << rad2deg(arg(z1)) << " gradi";
	
	cout << endl;
	
	cout << "Argomento (in gradi) del secondo numero complesso: "; // Calcola l'argomento del secondo numero complesso
	cout << rad2deg(arg(z2)) << " gradi";
	
	cout << endl << endl;
	sleep(1);
	
	cout << "Valore della coordinata polare del modulo del primo numero complesso sull'asse reale: ";
	cout << real(z1);
	
	cout << endl;
	
	cout << "Valore della coordinata polare del modulo del primo numero complesso sull'asse immaginario: ";
	cout << imag(z1);
	
	cout << endl << endl;
	sleep(1);
	
	cout << "Valore della coordinata polare del modulo del secondo numero complesso sull'asse reale: ";
	cout << (mod(z2) * cos(arg(z2)));
	
	cout << endl;
	
	cout << "Valore della coordinata polare del modulo del secondo numero complesso sull'asse immaginario: ";
	cout << (mod(z2) * sin(arg(z2)));
	
	cout << endl;
		
	return 0;
}

complx add(complx z1, complx z2) {
	return complx{(z1.re + z2.re), (z1.im + z2.im)};
}

complx sub(complx z1, complx z2) {
	return complx{(z1.re - z2.re), (z1.im - z2.im)};
}

complx mul(complx z1, complx z2) {
	return complx{(z1.re * z2.re) - (z1.im * z2.im), (z1.re * z2.im + (z1.im * z2.re))};
}

complx pow(complx z, int esp) {
	complx result {1, 0}; // (1, 0) è il valore neutro della moltiplicazione nei numeri complessi
	for (int i = 0; i < esp; i++) {
		result = mul(result, z);
	}
	
	return result;
}

float mod(complx z) {
	return hypot(z.re, z.im); // Funzione che svolge il calcolo del modulo del numero complesso
}

float arg(complx z) {
	return atan2(z.im, z.re); // Funzione che svolge il calcolo dell'argomento in radianti del numero complesso
}

float rad2deg(float x) {
	return (x * (180 / PI));
}

float real(complx z) {
	return (mod(z) * cos(arg(z)));
}

float imag(complx z) {
	return (mod(z) * sin(arg(z)));
}

void print(complx z) {
	if (z.im < 0) {
		cout << z.re << " - i" << -z.im << endl;
	} else {
		cout << z.re << " + i" << z.im << endl;
	}
}