AccelerometerPlayActivity代码注释(未完成)

因需要将类名修改为testActivity,同时对弃用的方法进行替换。因涉及Verlet积分法来计算位置,尚未充分理解,故代码注释不完整,待继续完善,此处先做以保存。

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.BitmapFactory.Options;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;

/**
 * This is an example of using the accelerometer to integrate the device's
 * acceleration to a position using the Verlet method. This is illustrated with
 * a very simple particle system comprised of a few iron balls freely moving on
 * an inclined wooden table. The inclination of the virtual table is controlled
 * by the device's accelerometer.
 * 这是一个通过加速度计使用Verlet方法来积分计算设备在某位置时的加速度的例子。
 * 通过一个非常简单的粒子系统——在斜木桌上自由移动铁球来进行演示。
 * 设备的加速度计控制着虚拟木卓的倾向程度。
 * @see SensorManager
 * @see SensorEvent
 * @see Sensor
 */

public class testActivity extends Activity {

    private SimulationView mSimulationView;
    private SensorManager mSensorManager;
    private Display mDisplay;
    //private WakeLock mWakeLock;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        //mPowerManager = (PowerManager) getSystemService(POWER_SERVICE);

        WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        // 获取系统当前默认的显示对象
        mDisplay = windowManager.getDefaultDisplay();

        // Create a bright wake lock创建一个亮度唤醒锁
        // SCREEN_BRIGHT_WAKE_LOCK已废弃,推荐使用如下方式来保持屏幕常亮
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        //mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass().getName());

        // instantiate our simulation view and set it as the activity's content
        //实例化我们定制的模拟View对象,并把它设置为Activity的显示内容
        mSimulationView = new SimulationView(this);
        setContentView(mSimulationView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        /*
         * when the activity is resumed, we acquire a wake-lock so that the
         * screen stays on, since the user will likely not be fiddling with the
         * screen or buttons.
         * 当Activity进入resume状态时,我们申请了一个唤醒锁,让屏幕在程序运行期间保持高亮,
         * 因为用户不太会在程序运行期间频繁的点击屏幕或按钮。
         */
        //mWakeLock.acquire();  mWakeLock已优化注释掉

        // Start the simulation启动模拟窗口
        mSimulationView.startSimulation();
    }

    @Override
    protected void onPause() {
        super.onPause();
        /*
         * When the activity is paused, we make sure to stop the simulation,
         * release our sensor resources and wake locks
         * 当Activity被挂起时,我们要确保终止模拟窗口,释放传感器资源和唤醒锁。
         */

        // Stop the simulation终止模拟窗口
        mSimulationView.stopSimulation();

        // and release our wake-lock  mWakeLock已优化注释掉
        //mWakeLock.release();
    }

    class SimulationView extends View implements SensorEventListener {
        // diameter of the balls in meters以米为单位定义小球的直径
        private static final float sBallDiameter = 0.004f;
        //小球的直径的平方
        private static final float sBallDiameter2 = sBallDiameter * sBallDiameter;

        // friction of the virtual table and air虚拟桌面和空气的摩擦力
        private static final float sFriction = 0.1f;

        private Sensor mAccelerometer;

	    //持续时间
        private long mLastT;

	    //时间增量
        private float mLastDeltaT;

	    //X、Y轴方向Dpi
        private float mXDpi;
        private float mYDpi;
		
	    //X、Y轴米像素
        private float mMetersToPixelsX;
        private float mMetersToPixelsY;

        private Bitmap mBitmap;
        private Bitmap mWood;

	    //X、Y轴初始位置
        private float mXOrigin;
        private float mYOrigin;

	    //
        private float mSensorX;
        private float mSensorY;

        //传感器时间戳
        private long mSensorTimeStamp;

        //CPU时间戳
        private long mCpuTimeStamp;

        //水平和垂直边界
        private float mHorizontalBound;
        private float mVerticalBound;
        private final ParticleSystem mParticleSystem = new ParticleSystem();

