AccelerometerPlayActivity代码注释(未完成)

来源:互联网 发布:java 图片识别数字 编辑:程序博客网 时间:2024/06/06 08:49

因需要将类名修改为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
原创粉丝点击