/* Programa    ap02_01.cc  -  versão final
   Assunto:		Determinação de raizes de uma função multivariada
   
	Condicionantes:
	Programa sem erros
	Os resultados deste programa foram bons em vários testes.
	
	compilar com
		g++ -Wall -oprog -lm ap02_01.c
         
	Descricao:	Varre um retângulo com uma malha dada 
		procurando quando f troca 	de sinal, ao encontrar uma
		troca de sinal calcula o ponto médio da diagonal do
		sub-retângulo como solução aproximada da equação.

int	rotulo(); // descreve o programa para o usuário
int	final();  // se despede com copyleft

==================
Quatro tipos de dados, (quatro  membros quando isto virar C++)
ponto			P = (x, x) = (float, float)
malha:		 (P,Q, delta) = (ponto, ponto, float)

resultado:  (P,teste) = (ponto, int)
	o ponto médio dos vértices-solução e um inteiro que pode ser 0,1 indicando que encontrou
	ou não uma solução. Se não encontrar devolve (0, 0) ou devolve
	(P,1)
retangulo:  (P,Q) = (ponto, ponto) 
	um retângulo determinado pela diagonal - área pode ser zero...
================================

futuros métodos:

//float	df1(float	x, float y); // derivadas parciais
//float	df2(float	x, float y); 
//float	precisao_desigualdade(float delta, float	epsilon);
//float	plano(float	A, float B ); // equação do plano tangente


float	f(float	x, float y); //  A função cujas raízes serão procuradas

      
		    
	Palavras-chave:	troca de sinal, raiz, plano tangente             
	por Tarcisio Praciano Pereira - 10 lições  para aprender C++
	Sobral, Abril de 2008   - UeVA
*/
                  
// sem uso
//float	df1(float	x, float y); // derivadas parciais
//float	df2(float	x, float y); 
//float	plano(float	A, float B ); // equação do plano tangente
// float	precisao_desigualdade(float delta, float	epsilon);
// void	zero(float x1, float y1);

# include <iostream>
# include "/home/tarcisio/tex/c/cplus/Ambiente.h" // Biblioteca particular: comunicacao com usuário
# include <math.h>
using namespace std;

Ambiente Tela;  // Uma instância de Ambiente - herda seus métodos


typedef	struct	{float x; float	y;} ponto;
typedef	struct	{ponto	P; ponto	Q;} retangulo;// determ. p/ diagonal PQ
typedef	struct	{ponto	P; int	teste;} resultado;  // (P,1) ou (0,0)
typedef 	struct 	{ponto P; ponto Q;  float delta;} malha;


// informações ao usuário
void	rotulo();
void rotulo_raiz();
void rotulo_integral();
int	final();

// a função usada - usar um parser para definir esta função
float			f(float	x, float y); //  A função cujas raízes serão procuradas

// entradas de dados
malha			entra_dados(malha ret);   // recebe a malha: retângulo, passo
int			menu(int opcao);

// o cálculo da raíz
void	calculo_raiz(); // uma gerente, entrada de dados e chama busca_solucao()
resultado	busca_solucao(malha	qdo);
resultado	testa_troca_sinal(retangulo mini_ret); // (30)
void			laudo(resultado	resultado_final, float delta);
ponto			zero(retangulo	mini_ret);	// devolve ponto médio da diagonal do retângulo

// o cálculo da integral
void	calculo_integral(); // uma gerente, entrada de dados e chama integral()
float	integral(malha reticulado);


// saidas de dados
void	imprime_retangulo(retangulo ret);
void	imprime_malha(malha ret);


int	main()
{
	int	opcao=1;
	Tela.limpa_janela();	rotulo();
	opcao = menu(opcao);
	switch(opcao)
	{
		case	1:
		rotulo_raiz(); Tela.apeteco2();
		calculo_raiz();
		break;

		case	2:
		rotulo_integral(); Tela.apeteco2();
		calculo_integral();
		break;
	}		
	final();			// se despede
 	return(0);
}


int	menu(int	opcao)
{
	cout	<< "(1) - Cálculo de uma raiz aproximada da equação f(x,y) = c \n"
			<< "(2) - Cálculo aproximado da integral de z = f(x,y) sobre um retângulo\n";
	opcao = Tela.entrada_int("sua opção -->  < 1 , 2 > ", opcao);
	return(opcao);
}

