Mieszanie kolorów, trójkąt Maxwella

(myszą możesz zmieniać punkty R, B i G)

Najpierw wywołamy wrażenie emisji trzech źródeł światła R, G i B.

Algorytm rysujący trójkąt Sierpińskiego, może nam być tutaj pomocny.

Jeden wędrujący punkt losowo wybiera wierzchołek trójkąta i zajmuje nową pozycję w wyskalowanej dległości od niego.
Uzyskamy dwa efekty :
pracę "jednego fotonu"
zamkniemy wędrówkę punktu wewnątrz Δ RGB.

W trakcie swojej wędrówki nasz punkt będzie podejmował decyzje o swoim kolorze, tak jak to przedstawiono w aplecie po lewej stronie.
Najbardziej znany efekt to tzw trójkąt Maxwella i nim zajmiemy się szczegółowo:

Zadeklarujemy prostą strukturę i procedurę rysującą:

//---deklaracje zmiennych------------
pkt2d w[ ]=new pkt2d[3];
pkt2d b;
int pal[ ]=new int[3];
//---Wierzchołki RGB,punkt i kolory--
public void init( )
{
  w[0]=new pkt2d(-7,-4);
  w[1]=new pkt2d(-1,6);
  w[2]=new pkt2d(7,-5);
  b=new pkt2d(0,0);
  pal[0]=0xff0000;
  pal[1]=0x00ff00;
  pal[2]=0x0000ff;
}
void swiatlo(Graphics g) 
{int los,kolor; 
  for(int i=0;i<1500;i++) 
    { 
      los=mat.losowa_c(n); 
      b.x=b.x+(w[los].x-b.x)/5.0; 
      b.y=b.y+(w[los].y-b.y)/5.0; 
      kolor=maxwella(b); 
      g.setColor(kolor); 
      lo28.punkt(g,b); 
    } 
}
Teraz najważniejsze to wyznaczanie koloru wg. algorytmu Maxwella, w wyniku którego uzyskamy efekt.
Przepis jest taki:
pełne barwy R,G,B    przypisujemy wierzchołkom
kolor punktu określa stosunek     trzech odległości od boków    trójkąta np:

 ρ(b,GB)
r=---------
   ρ(R,GB)


gdzie ρ(b,GB) to odległość punktu b od prostej pr(G,B).


Aby zapewnić odpowiednią "jasość" wyznaczam liczbę d=Max(r,g,b); i ustalam ostatecznie
kolor=new Color(r/d, g/d, b/d);

Jeszcze słowo o odległości np ρ(b,GB) lub ρ(R,GB).
Rozwiążmy problem ogólny tzn wyznaczymy funkcję odl liczącą odległość punktu p od prostej pr(a,b).
Najpierw ustalimy wzór prostej w postaci normalnej : Ax+By+C=0
v=[v.x,v.y]=[b.x-a.x, b.y-a.y] to wektor kierunkowy (równoległy) prostej.
Nas interesuje wektor normalny [A,B]=[-v.y,v.x]. Ostatecznie
To tyle matematyki, teraz kod funkcji odl i maxwella:
float odl(pkt2d p,pkt2d a,pkt2d b) 
{float A,B,C,l,m; 
  A=(float)(-b.y+a.y); 
  B=(float)(b.x-a.x); 
  C=(float)(-A*a.x-B*a.y); 
  l=(float)Math.abs(A*p.x+B*p.y+C); 
  m=(float)Math.sqrt(A*A+B*B); 
  
  return(l/m); 
}
Color maxwella(pkt2d p) 
{ 
  float dr=odl(p,w[1],w[2]); 
  float dg=odl(p,w[0],w[2]); 
  float db=odl(p,w[0],w[1]); 
  float r=dr/ro_r; 
  float g=dg/ro_g; 
  float b=db/ro_b; 
  float d=Max(r,g,b); 
  
  return(new Color(r/d,g/d,b/d)); 
}
 ro_r=odl(w[0],w[1],w[2]);
 ro_g=odl(w[1],w[0],w[2]);
 ro_b=odl(w[2],w[0],w[1]);

Pozostają jeszcze inne sposoby mieszania prezentowane w aplecie - są proste:

BRAKANDPLUS
kolor=new Color(pal[los]) kolor=new Color(pal[los] | getKolor(b)) kolor=new Color(pal[los]+getKolor(b))

Od biedy każdy z tych sposobów jakoś można odnieść do rzeczywistości:
"BRAK" to przyklad mieszania impresjonistycznego,
"OR" może symulować oświetlenie trzech silnych reflektorów teatralnych,
"PLUS" to prostu ciekawa plastyczna wariacja bez powodu. Zobacz wersję dla niecierpliwych