예제 #1
0
// ****** Rotation Matrix from Two Vector Directions ********
// ****** given two vector directions (v1 and v2) known in two frames (b and e) find Rbe ***
// ****** solution is approximate if can't be exact ***
uint8_t RotFrom2Vectors(const float v1b[3], const float v1e[3], const float v2b[3], const float v2e[3], float Rbe[3][3])
{
	float Rib[3][3], Rie[3][3];
	float mag;
	uint8_t i,j,k;

	// identity rotation in case of error
	for (i=0;i<3;i++){
		for (j=0;j<3;j++)
			Rbe[i][j]=0;
		Rbe[i][i]=1;
	}

	// The first rows of rot matrices chosen in direction of v1
	mag = VectorMagnitude(v1b);
	if (fabs(mag) < 1e-30)
		return (-1);
	for (i=0;i<3;i++)
		Rib[0][i]=v1b[i]/mag;

	mag = VectorMagnitude(v1e);
	if (fabs(mag) < 1e-30)
		return (-1);
	for (i=0;i<3;i++)
		Rie[0][i]=v1e[i]/mag;

	// The second rows of rot matrices chosen in direction of v1xv2
	CrossProduct(v1b,v2b,&Rib[1][0]);
	mag = VectorMagnitude(&Rib[1][0]);
	if (fabs(mag) < 1e-30)
		return (-1);
	for (i=0;i<3;i++)
		Rib[1][i]=Rib[1][i]/mag;

	CrossProduct(v1e,v2e,&Rie[1][0]);
	mag = VectorMagnitude(&Rie[1][0]);
	if (fabs(mag) < 1e-30)
		return (-1);
	for (i=0;i<3;i++)
		Rie[1][i]=Rie[1][i]/mag;

	// The third rows of rot matrices are XxY (Row1xRow2)
	CrossProduct(&Rib[0][0],&Rib[1][0],&Rib[2][0]);
	CrossProduct(&Rie[0][0],&Rie[1][0],&Rie[2][0]);

	// Rbe = Rbi*Rie = Rib'*Rie
	for (i=0;i<3;i++)
		for(j=0;j<3;j++){
			Rbe[i][j]=0;
			for(k=0;k<3;k++)
				Rbe[i][j] += Rib[k][i]*Rie[k][j];
		}

	return 1;
}
예제 #2
0
float Angle(vector3d &v1, vector3d &v2)
{
	float Dp1 = VectorMagnitude(v1)*VectorMagnitude(v2); // missing the angle calc
	float Dp2 = (v1.x*v2.x) + (v1.y*v2.y) + (v1.z*v2.z);

	float Ang = Dp2 / Dp1;
	if (Ang > 1.00000f)
		Ang = 1.00000f;
	if (Ang < -1.00000f)
		Ang = -1.00000f;
	Ang = (float)acos(Ang); //inverse cosine ang (cos-1 aka arccos)

	return Ang;
}
예제 #3
0
/*
 * From Roll-Pitch Gyro Drift Compensation, Rev 3. William Premerlani, 2012.
 */
