package jadex.bdi.examples.cleanerworld.cleaner;
import jadex.application.space.envsupport.environment.ISpaceObject;
import jadex.application.space.envsupport.environment.space2d.Space2D;
import jadex.application.space.envsupport.math.IVector2;
import jadex.bdi.runtime.IBDIInternalAccess;
import jadex.bdi.runtime.IExpression;
import jadex.bdi.runtime.IGoal;
import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.commons.IFuture;
import jadex.commons.concurrent.SwingDefaultResultListener;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JPanel;
/**
* Panel for showing the cleaner world view.
*/
class CleanerPanel extends JPanel
{
//-------- attributes --------
/** The cleaner agent. */
protected IExternalAccess agent;
/** The latest world view information. */
protected DrawData drawdata;
/** Flag to indicate that the draw data is currently updated to avoid multiple updates in parallel. */
protected boolean updating;
//-------- constructors --------
/**
* Create a cleaner panel.
*/
public CleanerPanel(IExternalAccess agent)
{
this.agent = agent;
}
//-------- JPanel methods --------
/**
* Paint the world view.
*/
protected void paintComponent(Graphics g)
{
if(!updating)
{
updating = true;
try
{
IFuture fut = agent.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess bia = (IBDIInternalAccess)ia;
DrawData drawdata = new DrawData();
drawdata.daytime = ((Boolean)bia.getBeliefbase().getBelief("daytime").getFact()).booleanValue();
drawdata.visited_positions = (MapPoint[])bia.getBeliefbase().getBeliefSet("visited_positions").getFacts();
drawdata.max_quantity = ((MapPoint)((IExpression)bia.getExpressionbase().getExpression("query_max_quantity")).execute()).getQuantity();
drawdata.xcnt = ((Integer[])bia.getBeliefbase().getBeliefSet("raster").getFacts())[0].intValue();
drawdata.ycnt = ((Integer[])bia.getBeliefbase().getBeliefSet("raster").getFacts())[1].intValue();
drawdata.cleaners = (ISpaceObject[])bia.getBeliefbase().getBeliefSet("cleaners").getFacts();
drawdata.chargingstations = (ISpaceObject[])bia.getBeliefbase().getBeliefSet("chargingstations").getFacts();
drawdata.wastebins = (ISpaceObject[])bia.getBeliefbase().getBeliefSet("wastebins").getFacts();
drawdata.wastes = (ISpaceObject[])bia.getBeliefbase().getBeliefSet("wastes").getFacts();
drawdata.my_vision = ((Double)bia.getBeliefbase().getBelief("my_vision").getFact()).doubleValue();
drawdata.my_chargestate = ((Double)bia.getBeliefbase().getBelief("my_chargestate").getFact()).doubleValue();
drawdata.myself = (ISpaceObject)bia.getBeliefbase().getBelief("myself").getFact();
drawdata.my_location = (IVector2)drawdata.myself.getProperty("position");
drawdata.my_waste = drawdata.myself.getProperty("waste")!=null;
IGoal[] goals = (IGoal[])bia.getGoalbase().getGoals("achievemoveto");
drawdata.dests = new IVector2[goals.length];
for(int i=0; i<goals.length; i++)
{
drawdata.dests[i] = (IVector2)goals[i].getParameter("location").getValue();
}
return drawdata;
}
});
fut.addResultListener(new SwingDefaultResultListener()
{
public void customResultAvailable(Object source, Object result)
{
CleanerPanel.this.drawdata = (DrawData)result;
updating = false;
}
public void customExceptionOccurred(Object source, Exception exception)
{
// exception.printStackTrace();
// updating = false; // Keep to false to disable any more updates
}
});
}
catch(ComponentTerminatedException e)
{
// Keep updating to false to disable any more updates
}
}
if(drawdata!=null)
{
// Paint background (dependent on daytime).
Rectangle bounds = getBounds();
g.setColor(drawdata.daytime ? Color.lightGray : Color.darkGray);
g.fillRect(0, 0, bounds.width, bounds.height);
// Paint map points
double cellh = 1/(double)drawdata.ycnt;
double cellw = 1/(double)drawdata.xcnt;
for(int i=0; i<drawdata.visited_positions.length; i++)
{
Point p = onScreenLocation(drawdata.visited_positions[i].getLocation(), bounds);
int h = 1;
if(drawdata.max_quantity>0)
h = (int)(((double)drawdata.visited_positions[i].getQuantity())*cellh/drawdata.max_quantity*bounds.height);
int y = (int)(p.y+cellh/2*bounds.height-h);
g.setColor(new Color(54, 10, 114));
//System.out.println("h: "+h);
g.fillRect(p.x+(int)(cellw*0.3*bounds.width), y,
Math.max(1, (int)(cellw/10*bounds.width)), h);
}
for(int i=0; i<drawdata.visited_positions.length; i++)
{
Point p = onScreenLocation(drawdata.visited_positions[i].getLocation(), bounds);
int h = (int)(drawdata.visited_positions[i].getSeen()*cellh*bounds.height);
int y = (int)(p.y+cellw/2*bounds.height-h);
g.setColor(new Color(10, 150, 150));
//System.out.println("h: "+h);
g.fillRect(p.x+(int)(cellw*0.4*bounds.width), y,
Math.max(1, (int)(cellw/10*bounds.width)), h);
}
// Paint the cleaners.
for(int i=0; i<drawdata.cleaners.length; i++)
{
// Paint agent.
Point p = onScreenLocation((IVector2)drawdata.cleaners[i].getProperty(Space2D.PROPERTY_POSITION), bounds);
int w = (int)(((Double)drawdata.cleaners[i].getProperty("vision_range")).doubleValue()*bounds.width);
int h = (int)(((Double)drawdata.cleaners[i].getProperty("vision_range")).doubleValue()*bounds.height);
g.setColor(new Color(100, 100, 100)); // Vision
g.fillOval(p.x-w, p.y-h, w*2, h*2);
g.setColor(new Color(50, 50, 50, 180));
g.fillOval(p.x-3, p.y-3, 7, 7);
g.drawString(drawdata.cleaners[i].getProperty(ISpaceObject.PROPERTY_OWNER).toString(),
p.x+5, p.y-5);
g.drawString("battery: " + (int)(((Double)drawdata.cleaners[i].getProperty("chargestate")).doubleValue()*100.0) + "%",
p.x+5, p.y+5);
g.drawString("waste: " + (drawdata.cleaners[i].getProperty("waste")!=null ? "yes" : "no"),
p.x+5, p.y+15);
}
// Draw me additionally.
if(drawdata.my_location!=null)
{
// Paint agent.
Point p = onScreenLocation(drawdata.my_location, bounds);
int w = (int)(drawdata.my_vision*bounds.width);
int h = (int)(drawdata.my_vision*bounds.height);
g.setColor(new Color(255, 255, 64, 180)); // Vision
g.fillOval(p.x-w, p.y-h, w*2, h*2);
g.setColor(Color.black); // Agent
g.fillOval(p.x-3, p.y-3, 7, 7);
g.drawString(agent.getComponentIdentifier().getLocalName(),
p.x+5, p.y-5);
g.drawString("battery: " + (int)(drawdata.my_chargestate*100.0) + "%",
p.x+5, p.y+5);
g.drawString("waste: " + (drawdata.my_waste ? "yes" : "no"),
p.x+5, p.y+15);
}
// Paint charge Stations.
for(int i=0; i<drawdata.chargingstations.length; i++)
{
g.setColor(Color.blue);
Point p = onScreenLocation((IVector2)drawdata.chargingstations[i].getProperty(Space2D.PROPERTY_POSITION), bounds);
g.drawRect(p.x-10, p.y-10, 20, 20);
g.setColor(drawdata.daytime ? Color.black : Color.white);
g.drawString(""+drawdata.chargingstations[i].getType(), p.x+14, p.y+5);
}
// Paint waste bins.
for(int i=0; i<drawdata.wastebins.length; i++)
{
g.setColor(Color.red);
Point p = onScreenLocation((IVector2)drawdata.wastebins[i].getProperty(Space2D.PROPERTY_POSITION), bounds);
g.drawOval(p.x-10, p.y-10, 20, 20);
g.setColor(drawdata.daytime ? Color.black : Color.white);
g.drawString(""+drawdata.wastebins[i].getType()+" ("+drawdata.wastebins[i].getProperty("wastes")+"/"+drawdata.wastebins[i].getProperty("capacity")+")", p.x+14, p.y+5);
}
// Paint waste.
for(int i=0; i<drawdata.wastes.length; i++)
{
g.setColor(Color.red);
IVector2 pos = (IVector2)drawdata.wastes[i].getProperty(Space2D.PROPERTY_POSITION);
if(pos!=null)
{
Point p = onScreenLocation(pos, bounds);
g.fillOval(p.x-3, p.y-3, 7, 7);
}
}
// Paint movement targets.
for(int i=0; i<drawdata.dests.length; i++)
{
if(drawdata.dests[i]!=null) // Hack!!! may want to move to null due to asynchronous update of waste position.
{
Point p = onScreenLocation(drawdata.dests[i], bounds);
g.setColor(Color.black);
g.drawOval(p.x-5, p.y-5, 10, 10);
g.drawLine(p.x-7, p.y, p.x+7, p.y);
g.drawLine(p.x, p.y-7, p.x, p.y+7);
}
}
}
}
//-------- helper methods --------
/**
* Get the on screen location for a location in the world.
*/
protected static Point onScreenLocation(IVector2 loc, Rectangle bounds)
{
assert loc!=null;
assert bounds!=null;
return new Point((int)(bounds.width*loc.getXAsDouble()),
(int)(bounds.height*(1.0-loc.getYAsDouble())));
}
//-------- helper classes --------
/**
* Data for drawing.
*/
public static class DrawData
{
// Allow object being transferred as XML using public fields.
public static boolean XML_INCLUDE_FIELDS = true;
public boolean daytime;
public MapPoint[] visited_positions;
public double max_quantity;
public int xcnt;
public int ycnt;
public ISpaceObject[] cleaners;
public double chargestate;
public IVector2 my_location;
public double my_vision;
public double my_chargestate;
public boolean my_waste;
public ISpaceObject myself;
public ISpaceObject[] chargingstations;
public ISpaceObject[] wastebins;
public ISpaceObject[] wastes;
public IVector2[] dests;
}
}