// questo e' un programma-C in stile simil-C++, ovvero con una logica vicina
// a quella che si utilizza in C++ con gli oggetti, i costruttori, metodi etc
// mi hai chiesto la versione C, quindi non ho utilizzato classi. Spero tuttavia
// che renda l'idea di "come" si ragiona.
// Nelle more segnalo che il funzionamento dal punto di vista matematico non e'
// certo (non ho provato tutte le possibilita')!
// Spesso non ho usato forme "furbe" che sarebbero state troppo a scapito della
// leggiblita'
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
double eps=0.0001; // definiamo un concetto approssimato di "zero"
// la struttura (=miniclasse) punto modella un punto reale. Il flag valido
// serve come flag nei casi in cui NON rappresenti un punto reale
struct punto
{
double x;
double y;
int valido; // se non vero il punto ha coordinate non reali
};
// la retta viene caratterizzata da due punti (anche se in verita' dal punto di vista
// "serio" e' sbagliato, la retta ha solo tre parametri a,b,c (ax+by+c=0)
// e quindi non ha senso metterci dentro "due" punti. Bisognerebbe lasciarli fuori
// ed, eventualmente, "ricrearli" alla bisogna. Questo, dal punto di vista C++, e' un
// errore GRAVE. Dal punto di vista-C... puoi fare come vuoi, e questo e' un programma
// C
struct retta
{
punto punto1; // mmmhhh...
punto punto2;
double delta_x;
double delta_y;
double m; // memorizzazione in formato cartesiano
double q;
int Verticale; // attenzione questo flag implica b=0!
int Orizzontale;
};
// questo e' una sorta di... costruttore C++ in C.
// la strategia e'... quick-and-dirty. In C++ sarebbe ben diversa, col costruttore
// di default, quello di copia, etc.etc. Inoltre uso un puntatore alla retta, mentre
// in C++ avrei usato un riferimento. Cmq...
void costruttoreRetta(retta* miaRetta, double x1,double y1,double x2,double y2)
{
(*miaRetta).punto1.x=x1;
(*miaRetta).punto2.x=x2;
(*miaRetta).punto1.y=y1;
(*miaRetta).punto2.y=y1;
(*miaRetta).m=0; // ridondante, messo per "buona abitudine2
(*miaRetta).q=0; // ridondante
(*miaRetta).delta_x=x2-x1;
(*miaRetta).delta_y=y2-y1;
(*miaRetta).Orizzontale = int ( fabs((*miaRetta).delta_y)<eps);
(*miaRetta).Verticale = int ( fabs((*miaRetta).delta_x)<eps);
if ((*miaRetta).Verticale)
{
(*miaRetta).q=x1; //la retta e' verticale
(*miaRetta).m=0;
}
else
if ((*miaRetta).Orizzontale)
{
(*miaRetta).q=y1; // la retta e' orizzontale (mi basterebbe sapere m=0
(*miaRetta).m=0; // quindi e' ridondante, solo per comodita'
}
else
{ // retta "normale". A questo punto si vede bene
// che potrei togliere punto1 e punto2 dalla struct
// pero' li tengo lo stesso
(*miaRetta).m=(*miaRetta).delta_y/(*miaRetta).delta_x;
(*miaRetta).q=y1-(*miaRetta).m*x1;
}
}
// questo e' un simil-metodo C++ che converte una retta in una stringa, discriminando
// i 3 casi diversi. Bisognerebbe aggiungervi dei controlli sul bufferOutput (e' null?)
// sull'inizializzazione di miaRetta etc.etc...
void trascriviRetta(retta miaRetta,char* bufferOutput)
{
if (miaRetta.Verticale)
sprintf(bufferOutput,"x=%+10.4f",miaRetta.q);
else
if (miaRetta.Orizzontale)
sprintf(bufferOutput,"y=%+10.4f",miaRetta.q);
else
sprintf(bufferOutput,"y=%+10.4fx %+10.4f",miaRetta.m,miaRetta.q);
}
// questa funzioncina verifica la condizione per le due rette. Nel caso C++
// avresti un unico parametro, l'altro implicito (this)
// anche qui, per facilita' di lettura, le condizioni sono tutte esplicitate
int perpendicolareA(retta retta1,retta retta2)
{
if ((retta1.Verticale && retta2.Orizzontale))
return 1;
else
if
(retta1.Orizzontale && retta1.Verticale)
return 1;
else
return int ( fabs(retta1.m- (-1.0/retta2.m))<eps);
}
// come sopra per la condizione di ||->tra l'altro serve per verificare se
// esiste una intersezione
int parallelaA(retta retta1,retta retta2)
{
if ((retta1.Verticale && retta2.Orizzontale))
return 0;
else
if
(retta1.Orizzontale && retta1.Verticale)
return 0;
else
return int (fabs(retta1.m-retta2.m)<eps);
}
// questa funzioncina calcola il punto (o almeno... spero! e' passata una
// vita da analisi I !!!) di intersezione.
// Verifica, prima, che questo esista.
punto calcolaIntersezione(retta retta1, retta retta2)
{
punto incontro;
incontro.valido=1; // per default il punto e' reale [qui ci vorrebbe il costruttore di default]
// e' superfluo ma meglio metterlo
if (parallelaA(retta1,retta2))
{
incontro.valido=0; // parallele -> no incontro
}
else
{
if (retta1.Verticale)
{
incontro.x=retta1.punto1.x;
incontro.y=retta2.m*incontro.x+retta2.q;
incontro.valido=1;
}
else
if (retta2.Verticale)
{
incontro.x=retta2.punto1.x;
incontro.y=retta1.m*incontro.x+retta1.q;
incontro.valido=0;
}
else
{
incontro.x=(retta1.q-retta2.q)/(retta2.m-retta1.m);
incontro.y=retta2.m*incontro.x+retta2.q;
incontro.valido=1;
}
}
return incontro;
}
// minimetodo di trascizione punto, anche qui senza controlli
void trascriviPunto(punto mioPunto,char* bufferOutput)
{
if (mioPunto.valido)
sprintf(bufferOutput,"x=%+10.4fx y=%+10.4f",mioPunto.x,mioPunto.y);
else
sprintf(bufferOutput,"PUNTO NON REALE");
}
// questo e' il main di un programma tipoco da console
// che ritorna un intero. come gia' detto argc e argv sono i parametri
// a riga di comando
int main(int argc, char *argv[])
{
double x1_1,y1_1, x2_1,y2_1;
double x1_2,y1_2, x2_2,y2_2;
// commento questa parte altrimenti si fatica a fare le prove!
/*
printf("PUNTI SULLA PRIMA RETTA\n\n\n");
printf("Inserire la x del primo punto: x1_1 ");
scanf("%deltay_2",&x1_1);
printf("Inserire la y del primo punto: y1_1 ");
scanf("%deltay_2",&y1_1);
printf("Inserire la x del secondo punto: x2_1 ");
scanf("%deltay_2",&x2_1);
printf("Inserire la y del secondo punto: y2_1 ");
scanf("%deltay_2",&y2_1);
system("cls");
printf("PUNTI SULLA SECONDA RETTA\n\n\n");
printf("Inserire la x del primo punto: (x1_2) ");
scanf("%deltay_2",&x1_2);
printf("Inserire la y del primo punto: (y1_2) ");
scanf("%deltay_2",&y1_2);
printf("Inserire la x del secondo punto: (x2_2) ");
scanf("%deltay_2",&x2_2);
printf("Inserire la y del secondo punto: (y2_2) ");
scanf("%deltay_2",&y2_2);
*/
x1_1=1; //1
y1_1=3; //3
x2_1=6; //6
y2_1=5; //5
x1_2=2; //2
y1_2=5; //5
x2_2=6; //6
y2_2=4; //4
retta retta1;
retta retta2;
int flagParallele; // logica falso (0), vero (altrimenti)
int flagPerpendicolari;
char stringaRetta[100]; // conversione in stringa di una retta
char stringaPunto[100]; // conversione in stringa di un punto
// creo le due rette in modo "simil-C++"
costruttoreRetta(&retta1,x1_1,y1_1,x2_1,y2_1);
costruttoreRetta(&retta2,x1_2,y2_2,x2_2,y2_2);
system("cls");
// stampo qualche informazione
printf("retta1 verticale %d\n",retta1.Verticale);
printf("retta2 verticale %d\n",retta1.Verticale);
printf("retta1 orizzonta %d\n",retta1.Orizzontale);
printf("retta2 orizzonta %d\n",retta1.Orizzontale);
// ed ora converto le rette nella rappresentazione a stringa
// (C++: incapsulamento, isolamento. In verita' avrei dovuto
// fare l'overload di un operatore (tipo <<) per scrivere su stream
// tipo cout. Ma questo e' un programma C!!!
trascriviRetta(retta1,stringaRetta);
printf("Equazione retta 1: %s\n",stringaRetta);
trascriviRetta(retta2,stringaRetta);
printf("Equazione retta 2: %s\n",stringaRetta);
flagPerpendicolari =perpendicolareA(retta1,retta2);
flagParallele =parallelaA(retta1,retta2);
printf("\n");
// calcolo il punto d'incontro. Se non esiste incontro.valido non e' "vero"
punto incontro;
incontro=calcolaIntersezione(retta1,retta2);
trascriviPunto(incontro,stringaPunto);
if (flagPerpendicolari)
printf("Sono perpendicolari\n");
else
printf("Non sono perpendicolari\n");
if (flagParallele)
printf("Sono parallele (nessun punto di incontro)\n");
else
{
printf("NON sono parallele\n");
printf("\n\n");
printf("punto di incontro %s\n",stringaPunto);
}
system("pause");
return EXIT_SUCCESS;
}