static void rollPitch_drift_GPS(float Rbe[3][3], float accels_e_int[3],
								 float delT_between_updates, float *errRollPitch_b)
{
	float errRollPitch_e[3];
	float dGPSdt_e[3];
	
	GPSVelocityData gpsVelocity;
	GPSVelocityGet(&gpsVelocity);
	
	dGPSdt_e[0] = (gpsVelocity.North - drft->GPSV_old[0]) / delT_between_updates;
	dGPSdt_e[1] = (gpsVelocity.East - drft->GPSV_old[1]) / delT_between_updates;
	dGPSdt_e[2] = -GRAVITY + (gpsVelocity.Down - drft->GPSV_old[2]) / delT_between_updates;
	
	drft->GPSV_old[0] = gpsVelocity.North;
	drft->GPSV_old[1] = gpsVelocity.East;
	drft->GPSV_old[2] = gpsVelocity.Down;
	
	float normdGPSdt_e = VectorMagnitude(dGPSdt_e);
	
	//Take cross product of integrated accelerometer measurements with integrated earth frame accelerations. We should be using normalized dGPSdt, but we perform that calculation in the following line(s).
	CrossProduct((const float *)accels_e_int, (const float *)dGPSdt_e, errRollPitch_e);
	
	//Scale cross product
	errRollPitch_e[0] /= (normdGPSdt_e * delT_between_updates);
	errRollPitch_e[1] /= (normdGPSdt_e * delT_between_updates);
	errRollPitch_e[2] /= (normdGPSdt_e * delT_between_updates);
	
	//Rotate earth drift error back into body frame;
	rot_mult(Rbe, errRollPitch_e, errRollPitch_b, FALSE);
}
예제 #4
0
/* define behavior for bots in the attack state */
void AIAttackEnter(ai_t *brain){
  player_t *enemy;
		
  brain->prevState = brain->curState;
  brain->timer = 0;
  if((enemy = AIGetEnemy()) != NULL){
	/* get a vector pointing towards the enemy */
	VectorSubtract(&brain->enemyDir, &enemy->position, &brain->body->position);
	/* get the distance to the enemy */
	brain->enemy_dis = VectorMagnitude(&brain->enemyDir);
	VectorScale(&brain->enemyDir, &brain->enemyDir, 1.0/brain->enemy_dis);
	
	/* decide if we need to move closer and if we do, we're in the wrong
	 * state (should be in reposition */
	if(brain->enemy_dis > AI_DESIRED_RANGE){
	  AIRepositionEnter(brain);
	}
	else{
       brain->curState = AI_ATTACK;
       brain->timeout = AI_ATTACK_TIMEOUT + R_TIME_MOD*rand();
       PlayerSetAnimation(brain->body, PLAYER_ANIM_IDLE2);
       PlayerReset(brain->body); 
	}
  }
}
예제 #5
0
void Rv2Rot(float Rv[3], float R[3][3])
{
	// Compute rotation matrix from a rotation vector
	// To save .text space, uses Quaternion2R()
	float q[4];

	float angle = VectorMagnitude(Rv);
	if (angle <= 0.00048828125f) {
		// angle < sqrt(2*machine_epsilon(float)), so flush cos(x) to 1.0f
		q[0] = 1.0f;

        // and flush sin(x/2)/x to 0.5
		q[1] = 0.5f*Rv[0];
		q[2] = 0.5f*Rv[1];
		q[3] = 0.5f*Rv[2];
		// This prevents division by zero, while retaining full accuracy
	}
	else {
		q[0] = cosf(angle*0.5f);
		float scale = sinf(angle*0.5f) / angle;
		q[1] = scale*Rv[0];
		q[2] = scale*Rv[1];
		q[3] = scale*Rv[2];
	}

	Quaternion2R(q, R);
}
예제 #6
0
CVector3 VectorNormalize(CVector3 vVector)
{
    
    float magnitude = VectorMagnitude(vVector);                
    vVector = vVector / magnitude;        
    return vVector;                                        
}
예제 #7
0
파일: sound3d.c 프로젝트: AlexSteel/wine
/* angle between vectors - rad version */
static inline D3DVALUE AngleBetweenVectorsRad (const D3DVECTOR *a, const D3DVECTOR *b)
{
	D3DVALUE la, lb, product, angle, cos;
	/* definition of scalar product: a*b = |a|*|b|*cos... therefore: */
	product = ScalarProduct (a,b);
	la = VectorMagnitude (a);
	lb = VectorMagnitude (b);
	if (!la || !lb)
		return 0;

	cos = product/(la*lb);
	angle = acos(cos);
	TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f radians (%f degrees)\n",  a->x, a->y, a->z, b->x,
	      b->y, b->z, angle, RadToDeg(angle));
	return angle;	
}
예제 #8
0
// Unit vector in the v direction
Vector3D VectorNormalize(Vector3D v)
{
    float length = VectorMagnitude(v);
    if (length == 0) return v;

    return VectorScalarMult( v, 1.0/length);

}
예제 #9
0
파일: sound3d.c 프로젝트: AlexSteel/wine
/* calculates the length of vector's projection on another vector */
static inline D3DVALUE ProjectVector (const D3DVECTOR *a, const D3DVECTOR *p)
{
	D3DVALUE prod, result;
	prod = ScalarProduct(a, p);
	result = prod/VectorMagnitude(p);
	TRACE("length projection of (%f,%f,%f) on (%f,%f,%f) = %f\n", a->x, a->y, a->z, p->x,
              p->y, p->z, result);
	return result;
}
예제 #10
0
void SurfaceNormal(struct coords *NP, struct coords *FP, struct coords *LP)
{

 NP->x = FP->y * LP->z - FP->z * LP->y;
 NP->y = FP->z * LP->x - FP->x * LP->z;
 NP->z = FP->x * LP->y - FP->y * LP->x;
 VectorMagnitude(NP);
 UnitVector(NP);

} /* SurfaceNormal() */
예제 #11
0
void NormalizeVector(const GzCoord a, GzCoord &b)
{
	float mag = VectorMagnitude(a);

	// prevent divide-by-zero
	if (mag == 0.0f)
		mag = 1.0f;
	
	b[0] = a[0] / mag;
	b[1] = a[1] / mag;
	b[2] = a[2] / mag;
}
예제 #12
0
void RotatePoint(struct coords *A, Matx3x3 M)
{
struct coords B;

 B.x = A->x * M[0][0] + A->y * M[0][1] + A->z * M[0][2];
 B.y = A->x * M[1][0] + A->y * M[1][1] + A->z * M[1][2];
 B.z = A->x * M[2][0] + A->y * M[2][1] + A->z * M[2][2];

 A->x = B.x;
 A->y = B.y;
 A->z = B.z;
 VectorMagnitude(A);

} /* RotatePoint() */
예제 #13
0
/* also calculates average heading and position as well as confidence level */
void AIFlockSenseMates(aiflock_t *flock){
  
  elist_t *ptr1, *ptr2;
  float tempDis;
  vector_t temp;
  vector_t heading = {0, 0, 0};
  vector_t position = {0, 0, 0};
  
  /* for each flock member */ 
  for(ptr1 = flock->bots->next; ptr1 != flock->bots; ptr1 = ptr1->next){
	/* start with no confidence */
	ptr1->bot->confidence = 0;
    /* for each other flock member besides yourself */
	ptr1->bot->mate_dis = 1000000; /* just something big as an initializer */
    for(ptr2 = flock->bots->next; ptr2 != flock->bots; ptr2 = ptr2->next){
	  if(ptr1 != ptr2){
		VectorSubtract(&temp, &ptr1->bot->body->position, 
						&ptr2->bot->body->position);
        tempDis = VectorMagnitude2(&temp);
	    if(tempDis < ptr1->bot->mate_dis){
		  ptr1->bot->mate_dis = tempDis;
		  ptr1->bot->mate = ptr2->bot;
	    }
        if(tempDis < AI_CONFIDENCE_MAX){
		  ptr1->bot->confidence++;
		}		
	  } /* end check to make sure you're not looking at yourself */
    } /* end loop to look for others besides yourself */
    VectorAdd(&heading, &heading, &ptr1->bot->body->forward);
    VectorAdd(&position, &position, &ptr1->bot->body->position);
  } /* end loop for each flock member */

  /* finish average heading and position */
  VectorScale(&flock->heading, &heading, 1/flock->nBots);
  VectorScale(&flock->position, &position, 1/flock->nBots);
  flock->speed = VectorMagnitude(&flock->heading);
  VectorScale(&flock->heading, &flock->heading, 1.0/flock->speed);
}
예제 #14
0
/* define behavior for bots in reposition state */
void AIRepositionEnter(ai_t *brain){
  player_t *enemy;
  vector_t orthog;
  vector_t temp;
  float diff;
 
  brain->prevState = brain->curState;
  brain->curState = AI_REPOSITION;
  brain->timer = 0;
  brain->timeout = AI_REPO_TIMEOUT + R_TIME_MOD*rand();
  PlayerSetAnimation(brain->body, PLAYER_ANIM_RUN);
  PlayerReset(brain->body); 
  VectorClear(&brain->destination);
  
  /* we're currently fighting, we just want to move slightly
   * before attacking again */ 
  if((enemy = AIGetEnemy()) != NULL){
	/* get a vector pointing towards the enemy */
	VectorSubtract(&brain->enemyDir, &enemy->position, &brain->body->position);
	/* get the distance to the enemy */
	brain->enemy_dis = VectorMagnitude(&brain->enemyDir);
	VectorScale(&brain->enemyDir, &brain->enemyDir, 1.0/brain->enemy_dis);
	/* get a vector orthogonal to the direction of the enemy */
	VectorCross(&orthog, &brain->enemyDir, &brain->body->up);
	/* decide if we need to move closer */
	if(brain->enemy_dis > AI_DESIRED_RANGE){
      diff = brain->enemy_dis - AI_DESIRED_RANGE + UNIRAND(6.0);
	  VectorScale(&temp, &brain->enemyDir, diff);
	  VectorAdd(&brain->destination, &temp, &brain->body->position);
	}
	/* now move sideways some */
	diff = AI_MOVE_SIZE + UNIRAND(6.0);
	VectorScale(&temp, &orthog, 0.2*SIGN(UNIRAND(1.0))*diff);
	VectorAdd(&brain->destination, &brain->destination, &temp);
  }
}
예제 #15
0
void Laser::Update(float a_Dt)
{
	m_Sprite.sprite->setPosition(m_StartPos);

	//raycast to determine the max length of this laser
	cpVect cpStartPos;
	cpStartPos.x = m_StartPos.x;
	cpStartPos.y = m_StartPos.y;
	sf::Vector2f addVector = m_FacingDir * MAX_LASER_DIST;
	sf::Vector2f sfEndPos = m_StartPos + addVector;
	cpVect cpEndPos;
	cpEndPos.x = sfEndPos.x;
	cpEndPos.y = sfEndPos.y;
	cpSegmentQueryInfo info;
	info.n = cpv(0,0);
	info.t = 0;
	info.shape = NULL;

	//cast ray
	cpShape* collided = cpSpaceSegmentQueryFirst(&m_Space, cpStartPos, cpEndPos, ~(cpLayers)COLLIDABLE::GLASSBLOCK, CP_NO_GROUP, &info);

	//grab some helper data
	m_MaxLength = float(min( cpSegmentQueryHitDist(cpStartPos, cpEndPos, info), MAX_LASER_DIST ));
	m_hitPoint = cpSegmentQueryHitPoint(cpStartPos, cpEndPos, info);

	//extend or reduce the laser to the max length
	if(m_CurLength < m_MaxLength)
	{
		//update end position
		//f**k you, lasers have velocity (but only when they're growing)
		sf::Vector2f newDist = m_FacingDir * LASER_VELOCITY * a_Dt;
		m_EndPos += newDist;
		m_CurLength += VectorMagnitude(newDist);

		//update sprite
		float baseSize = float(m_Sprite.sprite->getTexture()->getSize().x);
		sf::Vector2f diff = m_EndPos - m_StartPos;
		float newSize = VectorMagnitude(diff);
		m_Sprite.sprite->setScale(newSize / baseSize, 1);
		//m_resMgr.RemoveDrawableSprite(&m_endSprite);
	}
	else
	{
		//update end position
		m_EndPos = m_StartPos + m_FacingDir * m_MaxLength;
		sf::Vector2f diff = m_EndPos - m_StartPos;
		m_endSprite.sprite->setPosition(m_EndPos);
		//sf::Vector2f diff = m_blockPos - m_StartPos;
		m_CurLength = VectorMagnitude(diff);

		//update sprite
		float baseSize = float(m_Sprite.sprite->getTexture()->getSize().x);
		m_Sprite.sprite->setScale(m_CurLength / baseSize, 1);
		//m_resMgr.AddDrawableSprite(&m_endSprite);

		m_endDrawnHack = true;
	}
	
	/*if(m_pNextChainSegment)
	{
		m_pNextChainSegment->Update(a_Dt);
	}*/
}
예제 #16
0
void Laser::Update(float a_Dt)
{
	//raycast to determine the max length of this laser
	cpVect cpStartPos;
	cpStartPos.x = m_StartPos.x;
	cpStartPos.y = m_StartPos.y;
	sf::Vector2f addVector = m_FacingDir * MAX_LASER_DIST;
	sf::Vector2f sfEndPos = m_StartPos + addVector;
	cpVect cpEndPos;
	cpEndPos.x = sfEndPos.x;
	cpEndPos.y = sfEndPos.y;
	cpSegmentQueryInfo info;
	info.n = cpv(0,0);
	info.t = 0;
	info.shape = NULL;

	//cast ray
	cpShape* collided = cpSpaceSegmentQueryFirst(&m_Space, cpStartPos, cpEndPos, CP_ALL_LAYERS, CP_NO_GROUP, &info);

	//grab some helper data
	m_MaxLength = float(min( cpSegmentQueryHitDist(cpStartPos, cpEndPos, info), MAX_LASER_DIST ));
	m_hitPoint = cpSegmentQueryHitPoint(cpStartPos, cpEndPos, info);

	GameObject* pGameObj = NULL;
	if(collided)
		pGameObj = (GameObject*)collided->data;

	/*
	//check to see if we hit the player
	Player* pPlayer = NULL;
	bool colPlayer = false;
	if(pGameObj && pGameObj->GetType() == PLAYER)
	{
		//TODO: only reflect if the player is within 180 degrees of us?

		//reflect le laser
		if(!m_pNextChainSegment)
			ExtendNewSegment(m_FacingDir);
		
		pPlayer = (Player*)pGameObj;
		m_MaxLength = pPlayer->GetPosition().x;

		colPlayer = true;
	}
	else
	{
		//stop reflecting laser
		Laser* pCurLaser = m_pNextChainSegment;
		m_pNextChainSegment = NULL;
		while(pCurLaser)
		{
			m_resMgr.RemoveDrawableSprite(pCurLaser->GetSprite());
			pCurLaser = pCurLaser->GetNextSegment();
			delete pCurLaser;
		}
	}*/

	//extend or reduce the laser to the max length
	if(m_CurLength < m_MaxLength)
	{
		//update end position
		//f**k you, lasers have velocity (but only when they're growing)
		sf::Vector2f newDist = m_FacingDir * LASER_VELOCITY * a_Dt;
		m_EndPos += newDist;
		m_CurLength += VectorMagnitude(newDist);

		//update sprite
		float baseSize = float(m_Sprite.sprite->getTexture()->getSize().x);
		sf::Vector2f diff = m_EndPos - m_StartPos;
		float newSize = VectorMagnitude(diff);
		m_Sprite.sprite->setScale(newSize / baseSize, 1);

		if(m_endDrawn)
		{
			m_resMgr.RemoveDrawableSprite(&m_endSprite);
			m_resMgr.RemoveDrawableSprite(&m_reflectSprite);
			m_endDrawn = false;
		}
	}
	else if(m_CurLength > m_MaxLength)
	{
		bool colPlayer = false;
		//update end position
		m_EndPos = m_StartPos + m_FacingDir * m_MaxLength;
		sf::Vector2f diff = m_EndPos - m_StartPos;
		m_CurLength = VectorMagnitude(diff);

		//update sprite
		float baseSize = float(m_Sprite.sprite->getTexture()->getSize().x);
		m_Sprite.sprite->setScale(m_CurLength / baseSize, 1);

		//Show the end sprite
		if (!m_endDrawn)
		{
			if(colPlayer)
				m_resMgr.AddDrawableSprite(&m_reflectSprite);
			else
				m_resMgr.AddDrawableSprite(&m_endSprite);
			m_endDrawn = true;
		}	
		m_endDrawnHack = true;
	}
	
	/*
	//update reflected laser segment
	if(pPlayer && m_pNextChainSegment)
	{
		//get the player's angle and position
		m_pNextChainSegment->SetPosition(pPlayer->GetPosition());
		m_pNextChainSegment->SetFacingDir(pPlayer->GetRedirectDir());		//assumes already normalised
	}

	//update endsprite
	if(m_endDrawn)
	{
		//m_endSprite.sprite->setPosition(m_Sprite.sprite->getPosition().x+m_Sprite.sprite->getScale().x,m_Sprite.sprite->getPosition().y);
		if(colPlayer && pPlayer)
		{
			sf::Vector2u sprSize = pPlayer->GetSprite()->sprite->getTexture()->getSize();//sprSize
			sf::Vector2f playerPos = pPlayer->GetPosition();
			m_reflectSprite.sprite->setPosition(playerPos.x, playerPos.y);
		}
		else
			m_endSprite.sprite->setPosition(float(m_hitPoint.x)-4, float(m_hitPoint.y)-16);
		if(m_pAnimator)
			m_pAnimator->Update(a_Dt);
	}
	*/
}
예제 #17
0
void AIAttackUpdate(ai_t *brain){
  float strength;
  float diff;
  static int count;
  player_t *enemy;
  vector_t prediction = {0.0, 0.0, 0.0};
  vector_t temp;
  projectile_t *proj;
  
  brain->timer++;
  /* use info you can see from the player to figure out where he'll be in
   * the next step...we're trying to aim with some accuracy. The following
   * calculations approximate the exact solution which can be found for
   * the collision time of two moving projectiles. The general solution
   * only exists under certain conditions. This always exists, and works
   * quite well at reasonable range */
  enemy = AIGetEnemy();
  if(enemy->lFlag){
    VectorSubtract(&prediction, &prediction, &enemy->right);
  }
  else if(enemy->rFlag){
    VectorAdd(&prediction, &prediction, &enemy->right);
  }
  if(enemy->fFlag){
    VectorAdd(&prediction, &prediction, &enemy->forward);
  }
  else if(enemy->bFlag){
    VectorSubtract(&prediction, &prediction, &enemy->forward);
  }
  VectorSubtract(&temp, &enemy->position, &brain->body->position);
  VectorAdd(&temp, &temp, &prediction);
  VectorScale(&brain->enemyDir, &temp, enemy->speed);
  brain->enemy_dis = VectorMagnitude(&brain->enemyDir);
  VectorScale(&brain->enemyDir, &brain->enemyDir, 1.0/brain->enemy_dis);
  brain->dotEnemy = VectorDot(&brain->enemyDir, &brain->body->forward);
 
  /* decide if we need to move closer */
  if(brain->enemy_dis > AI_DESIRED_RANGE){
    diff = brain->enemy_dis - AI_DESIRED_RANGE + UNIRAND(3.0);
    VectorScale(&temp, &brain->enemyDir, diff);
    VectorAdd(&brain->destination, &temp, &brain->body->position);
	AIUpdateForwardByDesire(brain, &brain->destination);
	PlayerMoveForward(brain->body, brain->body->speed);
  }
  else{
    if(brain->dotEnemy < 1){
	  strength = 2 - brain->dotEnemy;
	  /* we need to aim at our opponent pitch/yaw */
      brain->body->yaw += 
			MAX_TURN*strength*(AIGetTurnDirectionH(brain, &brain->enemyDir));
      brain->body->pitch += 
			MAX_TURN*strength*(AIGetTurnDirectionV(brain, &brain->enemyDir));
    }
    if(!(count % AI_ATTACK_PERIOD)){
	  /* fire the projectile in the exactly direction even though we may
	   * not have our bodies pointed there yet */
      proj = ProjectileNew(&brain->enemyDir, &brain->body->position, 
				      PROJ_SPEED, 2);
      PListInsertAfter(plist, proj);
	  count = 0;
    } count++;
  }
}
예제 #18
0
/*
 * Although yaw correction is done in horizontal plane, it is 
 *  computed in 3 dimensions, just in case we change our minds later.
 */
