/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.app.mav;
import sim.portrayal.*;
import sim.engine.*;
import sim.util.*;
// we extend OvalPortrayal2D to steal its hitObjects() code -- but
// we override the draw(...) code to draw our own oval with a little line...
public /*strictfp*/ class Mav implements Steppable, Oriented2D
{
private static final long serialVersionUID = 1;
final static double[] theta = new double[/* 8 */]
{
0*(/*Strict*/Math.PI/180),
45*(/*Strict*/Math.PI/180),
90*(/*Strict*/Math.PI/180),
135*(/*Strict*/Math.PI/180),
180*(/*Strict*/Math.PI/180),
225*(/*Strict*/Math.PI/180),
270*(/*Strict*/Math.PI/180),
315*(/*Strict*/Math.PI/180)
};
final static double[] xd = new double[/* 8 */]
{
/*Strict*/Math.cos(theta[0]),
/*Strict*/Math.cos(theta[1]),
/*Strict*/Math.cos(theta[2]),
/*Strict*/Math.cos(theta[3]),
/*Strict*/Math.cos(theta[4]),
/*Strict*/Math.cos(theta[5]),
/*Strict*/Math.cos(theta[6]),
/*Strict*/Math.cos(theta[7]),
};
final static double[] yd = new double[/* 8 */]
{
/*Strict*/Math.sin(theta[0]),
/*Strict*/Math.sin(theta[1]),
/*Strict*/Math.sin(theta[2]),
/*Strict*/Math.sin(theta[3]),
/*Strict*/Math.sin(theta[4]),
/*Strict*/Math.sin(theta[5]),
/*Strict*/Math.sin(theta[6]),
/*Strict*/Math.sin(theta[7]),
};
public int orientation = 0;
public double x;
public double y;
public double orientation2D() { return theta[orientation]; }
public Mav(int orientation, double x, double y)
{
this.orientation = orientation; this.x = x; this.y = y;
}
public void step(SimState state)
{
final MavDemo mavdemo = (MavDemo)state;
orientation += mavdemo.random.nextInt(3) - 1;
if (orientation > 7) orientation = 0;
if (orientation < 0) orientation = 7;
x += xd[orientation];
y += yd[orientation];
if (x >= mavdemo.width) x = mavdemo.width - 1;
else if (x < 0) x = 0;
if (y >= mavdemo.height) y = mavdemo.height - 1;
else if (y < 0) y = 0;
mavdemo.mavs.setObjectLocation(this,new Double2D(x,y));
act(nearbyMAVs(mavdemo), currentSurface(mavdemo));
}
public void act(double[] sensorReading, int currentSurface)
{
//if (currentSurface == 100) System.out.println("Acting");
}
double[] proximitySensors = new double[8]; // all squared values
/** Re-uses the double[], so don't hang onto it */
public double[] nearbyMAVs(MavDemo mavdemo)
{
for(int i=0;i<8;i++) proximitySensors[i] = Double.MAX_VALUE;
final double d = mavdemo.sensorRangeDistance * mavdemo.sensorRangeDistance;
final Bag nearbyMavs = mavdemo.mavs.getNeighborsWithinDistance(new Double2D(x,y),16,false,false);
for(int i=0;i<nearbyMavs.numObjs;i++)
{
final Mav mav = (Mav)(nearbyMavs.objs[i]);
final double mavDistance = (mav.x-x)*(mav.x-x)+(mav.y-y)*(mav.y-y);
if (mavDistance < d) // it's within our range
{
final int octant = sensorForPoint(mav.x,mav.y); // figure the octant
proximitySensors[octant] = /*Strict*/Math.min(proximitySensors[octant],mavDistance);
}
}
return proximitySensors;
}
/** 0 is the default surface */
public int currentSurface(MavDemo mavdemo)
{
for(int i = 0; i < mavdemo.region.length;i++)
if (mavdemo.region[i].area.contains(
x-mavdemo.region[i].originx,y-mavdemo.region[i].originy))
return mavdemo.region[i].surface;
return 0;
}
// in order to rotate 45/2 degrees counterclockwise around origin
final double sinTheta = /*Strict*/Math.sin(45.0/2*/*Strict*/Math.PI/180);
final double cosTheta = /*Strict*/Math.cos(45.0/2*/*Strict*/Math.PI/180);
public int sensorForPoint(double px, double py)
{
int o = 0;
// translate to origin
px -= x; py -= y;
// rotate 45/2 degrees counterclockwise about the origin
final double xx = px * cosTheta + py * (-sinTheta);
final double yy = px * sinTheta + py * cosTheta;
// Now we've divided it into octants of 0--45, 45--90, etc.
// for each sensor area. The border between octants is
// arbitrarily, not evenly, assigned to the octants, because
// it results in fewer if/then statements/
if (!(xx == 0.0 && yy == 0.0))
{
if (xx > 0) // right side
{
if (yy > 0) // quadrant 1
{
if (xx > yy) o = 0;
else o = 1;
}
else // quadrant 4
{
if (xx > -yy) o = 7;
else o = 6;
}
}
else // left side
{
if (yy > 0) // quadrant 2
{
if (-xx > yy) o = 3;
else o = 2;
}
else // quadrant 3
{
if (-xx > -yy) o = 4;
else o = 5;
}
} // hope I got that right!
}
// now rotate to be relative to MAV's orientation
o += orientation;
if (o >= 8) o = o % 8;
return o;
}
}