/*
* Simbad - Robot Simulator
* Copyright (C) 2004 Louis Hugues
*
* 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
*
-----------------------------------------------------------------------------
* $Author: sioulseuguh $
* $Date: 2005/08/07 12:24:56 $
* $Revision: 1.17 $
* $Source: /cvsroot/simbad/src/simbad/sim/Agent.java,v $
* - AGent no more derived from CollidableObject
*/
package org.myrobotlab.mapper.sim;
import java.text.DecimalFormat;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TriangleArray;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import org.myrobotlab.mapper.gui.AgentInspector;
import com.sun.j3d.utils.geometry.Cylinder;
import com.sun.j3d.utils.geometry.Primitive;
/**
* This is the base class for all robot and is considered to be a heavy agent.
* <br>
* When deriving a new robot's class from this class, one should override the
* following methods:
* <ul>
* <li>initBehavior : called by the simulator to initialize the controler.</li>
* <li>performBehavior : called by the simulator on each simulation step.</li>
* </ul>
* * Implementation note : the agent doesnt have synchronized methods. All
* thread refering to the agent should do explicit synchronization with
* synchronized(agent){...}.
*
*/
public class Agent extends SimpleAgent {
/** panel dedicated to behavior output - can be null. */
private JPanel panel;
/** window dedicated to behavior output - can be null. */
JInternalFrame window;
/** Link back to agent inspector - can be null */
AgentInspector agentInspector;
/** Kinematic model used by the agent */
protected KinematicModel kinematicModel;
/** Current linear acceleration applied by motors. */
protected Vector3d motorsLinearAcceleration = new Vector3d();
/** Current angular acceleration applied by motors.. */
protected Vector3d motorsAngularAcceleration = new Vector3d();
private DecimalFormat format;
/** Used for frame rate measure */
protected FrameMeter frameMeter;
/**
* Constructs an Agent.
*
* @param pos
* start position in 3D world.
* @param name
* name of the agent.
*/
public Agent(Vector3d pos, String name) {
super(pos, name);
// No UI by default
this.panel = null;
agentInspector = null;
// physical parameters default
height = 0.5f;
radius = 0.3f;
staticFrictionCoefficient = 0;
mass = 50;
// display format for numbers
format = new DecimalFormat();
format.setMaximumFractionDigits(3);
format.setMinimumFractionDigits(3);
format.setPositivePrefix("+");
format.setMinimumIntegerDigits(1);
// Attached a default kinematic
kinematicModel = new DefaultKinematic();
// Performance measure
frameMeter = new FrameMeter();
}
/**
* Returns printable description of the agent.
*
* @return agent description as string.
*/
@Override
public String asString() {
String s = new String();
Vector3d t = v1;
translation.get(t);
s = "class = " + this.getClass().getName() + "\n" + "name \t= " + name + "\n" + "fps instant \t= " + format.format(frameMeter.fps) + "\n" + "fps total \t= "
+ format.format(frameMeter.fpsSinceStart) + "\n" + "counter \t= " + getCounter() + "\n" + "lifetime \t= " + format.format(getLifeTime()) + " s\n"
+ "collision \t= " + this.collisionDetected + "\n" +
// "interaction \t= " + this.interactionDetected+ "\n" +
kinematicModel.toString(format) + "x \t= " + format.format(t.x) + " m\n" + "y \t= " + format.format(t.y) + " m\n" + "z \t= "
+ format.format(t.z) + " m\n" + "odometer \t= " + format.format(odometer) + " m\n";
return s;
}
/** Create 3D geometry. */
@Override
protected void create3D() {
Color3f color = new Color3f(0.0f, 0.8f, 0.0f);
Color3f color2 = new Color3f(1.0f, 0.0f, 0.0f);
// body
Appearance appear = new Appearance();
color.clampMax(0.8f);
material.setDiffuseColor(color);
material.setSpecularColor(black);
appear.setMaterial(material);
int flags = Primitive.GEOMETRY_NOT_SHARED | Primitive.ENABLE_GEOMETRY_PICKING | Primitive.GENERATE_NORMALS;
flags |= Primitive.ENABLE_APPEARANCE_MODIFY;
body = new Cylinder(radius, height, flags, appear);
/*
* // allow geom intersect on each geom of the primitive cylinder
* allowIntersect(body.getShape(Cylinder.BODY));
* allowIntersect(body.getShape(Cylinder.TOP));
*/
// we must be able to change the pick flag of the agent
body.setCapability(Node.ALLOW_PICKABLE_READ);
body.setCapability(Node.ALLOW_PICKABLE_WRITE);
body.setPickable(true);
body.setCollidable(true);
addChild(body);
// direction indicator
float coords[] = { radius / 2, height, -radius / 2, //
radius / 2, height, radius / 2, //
radius, height, 0 //
};
float normals[] = { 0, 1, 0, 0, 1, 0, 0, 1, 0 };
TriangleArray tris = new TriangleArray(coords.length, GeometryArray.COORDINATES | GeometryArray.NORMALS);
tris.setCoordinates(0, coords);
tris.setNormals(0, normals);
appear = new Appearance();
appear.setMaterial(new Material(color2, black, color2, white, 100.0f));
Shape3D s = new Shape3D(tris, appear);
s.setPickable(false);
addChild(s);
// Add bounds for interactions and collision
Bounds bounds = new BoundingSphere(new Point3d(0, 0, 0), radius);
setBounds(bounds);
}
/**
* Creates the UI that may be associated to the agent. If the agent has set a
* Panel with setUIPanel a window is created containing the panel.
*/
JInternalFrame createUIWindow() {
JPanel panel = getUIPanel();
if (panel != null) {
window = new JInternalFrame("Output", false, false, false, false);
window.setContentPane(panel);
window.pack();
} else
window = null;
return window;
}
/** Dispose all resources */
@Override
protected void dispose() {
if (window != null)
window.dispose();
}
public AgentInspector getAgentInspector() {
return agentInspector;
}
protected KinematicModel getKinematicModel() {
return kinematicModel;
}
/**
* Returns the agent's odometer in meters.
*
* @return the agent odometer in meters.
*/
public double getOdometer() {
return odometer;
}
/**
* Gets rotational velocity in radians per second
*/
public final double getRotationalVelocity() {
// because it's one of the default kinematic fucntions we provide it in
// the
// agent's api.
if (kinematicModel instanceof DefaultKinematic)
return ((DefaultKinematic) kinematicModel).getRotationalVelocity();
else
return 0.0;
}
/**
* Gets translational velocity in meter per second.
*/
public final double getTranslationalVelocity() {
// agent's api.
if (kinematicModel instanceof DefaultKinematic)
return ((DefaultKinematic) kinematicModel).getTranslationalVelocity();
else
return 0.0;
}
/**
* Returns the UI panel previously set with <code>setUIPanel</code>
*
* @return the panel
*/
public JPanel getUIPanel() {
return panel;
}
/** called by simulator. */
@Override
protected void initBehavior() {
}
/** called by simulator. */
@Override
protected void initPreBehavior() {
// if there's a ui window show it
if (window != null)
window.toFront();
}
/** called by simulator. */
@Override
protected void performBehavior() {
}
/** called by simulator. */
@Override
protected void performPreBehavior() {
frameMeter.measurePoint(1);
}
/** Resets agent variables */
@Override
protected void reset() {
super.reset();
frameMeter.reset();
}
/** Resets agent variables and position and kinematic */
@Override
protected void resetPosition() {
super.resetPosition();
kinematicModel.reset();
}
public void setAgentInspector(AgentInspector ai) {
agentInspector = ai;
}
protected void setFrameMeterRate(int rate) {
frameMeter.setUpdateRate(rate);
}
/** Sets the kinematic model for this agent */
protected void setKinematicModel(KinematicModel kinematicModel) {
this.kinematicModel = kinematicModel;
}
/** set acceleration applied by motors . */
@Override
protected void setMotorsAcceleration(double dt) {
// TODO CHange this !!!
linearVelocity.set(0, 0, 0);
angularVelocity.set(0, 0, 0);
kinematicModel.update(dt, rotation, instantTranslation, instantRotation);
// derive two times displacement to obtain acceleration
double scale = 1.0 / (dt * dt);// dt non zero
motorsLinearAcceleration.set(instantTranslation);
motorsLinearAcceleration.scale(scale);
motorsAngularAcceleration.set(instantRotation);
motorsAngularAcceleration.scale(scale);
// contribute to general acceleration
linearAcceleration.set(motorsLinearAcceleration);
angularAcceleration.set(motorsAngularAcceleration);
}
/**
* Sets rotational velocity in radians per second.
*/
public final void setRotationalVelocity(double rv) {
// because it's one of the default kinematic fucntions we provide it in
// the
// agent's api.
if (kinematicModel instanceof DefaultKinematic)
((DefaultKinematic) kinematicModel).setRotationalVelocity(rv);
}
/**
* Sets translational velocity in meter per second.
*/
public final void setTranslationalVelocity(double tv) {
// because it's one of the default kinematic fucntions we provide it in
// the
// agent's api.
if (kinematicModel instanceof DefaultKinematic)
((DefaultKinematic) kinematicModel).setTranslationalVelocity(tv);
}
/**
* Add a UI panel to the agent. Typically used for displaying behavior
* outputs. A call to this method will have for consequence the creation of a
* dedicated window.
*
* @param panel
*/
public void setUIPanel(JPanel panel) {
this.panel = panel;
}
}