void yaw_drift_MagGPS(float Rbe[3][3], bool gpsNewData_flag, bool magNewData_flag, float *errYaw_b)
{
#if defined (PIOS_INCLUDE_GPS) || defined (PIOS_INCLUDE_MAGNETOMETER)
	
	//      Form the horizontal direction over ground based on rmat
	float horizDirOverGndRmat[3];
	
	//Define forward vector in earth frame, Rbe' * [1;0;0], and eliminate vertical component from vector
	horizDirOverGndRmat[0] = Rbe[0][0];
	horizDirOverGndRmat[1] = Rbe[0][1];
	horizDirOverGndRmat[2] = 0;
	
#if defined (PIOS_INCLUDE_GPS)
	if (gpsNewData_flag) {
		
		GPSVelocityData gpsVelocity;
		GPSVelocityGet(&gpsVelocity);
		
		if (fabs(gpsVelocity.North) > GPS_SPEED_MIN
		    || fabs(gpsVelocity.East) > GPS_SPEED_MIN) {
			float errorGPSYaw_e;
			float errorGPSYaw_b[3];
			float normGPS =
			sqrtf(gpsVelocity.North * gpsVelocity.North +
					gpsVelocity.East * gpsVelocity.East);
			float horizDirOverGndGPS[3] = { gpsVelocity.North / normGPS, gpsVelocity.East / normGPS, 0 };	//Normalized vector
			
			// vector cross product to get the rotation error in ground frame. However, save several processor cycles by 
			// condensing the math to take advantage of the cross products null entries on the x and y elements.
			// errorGPSYaw_e = horizDirOverGndRmat X horizDirOverGndGPS
			errorGPSYaw_e =
			horizDirOverGndRmat[0] * horizDirOverGndGPS[1] -
			horizDirOverGndGPS[0] * horizDirOverGndRmat[1];
			
			// Rotate error to body frame. Again, take advantage of the yaw error vector [0;0;errorGPSYaw_e]'s null entries
			// errorGPSYaw_b = Rbe * errorGPSYaw_e;
			errorGPSYaw_b[0] = Rbe[0][2] * errorGPSYaw_e;
			errorGPSYaw_b[1] = Rbe[1][2] * errorGPSYaw_e;
			errorGPSYaw_b[2] = Rbe[2][2] * errorGPSYaw_e;
			
			//Sum error with existing error
			errYaw_b[0] += errorGPSYaw_b[0] * GPS_YAW_KP;
			errYaw_b[1] += errorGPSYaw_b[1] * GPS_YAW_KP;
			errYaw_b[2] += errorGPSYaw_b[2] * GPS_YAW_KP;
		}
	}
#endif
	
	// TODO: Create a flag to indicate whether mag data is present (or check for updates of MagnetometerData)
#if defined (PIOS_INCLUDE_MAGNETOMETER)
	if (magNewData_flag) {
		MagnetometerData magnetometerData;
		MagnetometerGet(&magnetometerData);
		
		float errorMagYaw_e;
		float errorMagYaw_b[3];
		float horizDirOverGndMag[3];
		float mags_b[3] = { magnetometerData.x, magnetometerData.y, magnetometerData.z };
		
		// Rotate magnetometer to earth frame and eliminate vertical component
		rot_mult(Rbe, mags_b, horizDirOverGndMag, true);
		horizDirOverGndMag[2] = 0;
		
		//Compute norm
		float normMag = VectorMagnitude(horizDirOverGndMag);
		
		//Normalize mag_vector. Recall that horizDirOverGndMag[2]=0
		horizDirOverGndMag[0] /= normMag;
		horizDirOverGndMag[1] /= normMag;
		
		// vector cross product to get the rotation error in ground frame. However, save several processor cycles by 
		// condensing the math to take advantage of the cross products null entries on the x and y elements.
		// errorMagYaw_e = horizDirOverGndRmat X horizDirOverGndMag
		errorMagYaw_e = horizDirOverGndRmat[0] * horizDirOverGndMag[1] -
		horizDirOverGndMag[0] * horizDirOverGndRmat[1];
		
		// Rotate error to body frame. Again, take advantage of the yaw error vector [0;0;errorGPSYaw_e]'s null entries
		// errorMagYaw_b = Rbe * errorMagYaw_e;
		errorMagYaw_b[0] = Rbe[0][2] * errorMagYaw_e;
		errorMagYaw_b[1] = Rbe[1][2] * errorMagYaw_e;
		errorMagYaw_b[2] = Rbe[2][2] * errorMagYaw_e;
		
		errYaw_b[0] += errorMagYaw_b[0] * MAG_YAW_KP;
		errYaw_b[1] += errorMagYaw_b[1] * MAG_YAW_KP;
		errYaw_b[2] += errorMagYaw_b[2] * MAG_YAW_KP;
	}
#endif
#endif
}
예제 #19
0
/*
 * Correct sensor drift, using the DCM approach from W. Premerlani et. al
 */
