home *** CD-ROM | disk | FTP | other *** search
- Program Plot_3D;
-
- { PLOT 3-D
-
- Ein Programm von Jens Gelhar, (c) Himpelsoft 1990.
-
- MaxonPascal3-Anpassung / Test: Falk Zühlsdorff (PackMAN) 1994
-
- Unter Benutzung einiger Ideen (mein Programm kommt aber OHNE
- Quasi-Raytracing aus!) von Michael Aumer (KICKSTART 9/90, S.72)
-
- Dieses Programm plottet dreidimensionale Funktionen (z = f(x,y)).
- Dabei werden aber nicht irgendwelche häßliche Drahtgitter erzeugt
- (womöglich gar ohne Hidden Lines), sondern der Graph wird als
- plastischer Körper einschließlich Schatten dargestellt.
-
- Der Funktionsterm und einige Parameter müssen im Quelltext
- angegeben werden.
-
- Viel Spaß beim Ausprobieren!
-
- }
-
- {$opt q }
-
- Uses Intuition, Graphics;
-
- {
- Durch Definition eines Bezeichners "test" wird die "Preview"-
- Version des Plotters definiert, d. h. die Grafik wird erheblich
- schneller, aber sehr grob erstellt:
-
- Const test=1;
-
- }
-
- Const
- ScrH = 256;
- WinH = ScrH;
- ScrB = 640;
- WinB = ScrB;
- MinY = 80;
- MaxY = WinH-8;
-
- Schattenlänge = 4.5; { größerer Wert -> längere Schatten }
- Schattenhärte = 20; { größerer Wert -> weichere Schatten }
-
- {$if def test }
- Step = 15;
- {$endif }
-
- Var scr: ^Screen;
- win: ^Window;
- ras: ^RastPort;
- vp : ^ViewPort;
- Msg : Ptr;
- xi, zi : integer;
- yi : real;
- YStep : real;
- x, y, z : real;
- i, pen : integer;
- xd, yd, maxYd : real;
- xu, yu: integer;
- v0, v1, v2 : real;
- cosA : real;
- lastZ : real;
- Schatten, Schattenlinie : integer;
- Txt: String;
- tf: real;
- max : Array[0..WinB] of integer;
- plotIt : Boolean;
- SL2 : Real;
- xj : integer;
-
- Gfx : long;
-
- { Der folgende Text wird über die fertige Grafik geschrieben: }
-
- Const Funktion = 'z = cos(c*r) / (r^2+1)';
-
-
- Function f(x, y: real): real;
- { Diese Function repräsentiert die dargestellte Funktion.
- Wertebereich von x und y: -1 bis +1, wenn man andere Ausschnitte
- darstellen will, sind die Werte innerhalb der Function
- entsprechend zu normieren.
- Der von "f" zurückgegebene Wert muß der gewünschten Höhe in
- Bildpunkten (!) entsprechen. Die meisten Funktionen wird man also
- mit einem Faktor (z. B. 50) multiplizieren müssen, sonst wird das
- Bild zu "flach".
- }
- Var r : real;
- Begin
- r := sqr(x) + sqr(y);
- f := 50 * (1+cos(20*sqrt(r))) / (20*r+0.5);
- End;
-
-
- (******************* andere schöne Funktionen: ******************]
-
- { Kreis mit Mittelpunkt: }
- Var r : real;
- Begin f := 0;
- r := sqr(x) + sqr(y);
- If r < 0.1 Then
- f := 80 * cos(5*r*pi)
- Else
- If abs(r-0.9) < 0.1 Then
- Begin
- r := r-0.9;
- f := 25 * cos(5*r*pi)
- End
- Else f := 0;
- End;
-
- { Überlagerung zweier gedämpfter Schwingungen: }
- Var r1, r2: Real;
- Begin
- r1 := 3*(sqr(x+0.5) + sqr(y+0.2));
- r2 := 3*(sqr(x-0.6) + sqr(y-0.5));
- f := 10 *(cos (8*r1) / (r1 + 0.05) + cos(8*r2) / (r2+0.05) );
- End;
-
- { "Chaotische" Wellen: }
- Begin
- f := 50 * ( sin (3*x+4*y) * abs(cos (3*y-2*x))) + 20 * (sqr(x) + 1-sqr(y) );
- End;
-
- { total "hohl": }
- Var r : real;
- Begin
- r := sqr(x) + sqr(y);
- If r < 0.9 Then f := -100*cos(r*pi/1.8)
- Else f := 0
- End;
-
- [****************************************************************)
-
-
- Function Tiefenfaktor (y: real): real;
- { perspektivische Verkleinerung, 0 < y < 1, normiert auf tf(0)=1 }
- Begin
- Tiefenfaktor := 2 / (y+2)
- End;
-
-
- Begin
- {$opt b+ - Abbruch möglich }
- scr := Open_Screen(0, 0, ScrB, ScrH, 4, 0, 15, HIRES, 'Plot');
- win := Open_Window(0, 0, WinB, WinH, 1, MOUSEBUTTONS, BORDERLESS, Nil, scr,
- 0, 0, WinB, WinH);
- ras := win^.RPort;
- vp := ^scr^.ViewPort;
-
- For i:= 0 to 15 Do
- SetRGB4(vp, i, i, i, i);
- For i:= 0 to WinB do
- max[i] := MaxY;
-
- YStep := 2 / (MaxY-MinY);
- SL2 := Schattenlänge/2;
-
- yi := MaxY;
- While yi >= MinY Do
- Begin
-
- yu := Round(yi);
-
- y := (MaxY - yi) / (MaxY-MinY); { [0..1] }
- y := 2*(exp(y)-1) / (exp(1)-1) - 1; { [-1..+1] }
-
- tf := Tiefenfaktor( (MaxY-yi) / (MaxY-MinY) );
-
- Txt := IntStr(Round(50*y)+50) + '%';
- Move (ras, 1, 10);
- SetAPen (ras, 12);
- Gfx:=_Text (ras, Txt, Length(Txt))
-
- Schatten := -MaxInt;
- lastZ := f(-1-YStep, y);
- maxYD := 0;
-
- xi := 0;
- While xi < WinB Do
- Begin
- x := (2*xi - WinB) / WinB;
- xu := (WinB +Round( WinB * x * tf) )div 2;
- z := f(x,y);
- zi := yu - round( z*tf );
-
- plotIt := zi < max[xu];
-
- If plotIt Then
- Begin
- xd := (z - lastZ) {$if def test} / step {$endif} ;
- yd := z - f(x, y-YStep);
-
- { Vektorprodukt: V := (yStep, 0, xd) X (0, yStep, yd) }
- v0 := -xd * YStep;
- v1 := -yd * YStep;
- v2 := sqr(YStep);
-
- { A = (-SL2, 0, 1),
- cos alpha = (A*V) / (abs(A) * abs(V)) }
-
- cosA := (v2 - SL2*v0) / (sqrt(1+sqr(SL2)) * sqrt(sqr(v0)+sqr(v1)+sqr(v2)));
-
- pen := round((14*16 div 2) * (cosA+1));
-
- End;
-
- Schattenlinie := xu + Round( (yu-zi) * Schattenlänge );
- If (Schattenlinie < Schatten) and plotIt Then
- Begin
- If Schatten-Schattenlinie < Schattenhärte Then
- pen := round(pen / (1+2*(Schatten-Schattenlinie)/Schattenhärte))
- Else
- pen := pen div 3
- End
- Else
- If Schattenlinie >= Schatten Then
- Schatten := Schattenlinie;
-
- If plotIt Then
- Begin
-
- {$if def test }
- pen := pen shr 4;
- {$else }
- If random(16) < pen and 15 Then
- pen := (pen shr 4) + 1
- Else
- pen := pen shr 4;
- {$endif }
-
- If yi = MaxY Then pen := 10;
- SetAPen (ras, pen);
-
- {$if def test }
- For i := 0 to Step-1 Do
- Begin
- xj := xu + round(tf*i);
- Move (ras, xj, zi+round((Step-i)/Step * (z-lastZ) * tf ));
- Draw (ras, xj, max[xj]-1);
- End;
- For i := 0 to Step-1 Do
- Begin
- xj := xu + round(tf*i);
- max[xj-1] := zi + round((Step-i)/Step * (z-lastZ) * tf )
- End;
- {$else }
- Move(ras, xu, zi);
- Draw(ras, xu, max[xu]-1);
- max[xu] := zi;
- If yd > maxYD Then maxYD := yd;
- {$endif }
-
- End;
-
- LastZ := z;
-
- xi := xi + {$if def test} step {$else} 1 {$endif} ;
-
- End;
-
- {$if def test}
- yi := yi - 1 - step div 2;
- {$else }
- If maxYd*tf > 3 Then { bei starken Gefällen zum }
- yi := yi - 0.1 - 2/maxYd/tf { Betrachter hin um weniger }
- Else { als eine Zeile springen }
- yi := yi - 1
- {$endif}
-
- End;
-
- Txt := Funktion;
- Move (ras, 1, 10);
- SetAPen (ras, 12);
- Gfx:=_Text (ras, Txt, Length(Txt))
-
- Repeat
- { alle bisherigen Events überlesen }
- msg := Get_Msg(win^.UserPort);
- Until msg = nil;
-
- Repeat
- { Programm mit linker Maustaste beenden }
- msg := Wait_Port(win^.UserPort);
- Until msg <> nil;
-
- { Fenster + Screen schließen sich autmatisch }
-
- End.
-
-
-