/**
    C++ Mise en oeuvre pour Windows
    Brice-Arnaud Guérin
    Propos de l'exemple : Synthèse du GDI : tracé de fractales en 3D
    Notions clés : GDI
 */
// FractaleView.cpp : implementation of the CFractaleView class
//

#include "stdafx.h"
#include "Fractale.h"

#include <math.h>
#include "complexe.h"

#include "FractaleDoc.h"
#include "FractaleView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CFractaleView

IMPLEMENT_DYNCREATE(CFractaleView, CView)

BEGIN_MESSAGE_MAP(CFractaleView, CView)
	//{{AFX_MSG_MAP(CFractaleView)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFractaleView construction/destruction

CFractaleView::CFractaleView()
{
	// TODO: add construction code here

}

CFractaleView::~CFractaleView()
{
}

BOOL CFractaleView::PreCreateWindow(CREATESTRUCT& cs)
{
	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CFractaleView drawing
void CFractaleView::OnDraw(CDC* pDC)
{
	
	// associer la palette au DC
	CPalette* pOldPal;		// ancienne
	pOldPal = pDC->SelectPalette(&m_Palette, true);
	pDC->RealizePalette() ;

	// MX et MY déterminent la qualité de l'image
	int MX,MY;
	MX = 1500;
	MY = 1500;

	// dimensionner l'écran
	RECT rc;
	GetClientRect(&rc);

	// changer de repère et de système de coordonnées
	if(!pDC->IsPrinting()) {
		// dessiner une image de fond
		CBrush brosse;
		CBitmap image;
		image.LoadBitmap(IDB_IMAGE);
		brosse.CreatePatternBrush(&image);
		pDC->FillRect(&rc,&brosse);

		pDC->SetMapMode(MM_ISOTROPIC);
		pDC->SetViewportExt(rc.right,-rc.bottom);	// rapport de coordonnées
		pDC->SetViewportOrg(rc.right/2,rc.bottom/2);// fixer l'origine
	}
	pDC->SetWindowExt(2*MX,2*MY);				// plan de 1000² points

	CRect zone_invalide;	// zone à rafraîchir
	CPoint test;		// un point
	pDC->GetClipBox(&zone_invalide);
	zone_invalide.NormalizeRect();

	// créer une police
	police=new CFont;
	police->CreatePointFont(14*10,"Arial",pDC);
	pDC->SelectObject(police);

	CRect pos;
	CSize ttexte;
	char msg[500];
	sprintf(msg,"Graphique vu en 3D, %dx%d points",MX,MY);
	ttexte=pDC->GetTextExtent(msg);

	pos.left=-(ttexte.cx)/2;
	pos.right=pos.left+ttexte.cx;

	pos.top=-MX*0.75;
	pos.bottom=-MX;

	if(!pDC->IsPrinting())
	{
		pDC->SetBkMode(TRANSPARENT);

		pDC->SetTextColor(RGB(248,172,122));
		pDC->DrawText(msg,&pos,0);

		int dec = 15;
		pos.left += dec;
		pos.top -= dec;
		pos.right += dec;

		pDC->SetTextColor(RGB(250,234,96));
		pDC->DrawText(msg,&pos,0);
	} else {
		pDC->SetTextColor(RGB(0,0,0));
		pDC->DrawText(msg,&pos,0);
	}




	// -----------------------------------------------------
	// vue en 3D
	double a1,a2,a3,b1,b2,b3;	// coefficients de projection 3D
	double l,L;					// lattitude et longitude

	// point de vue
	l = 1.1;
	L = 1.20;

	l = ((CFractaleDoc*)GetDocument())->m_l;
	L = ((CFractaleDoc*)GetDocument())->m_L;

	// ces coofficients sont calculés pour une projection orthogonale
	a1 = -sin(L);
	a2 = cos(L);
	a3 = 0;
	b1 = -sin(l)*cos(L);
	b2 = -sin(l)*cos(L);
	b3 = cos(l);

	// -----------------------------------------------------
	// tracé d'une figure mathématique en 3D	
	int i,j;	// coordonnées dans l'espace logique
	int n;		// nombre d'itération
	int X,Y;	// coordonnées projetées (X,Y)=proj(x,y,z)
	
	double cote,x,y; // coordonnées mathématiques	
	int coul;		// couleur des points

	for(i=-MX;i<MX;i+=80)
		for(j=-MY;j<MY;j++)
		{								
		
			x = (double)i/MX*2;
			y = (double)j/MY*2;
			cote = 100 * sin(x)*sin(y)*exp(x*x - x*y +y*y);
			
			coul = 1000 + cote;

			if(coul>4000)
				coul = 1500;

			if(coul<0)
				coul = 800;

			// projection sur un plan
			X= a1*i + a2*j + a3*cote;
			Y= b1*i + b2*j + b3*cote;

			// test d'impact
			test.x=X;
			test.y=Y;

			if(PtInRect(&zone_invalide,test)) // le point est-il invalide ?
				pDC->SetPixel(test,PALETTEINDEX(coul)); // 40*100=4000
			
		}

	for(i=-MX;i<MX;i++)
		for(j=-MY;j<MY;j+=80)
		{								
		
			x = (double)i/MX*2;
			y = (double)j/MY*2;
			cote = 100 * sin(x)*sin(y)*exp(x*x - x*y +y*y);
			
			coul = 1000 + cote;

			if(coul>4000)
				coul = 1500;

			if(coul<0)
				coul = 800;

			// projection sur un plan
			X= a1*i + a2*j + a3*cote;
			Y= b1*i + b2*j + b3*cote;

			// test d'impact
			test.x=X;
			test.y=Y;

			if(PtInRect(&zone_invalide,test)) // le point est-il invalide ?
				pDC->SetPixel(test,PALETTEINDEX(coul)); // 40*100=4000
			
		}
	// ----------------------------------------------------------------
	// libérer GDI
	pDC->SelectPalette( pOldPal,true ) ;
	m_Palette.DeleteObject() ;
	pDC->SelectStockObject(ANSI_VAR_FONT);
	delete police;

}

/////////////////////////////////////////////////////////////////////////////
// CFractaleView printing

BOOL CFractaleView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CFractaleView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CFractaleView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CFractaleView diagnostics

#ifdef _DEBUG
void CFractaleView::AssertValid() const
{
	CView::AssertValid();
}

void CFractaleView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CFractaleDoc* CFractaleView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFractaleDoc)));
	return (CFractaleDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFractaleView message handlers

void CFractaleView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
	pDC->SetMapMode(MM_LOMETRIC);

	pDC->SetViewportExt(pInfo->m_rectDraw.right,-pInfo->m_rectDraw.bottom);	// rapport de coordonnées
	pDC->SetViewportOrg(pInfo->m_rectDraw.right/2,pInfo->m_rectDraw.bottom/2);// fixer l'origine

	CView::OnPrint(pDC, pInfo);
}