void Premerlani_GPS(float *accels, float *gyros, float Rbe[3][3], const float delT, bool GPS_Drift_Compensation, GlobalAttitudeVariables *glblAtt, float *omegaCorrP)
{
	float errYaw_b[3] = { 0, 0, 0 };
	float errRollPitch_b[3] = { 0, 0, 0 };
	
	float normOmegaScalar = VectorMagnitude(gyros);
	
	//Correct roll-pitch drift via GPS and accelerometer
	//The math is derived from Roll-Pitch Gyro Drift Compensation, Rev.3, by W. Premerlani
#if defined (PIOS_INCLUDE_GPS)
	if (drft->gpsPresent_flag && GPS_Drift_Compensation) {
		float accels_e[3];
		
		//Rotate accelerometer readings into Earth frame. Note that we need to take the transpose of Rbe.
		rot_mult(Rbe, accels, accels_e, TRUE);
		
		//Integrate accelerometer measurements in Earth frame
		drft->accels_e_integrator[0] += accels_e[0] * delT;
		drft->accels_e_integrator[1] += accels_e[1] * delT;
		drft->accels_e_integrator[2] += accels_e[2] * delT;
		
		drft->delT_between_GPS += delT;
		
		//Check if the GPS has new information.
		if (!
		    (drft->
		     gpsVelocityDataConsumption_flag & GPS_CONSUMED_BY_RPY)) {
				 
				 //Compute drift correction, errRollPitch_b, from GPS
				 rollPitch_drift_GPS(Rbe, drft->accels_e_integrator,
											drft->delT_between_GPS,
											errRollPitch_b);
				 
				 //Reset integrator
				 memset(drft->accels_e_integrator, 0,
						  sizeof(drft->accels_e_integrator));
				 
				 //Mark GPS data as consumed by this function
				 drft->gpsVelocityDataConsumption_flag |=
			    GPS_CONSUMED_BY_RPY;
				 
				 drft->delT_between_GPS = 0;
				 
			 }
	}
#endif
	
	if (!GPS_Drift_Compensation) {
#if defined (PIOS_INCLUDE_GPS) && 0 || defined (PIOS_INCLUDE_MAGNETOMETER)
		if (!(drft->gpsVelocityDataConsumption_flag & GPS_CONSUMED_BY_Y)) {
			// We're actually using new GPS data here, but it's already been stored in old by the previous function
			yaw_drift_MagGPS(Rbe, true, drft->magNewData_flag, errYaw_b);	
			
			// Mark GPS data as consumed by this function
			drft->gpsVelocityDataConsumption_flag |= GPS_CONSUMED_BY_Y;
		} else {
			// In addition to calculating the roll-pitch-yaw error, we can calculate yaw drift, errYaw_b, based on GPS and attitude data
			// We're actually using new GPS data here, but it's already been stored in old by the previous function
			yaw_drift_MagGPS(Rbe, false, drft->magNewData_flag, errYaw_b);	
		}
		
		// Reset flag. Not the best place to do it, but it's messy anywhere else
		if (drft->magNewData_flag) {
			drft->magNewData_flag = false;
		}
#endif
		//In addition, we can calculate roll-pitch error with only the aid of an accelerometer
#if defined(PIOS_GPS_PROVIDES_AIRSPEED)
		AirspeedActualData airspeedActualData;
		AirspeedActualGet(&airspeedActualData);
		float airspeed_tas = airspeedActualData.TrueAirspeed;
#else
		float airspeed_tas = 0;
#endif
		rollPitch_drift_accel(accels, gyros, Rbe, airspeed_tas,
									 errRollPitch_b);
	}
	
	// Calculate gyro drift, based on all errors
	gyro_drift(gyros, errYaw_b, errRollPitch_b, normOmegaScalar, delT, omegaCorrP, drft->omegaCorrI);
	
	//Calculate final drift response
	gyros[0] += omegaCorrP[0] + drft->omegaCorrI[0];
	gyros[1] += omegaCorrP[1] + drft->omegaCorrI[1];
	gyros[2] += omegaCorrP[2] + drft->omegaCorrI[2];
	
	//Add 0.0001% of proportional error back into gyroscope bias offset. This keeps DC elements out of the raw gyroscope data.
	glblAtt->gyro_correct_int[0] += omegaCorrP[0] / 1000000.0f;
	glblAtt->gyro_correct_int[1] += omegaCorrP[1] / 1000000.0f;
	
	// Because most crafts wont get enough information from gravity to zero yaw gyro, we try
	// and make it average zero (weakly)
	glblAtt->gyro_correct_int[2] += -gyros[2] * glblAtt->yawBiasRate;
}
예제 #20
0
/**
 * It connects waypoints together with straight lines, and fillets, so that the
 * vehicle dynamics, i.e. Dubin's cart constraints, are taken into account. However
 * the "direct with filleting" path planner still assumes that there are no obstacles
 * along the path.
 * The general approach is that before adding a new segment, the
 * path planner looks ahead at the next waypoint, and adds in fillets that align the vehicle with
 * this next waypoint.
 * @param[in] original the flight model to process
 * @param[out] new the resulting flight model
 * @return true for success, false for failure
 */
