home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / sonderh1 / polyfilp.pas < prev    next >
Pascal/Delphi Source File  |  1987-04-15  |  12KB  |  286 lines

  1. (*-------------------------------------------------------------------------*)
  2. (*                          POLYFILP.PAS                                   *)
  3. (*         Aenderungen die an POLYFILL vorgenommen werden muessen,         *)
  4. (*               um den PatternFill zu erhalten.                           *)
  5.  
  6. (***       Neuer Prozedurkopf mit zusaetzlichem Parameter 'Muster':      ***)
  7. PROCEDURE PolyFill (Punkte: Polygon;
  8.                     AnzahlEcken: PolyIndex;
  9.                     Muster: Pattern_);
  10.  
  11.  
  12. TYPE Zeiger = ^EckenInfo;
  13.      EckenInfo = RECORD
  14.                    YTop : INTEGER;          (* Max. y-Wert der Kante       *)
  15.                    XMin,                    (* Min. x-Wert der Kante       *)
  16.                    m_inverse : REAL;        (* reziproke Steig. der Kante  *)
  17.                    next : Zeiger            (* Naechste Kante              *)
  18.                  END;
  19.  
  20. VAR
  21.        (* Es ist guenstiger, die Punkte intern bei 0 beginnend zu zaehlen, *)
  22.        (* siehe Anwendungen der Modulafunktion im Algorithmus. Daher :     *)
  23.     PunktIntern: ARRAY [0..PolyMax] OF PolyPunkt;
  24.     EckenTabelle : ARRAY [0..ScreenYmax] OF Zeiger;
  25.     ScanLine : Zeiger;            (* Schnittpunktliste fuer aktuelle Zeile *)
  26.     i : INTEGER;
  27.  
  28. (*-------------------------------------------------------------------------*)
  29. (*                  Prozeduren zur Listenbearbeitung:                      *)
  30.  
  31.   (*-----------------------------------------------------------------------*)
  32.   (*              reziproke Steigung einer Kante berechnen:                *)
  33.   FUNCTION Inverse (i: INTEGER): REAL;
  34.  
  35.   BEGIN
  36.     IF PunktIntern[i].y = PunktIntern[Succ(i) MOD AnzahlEcken].y THEN
  37.       Inverse := 0                                    (* horizontale Kante *)
  38.     ELSE
  39.       Inverse := (PunktIntern[i].x-PunktIntern[Succ(i) MOD AnzahlEcken].x)
  40.                   /(PunktIntern[i].y-PunktIntern[Succ(i) MOD AnzahlEcken].y)
  41.   END;
  42.  
  43.   (*-----------------------------------------------------------------------*)
  44.  
  45.   PROCEDURE Einfuegen (Ecke: Zeiger; VAR Liste: Zeiger);
  46.  
  47.   VAR
  48.     Akt,
  49.     Vor : Zeiger;
  50.  
  51.   BEGIN
  52.     IF Liste = NIL THEN                             (* Liste ist noch leer *)
  53.       Liste := Ecke
  54.     ELSE                                        (* Ecke in Liste einfuegen *)
  55.       IF Ecke^.XMin <= Liste^.XMin THEN
  56.         BEGIN                     (* Ecke muss als erste eingefuegt werden *)
  57.           Ecke^.next := Liste;
  58.           Liste := Ecke
  59.         END
  60.       ELSE
  61.         BEGIN                                           (* Position suchen *)
  62.           Akt := Liste;
  63.           WHILE (Akt^.next <> NIL) AND (Akt^.XMin < Ecke^.XMin) DO
  64.           BEGIN
  65.             Vor := Akt;                      (* Vorherige Position sichern *)
  66.             Akt := Akt^.next                 (* und zur naechsten ....     *)
  67.           END;
  68.           IF (Akt^.next = NIL) AND (Akt^.XMin < Ecke^.XMin) THEN
  69.                                        (* Ecke gehoert an's Ende der Liste *)
  70.             Akt^.next := Ecke
  71.           ELSE
  72.             BEGIN                               (* Ecke in Liste einketten *)
  73.               Ecke^.next := Akt;
  74.               Vor^.next := Ecke
  75.             END
  76.         END
  77.   END;
  78.  
  79.   (*-----------------------------------------------------------------------*)
  80.  
  81.   PROCEDURE ErstelleTabelle (AnzahlEcken: INTEGER);
  82.  
  83.   VAR ScanLine,                               (* Abtastlinie               *)
  84.       k           : INTEGER;                  (* Ecken-Laufindex           *)
  85.       Eckenliste  : Zeiger;
  86.  
  87.   BEGIN
  88.     FOR ScanLine := 0 TO ScreenYmax DO
  89.       EckenTabelle[ScanLine] := NIL;
  90.                        (* Eckeninformationen in die Eckentabelle einfuegen *)
  91.     FOR k := 0 TO Pred(AnzahlEcken) DO
  92.     BEGIN
  93.       New(Eckenliste);
  94.       Eckenliste^.m_inverse := Inverse(k);
  95.       Eckenliste^.next := NIL;
  96.  
  97.       (* Falls PunktIntern[k].y weiter oben ist als PunktIntern[k+1], dann *)
  98.       (* YTop auf diesen Wert setzen.                                      *)
  99.       IF PunktIntern[k].y > PunktIntern[Succ(k) MOD AnzahlEcken].y THEN
  100.         BEGIN
  101.           Eckenliste^.YTop := PunktIntern[k].y;
  102.                         (* Falls am PunktIntern[k+1] ein Minimum vorliegt, *)
  103.                         (* die Kante NICHT verkuerzen.                     *)
  104.           IF PunktIntern[Succ(k) MOD AnzahlEcken].y <
  105.              PunktIntern[(k + 2) MOD AnzahlEcken].y THEN
  106.             BEGIN
  107.               Eckenliste^.XMin := PunktIntern[Succ(k) MOD AnzahlEcken].x;
  108.               Einfuegen(Eckenliste,
  109.                         EckenTabelle[PunktIntern[Succ(k) MOD AnzahlEcken].y])
  110.             END
  111.           ELSE                      (* Falls Ecke[k + 1] KEIN Extrema ist, *)
  112.             BEGIN                   (* das niedrigere Ende kuerzen         *)
  113.               Eckenliste^.XMin := PunktIntern[Succ(k) MOD AnzahlEcken].x
  114.                                   + Eckenliste^.m_inverse;
  115.               Einfuegen(Eckenliste,
  116.                         EckenTabelle[Succ(PunktIntern[Succ(k) MOD
  117.                                                          AnzahlEcken].y)])
  118.           END
  119.         END
  120.       ELSE
  121.                 (* Falls PunktIntern[k + 1] hoeher ist als PunktIntern[k], *)
  122.                 (* YTop entsprechend setzen. Darf NICHT bei einer waage-   *)
  123.                 (* rechten Kante gemacht werden !                          *)
  124.         IF PunktIntern[k].y < PunktIntern[Succ(k) MOD AnzahlEcken].y THEN
  125.         BEGIN
  126.           Eckenliste^.YTop := PunktIntern[Succ(k) MOD AnzahlEcken].y;
  127.                                 (* Falls kein Minimum, Kante NICHT kuerzen *)
  128.           IF (PunktIntern[k].y <
  129.               PunktIntern[Pred(k + AnzahlEcken) MOD AnzahlEcken].y) THEN
  130.             BEGIN
  131.               Eckenliste^.XMin := PunktIntern[k].x;
  132.               Einfuegen(Eckenliste,EckenTabelle[PunktIntern[k].y])
  133.             END
  134.           ELSE
  135.             BEGIN               (* Ecke ist kein Extrema ==> Kante kuerzen *)
  136.               Eckenliste^.XMin := PunktIntern[k].x + Eckenliste^.m_inverse;
  137.               Einfuegen(Eckenliste,EckenTabelle[Succ(PunktIntern[k].y)])
  138.             END
  139.         END
  140.     END (* FOR *)
  141.   END;
  142.  
  143.   (*-----------------------------------------------------------------------*)
  144.   (* NeueListe ist die Liste aus der Eckentabelle, AlteListe wird fuer die
  145.      Scanline aufgebaut.                                                   *)
  146.  
  147.   PROCEDURE Mischen (NeueListe: Zeiger; VAR AlteListe: Zeiger);
  148.  
  149.   VAR Temp, Neu: Zeiger;
  150.  
  151.   BEGIN
  152.     IF AlteListe = NIL THEN                              (* Leere Scanline *)
  153.       AlteListe := NeueListe
  154.     ELSE
  155.       BEGIN                                                     (* Mischen *)
  156.         Neu := NeueListe;
  157.         WHILE Neu <> NIL DO
  158.         BEGIN                          (* Ecke in ScanLine-Liste einfuegen *)
  159.           Temp := Neu^.next;
  160.           Neu^.next := NIL;
  161.           Einfuegen(Neu, AlteListe);
  162.           Neu := Temp                               (* Zur naechsten Kante *)
  163.         END
  164.       END
  165.   END;
  166.  
  167.   (*-----------------------------------------------------------------------*)
  168.   (* Entfernt aus der ScanLine-Liste solche Kanten, die an der aktuellen
  169.      ScanLine enden.                                                       *)
  170.  
  171.   PROCEDURE Entferne (VAR ScanLine: Zeiger; YZeile: INTEGER);
  172.  
  173.   VAR Akt, Letzte : Zeiger;
  174.  
  175.   BEGIN
  176.     Akt := ScanLine;
  177.     WHILE Akt <> NIL DO
  178.     BEGIN
  179.       IF Akt = ScanLine THEN                          (* erste entfernen ? *)
  180.         IF Akt^.YTop = YZeile THEN
  181.           BEGIN                                             (* entfernen ! *)
  182.             ScanLine := ScanLine^.next;
  183.             Akt := ScanLine;
  184.             Letzte := Akt
  185.           END
  186.         ELSE
  187.           BEGIN                             (* erste Kante NICHT entfernen *)
  188.             Letzte := Akt;                  (* weiter...                   *)
  189.             Akt := Akt^.next
  190.           END
  191.       ELSE
  192.         BEGIN                                    (* andere Ecken behandeln *)
  193.           IF Akt^.YTop = YZeile THEN                    (* Ecke entfernen? *)
  194.             Letzte^.next := Akt^.next                   (* ja...           *)
  195.           ELSE
  196.             Letzte := Akt;
  197.           Akt := Akt^.next                 (* und weiter in beiden Faellen *)
  198.         END
  199.     END
  200.   END;
  201.  
  202.   (*-----------------------------------------------------------------------*)
  203.   (* Inkrementiert die XMin-Werte der ScanLine-Liste um m_inverse und      *)
  204.   (* sortiert die ScanLine-Liste aufgrund der XMin-Werte neu.              *)
  205.  
  206.   PROCEDURE NeuSortieren (VAR ScanLine: Zeiger);
  207.  
  208.   VAR SortZeiger, SortNext: Zeiger;
  209.  
  210.   BEGIN
  211.     IF ScanLine <> NIL THEN
  212.     BEGIN                                          (* Erste Ecke behandeln *)
  213.       ScanLine^.XMin := ScanLine^.XMin + ScanLine^.m_inverse;
  214.       SortZeiger := ScanLine^.next;
  215.       ScanLine^.next := NIL;
  216.                              (* Damit hat ScanLine nur noch die erste Ecke *)
  217.                              (* Restlichen Ecken behandeln...              *)
  218.       WHILE SortZeiger <> NIL DO
  219.       BEGIN                                         (* XMin inkrementieren *)
  220.         SortZeiger^.XMin := SortZeiger^.XMin + SortZeiger^.m_inverse;
  221.         SortNext := SortZeiger^.next;
  222.  
  223.         SortZeiger^.next := NIL;     (* Fuer Einfuegen EINE Ecke isolieren *)
  224.         Einfuegen(SortZeiger, ScanLine);
  225.         SortZeiger := SortNext
  226.       END
  227.     END
  228.   END;
  229.  
  230.   (*-----------------------------------------------------------------------*)
  231.   (* diese modifizierte Prozedur 'Fuelle_ScanLine' gegen die alte ersetzen!*)
  232.  
  233.   PROCEDURE Fuelle_ScanLine (ScanLine: Zeiger; y: INTEGER);
  234.  
  235.   VAR k: INTEGER;      (* k = gerade ==> zeichnen, k = ungerade ==> move'n *)
  236.       Akt: Zeiger;
  237.       AktX,                                   (* X-Wert Pixel auf ScanLine *)
  238.       xi, yi: INTEGER;                                    (* Pattern Index *)
  239.  
  240.   BEGIN
  241.     k := 0;
  242.     IF ScanLine <> NIL THEN
  243.     BEGIN                                        (* Es gibt was zu fuellen *)
  244.       Akt := ScanLine;
  245.       WHILE Akt <> NIL DO
  246.       BEGIN                                                    (* Zeichnen *)
  247.         k := Succ(k);
  248.         IF k MOD 2 = 1 THEN
  249.           movea(Round(Akt^.XMin),y)
  250.         ELSE
  251.           BEGIN
  252.             yi := y MOD Succ(PatternSize);
  253.             FOR AktX := Pen_xPos TO Round(Akt^.XMin) DO
  254.             BEGIN
  255.               xi := AktX MOD Succ(PatternSize);
  256.               IF Muster[yi,xi] THEN
  257.                 point(AktX,y)
  258.             END
  259.           END;
  260.         Akt := Akt^.next
  261.       END
  262.     END
  263.   END;
  264.  
  265.   (*-----------------------------------------------------------------------*)
  266.  
  267. BEGIN (* PolyFill *)
  268.   FOR i := 1 TO AnzahlEcken DO        (* Punkte in PunktIntern umsortieren *)
  269.     PunktIntern[Pred(i)] := Punkte[i];
  270.   PolyLine(Punkte, AnzahlEcken);
  271.                                                      (* Polygon schliessen *)
  272.   Line(Punkte[1].x,Punkte[1].y,Punkte[AnzahlEcken].x,Punkte[AnzahlEcken].y);
  273.   ErstelleTabelle(AnzahlEcken);
  274.   ScanLine := NIL;
  275.   FOR i := 0 TO ScreenYmax DO
  276.   BEGIN
  277.     IF EckenTabelle[i] <> NIL THEN
  278.       Mischen(EckenTabelle[i], ScanLine);
  279.     Fuelle_ScanLine(ScanLine, i);
  280.     Entferne(ScanLine, i);
  281.     NeuSortieren(ScanLine);
  282.   END
  283. END;
  284.  
  285. (*-------------------------------------------------------------------------*)
  286. (*                             Ende POLYFILP.PAS                           *)