// é uma gerente - recebe os dados e chama busca_solucao(reticulado)
void	calculo_raiz()
{
	ponto	P = {-3.0, -3.0}, Q ={ 3.0, 3.0}, P1 = {0.0,0.0}; // dados padrao 
	float delta = 0.01;
	malha	reticulado= {P, Q, delta}; // malha padrão
	resultado	resultado_final={P1, 0};// (10) (P,1)  ou (0,0) (ponto, int)
	//  fim inicialização das variáveis - inicio do processamento
	reticulado	= 	entra_dados(reticulado); // entrada de dados
	resultado_final = busca_solucao(reticulado); // (retangulo, int)
	laudo(resultado_final, delta);	//diz o que pôde  encontrar
}

// é uma gerente - recebe os dados e chama integral(reticulado)
void	calculo_integral()
{
	ponto	P = {-3.0, -3.0}, Q ={ 3.0, 3.0}; // dados padrão
	float delta = 0.01;
	malha	reticulado= {P, Q, delta}; // malha padrão
	//  fim inicialização das variáveis - inicio do processamento
	reticulado	= 	entra_dados(reticulado); // entrada de dados
	cout << " O valor aproximado da integral de f relativamente à malha \n";
	imprime_malha(reticulado);
	cout << " é " << integral(reticulado) << endl;
	Tela.apeteco2();
}


malha	entra_dados(malha ret)
{
	cout	<< "Recebendo os dados da malha em [a,b]x[c,d] com passo delta \n";
	ret.P.x = Tela.entrada_float("a = ", ret.P.x);
	ret.Q.x = Tela.entrada_float("b = ", ret.Q.x);	
	ret.P.y = Tela.entrada_float("c = ", ret.P.y);
	ret.Q.y = Tela.entrada_float("d = ", ret.Q.y);
	ret.delta = Tela.entrada_float(
		"passo da malha  (0.01 < delta < 0.5) delta = ", ret.delta);	
	//**********  fim   da   entrada de   dados  **************************
	cout << "=================================================" << endl
	    << "busca de raizes na malha  ";
	imprime_malha(ret);
	return(ret);  // [a,b] x [c,d], delta
}


// desnecessária ????  ou começe a usar.
void	imprime_retangulo(retangulo ret)
{
	cout << " [" << ret.P.x << "," << ret.Q.x << "] " << " x "
	     << " [" << ret.P.y << "," << ret.Q.y << "]" << endl;
}


void	imprime_malha(malha ret)
{
	cout  << " ["  << ret.P.x << "," << ret.Q.x << "] x " 
			<< " ["  << ret.P.y << "," << ret.Q.y  << "]" << endl
			<< "passo da malha = " << ret.delta;
}

// devolve (float, float, int) 
resultado	testa_troca_sinal(retangulo mini_ret)
{
	ponto			P={0.0, 0.0}; int teste=0;
	resultado	valor={P, teste}; // o padrão  é falso  (0,0,0)
	float x1= mini_ret.P.x, y1 = mini_ret.P.y; // (x1, y1)
	float x2= mini_ret.Q.x, y2 = mini_ret.Q.y; // (x2, y2)	
	// testa os quatro vértices do retângulo
	if ( f(x1,y1)*f(x2,y2) <= 0)
		{
			valor.P.x = (x1+x2)/2; valor.P.y = (y1+y2)/2; valor.teste = 1;
			return(valor); 
		}
		else 	if ( f(x1,y1)*f(x1,y2) <= 0)
		{
			valor.P.x = (x1+x1)/2; valor.P.y = (y1+y2)/2; valor.teste = 1;
			return(valor); 
		} 
		else 	if ( f(x1,y1)*f(x2,y1) <= 0)
			{
			valor.P.x = (x1+x2)/2; valor.P.y = (y1+y1)/2; valor.teste = 1;
			return(valor); 
			} 		
		else 	return(valor);	// devolve falso como última saída (0,0,0)
}


                       
// (60) selecione uma função
float	f(float	x, float y)
{
  return(x*x - 3*x*x*y + y*y*y -3);
}