bool PathFillet::processPath(FlightDataModel *model)
{
    new_model = new FlightDataModel(this);

    int newWaypointIdx = 0;

    float pos_prev[3];
    float pos_current[3];
    float pos_next[3];

    float previous_curvature;

    for(int wpIdx = 0; wpIdx < model->rowCount(); wpIdx++) {

        // Get the location
        pos_current[0] = model->data(model->index(wpIdx, FlightDataModel::NED_NORTH)).toDouble();
        pos_current[1] = model->data(model->index(wpIdx, FlightDataModel::NED_EAST)).toDouble();
        pos_current[2] = model->data(model->index(wpIdx, FlightDataModel::NED_DOWN)).toDouble();

        // Get the internal parameters
        quint8 Mode = model->data(model->index(wpIdx, FlightDataModel::MODE), Qt::UserRole).toInt();
        float ModeParameters = model->data(model->index(wpIdx, FlightDataModel::MODE_PARAMS)).toFloat();
        float finalVelocity = model->data(model->index(wpIdx, FlightDataModel::VELOCITY)).toFloat();

        // Determine if the path is a straight line or if it arcs
        float curvature = 0;
        switch (Mode)
        {
        case Waypoint::MODE_CIRCLEPOSITIONRIGHT:
            return false;
        case Waypoint::MODE_FLYCIRCLERIGHT:
        case Waypoint::MODE_DRIVECIRCLERIGHT:
            curvature = 1.0f/ModeParameters;
            break;
        case Waypoint::MODE_CIRCLEPOSITIONLEFT:
            return false;
        case Waypoint::MODE_FLYCIRCLELEFT:
        case Waypoint::MODE_DRIVECIRCLELEFT:
            curvature = -1.0f/ModeParameters;
            break;
        }

        // First waypoint cannot be fileting since we don't have start.  Keep intact.
        if (wpIdx == 0) {
            setNewWaypoint(newWaypointIdx++, pos_current, finalVelocity, curvature);
            continue;
        }

        // Only add fillets if the radius is greater than 0, and this is not the last waypoint
        if (fillet_radius > 0 && wpIdx < (model->rowCount() - 1))
        {
            // If waypoints have been set on the new model then use that to know the previous
            // location.  Otherwise this is setting the first segment.  On board that uses the
            // current location but while planning offline this is unknown so we use home.
            if (newWaypointIdx > 0) {
                pos_prev[0] = new_model->data(new_model->index(newWaypointIdx-1, FlightDataModel::NED_NORTH)).toDouble();
                pos_prev[1] = new_model->data(new_model->index(newWaypointIdx-1, FlightDataModel::NED_EAST)).toDouble();
                pos_prev[2] = new_model->data(new_model->index(newWaypointIdx-1, FlightDataModel::NED_DOWN)).toDouble();
                // TODO: fix sign
                float previous_radius = new_model->data(new_model->index(newWaypointIdx-1, FlightDataModel::MODE_PARAMS)).toDouble();
                previous_curvature = (previous_radius < 1e-4) ? 0 : 1.0 / previous_radius;
            } else {
                // Use the home location as the starting point of paths.
                pos_prev[0] = 0;
                pos_prev[1] = 0;
                pos_prev[2] = 0;
                previous_curvature = 0;
            }

            // Get the settings for the upcoming waypoint
            pos_next[0] = model->data(model->index(wpIdx+1, FlightDataModel::NED_NORTH)).toDouble();
            pos_next[1] = model->data(model->index(wpIdx+1, FlightDataModel::NED_EAST)).toDouble();
            pos_next[2] = model->data(model->index(wpIdx+1, FlightDataModel::NED_DOWN)).toDouble();
            quint8 NextMode = model->data(model->index(wpIdx + 1, FlightDataModel::MODE), Qt::UserRole).toInt();
            float NextModeParameter = model->data(model->index(wpIdx + 1, FlightDataModel::MODE_PARAMS), Qt::UserRole).toInt();

            NextModeParameter = 0;
            bool future_path_is_circle = NextMode == Waypoint::MODE_CIRCLEPOSITIONRIGHT ||
                    NextMode == Waypoint::MODE_CIRCLEPOSITIONLEFT;

            // The vector in and out of the current waypoint
            float q_future[3];
            float q_future_mag = 0;
            float q_current[3];
            float q_current_mag = 0;

            // In the case of line-line intersection lines, this is simply the direction of
            // the old and new segments.
            if (curvature == 0 &&
                    (NextModeParameter == 0 || future_path_is_circle)) { // Fixme: waypoint_future.ModeParameters needs to be replaced by waypoint_future.Mode. FOr this, we probably need a new function to handle the switch(waypoint.Mode)

                // Vector from past to present switching locus
                q_current[0] = pos_current[0] - pos_prev[0];
                q_current[1] = pos_current[1] - pos_prev[1];

                // Calculate vector from preset to future switching locus
                q_future[0] = pos_next[0] - pos_current[0];
                q_future[1] = pos_next[1] - pos_current[1];
            }
            //In the case of line-arc intersections, calculate the tangent of the new section.
            else if (curvature == 0 &&
                     (NextModeParameter != 0 && !future_path_is_circle)) { // Fixme: waypoint_future.ModeParameters needs to be replaced by waypoint_future.Mode. FOr this, we probably need a new function to handle the switch(waypoint.Mode)
                // Old segment: straight line
                q_current[0] = pos_current[0] - pos_prev[0];
                q_current[1] = pos_current[1] - pos_prev[1];

                // New segment: Vector perpendicular to the vector from arc center to tangent point
                bool clockwise = curvature > 0;
                qint8 lambda;

                if (clockwise == true) { // clockwise
                    lambda = 1;
                } else { // counterclockwise
                    lambda = -1;
                }

                // Calculate circle center
                float arcCenter_NE[2];
                find_arc_center(pos_current, pos_next, 1.0f/curvature, arcCenter_NE, curvature > 0, true);

                // Vector perpendicular to the vector from arc center to tangent point
                q_future[0] = -lambda*(pos_current[1] - arcCenter_NE[1]);
                q_future[1] = lambda*(pos_current[0] - arcCenter_NE[0]);
            }
            //In the case of arc-line intersections, calculate the tangent of the old section.
            else if (curvature != 0 && (NextModeParameter == 0 || future_path_is_circle)) { // Fixme: waypoint_future.ModeParameters needs to be replaced by waypoint_future.Mode. FOr this, we probably need a new function to handle the switch(waypoint.Mode)
                // Old segment: Vector perpendicular to the vector from arc center to tangent point
                bool clockwise = previous_curvature > 0;
                bool minor = true;
                qint8 lambda;

                if ((clockwise == true && minor == true) ||
                        (clockwise == false && minor == false)) { //clockwise minor OR counterclockwise major
                    lambda = 1;
                } else { //counterclockwise minor OR clockwise major
                    lambda = -1;
                }

                // Calculate old circle center
                float arcCenter_NE[2];
                find_arc_center(pos_prev, pos_current,
                                1.0f/previous_curvature, arcCenter_NE,	clockwise, minor);

                // Vector perpendicular to the vector from arc center to tangent point
                q_current[0] = -lambda*(pos_current[1] - arcCenter_NE[1]);
                q_current[1] = lambda*(pos_current[0] - arcCenter_NE[0]);

                // New segment: straight line
                q_future [0] = pos_next[0] - pos_current[0];
                q_future [1] = pos_next[1] - pos_current[1];
            }
            //In the case of arc-arc intersections, calculate the tangent of the old and new sections.
            else if (curvature != 0 && (NextModeParameter != 0 && !future_path_is_circle)) { // Fixme: waypoint_future.ModeParameters needs to be replaced by waypoint_future.Mode. FOr this, we probably need a new function to handle the switch(waypoint.Mode)
                // Old segment: Vector perpendicular to the vector from arc center to tangent point
                bool clockwise = previous_curvature > 0;
                bool minor = true;
                qint8 lambda;

                if ((clockwise == true && minor == true) ||
                        (clockwise == false && minor == false)) { //clockwise minor OR counterclockwise major
                    lambda = 1;
                } else { //counterclockwise minor OR clockwise major
                    lambda = -1;
                }

                // Calculate old arc center
                float arcCenter_NE[2];
                find_arc_center(pos_prev, pos_current,
                                1.0f/previous_curvature, arcCenter_NE,	clockwise, minor);

                // New segment: Vector perpendicular to the vector from arc center to tangent point
                q_current[0] = -lambda*(pos_prev[1] - arcCenter_NE[1]);
                q_current[1] = lambda*(pos_prev[0] - arcCenter_NE[0]);

                if (curvature > 0) { // clockwise
                    lambda = 1;
                } else { // counterclockwise
                    lambda = -1;
                }

                // Calculate new arc center
                find_arc_center(pos_current, pos_next, 1.0f/curvature, arcCenter_NE, curvature > 0, true);

                // Vector perpendicular to the vector from arc center to tangent point
                q_future[0] = -lambda*(pos_current[1] - arcCenter_NE[1]);
                q_future[1] = lambda*(pos_current[0] - arcCenter_NE[0]);
            }

            q_current[2] = 0;
            q_current_mag = VectorMagnitude(q_current); //Normalize
            q_future[2] = 0;
            q_future_mag = VectorMagnitude(q_future); //Normalize

            // Normalize q_current and q_future
            if (q_current_mag > 0) {
                for (int i=0; i<3; i++)
                    q_current[i] = q_current[i]/q_current_mag;
            }
            if (q_future_mag > 0) {
                for (int i=0; i<3; i++)
                    q_future[i] = q_future[i]/q_future_mag;
            }

            // Compute heading difference between current and future tangents.
            float theta = angle_between_2d_vectors(q_current, q_future);

            // Compute angle between current and future tangents.
            float rho = circular_modulus_rad(theta - M_PI);

            // Compute half angle
            float rho2 = rho/2.0f;

            // Circle the outside of acute angles
            if (fabsf(rho) < M_PI/3.0f) {
                float R = fillet_radius;
                if (q_current_mag>0 && q_current_mag< R*sqrtf(3))
                    R = q_current_mag/sqrtf(3)-0.1f; // Remove 10cm to guarantee that no two points overlap.
                if (q_future_mag >0 && q_future_mag < R*sqrtf(3))
                    R = q_future_mag /sqrtf(3)-0.1f; // Remove 10cm to guarantee that no two points overlap.

                // The sqrt(3) term comes from the fact that the triangle that connects the center of
                // the first/second arc with the center of the second/third arc is a 1-2-sqrt(3) triangle
                float f1[3] = {pos_current[0] - R*q_current[0]*sqrtf(3), pos_current[1] - R*q_current[1]*sqrtf(3), pos_current[2]};
                float f2[3] = {pos_current[0] + R*q_future[0]*sqrtf(3), pos_current[1] + R*q_future[1]*sqrtf(3), pos_current[2]};

                // Add the waypoint segment
                newWaypointIdx += addNonCircleToSwitchingLoci(f1, finalVelocity, curvature, newWaypointIdx);

                float gamma = atan2f(q_current[1], q_current[0]);

                // Compute eta, which is the angle between the horizontal and the center of the filleting arc f1 and
                // sigma, which is the angle between the horizontal and the center of the filleting arc f2.
                float eta;
                float sigma;
                if (theta > 0) {  // Change in direction is clockwise, so fillets are clockwise
                    eta = gamma - M_PI/2.0f;
                    sigma = gamma + theta - M_PI/2.0f;
                }
                else {
                    eta = gamma + M_PI/2.0f;
                    sigma = gamma + theta + M_PI/2.0f;
                }

                // This starts the fillet into the circle
                float pos[3] = {(pos_current[0] + f1[0] + R*cosf(eta))/2,
                                (pos_current[1] + f1[1] + R*sinf(eta))/2,
                                pos_current[2]};
                setNewWaypoint(newWaypointIdx++, pos, finalVelocity, -SIGN(theta)*1.0f/R);

                // This is the halfway point through the circle
                pos[0] = pos_current[0] + R*cosf(gamma);
                pos[1] = pos_current[1] + R*sinf(gamma);
                pos[2] = pos_current[2];
                setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta)*1.0f/R);

                // This is the transition from the circle to the fillet back onto the path
                pos[0] = (pos_current[0] + (f2[0] + R*cosf(sigma)))/2;
                pos[1] = (pos_current[1] + (f2[1] + R*sinf(sigma)))/2;
                pos[2] = pos_current[2];
                setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta)*1.0f/R);

                // This is the point back on the path
                pos[0] = f2[0];
                pos[1] = f2[1];
                pos[2] = pos_current[2];
                setNewWaypoint(newWaypointIdx++, pos, finalVelocity, -SIGN(theta)*1.0f/R);
            }
            else if (theta != 0) { // The two tangents have different directions
                float R = fillet_radius;

                // Remove 10cm to guarantee that no two points overlap. This would be better if we solved it by removing the next point instead.
                if (q_current_mag>0 && q_current_mag<fabsf(R/tanf(rho2)))
                    R = qMin(R, q_current_mag*fabsf(tanf(rho2))-0.1f);
                if (q_future_mag>0  && q_future_mag <fabsf(R/tanf(rho2)))
                    R = qMin(R, q_future_mag* fabsf(tanf(rho2))-0.1f);

                // Add the waypoint segment
                float f1[3];
                f1[0] = pos_current[0] - R/fabsf(tanf(rho2))*q_current[0];
                f1[1] = pos_current[1] - R/fabsf(tanf(rho2))*q_current[1];
                f1[2] = pos_current[2];
                newWaypointIdx += addNonCircleToSwitchingLoci(f1, finalVelocity, curvature, newWaypointIdx);

                // Add the filleting segment in preparation for the next waypoint
                float pos[3] = {pos_current[0] + R/fabsf(tanf(rho2))*q_future[0],
                                pos_current[1] + R/fabsf(tanf(rho2))*q_future[1],
                                pos_current[2]};
                setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta)*1.0f/R);

            }
            else {
                // In this case, the two tangents are colinear
                newWaypointIdx += addNonCircleToSwitchingLoci(pos_current, finalVelocity, curvature, newWaypointIdx);
            }
        }
        else if (wpIdx == model->rowCount()-1)
            // This is the final waypoint
            newWaypointIdx += addNonCircleToSwitchingLoci(pos_current, finalVelocity, curvature, newWaypointIdx);
    }

    // Migrate the data to the original model now it is complete
    model->replaceData(new_model);
    delete new_model;
    new_model = NULL;

    return true;
}
예제 #21
0
파일: sound3d.c 프로젝트: AlexSteel/wine
void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
{
	/* volume, at which the sound will be played after all calcs. */
	D3DVALUE lVolume = 0;
	/* stuff for distance related stuff calc. */
	D3DVECTOR vDistance;
	D3DVALUE flDistance = 0;
	/* panning related stuff */
	D3DVALUE flAngle, flAngle2;
	D3DVECTOR vLeft;
	int i, num_main_speakers;
	float a, ingain;
	/* doppler shift related stuff */

	TRACE("(%p)\n",dsb);

	/* initial buffer volume */
	lVolume = dsb->ds3db_lVolume;
	
	switch (dsb->ds3db_ds3db.dwMode)
	{
		case DS3DMODE_DISABLE:
			TRACE("3D processing disabled\n");
			/* this one is here only to eliminate annoying warning message */
			DSOUND_RecalcVolPan (&dsb->volpan);
			return;
		case DS3DMODE_NORMAL:
			TRACE("Normal 3D processing mode\n");
			/* we need to calculate distance between buffer and listener*/
			vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition);
			flDistance = VectorMagnitude (&vDistance);
			break;
		case DS3DMODE_HEADRELATIVE:
			TRACE("Head-relative 3D processing mode\n");
			/* distance between buffer and listener is same as buffer's position */
			vDistance = dsb->ds3db_ds3db.vPosition;
			flDistance = VectorMagnitude (&vDistance);
			break;
	}
	
	if (flDistance > dsb->ds3db_ds3db.flMaxDistance)
	{
		/* some apps don't want you to hear too distant sounds... */
		if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE)
		{
			dsb->volpan.lVolume = DSBVOLUME_MIN;
			DSOUND_RecalcVolPan (&dsb->volpan);		
			/* i guess mixing here would be a waste of power */
			return;
		}
		else
			flDistance = dsb->ds3db_ds3db.flMaxDistance;
	}		

	if (flDistance < dsb->ds3db_ds3db.flMinDistance)
		flDistance = dsb->ds3db_ds3db.flMinDistance;
	
	/* attenuation proportional to the distance squared, converted to millibels as in lVolume*/
	lVolume -= log10(flDistance/dsb->ds3db_ds3db.flMinDistance * flDistance/dsb->ds3db_ds3db.flMinDistance)*1000 * dsb->device->ds3dl.flRolloffFactor;
	TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %d to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume);

	/* conning */
	/* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/
	if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0)
	{
		TRACE("conning: cones not set\n");
	}
	else
	{
		D3DVECTOR vDistanceInv;

		vDistanceInv.x = -vDistance.x;
		vDistanceInv.y = -vDistance.y;
		vDistanceInv.z = -vDistance.z;

		/* calculate angle */
		flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistanceInv);
		/* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */
		if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle)
		{
			/* my test show that for my way of calc., we need only half of angles */
			DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2;
			DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2;
			if (dwOutsideConeAngle == dwInsideConeAngle)
				++dwOutsideConeAngle;

			/* full volume */
			if (flAngle < dwInsideConeAngle)
				flAngle = dwInsideConeAngle;
			/* min (app defined) volume */
			if (flAngle > dwOutsideConeAngle)
				flAngle = dwOutsideConeAngle;
			/* this probably isn't the right thing, but it's ok for the time being */
			lVolume += ((flAngle - dwInsideConeAngle)/(dwOutsideConeAngle - dwInsideConeAngle)) * dsb->ds3db_ds3db.lConeOutsideVolume;
		}
		TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %d deg; OutsideConeAngle(/2) = %d deg; ConeOutsideVolume = %d => adjusting volume to %f\n",
		       flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume);
	}
	dsb->volpan.lVolume = lVolume;

	ingain = pow(2.0, dsb->volpan.lVolume / 600.0) * 0xffff;

	if (dsb->device->pwfx->nChannels == 1)
	{
		dsb->volpan.dwTotalAmpFactor[0] = ingain;
		return;
	}
	
	/* panning */
	if (vDistance.x == 0.0f && vDistance.y == 0.0f && vDistance.z == 0.0f)
		flAngle = 0.0;
	else
	{
		vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop);
		/* To calculate angle to sound source we need to:
		 * 1) Get angle between vDistance and a plane on which angle to sound source should be 0.
		 *    Such a plane is given by vectors vOrientFront and vOrientTop, and angle between vector
		 *    and a plane equals to M_PI_2 - angle between vector and normal to this plane (vLeft in this case).
		 * 2) Determine if the source is behind or in front of us by calculating angle between vDistance
		 *    and vOrientFront.
		 */
		flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance);
		flAngle2 = AngleBetweenVectorsRad(&dsb->device->ds3dl.vOrientFront, &vDistance);
		if (flAngle2 > M_PI_2)
			flAngle = -flAngle;
		flAngle -= M_PI_2;
		if (flAngle < -M_PI)
			flAngle += 2*M_PI;
	}
	TRACE("panning: Angle = %f rad, lPan = %d\n", flAngle, dsb->volpan.lPan);

	/* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */
