/*
* Javlov - a Java toolkit for reinforcement learning with multi-agent support.
*
* Copyright (c) 2009 Matthijs Snel
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package net.javlov.world.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JPanel;
import net.javlov.world.AgentBody;
import net.javlov.world.Body;
import net.javlov.world.World;
public class WorldView extends JPanel implements Observer, MouseWheelListener, ActionListener {
private static final long serialVersionUID = -193232841584505904L;
protected World model;
protected List<BodyView> bodies;
private AffineTransform scaleXform, saveXform;
private double modelWidth, modelHeight;
public WorldView(World w) {
bodies = new ArrayList<BodyView>();
setModel(w);
addMouseWheelListener(this);
scaleXform = new AffineTransform();
}
public void add(Body b) {
//TODO use factory
if ( b instanceof AgentBody )
bodies.add(new AgentBodyView(b));
else {
bodies.add(new BodyView(b));
}
}
public World getModel() {
return model;
}
public void setModel(World model) {
bodies.clear();
List<Body> modelBodies = model.getObjects();
for ( int i = 0; i < modelBodies.size(); i++ ) {
add(modelBodies.get(i));
//System.out.println(modelBodies.get(i).getType());
}
this.model = model;
modelWidth = model.getWidth();
modelHeight = model.getHeight();
setPreferredSize(new Dimension((int)modelWidth, (int)modelHeight));
}
/**
* Just invokes paintImmediately to repaint the whole world. Override if anything
* more fancy should be going on, e.g. redrawing only the areas that have changed, which
* makes sense for worlds with few moving objects.
*/
public void draw() {
paintImmediately(0, 0, getWidth(), getHeight());
}
@Override
protected void paintComponent(Graphics g) {
//TODO add possibility to draw joints and contacts
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
saveXform = g2d.getTransform();
g2d.transform(scaleXform);
g2d.setColor(Color.white);
g2d.fillRect(0, 0, (int)modelWidth, (int)modelHeight);
g2d.setColor(Color.black);
for ( BodyView view : bodies ) {
view.draw(g);
}
g2d.setTransform(saveXform);
}
@Override
public void update(Observable o, Object arg) {
//a body was added to the simulation
if ( arg != null && arg instanceof Body )
add((Body)arg);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
scaleXform.scale(1 - e.getWheelRotation()*0.05, 1 - e.getWheelRotation()*0.05);
repaint();
}
@Override
public void actionPerformed(ActionEvent e) {
draw();
}
/**
* Only call this from within paintComponent, otherwise transform may be an old one
* @return
*/
protected AffineTransform getOriginalTransform() {
return saveXform;
}
/**
* Only call this from within paintComponent, otherwise transform may be an old one
* @return
*/
protected AffineTransform getScaleTransform() {
return scaleXform;
}
}