コード例 #1
0
void ParticleController::doubleDensityRelaxation( float neighborhood, float restDensity, float stiffnessParameter, float stiffnessParameterNear )
{
    float neighborhoodSqrd = neighborhood * neighborhood;
    for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){
		p1->mDensity = 0.0f;
        p1->mNearDensity = 0.0f;
        for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){
            Vec2f rij = p1->mPos - p2->mPos;
            float rijSqrd = rij.lengthSquared();
            float q = rijSqrd / neighborhoodSqrd;
            p1->mDensity += ( 1-q ) * ( 1-q );
            p1->mNearDensity += ( 1-q ) * ( 1-q ) * ( 1-q );
        }
        p1->mPressure = stiffnessParameter * ( p1->mDensity - restDensity );
        p1->mNearPressure = stiffnessParameterNear * p1->mNearDensity;
        Vec2f dpos = Vec2f::zero();
        for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){
            Vec2f rij = p1->mPos - p2->mPos;
            float rijSqrd = rij.lengthSquared();
            float q = rijSqrd / neighborhoodSqrd;
            Vec2f DPos = rij.normalized() * ( p1->mPressure * ( 1-q ) + p1->mNearPressure * ( 1-q ) * ( 1-q ) );
            p2->mPos += DPos/2;
            dpos -= DPos/2;
        }
        p1->mPos += dpos;
    }

}
コード例 #2
0
ファイル: faction_state.cpp プロジェクト: baszalmstra/aifc
//---------------------------------------------------------------------------------------------------
void FactionState::ProcessAction(AIAction action, const ActionBuffer& commandBuffer)
{
  ShipState* ship;
  uint32_t shipId;
  switch (action)
  {
  case kForce:
    shipId = commandBuffer.ReadUInt();
    ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr;
    if (ship != nullptr && &ship->faction() == this)
    {
      Vec2f force = commandBuffer.ReadVec2f();
      float totalForceSquared = force.lengthSquared();
      if (totalForceSquared > AICommand::kMaxForce*AICommand::kMaxForce)
        force = force.normalized() * AICommand::kMaxForce;        
      ship->set_force(force);
    }
    break;
  case kFire:
    shipId = commandBuffer.ReadUInt();
    ship = battle_.ships().has(shipId) ? &battle_.ships().lookup(shipId) : nullptr;
    if (ship != nullptr && &ship->faction() == this)
      battle_.Fire(*ship);
    break;
  }
}
コード例 #3
0
void WaterSimApp::mouseMove( MouseEvent event )
{
	Vec2f delta = Vec2f( getWindowWidth(), getWindowHeight() ) / 2.0f - event.getPos();
	if( delta.lengthSquared() > 5 ) {
		mGravityVector = delta.normalized() * 9.8f;
		mGravityVector.y = -mGravityVector.y;
	}
}
コード例 #4
0
ファイル: hexApp.cpp プロジェクト: pholz/hex
	void draw()
	{
		glPushMatrix();
		
		gl::translate(pos);
		
		gl::color(TILECOLOR);
		
		gl::draw(*hex);
		
		gl::color(TILECOLOR2);
		
		glBegin(GL_TRIANGLE_FAN);
		
		PolyLine<Vec2f>::iterator pt;
		
		for(pt = hex->begin(); pt < hex->end(); pt++)
		{
			gl::vertex(*pt);
		}
		
		glEnd();
		
		/*
		 gl::color(Color(1.0f, .0f, .0f));
		 for(pt = hex->begin(); pt < hex->end() - 1; pt++)
		 {
		 gl::vertex(*pt);
		 }
		 */
		
		for(int i = 0; i < 6; i++)
		{
			if(connections[i])
			{
				Vec2f v = (connections[i]->pos - pos)/2.0f;
				gl::color(Color(.0f, 1.0f, .0f));
				gl::drawLine(Vec2f(.0f, .0f), v);
			}
			
			if(state[i])
			{
				Vec2f p = cart(TILERAD_MIN - 2.0f, -M_PI/2 - i * M_PI/3.0f);
				gl::color(Color(1.0f, .0f, .0f));
				//				gl::drawSolidCircle(p, 5.0f, 32);
				Vec2f pnorm = p.normalized();
				pnorm.rotate(-M_PI/2.0f);
				
				Vec2f p0 = p - 22.0f * pnorm;
				Vec2f p1 = p + 22.0f * pnorm;
				gl::drawLine(p0, p1);
			}
		}
		
		glPopMatrix();
	}