if(0)
{
	D3DVALUE flFreq, flBufferVel, flListenerVel;
	/* doppler shift*/
	if (!VectorMagnitude(&dsb->ds3db_ds3db.vVelocity) && !VectorMagnitude(&dsb->device->ds3dl.vVelocity))
	{
		TRACE("doppler: Buffer and Listener don't have velocities\n");
	}
	else if (!(dsb->ds3db_ds3db.vVelocity.x == dsb->device->ds3dl.vVelocity.x &&
	           dsb->ds3db_ds3db.vVelocity.y == dsb->device->ds3dl.vVelocity.y &&
	           dsb->ds3db_ds3db.vVelocity.z == dsb->device->ds3dl.vVelocity.z))
	{
		/* calculate length of ds3db_ds3db.vVelocity component which causes Doppler Effect
		   NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE
		         if buffer moves AWAY from listener, it's velocity component is POSITIVE */
		flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance);
		/* calculate length of ds3dl.vVelocity component which causes Doppler Effect
		   NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE
		         if listener moves AWAY from buffer, it's velocity component is NEGATIVE */
		flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance);
		/* formula taken from Gianicoli D.: Physics, 4th edition: */
		/* FIXME: replace dsb->freq with appropriate frequency ! */
		flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel));
		TRACE("doppler: Buffer velocity (component) = %f, Listener velocity (component) = %f => Doppler shift: %d Hz -> %f Hz\n",
		      flBufferVel, flListenerVel, dsb->freq, flFreq);
		/* FIXME: replace following line with correct frequency setting ! */
		dsb->freq = flFreq;
		DSOUND_RecalcFormat(dsb);
	}
}

	for (i = 0; i < dsb->device->pwfx->nChannels; i++)
		dsb->volpan.dwTotalAmpFactor[i] = 0;

	num_main_speakers = dsb->device->pwfx->nChannels;

	if (dsb->device->lfe_channel != -1) {
		dsb->volpan.dwTotalAmpFactor[dsb->device->lfe_channel] = ingain;
		num_main_speakers--;
	}

	/* adapted from OpenAL's Alc/panning.c */
	for (i = 0; i < num_main_speakers - 1; i++)
	{
		if(flAngle >= dsb->device->speaker_angles[i] && flAngle < dsb->device->speaker_angles[i+1])
		{
			/* Sound is between speakers i and i+1 */
			a = (flAngle-dsb->device->speaker_angles[i]) / (dsb->device->speaker_angles[i+1]-dsb->device->speaker_angles[i]);
			dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i]] = sqrtf(1.0f-a) * ingain;
			dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i+1]] = sqrtf(a) * ingain;
			return;
		}
	}

	/* Sound is between last and first speakers */
	if (flAngle < dsb->device->speaker_angles[0]) { flAngle += M_PI*2.0f; }
	a = (flAngle-dsb->device->speaker_angles[i]) / (M_PI*2.0f + dsb->device->speaker_angles[0]-dsb->device->speaker_angles[i]);
	dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[i]] = sqrtf(1.0f-a) * ingain;
	dsb->volpan.dwTotalAmpFactor[dsb->device->speaker_num[0]] = sqrtf(a) * ingain;
}
예제 #22
0
파일: sound3d.c 프로젝트: GYGit/reactos
void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
{
	/* volume, at which the sound will be played after all calcs. */
	D3DVALUE lVolume = 0;
	/* stuff for distance related stuff calc. */
	D3DVECTOR vDistance;
	D3DVALUE flDistance = 0;
	/* panning related stuff */
	D3DVALUE flAngle;
	D3DVECTOR vLeft;
	/* doppler shift related stuff */
#if 0
	D3DVALUE flFreq, flBufferVel, flListenerVel;
#endif

	TRACE("(%p)\n",dsb);

	/* initial buffer volume */
	lVolume = dsb->ds3db_lVolume;
	
	switch (dsb->ds3db_ds3db.dwMode)
	{
		case DS3DMODE_DISABLE:
			TRACE("3D processing disabled\n");
			/* this one is here only to eliminate annoying warning message */
			DSOUND_RecalcVolPan (&dsb->volpan);
			break;
		case DS3DMODE_NORMAL:
			TRACE("Normal 3D processing mode\n");
			/* we need to calculate distance between buffer and listener*/
			vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->device->ds3dl.vPosition);
			flDistance = VectorMagnitude (&vDistance);
			break;
		case DS3DMODE_HEADRELATIVE:
			TRACE("Head-relative 3D processing mode\n");
			/* distance between buffer and listener is same as buffer's position */
			flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition);
			break;
	}
	
	if (flDistance > dsb->ds3db_ds3db.flMaxDistance)
	{
		/* some apps don't want you to hear too distant sounds... */
		if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE)
		{
			dsb->volpan.lVolume = DSBVOLUME_MIN;
			DSOUND_RecalcVolPan (&dsb->volpan);		
			/* i guess mixing here would be a waste of power */
			return;
		}
		else
			flDistance = dsb->ds3db_ds3db.flMaxDistance;
	}		

	if (flDistance < dsb->ds3db_ds3db.flMinDistance)
		flDistance = dsb->ds3db_ds3db.flMinDistance;
	
	/* attenuation proportional to the distance squared, converted to millibels as in lVolume*/
	lVolume -= log10(flDistance/dsb->ds3db_ds3db.flMinDistance * flDistance/dsb->ds3db_ds3db.flMinDistance)*1000;
	TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %d to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume);

	/* conning */
	/* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/
	if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0)
	{
		TRACE("conning: cones not set\n");
	}
	else
	{
		/* calculate angle */
		flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance);
		/* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */
		if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle)
		{
			/* my test show that for my way of calc., we need only half of angles */
			DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2;
			DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2;
			if (dwOutsideConeAngle == dwInsideConeAngle)
				++dwOutsideConeAngle;

			/* full volume */
			if (flAngle < dwInsideConeAngle)
				flAngle = dwInsideConeAngle;
			/* min (app defined) volume */
			if (flAngle > dwOutsideConeAngle)
				flAngle = dwOutsideConeAngle;
			/* this probably isn't the right thing, but it's ok for the time being */
			lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle;
		}
		TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %d deg; OutsideConeAngle(/2) = %d deg; ConeOutsideVolume = %d => adjusting volume to %f\n",
		       flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume);
	}
	dsb->volpan.lVolume = lVolume;
	
	/* panning */
	if (dsb->device->ds3dl.vPosition.x == dsb->ds3db_ds3db.vPosition.x &&
	    dsb->device->ds3dl.vPosition.y == dsb->ds3db_ds3db.vPosition.y &&
	    dsb->device->ds3dl.vPosition.z == dsb->ds3db_ds3db.vPosition.z) {
		dsb->volpan.lPan = 0;
		flAngle = 0.0;
	}
	else
	{
		vDistance = VectorBetweenTwoPoints(&dsb->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition);
		vLeft = VectorProduct(&dsb->device->ds3dl.vOrientFront, &dsb->device->ds3dl.vOrientTop);
		flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance);
		/* for now, we'll use "linear formula" (which is probably incorrect); if someone has it in book, correct it */
		dsb->volpan.lPan = 10000*2*flAngle/M_PI - 10000;
	}
	TRACE("panning: Angle = %f rad, lPan = %d\n", flAngle, dsb->volpan.lPan);

	/* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */
