//Classe de bouton
class Hbouton
{
int width, height;// largeur et hauteur du bouton
int xpos, ypos; // positions du bouton
boolean over; // la souris est-elle sur le bouton ?
boolean locked; // le bouton est il ans l'état ON ?
String label;
color couleurOn=color(169,111,217);
color couleurOff=color(255,255,255);
Hbouton (int xp, int yp, int sw, int sh, String lb) {
width = sw;
height = sh;
xpos = xp;
ypos = yp;
label=lb;
over=false;
locked=false;
}
void draw() {
rectMode(CORNER);
if (over && !locked )
{
stroke(couleurOn);
fill(couleurOn);
rect(xpos, ypos, width, height);
fill(couleurOff);
text(label,xpos+width+10,ypos+height);
}
if (locked)
{
stroke(couleurOn);
fill(couleurOn);
rect(xpos, ypos, width, height);
text(label,xpos+width+10,ypos+height);
}
if(!over && !locked){
stroke(couleurOff);
fill(couleurOff);
rect(xpos, ypos, width, height);
text(label,xpos+width+10,ypos+height);
}
}
}
//Classe de curseur horizontal valeur réelle
class Hslider
{
int swidth, sheight; // largeur et hauteur du curseur
int xpos, ypos; // positions de l'extrémité gauche de la barre du curseur
int spos, newspos; // x position du curseur
float val,valMin,valMax,valPrec; //valeur associée à la position du curseur comprise entre valmin et valmax
boolean over; // is the mouse over the slider?
boolean locked;
String label;
Hslider (int xp, int yp, int sw, int sh, String lb, float vMin, float vMax) {
swidth = sw;
sheight = sh;
xpos = xp;
ypos = yp-sheight/2;
spos = xpos + swidth/2;
newspos = spos;
valMin = vMin;
valMax = vMax;
val = valMin + (spos-xpos)*(valMax-valMin)/swidth;
valPrec = val;
label=lb;
}
void update() {
if(over()) {
over = true;
} else {
over = false;
}
if(mousePressed && over) {
locked = true;
}
if(!mousePressed) {
locked = false;
}
if(locked) {
newspos = rampe(mouseX, xpos, xpos+swidth);
}
if(abs(newspos - spos) > 1) {
spos = spos + (newspos-spos)/2;
val = valMin + (spos-xpos)*(valMax-valMin)/swidth;
}
}
int rampe(int xx, int xxMin, int xxMax) {
return min(max(xx, xxMin), xxMax);
}
boolean over() {
if(mouseX >= xpos && mouseX <= xpos+swidth &&
mouseY >= ypos-sheight/2 && mouseY <= ypos+sheight/2) {
return true;
} else {
return false;
}
}
void draw() {
rectMode(CENTER);
stroke(0);
line(xpos,ypos,swidth+xpos,ypos);
for(int i=1;i<2;i++){
stroke(163,105,211,200-100*(i-1));
line(xpos,ypos+i,swidth+xpos,ypos+i);
line(xpos,ypos-i,swidth+xpos,ypos-i);
}
if(over || locked) {
fill(163,105,211,120);
stroke(255,255,255);
} else {
stroke(163,105,211);
fill(255,255,255);
}
rect(spos, ypos, sheight, sheight);
fill(0);
text(label,xpos,ypos-sheight);
text(val,xpos,ypos+2*sheight);
rectMode(CORNER);
}
float getVal() {
// donne la valeur associée au curseur.
return val;
}
boolean change() {
if(valPrec!=val) {
valPrec=val;return true;
} else {
return false;
}
}
}
//diffraction_rectangle
//Simulation de la répartition angulaire de l'éclairement obtenu par diffraction d'une onde plane par un obstacle rectangulaire axb.
//On se place dans le cadre de la diffraction de Fraunhoffer.
//On peut voir l'influence de la source et de la géométrie de l'obstacle.
//J.roussel
//http://perso.ensc-rennes.fr/jimmy.roussel/index.php
//Oct 2009
//A FAIRE : PAS DE ZOOM. DESSINER L'IMAGE GÉOMÉTRIQUE DANS LE PLAN FOCAL D'UNE LENTILLE
//********************************************
//Déclaration des variables (classe variable;)
//********************************************
int H;//demi largeur du diffractogramme
int h;//demi-hauteur du "bandeau titre+echelle"
int dimP;//largeur du panneau de commandes
float a,b;// dimensions de la pupille diffractante
float IR,IG,IB;//3 composantes RGB pour une raie spectrale
int sat2=1;
//sources
//lumiere blanche
float source3[]={380,400,420,440,460,480,500,520,540,560,600,620,640,660,680,700,720,740,760,780};
//sodium
float source0[]={589,589.6};
//laser rouge He-Ne
float source1[]={632.8};
//mercure
float source2[]={435.8,546,576.9,579};
int A=0; //numéro de la source activée
//curseurs horizontaux et boutons
Hslider[] sliders=new Hslider[3];
Hbouton[] boutons= new Hbouton[4];
//police
PFont fontA;
//******** Initialisation ****************
void setup() {
size(550,400,P2D);
frameRate(15);
h=16;
H=int(height/2-h);
dimP=width-2*H;
background(0);
a=100;
b=100;
//curseurs et boutons
sliders[0]=new Hslider(2*H+10,50,100,10,"largeur [µm] ",10,400);
sliders[1]=new Hslider(2*H+10,100,100,10,"hauteur [µm] ",10,400);
sliders[2]=new Hslider(2*H+10,280,100,10,"Saturation",1,50);
boutons[0]=new Hbouton(2*H+10,150,10,10,"Sodium");
boutons[1]=new Hbouton(2*H+10,170,10,10,"LASER He-Ne");
boutons[2]=new Hbouton(2*H+10,190,10,10,"Lampe Hg");
boutons[3]=new Hbouton(2*H+10,210,10,10,"Lumière blanche");
boutons[A].locked=true;
//Titres
fontA = loadFont("Helvetica-24.vlw");
textFont(fontA, 18);
pushMatrix();
translate(width/2,2*H+20);//centrage du titre sous l'interférogramme
textAlign(CENTER);
text("Diffraction à l'infini par une pupille rectangulaire",0,0);
textAlign(CORNER);
popMatrix();
textFont(fontA, 12);
}
//*******séquences*******************
void draw() {
//********panneau de commandes************
noStroke();
fill(100);
// rect(2*H,0,dimP,2*H);
rect(0,0,width,2*H+1);
sat2=int(sliders[2].getVal());
for (int i=0;i<sliders.length;i++){
sliders[i].update();
sliders[i].draw();}
// a=slider1.getVal();
boutonsUpdate(boutons);
for (int i=0;i<boutons.length;i++){
boutons[i].draw();}
//********* tracé de l'interférogramme **************
pushMatrix();
translate(H,H);//centrage de l'origine du repère
if (A==0){diffrac(source0,sliders[0].getVal(),sliders[1].getVal());}
if (A==1){diffrac(source1,sliders[0].getVal(),sliders[1].getVal());}
if (A==2){diffrac(source2,sliders[0].getVal(),sliders[1].getVal());}
if (A==3){diffrac(source3,sliders[0].getVal(),sliders[1].getVal());}
translate(0,-H+h);//echelle
stroke(255);
line(0,0,40,0);//1cm=40pixels
textAlign(CORNER);
text("1 cm",50,0);
popMatrix();
}
//************** Mise à jour de l'état des boutons *************
void boutonsUpdate(Hbouton[] x)
{int kmax=x.length;
for (int k=0;k<kmax;k++){
if (mouseX >= x[k].xpos && mouseX <= x[0].xpos+x[k].width &&
mouseY >= x[k].ypos && mouseY <= x[k].ypos+x[k].height)
{ x[k].over= true;
if(mousePressed){x[k].locked=true;A=k;
for(int i=0;i<k;i++){
x[i].locked=false;}
for(int i=k+1;i<kmax;i++){
x[i].locked=false;}
}
}
else{x[k].over=false;}
}
}
//********* procédure de conversion lambda->RGB ****************
void lambdaToRgb(float x)
{
float R=1;
float G=1;
float B=1;
float sat=1;
if(x<440. && x>=380.){
R=(440.-x)/60;
G=0;
B=1.;
}
if(x<490. && x>=440.){
R=0;
G=(x-440.)/50.;
B=1.;
}
if(x<510. && x>=490.){
R=0;
G=1.;
B=(510.-x)/20.;
}
if(x<580. && x>=510.){
R=(x-510.)/70.;
G=1.;
B=0;
}
if(x<645. && x>=580.){
R=1;
G=(645.-x)/65.;
B=0;
}
if(x<780. && x>=645.){
R=1.;
G=0;
B=0;
}
if(x>700.){
sat=0.3+0.7*(780.-x)/80.;
}
if(x<420.){
sat=0.3+0.7*(x-380.)/40.;
}
IR=(255*sat*R);
IG=(255*sat*G);
IB=(255*sat*B);
}
//donne l'éclairement en un point M(x,y) de l'écran situé à la distance D de la lame d'air.
// x et y sont en pixel et la longueur d'onde en nm
float eLambda(int x1,int y1,float l1, float a1, float b1) {
float phiX=PI*a1/l1*x1/4;
float phiY=PI*b1/l1*y1/4;
//float eclairement=constrain(sat2*sq(sinc(phiX)*sinc(phiY)),0,1);
//return(eclairement);
return(sat2*sq(sinc(phiX)*sinc(phiY)));
}
float sinc(float var){
return (sin(var)/var);
}
void diffrac(float[] source,float aa, float bb){
float lambdaK,eclairement;
int N;
N=source.length;
for (int i=0;i<H;i++){
for (int j=0;j<H;j++){
float doseR=0;
float doseG=0;
float doseB=0;
for (int k=0;k<N;k++){
lambdaK=source[k];
lambdaToRgb(lambdaK);
eclairement=eLambda(i,j,lambdaK,aa,bb);
doseR+=IR*eclairement;
doseG+=IG*eclairement;
doseB+=IB*eclairement;
}
stroke(doseR/N,doseG/N,doseB/N);
point(i,j);
point(-i,j);
point(i,-j);
point(-i,-j);
}
}
}