// ---------------------------------------------------------------------------
//	fixPhaseForward
//
//! Recompute phases of all Breakpoints on the closed range [pos, stopHere]
//! so that the synthesized phases of those Breakpoints matches 
//! the stored phase, as long as the synthesized phase at pos
//! matches the stored (not recomputed) phase. The phase at pos 
//! is modified only if pos is the position of a null Breakpoint
//! and the Breakpoint that follows is non-null.
//! 
//! Phase fixing is only applied to non-null (nonzero-amplitude) Breakpoints,
//! because null Breakpoints are interpreted as phase reset points in 
//! Loris. If a null is encountered, its phase is corrected from its non-Null
//! successor, if it has one, otherwise it is unmodified.
//!
//! \pre    pos and stopHere are iterators on the same Partial, and
//!         pos must be not later than stopHere.
//! \pre    stopHere cannot be end of the Partial, it must be the postion
//!         of a valid Breakpoint.
//! \param  pos the position of the first Breakpoint whose phase might be
//!         recomputed.
//! \param  stopHere the position of the last Breakpoint whose phase might
//!         be modified.
//
void fixPhaseForward( Partial::iterator pos, Partial::iterator stopHere )
{
    while ( pos != stopHere )
    {
        Partial::iterator posPrev = pos++;
        if ( NoNulls || BreakpointUtils::isNonNull( pos.breakpoint() ) )
        {
            // pos is the position of a non-Null Breakpoint
            double travel = phaseTravel( posPrev, pos );
            
            if ( NoNulls || BreakpointUtils::isNonNull( posPrev.breakpoint() ) )
            {                        
                // if its predecessor of pos is non-Null, then fix
                // the phase of the Breakpoint at pos.
                pos.breakpoint().setPhase( wrapPi( posPrev.breakpoint().phase() + travel ) );
            }
            else
            {
                // if the predecessor of pos is Null, then
                // correct the predecessor's phase so that 
                // it correctly resets the synthesis phase 
                // so that the phase of the Breakpoint at 
                // pos is achieved in synthesis.
                posPrev.breakpoint().setPhase( wrapPi( pos.breakpoint().phase() - travel ) );
            }
        }
    }
}
// 变换为“限制集”欧拉角
void EulerAngles::cononize()
{
	pitch = wrapPi(pitch);
	if (pitch < -kPiOver2)
	{
		pitch = -kPi - pitch;
		heading += kPi;
		bank += kPi;
	}
	else if (pitch>kPiOver2)
	{
		pitch = kPi - pitch;
		heading += kPi;
		bank += kPi;
	}

	if (fabs(pitch) > kPiOver2 - 1e-4)
	{
		heading += bank;
		bank = 0.0f;
	}
	else
	{
		bank = wrapPi(bank);
	}
	heading = wrapPi(heading);
}
Exemple #3
0
void EulerAngles::canonize()
{
	pitch = wrapPi(pitch);

	if (pitch < -PI_OVER_2)
	{
		pitch = -PI - pitch;
		heading += PI;
		bank += PI;
	}
	else if (pitch > -PI_OVER_2)
	{
		pitch = PI - pitch;
		heading += PI;
		bank += PI;
	}

	//检测万向锁,即pitch是否等于pi/2,允许有误差
	if (fabs(pitch) > PI_OVER_2 - EPSINON)
	{
		heading += bank;
		bank = 0.0f;
	}
	else
	{
		bank = wrapPi(bank);
	}

	heading = wrapPi(heading);
}
Exemple #4
0
void	EulerAngles::canonize() {

	// 首先,回绕pitch到-pi到pi
	// First, wrap pitch in range -pi ... pi

	pitch = wrapPi(pitch);

	// 现在,检查矩阵的“后面”,pitch超出标准范围-pi/2到pi/2
	// Now, check for "the back side" of the matrix, pitch outside
	// the canonical range of -pi/2 ... pi/2

	if (pitch < -kPiOver2) {
		pitch = -kPi - pitch;
		heading += kPi;
		bank += kPi;
	} else if (pitch > kPiOver2) {
		pitch = kPi - pitch;
		heading += kPi;
		bank += kPi;
	}

	// 好了,现在检查万向锁情况(需要一点容忍度)
	// OK, now check for the gimbel lock case (within a slight
	// tolerance)

	if (fabs(pitch) > kPiOver2 - 1e-4) {

		// 我们遇到了万向锁。将所有竖直轴的旋转交给heading
		// We are in gimbel lock.  Assign all rotation
		// about the vertical axis to heading

		heading += bank;
		bank = 0.0f;

	} else {

		// 没有遇到万向锁。回绕到标准范围的bank角度。
		// Not in gimbel lock.  Wrap the bank angle in
		// canonical range 

		bank = wrapPi(bank);
	}

	// 将heading回绕到标准范围
	// Wrap heading in canonical range

	heading = wrapPi(heading);
}
// ---------------------------------------------------------------------------
//	fixPhaseBackward
//
//! Recompute phases of all Breakpoints on the half-open range [stopHere, pos)
//! so that the synthesized phases of those Breakpoints matches 
//! the stored phase, as long as the synthesized phase at stopHere
//! matches the stored (not recomputed) phase.
//!
//! The phase is corrected beginning at the end of the range, maintaining
//! the stored phase in the Breakpoint at pos.
//!
//! Backward phase-fixing stops if a null (zero-amplitude) Breakpoint
//! is encountered, because nulls are interpreted as phase reset points
//! in Loris. If a null is encountered, the remainder of the range
//! (the front part) is fixed in the forward direction, beginning at
//! the start of the stopHere.
//!
//! \pre    pos and stopHere are iterators on the same Partial, and
//!         pos must be not later than stopHere.
//! \pre    pos cannot be end of the Partial, it must be the postion
//!         of a valid Breakpoint.
//! \param  stopHere the position of the earliest Breakpoint whose phase might be
//!         recomputed.
//! \param  pos the position of a (later) Breakpoint whose phase is to be matched.
//!         The phase at pos is not modified.
//
void fixPhaseBackward( Partial::iterator stopHere, Partial::iterator pos )
{
    while ( pos != stopHere && 
            ( NoNulls || BreakpointUtils::isNonNull( pos.breakpoint() ) ) )
    {
        // pos is not the first Breakpoint in the Partial, 
        // and pos is not a Null Breakpoint.
        // Compute the correct phase for the
        // predecessor of pos.
        Partial::iterator posFwd = pos--;
        double travel = phaseTravel( pos, posFwd );
        pos.breakpoint().setPhase( wrapPi( posFwd.breakpoint().phase() - travel ) );
    }
    
    // if a null was encountered, then stop fixing backwards,
    // and fix the front of the Partial in the forward direction:
    if ( pos != stopHere )
    {
        // pos is not the first Breakpoint in the Partial,
        // and it is a Null Breakpoint (zero amplitude),
        // so it will be used to reset the phase during 
        // synthesis. 
        // The phase of all Breakpoints starting with pos
        // and ending with the Breakpoint nearest to time t
        // has been corrected. 
        // Fix phases before pos starting at the beginning
        // of the Partial.
        //
        // Dont fix pos, it has already been fixed.
        fixPhaseForward( stopHere, --pos );
    }
}
/// Determines the canonical Euler angle triple for this
/// set of angles and canonizes it.  Note that while this
/// doesn't affect the rotation represented by the triplet,
/// if your code uses the angles for some other purpose
///  (e.g., angular velocity), the results may be unexpected.
/// \note See section 10.3 for more information.
void	EulerAngles::canonize() {

	// First, wrap pitch in range -pi ... pi

	pitch = wrapPi(pitch);

	// Now, check for "the back side" of the matrix, pitch outside
	// the canonical range of -pi/2 ... pi/2

	if (pitch < -kPiOver2) {
		pitch = -kPi - pitch;
		heading += kPi;
		bank += kPi;
	} else if (pitch > kPiOver2) {
		pitch = kPi - pitch;
		heading += kPi;
		bank += kPi;
	}

	// OK, now check for the gimbal lock case (within a slight
	// tolerance)

	if (fabs(pitch) > kPiOver2 - 1e-4) {

		// We are in gimbal lock.  Assign all rotation
		// about the vertical axis to heading

		heading += bank;
		bank = 0.0f;

	} else {

		// Not in gimbal lock.  Wrap the bank angle in
		// canonical range 

		bank = wrapPi(bank);
	}

	// Wrap heading in canonical range

	heading = wrapPi(heading);
}
Exemple #7
0
// processes movement and input
/// \param elapsed time in seconds since the last call to this function
void FreeCamera::process(float elapsed)
{  
  Matrix4x3 view;

  Vector3 movement = Vector3(0.0f,0.0f,0.0f);

  if (gInput.keyDown(DIK_UPARROW))
    movement.z = 1.0f;
  
  if (gInput.keyDown(DIK_DOWNARROW))
    movement.z = -1.0f;
  
  if (gInput.keyDown(DIK_LEFTARROW))  
    movement.x = -1.0f;

  if (gInput.keyDown(DIK_RIGHTARROW))  
    movement.x = 1.0f;

  if (gInput.keyDown(DIK_PGUP))
    movement.y = 1.0f;

  if (gInput.keyDown(DIK_PGDN))
    movement.y = -1.0f;


  // get mouse movement from input manager
  float lx = gInput.getMouseLX();
  float ly = gInput.getMouseLY();
  
  m_cameraOrientMoving.pitch += ly / 100.0f;
  m_cameraOrientMoving.heading += lx / 100.0f;  
    
  // add 80% of cameraOrientMoving to cameraOrient
  // then remove 80% of cameraOrientMoving
  cameraOrient += m_cameraOrientMoving * 0.8f;  
  m_cameraOrientMoving += m_cameraOrientMoving * -0.8f;

  // constrain pitch
  if (cameraOrient.pitch > kPiOver2)
    cameraOrient.pitch = kPiOver2;
  if (cameraOrient.pitch < -kPiOver2)
    cameraOrient.pitch = -kPiOver2;

  // wrap heading btw -pi and pi
  cameraOrient.heading = wrapPi(cameraOrient.heading);
    
  // create a matrix to transform the movement to world space
  view.setupParentToLocal(Vector3::kZeroVector, cameraOrient);
  view = view.inverse();
  movement = movement*view;

  cameraPos += movement * elapsed * m_speed;
}
// ---------------------------------------------------------------------------
//	matchPhaseFwd
//
//!	Compute the target frequency that will affect the
//!	predicted (by the Breakpoint phases) amount of
//!	sinusoidal phase travel between two breakpoints, 
//!	and assign that frequency to the target Breakpoint.
//!	After computing the new frequency, update the phase of
//!	the later Breakpoint.
//!
//! If the earlier Breakpoint is null and the later one
//! is non-null, then update the phase of the earlier
//! Breakpoint, and do not modify its frequency or the 
//! later Breakpoint.
//!
//! The most common kinds of errors are local (or burst) errors in 
//! frequency and phase. These errors are best corrected by correcting
//! less than half the detected error at any time. Correcting more
//! than that will produce frequency oscillations for the remainder of
//! the Partial, in the case of a single bad frequency (as is common
//! at the onset of a tone). Any damping factor less then one will 
//! converge eventually, .5 or less will converge without oscillating.
//! Use the damping argument to control the damping of the correction.
//!	Specify 1 for no damping.
//!
//! \pre		The two Breakpoints are assumed to be consecutive in
//!				a Partial.
//! \param		bp0	The earlier Breakpoint.
//! \param		bp1	The later Breakpoint.
//! \param		dt The time (in seconds) between bp0 and bp1.
//! \param		damping The fraction of the amount of phase error that will
//!				be corrected (.5 or less will prevent frequency oscilation 
//!				due to burst errors in phase). 
//! \param		maxFixPct The maximum amount of frequency adjustment
//!				that can be made to the frequency of bp1, expressed
//!				as a precentage of the unmodified frequency of bp1.
//!				If the necessary amount of frequency adjustment exceeds
//!				this amount, then the phase will not be matched, 
//!				but will be updated as well to be consistent with
//!				the frequencies. (default is 0.2%)
//
void matchPhaseFwd( Breakpoint & bp0, Breakpoint & bp1,
				    double dt, double damping, double maxFixPct )
{
	double travel = phaseTravel( bp0, bp1, dt );
    
    if ( ! BreakpointUtils::isNonNull( bp1 ) )
    {
        // if bp1 is null, just compute a new phase,
        // no need to match it.
        bp1.setPhase( wrapPi( bp0.phase() + travel ) );
    }
    else if ( ! BreakpointUtils::isNonNull( bp0 ) )
    {
        // if bp0 is null, and bp1 is not, then bp0
        // should be a phase reset Breakpoint during
        // rendering, so compute a new phase for
        // bp0 that achieves bp1's phase.
        bp0.setPhase( wrapPi( bp1.phase() - travel ) ) ;
    } 
    else
    {
        // invariant:
        // neither bp0 nor bp1 is null
        //
        // modify frequecies to match phases as nearly as possible
        double err = wrapPi( bp1.phase() - ( bp0.phase() + travel ) );
        
        //  The most common kinds of errors are local (or burst) errors in 
        //  frequency and phase. These errors are best corrected by correcting
        //  less than half the detected error at any time. Correcting more
        //  than that will produce frequency oscillations for the remainder of
        //  the Partial, in the case of a single bad frequency (as is common
        //  at the onset of a tone). Any damping factor less then one will 
        //  converge eventually, .5 or less will converge without oscillating.
        //  #define DAMPING .5
        travel += damping * err;
        
        double f0 = bp0.frequency();
        double ftgt = ( travel / ( Pi * dt ) ) - f0;
        
        #ifdef Loris_Debug
        debugger << "matchPhaseFwd: correcting " << bp1.frequency() << " to " << ftgt 
                 << " (phase " << wrapPi( bp1.phase() ) << "), ";
        #endif
        
        //	If the target is not a null breakpoint, may need to 
        //	clamp the amount of frequency modification.
        //
        //  Actually, should probably always clamp the amount
        //  of modulation, should never have arbitrarily large
        //  frequency adjustments. 
        //
        //  Really, should never call this function if bp1
        //  is a null Breakpoint, because we don't care about 
        //  those phases in Loris. 
        if ( true ) //  bp1.amplitude() != 0. )
        {	
            if ( ftgt > bp1.frequency() * ( 1 + (maxFixPct*.01) ) )
            {
                ftgt = bp1.frequency() * ( 1 + (maxFixPct*.01) );
            }
            else if ( ftgt < bp1.frequency() * ( 1 - (maxFixPct*.01) ) )
            {
                ftgt = bp1.frequency() * ( 1 - (maxFixPct*.01) );
            }
        }
        bp1.setFrequency( ftgt );
        
        //	Recompute the phase according to the new frequency.
        double phi = wrapPi( bp0.phase() + phaseTravel( bp0, bp1, dt ) );
        bp1.setPhase( phi );

        #ifdef Loris_Debug
        debugger << "achieved " << ftgt << " (phase " << phi << ")" << endl;
        #endif
    }
}
// ---------------------------------------------------------------------------
//  fixPhaseBetween
//
//!	Fix the phase travel between two Breakpoints by adjusting the
//!	frequency and phase of Breakpoints between those two.
//!
//!	This algorithm assumes that there is nothing interesting about the
//!	phases of the intervening Breakpoints, and modifies their frequencies 
//!	as little as possible to achieve the correct amount of phase travel 
//!	such that the frequencies and phases at the specified times
//!	match the stored values. The phases of all the Breakpoints between 
//! the specified times are recomputed.
//!
//! Null Breakpoints are treated the same as non-null Breakpoints.
//!
//! \pre        b and e are iterators on the same Partials, and
//!             e must not preceed b in that Partial.
//! \pre        There must be at least one Breakpoint in the
//!             Partial between b and e.
//! \post       The phases and frequencies of the Breakpoints in the 
//!             range have been recomputed such that an oscillator
//!             initialized to the parameters of the first Breakpoint
//!             will arrive at the parameters of the last Breakpoint,
//!             and all the intervening Breakpoints will be matched.
//! \param b    The phases and frequencies of Breakpoints later than
//!             this one may be modified.
//! \param e    The phases and frequencies of Breakpoints earlier than  
//!             this one may be modified.
//
void fixPhaseBetween( Partial::iterator b, Partial::iterator e )
{  
    if ( 1 < std::distance( b, e ) )
    {
        //	Accumulate the actual phase travel over the Breakpoint
        //	span, and count the envelope segments.
        double travel = 0;
        Partial::iterator next = b;
        do
        {
            Partial::iterator prev = next++;
            travel += phaseTravel( prev, next );
        } while( next != e );

        //	Compute the desired amount of phase travel:
        double deviation = wrapPi( e.breakpoint().phase() - ( b.breakpoint().phase() + travel ) );
        double desired = travel + deviation;
        
        /*
        debugger << "---------- fixing breakpoint frequencies over time ( " 
                 << b.time() << " , " << e.time() << " )" << endl;
             
        debugger << "desired travel: " << desired << endl;
        debugger << "actual travel: " << travel << endl;
        */
        
        //	Compute the amount by which to perturb the frequencies of
        //	all the null Breakpoints between b and e.
        //
        //	The accumulated phase travel is the sum of the average frequency
        //	(in radians) of each segment times the duration of each segment
        //	(the actual phase travel is computed this way). If this sum is
        //	computed with each Breakpoint frequency perturbed (additively) 
        //	by delta, and set equal to the desired phase travel, then it
        //	can be simplified to:
        //		delta = 2 * ( phase error ) / ( tN + tN-1 - t1 - t0 )
        //	where tN is the time of e, tN-1 is the time of its predecessor,
        //	t0 is the time of b, and t1 is the time of b's successor.
        //
        Partial::iterator iter = b;
        double t0 = iter.time();
        ++iter;
        double t1 = iter.time();
        iter = e;
        double tN = iter.time();
        --iter;
        double tNm1 = iter.time();
        
        Assert( t1 < tN );	//	else there were no Breakpoints in between
        
        double delta = ( 2 * ( desired - travel ) / ( tN + tNm1 - t1 - t0 ) ) / ( 2 * Pi );
        
        //	Perturb the Breakpoint frequencies.
        double DEBUGtravel = 0;
        next = b;
        Partial::iterator prev = next++;
        while ( next != e )
        {
            //debugger << "changing frequency from " << next.breakpoint().frequency();
            next.breakpoint().setFrequency( next.breakpoint().frequency() + delta );
            //debugger << " to " << next.breakpoint().frequency() << endl;
            
            double newtravel = phaseTravel( prev, next );
            DEBUGtravel += newtravel;
            
            //debugger << "changing phase from " << wrapPi( next.breakpoint().phase() );
            next.breakpoint().setPhase( wrapPi( prev.breakpoint().phase() + newtravel ) );
            //debugger << " to " << next.breakpoint().phase() << endl;
            
            prev = next++;
        }
        DEBUGtravel += phaseTravel( prev, next );
        /*
        debugger << "travel: " << DEBUGtravel << endl;
        
        debugger << "desired: " << e.breakpoint().phase() << endl;
        debugger << "got: " << wrapPi( prev.breakpoint().phase() + phaseTravel( prev, next ) ) << endl;
        debugger << "---------- done." << endl;
        */
    }
    else
    {
        // Preconditions not met, cannot fix the phase travel.
        // Should raise exception?
        debugger << "cannot fix phase between " << b.time() << " and " << e.time()
                 << ", there are no Breakpoints between those times" << endl;
    }

}