        /*
         * Each of our particle holds its previous and current position, its
         * acceleration. for added realism each particle has its own friction
         * coefficient.
         * 每个粒子都保存这它的前一个位置和当前位置,以及加速度。
         * 为了表现的更加真实,每个粒子都有它们自己的摩擦系数。
         */
        class Particle {
            //当前位置的X、Y坐标
            private float mPosX;
            private float mPosY;

            //X、Y方向上的加速度
            private float mAccelX;
            private float mAccelY;

            //前一个位置的X、Y坐标
            private float mLastPosX;
            private float mLastPosY;

            //摩擦系数( < 1 )
            private float mOneMinusFriction;

            Particle() {
                /*
                * make each particle a bit different by randomizing its
                * coefficient of friction
                * 通过设置随机的摩擦系数让每个粒子稍有不同
                */
                final float r = ((float) Math.random() - 0.5f) * 0.2f;  //[-0.1,0.1)
                mOneMinusFriction = 1.0f - sFriction + r;
            }

            void computePhysics(float sx, float sy, float dT, float dTC) {
                // Force of gravity applied to our virtual object
                //我们虚拟物理的重力
                final float m = 1000.0f; // mass of our virtual object质量

                //X、Y轴方向上的重力
                final float gx = -sx * m;
                final float gy = -sy * m;

                /*
                 * F = mA <=> A = F / m We could simplify the code by
                 * completely eliminating "m" (the mass) from all the equations,
                 * but it would hide the concepts from this sample code.
                 * 把公式 F=mA 转换成 A=F/m,我们能够通过完全消除所有公式中的“m”(质量)来简化代码
                 * 但是它也从这段示例代码中隐藏了概念合力=质量乘以加速度
                 */

                //m分之一
                final float invm = 1.0f / m;

                //X、Y轴方向上的加速度
                final float ax = gx * invm;
                final float ay = gy * invm;

                /*用d来表示deltaT
                 * Time-corrected Verlet integration The position Verlet
                 * integrator is defined as x(t+d) = x(t) + x(t) - x(t-d) +
                 * a(t)d? However, the above equation doesn't handle variable
                 * d very well, a time-corrected version is needed: x(t+d) =
                 * x(t) + (x(t) - x(t-d)) * (d/d_prev) + a(t)d? We also add
                 * a simple friction term (f) to the equation: x(t+d) = x(t) +
                 * (1-f) * (x(t) - x(t-d)) * (d/d_prev) + a(t)d?
                 *
                 * 关于Verlet积分法的使用,参见以下链接:
                 * https://en.wikipedia.org/wiki/Verlet_integration
                 * http://www.cnblogs.com/crackpotisback/p/5293991.html
                 *
                 * 计算通过Δt时间后的位置。
                 */
                final float dTdT = dT * dT;
                final float x = mPosX + mOneMinusFriction * dTC * (mPosX - mLastPosX) + mAccelX
                        * dTdT;
                final float y = mPosY + mOneMinusFriction * dTC * (mPosY - mLastPosY) + mAccelY
                        * dTdT;
                mLastPosX = mPosX;
                mLastPosY = mPosY;
                mPosX = x;
                mPosY = y;
                mAccelX = ax;
                mAccelY = ay;
            }

            /*
             * Resolving constraints and collisions with the Verlet integrator
             * can be very simple, we simply need to move a colliding or
             * constrained particle in such way that the constraint is
             * satisfied.
             * 用Verlet积分法能轻易的解决约束和碰撞的问题,
             * 我们只需用满足约束条件的方式来移动发生碰撞或受到约束的粒子
             *
             */
            void resolveCollisionWithBounds() {
                // X,Y轴的最大边界
                final float xmax = mHorizontalBound;
                final float ymax = mVerticalBound;
                final float x = mPosX;
                final float y = mPosY;
                if (x > xmax) {
                    mPosX = xmax;
                } else if (x < -xmax) {
                    mPosX = -xmax;
                }
                if (y > ymax) {
                    mPosY = ymax;
                } else if (y < -ymax) {
                    mPosY = -ymax;
                }
            }
        }