コード例 #5
0
void Turtle::init( Vec2f position, Vec2f direction, float length)
{
    mStartPosition = position;
    mCurrentPosition = mStartPosition;
    mLength = length;
    
    mDirection = direction.normalized();
    
    branchNow = false;
    branched = false;
}
コード例 #6
0
ファイル: Particle.cpp プロジェクト: pholz/voidnoise
void Particle::pullToCenter(const Vec2f &center)
{
	Vec2f dirToCenter = m_loc - center;
	float distToCenter = dirToCenter.length();
	
	if (distToCenter > voidnoise::Settings::get().gravityDistance)
	{
		m_acc -= dirToCenter.normalized() *
			((distToCenter - voidnoise::Settings::get().gravityDistance) * voidnoise::Settings::get().gravity);
	}
}
コード例 #7
0
ファイル: RenderMesh.cpp プロジェクト: pourpluie/Pockets
void RenderMesh2D::setAsLine( const Vec2f &begin, const Vec2f &end, float width )
{
  Vec2f ray = end - begin;
  Vec2f side = ray.normalized() * width;
  Vec2f N( -side.y, side.x );
  Vec2f S = -N;

  if( vertices.size() != 4 )
  { vertices.assign( 4, Vertex() ); }
  vertices.at(0).position = begin + S;
  vertices.at(1).position = begin + N;
  vertices.at(2).position = end + S;
  vertices.at(3).position = end + N;
}
コード例 #8
0
void ParticleController::applyViscosity( float neighborhood, float viscositySigma, float viscosityBeta )
{
    float neighborhoodSqrd = neighborhood * neighborhood;
    for ( list<Particle>::iterator p1 = mParticles.begin(); p1 != mParticles.end(); ++p1 ){
		for ( list<Particle>::iterator p2 = p1->mNeighbors.begin(); p2 != p1->mNeighbors.end(); ++p2 ){
            Vec2f rij = p1->mPos - p2->mPos;
            float rijSqrd = rij.lengthSquared();
            float u = ( p1->mVel - p2->mVel ).dot( rij.normalized() );
            float q = rijSqrd / neighborhoodSqrd;
            if ( u > 0 ){
                Vec2f I = ( 1 - q ) * ( ( viscositySigma * u ) + ( viscosityBeta * u * u ) ) * rij.normalized();
                p1->mVel -= I/2;
                p2->mVel += I/2;
            }
        }
    }
}
コード例 #9
0
void DelayFeedback::addSplash( const Vec2f &pos )
{
	mSplashes.push_back( Splash() );

	auto &splash = mSplashes.back();
	splash.mCenter = pos;
	splash.mAlpha = 1;

	float radiusMin = ( 1 - (float)pos.y / (float)getWindowHeight() ) * MAX_RADIUS / 2;
	splash.mRadius = randFloat( radiusMin, 30 );

	float endRadius = randFloat( MAX_RADIUS * 0.9f, MAX_RADIUS );
	timeline().apply( &splash.mRadius, endRadius, 7, EaseOutExpo() );
	timeline().apply( &splash.mAlpha, 0.0f, 7 );

	float h = math<float>::min( 1,  mPerlin.fBm( pos.normalized() ) * 7.0f );
	splash.mColorHsv = Vec3f( fabsf( h ), 1, 1 );
}
コード例 #10
0
void Ball::collideWith(BallRef other)
{
	// calculate minimal distance between balls
	static float minimal = 2 * RADIUS;

	// 1) we have already established that the two balls are colliding,
	// let's move back in time to the moment before collision
	mPosition -= mVelocity;
	other->mPosition -= other->mVelocity;

	// 2) convert to simple 1-dimensional collision 
	//	by projecting onto line through both centers
	Vec2f line = other->mPosition - mPosition;
	Vec2f unit = line.normalized();

	float distance = line.dot(unit);
	float velocity_a = mVelocity.dot(unit);
	float velocity_b = other->mVelocity.dot(unit);
	if(velocity_a == velocity_b) return; // no collision will happen

	// 3) find time of collision
	float t = (minimal - distance) / (velocity_b - velocity_a);

	// 4) move to that moment in time
	mPosition += t * mVelocity;
	other->mPosition += t * other->mVelocity;

	// 5) exchange velocities 	
	mVelocity -= velocity_a * unit;
	mVelocity += velocity_b * unit;

	other->mVelocity -= velocity_b * unit;
	other->mVelocity += velocity_a * unit;

	// 6) move forward to current time 
	mPosition += (1.0f - t) * mVelocity;
	other->mPosition += (1.0f - t) * other->mVelocity;

	// 7) make sure the balls stay within window
	collideWithWindow();
	other->collideWithWindow();
}
コード例 #11
0
ファイル: RenderMesh.cpp プロジェクト: pourpluie/Pockets
void RenderMesh2D::setAsCappedLine( const ci::Vec2f &begin, const ci::Vec2f &end, float width )
{
  Vec2f ray = end - begin;
  Vec2f cap = ray.normalized() * width;
  Vec2f N( -cap.y, cap.x );
  Vec2f S = -N;
  Vec2f NW = N - cap;
  Vec2f NE = N + cap;
  Vec2f SE = -NW;
  Vec2f SW = -NE;

  if( vertices.size() != 8 )
  { vertices.assign( 8, Vertex() ); }
  vertices.at(0).position = begin + SW;
  vertices.at(1).position = begin + NW;
  vertices.at(2).position = begin + S;
  vertices.at(3).position = begin + N;
  vertices.at(4).position = end + S;
  vertices.at(5).position = end + N;
  vertices.at(6).position = end + SE;
  vertices.at(7).position = end + NE;
}
コード例 #12
0
ファイル: Dummy1.cpp プロジェクト: ch0kee/parkinglot
	ParkingSpace(float w, float l, Vec2f loc, Vec2f dir)
		: _width(w)
		, _length(l)
		, _location(loc)
		, _entryDir(dir.normalized())
	{ }
コード例 #13
0
ファイル: cApp.cpp プロジェクト: stdmtb/n9
void cApp::update(){

    
    /*
        add particle
    */
    
    int numPs = ps.size();
    
    if( frame%100 != 0 ){
        
        int num = randInt(10, 30);
        
        for( int i=0; i<num; i++ ){
            
            // pick up color
            int cid = numPs + i;
            int cidx = cid % mColorSample1.size();
            int cidy = cid / mColorSample1.size();
            cidx %= mColorSample1.size();
            cidy %= mColorSample1[0].size();
            ColorAf col = mColorSample1[cidx][cidy];
            float angle = mPlns[1].fBm( cid*0.01 ) * 10.0;
            Vec2f vel = Vec2f(1,1) * randFloat(10, 20);
            vel.rotate(angle);
            
            ps.push_back( Vec2f(0,0) );
            cs.push_back( col );
            vs.push_back( vel );
        }
        
    }else{
        int num = randInt(20000, 30000);
    
        for( int i=0; i<num; i++ ){
            
            // pick up color
            int cid = numPs + i;
            int cidx = cid % mColorSample1.size();
            int cidy = cid / mColorSample1.size();
            cidx %= mColorSample1.size();
            cidy %= mColorSample1[0].size();
            ColorAf col = mColorSample1[cidx][cidy];
            
            Vec3f n = mPlns[0].dfBm( frame, col.r*col.g, col.b );
            Vec2f vel;
            vel.x = n.x * n.y * 20;
            vel.y = n.y * n.z * 20;
            
            if(vel.length() <= 20){
                vel = vel.normalized() * lmap(abs(n.z), 0.0f, 1.0f, 0.7f, 1.0f) *20;
            }
            
            ps.push_back( Vec2f(0,0) );
            cs.push_back( col );
            vs.push_back( vel );
        }
    }
    
    
    
    /*
        update particle
    */
    for( int i=0; i<ps.size(); i++ ){
        Vec2f & p = ps[i];
        Vec2f & v = vs[i];
        ColorAf & c = cs[i];
        
        
        Vec3f n = mPlns[1].dfBm( frame*0.01, i*0.01, c.b*0.5 );
        c.r += n.x * 0.02;
        c.g += n.y * 0.02;
        c.b += n.z * 0.02;
        
        Vec2f new_vel;
        new_vel.x = n.x;
        new_vel.y = n.y;
        v += new_vel*2;
        
        p += v;
        
        v *= 0.999;
        c.a *= 0.999;
        
    }
    
    
    /*
        
        remove
     
     */
    vector<Vec2f>::iterator pit = ps.begin();
    vector<Vec2f>::iterator vit = vs.begin();
    vector<ColorAf>::iterator cit = cs.begin();
    
    int xmin = -mExp.mFbo.getWidth()/2;
    int xmax = mExp.mFbo.getWidth()/2;
    int ymin = -mExp.mFbo.getHeight()/2;
    int ymax = mExp.mFbo.getHeight()/2;
    
    while ( pit!=ps.end() ) {
        Vec2f & p = *pit;
    
        if( (p.x<xmin || xmax<p.x) || p.y<ymin || ymax<p.y  ){
            pit = ps.erase(pit);
            vit = vs.erase(vit);
            cit = cs.erase(cit);
        }else{
            pit++;
            vit++;
            cit++;
        }
    }
    
    frame++;
}
コード例 #14
0
ファイル: gravApp.cpp プロジェクト: pholz/grav
	void update(float dt, vector<Planet*>& planets, paramStruct& params)
	{
		if(charging && charge < MAXCHARGE) charge += dt * 1.5f;
		
		pars = params;
		
		if(jumpInert > .0f)
			jumpInert-=dt;
		if(jumpInert < .0f)
			jumpInert = .0f;
		
		if(turn != params.turn)
		{
			charging = false;
			charge = .0f;
		}
		
		turn = params.turn;
		
		pos += vel * dt;
		
		if(pos.x > getWindowWidth())
		{
			pos.x = pos.x-getWindowWidth();
		}
		
		if(pos.x < 0)
		{
			pos.x = getWindowWidth()+pos.x;
		}
		
		if(pos.y > getWindowHeight())
		{
			pos.y = pos.y-getWindowHeight();
		}
		
		if(pos.y < 0)
		{
			pos.y = getWindowHeight()+pos.y;
		}
		
		Planet* closest = planets[0];
		float dst = 999999999.0f;
		vector<Planet*>::iterator it;
		for(it = planets.begin(); it < planets.end(); it++)
		{
			Vec2f moonToPlanet = ((*it)->pos - pos);
			
			if(moonToPlanet.length() < dst)
			{
				closest = (*it);
				dst = moonToPlanet.length();
			}
				
			
		//	vel += moonToPlanet.normalized() * 1.0f * (*it)->radius * (*it)->radius * 3.14 / (math<float>::max(moonToPlanet.length() * moonToPlanet.length(), 80.0f));

		//	vel += moonToPlanet.normalized() * params.distFactor * moonToPlanet.length();//20000.0f/(math<float>::max(moonToPlanet.length(), 100.0f));
			
		//	vel += (-params.repulse)* moonToPlanet.normalized() / moonToPlanet.length();
		}
		
		nearest = closest;
		
		Vec2f moonToPlanet = closest->pos - pos;
		
		if(!closestPlanet && moonToPlanet.length() > closest->radius * 2.5f)
		{
			vel += moonToPlanet.normalized() * 36.5f * pars.speed *
					closest->radius * closest->radius * closest->radius * (2.0f/3.0f) * M_PI 
					/ (math<float>::max(moonToPlanet.length() * moonToPlanet.length(), 80.0f));
		}
		if(!jumpInert && !closestPlanet && moonToPlanet.length() < closest->radius * 1.7f && losing.size() == 0)
		{
			closestPlanet = closest;
			
		}
		if(closestPlanet && !jumpInert && losing.size() == 0)
		{
			Vec2f m2cp = (closestPlanet->pos - pos);
			
			Vec2f r = pos - closestPlanet->pos;
			r.normalize();
			r.rotate(M_PI/1.97f);
		  
			vel = r * 300.0f * pars.speed;
			
			if(m2cp.length() < closestPlanet->radius)
			{
				pos += -m2cp.normalized() * (5.0f + closestPlanet->radius - m2cp.length());
			}
		}
		
		//vel /= planets.size();
		
		//
//		Vec2f newpos = (pos + vel * dt);
//		for(it = planets.begin(); it < planets.end(); it++)
//		{
//			if(newpos.distance((*it)->pos) < (*it)->radius * 1.5f)
//				vel -= ((*it)->pos - pos);
//		}
		
		closest = 0;
		delete closest;
		
		// particles
		
		vector<Particle*>::iterator pit;
		for(pit = losing.begin(); pit < losing.end(); pit++)
		{
			(*pit)->update(dt);
			if((*pit)->time > (*pit)->lt)
				losing.erase(pit);
		}
	}
