Example #1
0
/* take the definition of a camera and a point within the film plane of the camera and generate a RAY
   x and y both have a range of -0.5 to +0.5 */
Ray *camGenerateRay(Camera *camera, double x, double y, Ray *ray){
	Vec direction;
	Vec cameraX, cameraY;
	
	/* work out direction camera is pointing in */
	vecSub(&(camera->lookAt), &(camera->at), &direction);
	vecNormalise(&direction, &direction);

	/* using that and DOWN, work out the camera axes and normalise */
	vecProduct(&direction, &(camera->down), &cameraX);
	vecProduct(&direction, &cameraX, &cameraY);
	vecNormalise(&cameraX, &cameraX);
	vecNormalise(&cameraY, &cameraY);
	
	/* finally combine film offset and camera axes to work out film position */
	vecScale(x * camera->width, &cameraX, &cameraX);
	vecScale(y * camera->height, &cameraY, &cameraY);
	vecScale(camera->depth, &direction, &direction);
	vecAdd(&cameraX, &direction, &direction);
	vecAdd(&cameraY, &direction, &direction);
	
	rayInit(&(camera->at), &direction, ray);
	return ray;
}
void applyTransitions(jrPlanet *pPlanet) {
	if (pPlanet) {
		float afForce[4];
		vecInitDVec(afForce);

		for (jrPlanet *pOtherPlanet = g_pHead; pOtherPlanet; pOtherPlanet = pOtherPlanet->m_pNext) {

			if (pPlanet != pOtherPlanet && pOtherPlanet)  {
				float afDistance[3];
				vecSub(pPlanet->afPosition, pOtherPlanet->afPosition, afDistance); //get distance

				float fForce = g_fGravity * (pPlanet->fMass * pOtherPlanet->fMass) / (vecLength(afDistance));

				float afNormaliseInput[4];
				vecSub(pOtherPlanet->afPosition, pPlanet->afPosition, afNormaliseInput);
				float afNormaliseOutput[4];
				vecInit(afNormaliseOutput);

				vecNormalise(afNormaliseInput, afNormaliseOutput);

				afForce[0] = (afForce[0] + afNormaliseOutput[0]);
				afForce[1] = (afForce[1] + afNormaliseOutput[1]);
				afForce[2] = (afForce[2] + afNormaliseOutput[2]);

				if (pPlanet->fMass > pOtherPlanet->fMass) {
					if (detectCollision(pPlanet, pOtherPlanet, afDistance)) {
						break;
					}
				}
			}
		}

		// calc accV -> afForce/mass
		pPlanet->afAcceleration[0] = afForce[0] / pPlanet->fMass;
		pPlanet->afAcceleration[1] = afForce[1] / pPlanet->fMass;
		pPlanet->afAcceleration[2] = afForce[2] / pPlanet->fMass;

		// calc new pos
		if (!pPlanet->m_bFixed) {
			pPlanet->afPosition[0] = pPlanet->afPosition[0] + (pPlanet->afVelocity[0] * g_fVelocityMultiplier);
			pPlanet->afPosition[1] = pPlanet->afPosition[1] + (pPlanet->afVelocity[1] * g_fVelocityMultiplier);
			pPlanet->afPosition[2] = pPlanet->afPosition[2] + (pPlanet->afVelocity[2] * g_fVelocityMultiplier);
		}
		// calc new vel
		pPlanet->afVelocity[0] = pPlanet->afVelocity[0] + pPlanet->afAcceleration[0];
		pPlanet->afVelocity[1] = pPlanet->afVelocity[1] + pPlanet->afAcceleration[1];
		pPlanet->afVelocity[2] = pPlanet->afVelocity[2] + pPlanet->afAcceleration[2];

		// apply drag
		pPlanet->afAcceleration[0] = pPlanet->afAcceleration[0] * g_fDamping;
		pPlanet->afAcceleration[1] = pPlanet->afAcceleration[1] * g_fDamping;
		pPlanet->afAcceleration[2] = pPlanet->afAcceleration[2] * g_fDamping;

		// end

		if (pPlanet->iHistoryCount < g_iHistoryVariableLength - 4) {
			pPlanet->iHistoryCount = pPlanet->iHistoryCount + 3;
		}
		else {
			pPlanet->iHistoryCount = 0;
		}

		pPlanet->afPositionHistory[pPlanet->iHistoryCount] = pPlanet->afPosition[0];
		pPlanet->afPositionHistory[pPlanet->iHistoryCount + 1] = pPlanet->afPosition[1];
		pPlanet->afPositionHistory[pPlanet->iHistoryCount + 2] = pPlanet->afPosition[2];

		if (pPlanet->fRotationAngle > 359.0f) {
			pPlanet->fRotationAngle = 0.0f;
		}
		else {
			pPlanet->fRotationAngle = pPlanet->fRotationAngle += 1.0f;
		}
	}

}
Example #3
0
File: imu.c Project: jonkster/biot
myQuat_t getPosition(mpu9250_t dev)
{
    imuData_t imuData;
    if (getIMUData(dev, &imuData))
    {
        if (! validIMUData(imuData))
        {
            puts("invalid IMU data");
            if (failureCount++ > 20)
            {
                puts("Error in IMU, restarting!");
                identifyYourself("IMU failure");
                if (! initialiseIMU(&dev))
                {
                    puts("Could not initialise IMU! dying...");
                    exit(1);
                }
            }
            return currentQ;
        }
        failureCount = 0;

        /************************************************************************
         * Get Gyro data that records current angular velocity and create an
         * estimated quaternion representation of orientation using this
         * velocity, the time interval between the last calculation and the
         * previous orientation:
         * change in position = velocity * time,
         * new position = old position + change in position)
         ************************************************************************/

        // get orientation as deduced by adding gyro measured rotational
        // velocity (times time interval) to previous orientation.
        double gx1 = (double)(imuData.gyro.x_axis);
        double gy1 = (double)(imuData.gyro.y_axis);
        double gz1 = (double)(imuData.gyro.z_axis);
        double omega[3] = { gx1, gy1, gz1 }; // this will be in degrees/sec
        //double omegaMagnitude = fabs(vecLength(omega));

        uint32_t dt = imuData.ts - lastIMUData.ts; // dt in microseconds
        lastIMUData = imuData;
        myQuat_t gRot = makeQuatFromAngularVelocityTime(omega, dt/1000000.0);
        myQuat_t gyroDeducedQ =  quatMultiply(currentQ, gRot);
        quatNormalise(&gyroDeducedQ);
        if (! useGyroscopes)
        {
            makeIdentityQuat(&gyroDeducedQ);
        }

        if (! (useAccelerometers | useMagnetometers))
        {
            // return now with just the gyro data
            currentQ = gyroDeducedQ;
            lastIMUData = imuData;
            return currentQ;
        }

        // get orientation from the gyro as Roll Pitch Yaw (ie Euler angles)
        double gyroDeducedYPR[3];
        quatToEuler(gyroDeducedQ, gyroDeducedYPR);
        double currentYPR[3];
        quatToEuler(currentQ, currentYPR);


        // Calculate a roll/pich/yaw from the accelerometers and magnetometers.

        /************************************************************************
         * Get Accelerometer data that records gravity direction and create a
         * 'measured' Quaternion representation of orientation (will only be
         * pitch and roll, not yaw)
         ************************************************************************/

        // get gravity direction from accelerometer
        double ax1 = imuData.accel.x_axis / 1024.0;
        double ay1 = imuData.accel.y_axis / 1024.0;
        double az1 = imuData.accel.z_axis / 1024.0;
        double downSensor[3] = { ax1, ay1, az1 };
        if (fabs(vecLength(downSensor) - 0.98) > 0.5)
        {
            // excessive accelerometer reading, bail out
            //printf("too much accel: %f ", fabs(vecLength(downSensor)));
            //dumpVec(downSensor);
            currentQ = gyroDeducedQ;
            lastIMUData = imuData;
            return currentQ;
        }
        vecNormalise(downSensor);

        // The accelerometers can only measure pitch and roll (in the world reference
        // frame), calculate the pitch and roll values to account for
        // accelerometer readings, make yaw = 0.

        double ypr[3];
        double downX = downSensor[X_AXIS];
        double downY = downSensor[Y_AXIS];
        double downZ = downSensor[Z_AXIS];

        // add a little X into Z when calculating roll to compensate for
        // situations when pitching near vertical as Y, Z will be near 0 and
        // the results will be unstable
        double fiddledDownZ = sqrt(downZ*downZ + 0.001*downX*downX);
        if (downZ <= 0) // compensate for loss of sign when squaring Z
            fiddledDownZ *= -1.0;
        ypr[ROLL] = atan2(downY, fiddledDownZ);
        ypr[PITCH] = -atan2(downX, sqrt(downY*downY + downZ*downZ));
        ypr[YAW] = 0;  // yaw == 0, accelerometer cannot measure yaw
        if (! useAccelerometers) 
        {
            // if no accelerometers, use roll and pitch values from gyroscope
            // derived orientation
            ypr[PITCH] = gyroDeducedYPR[PITCH];
            ypr[ROLL] = gyroDeducedYPR[ROLL];
            ypr[YAW] = gyroDeducedYPR[YAW];
        }
        else if (vecLength(downSensor) == 0)
        {
            puts("weightless?");
            // something wrong! - weightless??
            ypr[PITCH] = gyroDeducedYPR[PITCH];
            ypr[ROLL] = gyroDeducedYPR[ROLL];
            ypr[YAW] = gyroDeducedYPR[YAW];
        }

        if (! useMagnetometers)
        {
            ypr[YAW] = gyroDeducedYPR[YAW];
        }
        myQuat_t accelQ = eulerToQuat(ypr);
        myQuat_t invAccelQ = quatConjugate(accelQ);


        /************************************************************************
         * Get Magnetometer data that records north direction and create a
         * 'measured' Quaternion representation of orientation (will only be
         * yaw)
         ************************************************************************/

        // get magnetometer indication of North
        double mx1 = (double)(imuData.mag.x_axis - magHardCorrection[X_AXIS]);
        double my1 = (double)(imuData.mag.y_axis - magHardCorrection[Y_AXIS]);
        double mz1 = (double)(imuData.mag.z_axis - magHardCorrection[Z_AXIS]);
        mx1 *= magSoftCorrection[X_AXIS];
        my1 *= magSoftCorrection[Y_AXIS];
        mz1 *= magSoftCorrection[Z_AXIS];
        // NB MPU9250 has different XYZ axis for magnetometers than for gyros
        // and accelerometers so juggle x,y,z here...
        double magV[3] = { my1, mx1, -mz1 };
        vecNormalise(magV);
        // make quaternion representing mag readings
        myQuat_t magQ = quatFromValues(0, magV[X_AXIS], magV[Y_AXIS], magV[Z_AXIS]);
        if (vecLength(magV) == 0)
        {
            // something wrong! - no magnetic field??
            //puts("not on earth?");
            magQ = quatFromValues(1, 0, 0, 0);
        }

        // the magnetometers can only measure yaw (in the world reference
        // frame), adjust the yaw of the roll/pitch/yaw values calculated
        // earlier to account for the magnetometer readings.
        if (useMagnetometers) 
        {
            // pitch and roll the mag direction using accelerometer info to
            // create a quaternion that represents the IMU as if it was
            // horizontal (so we can get pure yaw)
            myQuat_t horizQ = quatMultiply(accelQ, magQ);
            horizQ = quatMultiply(horizQ, invAccelQ);

            // calculate pure yaw
            ypr[YAW] = -atan2(horizQ.y, horizQ.x);
        }

        // measuredQ is the orientation as measured using the
        // accelerometer/magnetometer readings
        myQuat_t measuredQ = eulerToQuat(ypr);
        // check measured and deduced orientations are not wildly different (eg
        // due to a 360d alias flip) and adjust if problem...
        measuredQ = adjustForCongruence(measuredQ, gyroDeducedQ);

        /*************************************************************************
         * The gyro estimated orientation will be smooth and precise over short
         * time intervals but small errors will accumulate causing it to
         * drift over time.  The 'measured' orientation as obtained from the
         * magnetometer and accelerometer will be jumpy but will always average
         * around the correct orientation.
         *
         * Take the mag and accel 'measured' orientation and the gyro
         * 'estimated' orientation and create a new 'current' orientation that
         * is the estimated orientation corrected slightly towards the measured
         * orientation.  That way we get the smooth precision of the gyros but
         * eliminate the accumulation of drift errors.
         ************************************************************************/

        if (useGyroscopes)
        {
            // the new orientation is the gyro deduced position corrected
            // towards the accel/mag measured position using interpolation
            // between quaternions.
            currentQ = slerp(gyroDeducedQ, measuredQ, 0.02);
        }
        else
        {
            currentQ = measuredQ;
        }

        if (! isQuatValid(currentQ))
        {
            puts("error in quaternion, reseting orientation...");
            displayData(imuData);
            dumpQuat(currentQ);
            makeIdentityQuat(&currentQ);
        }
    }
    return currentQ;
}