        /*
         * A particle system is just a collection of particles
         * 一个粒子系统即粒子的集合
         */
        class ParticleSystem {
            static final int NUM_PARTICLES = 15;
            private Particle mBalls[] = new Particle[NUM_PARTICLES];

            ParticleSystem() {
                /*
                 * Initially our particles have no speed or acceleration
                 * 最初我们的例子没有速度和加速度
                 */
                for (int i = 0; i < mBalls.length; i++) {
                    mBalls[i] = new Particle();
                }
            }

            /*
             * Update the position of each particle in the system using the
             * Verlet integrator.
             * 使用Verlet积分法更新系统中每个粒子的位置
             */
            private void updatePositions(float sx, float sy, long timestamp) {
                final long t = timestamp;
                if (mLastT != 0) {
                    final float dT = (float) (t - mLastT) * (1.0f / 1000000000.0f);
                    if (mLastDeltaT != 0) {
                        final float dTC = dT / mLastDeltaT;
                        //final int count = mBalls.length;
                        for (Particle ball : mBalls) {
                            ball.computePhysics(sx, sy, dT, dTC);
                        }
                    }
                    mLastDeltaT = dT;
                }
                mLastT = t;
            }

            /*
             * Performs one iteration of the simulation. First updating the
             * position of all the particles and resolving the constraints and
             * collisions.
             * 执行一次传感器模拟的迭代。
             * 首先更新所有的粒子的位置,并解决约束和碰撞的问题
             */
            void update(float sx, float sy, long now) {
                // update the system's positions更新粒子系统中各粒子的位置
                updatePositions(sx, sy, now);

                // We do no more than a limited number of iterations
                //最大迭代数
                final int NUM_MAX_ITERATIONS = 10;

                /*
                 * Resolve collisions, each particle is tested against every
                 * other particle for collision. If a collision is detected the
                 * particle is moved away using a virtual spring of infinite
                 * stiffness.
                 * 每个粒子都要被检测是否碰撞了其他粒子
                 * 如果检测到了一个碰撞,那么使用无限刚度的弹性运动来移走这个粒子
                 */
                boolean more = true;
                final int count = mBalls.length;
                for (int k = 0; k < NUM_MAX_ITERATIONS && more; k++) {
                    more = false;
                    for (int i = 0; i < count; i++) {
                        Particle curr = mBalls[i];
                        for (int j = i + 1; j < count; j++) {
                            Particle ball = mBalls[j];
                            float dx = ball.mPosX - curr.mPosX;
                            float dy = ball.mPosY - curr.mPosY;
                            float dd = dx * dx + dy * dy;
                            // Check for collisions检测碰撞
                            if (dd <= sBallDiameter2) {
                                /*
                                 * add a little bit of entropy, after nothing is
                                 * perfect in the universe.
                                 */
                                dx += ((float) Math.random() - 0.5f) * 0.0001f;
                                dy += ((float) Math.random() - 0.5f) * 0.0001f;
                                dd = dx * dx + dy * dy;
                                // simulate the spring
                                final float d = (float) Math.sqrt(dd);
                                final float c = (0.5f * (sBallDiameter - d)) / d;
                                curr.mPosX -= dx * c;
                                curr.mPosY -= dy * c;
                                ball.mPosX += dx * c;
                                ball.mPosY += dy * c;
                                more = true;
                            }
                        }
                        /*
                         * Finally make sure the particle doesn't intersect
                         * with the walls.
                         */
                        curr.resolveCollisionWithBounds();
                    }
                }
            }

            int getParticleCount() {
                return mBalls.length;
            }

            float getPosX(int i) {
                return mBalls[i].mPosX;
            }

            float getPosY(int i) {
                return mBalls[i].mPosY;
            }
        }

        public void startSimulation() {
            /*
             * It is not necessary to get accelerometer events at a very high
             * rate, by using a slower rate (SENSOR_DELAY_UI), we get an
             * automatic low-pass filter, which "extracts" the gravity component
             * of the acceleration. As an added benefit, we use less power and
             * CPU resources.
             */
            mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
        }

