zoukankan      html  css  js  c++  java
  • MultiTouch camera controls source code

    http://www.jpct.net/wiki/index.php/MultiTouch_camera_controls

    MultiTouch camera controls

    This code will handle control from 1 or 2 fingers, it was made for a tablet showing 3D objects, so it's made for navigating not for FPS gaming.

    Usage Call MovementHandler.handleMotionEvent for every motionEvent you receive. CAll MovementHandler.getMovement for every tick or whenever you can to update the movement.

    import android.util.Log;
    import android.view.MotionEvent;
    
    /**
     * 
     * @author Ruben.Hesselbaek@beumergroup.com
     *
     */
    public class MovementHandler {
    
        /**
         * Logs a lot of stuff
         */
        public static final boolean DEBUG_MOVEMENT = false;
    
        /**
         * Min 0.25 degrees
         */
        public static final float MIN_ANGLE_XMOVEMENT = (float) (Math.PI / 720);
    
        /**
         * Max 15 degrees
         */
        public static final float MAX_ANGLE_XMOVEMENT = (float) MIN_ANGLE_XMOVEMENT * 60;
    
        /**
         * Pixels->Angle ratio on the X-axis
         */
        public static final float XANGLE_FACTOR = 360;
    
        /**
         * Min 0.25 degrees
         */
        public static final float MIN_ANGLE_YMOVEMENT = (float) (Math.PI / 720);
    
        /**
         * Max 15 degrees
         */
        public static final float MAX_ANGLE_YMOVEMENT = (float) MIN_ANGLE_YMOVEMENT * 60;
    
        /**
         * Pixels->Angle ratio on the Y-axis
         */
        public static final float YANGLE_FACTOR = 360;
    
        /**
         * Pixels->Distance ratio
         */
        public static final float DISTANCE_FACTOR = 10;
    
        /**
         * Pixels->Movement ratio
         */
        public static final float MOVEMENT_X_FACTOR = 10;
    
        /**
         * Pixels->Movement ratio
         */
        public static final float MOVEMENT_Y_FACTOR = 10;
    
        public static final float MIN_MOVEMENT_DELTA = 0.1f;
        public static final float MAX_MOVEMENT_DELTA = 5;
    
        private int _firstPointerId = MotionEvent.INVALID_POINTER_ID;
        private float startMovementx1;
        private float startMovementy1;
        private float lastMovementx1;
        private float lastMovementy1;
    
        private int _secondPointerId = MotionEvent.INVALID_POINTER_ID;
        private float startMovementx2;
        private float startMovementy2;
        private float lastMovementy2;
        private float lastMovementx2;
    
        private float startDistance;
        private float lastDistance;
    
        private float startAngle;
        private float lastAngle;
    
        public synchronized Movement getMovement() {
            Movement movement = new Movement();
    
            if (_secondPointerId != MotionEvent.INVALID_POINTER_ID) {
                float movementX1 = lastMovementx1 - startMovementx1;
                float movementY1 = lastMovementy1 - startMovementy1;
                float movementX2 = lastMovementx2 - startMovementx2;
                float movementY2 = lastMovementy2 - startMovementy2;
    
                if ((movementX1 > 0 && movementX2 > 0)
                        || (movementX1 < 0 && movementX2 < 0)) {
                    float movementX = Math.min(Math.abs(movementX1),
                            Math.abs(movementX2))
                            / MOVEMENT_X_FACTOR;
                    if (movementX > MIN_MOVEMENT_DELTA
                            && movementX < MAX_MOVEMENT_DELTA) {
                        if (movementX1 > 0) {
                            movement.cameraMovementX = movementX;
                        } else {
                            movement.cameraMovementX = -movementX;
                        }
                    } else {
                        if (DEBUG_MOVEMENT) {
                            Log.d("MovementHandler",
                                    "getMovement(): Invalid movement: movementX=<"
                                            + movementX + ">, movementX1=<"
                                            + movementX1 + ">, movementX2=<"
                                            + movementX2 + ">");
                        }
                    }
                }
    
                if ((movementY1 > 0 && movementY2 > 0)
                        || (movementY1 < 0 && movementY2 < 0)) {
                    float movementY = Math.min(Math.abs(movementY1),
                            Math.abs(movementY2))
                            / MOVEMENT_Y_FACTOR;
                    if (movementY > MIN_MOVEMENT_DELTA
                            && movementY < MAX_MOVEMENT_DELTA) {
                        if (movementY1 > 0) {
                            movement.cameraMovementY = movementY;
                        } else {
                            movement.cameraMovementY = -movementY;
                        }
                    } else {
                        if (DEBUG_MOVEMENT) {
                            Log.d("MovementHandler",
                                    "getMovement(): Invalid movement: movementY<"
                                            + movementY + ">, movementY1=<"
                                            + movementY1 + ">, movementY2=<"
                                            + movementY2 + ">");
                        }
                    }
                }
                float distanceDelta = lastDistance - startDistance;
                float distance = distanceDelta / DISTANCE_FACTOR;
                float absoluteDistance = Math.abs(distance);
                if (absoluteDistance > MIN_MOVEMENT_DELTA
                        && absoluteDistance < MAX_MOVEMENT_DELTA) {
                    movement.cameraMovementZ = distance;
                } else {
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "getMovement(): Invalid movement: distanceDelta=<"
                                        + distanceDelta + ">, distance=<"
                                        + distance + ">");
                    }
                }
    
                float angleDelta = lastAngle - startAngle;
                float absoluteAngle = Math.abs(angleDelta);
                if (absoluteAngle > MIN_ANGLE_XMOVEMENT
                        && absoluteAngle < MAX_ANGLE_XMOVEMENT) {
                    movement.cameraRotationY = angleDelta;
                } else {
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "getMovement(): Invalid movement: absoluteAngle=<"
                                        + absoluteAngle + ">, startAngle=<"
                                        + Math.toDegrees(startAngle)
                                        + ">, lastAngle=<"
                                        + Math.toDegrees(lastAngle) + ">");
                    }
                }
            } else if (_firstPointerId != MotionEvent.INVALID_POINTER_ID) {
                float movementX1 = lastMovementx1 - startMovementx1;
                float angle = (float) ((movementX1) / XANGLE_FACTOR);
                float absoluteAngle = Math.abs(angle);
                if (absoluteAngle > MIN_ANGLE_XMOVEMENT
                        && absoluteAngle < MAX_ANGLE_XMOVEMENT) {
                    movement.cameraRotationY = angle;
                } else {
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "getMovement(): Invalid movement: movementX=<"
                                        + movementX1 + ">, angle=<" + absoluteAngle
                                        + ">");
                    }
                }
    
                float movementY1 = lastMovementy1 - startMovementy1;
                angle = (float) ((movementY1) / YANGLE_FACTOR);
                absoluteAngle = Math.abs(angle);
                if (absoluteAngle > MIN_ANGLE_YMOVEMENT
                        && absoluteAngle < MAX_ANGLE_YMOVEMENT) {
                    movement.worldRotationX = angle;
                } else {
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "getMovement(): Invalid movement: movementY=<"
                                        + movementY1 + ">, angle=<" + absoluteAngle
                                        + ">");
                    }
                }
            }
            startMovementx1 = lastMovementx1;
            startMovementy1 = lastMovementy1;
            startMovementx2 = lastMovementx2;
            startMovementy2 = lastMovementy2;
            startDistance = lastDistance;
            startAngle = lastAngle;
            return movement;
        }
    
        public synchronized void handleMotionEvent(MotionEvent event) {
            final int pointerIndex = event.getActionIndex();
            final int pointerId = event.getPointerId(pointerIndex);
    
            if (DEBUG_MOVEMENT) {
                Log.d("MovementHandler", "handleMotionEvent(pointerIndex=<"
                        + pointerIndex + ">, pointerId=<" + pointerId
                        + ">, event=<" + event.getActionMasked()
                        + ">, pointerCount=<" + event.getPointerCount() + ">");
            }
            switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
                _firstPointerId = pointerId;
                _secondPointerId = MotionEvent.INVALID_POINTER_ID;
                startMovementx1 = event.getX(_firstPointerId);
                startMovementy1 = event.getY(_firstPointerId);
                lastMovementx1 = startMovementx1;
                lastMovementy1 = startMovementy1;
                if (DEBUG_MOVEMENT) {
                    Log.d("MovementHandler", "ACTION_DOWN(firstPointerId=<"
                            + _firstPointerId + ">(" + startMovementx1 + ","
                            + startMovementy1 + ")");
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                _firstPointerId = MotionEvent.INVALID_POINTER_ID;
                _secondPointerId = MotionEvent.INVALID_POINTER_ID;
                if (DEBUG_MOVEMENT) {
                    Log.d("MovementHandler", "ACTION_UP(firstPointerId=<"
                            + _firstPointerId + ">)");
                }
                break;
            }
            case MotionEvent.ACTION_POINTER_DOWN:
                if (event.getPointerCount() == 2) {
                    _secondPointerId = pointerId;
                    startMovementx2 = event.getX(_secondPointerId);
                    startMovementy2 = event.getY(_secondPointerId);
                    lastMovementx2 = startMovementx2;
                    lastMovementy2 = startMovementy2;
                    startDistance = calcDistance();
                    startAngle = calcAngle();
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "ACTION_POINTER_DOWN(secondPointerId=<"
                                        + _secondPointerId + ">)");
                    }
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                if (pointerId == _firstPointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    _firstPointerId = event.getPointerId(newPointerIndex);
                    int oldPointerId = _firstPointerId;
                    if (DEBUG_MOVEMENT) {
                        Log.d("MovementHandler",
                                "ACTION_POINTER_UP(_firstPointerId=<"
                                        + _firstPointerId + ">, oldPointerId=<"
                                        + oldPointerId + ">)");
                    }
                    startMovementx1 = event.getX(newPointerIndex);
                    startMovementy1 = event.getY(newPointerIndex);
                } else if (pointerId == _secondPointerId) {
                    if (event.getPointerCount() > 2) {
                        // This was our active secondpointer going up. Choose a new
                        // active pointer and adjust accordingly.
                        final int newPointerIndex = pointerIndex == 1 ? 2 : 1;
                        _secondPointerId = event.getPointerId(newPointerIndex);
                        int oldPointerId = _secondPointerId;
                        if (DEBUG_MOVEMENT) {
                            Log.d("MovementHandler",
                                    "ACTION_POINTER_UP(secondPointerId=<"
                                            + _secondPointerId
                                            + ">, oldPointerId=<" + oldPointerId
                                            + ">)");
                        }
                        startMovementx2 = event.getX(newPointerIndex);
                        startMovementy2 = event.getY(newPointerIndex);
                    } else {
                        _secondPointerId = MotionEvent.INVALID_POINTER_ID;
                        if (DEBUG_MOVEMENT) {
                            Log.d("MovementHandler",
                                    "ACTION_POINTER_UP(secondPointerId=<"
                                            + _secondPointerId + ">)");
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE: {
                int firstPointerIndex = event.findPointerIndex(_firstPointerId);
                int secondPointerIndex = event.findPointerIndex(_secondPointerId);
                if (event.getPointerCount() > 0) {
                    lastMovementx1 = event.getX(firstPointerIndex);
                    lastMovementy1 = event.getY(firstPointerIndex);
                }
                if (event.getPointerCount() > 1) {
                    lastMovementx2 = event.getX(secondPointerIndex);
                    lastMovementy2 = event.getY(secondPointerIndex);
                    lastDistance = calcDistance();
                    lastAngle = calcAngle();
                }
                break;
            }
            }
        }
    
        private float calcDistance() {
            float deltaX = lastMovementx2 - lastMovementx1;
            float deltaY = lastMovementy2 - lastMovementy1;
            return (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
        }
    
        private float calcAngle() {
            return (float) Math.atan2(lastMovementx1 - lastMovementx2,
                    lastMovementy1 - lastMovementy2);
        }
    }
    /**
     * 
     * @author Ruben.Hesselbaek@beumergroup.com
     *
     */
    public class Movement {
    
        public float worldRotationX;
        public float cameraRotationY;
        public float cameraMovementX;
        public float cameraMovementY;
        public float cameraMovementZ;
    
        public boolean hasMovement() {
            return worldRotationX != 0f || cameraRotationY != 0f
                    || cameraMovementX != 0f || cameraMovementY != 0f
                    || cameraMovementZ != 0f;
        }
    
        @Override
        public String toString() {
            return "Movement (hasMovement=<"+hasMovement()+">, worldRotationX=" + worldRotationX
                    + ", cameraRotationY=" + cameraRotationY + ", cameraMovementX="
                    + cameraMovementX + ", cameraMovementY=" + cameraMovementY
                    + ", cameraMovementZ=" + cameraMovementZ + ")";
        }
    
    }
    @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            _movementHandler.handleMotionEvent(event);
            return true;
        }
    
        private void moveCamera() {
            Movement movement = _movementHandler.getMovement();
    
            if (movement.hasMovement()) {
                Camera camera = world.getCamera();
    
                Matrix rot = camera.getBack();
    
                rot.rotateAxis(rot.getYAxis(), -(float) movement.cameraRotationY);
                worldObject.rotateX(movement.worldRotationX);
                float angle = worldObject.getYAxis().calcAngle(
                        new SimpleVector(0, 1, 0));
                float crossAngle = worldObject.getYAxis().calcCross(
                        new SimpleVector(0, 1, 0)).x;
                if (crossAngle > 0) {
                    worldObject.rotateX(-angle);
                } else {
                    float delta = (float) (angle - (Math.PI / 2));
                    if (delta > 0) {
                        worldObject.rotateX(delta);
                    }
                }
    
                camera.moveCamera(Camera.CAMERA_MOVELEFT, movement.cameraMovementX);
                camera.moveCamera(Camera.CAMERA_MOVEUP, movement.cameraMovementY);
                camera.moveCamera(Camera.CAMERA_MOVEIN, movement.cameraMovementZ);
            }
        }
  • 相关阅读:
    Ansible专题整理
    前端基础之JQuery
    Three.js开发指南---创建,加载高级网格和几何体(第八章)
    Three.js开发指南---粒子和粒子系统(第七章)
    Three.js开发指南---使用高级几何体和二元操作(第六章)
    Three.js开发指南---学习使用几何体(第五章)
    Three.js开发指南---使用three.js的材质(第四章)
    Three.js开发指南---使用three.js里的各种光源(第三章)
    Three.js开发指南---使用构建three.js的基本组件(第二章)
    -Three.js开发指南---用three.js创建你的第一个三维场景(第一章)
  • 原文地址:https://www.cnblogs.com/welhzh/p/4295105.html
Copyright © 2011-2022 走看看