void 	rotulo()
{
  cout  << "Este programa tem dois módulos e você vai agora fazer a escolha de qual dois\n"
   << "módulos lhe interessa rodar.\n"
   << "Um dos módulos calcula uma solução da equação f(x,y) = c que é uma condição\n"
   << "inicial da curva de nível. O projeto mais amplo em que se este programa está\n"
   << "inserido é a determinação de curvas de nível como uma poligonal usando esta\n"
   << "condição inicial, este módulo encontra esta condição inicial. Do ponto de\n"
   << "vista deste programa seu objetivo é encontrar uma solução da equação mencionada\n"
   << "acima, f(x,y) = c.\n"
   << "\n"
   << "O outro módulo deste programa calcula uma soma de Riemann num retângulo \n"
   << "cujo contorno você poderá fornecer assim como o passo da malha associada ao\n"
   << "retângulo. O passo da malha é a precisão no cálculo da integral.\n"
   << "O programa tem dados padrão que é interessante usar ao rodá-lo pela primeira vez,\n"
   << "para ver como o programa funciona.\n";
}


void 	rotulo_raiz()
{
   cout  << "Este módulo do programa varre um retângulo para determinar uma solução  \n" 
   		<< "aproximada da equação f(x,y) = c \n"
   		<< "Você poderá alterar a equação da função, os dados do retângulo \n"
   		<< "onde é feita a busca, e o passo da malha.\n"
   		<< "Por definição, a malha é um retângulo associado a um passo e o programa\n"
   		<< "define uma estrutura \n"
			<< " \t	[a,b] x [c,d], passo\n"
			<< "que se chama de malha. \n"
			<< "Quando o programa encontrar um troca de sinal entre os vẽrtice de um\n"
			<< "sub-retãngulo da malha ele seleciona o ponto médio do retângulo definido\n"
			<< "pelos dois pontos P, Q entre os quais foi detetectada a troca de sinal.\n"
			<< "Para isto programa verifica a troca de sinal entre o vêrtice inferior à  \n"
			<< "esquerda e os demais vértices (chamados Q) de cada retângulo da malha. \n"
			<< "O ponto médio encontrado é solução aproximada da equação.\n"
			<<  endl;
}


void rotulo_integral()
{
   cout  << "Este módulo do programa varre um retângulo para calcula uma soma   \n" 
   		<< "de Riemann como valor aproximad da integral de z = f(x,y)  \n"
   		<< "Você poderá alterar a equação da função, os dados do retângulo \n"
   		<< "onde é feita a busca, e o passo da malha.\n"
   		<< "Por definição, a malha é um retângulo associado a um passo e o programa\n"
   		<< "define uma estrutura \n"
			<< " 								[a,b] x [c,d], passo\n"
			<< "que se chama de malha. \n"
			<< "O passo é a aproximação com o programa vai calcular a soma de Riemann.\n"
			<<  endl;
}

 
 
int   final()
{
	 bool  resposta=0;
	 Tela.limpa_janela();
	 cout  << "A resposta padrão para esta pergunta é \"não\" bastando que\n"
	 << "você acione o <enter> \n"
	 << "Deseja ler a noticia sobre os direitos autorais ? <s,n> \n";
	 resposta = Tela.sim_nao();
	 if (resposta)
	 {
	 Tela.copyleft();  Tela.obrigado();  Tela.apetecof();Tela.limpa_janela();
	 }
	 else
	 {
	 Tela.obrigado();Tela.apetecof();Tela.limpa_janela();
	 }
	 return(0);
}

void	laudo(resultado	resultado_final, float delta)
{
	float	x=resultado_final.P.x, y = resultado_final.P.y;
	if (resultado_final.teste)
		{
			cout << "Encontrei 1 retângulo onde há raizes: \n" << endl
					<< " ["  << x << "," << x+delta 
					<< "] x [" << y << "," << y+delta << "]" << endl;
			cout	<< "O valor da função no ponto médio da diagonal deste retângulo é \n" 
					<< "f(" << x << "," << y << ") = " << f(x,y) << endl;		
					Tela.apeteco2();
		}
	else 
	// se teste for zero, nao encontrou raizes
	{
	printf("Nao encontrei raízes...mas isto não significa que \n");
	printf("nao as haja!  apenas eu não consegui encontrá-las !\n");
	printf("Rode, novamente, o programa, com passo mais fino...\n");
	printf("ou em  retângulo diferente. \n");
	}
}


// recebe diagonal P,Q delta 
// se encontrar apresenta e devolve (x,y,1) senão  (0,0,0) (float, float, int)