#if 0	
	/* doppler shift*/
	if ((VectorMagnitude(&ds3db_ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->device->ds3dl.vVelocity) == 0))
	{
		TRACE("doppler: Buffer and Listener don't have velocities\n");
	}
	else if (ds3db_ds3db.vVelocity != dsb->device->ds3dl.vVelocity)
	{
		/* calculate length of ds3db_ds3db.vVelocity component which causes Doppler Effect
		   NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE
		         if buffer moves AWAY from listener, it's velocity component is POSITIVE */
		flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance);
		/* calculate length of ds3dl.vVelocity component which causes Doppler Effect
		   NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE
		         if listener moves AWAY from buffer, it's velocity component is NEGATIVE */
		flListenerVel = ProjectVector(&dsb->device->ds3dl.vVelocity, &vDistance);
		/* formula taken from Gianicoli D.: Physics, 4th edition: */
		/* FIXME: replace dsb->freq with appropriate frequency ! */
		flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel));
		TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel,
		      dsb->freq, flFreq);
		/* FIXME: replace following line with correct frequency setting ! */
		dsb->freq = flFreq;
		DSOUND_RecalcFormat(dsb);
		DSOUND_MixToTemporary(dsb, 0, dsb->buflen);
	}
#endif	
	
	/* time for remix */
	DSOUND_RecalcVolPan(&dsb->volpan);
}
예제 #23
0
void VectorNormalize(vector_t *arg){
  float mag = VectorMagnitude(arg);
  arg->x = arg->x/mag;
  arg->y = arg->y/mag;
  arg->z = arg->z/mag;
}
예제 #24
0
/**
 * Correct attitude drift. Choose from any of the following algorithms
 */
