zoukankan      html  css  js  c++  java
  • Android sample 之模拟重力感应,加速度

       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;
    
            private float mXDpi;
            private float mYDpi;
            private float mMetersToPixelsX;
            private float mMetersToPixelsY;
            private Bitmap mBitmap;
            private Bitmap mWood;
            private float mXOrigin;
            private float mYOrigin;
            private float mSensorX;
            private float mSensorY;
            private long mSensorTimeStamp;
            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 {
                private float mPosX;
                private float mPosY;
                private float mAccelX;
                private float mAccelY;
                private float mLastPosX;
                private float mLastPosY;
                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;
                    mOneMinusFriction = 1.0f - sFriction + r;
                }
    
                public 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
                    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.
                     */
                    final float invm = 1.0f / m;
                    final float ax = gx * invm;
                    final float ay = gy * invm;
    
                    /*
                     * Time-corrected Verlet integration The position Verlet
                     * integrator is defined as x(t+dt) = x(t) + x(t) - x(t-dt) +
                     * a(t).t^2 However, the above equation doesn't handle variable
                     * dt very well, a time-corrected version is needed: x(t+dt) =
                     * x(t) + (x(t) - x(t-dt)) * (dt/dt_prev) + a(t).t^2 We also add
                     * a simple friction term (f) to the equation: x(t+dt) = x(t) +
                     * (1-f) * (x(t) - x(t-dt)) * (dt/dt_prev) + a(t)t^2
                     */
                    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.
                 */
                public void resolveCollisionWithBounds() {
                    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.
                 */
                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 (int i = 0; i < count; i++) {
                                Particle ball = mBalls[i];
                                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.
                 */
                public 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 intersects
                             * with the walls.
                             */
                            curr.resolveCollisionWithBounds();
                        }
                    }
                }
    
                public int getParticleCount() {
                    return mBalls.length;
                }
    
                public float getPosX(int i) {
                    return mBalls[i].mPosX;
                }
    
                public 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) {
            }
        }
    

      

  • 相关阅读:
    我用Python爬虫挣钱的那点事
    猿人学 . 爬虫逆向高阶课
    Python中实用却不常见的小技巧
    Python内存数据序列化到硬盘上哪家强
    利用setuptools发布Python程序到PyPI,为Python添砖加瓦
    配置tmux在机器重启后自动恢复tmux工作现场,告别重启恐惧症
    用python实现新词发现程序——基于凝固度和自由度
    学习笔记:Python序列化常用工具及性能对比
    浅谈自然语言在科技时代的运用
    python学习笔记:建立一个自己的搜索引擎
  • 原文地址:https://www.cnblogs.com/spring87/p/5323022.html
Copyright © 2011-2022 走看看