resultado busca_solucao(malha reticulado)
{
	ponto	P = {reticulado.P};
	ponto Q = {reticulado.Q};
	float delta = reticulado.delta;
	ponto X1 = {0.0, 0.0}; int teste;		//  resposta padrão - sem raizes
	resultado	resultado_final = {X1, teste}; // (10) (float, float, int)
	// x \in [ret.a, ret.b]  y \in [ret.c, ret.d]
	float	inicioX=P.x, 	finalX=Q.x;
	float inicioY=P.y, 	finalY=Q.y;
	float x = inicioX, y=inicioY;
	Tela.apeteco2(); // apagar
	// x percorre a malha na paralela a OX - loop externo
	while ( x <= finalX )	
	{
		y = inicioY; // reinicia y para percorrer a malha em paralela a OY
		while( y <= finalY )	   
		{
			
			ponto P1={x,y}, Q1 = {x+delta, y+delta};
			retangulo	mini_ret={P1, Q1}; // um retângulo da malha
			if ( testa_troca_sinal( mini_ret ).teste  )
			{
				
				resultado_final.P =  zero(mini_ret); // calcula o ponto médio
				teste++;
				resultado_final.teste = teste;
				cout << "(" <<  x << "," << y << ")" << endl; // apagar
				cout << "dentro do loop interno, no primeiro teste  "<< endl;  // apagar 
				Tela.apeteco2();
				break;
				//y = b2; // [a2,b2]
				//x = b1;     // termina! [a1,b1]
			}
			if ( fabsf( f(P1.x,P1.y)) <= 0.000001 ) // (20) se encontrar solução exata!
			{
				resultado_final.P = P1; 
				teste++;
				resultado_final.teste = teste; 
				break;				
			}
			y = y + delta;
		}
		if (teste) 		 break;
		x = x + delta;
	}
	return(resultado_final); // já começa com resultado_final inicializado....
}

float	integral(malha reticulado)
{
	ponto	P = {reticulado.P};
	ponto Q = {reticulado.Q};
	float delta = reticulado.delta;
	// x \in [ret.a, ret.b]  y \in [ret.c, ret.d]
	float	inicioX=P.x, 	finalX=Q.x;
	float inicioY=P.y, 	finalY=Q.y;
	float x = inicioX, y=inicioY;
	float	soma = 0;
	// x percorre a malha na paralela a OX - loop externo
	while ( x <= finalX )	
	{
		y = inicioY; // reinicia y para percorrer a malha em paralela a OY
		while( y <= finalY )	   
		{
			soma = soma+f(x,y);
			y = y + delta;
		}
		x = x + delta;
	}
	return(soma*delta*delta);
}


ponto	zero(retangulo	mini_ret)
{
	float	x=(mini_ret.P.x+mini_ret.Q.x)/2;
	float y=(mini_ret.P.y+mini_ret.Q.y)/2;
	ponto P={x,y};
	return(P);
}



// sem uso
/*  sem uso
void	zero(float x1, float y1)
{
  // z = c - A(x-x1) - B(y-y1) = f(x1,y1) - A(x-x1) - B(y-y1)
  float A=df1(x1,y1), B=df2(x1, y1),  c = f(x1,y1), a;
	// considerando y = y1
  if (A) { a = x1 + c/A;}
	  else 
	  if (B) { a = y1 + c/B;}  // else considerando x = x1
  cout << a  << endl
		 << " raiz aproximada controlando -->  " << endl;
		 if (A) 
		 {
		 		cout << "f(" << a << "," << y1 << ") = " << f(a,y1) << endl;
		 }
		 else
			cout << "f(" << x1 << "," << a << ") = " << f(x1,a) << endl;		 	
			
		 cout << " encerrando  " << endl;
}
 

float	df1(float	x, float y)
{
  return(2*x - 6*x*y);
}

float	df2(float	x, float y)
{
  return(- 3*x*x + 3*y*y);
}


// sem uso - deve escolher uma precisão para desigualdade

float	precisao_desigualdade(float delta, float	epsilon)
{
	if(delta > 1) { epsilon = 0.1;}
		else  { epsilon = 0.1*delta;}	
	x = a1; y = a2;
	return(epsilon);
}



(10) O resultado final é uma estrutura  (ponto , int)  se
		for encontrada uma solução (P,1)
		caso contrário  (0, 0), só interessa neste caso o inteiro

(20) usar um submúltiplo do passo da malha 

(30)	Devolve um retângulo, mesmo que seja um retângulo de área zero ...
		devolve a diagonal de um dos retângulos da malha 
		ou um dos lados, 
		onde se der a troca de sinal
		Um retângulo em um conjunto de pontos opostos pela diagonal....
			pode ser de área zero.
*/

