Una possibile soluzione, molto pi`u esauriente rispetto alle richieste

Una possibile soluzione, molto più esauriente rispetto alle richieste stesse del problema è la seguente (è stata
“ragionevolmente” controllata, ma se qualcuno trovasse dei difetti di funzionamento è pregato di segnalarlo)
#include <iostream>
#include <iomanip>
#include <math.h>
#define ORTHO 0
#define BARIC 1
#define CIRCO 2
#define INCEN 3
#define PERIMETRO UNITARIO 1
#define AREA UNITARIA 2
using namespace std;
/* questa funzione non è membro della classe e serve
a convertire i tre angoli di un triangolo da radianti a
gradi sessagesimali, primi, secondi */
int ** converti(double a[])
{int ** i;
double dumm, domm;
i = new int*[3];
for(int j=0; j < 3; j++)
i[j] = new int[3],
domm = a[j]*180.0/M PI,
i[j][0] = static cast<int>(floor(domm)),
dumm = (domm - static cast<double>(i[j][0]))*60.0,
i[j][1] = static cast<int>(floor(dumm)),
domm = (dumm - static cast<double>(i[j][1]))*60.0,
i[j][2] = static cast<int>(floor(domm));
if(i[0][2]+i[1][2]+i[2][2]) i[2][2]++;
return i;}
/* qui inizia la classe dei triangoli */
class Triangolo
{
/* la variabile booleana "fatto" indica se è stato
possibile costruire effettivamente il triangolo*/
bool fatto;
// verifica delle disuguaglianze triangolari
bool testCongruenzaLati(double l[], char q)
{bool r = true;
for(char c=0; c < q; c++) r = r && l[c] > 0.0;
if(q == 2) return r;
return r &&
l[0] < l[1]+l[2] && l[1] < l[2]+l[0] && l[2] < l[0]+l[1] &&
l[0] >= fabs(l[1]-l[2]) && l[1] >= fabs(l[2]-l[0]) && l[2] >= fabs(l[0]-l[1]);}
/* ordinamento dei lati dal maggiore al minore e "riconoscimento"
del grado di "regolarità" del triangolo */
void ordinaLati()
{if(fabs(lati[0] - lati[1]) > 1.e-8*lati[0]
&& fabs(lati[0] - lati[2]) > 1.e-8*lati[0]
&& fabs(lati[1] - lati[2]) > 1.e-8*lati[1]) regolarita = scaleno;
else if(fabs(lati[0] - lati[1]) <= 1.e-8*lati[0]
|| fabs(lati[0] - lati[2]) <= 1.e-8*lati[0])
{if(fabs(lati[1] - lati[2]) <= 1.e-8*lati[1])
lati[2] = lati[1] = lati[0], regolarita = equilatero;
else lati[1] = lati[0], regolarita = isoscele;}
i[0] = ((lati[0] >= lati[1]) ? ((lati[0] >= lati[2]) ? 0 : 2)
: ((lati[1] >= lati[2]) ? 1 : 2)),
i[2] = ((lati[0] < lati[1]) ? ((lati[0] < lati[2]) ? 0 : 2)
: ((lati[1] < lati[2]) ? 1 : 2));
i[1] = 3 - i[0] - i[2];}
/* calcolo del punto d’incontro di due rette */
double * incrociaRette(double * r1, double *r2)
{double d;
if((d = r1[0]*r2[1] - r1[1]*r2[0]) == 0.0) return 0;
double *xy = new double[2];
xy[0] = (r1[1]*r2[2]-r1[2]*r2[1]) / d,
xy[1] = (r1[2]*r2[0]-r1[0]*r2[2]) / d;
return xy;}
/* calcolo dei coefficienti dell’equazione della
retta bisettrice dell’angolo numero a */
double * rettaBisettrice(int a)
{double * c = new double[3];
c[1] = 1.0;
switch(a)
{case 0:
c[0] = tan(angoli[2]+0.5*angoli[a]), c[2] = -vertici[2][1] -vertici[2][0]*c[0];
break;
case 1:
c[0] = -tan(0.5*angoli[a]), c[2] = 0.0;
break;
case 2:
c[0] = tan(0.5*angoli[a]), c[2] = lati[0]*c[0];}
return c;}
/* calcolo dei coefficienti dell’equazione della
retta che porta l’altezza relativa al lato numero a */
double * rettaAltezza(int a)
{double * c = new double[3];
switch(a)
{case 0:
c[1] = 0.0, c[0] = 1.0, c[2] = -vertici[2][0];
break;
case 1:
if(rette[1][1] == 0.0) c[0] = c[2] = 0.0, c[1] = 1.0;
else c[0] = -rette[1][1]/rette[1][0], c[1] = 1.0, c[2] = 0.0;
break;
case 2:
if(rette[2][1] == 0.0) c[0] = c[2] = 0.0, c[1] = 1.0;
else c[0] = -rette[2][1]/rette[2][0], c[1] = 1.0, c[2] = 0.0;}
return c;}
/* calcolo dei coefficienti dell’equazione della
retta che porta l’asse del lato numero a */
double * rettaAsse(int a)
{double * c = new double[3];
switch(a)
{case 0:
c[0] = 1.0, c[1] = 0.0, c[2] = -0.5*lati[0];
break;
case 1:
if(rette[1][1] == 0.0) c[0] = 0.0, c[1] = 1.0, c[2] = -0.5*lati[1];
else
c[0] = -rette[1][1]/rette[1][0], c[1] = 1.0,
c[2] = 0.5*lati[1]*(c[0]*cos(angoli[2])-sin(angoli[2])) -c[0]*lati[0];
break;
case 2:
if(rette[2][1] == 0.0) c[0] = 0.0, c[1] = 1.0, c[2] = -0.5*lati[2];
else
c[0] = -rette[2][1]/rette[2][0], c[1] = 1.0,
c[2] = -0.5*lati[2]*(c[0]*cos(angoli[1])+sin(angoli[1]));}
return c;}
/* calcolo dei coefficienti dell’equazione della
retta che porta la mediana relativa al lato numero a */
double * rettaMediana(int a)
{double * c = new double[3];
switch(a)
{case 0:
if(vertici[2][0] == 0.5*lati[0]) c[0] = 1.0, c[1] = 0.0, c[2] = -vertici[2][0];
else
c[0] = 1.0/(0.5*lati[0] - vertici[2][0]), c[1] = 1.0/vertici[2][1],
c[2] = -1.0 - vertici[2][0]/(0.5*lati[0] - vertici[2][0]);
break;
case 1:
c[2] = 0.0;
if(vertici[2][0] == -lati[0]) c[0] = 1.0, c[1] = 0.0;
else
c[0] = 2.0/(vertici[2][0]+lati[0]), c[1] = -2.0/vertici[2][1];
break;
case 2:
if(vertici[2][0] == 2.0*lati[0]) c[0] = 1.0, c[1] = 0.0, c[2] = -lati[0];
else
c[0] = 1.0/(0.5*vertici[2][0]-lati[0]), c[1] = -2.0/vertici[2][1],
c[2] = -lati[0]/(0.5*vertici[2][0]-lati[0]);}
return c;}
/* attribuzione delle coordinate ai vertici del triangolo: il
primo vertice sta nell’origine, il secondo lungo l’asse
orizzontale, il terzo di conseguenza...; sono anche determinate
le equazioni delle rette che portano i tre lati.*/
void calcolaVertici()
{vertici[0][0] = vertici[0][1] = 0.0,
vertici[1][0] = lati[0], vertici[1][1] = 0.0,
vertici[2][0] = lati[2] * cos(angoli[1]), vertici[2][1] = lati[2] * sin(angoli[1]),
rette[0][0] = rette[0][2] = 0.0, rette[0][1] = 1.0,
rette[1][0] = (vertici[2][0] != vertici[1][0]) ?
1.0 /(vertici[2][0] - vertici[1][0]) : 1.0,
rette[1][1] = (vertici[2][0] != vertici[1][0]) ?
-1.0 /(vertici[2][1] - vertici[1][1]) : 0.0,
rette[1][2] = rette[1][0] == 1.0 ? 0.0 :
vertici[1][1] / (vertici[2][1] - vertici[1][1]) vertici[1][0] / (vertici[2][0] - vertici[1][0]);
rette[2][0] = (vertici[2][0] != vertici[0][0]) ?
1.0 /(vertici[2][0] - vertici[0][0]) : 1.0,
rette[2][1] = (vertici[2][0] != vertici[0][0]) ?
-1.0 /(vertici[2][1] - vertici[0][1]) : 0.0,
rette[2][2] = rette[2][0] == 1.0 ? 0.0 :
vertici[0][1] / (vertici[2][1] - vertici[0][1]) vertici[0][0] / (vertici[2][0] - vertici[0][0]);}
static
static
static
static
char *
double
enum regolarita {equilatero, isoscele, scaleno}regolarita;
enum forma {Equilatero, acutangolo, rettangolo, ottusangolo}forma;
const char * descrizioni regolarita[];
const char * descrizioni forma[];
caratteristiche[2], i[3];
lati[3], angoli[3], vertici[3][2], centri[4][2], rette[3][3];
/* "amicizia" con l’operatore << */
friend ostream & operator << (ostream &, Triangolo);
/* un metodo per la creazione di un
triangolo equilatero */
void faiEquilatero(double l)
{lati[0] = lati[1] = lati[2] = l,
angoli[0] = angoli[1] = angoli[2] = M PI/3.0,
regolarita = equilatero, forma = Equilatero,
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* un metodo che calcola tutti i centri di un triangolo */
void calcolaCentri()
{double *xy, *r, *s;
xy = incrociaRette(r = rettaAltezza(0), s = rettaAltezza(1)),
centri[ORTHO][0] = xy[0], centri[ORTHO][1] = xy[1],
delete[] r, delete[] s, delete [] xy,
xy = incrociaRette(r = rettaMediana(0), s = rettaMediana(1)),
centri[BARIC][0] = xy[0], centri[BARIC][1] = xy[1],
delete[] r, delete[] s, delete [] xy,
xy = incrociaRette(r = rettaAsse(0), s = rettaAsse(1)),
centri[CIRCO][0] = xy[0], centri[CIRCO][1] = xy[1],
delete[] r, delete[] s, delete [] xy,
xy = incrociaRette(r = rettaBisettrice(0), s = rettaBisettrice(1)),
centri[INCEN][0] = xy[0], centri[INCEN][1] = xy[1],
delete[] r, delete[] s, delete [] xy;}
/* un metodo che "riconosce" la forma di un triangolo */
void determinaForma()
{if(fabs(2.0*angoli[i[0]]-M PI) < 1.e-9) forma = rettangolo;
else if(2.0*angoli[i[0]] > M PI) forma = ottusangolo;
else if(regolarita != equilatero) forma = acutangolo;
else forma = Equilatero;}
public:
/* metodi PUBBLICI (significato ovvio)*/
bool malRiuscito() {return !fatto;}
double * Lati() {return lati;}
double Lati(int i) {return lati[i];}
double * Angoli() {return angoli;}
double Angoli(int i) {return angoli[i];}
double Perimetro() {return lati[0]+lati[1]+lati[2];}
double Area()
{double p = Perimetro();
return 0.25*sqrt(p*(p-2.0*lati[0])*(p-2.0*lati[1])*(p-2.0*lati[2]));}
/* costruttore default: costruisce un triangolo equilatero di lato 1 */
Triangolo() {faiEquilatero(1.0), fatto = true;}
/* costruttore parametrico num. 1:
costruisce un triangolo equilatero di lato l */
Triangolo(double l) {faiEquilatero(l), fatto = true;}
/* costruttore parametrico num. 2: costruisce un
triangolo (se possibile) assegnati i tre lati */
Triangolo(double l[])
{fatto = testCongruenzaLati(l, 3);
if(!fatto) {cerr << "questi lati: " << l[0] << ", " << l[1] << ", "
<< l[2] << " non possono formare un triangolo\n"; return;}
lati[0] = l[0], lati[1] = l[1], lati[2] = l[2], ordinaLati(),
angoli[i[0]] = acos((l[i[1]]*l[i[1]]+l[i[2]]*l[i[2]]
-l[i[0]]*l[i[0]])/(2.0*l[i[1]]*l[i[2]]));
determinaForma(),
angoli[i[1]] = asin(sin(angoli[i[0]])*l[i[1]]/l[i[0]]),
angoli[i[2]] = asin(sin(angoli[i[0]])*l[i[2]]/l[i[0]]),
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* costruttore parametrico num. 3: costruisce un triangolo
assegnati due lati e l’angolo compreso (sempre possibile...
salvo patologie) */
Triangolo(double l[], double a)
{fatto = testCongruenzaLati(l, 2);
if(!fatto) {cerr << "questi lati: " << l[0] << ", " << l[1]
<< " non possono formare un triangolo\n"; return;}
if(!(fatto && a > 0.0 && a < M PI))
{fatto = false; cerr << "quest’angolo: " << a
<< " non può stare in un triangolo\n"; return;}
lati[0] = l[0], lati[1] = l[1],
lati[2] = sqrt(l[0]*l[0]+l[1]*l[1]-2.0*l[0]*l[1]*cos(a)),
ordinaLati(),
angoli[2] = a,
angoli[0] = asin(sin(angoli[2])*lati[0]/lati[2]),
angoli[1] = asin(sin(angoli[2])*lati[1]/lati[2]),
determinaForma(),
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* costruttore parametrico num. 4: costruisce un triangolo
assegnato un lato e i due angoli adiacenti */
Triangolo(double l, double a[])
{fatto = a[0] > 0.0 && a[1] > 0.0 && a[0] + a[1] < M PI;
if(!fatto)
{cout<<
"\n...\n\" O cara piota mia che sı̀ t’insusi\n\
che, come veggion le terrene menti\n\
non càpere in trı̈angol due ottusi,\n\n\
cosı̀ vedi le cose contingenti\n\
anzi che sieno in sé, mirando il punto\n\
a cui tutti li tempi son presenti\n...\"\n"; return;}
if(!(fatto && l > 0)) {fatto = false; cerr << "questo lato: " << l
<< " non può appartenere a un triangolo\n"; return;}
angoli[1] = a[0], angoli[2] = a[1], angoli[0] = M PI - a[0] - a[1],
lati[0] = l,
lati[1] = l * sin(angoli[1]) / sin(angoli[0]),
lati[2] = l * sin(angoli[2]) / sin(angoli[0]),
ordinaLati(),
determinaForma(),
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* costruttore parametrico num. 5: costruisce un triangolo
assegnati due lati, un angolo e un criterio di scelta
nel caso esistano due triangoli compatibili (triangolo
NON rettangolo) */
Triangolo(double l[], double a, char c)
{fatto = a > 0.0 && a < M PI && l[0] > 0. && l[1] >= l[0] * sin(a);
if(!fatto) {cerr << "la configurazione fornita (lati: " << l[0] <<", " << l[1]
<< "); angolo = " << a << " non può sussistere\n"; return;}
angoli[2] = a;
if(l[1] == l[0] * sin(a)) angoli[1] = 0.5*M PI, forma = rettangolo;
else
{angoli[1] = asin(sin(a)*l[0]/l[1]), forma = acutangolo;
if(c == ’O’) forma = ottusangolo, angoli[1] = M PI - angoli[1];}
angoli[0] = M PI - angoli[1] - angoli[2],
lati[1] = l[0], lati[2] = l[1], lati[0] = lati[1] * sin(angoli[0]) / sin(angoli[1]),
ordinaLati(),
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* costruttore parametrico num. 6: costruisce un triangolo
assegnati i tre angoli e un criterio di scelta tra gli
infiniti triangoli della data forma */
Triangolo(double a[], char c)
{double p = 1.0;
fatto = a[0] > 0.0 && a[1] > 0.0 && a[2] > 0.0 && fabs(a[0]+a[1]+a[2] - M PI) < 1.e-12;
if(!fatto)
{cerr << "gli angoli assegnati: " << a[0] << ’ ’ << a[1] << ’ ’ << a[2]
<< " (la cui somma vale " << a[0]+a[1]+a[2]
<<") non possono appartenere a un triangolo\n";
return;}
angoli[0] = a[0], angoli[1] = a[1], angoli[2] = a[2],
determinaForma(),
lati[0] = 1.0,
lati[1] = sin(angoli[1])/sin(angoli[0]), lati[2] = sin(angoli[2])/sin(angoli[0]),
ordinaLati();
switch(c)
{case PERIMETRO UNITARIO:
p = Perimetro(), lati[0] /= p, lati[1] /= p, lati[2] /= p;
break;
case AREA UNITARIA:
p = sqrt(Area()), lati[0] /= p, lati[1] /= p, lati[2] /= p;}
caratteristiche[0] = const cast<char *>(descrizioni regolarita[regolarita]),
caratteristiche[1] = const cast<char *>(descrizioni forma[forma]),
calcolaVertici(), calcolaCentri();}
/* overload dell’operator []: restituisce uno dei centri
di un triangolo, secondo il valore trasferito come
argomento e dichiarato in direttive define */
double * operator[](char c)
{double * r;
switch(c)
{case ORTHO: case BARIC: case CIRCO: case INCEN:
r = centri[c];
break;
default: r = 0;}
return r;}};
/* FINE DELLA CLASSE PER I TRIANGOLI */
/* variabili statiche */
enum Triangolo :: regolarita Triangolo :: regolarita;
enum Triangolo :: forma Triangolo :: forma;
const char * Triangolo :: descrizioni regolarita[] =
{" equilatero ", " isoscele ", " scaleno "};
const char * Triangolo :: descrizioni forma[] =
{" ", " acutangolo ", " rettangolo ", " ottusangolo "};
/* friend operator di output: modificabile a piacimento */
ostream & operator << (ostream & stream, Triangolo t)
{
int ** gradi minuti secondi = converti(t.angoli);
char l;
stream << setiosflags(ios::fixed) << setprecision(3)
<< "informazioni relative a un triangolo" << t.caratteristiche[0] << ’\b’
<< t.caratteristiche[1] << "\b:\n";
switch(t.regolarita)
{case Triangolo :: equilatero:
stream << "lato = " << t.lati[0]<<endl,
stream << "angolo = 60 0 0\n";
break;
case Triangolo :: isoscele:
switch(t.forma)
{
case Triangolo :: ottusangolo:
case Triangolo :: acutangolo:
l = 2 * (t.forma == Triangolo :: acutangolo),
stream << "base = " << t.lati[t.i[l]] << endl,
stream << "lato obliquo = " << t.lati[t.i[2-l]] << endl,
stream << "angolo al vertice = " << gradi minuti secondi[t.i[l]][0] << ’ ’
<< gradi minuti secondi[t.i[l]][1] << ’ ’ << gradi minuti secondi[t.i[l]][2]<< endl,
stream << "angolo alla base = " << gradi minuti secondi[t.i[2-l]][0] << ’ ’
<< gradi minuti secondi[t.i[2-l]][1] << ’ ’ << gradi minuti secondi[t.i[2-l]][2]<< endl;
break;
case Triangolo :: rettangolo:
stream << "ipotenusa = " << t.lati[t.i[0]] << endl,
stream << "cateto = " << t.lati[t.i[1]] << endl,
stream << "angolo acuto = 45 0 0\n";}
break;
case Triangolo :: scaleno:
switch(t.forma)
{
case Triangolo :: ottusangolo:
case Triangolo :: acutangolo:
stream << "lati: " << t.lati[0] << ’ ’ << t.lati[1] << ’ ’ << t.lati[2] << endl,
stream << "angoli:"
<< gradi minuti secondi[t.i[0]][0] << ’ ’
<< gradi minuti secondi[t.i[0]][1] << ’ ’
<< gradi minuti secondi[t.i[0]][2] << "; "
<< gradi minuti secondi[t.i[1]][0] << ’ ’
<< gradi minuti secondi[t.i[1]][1] << ’ ’
<< gradi minuti secondi[t.i[1]][2] << "; "
<< gradi minuti secondi[t.i[2]][0] << ’ ’
<< gradi minuti secondi[t.i[2]][1] << ’ ’
<< gradi minuti secondi[t.i[2]][2] << ’\n’;
break;
case Triangolo :: rettangolo:
stream << "ipotenusa = " << t.lati[t.i[0]] << endl,
stream << "cateti: " << t.lati[t.i[1]] << ’ ’ << t.lati[t.i[2]] << endl,
stream << "angoli acuti:"
<< gradi minuti secondi[t.i[1]][0] << ’ ’
<< gradi minuti secondi[t.i[1]][1] << ’ ’
<< gradi minuti secondi[t.i[1]][2] << "; "
<< gradi minuti secondi[t.i[2]][0] << ’ ’
<< gradi minuti secondi[t.i[2]][1] << ’ ’
<< gradi minuti secondi[t.i[2]][2] << ’\n’;}}
stream << "il perimetro del triangolo vale " << t.Perimetro()<<"\ne l’area vale "
<< t.Area() << endl;
return stream;}