Durch räumliche Überlagerung harmonischer Schwingungen entstehen
die, nach dem französichen Physiker Jules Antoine Lissasjous (1822–1880) benannten,
Lissajou-Figuren. Diese Figuren zeigen sich z. B. wenn bei einem Oszilloskop
sowohl am Eingang für die x-, als auch für die y-Ablenkung eine harmonische
Wechselspannung angelegt wird.
//Voraussetzung: Java3D
Alles anzeigen
die, nach dem französichen Physiker Jules Antoine Lissasjous (1822–1880) benannten,
Lissajou-Figuren. Diese Figuren zeigen sich z. B. wenn bei einem Oszilloskop
sowohl am Eingang für die x-, als auch für die y-Ablenkung eine harmonische
Wechselspannung angelegt wird.
//Voraussetzung: Java3D
Quellcode
- package Lissajou;
- import java.awt.*;
- import java.awt.event.*;
- import javax.vecmath.*;
- public class LissajouApplication {
- public static int xPeriod = 1, yPeriod = 1;
- public static boolean cancel=false;
- public static boolean trajectory;
- public static void main(String[] args) {
- new LissajouGUI(800, 600);
- }
- @SuppressWarnings("serial")
- static class LissajouGUI extends Frame {
- private LissaJouCanvas canvas = new LissaJouCanvas();
- /**
- * Konstruktor der GUI
- */
- public LissajouGUI(int width, int height) {
- super("Lissajou Figures");
- //Optionen fuer die Zeichenflaeche
- canvas.setBackground(Color.LIGHT_GRAY);
- canvas.setSize(width, height);
- //Fenster schliessen
- addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- System.exit(0);
- }
- });
- //Layout Initialisierung
- GridBagLayout gridB = new GridBagLayout();
- GridBagConstraints layout = new GridBagConstraints();
- setLayout(gridB);
- layout.gridwidth = 1;
- layout.gridheight = 8;
- layout.gridx = 1;
- layout.gridy = 1;
- //Layout defaults
- layout.fill = GridBagConstraints.BOTH; //horizontal und vertikal auf MAX
- gridB.setConstraints(canvas, layout);
- add(canvas);
- //Hier beginnt die rechte Spalte
- layout.gridheight = 1;
- layout.gridx = 2;
- layout.gridy = 1;
- // Label x- period
- Label labelx = new Label("x-period");
- gridB.setConstraints(labelx, layout);
- add(labelx);
- layout.gridy++;
- // Choice x-period
- Choice xxx = new Choice();
- for (int x = 1; x <= 16; x += 1)
- xxx.add(x + "");
- xxx.addItemListener(new ItemAdapter() {
- public void itemStateChanged(ItemEvent event) {
- xPeriod = ((Choice) event.getSource()).getSelectedIndex() + 1;
- System.out.println("x-periode: "+xPeriod);
- }
- });
- gridB.setConstraints(xxx, layout);
- add(xxx);
- layout.gridy++;
- // Label y-Period
- Label labely = new Label("y-period");
- gridB.setConstraints(labely, layout);
- add(labely);
- layout.gridy++;
- // Choice y-period
- Choice yyy = new Choice();
- for (int y = 1; y <= 16; y += 1)
- yyy.add(y + "");
- gridB.setConstraints(yyy, layout);
- yyy.addItemListener(new ItemAdapter() {
- public void itemStateChanged(ItemEvent event) {
- yPeriod = ((Choice) event.getSource()).getSelectedIndex() + 1;
- System.out.println("y-periode: "+yPeriod);
- }
- });
- add(yyy);
- layout.gridy++;
- // checkBox trajectory
- Checkbox checkTrajectory = new Checkbox("show trajectory");
- gridB.setConstraints(checkTrajectory, layout);
- checkTrajectory.addItemListener(new ItemAdapter() {
- public void itemStateChanged(ItemEvent event) {
- Checkbox tmp = (Checkbox) event.getSource();
- System.out.println("Trajectory: "+tmp.getState());
- if (tmp.getState())
- trajectory = true;
- else
- trajectory = false;
- }
- });
- add(checkTrajectory);
- layout.gridy++;
- // Clear Button
- Button clearBut = new Button("clear");
- gridB.setConstraints(clearBut, layout);
- clearBut.addActionListener(new ActionAdapter() {
- public void actionPerformed(ActionEvent e) {
- canvas.repaint();
- }
- });
- add(clearBut);
- layout.gridy++;
- // Stop Button
- Button stopBut = new Button("Stop");
- gridB.setConstraints(stopBut, layout);
- stopBut.addActionListener(new ActionAdapter() {
- public void actionPerformed(ActionEvent e) {
- LissajouApplication.cancel = true;
- }
- });
- add(stopBut);
- layout.gridy++;
- // Start Button
- Button startBut = new Button("Start");
- gridB.setConstraints(startBut, layout);
- startBut.addActionListener(new ActionAdapter() {
- public void actionPerformed(ActionEvent e) {
- canvas.startAnimation();
- }
- });
- add(startBut);
- setSize(width,height);
- setLocation(150,100);
- setVisible(true);
- pack();
- }
- abstract class ItemAdapter extends Object implements ItemListener {
- public abstract void itemStateChanged(ItemEvent event);
- }
- abstract class ActionAdapter extends Object implements ActionListener {
- public abstract void actionPerformed(ActionEvent e);
- }
- }
- @SuppressWarnings("serial")
- static class LissaJouCanvas extends Canvas implements Runnable {
- /**
- * startet den Thread fuer die Animation
- */
- public void startAnimation() {
- try {
- LissajouApplication.cancel = false;
- new Thread(this).start();
- } catch (Exception e){}
- }
- // public void repaint() {
- // wird zum clearen benutzt.. daher ist das original OK
- // }
- /**
- * zeichnet die Lissajou Kurve wieder und wieder
- */
- public void run() {
- while(true) //Wenn fertig gezeichnet, dann zeichne nochmal
- new Lissajou(getGraphics(), this.getWidth()/2, this.getHeight()/2, xPeriod, yPeriod, trajectory);
- }
- }
- static class Lissajou {
- /**
- * Konstruktor - Zeichnet die Lissajou Figur
- * @param g Graphics Objekt
- * @param startX
- * @param startY
- * @param xPeriod X Position
- * @param yPeriod Y Position
- * @param trajectory Kometenschweif
- */
- public Lissajou(Graphics g, int startX, int startY, int xPeriod, int yPeriod, boolean trajectory) {
- final double deltaT = 0.01;
- double t;
- Point2d p;
- Vector2d v;
- int kgv =Kgv(xPeriod,yPeriod);
- int stop = (int)(kgv/deltaT); //Abbruchbedingug
- int[] x = new int[stop+1], y = new int[stop+1]; //Polyline Array
- for(int s=1, counter=0; s<=stop && !LissajouApplication.cancel; s++) {
- t = s * deltaT;
- p = makePoint2d(t, startX, startY, xPeriod, yPeriod);
- v = makeVector2d(t, xPeriod, yPeriod);
- //Kometenschweif anzeigen?
- if(LissajouApplication.trajectory) {
- x[counter] = (int)p.x;
- y[counter] = (int)p.y;
- g.drawPolyline(x, y, counter);
- counter++;
- }
- //ueberzeichne mit Hintergrundfarbe
- g.fillPolygon(arrow(p,v,5,2));
- g.setColor(Color.LIGHT_GRAY);
- //Das ist eine menschlich sichtbare Animation, also schlafe ein wenig
- try {
- Thread.sleep(40);
- } catch (Exception e) {}
- //ueberzeichne schwarz
- g.fillPolygon(arrow(p,v,5,2));
- g.setColor(Color.BLACK);
- }
- }
- /**
- * zeichnet einen gerichteten Pfeil
- * @param pos Position
- * @param dir Richtung
- * @param s hoehe
- * @param r breite
- * @return Polygon
- */
- private Polygon arrow(Point2d pos, Vector2d dir, double s, double r) {
- dir.normalize();
- dir.scale(s);
- Vector2d vec = new Vector2d(-dir.y, dir.x);
- dir.scale(2 * r);
- Polygon polygon = new Polygon();
- polygon.addPoint((int) (pos.x + vec.x), (int) (pos.y + vec.y));
- polygon.addPoint((int) (pos.x + dir.x), (int) (pos.y + dir.y));
- polygon.addPoint((int) (pos.x - vec.x), (int) (pos.y - vec.y));
- return polygon;
- }
- private Point2d makePoint2d(double t,int startX, int startY, int xPeriod,int yPeriod){
- Point2d ret = new Point2d();
- ret.x = startX + startX *Math.cos((2*Math.PI/xPeriod)*t);
- ret.y = startY + startY *Math.sin((2*Math.PI/yPeriod)*t);
- return ret;
- }
- private Vector2d makeVector2d(double t, int xPeriod,int yPeriod){
- Vector2d ret = new Vector2d();
- ret.x = -1*(2*Math.PI/xPeriod)*Math.sin((2*Math.PI/xPeriod)*t);
- ret.y = (2*Math.PI/yPeriod)*Math.cos((2*Math.PI/yPeriod)*t);
- return ret;
- }
- private int Kgv(int xPeriod, int yPeriod) {
- int tmp = xPeriod * yPeriod;
- return tmp/ggt(xPeriod, yPeriod);
- }
- /**
- * kleinstes gemeinsames Vielfaches
- * groesster gemeinsamer Teiler
- * @param a Zahl 1
- * @param b Zahl 2
- * @return ggT
- */
- private int ggt(int a, int b) {
- if(a % b == 0)
- return b;
- else
- return ggt(b, a % b);
- }
- }
- }