/* * Copyright (C) 1998 Ralf Wiebicke * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package de.rw7; import java.awt.BorderLayout; import java.awt.Choice; import java.awt.Color; import java.awt.Event; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Scrollbar; import java.awt.image.ColorModel; import java.awt.image.MemoryImageSource; import java.awt.image.PixelGrabber; /** Poincare'sche Wiederkehr. Fuer eine ausfuehrliche Erklaerung siehe DOS (Compterzeitschrift, Franzis Verlag) 4/94 Seite 240. */ public class Poincare extends java.applet.Applet implements Runnable { static String[] Sources = { "Kreuz", "Kreis", "Garten", "Kompass" }; static final int M00 = 1, M10 = 3, M01 = 1, M11 = 2, Mmod = 60; final int N = 200; final int[] Src = new int[N * N]; final int[] Dst = new int[N * N]; int Exponent = 0; String Source = Sources[0]; boolean changed = false; Scrollbar ExponentScrollbar = null; Choice SrcChoice = null; ColorModel CM; Image ScreenBuffer; Thread running; public void init() { setLayout(new BorderLayout()); add( "South", ExponentScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 0, 0, Mmod + 1)); SrcChoice = new Choice(); for (int i = 0; i < Sources.length; i++) SrcChoice.addItem(Sources[i]); add("East", SrcChoice); CM = ColorModel.getRGBdefault(); } public void start() { if (running == null) { running = new Thread(this); running.setPriority(Thread.MIN_PRIORITY); running.setDaemon(true); running.start(); } } public void stop() { if (running != null) { running.stop(); running = null; } } public void run() { final int N = this.N; final int[] Src = this.Src; final int[] Dst = this.Dst; boolean matrixToPaint = true; int Exponent = (-1); String Source = null; int d00 = 1, d10 = 0, d01 = 0, d11 = 1; while (true) { if (Source != this.Source) { Source = this.Source; Image img = createImage(N, N); Rectangle r = new Rectangle(0, 0, N, N); Graphics g = img.getGraphics(); if ("Kreuz".equals(Source)) drawKreuz(g, r); else if ("Kreis".equals(Source)) drawKreis(g, r); else if ("Garten".equals(Source)) drawGarten(g, r); else if ("Kompass".equals(Source)) drawKompass(g, r); else throw (new IllegalArgumentException()); g.dispose(); PixelGrabber pg = new PixelGrabber(img, 0, 0, N, N, Src, 0, N); try { pg.grabPixels(); } catch (InterruptedException e) { }; matrixToPaint = true; } if (Exponent != this.Exponent) { Exponent = this.Exponent; d00 = 1; d10 = 0; d01 = 0; d11 = 1; // Einheitsmatrix if (Exponent == 0) for (int i = 0; i < Src.length; i++) Dst[i] = Src[i]; else { showStatus( "erstelle Matrix (" + String.valueOf(Exponent) + ") ..."); int a00 = M00, a10 = M10, a01 = M01, a11 = M11; // Basis int t00, t10, t01; int n = Exponent; while (n > 0) { if (n % 2 > 0) { t00 = (a00 * d00 + a01 * d10) % N; t10 = (a10 * d00 + a11 * d10) % N; t01 = (a00 * d01 + a01 * d11) % N; d11 = (a10 * d01 + a11 * d11) % N; d00 = t00; d10 = t10; d01 = t01; }; t00 = (a00 * a00 + a01 * a10) % N; t10 = (a10 * a00 + a11 * a10) % N; t01 = (a00 * a01 + a01 * a11) % N; a11 = (a10 * a01 + a11 * a11) % N; a00 = t00; a10 = t10; a01 = t01; n /= 2; }; }; matrixToPaint = true; }; if (matrixToPaint) { matrixToPaint = false; showStatus( "transformiere Bild (" + String.valueOf(this.Exponent) + ") ..."); for (int y = 0, i = 0; y < N; y++) for (int x = 0; x < N; x++) Dst[(d00 * x + d10 * y) % N + N * ((d01 * x + d11 * y) % N)] = Src[i++]; }; showStatus("generiere Bild..."); if (ScreenBuffer == null) ScreenBuffer = createImage(new MemoryImageSource(N, N, CM, Dst, 0, N)); else ScreenBuffer.flush(); showStatus("fertig."); repaint(); if (!changed) running.suspend(); changed = false; } } public void paint(Graphics g) { if (ScreenBuffer != null) g.drawImage(ScreenBuffer, 0, 0, null); g.drawString(String.valueOf(Exponent), 0, 20); } public boolean handleEvent(Event e) { if (e.target == ExponentScrollbar) { int n = (((Integer) e.arg).intValue()); Exponent = n; ExponentScrollbar.setValue(n); changed = true; running.resume(); } else if (e.target == SrcChoice && e.id == 1001) { Source = (String) e.arg; changed = true; running.resume(); } return (super.handleEvent(e)); } private static void drawKreuz(Graphics g, Rectangle r) { g.setColor(Color.black); g.fillRect(r.x, r.y, r.width, r.height); g.setColor(Color.white); g.fillOval( r.x + r.width / 8, r.y + r.height / 8, 3 * r.width / 4, 3 * r.height / 4); g.setColor(Color.blue); g.fillRect( r.x + r.width / 4, r.y + 9 * r.height / 20, r.width / 2, r.height / 10); g.fillRect( r.x + 9 * r.width / 20, r.y + r.height / 4, r.width / 10, r.height / 2); } private static void drawKreis(Graphics g, Rectangle r) { g.setColor(Color.white); g.fillRect(r.x, r.y, r.width, r.height); g.setColor(Color.black); g.drawOval(r.x, r.y, r.width - 1, r.height - 1); } private static void drawGarten(Graphics g, Rectangle r) { g.setColor(Color.blue); g.fillRect(r.x, r.y, r.width, 3 * r.height / 4); g.setColor(Color.green); g.fillRect(r.x, r.y + 3 * r.height / 4, r.width, r.height / 4); g.setColor(Color.orange); g.fillRect( r.x + 9 * r.width / 20, r.y + r.height / 3, r.width / 10, r.height / 2); g.setColor(Color.green); g.fillOval( r.x + r.width / 4, r.y + r.height / 10, r.width / 2, r.height / 2); g.setColor(Color.yellow); g.fillOval( r.x + r.width / 20, r.y + r.height / 20, r.width / 5, r.height / 5); g.setColor(Color.white); g.fillOval( r.x + 15 * r.width / 20, r.y + r.height / 20, r.width / 15, r.height / 15); g.fillOval( r.x + 16 * r.width / 20, r.y + r.height / 20, r.width / 15, r.height / 15); g.fillOval( r.x + 16 * r.width / 20, r.y + 3 * r.height / 20, r.width / 15, r.height / 15); g.fillOval( r.x + 17 * r.width / 20, r.y + 3 * r.height / 20, r.width / 15, r.height / 15); } private static void drawKompass(Graphics g, Rectangle r) { g.setColor(Color.yellow); g.fillRect(r.x, r.y, r.width / 2, r.height / 2); g.setColor(Color.green); g.fillRect(r.x + r.width / 2, r.y, r.width / 2, r.height / 2); g.setColor(Color.blue); g.fillRect(r.x, r.y + r.height / 2, r.width / 2, r.height / 2); g.setColor(Color.red); g.fillRect( r.x + r.width / 2, r.y + r.height / 2, r.width / 2, r.height / 2); g.setColor(Color.black); FontMetrics fm = g.getFontMetrics(); g.drawString("N", r.width / 2 - fm.charWidth('N') / 2, fm.getAscent()); g.drawString("S", r.width / 2 - fm.charWidth('S') / 2, r.height); g.drawString("W", 0, r.height / 2 + fm.getAscent() / 2); g.drawString( "E", r.width - fm.charWidth('E'), r.height / 2 + fm.getAscent() / 2); } } // class Poincare