void CFractaleView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	
	// préparer une palette personnalisée
	nColors=4000;		// nombre de couleurs représentées dans la palette

	// réserver la mémoire pour exprimer la palette
	m_pPalette = (LOGPALETTE*)new char[sizeof(LOGPALETTE) +
		sizeof(PALETTEENTRY)*nColors];

	// définir les nuances de la palette
	m_pPalette->palVersion = 0x300;
	m_pPalette->palNumEntries = nColors ;

	for( int co=0 ; co<192 ; co++) {
		m_pPalette->palPalEntry[co].peRed = 0;
		m_pPalette->palPalEntry[co].peBlue = co;
		m_pPalette->palPalEntry[co].peGreen = co >> 4;
		m_pPalette->palPalEntry[co].peFlags = 0;
	}

	for( int co = 192 ; co<256 ; co++) {
		m_pPalette->palPalEntry[co].peRed = 0;
		m_pPalette->palPalEntry[co].peBlue = co;
		m_pPalette->palPalEntry[co].peGreen = co;
		m_pPalette->palPalEntry[co].peFlags = 0;
	}

	for( int co = 256 ; co<nColors ; co++) {
		m_pPalette->palPalEntry[co].peRed = co >> 3;
		m_pPalette->palPalEntry[co].peBlue = co >> 4;
		m_pPalette->palPalEntry[co].peGreen = co >> 2;
		m_pPalette->palPalEntry[co].peFlags = 0;
	}

	// créer la palette dans GDI
	m_Palette.CreatePalette( m_pPalette ) ;
	m_Palette.SetPaletteEntries( 0, nColors,
					(PALETTEENTRY*)&m_pPalette->palPalEntry ) ;

	CView::OnPrepareDC(pDC, pInfo);
}