void updateAttitudeDrift(AccelsData * accelsData, GyrosData * gyrosData, const float delT, GlobalAttitudeVariables *glblAtt, AttitudeSettingsData *attitudeSettings, SensorSettingsData *inertialSensorSettings)
{
	float *gyros = &gyrosData->x;
	float *accels = &accelsData->x;
	float omegaCorrP[3];

	if (attitudeSettings->FilterChoice == ATTITUDESETTINGS_FILTERCHOICE_CCC) {
		CottonComplementaryCorrection(accels, gyros, delT, glblAtt, omegaCorrP);
	} else if (attitudeSettings->FilterChoice == ATTITUDESETTINGS_FILTERCHOICE_PREMERLANI || 
		attitudeSettings->FilterChoice == ATTITUDESETTINGS_FILTERCHOICE_PREMERLANI_GPS) {
		if (firstpass_flag) {
			uint8_t module_state[MODULESETTINGS_ADMINSTATE_NUMELEM];
			ModuleSettingsAdminStateGet(module_state);

			//Allocate memory for DCM drift globals
			drft = (struct GlobalDcmDriftVariables *)
			    pvPortMalloc(sizeof (struct GlobalDcmDriftVariables));

			memset(drft->GPSV_old, 0, sizeof(drft->GPSV_old));
			memset(drft->omegaCorrI, 0, sizeof(drft->omegaCorrI));
			memset(drft->accels_e_integrator, 0, sizeof(drft->accels_e_integrator));

			// TODO: Expose these settings through UAVO
			drft->accelsKp = 1;
			drft->rollPitchKp = 20;
			drft->rollPitchKi = 1;
			drft->yawKp = 0;
			drft->yawKi = 0;
			drft->gyroCalibTau = 100;

			// Set flags
			if (module_state[MODULESETTINGS_ADMINSTATE_GPS] == MODULESETTINGS_ADMINSTATE_ENABLED && PIOS_COM_GPS) {
				GPSVelocityConnectCallback(GPSVelocityUpdatedCb);
				drft->gpsPresent_flag = true;
				drft->gpsVelocityDataConsumption_flag = GPS_CONSUMED;
			} else {
				drft->gpsPresent_flag = false;
			}

#if defined (PIOS_INCLUDE_MAGNETOMETER)
			MagnetometerConnectCallback(MagnetometerUpdatedCb);
#endif
			drft->magNewData_flag = false;
			drft->delT_between_GPS = 0;
			firstpass_flag = false;
		}

		// Apply arbitrary scaling to get into effective units
		drft->rollPitchKp = glblAtt->accelKp * 1000.0f;
		drft->rollPitchKi = glblAtt->accelKi * 10000.0f;

		// Convert quaternions into rotation matrix
		float Rbe[3][3];
		Quaternion2R(glblAtt->q, Rbe);

#if defined (PIOS_INCLUDE_GPS)
		if (attitudeSettings->FilterChoice == ATTITUDESETTINGS_FILTERCHOICE_PREMERLANI_GPS) {
			Premerlani_GPS(accels, gyros, Rbe, delT, true, glblAtt, omegaCorrP);
		} else if (attitudeSettings->FilterChoice == ATTITUDESETTINGS_FILTERCHOICE_PREMERLANI)
#endif
		{
			Premerlani_DCM(accels, gyros, Rbe, delT, false, glblAtt, omegaCorrP); //<-- GAWD, I HATE HOW FUNCTION ARGUMENTS JUST PILE UP. IT LOOKS UNPROFESSIONAL TO MIX INPUTS AND OUTPUTS
		}
	}
	
	//Calibrate the gyroscopes.	
	//TODO: but only calibrate when system is armed.
	if (0) { //<-- CURRENTLY DISABLE UNTIL TESTING CAN BE DONE.
		float normOmegaScalar = VectorMagnitude(gyros);
		calibrate_gyros_high_speed(gyros, omegaCorrP, normOmegaScalar, delT, inertialSensorSettings);
	}
}