All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sim.app.woims.Woim Maven / Gradle / Ivy

Go to download

MASON is a fast discrete-event multiagent simulation library core in Java, designed to be the foundation for large custom-purpose Java simulations, and also to provide more than enough functionality for many lightweight simulation needs. MASON contains both a model library and an optional suite of visualization tools in 2D and 3D.

The newest version!
/*
  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.woims;

import sim.util.*;
import sim.engine.*;
import java.awt.*;
import sim.portrayal.*;
import java.awt.geom.*;

public /*strictfp*/ class Woim extends SimplePortrayal2D implements Steppable
    {
    private static final long serialVersionUID = 1;

    public static final double CENTROID_DISTANCE = 20 * WoimsDemo.DIAMETER;
    public static final double AVOID_DISTANCE = 16 * WoimsDemo.DIAMETER;
    public static final double COPY_SPEED_DISTANCE = 40 * WoimsDemo.DIAMETER;

    public static final double OBSTACLE_AVOID_COEF = 1.05;
    public static final double OBSTACLE_FAST_AVOID_COEF = 1.5;

    public static final double MAX_DISTANCE = /*Strict*/Math.max( CENTROID_DISTANCE,
        /*Strict*/Math.max( AVOID_DISTANCE,
            COPY_SPEED_DISTANCE ) );

    public static final double ADJUSTMENT_RATE = 0.025;
    public static final double MIN_VELOCITY = 0.25;
    public static final double MAX_VELOCITY = 0.75;

    // initialize the woim
    public Woim() 
        {
        ond = /*Strict*/Math.random()*2*Math.PI;
        ondSpeed = 0.05 + /*Strict*/Math.random()*0.15;
        setNumberOfLinks( numLinks );
        }

    // squared distance between two points
    public final double distanceSquared( final Vector2D loc1, final Vector2D loc2 )
        {
        return( (loc1.x-loc2.x)*(loc1.x-loc2.x)+(loc1.y-loc2.y)*(loc1.y-loc2.y) );
        }

    // squared distance between two points
    public final double distanceSquared( final Vector2D loc1, final Double2D loc2 )
        {
        return( (loc1.x-loc2.x)*(loc1.x-loc2.x)+(loc1.y-loc2.y)*(loc1.y-loc2.y) );
        }

    // squared distance between two points
    public final double distanceSquared( final double x1, final double y1, final double x2, final double y2 )
        {
        return ((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
        }

    // dot product between two vectors
    public final double dotproduct( final Vector2D loc1, final Vector2D loc2 )
        {
        return loc1.x*loc2.x+loc1.y*loc2.y;
        }

    // initializes distances to closeby woims. it should be called a single time in the step function at each timestep.
    Bag nearbyWoims;
    double[] distSqrTo;
    void preprocessWoims( final WoimsDemo state, Double2D pos, double distance )
        {
        nearbyWoims = state.woimsEnvironment.getNeighborsWithinDistance( pos, distance );
/*
  if( nearbyWoims == null )
  {
  return;
  }
*/
        distSqrTo = new double[nearbyWoims.numObjs];
        for( int i = 0 ; i < nearbyWoims.numObjs ; i++ )
            {
            Woim p = (Woim)(nearbyWoims.objs[i]);
            distSqrTo[i] = distanceSquared(
                pos.x,pos.y,p.x,p.y);
            }
        }

    // returns a vector towards the center of the flock
    public Vector2D towardsFlockCenterOfMass( final WoimsDemo state )
        {
        if( nearbyWoims == null )
            return new Vector2D( 0, 0 );
        Vector2D mean = new Vector2D( 0, 0 );
        int n = 0;
        for( int i = 0 ; i < nearbyWoims.numObjs ; i++ )
            {
            if( nearbyWoims.objs[i] != this &&
                distSqrTo[i] <= CENTROID_DISTANCE * CENTROID_DISTANCE &&
                distSqrTo[i] > AVOID_DISTANCE * AVOID_DISTANCE )
                {
                Woim p = (Woim)(nearbyWoims.objs[i]);
                mean = mean.add(new Double2D(p.x,p.y));
                n++;
                }
            }
        if( n == 0 )
            return new Vector2D( 0, 0 );
        else
            {
            mean = mean.amplify( 1.0 / n );
            mean = mean.subtract( woimPosition );
            return mean.normalize();
            }
        }

    // returns a vector away from woims that are too close
    public Vector2D awayFromCloseBys( final WoimsDemo state )
        {
        if( nearbyWoims == null )
            return new Vector2D( 0, 0 );
        Vector2D away = new Vector2D( 0, 0 );
        for( int i = 0 ; i < nearbyWoims.numObjs ; i++ )
            {
            if( nearbyWoims.objs[i] != this &&
                distSqrTo[i] <= AVOID_DISTANCE * AVOID_DISTANCE )
                {
                Woim p = (Woim)(nearbyWoims.objs[i]);
                Vector2D temp = woimPosition.subtract(new Double2D(p.x,p.y));
                temp = temp.normalize();
                away = away.add( temp ); 
                }
            }
        return away.normalize();
        }

    // returns the mean speed of the nearby woims
    public Vector2D matchFlockSpeed( final SimState state )
        {
        if( nearbyWoims == null )
            return new Vector2D( 0, 0 );
        Vector2D mean = new Vector2D( 0, 0 );
        int n = 0;
        for( int i = 0 ; i < nearbyWoims.numObjs ; i++ )
            {
            if( nearbyWoims.objs[i] != this &&
                distSqrTo[i] <= COPY_SPEED_DISTANCE * COPY_SPEED_DISTANCE &&
                distSqrTo[i] > AVOID_DISTANCE * AVOID_DISTANCE )
                {
                mean = mean.add( ((Woim)(nearbyWoims.objs[i])).velocity );
                n++;
                }
            }
        if( n == 0 )
            return new Vector2D( 0, 0 );
        else
            {
            mean = mean.amplify( 1.0 / n );
            return mean.normalize();
            }
        }

    // returns a random directions
    public Vector2D randomDirection( final SimState state )
        {
        Vector2D temp = new Vector2D( 1.0 - 2.0 * state.random.nextDouble(),
            1.0 - 2.0 * state.random.nextDouble() );
        return temp.setLength( MIN_VELOCITY + state.random.nextDouble()*(MAX_VELOCITY-MIN_VELOCITY) );
        }

    // returns the oscilation vector
    double ond;
    double ondSpeed;
    public Vector2D niceUndulation( final SimState state )
        {
        ond += ondSpeed;
        if( ond > 7 )
            ond -= 2*Math.PI;
        double angle = /*Strict*/Math.cos( ond );
        Vector2D temp = velocity;
        double velA = /*Strict*/Math.atan2( temp.y, temp.x );
        velA = velA + (Math.PI/2)*angle;
        return new Vector2D( /*Strict*/Math.cos(velA), /*Strict*/Math.sin(velA) );
        }

    // returns a direction away from obstacles
    public Vector2D avoidObstacles( final SimState state )
        {
        double[][] info = WoimsDemo.obstInfo;
        if( info == null || info.length == 0 )
            return new Vector2D( 0, 0 );
            
        Vector2D away = new Vector2D( 0, 0 );
        for( int i = 0 ; i < info.length ; i++ )
            {
            double dist = /*Strict*/Math.sqrt( (woimPosition.x-info[i][1])*(woimPosition.x-info[i][1]) +
                (woimPosition.y-info[i][2])*(woimPosition.y-info[i][2]) );
            if( dist <= info[i][0]+AVOID_DISTANCE )
                {
                Vector2D temp = woimPosition.subtract( new Vector2D( info[i][1], info[i][2] ) );
                temp = temp.normalize();
                away = away.add( temp ); 
                }
            }
        return away.normalize();
        }

    protected Vector2D woimPosition = new Vector2D( 0, 0 );

    public void step( final SimState state )
        {
        WoimsDemo bd = (WoimsDemo)state;
                {
                Double2D temp = new Double2D(x,y);  //bd.environment.getObjectLocation( this );
                woimPosition.x = x;
                woimPosition.y = y;
                preprocessWoims( bd, temp, MAX_DISTANCE );
                }

        Vector2D vel = new Vector2D( 0, 0 );
        vel = vel.add( avoidObstacles(bd).amplify( 1.5 ) );
        vel = vel.add( towardsFlockCenterOfMass(bd).amplify(0.5) );
        vel = vel.add( matchFlockSpeed(bd).amplify(0.5) );
        vel = vel.add( awayFromCloseBys(bd).amplify(1.5) );
        if( vel.length() <= 1.0 )
            {
            vel = vel.add( niceUndulation(bd).amplify(0.5) );
            vel = vel.add( randomDirection(bd).amplify(0.25) );
            }

        double vl = vel.length();
        if( vl < MIN_VELOCITY )
            vel = vel.setLength( MIN_VELOCITY );
        else if( vl > MAX_VELOCITY )
            vel = vel.setLength( MAX_VELOCITY );
        vel = new Vector2D( (1-ADJUSTMENT_RATE)*velocity.x + ADJUSTMENT_RATE*vel.x,
            (1-ADJUSTMENT_RATE)*velocity.y + ADJUSTMENT_RATE*vel.y );
        velocity = vel;
        Double2D desiredPosition = new Double2D( woimPosition.x+vel.x*WoimsDemo.TIMESTEP,
            woimPosition.y+vel.y*WoimsDemo.TIMESTEP );
        bd.setObjectLocation( this, desiredPosition );
        updateLinkPosition();
        }

    public double x;
    public double y;
    
    Vector2D[] lastPos;
    Color[] colors;
    int numLinks = 7;
    public int getNumberOfLinks() { return numLinks; }
    public void setNumberOfLinks( int n )
        {
        if( numLinks == n && colors != null )
            return;
        if( n <= 0 )
            return;
        if( n > WoimsDemo.MAX_LINKS )
            n = WoimsDemo.MAX_LINKS;
        numLinks = n;
        lastPos = new Vector2D[numLinks];
        colors = new Color[numLinks];
        for( int i = 0 ; i < colors.length ; i++ )
            colors[i] = new Color( (int) (63+(192.0*(colors.length-i))/colors.length), 0, 0 );
        updateLinkPosition();
        }

    protected double orientation;
    protected Vector2D velocity = new Vector2D( 0, 0 );
    protected Vector2D acceleration = new Vector2D( 0, 0 );

    // drawing graphics
    void drawLink( final Graphics2D graphics, double x, double y, double rx, double ry, final Color color)
        {
        graphics.setColor( color );
        graphics.fillOval( (int)(x-rx/2.0), (int)(y-ry/2.0), (int)(rx), (int)(ry));
        }

    public void updateLinkPosition()
        {
        double centerx, centery;


        // the head!
        centerx = x;
        centery = y;
        lastPos[0] = new Vector2D( centerx, centery );
        for( int i = 1 ; i < numLinks ; i++ )
            {
            if( lastPos[i] == null )
                {
                Vector2D temp = velocity.normalize().amplify(-1.0);
                centerx = lastPos[i-1].x+1.0*temp.x;
                centery = lastPos[i-1].y+1.0*temp.y;
                lastPos[i] = new Vector2D( centerx, centery );
                }
            else
                {
                Vector2D temp = lastPos[i-1].subtract( lastPos[i] );
                temp = temp.setLength( 1.0 );
                temp = lastPos[i-1].subtract( temp );
                lastPos[i] = temp;
                }
            }
        }

    public final void draw(Object object,  final Graphics2D graphics, final DrawInfo2D info)
        {
        if( lastPos == null )
            return;
        for( int i = 0 ; i < numLinks ; i++ )
            if( lastPos[i] != null )
                drawLink( graphics,
                    info.draw.x+info.draw.width*(lastPos[i].x-lastPos[0].x),
                    info.draw.y+info.draw.height*(lastPos[i].y-lastPos[0].y),
                    info.draw.width,
                    info.draw.height,
                    colors[i] );
        }

    /** If drawing area intersects selected area, add last portrayed object to the bag */
    public boolean hitObject(Object object, DrawInfo2D info)
        {
        if( lastPos == null )
            return false;
        for( int i = 0 ; i < numLinks ; i++ )
            if( lastPos[i] != null )
                {
                Ellipse2D.Double ellipse = new Ellipse2D.Double(
                    info.draw.x+info.draw.width*(lastPos[i].x-lastPos[0].x),
                    info.draw.y+info.draw.height*(lastPos[i].y-lastPos[0].y),
                    info.draw.width,
                    info.draw.height );
                if( ellipse.intersects( info.clip.x, info.clip.y, info.clip.width, info.clip.height ) )
                    {
                    return true;
                    }
                }
        return false;
        }
    }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy