Example #1
0
void Projectile::orient(b2Vec2 target)
{
	float bodyAngle = body_->GetAngle();
	float desiredAngle = atan2f(-target.x, target.y);
	float nextAngle = body_->GetAngle() + body_->GetAngularVelocity() / _TICKTIME_;

	float totalRotation = desiredAngle - bodyAngle;

	while (totalRotation < M_PI) totalRotation += 2 * M_PI;
	while (totalRotation > M_PI) totalRotation -= 2 * M_PI;

	float change = 10 * DR; //allow 20 degree rotation per time step
	float newAngle = bodyAngle + std::min(change, std::max(-change, totalRotation));
	
	float vel = body_->GetLinearVelocity().Length();
	
	b2Vec2 newVel(vel * cos(newAngle), vel * sin(newAngle));
	
	//body_->SetLinearVelocity(newVel);

	//body_->SetTransform(body_->GetPosition(), newAngle);
	//vx = magnitude * cos(angle)
	//vy = magnitude * sin(angle)
}
// ---------------------------------------------------------------
// advance solution by one timestep
// return max safe timestep
Real
AMRNavierStokes::advance()
{
  if (s_verbosity >= 2)
  {
    pout () << "AMRNavierStokes::advance " << m_level
            << ", starting time = "
            << setiosflags(ios::fixed) << setprecision(6)
            << setw(12) << m_time
            << ", dt = "
            << setiosflags(ios::fixed) << setprecision(6) << setw(12) << dt()
            << endl;
  }

#ifdef DEBUG
  // if we're at the beginning of a composite timestep,
  // save current multilevel state
  if (m_level == 0)
    {
      AMRNavierStokes* levelPtr = this;
      // figure out finest level
      while (!levelPtr->finestLevel())
        {
          levelPtr = levelPtr->finerNSPtr();
        }
    int finest_level = levelPtr->m_level;

    levelPtr = this;
    for (int lev=0; lev<= finest_level; lev++)
      {
        levelPtr->m_saved_time = m_time;

        levelPtr->newVel().copyTo(levelPtr->newVel().interval(),
                                  *levelPtr->m_vel_save_ptr,
                                  levelPtr->m_vel_save_ptr->interval());

        levelPtr->newLambda().copyTo(levelPtr->newLambda().interval(),
                                     *levelPtr->m_lambda_save_ptr,
                                     levelPtr->m_lambda_save_ptr->interval());

        for (int comp=0; comp<s_num_scal_comps; comp++)
          {
            levelPtr->newScal(comp).copyTo(levelPtr->newScal(comp).interval(),
                                           *levelPtr->m_scal_save[comp],
                                           levelPtr->m_scal_save[comp]->interval());
          }

        levelPtr = levelPtr->finerNSPtr();
      }
    }
#endif

  Real old_time = m_time;
  Real new_time = m_time + m_dt;
  m_dt_save = m_dt;
  swapOldAndNewStates();

  const DisjointBoxLayout levelGrids = newVel().getBoxes();

  // initialize flux registers
  if (!finestLevel())
    {
      m_flux_register.setToZero();
      for (int comp=0; comp<s_num_scal_comps; comp++)
        {
          m_scal_fluxreg_ptrs[comp]->setToZero();
        }
      m_lambda_flux_reg.setToZero();
    }

  // compute advection velocities -- if we're using the
  // patchGodunov approach, these will have ghost cells.
  IntVect advVelGhost(IntVect::Unit);
  LevelData<FluxBox> advectionVel(levelGrids, 1, advVelGhost);

  if (s_set_bogus_values)
    {
      setValLevel(advectionVel, s_bogus_value);
    }

  computeAdvectionVelocities(advectionVel);

  // now that advection velocities have been computed,
  // update advected scalars

  // do scalar boundary conditions on lambda
  // (also grow to appropriate size)

  LevelData<FArrayBox> lambdaTemp;

  fillLambda(lambdaTemp, old_time);

  LevelFluxRegister* crseLambdaFluxRegPtr = NULL;
  if (m_level > 0)
    {
      crseLambdaFluxRegPtr = &(crseNSPtr()->m_lambda_flux_reg);
    }

  advectScalar(newLambda(), lambdaTemp, advectionVel,
               crseLambdaFluxRegPtr, m_lambda_flux_reg,
               m_patchGodLambda,
               m_dt);

  // now do advected-diffused scalars
  if (s_num_scal_comps > 0)
    {
      // loop over scalar components
      for (int comp=0; comp<s_num_scal_comps; comp++)
        {
          BCHolder scalPhysBCs = m_physBCPtr->scalarTraceFuncBC(comp);

          LevelData<FArrayBox> scalarTemp;
          fillScalars(scalarTemp, old_time,comp);

          // now get coarse-level scalars for BC's if necessary
          LevelData<FArrayBox>* newCrseScalPtr = NULL;
          LevelData<FArrayBox>* oldCrseScalPtr = NULL;
          Real oldCrseTime = -s_bogus_value;
          Real newCrseTime = s_bogus_value;
          LevelFluxRegister* crseScalFluxRegPtr = NULL;

          if (m_level > 0)
            {
              newCrseScalPtr = &(crseNSPtr()->newScal(comp));
              oldCrseScalPtr = &(crseNSPtr()->oldScal(comp));
              newCrseTime = crseNSPtr()->time();
              oldCrseTime = newCrseTime - crseNSPtr()->dt();
              crseScalFluxRegPtr = (crseNSPtr()->m_scal_fluxreg_ptrs[comp]);
            }

          advectDiffuseScalar(newScal(comp), scalarTemp,
                              advectionVel,
                              s_scal_coeffs[comp],
                              oldCrseScalPtr, newCrseScalPtr,
                              oldCrseTime, newCrseTime,
                              crseScalFluxRegPtr,
                              *(m_scal_fluxreg_ptrs[comp]),
                              *(m_patchGodScalars[comp]),
                              scalPhysBCs,
                              m_dt, comp);
        } // end loop over components
    } // end advected-diffused scalars

  // now predict velocities -- this returns the advection term
  // put this in "new_vel"
  LevelData<FArrayBox>& uStar = newVel();
  predictVelocities(uStar, advectionVel);

  computeUStar(uStar);

  // if a coarser level exists, will need coarse-level data for proj
  LevelData<FArrayBox>* crseVelPtr = NULL;

  if (m_level > 0)
    {
      const DisjointBoxLayout& crseGrids = crseNSPtr()->newVel().getBoxes();
      crseVelPtr = new LevelData<FArrayBox>(crseGrids, SpaceDim);
      // coarse velocity BC data is interpolated in time
      crseNSPtr()->fillVelocity(*crseVelPtr, new_time);
    }

  // need to do physical boundary conditions and exchanges
  bool isViscous = (s_nu > 0);
  VelBCHolder velBC(m_physBCPtr->uStarFuncBC(isViscous));
  velBC.applyBCs(uStar, levelGrids,
                 m_problem_domain, m_dx,
                 false); // inhomogeneous

  // noel -- all time in level project
  m_projection.LevelProject(uStar, crseVelPtr, new_time, m_dt);

  // as things stand now, physical BC's are re-set in LevelProjection

  // compute maximum safe timestep for next iteration
  Real newDt = computeDt();

  // clean up temp storage
  if (crseVelPtr != NULL)
    {
      delete crseVelPtr;
      crseVelPtr = NULL;
    }

  ++m_level_steps;

  if (s_verbosity >= 2)
    {

      pout () << "AMRNavierStokes::advance " << m_level
              << ",      end time = "
              << setiosflags(ios::fixed) << setprecision(6) << setw(12) << m_time
              << ", dt = "
              << setiosflags(ios::fixed) << setprecision(6)
              << setw(12) << dt()
              << endl;
    }

  return newDt;
}
// ---------------------------------------------------------------
void
AMRNavierStokes::computeAdvectionVelocities(LevelData<FluxBox>& a_advVel)
{
  if (s_verbosity >= 3)
    {
      pout() << "AMRNavierStokes::computeAdvectionVelocities: "
             << m_level << endl;
    }

  bool isViscous = (s_nu > 0.0);

  const DisjointBoxLayout& levelGrids = newVel().getBoxes();

  /// need to build grown grids to get be able to do all of
  /// tracing properly
  IntVect advect_grow(D_DECL(ADVECT_GROW, ADVECT_GROW, ADVECT_GROW));

  LevelData<FArrayBox> old_vel(levelGrids, SpaceDim, advect_grow);
  LevelData<FArrayBox> viscousSource(levelGrids, SpaceDim, advect_grow);
  LevelData<FArrayBox>* crseVelPtr = NULL;

  if (s_set_bogus_values)
    {
      setValLevel(old_vel, s_bogus_value);
      setValLevel(viscousSource, s_bogus_value);
    }

  // m_time contains the time at which the new state is centered
  Real old_time = m_time - m_dt;
  fillVelocity(old_vel, old_time);

  // set physical boundary conditions here
  // set physical boundary conditions on velocity

  if (isViscous)
    {
      LevelData<FArrayBox> viscousVel(levelGrids, SpaceDim, advect_grow);
      DataIterator dit = viscousVel.dataIterator();
      // rather than resetting BC's on old_vel, and then setting them
      // back, just copy old_vel to a temporary holder, and set
      // BCs on that one.
      for (dit.begin(); dit.ok(); ++dit)
        {
          viscousVel[dit].copy(old_vel[dit]);
        }
      VelBCHolder velBC(m_physBCPtr->viscousVelFuncBC());
      velBC.applyBCs(viscousVel, levelGrids,
                     m_problem_domain, m_dx,
                     false); // inhomogeneous

      // if crse level exists, fill coarse velocity BC
      if (m_level > 0)
        {
          const DisjointBoxLayout& crseGrids = crseNSPtr()->newVel().getBoxes();
          crseVelPtr = new LevelData<FArrayBox>(crseGrids, SpaceDim);
          crseNSPtr()->fillVelocity(*crseVelPtr, old_time);
        }

      computeLapVel(viscousSource, viscousVel, crseVelPtr);

      for (dit.reset(); dit.ok(); ++dit)
        {
          viscousSource[dit].mult(s_nu);
        }
    }
  else
    {
      setValLevel(viscousSource, 0.0);
    }

  // tracing will use inviscid BC's
  {
    VelBCHolder velBC(m_physBCPtr->tracingVelFuncBC());
    velBC.applyBCs(old_vel, levelGrids,
                   m_problem_domain, m_dx,
                   false); // inhomogeneous
  }

  // call utility function to do tracing
  traceAdvectionVel(a_advVel, old_vel, viscousSource,
                    m_patchGodVelocity, old_time, m_dt);

  EdgeVelBCHolder edgeVelBC(m_physBCPtr->advectionVelFuncBC(isViscous));
  edgeVelBC.applyBCs(a_advVel, levelGrids,
                     m_problem_domain, m_dx,
                     false); // inhomogeneous

  // noel  levelMacProject is big guy
  // now MAC project
  m_projection.levelMacProject(a_advVel, old_time, m_dt);

  // finally, add volume discrepancy correction
  if (m_projection.etaLambda() > 0 && s_applyFreestreamCorrection)
    {
      LevelData<FluxBox>& grad_e_Lambda = m_projection.grad_eLambda();

      DataIterator dit = levelGrids.dataIterator();
      for (dit.reset(); dit.ok(); ++dit)
        {
          FluxBox& thisGrad_eLambda = grad_e_Lambda[dit];
          FluxBox& thisAdvVel = a_advVel[dit];
          for (int dir=0; dir<SpaceDim; dir++)
            {
              thisAdvVel[dir] += thisGrad_eLambda[dir];
            }
        }
    }

  edgeVelBC.applyBCs(a_advVel, levelGrids,
                     m_problem_domain, m_dx,
                     false); // inhomogeneous

  // clean up storage
  if (crseVelPtr != NULL)
    {
      delete crseVelPtr;
      crseVelPtr = NULL;
    }
}
Example #4
0
  void 
  GWaker::runEvent(const Particle& part, const double dt) const
  {
    GlobalEvent iEvent(getEvent(part));
    iEvent.setdt(dt); //We only trust the schedulers time, as we don't
    //track the motion of the system in Globals
  
#ifdef DYNAMO_DEBUG 
    if (boost::math::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found"
		<< iEvent.stringData(Sim);
  
    if (iEvent.getdt() == HUGE_VAL)
      M_throw() << "An infinite Interaction (not marked as NONE) collision time has been found\n"
		<< iEvent.stringData(Sim);
#endif

    Sim->dSysTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->dynamics.stream(iEvent.getdt());

    Sim->dynamics.getLiouvillean().updateParticle(part);

    //Here is where the particle goes to sleep or wakes
    ++Sim->eventCount;
  
    _neighbors = 0;

    //Add the interaction events
    Sim->ptrScheduler->getParticleNeighbourhood(part, magnet::function::MakeDelegate(this, &GWaker::nblistCallback));
  
    //  if (_neighbors < 10)
    //    {
    iEvent.addTime(Sim->freestreamAcc);      
    Sim->freestreamAcc = 0;

    ParticleEventData EDat(part, Sim->dynamics.getSpecies(part), iEvent.getType());
      
    Vector newVel(Sim->normal_sampler(),Sim->normal_sampler(),Sim->normal_sampler());
    newVel *= _wakeVelocity / newVel.nrm();
      
    const_cast<Particle&>(part).getVelocity() = newVel;
    const_cast<Particle&>(part).setState(Particle::DYNAMIC);
      
    EDat.setDeltaKE(0.5 * EDat.getSpecies().getMass(part.getID())
		    * (part.getVelocity().nrm2() 
		       - EDat.getOldVel().nrm2()));
      
    Sim->signalParticleUpdate(EDat);
      
    BOOST_FOREACH(shared_ptr<OutputPlugin> & Ptr, Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);
    //    }
    //  else
    //    Sim->freestreamAcc += iEvent.getdt();

    //Now we're past the event, update the scheduler and plugins
    Sim->ptrScheduler->fullUpdate(part);
  }
// -----------------------------------------------------------------------------
// This does the actual computation to update the state variables.
// I've included this function since the initializeGlobalPressure() and advance()
// functions are, for the most part, the same piece of code.
// -----------------------------------------------------------------------------
void AMRNavierStokes::PPMIGTimeStep (const Real a_oldTime,
                                     const Real a_dt,
                                     const bool a_updatePassiveScalars,
                                     const bool a_doLevelProj)
{
    CH_TIME("AMRNavierStokes::PPMIGTimeStep");
    pout() << setiosflags(ios::scientific) << setprecision(8) << flush;

    // Set up some basic values
    const RealVect& dx = m_levGeoPtr->getDx();
    const DisjointBoxLayout& grids = newVel().getBoxes();
    DataIterator dit = grids.dataIterator();
    const Box domainBox = m_problem_domain.domainBox();
    const bool isViscous = (s_nu > 0.0);

    // Initialize all flux registers
    if (!finestLevel()) {
        m_vel_flux_reg.setToZero();
        for (int comp = 0; comp < s_num_scal_comps; ++comp) {
            m_scal_fluxreg_ptrs[comp]->setToZero();
        }
        m_lambda_flux_reg.setToZero();
    }

    // Sanity checks
    CH_assert(m_levGeoPtr->getBoxes() == grids);
    CH_assert(m_levGeoPtr->getDomain() == m_problem_domain);
    CH_assert(Abs(a_oldTime - (m_time - a_dt)) < TIME_EPS);
    CH_assert(s_num_scal_comps <= 1);
    CH_assert(s_num_scal_comps > 0 || s_gravityMethod == ProblemContext::GravityMethod::NONE);

    // Reference new holders
    LevelData<FArrayBox>& new_vel = newVel();
    LevelData<FArrayBox>& new_lambda = newLambda();
    LevelData<FArrayBox> new_b;
    if (s_num_scal_comps > 0) {
        aliasLevelData(new_b, &(newScal(0)), Interval(0,0));
    }


    // Compute advecting velocities
    LevelData<FArrayBox> old_vel(grids, SpaceDim, m_tracingGhosts);
    fillVelocity(old_vel, a_oldTime);
    old_vel.exchange(m_tracingExCopier);

    LevelData<FluxBox> adv_vel(grids, 1, IntVect::Unit); // Changed from m_tracingGhosts to 1
    computeAdvectingVelocities(adv_vel, old_vel, a_oldTime, a_dt);

    if (a_updatePassiveScalars) {
        // Lambda update
        LevelData<FArrayBox> old_lambda;
        fillLambda(old_lambda, a_oldTime);
        old_lambda.exchange(m_tracingExCopier);

        LevelData<FArrayBox> dLdt(grids, 1);
        getNewLambda(dLdt, new_lambda, old_lambda, old_vel, adv_vel, a_oldTime, a_dt, a_dt);
    }

    LevelData<FArrayBox> old_b;
    if (s_num_scal_comps > 0) {
        // Scalar update
        fillScalars(old_b, a_oldTime, 0);
        old_b.exchange(m_tracingExCopier);

        LevelData<FArrayBox> dSdt(grids, 1);
        getNewScalar(dSdt, new_b, old_b, old_vel, adv_vel, a_oldTime, a_dt, a_dt, 0);
    }

    for (int comp = 1; comp < s_num_scal_comps; ++comp) {
        // Scalar update
        LevelData<FArrayBox> old_scal;
        fillScalars(old_scal, a_oldTime, comp);
        old_scal.exchange(m_tracingExCopier);

        LevelData<FArrayBox> dSdt(grids, 1);
        getNewScalar(dSdt, newScal(comp), old_scal, old_vel, adv_vel, a_oldTime, a_dt, a_dt, comp);
    }

    {   // Update CC velocities
        LevelData<FArrayBox> dUdt(grids, SpaceDim);
        getNewVelocity(dUdt, new_vel, old_vel, adv_vel, a_oldTime, a_dt, a_dt);
    }

    if (s_num_scal_comps > 0) {
        // Do implicit gravity update and CC projection.
        doCCIGProjection(new_vel, new_b, old_vel, old_b, adv_vel, a_oldTime, a_dt, a_doLevelProj);
    } else {
        // Do a standard CC projection.
        doCCProjection(new_vel, a_oldTime + a_dt, a_dt, a_doLevelProj);
    }
}
/**
 *	This method executes the action for the given frame of time. The dTime
 *	parameter is the time elapsed since the last call.
 *
 *	@param particleSystem	The particle system on which to operate.
 *	@param dTime			Elapsed time in seconds.
 */
void CollidePSA::execute( ParticleSystem &particleSystem, float dTime )
{
	BW_GUARD;
	SourcePSA* pSource = static_cast<SourcePSA*>( &*particleSystem.pAction( PSA_SOURCE_TYPE_ID ) );

	if ( !pSource )
		return;

	RompColliderPtr pGS = pSource->groundSpecifier();
	if ( !pGS )
		return;

	uint64	tend = timestamp() + stampsPerSecond() / 2000;

	bool soundHit = false;
	float maxVelocity = 0;
	Vector3 soundPos;
	uint materialKind;

	Particles::iterator it = particleSystem.begin();
	Particles::iterator end = particleSystem.end();

	WorldTriangle tri;

	//bust out of the loop if we take more than 0.5 msec

	//Sprite particles don't calculate spin
	while ( it != end && timestamp()<tend )
	{
		Particle &particle = *it++;

		if (!particle.isAlive())
		{		
			continue;
		}

		//note - particles get moved after actions.
		Vector3 velocity;
		particle.getVelocity(velocity);
		Vector3 pos;
		Vector3 newPos;

		if(particleSystem.isLocal())
		{
			Matrix world = particleSystem.worldTransform();
			pos = world.applyPoint(particle.position());
			Vector3 nPos;
			particleSystem.predictPosition( particle, dTime, nPos );
			newPos = world.applyPoint(nPos);
		}
		else
		{
			pos = particle.position();
			particleSystem.predictPosition( particle, dTime, newPos );
		}


		float tValue = pGS->collide( pos, newPos, tri );
		if ( tValue >= 0.f && tValue <= 1.f )
		{
			// calc v as a dotprod of the two normalised vectors (before and after collision)
			Vector3 oldVel = velocity / velocity.length();
			tri.bounce( velocity, elasticity_ );
			particle.setVelocity( velocity );
			float newSpeed = velocity.length();
			Vector3 newVel(velocity / newSpeed);
			float severity = oldVel.dotProduct(newVel);
			//DEBUG_MSG("severity: %1.3f, speed=%1.3f\n", severity, newSpeed);
			float v = (1 - severity) * newSpeed;

			//now spin the particle ( mesh only )
			if ( !spriteBased_ )
			{
				//first, calculate the current rotation, and update the pitch/yaw value.
				Matrix currentRot;
				currentRot.setRotate( particle.yaw(), particle.pitch(), 0.f );
				Matrix spin;
                float spinSpeed = particle.meshSpinSpeed();
                Vector3 meshSpinAxis = particle.meshSpinAxis();
                // If there is no spin direction then creating a rotation 
                // matrix can create weird matrices - e.g. matrices with
                // negative scale components and a translation.  We choose the
                // velocity as the spin direction (aribitrarily choosing, for
                // example up looks weird).
                if (meshSpinAxis == Vector3::zero())
                {
                    meshSpinAxis = velocity;
                    meshSpinAxis.normalise();
                }
				
				D3DXMatrixRotationAxis
                ( 
                    &spin, 
                    &meshSpinAxis, 
                    spinSpeed * (particle.age()-particle.meshSpinAge()) 
                );
				
				currentRot.preMultiply( spin );		
				particle.pitch( currentRot.pitch() );
				particle.yaw( currentRot.yaw() );

				//now, reset the age of the spin 
				particle.meshSpinAge( particle.age() );

				//finally, update the spin ( stored in the particle's colour )
				float addedSpin = unitRand() * (maxAddedRotation_-minAddedRotation_) + minAddedRotation_;
				addedSpin *= min( newSpeed, 1.f );				
				spinSpeed = Math::clamp( 0.f, spinSpeed + addedSpin, 1.f );
                particle.meshSpinSpeed(spinSpeed);
                particle.meshSpinAxis(meshSpinAxis);
			}

			if ( soundEnabled_ && v > 0.5f )
			{
				soundHit = true;
				if (v > maxVelocity) {
					maxVelocity = v;
					soundPos = particle.position();
					materialKind = tri.materialKind();
				}
			}
		}
	}

	if ( soundHit )
	{
		SmartPointer < RompSound > rs = RompSound::getProvider();
		if (rs)
		{
			if (!soundTag_.empty())
			{
				rs->playParticleSound( soundTag_.c_str(), soundPos, maxVelocity, soundSrcIdx_, materialKind );
			}
		}
	}
}
// ---------------------------------------------------------------
// tag cells for regridding
void
AMRNavierStokes::tagCells(IntVectSet & a_tags)
{
  if (s_verbosity >= 3)
    {
      pout () << "AMRNavierStokes::tagCells " << m_level << endl;
    }

  IntVectSet local_tags;

  // create tags based on something or other
  // for now, don't do anything
  const DisjointBoxLayout& level_domain = newVel().getBoxes();

  if (s_tag_vorticity)
    {
      LevelData<FArrayBox> vorticity;
      LevelData<FArrayBox> mag_vorticity;
      if (SpaceDim == 2)
        {
          vorticity.define(level_domain,1);
        }
      else if (SpaceDim == 3)
        {
          vorticity.define(level_domain,SpaceDim);
          mag_vorticity.define(level_domain,1);
        }
      computeVorticity(vorticity);

      Interval vortInterval(0,0);
      if (SpaceDim == 3)
        {
          vortInterval = Interval(0,SpaceDim-1);
        }
      Real tagLevel = norm(vorticity, vortInterval, 0);
      // Real tagLevel = 1.0;
      //tagLevel *= s_vort_factor/m_dx;
      // actually tag where vort*dx > s_vort_factor*max(vort)
      tagLevel = s_vort_factor/m_dx;

      if (tagLevel > 0)
        {
          // now tag where vorticity magnitude is greater than or equal
          // to tagLevel
          DataIterator dit = vorticity.dataIterator();
          for (dit.reset(); dit.ok(); ++dit)
            {
              FArrayBox& vortFab = vorticity[dit];

              // this only needs to be done in 3d...
              if (SpaceDim==3)
                {
                  FArrayBox& magVortFab = mag_vorticity[dit];
                  FORT_MAGVECT(CHF_FRA1(magVortFab,0),
                               CHF_CONST_FRA(vortFab),
                               CHF_BOX(level_domain[dit]));
                }

              BoxIterator bit(vortFab.box());
              for (bit.begin(); bit.ok(); ++bit)
                {
                  const IntVect& iv = bit();
                  if (SpaceDim == 2)
                    {
                      if (abs(vortFab(iv)) >= tagLevel)
                        {
                          local_tags |= iv;
                        }
                    }
                  else if (SpaceDim == 3)
                    {
                      FArrayBox& magVortFab = mag_vorticity[dit];
                      if (abs(magVortFab(iv)) >= tagLevel)
                        {
                          local_tags |= iv;
                        }
                    } // end if DIM=3
                } // end loop over interior of box
            } // loop over grids
        } // if taglevel > 0
    } // if tagging on vorticity

  a_tags = local_tags;
}
void InputHandler::handlePlayerEvents()
{
    if (!m_player) return;

    // check to see if mouse is hovering
    s_pos = gdata.toScreenPixels(m_player->getAbsolutePosition());
    s_pos.y = gdata.window->getSize().y - s_pos.y;

    Vector2 d = gdata.mouse - s_pos;
    if (d.getMagnitude() <= (0.5 * WORLD_SCALE * gdata.zoom))
    {
        if (!m_player->hover)
        {
            m_player->hover = true;
            m_player->shrink_thickness = m_player->circle.getOutlineThickness();
        }
    }
    else
    {
        m_player->hover = false;
    }

    if (gdata.keys[KEY_MOUSE_RIGHT].isKeyPressed)
    {
        if (selecting && !launched)
            angle_lock = !angle_lock;
    }

    if (gdata.keys[sf::Keyboard::Space].isKeyPressed)
    {
        angle_snap = angle_snap == 1 ? 0 : 1;
        gdata.angle_snap = angle_snap;
    }

    if (gdata.keys[sf::Keyboard::F1].isKeyPressed)
    {
        gdata.show_help = !gdata.show_help;
    }

    if (gdata.keys[sf::Keyboard::C].isKeyPressed)
    {
        gdata.random_colors = !gdata.random_colors;
    }

	if (gdata.keys[KEY_MOUSE_LEFT].isKeyPressed)
	{
	    if (!launched)
        {
            s_pos = gdata.toScreenPixels(m_player->getAbsolutePosition());
            s_pos.y = gdata.window->getSize().y - s_pos.y;

            Vector2 d = gdata.mouse - s_pos;
            if (d.getMagnitude() <= (0.5 * WORLD_SCALE * gdata.zoom))
            {
                selecting = true;
                m_player->shot = true;
                //power = 10;
            }
        }
	}

	if (gdata.keys[KEY_MOUSE_LEFT].isKeyDown)
	{
	    if (selecting)
        {
            if (!angle_lock)
            {
                e_pos = gdata.mouse;
                // don't allow for zero velocity
                if (e_pos == s_pos) ++e_pos.y;

                vel = s_pos - e_pos;
                vel.setMagnitude(vel.getMagnitude());

                if (vel.getMagnitude() > max_dist) vel.setMagnitude(max_dist);
                if (vel.getMagnitude() < min_dist) vel.setMagnitude(min_dist);

                float vel_percent = vel.getMagnitude() / max_dist;
                float speed = m_player->maxSpeed * vel_percent;
                vel.setMagnitude( speed );
                if (angle_snap > 0)
                {
                    float a = utils::roundNearest(vel.getAngle(),angle_snap);
                    Vector2 newVel(speed,0);
                    newVel.rotate(a);
                    vel = newVel;
                }


                power = utils::roundNearest(vel_percent*100,1);
                angle = vel.getAngle();
                m_player->angle = angle;
                m_player->power = power;
            }
            else
            {
                Vector2 m = s_pos - gdata.mouse;
                // don't change the angle just change the magnitude
                if (m.getMagnitude() > max_dist)        vel.setMagnitude(max_dist);
                else if (m.getMagnitude() < min_dist)   vel.setMagnitude(min_dist);
                else                                    vel.setMagnitude(m.getMagnitude());

                float vel_percent = vel.getMagnitude() / max_dist;
                vel.setMagnitude( m_player->maxSpeed * vel_percent );

                power = utils::roundNearest(vel_percent*100,1);
                angle = vel.getAngle();
                m_player->power = power;
                m_player->angle = angle;
            }
	    }
	}

	if (gdata.keys[KEY_MOUSE_LEFT].isKeyReleased)
	{
	    if (selecting && !launched)
		{
		    m_player->shootPlayer();
		    //m_player->currentSpeed = vel.getMagnitude();
            //m_player->trail.addPoint( m_player->getAbsolutePosition() );
            //m_player->setLinearVelocity(vel);
            //m_player->trail.length = MAX_TAIL_LENGTH * (vel.getMagnitude() / m_player->maxSpeed);

		    launched = true;
		    selecting = false;
		    gdata.last_angle = vel.getAngle();
		    gdata.first_shot = false;

		    Vector2 dir(50,0);
		    dir.rotate(vel.getAngle());
		    gdata.p1 = m_player->getAbsolutePosition();
		    gdata.p2 = gdata.p1 + dir;

		    gdata.audio->playSound("shoot",true);

		    // need to keep track for direction, speed and time
		    BallShotData bsd(timer,vel.getAngle(),power);
		    gdata.shotData.push_back(bsd);
		    cout << "timer:" << timer << endl;
		}
	}
}