コード例 #15
0
void CudaRenderer::constructBlurLUT(void)
{
    // start by constructing low-discrepancy unit square
    int N = 100; // number of samples
    int S = 24;  // max radius

    // init to random
    Array<Vec2f> pos;
    for (int i=0; i < N; i++)
    {
        Vec2f p;
        p.x = (float)hashBits(i) / (float)(((U64)1)<<32);
        p.y = (float)hashBits(i+N) / (float)(((U64)1)<<32);
        pos.add(p);
    }

    // relax by repulsion force
    Array<Vec2f> force;
    force.resize(N);
    for (int i=0; i < 20; i++)
    {
        for (int j=0; j < N; j++)
        {
            Vec2f f(0.f, 0.f);
            Vec2f p = pos[j];
            for (int k=0; k < N; k++)
            {
                if (k==j)
                    continue;

                Vec2f q = pos[k];
                Vec2f d = p-q;
                if (d.x > .5f)  d.x -= 1.f;
                if (d.y > .5f)  d.y -= 1.f;
                if (d.x < -.5f) d.x += 1.f;
                if (d.y < -.5f) d.y += 1.f;
                float d2 = (d.x*d.x + d.y*d.y);
                float m  = 1.f/d2;
                m *= .0001f;
                f += d.normalized() * m;
            }
            float flen = f.length();
            flen = min(flen, .2f);
            f = f.normalized() * flen;
            force[j] = f;
        }
        for (int j=0; j < N; j++)
        {
            Vec2f p = pos[j];
            p += force[j];
            while (p.x > 1.f) p.x -= 1.f;
            while (p.y > 1.f) p.y -= 1.f;
            while (p.x < 0.f) p.x += 1.f;
            while (p.y < 0.f) p.y += 1.f;
            pos[j] = p;
        }
    }

    // form into a disc
    for (int i=0; i < N; i++)
    {
        Vec2f p = pos[i];
        float an = p.x * 2.f * 3.14159f;
        float d  = p.y; // inverse square weighting
        p.x = d * sinf(an);
        p.y = d * cosf(an);
        p = (p + 1.f) * .5f;
        pos[i] = p;
    }

    // work with pixels from now on
    Array<Vec2i> ipos;
    for (int i=0; i < N; i++)
    {
        Vec2f p = pos[i];
        p.x = min(max(p.x, 0.f), 1.f);
        p.y = min(max(p.y, 0.f), 1.f);
        p = (pos[i] - .5f) * 2.f * (float)S;
        int x = (int)(p.x+.5f);
        int y = (int)(p.y+.5f);
        ipos.add(Vec2i(x, y));
    }

    // trim set to unique pixels
    Set<Vec2i> used;
    Array<Vec2i> iposTemp = ipos;
    ipos.clear();
    for (int i=0; i < N; i++)
    {
        Vec2i p = iposTemp[i];
        if (used.contains(p))
            continue;
        used.add(p);
        ipos.add(p);
    }
    N = ipos.getSize();
    printf("CudaRenderer: blur LUT has %d samples\n", ipos.getSize());

    // sort according to distance
    for (int i=0; i < N; i++)
    {
        int dmin = -1;
        int imin = 0;
        for (int j=i; j < N; j++)
        {
            Vec2i p = ipos[j];
            int d = p.x*p.x + p.y*p.y;
            if (d < dmin || dmin < 0)
            {
                dmin = d;
                imin = j;
            }
        }
        swap(ipos[i], ipos[imin]);
    }

    // construct bitmap for support find
    Array<int> bmap;
    bmap.resize(4*S*S);
    for (int i=0; i < bmap.getSize(); i++)
        bmap[i] = -1;

    // blit seeds
    for (int i=0; i < N; i++)
    {
        Vec2i p = ipos[i];
        p.x += S;
        p.y += S;
        p.x = min(max(p.x, 0), 2*S-1);
        p.y = min(max(p.y, 0), 2*S-1);
        bmap[p.x + 2*S*p.y] = i;
    }

    // fill until full
    for(;;)
    {
        Array<int> bmapTemp = bmap;
        bool changed = false;
        for (int y=0; y < 2*S; y++)
        for (int x=0; x < 2*S; x++)
        {
            int d2 = sqr(x-S) + sqr(y-S);
            if (d2 > S*S)
                continue;

            int b = bmap[x+2*S*y];
            if (b >= 0)
                continue;

            int x0 = max(x-1, 0);
            int x1 = min(x+1, 2*S-1);
            int y0 = max(y-1, 0);
            int y1 = min(y+1, 2*S-1);
            for (int py=y0; py<=y1; py++)
            for (int px=x0; px<=x1; px++)
            {
                int c = bmap[px+2*S*py];
                if (c >= 0)
                    b = c;
            }

            if (b >= 0)
            {
                changed = true;
                bmapTemp[x+2*S*y] = b;
            }
        }

        if (!changed)
            break;

        bmap = bmapTemp;
    }

    // count weights
    Array<int> weight;
    weight.resize(N);
    for (int i=0; i < N; i++)
        weight[i] = 0;
    for (int i=0; i < 4*S*S; i++)
    {
        int b = bmap[i];
        if (b >= 0)
            weight[b]++;
    }

    // construct lut
    for (int i=0; i < N; i++)
        m_blurLUT.add(Vec3i(ipos[i].x, ipos[i].y, weight[i]));

    // convert bitmap into lut
#if 0
    m_blurLUT.clear();
    for (int y=0; y < 2*S; y++)
    for (int x=0; x < 2*S; x++)
    {
        int b = bmap[x+2*S*y];
        if (b < 0)
            continue;

        m_blurLUT.add(Vec3i(x-S, y-S, hashBits(b)));
    }
#endif
}
コード例 #16
0
ファイル: Branch.cpp プロジェクト: gaborpapp/apps
void Branch::calcPath()
{
	// TODO: build this up sequentially
#if 1
	mLength = 0.f;
	for ( int i = 0; i < mMaxIterations; i++ )
	{
		bool lastArc = false;
		Vec2f targetDir = mTargetPosition - mCurrentPosition;
		if ( mCurrentPosition.distanceSquared( mTargetPosition ) < ( mStemLengthMax * mStemLengthMax ) )
		{
			// add the target if it is in the direction range in the next step
			lastArc = true;
		}

		if ( i == 0 )
		{
			addArc( mCurrentPosition );
			if ( lastArc )
				mCurrentPosition = mTargetPosition;
			else
				mCurrentPosition += mStemLengthMin * targetDir.normalized();
			addArc( mCurrentPosition );
			mLength += mStemLengthMin;
		}
		else
		{
			// current direction
			size_t segmentNum = mPath.getNumSegments();
			Vec2f p0 = mPath.getSegmentPosition( segmentNum - 1, 1.f );
			Vec2f currentDir = p0 - mPath.getSegmentPosition( segmentNum - 1, .98f );

			// minimum angle between the current direction and the target
			float angleDir = math< float >::atan2( currentDir.y, currentDir.x );
			float angleTarget = math< float >::atan2( targetDir.y, targetDir.x );
			float angle = angleTarget - angleDir;
			if ( angle > M_PI )
				angle -= 2 * M_PI;
			else
			if ( angle < -M_PI )
				angle += 2 * M_PI;

#if 0
			/* direction range towards the target is the intersection of the bearing angle interval around the target and
			   the current direction, if the intersecion is empty, the maximum angle is used in that direction */
			float angleMin = math< float >::clamp( angle - mStemBearingDelta, -mStemBearingDelta, mStemBearingDelta );
			float angleMax = math< float >::clamp( angle + mStemBearingDelta, -mStemBearingDelta, mStemBearingDelta );
#endif
			// FIXME: bearing delta .25 breaks continuity?
			// this algorithm tends to keep the target in sight better
			float angleMin, angleMax;
			if ( lastArc )
			{
				// get as close to the target as possible with the last arc
				if ( ( angle > -mStemBearingDelta ) && ( angle < mStemBearingDelta ) )
					angleMin = angleMax = angle;
				else
				if ( angle <= -mStemBearingDelta )
					angleMin = angleMax = -mStemBearingDelta;
				else
				if ( angle >= mStemBearingDelta )
					angleMin = angleMax = mStemBearingDelta;
			}
			else
			if ( angle <= -mStemBearingDelta ) // the angle is the maximum if the target is outside the range
			{
				angleMin = angleMax = -mStemBearingDelta;
			}
			else
			if ( angle >= mStemBearingDelta )
			{
				angleMin = angleMax = mStemBearingDelta;
			}
			else // inside the range on the left handside, allow leftward movements only
			if ( angle < 0.f )
			{
				angleMin = -mStemBearingDelta;
				angleMax = 0.f;
			}
			else // inside the range on the right handside, allow rightward movements only
			if ( angle > 0.f )
			{
				angleMin = 0.f;
				angleMax = mStemBearingDelta;
			}
			else // angle = 0, turn is allowed to either side
			{
				angleMin = -mStemBearingDelta;
				angleMax = mStemBearingDelta;
			}

			float bearingMin = angleDir + angleMin;
			float bearingMax = angleDir + angleMax;

			float stemDistance;
			if ( lastArc )
				stemDistance = targetDir.length();
			else
				stemDistance = Rand::randFloat( mStemLengthMin, mStemLengthMax );
			float stemBearingAngle = Rand::randFloat( bearingMin, bearingMax );

			Vec2f bearing( math< float >::cos( stemBearingAngle ), math< float >::sin( stemBearingAngle ) );
			mCurrentPosition += stemDistance * bearing;
			addArc( mCurrentPosition );
			mLength += stemDistance;
		}
		if ( lastArc )
			break;
	}
#endif
#if 0
	// simple algorithm with big curly movements
	for ( int i = 0; i < mMaxIterations; i++ )
	{
		Vec2f d = mTargetPosition - mCurrentPosition;

		float stemDistance = Rand::randFloat( mStemLengthMin, mStemLengthMax );
		if ( d.length() < stemDistance )
		{
			mCurrentPosition = mTargetPosition;
			addArc( mCurrentPosition );
			break;
		}
		else
		{
			float stemBearingAngle = Rand::randFloat( mStemBearingDelta );
			Vec2f bearing( d.normalized() );
			bearing.rotate( ( ( i & 1 ) ? 1 : -1 ) * stemBearingAngle );
			mCurrentPosition += stemDistance * bearing;
			addArc( mCurrentPosition );
		}
	}
#endif
}