        public void stopSimulation() {
            mSensorManager.unregisterListener(this);
        }

        public SimulationView(Context context) {
            super(context);
            mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            mXDpi = metrics.xdpi;
            mYDpi = metrics.ydpi;
            mMetersToPixelsX = mXDpi / 0.0254f;
            mMetersToPixelsY = mYDpi / 0.0254f;

            // rescale the ball so it's about 0.5 cm on screen
            Bitmap ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
            final int dstWidth = (int) (sBallDiameter * mMetersToPixelsX + 0.5f);
            final int dstHeight = (int) (sBallDiameter * mMetersToPixelsY + 0.5f);
            mBitmap = Bitmap.createScaledBitmap(ball, dstWidth, dstHeight, true);

            Options opts = new Options();
            opts.inDither = true;
            opts.inPreferredConfig = Bitmap.Config.RGB_565;
            mWood = BitmapFactory.decodeResource(getResources(), R.drawable.wood, opts);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            // compute the origin of the screen relative to the origin of
            // the bitmap
            mXOrigin = (w - mBitmap.getWidth()) * 0.5f;
            mYOrigin = (h - mBitmap.getHeight()) * 0.5f;
            mHorizontalBound = ((w / mMetersToPixelsX - sBallDiameter) * 0.5f);
            mVerticalBound = ((h / mMetersToPixelsY - sBallDiameter) * 0.5f);
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
                return;
            /*
             * record the accelerometer data, the event's timestamp as well as
             * the current time. The latter is needed so we can calculate the
             * "present" time during rendering. In this application, we need to
             * take into account how the screen is rotated with respect to the
             * sensors (which always return data in a coordinate space aligned
             * to with the screen in its native orientation).
             * 记录加速传感器的数据、事件发生的时间以及当前时间。
             * 我们需要后者来计算渲染期间的展现时间。在这个应用程序中,
             * 我们需要考虑屏幕是怎样跟传感器一起旋转的(让它返回的数据
             * 跟屏幕的原始坐标空间相对应)
             */

            switch (mDisplay.getRotation()) {
                case Surface.ROTATION_0:
                    mSensorX = event.values[0];
                    mSensorY = event.values[1];
                    break;
                case Surface.ROTATION_90:
                    mSensorX = -event.values[1];
                    mSensorY = event.values[0];
                    break;
                case Surface.ROTATION_180:
                    mSensorX = -event.values[0];
                    mSensorY = -event.values[1];
                    break;
                case Surface.ROTATION_270:
                    mSensorX = event.values[1];
                    mSensorY = -event.values[0];
                    break;
            }

            mSensorTimeStamp = event.timestamp;
            mCpuTimeStamp = System.nanoTime();
        }

        @Override
        protected void onDraw(Canvas canvas) {

            /*
             * draw the background
             */

            canvas.drawBitmap(mWood, 0, 0, null);

            /*
             * compute the new position of our object, based on accelerometer
             * data and present time.
             */

            final ParticleSystem particleSystem = mParticleSystem;
            final long now = mSensorTimeStamp + (System.nanoTime() - mCpuTimeStamp);
            final float sx = mSensorX;
            final float sy = mSensorY;

            particleSystem.update(sx, sy, now);

            final float xc = mXOrigin;
            final float yc = mYOrigin;
            final float xs = mMetersToPixelsX;
            final float ys = mMetersToPixelsY;
            final Bitmap bitmap = mBitmap;
            final int count = particleSystem.getParticleCount();
            for (int i = 0; i < count; i++) {
                /*
                 * We transform the canvas so that the coordinate system matches
                 * the sensors coordinate system with the origin in the center
                 * of the screen and the unit is the meter.
                 */

                final float x = xc + particleSystem.getPosX(i) * xs;
                final float y = yc - particleSystem.getPosY(i) * ys;
                canvas.drawBitmap(bitmap, x, y, null);
            }

            // and make sure to redraw asap
            invalidate();
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值