/*********** Node ********************/ class Node { /* constants definition */ public static final int NEUTRAL = 0; public static final int Head = 1; public static final int Tail = 2; public static final int Head_CORE = 3; public static final int Tail_CORE = 4; public static final int ANTENNA_CORE = 0; public static final int ANTENNA_BRANCH = 0; public static final int ANTENNA_LEEF = 0; public static final float fdRange = 50.0; /* constants definition end */ /* external parameters */ public Point2D pPosition; public Point2D pDirection; int iRadius; int type = NEUTRAL; /* external parameters end */ /* internal parameters */ // movements public Point2D pDestination; public float fUrgeToMove; public Point2D pRepulsion; public Point2D pAttraction; // circadian rhythm public float fCircadianRhythm; public float fFrequency; public float fPulse; // emotion public float fAngry; public float fHungry; public float fPanic; public float fRelaxed; public float fIntellectual; /* internal parameters end */ /* mutation parameters start*/ public float fNeutralGeneInducer = 0.; public float fHeadGeneInducer = 0.; public float fTailGeneInducer = 0.; public float fHeadCoreGeneExpression = 0.; public float fTailCoreGeneExpression = 0.; /* mutation parameters end */ public Node(){ pPosition = new Point2D.Float(); pDestination = new Point2D.Float(); pRepulsion = new Point2D.Float(); pAttraction = new Point2D.Float(); pDirection = new Point2D.Float(); iRadius = 10; fAngry = 0.0; fHungry = 0.0; fPanic = 0.0; fRelaxed = 0.0; fIntellectual = 0.5; fUrgeToMove = random(2.0); fCircadianRhythm = random(1.0); fFrequency = random(0.02); } public void setType(int type){ this.type = type; if(type == NEUTRAL){ iRadius = 10; } else if(type== Head){ iRadius = 10; } else if(type== Head_CORE){ iRadius = 10; } else if(type== Tail_CORE){ iRadius = 10; } else if(type == Tail){ iRadius = 10; } } public float distanceTo(Node node){ return (float)pPosition.distance(node.pPosition); } public void getSignalFrom(Node node){ float distance = distanceTo(node); if(this.type == NEUTRAL || this.type == Head || this.type == Tail){ // Gene expression if(node.type == Head_CORE){ fHeadGeneInducer = accelerate(fHeadGeneInducer); fNeutralGeneInducer = 0.9; float tmpDx = (float)(pDirection.getX() + ( node.pPosition.getX() - pPosition.getX() ) /50.0); float tmpDy = (float)(pDirection.getY() + ( node.pPosition.getY() - pPosition.getY() ) /50.0); if(tmpDx < -fdRange ) tmpDx = -fdRange; if(tmpDx > fdRange ) tmpDx = fdRange; if(tmpDy < -fdRange ) tmpDy = -fdRange; if(tmpDy > fdRange ) tmpDy = fdRange; pDirection.setLocation(tmpDx, tmpDy); } else if(node.type == Tail_CORE){ fTailGeneInducer = accelerate(fTailGeneInducer); fNeutralGeneInducer = 0.9; float tmpDx = (float)(pDirection.getX() + ( node.pPosition.getX() - pPosition.getX() ) /50.0); float tmpDy = (float)(pDirection.getY() + ( node.pPosition.getY() - pPosition.getY() ) /50.0); if(tmpDx < -fdRange ) tmpDx = -fdRange; if(tmpDx > fdRange ) tmpDx = fdRange; if(tmpDy < -fdRange ) tmpDy = -fdRange; if(tmpDy > fdRange ) tmpDy = fdRange; pDirection.setLocation(tmpDx, tmpDy); } else if (node.type == NEUTRAL ){ fNeutralGeneInducer = mixValues(fNeutralGeneInducer, node.fNeutralGeneInducer, distance); } else if(this.type == Head && node.type == Head){ } } float lineParam = (fHeadGeneInducer+node.fHeadGeneInducer); if( lineParam > 0.1){ stroke(100, 200, 200,lineParam * 255); line((int)this.pPosition.getX(), (int)this.pPosition.getY(), (int)node.pPosition.getX(), (int)node.pPosition.getY()); } lineParam = (fTailGeneInducer+node.fTailGeneInducer); if( lineParam > 0.1){ stroke(200, 200, 200,lineParam * 255); line((int)this.pPosition.getX(), (int)this.pPosition.getY(), (int)node.pPosition.getX(), (int)node.pPosition.getY()); } // Syncronizing internal states fUrgeToMove = mixValues(fUrgeToMove, node.fUrgeToMove, distance); fCircadianRhythm = mixValues(fCircadianRhythm, node.fCircadianRhythm, distance); fFrequency = mixValues(fFrequency, node.fFrequency, distance); fAngry = mixValues(fAngry, node.fAngry, distance); fHungry = mixValues(fHungry, node.fHungry, distance); fPanic = mixValues(fPanic, node.fPanic, distance); fRelaxed = mixValues(fRelaxed, node.fRelaxed, distance); // Physical interaction // Repulsion if(distance < iRadius + node.iRadius/2){ float D = (float)(pPosition.distance(node.pPosition.getX(), node.pPosition.getY())); float tmpX = (float)(pRepulsion.getX()+ (pPosition.getX() - node.pPosition.getX()) / D * iRadius/5); float tmpY = (float)(pRepulsion.getY()+ (pPosition.getY() - node.pPosition.getY()) / D * iRadius/5); pRepulsion.setLocation( tmpX, tmpY); } // Attraction else { // float tmpX = (float)(pAttraction.getX() +(-node.pPosition.getX() + pPosition.getX())/300.0); // float tmpY = (float)(pAttraction.getY() +(-node.pPosition.getY() + pPosition.getY())/300.0); // } float tmpDx = (float)(pDirection.getX() + ( node.pPosition.getX() - pPosition.getX() ) /50.0); float tmpDy = (float)(pDirection.getY() + ( node.pPosition.getY() - pPosition.getY() ) /50.0); if(tmpDx < -fdRange ) tmpDx = -fdRange; if(tmpDx > fdRange ) tmpDx = fdRange; if(tmpDy < -fdRange ) tmpDy = -fdRange; if(tmpDy > fdRange ) tmpDy = fdRange; pDirection.setLocation(tmpDx, tmpDy); float tmpDist = distance; float distX = mixValues((float)pDestination.getX(), (float)node.pDestination.getX(), tmpDist); float distY = mixValues((float)pDestination.getY(), (float)node.pDestination.getY(), tmpDist); pDestination.setLocation(distX, distY); tmpDist = distance; distX = mixValues((float)pDestination.getX(), (float)node.pDestination.getX(), tmpDist); distY = mixValues((float)pDestination.getY(), (float)node.pDestination.getY(), tmpDist); pDestination.setLocation(distX, distY); fIntellectual = accelerate(fIntellectual); fPulse = cos(2*PI*fCircadianRhythm); } public float mixValues(float src, float ingredient, float distance){ float retval = 0; if(distance < 1.0) distance= 2.0; retval = src + (ingredient - src) / distance; return retval; } public void moveToDestination(){ float tmpX = (float)(pPosition.getX() + (pDestination.getX() - pPosition.getX())/300. * fUrgeToMove); float tmpY = (float)(pPosition.getY() + (pDestination.getY() - pPosition.getY())/300. * fUrgeToMove); if(tmpX < 0) tmpX = 0; else if(tmpX > width) tmpX = width; if(tmpY < 0) tmpY = 0; else if(tmpY > height) tmpY = height; pPosition.setLocation(tmpX, tmpY); } public void moveByRepulsion(){ float tmpX = (float)(pPosition.getX() + pRepulsion.getX()); float tmpY = (float)(pPosition.getY() + pRepulsion.getY()); if(tmpX < 0) tmpX = 0; else if(tmpX > width) tmpX = width; if(tmpY < 0) tmpY = 0; else if(tmpY > height) tmpY = height; pPosition.setLocation(tmpX, tmpY); } public void moveByAttraction(){ float tmpX = (float)(pPosition.getX() + pAttraction.getX()); float tmpY = (float)(pPosition.getY() + pAttraction.getY()); if(tmpX < 0) tmpX = width; else if(tmpX > width) tmpX = 0.0; if(tmpY < 0) tmpY = height; else if(tmpY > height) tmpY =0.; pPosition.setLocation(tmpX, tmpY); } public void nextCycle(){ fCircadianRhythm += fFrequency; /* mutation state transition */ // fHeadCoreGeneExpression = decelerate(fHeadCoreGeneExpression); // fTailCoreGeneExpression = decelerate(fTailCoreGeneExpression); if(type == NEUTRAL){ if(fHeadGeneInducer > 0.6) setType(Head); else if(fTailGeneInducer > 0.6) setType(Tail); else setType(NEUTRAL); if(random(1000) < 1.0){ fHeadCoreGeneExpression = 1.0; if(fNeutralGeneInducer > 0.01) ; else setType(Head_CORE); } if(random(1000) < 1.0){ fTailCoreGeneExpression = 1.0; if(fNeutralGeneInducer > 0.01) ; else setType(Tail_CORE); } } else if(type == Head){ pDestination.setLocation( pDestination.getX() - pDirection.getX()*0.2, pDestination.getY() - pDirection.getY()*0.2); if(fHeadGeneInducer < 0.1) setType(NEUTRAL); } else if(type == Tail){ pDestination.setLocation( pDestination.getX() + pDirection.getX()*0.5, pDestination.getY() + pDirection.getY()*0.5); if(fTailGeneInducer < 0.1) setType(NEUTRAL); } else if(type == Head_CORE){ if(fIntellectual > 0.3 && pDirection.distance(0., 0.) < 0.5) fHeadCoreGeneExpression = accelerate(fHeadCoreGeneExpression); else fHeadCoreGeneExpression = decelerate(fHeadCoreGeneExpression); if(fHeadCoreGeneExpression < 0.03){ setType(NEUTRAL); } } else if(type == Tail_CORE){ if(fIntellectual > 0.3 && pDirection.distance(0., 0.) < 0.5) fTailCoreGeneExpression = accelerate(fTailCoreGeneExpression); else fTailCoreGeneExpression = decelerate(fTailCoreGeneExpression); if(fTailCoreGeneExpression < 0.03){ setType(NEUTRAL); } } fTailGeneInducer = fTailGeneInducer * 0.97; fHeadGeneInducer = fHeadGeneInducer * 0.97; fNeutralGeneInducer = fNeutralGeneInducer * 0.8; moveToDestination(); moveByRepulsion(); /* energy diffusion */ pDirection.setLocation( decelerate((float)pDirection.getX()), decelerate((float)pDirection.getY())); fFrequency = convergeTo(0.05, fFrequency); fIntellectual = decelerate(fIntellectual); pRepulsion.setLocation(pRepulsion.getX()*0.5, pRepulsion.getY()*0.5); pAttraction.setLocation(pAttraction.getX()*0.5, pAttraction.getY()*0.5); } float convergeTo(float dest, float val){ if(val > dest) val = decelerate(val); else val = accelerate(val); return val; } float accelerate(float val){ int sign = 1; if( val < 0.0){ sign = -1; val = -val; } if(val < 0.05) val = 0.1; if(val < 1.0){ val = val * 1.05; } if(val > 1.0) val = 1.0; return sign * val; } float decelerate(float val){ int sign = 1; if( val < 0.0){ sign = -1; val = -val; } if(val > 0.0){ val = val * 0.98; } if(val < 0.001) val = 0.0; return sign*val; } public void draw(int iRepType){ noStroke(); if(iRepType == 0){ fill(0, 0, 0, 100); drawAntenna(); // if(type == NEUTRAL){ // fill(0, 0, 0); // ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius, iRadius);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); fill(0, 200 * fHeadGeneInducer,(int)(40*fPulse+128));//); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius*(1. + fHeadGeneInducer), iRadius*(1. + fHeadGeneInducer));//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); fill(0, 50,(int)(10*fPulse+20));//); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius*(1.+fHeadGeneInducer)/2, iRadius*(1.+fHeadGeneInducer)/2);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); /* } else if(type == Head){ fill(255, 50, 50, 200); fill(0, 200 * fIntellectual,(int)(128*fPulse+128));//); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius, iRadius);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); */ /* beginShape(POLYGON); vertex((float)( pDirection.getX() / 10.0 + pPosition.getX()),(float)(pDirection.getY() / 10.0 + pPosition.getY())); vertex((float)( -pDirection.getY() / 2.0 + pPosition.getX()), (float)(pDirection.getX() / 2.0 + pPosition.getY())); vertex((float)( -pDirection.getX() / 10.0 + pPosition.getX()),(float)(-pDirection.getY() / 10.0 + pPosition.getY())); vertex((float)( pDirection.getY() / 2.0 + pPosition.getX()), (float)(-pDirection.getX() / 2.0 +pPosition.getY())); endShape(); */ /* } else if(type == Head_CORE){ fill(80, 80, 80, 200); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius, iRadius);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); } else if(type == Tail){ fill(0, 200 * fIntellectual,(int)(128*fPulse+128));//); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius, iRadius);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); */ /* beginShape(POLYGON); vertex((float)( pDirection.getX() / 10.0 + pPosition.getX()),(float)(pDirection.getY() / 10.0 + pPosition.getY())); vertex((float)( -pDirection.getY() / 2.0 + pPosition.getX()), (float)(pDirection.getX() / 2.0 + pPosition.getY())); vertex((float)( -pDirection.getX() / 10.0 + pPosition.getX()),(float)(-pDirection.getY() / 10.0 + pPosition.getY())); vertex((float)( pDirection.getY() / 2.0 + pPosition.getX()), (float)(-pDirection.getX() / 2.0 +pPosition.getY())); endShape(); */ /* } else if(type == Tail_CORE){ fill(80, 80, 80, 200); ellipse((float)pPosition.getX(), (float)pPosition.getY(), iRadius, iRadius);//iRadius * -fPulse +iRadius*2, iRadius * -fPulse +iRadius*2); } */ } } public void drawAntenna(){ beginShape(POLYGON); vertex((float)( -pDirection.getX()* (fPulse/5.+ fTailGeneInducer*5) /3. + pPosition.getX() ),(float)(-pDirection.getY()* (fPulse/5.+ fTailGeneInducer*5) /3. + pPosition.getY())); vertex((float)( -pDirection.getY() / 15.0 + pPosition.getX()), (float)(pDirection.getX() / 15.0 + pPosition.getY())); vertex((float)( pDirection.getY() / 15.0 + pPosition.getX()), (float)(-pDirection.getX() / 15.0 +pPosition.getY())); endShape(); } }