手势_手势笔 - CSDN
  • 转载请标明出处:...具体请参考:Android 手势检测实战 打造支持缩放平移的图片预览效果(上);本篇继续完善我们的ImageView~~首先加入放大后的移动~~1、自由的进行移动我们在on

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:【张鸿洋的博客】

    上一篇已经带大家实现了自由的放大缩小图片,简单介绍了下Matrix;具体请参考:Android 手势检测实战 打造支持缩放平移的图片预览效果(上);本篇继续完善我们的ImageView~~

    首先加入放大后的移动~~

    1、自由的进行移动

    我们在onTouchEvent里面,加上移动的代码,当然了,必须长或宽大于屏幕才可以移动~~~

    @Override
    	public boolean onTouch(View v, MotionEvent event)
    	{
    		mScaleGestureDetector.onTouchEvent(event);
    
    		float x = 0, y = 0;
    		// 拿到触摸点的个数
    		final int pointerCount = event.getPointerCount();
    		// 得到多个触摸点的x与y均值
    		for (int i = 0; i < pointerCount; i++)
    		{
    			x += event.getX(i);
    			y += event.getY(i);
    		}
    		x = x / pointerCount;
    		y = y / pointerCount;
    
    		/**
    		 * 每当触摸点发生变化时,重置mLasX , mLastY 
    		 */
    		if (pointerCount != lastPointerCount)
    		{
    			isCanDrag = false;
    			mLastX = x;
    			mLastY = y;
    		}
    		
    
    		lastPointerCount = pointerCount;
    
    		switch (event.getAction())
    		{
    		case MotionEvent.ACTION_MOVE:
    			Log.e(TAG, "ACTION_MOVE");
    			float dx = x - mLastX;
    			float dy = y - mLastY;
    			
    			if (!isCanDrag)
    			{
    				isCanDrag = isCanDrag(dx, dy);
    			}
    			if (isCanDrag)
    			{
    				RectF rectF = getMatrixRectF();
    				if (getDrawable() != null)
    				{
    					isCheckLeftAndRight = isCheckTopAndBottom = true;
    					// 如果宽度小于屏幕宽度,则禁止左右移动
    					if (rectF.width() < getWidth())
    					{
    						dx = 0;
    						isCheckLeftAndRight = false;
    					}
    					// 如果高度小雨屏幕高度,则禁止上下移动
    					if (rectF.height() < getHeight())
    					{
    						dy = 0;
    						isCheckTopAndBottom = false;
    					}
    					mScaleMatrix.postTranslate(dx, dy);
    					checkMatrixBounds();
    					setImageMatrix(mScaleMatrix);
    				}
    			}
    			mLastX = x;
    			mLastY = y;
    			break;
    
    		case MotionEvent.ACTION_UP:
    		case MotionEvent.ACTION_CANCEL:
    			Log.e(TAG, "ACTION_UP");
    			lastPointerCount = 0;
    			break;
    		}
    
    		return true;
    	}

    首先我们拿到触摸点的数量,然后求出多个触摸点的平均值,设置给我们的mLastX , mLastY , 然后在移动的时候,得到dx ,dy 进行范围检查以后,调用mScaleMatrix.postTranslate进行设置偏移量,当然了,设置完成以后,还需要再次校验一下,不能把图片移动的与屏幕边界出现白边,校验完成后,调用setImageMatrix.

    这里:需要注意一下,我们没有复写ACTION_DOWM,是因为,ACTION_DOWN在多点触控的情况下,只要有一个手指按下状态,其他手指按下不会再次触发ACTION_DOWN,但是多个手指以后,触摸点的平均值会发生很大变化,所以我们没有用到ACTION_DOWN。每当触摸点的数量变化,我们就会跟新当前的mLastX,mLastY.

    下面是上面用到的两个私有方法,一个用于检查边界,一个用于判断是否是拖动的操作:

    /**
    	 * 移动时,进行边界判断,主要判断宽或高大于屏幕的
    	 */
    	private void checkMatrixBounds()
    	{
    		RectF rect = getMatrixRectF();
    
    		float deltaX = 0, deltaY = 0;
    		final float viewWidth = getWidth();
    		final float viewHeight = getHeight();
    		// 判断移动或缩放后,图片显示是否超出屏幕边界
    		if (rect.top > 0 && isCheckTopAndBottom)
    		{
    			deltaY = -rect.top;
    		}
    		if (rect.bottom < viewHeight && isCheckTopAndBottom)
    		{
    			deltaY = viewHeight - rect.bottom;
    		}
    		if (rect.left > 0 && isCheckLeftAndRight)
    		{
    			deltaX = -rect.left;
    		}
    		if (rect.right < viewWidth && isCheckLeftAndRight)
    		{
    			deltaX = viewWidth - rect.right;
    		}
    		mScaleMatrix.postTranslate(deltaX, deltaY);
    	}
    
    	/**
    	 * 是否是推动行为
    	 * 
    	 * @param dx
    	 * @param dy
    	 * @return
    	 */
    	private boolean isCanDrag(float dx, float dy)
    	{
    		return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
    	}

    这样,我们就可以快乐的放大、缩小加移动了~~~

    效果图:这次换个男人的图片,我们越狱的主角之一,TBug~


    我们的缩放+移动搞定~~

    2、双击放大与缩小

    谈到双击事件,我们的GestureDetector终于要登场了,这哥们可以捕获双击事件~~

    1、GestureDetector的使用

    因为GestureDetector设置监听器的话,方法一大串,而我们只需要onDoubleTap这个回调,所以我们准备使用它的一个内部类SimpleOnGestureListener,对接口的其他方法实现了空实现。

    不过还有几个问题需要讨论下,才能开始我们的代码:

    1、我们双击尺寸如何变化?

    我是这样的,根据当前的缩放值,如果是小于2的,我们双击直接到变为原图的2倍;如果是2,4之间的,我们双击直接为原图的4倍;其他状态也就是4倍,双击后还原到最初的尺寸。

    如果你觉得这样不合适,可以根据自己的爱好调整。

    2、我们双击变化,需要一个动画~~比如我们上例的演示图,图片很大,全屏显示的时候initScale=0.5左后,如果双击后变为2,也就是瞬间大了四倍,没有一个过渡的效果的话,给用户的感觉会特别差。所以,我们准备使用postDelay执行一个Runnable,Runnable中再次根据的当然的缩放值继续执行。

    首先我们在构造方法中,完成对GestureDetector的初始化,以及设置onDoubleTap监听

    public ZoomImageView(Context context, AttributeSet attrs)
    	{
    		super(context, attrs);
    		mScaleGestureDetector = new ScaleGestureDetector(context, this);
    		mGestureDetector = new GestureDetector(context,
    				new SimpleOnGestureListener()
    				{
    					@Override
    					public boolean onDoubleTap(MotionEvent e)
    					{
    						if (isAutoScale == true)
    							return true;
    
    						float x = e.getX();
    						float y = e.getY();
    						Log.e("DoubleTap", getScale() + " , " + initScale);
    						if (getScale() < SCALE_MID)
    						{
    							ZoomImageView.this.postDelayed(
    									new AutoScaleRunnable(SCALE_MID, x, y), 16);
    							isAutoScale = true;
    						} else if (getScale() >= SCALE_MID
    								&& getScale() < SCALE_MAX)
    						{
    							ZoomImageView.this.postDelayed(
    									new AutoScaleRunnable(SCALE_MAX, x, y), 16);
    							isAutoScale = true;
    						} else
    						{
    							ZoomImageView.this.postDelayed(
    									new AutoScaleRunnable(initScale, x, y), 16);
    							isAutoScale = true;
    						}
    
    						return true;
    					}
    				});
    		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    		super.setScaleType(ScaleType.MATRIX);
    		this.setOnTouchListener(this);
    	}

    1、当双击的时候,首先判断是否正在自动缩放,如果在,直接retrun ; 

    2、然后就进入了我们的if,如果当然是scale小于2,则通过view.发送一个Runnable进行执行;其他类似;

    下面看我们的Runnable的代码:

    /**
    	 * 自动缩放的任务
    	 * 
    	 * @author zhy
    	 * 
    	 */
    	private class AutoScaleRunnable implements Runnable
    	{
    		static final float BIGGER = 1.07f;
    		static final float SMALLER = 0.93f;
    		private float mTargetScale;
    		private float tmpScale;
    
    		/**
    		 * 缩放的中心
    		 */
    		private float x;
    		private float y;
    
    		/**
    		 * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小
    		 * 
    		 * @param targetScale
    		 */
    		public AutoScaleRunnable(float targetScale, float x, float y)
    		{
    			this.mTargetScale = targetScale;
    			this.x = x;
    			this.y = y;
    			if (getScale() < mTargetScale)
    			{
    				tmpScale = BIGGER;
    			} else
    			{
    				tmpScale = SMALLER;
    			}
    
    		}
    
    		@Override
    		public void run()
    		{
    			// 进行缩放
    			mScaleMatrix.postScale(tmpScale, tmpScale, x, y);
    			checkBorderAndCenterWhenScale();
    			setImageMatrix(mScaleMatrix);
    
    			final float currentScale = getScale();
    			//如果值在合法范围内,继续缩放
    			if (((tmpScale > 1f) && (currentScale < mTargetScale))
    					|| ((tmpScale < 1f) && (mTargetScale < currentScale)))
    			{
    				ZoomImageView.this.postDelayed(this, 16);
    			} else//设置为目标的缩放比例
    			{
    				final float deltaScale = mTargetScale / currentScale;
    				mScaleMatrix.postScale(deltaScale, deltaScale, x, y);
    				checkBorderAndCenterWhenScale();
    				setImageMatrix(mScaleMatrix);
    				isAutoScale = false;
    			}
    
    		}
    	}

    代码写完了,我们依然需要把我们的event传给它,依然是在onTouch方法:

    @Override
    	public boolean onTouch(View v, MotionEvent event)
    	{
    		if (mGestureDetector.onTouchEvent(event))
    			return true;

    好了,双击放大与缩小的功能就搞定了,下面测试下~~~

    效果图,终于可以用模拟器了~~:



    3、处理与ViewPager的冲突

    直接把我们的图片作为ViewPager的Item,可想而知,肯定有冲突~~

    1、布局文件

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <android.support.v4.view.ViewPager
            android:id="@+id/id_viewpager"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
        </android.support.v4.view.ViewPager>
    
    </RelativeLayout>


    2、Activity代码

    package com.zhy.zhy_scalegesturedetector02;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    
    import com.zhy.view.ZoomImageView;
    
    public class MainActivity extends Activity
    {
    	private ViewPager mViewPager;
    	private int[] mImgs = new int[] { R.drawable.tbug, R.drawable.a,
    			R.drawable.xx };
    	private ImageView[] mImageViews = new ImageView[mImgs.length];
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState)
    	{
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.vp);
    		
    		mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
    		mViewPager.setAdapter(new PagerAdapter()
    		{
    
    			@Override
    			public Object instantiateItem(ViewGroup container, int position)
    			{
    				ZoomImageView imageView = new ZoomImageView(
    						getApplicationContext());
    				imageView.setImageResource(mImgs[position]);
    				container.addView(imageView);
    				mImageViews[position] = imageView;
    				return imageView;
    			}
    
    			@Override
    			public void destroyItem(ViewGroup container, int position,
    					Object object)
    			{
    				container.removeView(mImageViews[position]);
    			}
    
    			@Override
    			public boolean isViewFromObject(View arg0, Object arg1)
    			{
    				return arg0 == arg1;
    			}
    
    			@Override
    			public int getCount()
    			{
    				return mImgs.length;
    			}
    		});
    
    	}
    }
    

    现在直接运行,发现ViewPager好着呢,但是我们的图片放大以后,移动和ViewPager冲突了,又不能移动了~。。。擦擦擦。。。

    3、处理冲突

    现在我们迅速的想一想,记得之前学习过事件分发机制,我们的ZoomImageView在ViewPager中,如果我们不想被拦截,那么如何做呢?
    首先不想被拦截的条件是:我们的宽或高大于屏幕宽或高时,因为此时可以移动,我们不想被拦截。接下来,不想被拦截:

    getParent().requestDisallowInterceptTouchEvent(true);

    一行代码足以,如果你对事件分发中,不被拦截不清晰,可以参考:如何不被拦截 。

    放在一起我们的代码就是:

    switch (event.getAction())
    		{
    		case MotionEvent.ACTION_DOWN:
    			if (rectF.width() > getWidth() || rectF.height() > getHeight())
    			{
    				getParent().requestDisallowInterceptTouchEvent(true);
    			}
    			break;
    		case MotionEvent.ACTION_MOVE:
    			if (rectF.width() > getWidth() || rectF.height() > getHeight())
    			{
    				getParent().requestDisallowInterceptTouchEvent(true);
    			}

    ~当宽或高大于屏幕宽或高时,拖动效果认为是移动图片,反之则让ViewPager去处理

    此时的效果:


    ok,现在已经解决了和ViewPager的冲突,ps:尼玛不应该双击还能放大两次到4倍,,,,,好恶心。。。

    4、到达边界事件交给ViewPager处理

    可能有些用户还希望,当图片到达边界时,不能再拖动的时候,能够把事件给ViewPager

    那就在ACTION_MOVE中,判断当前已经到达边界,且还在拉的时候,事件交给ViewPager

    if (isCanDrag)
    			{
    
    				if (getDrawable() != null)
    				{
    					if (getMatrixRectF().left == 0 && dx > 0)
    					{
    						getParent().requestDisallowInterceptTouchEvent(false);
    					}
    
    					if (getMatrixRectF().right == getWidth() && dx < 0)
    					{
    						getParent().requestDisallowInterceptTouchEvent(false);
    					}

    此时的效果:


    好了,其实添加了这个之后,体验一般哈~~~



    终于写完了,代码中可能存在BUG,发现问题,或者解决了发现的BUG时,希望可以直接在博客下面留言,也能够方便他人~~

    到此,我们的Android 手势检测实战 打造支持缩放平移的图片预览效果 结束~~!


    建议把双击放大到4倍的地方,注释掉一个If

    //						else if (getScale() >= SCALE_MID
    //								&& getScale() < SCALE_MAX)
    //						{
    //							ZoomImageView.this.postDelayed(
    //									new AutoScaleRunnable(SCALE_MAX, x, y), 16);
    //							isAutoScale = true;
    //						} 

    连续双击放大,感觉不爽,代码已经上传,我就不重传了,如果你也觉得不爽,可以自行注释。


    单图版源码点击下载


    ViewPager版源码下载



    ----------------------------------------------------------------------------------------------------------

    博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

    1、高仿微信5.2.1主界面及消息提醒

    2、高仿QQ5.0侧滑







    展开全文
  • 由于项目要求,需要在QWidget中实现一个手势操作的功能,对图片进行放大/缩小/平移功能,并且还需要支持通过鼠标和键盘来实现该功能。其实这种功能在QGraphicsView中实现比较简单, 不过在QWidget中也能实现,本次...

    由于项目要求,需要在QWidget中实现一个手势操作的功能,对图片进行放大/缩小/平移功能,并且还需要支持通过鼠标和键盘来实现该功能。其实这种功能在QGraphicsView中实现比较简单, 不过在QWidget中也能实现,本次通过QGestureEvent来捕捉手势操作,然后对图片进行缩放或者移动。

    废话不多说,直接上代码


    首先来看头文件:

    class QGestureEvent;
    class QPanGesture;
    class QPinchGesture;
    class QSwipeGesture;
    class CProjectionPicture;
    
    class CProjectionPicture : public QWidget
    {
        Q_OBJECT
    public:
        CProjectionPicture(QWidget *parent = 0);
    
        void setPicture(QImage & image);
    
    protected:
        // 放大/缩小
        void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
        void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    
    
        void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
        // 平移
        void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
        void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
        void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    
        bool event(QEvent *event) Q_DECL_OVERRIDE;
        void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
        void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;
    
    
    public Q_SLOTS:
        void zoomIn();  // 放大
        void zoomOut();  // 缩小
        void zoom(float scale); // 缩放 - scaleFactor:缩放的比例因子
        void translate(QPointF delta);  // 平移
    
    
    private:
        bool gestureEvent(QGestureEvent *event);
        void panTriggered(QPanGesture*);
        void pinchTriggered(QPinchGesture*);
    
        QImage loadImage(const QString &fileName);
    
        QImage currentImage;
    
        qreal horizontalOffset;
        qreal verticalOffset;
    
        qreal scaleFactor;
        qreal currentStepScaleFactor;
        Qt::MouseButton m_translateButton;  // 平移按钮
        bool m_bMouseTranslate;
        qreal m_zoomDelta;  // 缩放的增量
        QPoint m_lastMousePos;  // 鼠标最后按下的位置
    
    
    };

    源文件:

    CProjectionPicture::CProjectionPicture(QWidget *parent)
        : QWidget(parent),
        horizontalOffset(0),
        verticalOffset(0),
        scaleFactor(1),
        currentStepScaleFactor(1),
        m_translateButton(Qt::LeftButton),
        m_bMouseTranslate(false),
        m_zoomDelta(0.2),
    {
        this->setFocusPolicy(Qt::ClickFocus);
     
        grabGesture(Qt::PanGesture);
        grabGesture(Qt::PinchGesture);
        grabGesture(Qt::SwipeGesture);
    }
    void CProjectionPicture::setPicture(QImage &image)
    {
        currentImage = image.convertToFormat(QImage::Format_RGB888);
        update();
    }
    
    
    bool CProjectionPicture::event(QEvent *event)
    {
        if (event->type() == QEvent::Gesture)
            return gestureEvent(static_cast<QGestureEvent*>(event));
        return QWidget::event(event);
    }
    
    void CProjectionPicture::paintEvent(QPaintEvent*)
    {
        QPainter painter(this);
        QImage image = currentImage;
    
       
        if(!image.isNull()){
            image = image.scaled(this->width()*currentStepScaleFactor * scaleFactor,
                                 this->height()*currentStepScaleFactor * scaleFactor,
                                 Qt::KeepAspectRatio,
                                 Qt::SmoothTransformation);
        }
            
        const qreal iw = image.width();
        const qreal ih = image.height();
        const qreal wh = height();
        const qreal ww = width();
    
        painter.translate(ww/2, wh/2);
        painter.translate(horizontalOffset, verticalOffset);
        //painter.scale(currentStepScaleFactor * scaleFactor, currentStepScaleFactor * scaleFactor);
        painter.translate(-iw/2, -ih/2);
        painter.drawImage(0,0,image);
    
    }
    
    void CProjectionPicture::mouseDoubleClickEvent(QMouseEvent *)
    {
        scaleFactor = 1;
        currentStepScaleFactor = 1;
        verticalOffset = 0;
        horizontalOffset = 0;
        update();
    }
    
    bool CProjectionPicture::gestureEvent(QGestureEvent *event)
    {
        if (QGesture *pan = event->gesture(Qt::PanGesture))
            panTriggered(static_cast<QPanGesture *>(pan));
        if (QGesture *pinch = event->gesture(Qt::PinchGesture))
            pinchTriggered(static_cast<QPinchGesture *>(pinch));
        return true;
    }
    
    void CProjectionPicture::panTriggered(QPanGesture *gesture)
    {
    #ifndef QT_NO_CURSOR
        switch (gesture->state()) {
            case Qt::GestureStarted:
            case Qt::GestureUpdated:
                setCursor(Qt::SizeAllCursor);
                break;
            default:
                setCursor(Qt::ArrowCursor);
        }
    #endif
        QPointF delta = gesture->delta();
        horizontalOffset += delta.x();
        verticalOffset += delta.y();
        update();
    }
    
    void CProjectionPicture::pinchTriggered(QPinchGesture *gesture)
    {
        QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
        if (changeFlags & QPinchGesture::ScaleFactorChanged) {
            currentStepScaleFactor = gesture->totalScaleFactor();
        }
        if (gesture->state() == Qt::GestureFinished) {
            scaleFactor *= currentStepScaleFactor;
            currentStepScaleFactor = 1;
        }
        update();
    }
    
    void CProjectionPicture::resizeEvent(QResizeEvent*e)
    {
        update();
        QWidget::resizeEvent(e);
    }
    
    // 上/下/左/右键向各个方向移动、加/减键进行缩放
    void CProjectionPicture::keyPressEvent(QKeyEvent *event)
    {
        switch (event->key()) {
        qDebug() << event->key();
        case Qt::Key_Up:
            translate(QPointF(0, -5));  // 上移
            break;
        case Qt::Key_Down:
            translate(QPointF(0, 5));  // 下移
            break;
        case Qt::Key_Left:
            translate(QPointF(-5, 0));  // 左移
            break;
        case Qt::Key_Right:
            translate(QPointF(5, 0));  // 右移
            break;
        case Qt::Key_Plus:  // 放大
            zoomIn();
            break;
        case Qt::Key_Minus:  // 缩小
            zoomOut();
            break;
        default:
            QWidget::keyPressEvent(event);
        }
        QWidget::keyPressEvent(event);
    }
    
    // 平移
    void CProjectionPicture::mouseMoveEvent(QMouseEvent *event)
    {
        if (m_bMouseTranslate){
            QPointF mouseDelta = event->pos() - m_lastMousePos;
            translate(mouseDelta);
        }
    
        m_lastMousePos = event->pos();
    
        QWidget::mouseMoveEvent(event);
    }
    
    void CProjectionPicture::mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "CProjectionPicture::mousePressEvent";
        if (event->button() == m_translateButton) {
            m_bMouseTranslate = true;
            m_lastMousePos = event->pos();
            setCursor(Qt::OpenHandCursor);
        }
    
        QWidget::mousePressEvent(event);
    }
    
    void CProjectionPicture::mouseReleaseEvent(QMouseEvent *event)
    {
        if (event->button() == m_translateButton)
        {
            m_bMouseTranslate = false;
            setCursor(Qt::ArrowCursor);
        }
    
        QWidget::mouseReleaseEvent(event);
    }
    
    // 放大/缩小
    void CProjectionPicture::wheelEvent(QWheelEvent *event)
    {
        qDebug() << "CProjectionPicture::wheelEvent";
    //    QPoint numPixels = event->pixelDelta();
        QPoint scrallAmount = event->angleDelta();
        if(scrallAmount.y() > 0){
            zoomIn();
        }
        else if(scrallAmount.y() < 0){
            zoomOut();
        }
        QWidget::wheelEvent(event);
    }
    
    // 放大
    void CProjectionPicture::zoomIn()
    {
        zoom(1 + m_zoomDelta);
    }
    
    // 缩小
    void CProjectionPicture::zoomOut()
    {
        zoom(1 - m_zoomDelta);
    }
    
    // 缩放 - scaleFactor:缩放的比例因子
    void CProjectionPicture::zoom(float scale)
    {
        scaleFactor *= scale;
        update();
    }
    
    // 平移
    void CProjectionPicture::translate(QPointF delta)
    {
        horizontalOffset += delta.x();
        verticalOffset += delta.y();
        update();
    }

    本文参考:http://blog.csdn.net/liang19890820/article/details/53543017

    展开全文
  • 1,本地leap手势数据的获取,并转换成字节码。 通过leap获取手势各关节的点坐标时,默认顺序是从大拇指到小拇指为0---4,然后关节从掌心到指尖默认为从0--1--2--3--4 using System.Collections.Generic; ...

    1,本地leap手势数据的获取,并转换成字节码。

    通过leap获取手势各关节的点坐标时,默认顺序是从大拇指到小拇指为0---4,然后关节从掌心到指尖默认为从0--1--2--3--4

     

     

    using System.Collections.Generic;
    using System;
    using UnityEngine;
    using Leap;
    using Leap.Unity;
    using PersonShare;
    using ServerCommunication;
    
    public class LocalHands : MonoBehaviour
    {
        public int HandID;
        private LeapProvider mProvider;
        public RemoteHand LeftHand = new RemoteHand();
        public RemoteHand RightHand = new RemoteHand();
    
        private int numL = 0, numR = 0;
        private const int leapHandLen= 44 * 3 * sizeof(double) + 4 * sizeof(double);
    
        //string path = "D:/Works/DEMO/Hands/Assets/StreamingAssets/";
        private  List<Vector3> Pos_Left = new List<Vector3>();
        private  List<Vector3> Pos_Right = new List<Vector3>();
        private byte[] currentFrameLeft = new byte[leapHandLen];
        private byte[] currentFrameRight = new byte[leapHandLen];
        private byte[] currentFrameHands= new byte[2* leapHandLen];
    
        //some varibales to send the data of Leap hands
    
        public ClientManager clientManager;
        void Start()
        {
            mProvider = FindObjectOfType<LeapProvider>() as LeapProvider;
        }
        void LateUpdate()
        {
            //1 Get hand data
            Frame mFrame = mProvider.CurrentFrame;//获取当前帧
            Hands_Model(mFrame);
    
            // 2 Connect the server
            if (clientManager == null)
                return;
            TCPConnection myTCP = clientManager.TCP;
            MessageIDInfo msgHands = new MessageIDInfo(MessageTypes.MT_SHAREHANDS);
            msgHands.ID = BitConverter.GetBytes(HandID);
    
            /// 3 Transform  the left hand data to bytes
            if (Pos_Left.Count == 0)
            {
                LeftHand.Arm.Direction = new Quaternion(0,0,0,0);  
                for (int i = 0; i < 44; i++)
                {
                    Pos_Left.Add(new Vector3(0, 0, 0));
                }
            }
            currentFrameLeft = EncodeLeftToByteArray();
            currentFrameLeft.CopyTo(currentFrameHands, 0);
    
            //4 Transform the right hand data to bytes
            if (Pos_Right.Count == 0)
            {
                RightHand.Arm.Direction = new Quaternion(0, 0, 0, 0);
                for (int i = 0; i < 44; i++)
                {
                    Pos_Right.Add(new Vector3(0, 0, 0));
                }
            }
            currentFrameRight = EncodeRightToByteArray();
            currentFrameRight.CopyTo(currentFrameHands, leapHandLen);
            msgHands.Info = currentFrameHands;
            //5 send to server
            myTCP.WriteSocket(msgHands.ToByteArray());
    
            //File.WriteAllBytes(path+"LeftHand.bytes", currentFramesLeft);
            //Debug.Log("左手数据存储成功!");
    
            //6 clear the list
    
            if (numL >= 1)
            {
                    Pos_Left.Clear();
                    numL = 0;
            }
    
            if (numR >= 1)
            {
                Pos_Right.Clear();
                numR = 0;
            }
        }
        void Hands_Model(Frame mFrame)
        {
            foreach (var itemHands in mFrame.Hands)//遍历左右手
            {
                if (itemHands.IsLeft)
                {
                    LeftHand.Wrist= new Vector3(itemHands.WristPosition.x, itemHands.WristPosition.y, itemHands.WristPosition.z);
                    LeftHand.Palm = new Vector3(itemHands.PalmPosition.x, itemHands.PalmPosition.y, itemHands.PalmPosition.z);
                    LeftHand.Arm.WristPosition = new Vector3(itemHands.Arm.NextJoint.x, itemHands.Arm.NextJoint.y, itemHands.Arm.NextJoint.z);
                    LeftHand.Arm.ElbowPosition = new Vector3(itemHands.Arm.PrevJoint.x, itemHands.Arm.PrevJoint.y, itemHands.Arm.PrevJoint.z);
                    LeftHand.Arm.Direction= new Quaternion(itemHands.Arm.Rotation.x, itemHands.Arm.Rotation.y, itemHands.Arm.Rotation.z, itemHands.Arm.Rotation.w);
                    
    
                    Pos_Left.Add(LeftHand.Wrist);
                    Pos_Left.Add(LeftHand.Palm);
                    Pos_Left.Add(LeftHand.Arm.WristPosition);
                    Pos_Left.Add(LeftHand.Arm.ElbowPosition);
                    
                    foreach (var itemFingers in itemHands.Fingers)//五个手指,itemHands.Fingers[0]代表大拇指
                    {
                        foreach (var itemBones in itemFingers.bones)//骨头的四个骨关节,NextJoint代表靠近指尖的部分,
                                                                    //PrevJoint代表靠近手腕的位置
                        {
                            LeftHand.Finger.Bone.PrevJoint = new Vector3(itemBones.PrevJoint.x, itemBones.PrevJoint.y, itemBones.PrevJoint.z);
                            LeftHand.Finger.Bone.NextJoint = new Vector3(itemBones.NextJoint.x, itemBones.NextJoint.y, itemBones.NextJoint.z);
                            Pos_Left.Add(LeftHand.Finger.Bone.PrevJoint);
                            Pos_Left.Add(LeftHand.Finger.Bone.NextJoint);
                        }
                    }
    
                    numL++;
                }
                if (itemHands.IsRight)
                {
                    RightHand.Wrist = new Vector3(itemHands.WristPosition.x, itemHands.WristPosition.y, itemHands.WristPosition.z);
                    RightHand.Palm = new Vector3(itemHands.PalmPosition.x, itemHands.PalmPosition.y, itemHands.PalmPosition.z);
                    RightHand.Arm.WristPosition = new Vector3(itemHands.Arm.NextJoint.x, itemHands.Arm.NextJoint.y, itemHands.Arm.NextJoint.z);
                    RightHand.Arm.ElbowPosition = new Vector3(itemHands.Arm.PrevJoint.x, itemHands.Arm.PrevJoint.y, itemHands.Arm.PrevJoint.z);
                    RightHand.Arm.Direction = new Quaternion(itemHands.Arm.Rotation.x, itemHands.Arm.Rotation.y, itemHands.Arm.Rotation.z, itemHands.Arm.Rotation.w);
    
                    Pos_Right.Add(RightHand.Wrist);
                    Pos_Right.Add(RightHand.Palm);
                    Pos_Right.Add(RightHand.Arm.WristPosition);
                    Pos_Right.Add(RightHand.Arm.ElbowPosition);
                    foreach (var itemFingers in itemHands.Fingers)
                    {
                        foreach (var itemBones in itemFingers.bones)
                        {
                            RightHand.Finger.Bone.PrevJoint = new Vector3(itemBones.PrevJoint.x, itemBones.PrevJoint.y, itemBones.PrevJoint.z);
                            RightHand.Finger.Bone.NextJoint = new Vector3(itemBones.NextJoint.x, itemBones.NextJoint.y, itemBones.NextJoint.z);
                            Pos_Right.Add(RightHand.Finger.Bone.PrevJoint);
                            Pos_Right.Add(RightHand.Finger.Bone.NextJoint);
                        }
                    }
                    numR++;
                }
            }
        }
        public byte[] EncodeLeftToByteArray()//编码左手
        {
            int index = 0;
           
            byte[] qua_x = BitConverter.GetBytes((double)LeftHand.Arm.Direction.x);
            qua_x.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            byte[] qua_y = BitConverter.GetBytes((double)LeftHand.Arm.Direction.y);
            qua_y.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            byte[] qua_z = BitConverter.GetBytes((double)LeftHand.Arm.Direction.z);
            qua_z.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            byte[] qua_w = BitConverter.GetBytes((double)LeftHand.Arm.Direction.w);
            qua_w.CopyTo(currentFrameLeft, index);
    
            index += sizeof(double);
            for (int i = 0; i < 44; i++)
            {
            byte[] pos_x = BitConverter.GetBytes((double)Pos_Left[i].x);
            pos_x.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            byte[] pos_y = BitConverter.GetBytes((double)Pos_Left[i].y);
            pos_y.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            byte[] pos_z = BitConverter.GetBytes((double)Pos_Left[i].z);
            pos_z.CopyTo(currentFrameLeft, index);
            index += sizeof(double);
            }
            return currentFrameLeft;
        }
        public byte[] EncodeRightToByteArray()//编码右手
        {
            int index = 0;
    
            byte[] qua_x = BitConverter.GetBytes((double)RightHand.Arm.Direction.x);
            qua_x.CopyTo(currentFrameRight, index);
            index += sizeof(double);
            byte[] qua_y = BitConverter.GetBytes((double)RightHand.Arm.Direction.y);
            qua_y.CopyTo(currentFrameRight, index);
            index += sizeof(double);
            byte[] qua_z = BitConverter.GetBytes((double)RightHand.Arm.Direction.z);
            qua_z.CopyTo(currentFrameRight, index);
            index += sizeof(double);
            byte[] qua_w = BitConverter.GetBytes((double)RightHand.Arm.Direction.w);
            qua_w.CopyTo(currentFrameRight, index);
    
            index += sizeof(double);
            for (int i = 0; i < 44; i++)
            {
                byte[] pos_x = BitConverter.GetBytes((double)Pos_Right[i].x);
                pos_x.CopyTo(currentFrameRight, index);
                index += sizeof(double);
                byte[] pos_y = BitConverter.GetBytes((double)Pos_Right[i].y);
                pos_y.CopyTo(currentFrameRight, index);
                index += sizeof(double);
                byte[] pos_z = BitConverter.GetBytes((double)Pos_Right[i].z);
                pos_z.CopyTo(currentFrameRight, index);
                index += sizeof(double);
            }
            return currentFrameRight;
        }
    }
    

    2, 远程接收字节码后,解析并赋给自己绘制的手势

     

    using System;
    using UnityEngine;
    using PersonShare;
    using System.IO;
    using System.Collections;
    
    class RemoteHands : MonoBehaviour
    {
        private const int leapHandLen = 44 * 3 * sizeof(double) + 4 * sizeof(double);
        public int HandID;
        public byte[] remoteFrameHands = new byte[2 * leapHandLen+sizeof(Int32)];
    
        private byte[] currentFramesLeft = new byte[leapHandLen];
        private byte[] currentFramesRight = new byte[leapHandLen];
    
        public RemoteHand Hand = new RemoteHand();
        string Leftpath = "D:/Works/DEMO/Hands/Assets/StreamingAssets/LeftHand.bytes";
        string Rightpath = "D:/Works/DEMO/Hands/Assets/StreamingAssets/RightHand.bytes";
        public const int NUM_Wrist = 1;
        public const int NUM_Palm = 1;
        public const int NUM_BONES = 20;
        public const int NUM_JOINTS = 42;
        public const int NUM_META = 12;
        public const int NUM_ARM = 4;
    
        public GameObject[] L_Wrist = new GameObject[NUM_Wrist];
        public GameObject[] L_Palm = new GameObject[NUM_Palm];
        public GameObject[] L_Bones = new GameObject[NUM_BONES];
        public GameObject[] L_Joints = new GameObject[NUM_JOINTS];
        public GameObject[] L_Meta = new GameObject[NUM_META];
        public GameObject[] L_Arm = new GameObject[NUM_ARM];
    
        public GameObject[] R_Wrist = new GameObject[NUM_Wrist];
        public GameObject[] R_Palm = new GameObject[NUM_Palm];
        public GameObject[] R_Bones = new GameObject[NUM_BONES];
        public GameObject[] R_Joints = new GameObject[NUM_JOINTS];
        public GameObject[] R_Meta = new GameObject[NUM_META];
        public GameObject[] R_Arm = new GameObject[NUM_ARM];
        IEnumerator Loadlefthandbyte(string path)
        {
            WWW www = new WWW(path);
            yield return www;
            LoadRemoteLeftHand(www.bytes);
        }
        IEnumerator Loadrighthandbyte(string path)
        {
            WWW www = new WWW(path);
            yield return www;
            LoadRemoteRightHand(www.bytes);
        }
        private void LateUpdate()
        {
    
            Buffer.BlockCopy(remoteFrameHands,0, currentFramesLeft,0, leapHandLen);
            Buffer.BlockCopy(remoteFrameHands, leapHandLen, currentFramesRight, 0, leapHandLen);
            if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.L))
            {
                StartCoroutine(Loadlefthandbyte(Leftpath));
                Debug.Log("左手数据加载成功!");
            }
            else
            {
                LoadRemoteLeftHand(currentFramesLeft);
                //LoadRemoteLeftHand(LocalHands.currentFramesLeft);
    
            }
            if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.R))
            {
                StartCoroutine(Loadrighthandbyte(Rightpath));
                Debug.Log("右手数据加载成功!");
            }
            else
            {
                //LoadRemoteRightHand(LocalHands.currentFramesRight);
                LoadRemoteRightHand(currentFramesRight);
            }
            AddDataToJoins();
        }
        private void AddDataToJoins()
        {
            #region LeftHand
            #region Thumb
            BoneLenth(L_Joints[0], L_Joints[0], L_Bones[0]);
            BoneLenth(L_Joints[1], L_Joints[3], L_Bones[1]);
            BoneLenth(L_Joints[3], L_Joints[5], L_Bones[2]);
            BoneLenth(L_Joints[5], L_Joints[7], L_Bones[3]);
            #endregion
    
            #region Index
            BoneLenth(L_Joints[0], L_Joints[9], L_Bones[4]);
            BoneLenth(L_Joints[9], L_Joints[11], L_Bones[5]);
            BoneLenth(L_Joints[11], L_Joints[13], L_Bones[6]);
            BoneLenth(L_Joints[13], L_Joints[15], L_Bones[7]);
            #endregion
    
            #region Middle
            BoneLenth(L_Joints[16], L_Joints[17], L_Bones[8]);
            BoneLenth(L_Joints[17], L_Joints[19], L_Bones[9]);
            BoneLenth(L_Joints[19], L_Joints[21], L_Bones[10]);
            BoneLenth(L_Joints[21], L_Joints[23], L_Bones[11]);
            #endregion
    
            #region Ring
            BoneLenth(L_Joints[24], L_Joints[25], L_Bones[12]);
            BoneLenth(L_Joints[25], L_Joints[27], L_Bones[13]);
            BoneLenth(L_Joints[27], L_Joints[29], L_Bones[14]);
            BoneLenth(L_Joints[29], L_Joints[31], L_Bones[15]);
            #endregion
    
            #region Pinky
            BoneLenth(L_Joints[32], L_Joints[33], L_Bones[16]);
            BoneLenth(L_Joints[33], L_Joints[35], L_Bones[17]);
            BoneLenth(L_Joints[35], L_Joints[37], L_Bones[18]);
            BoneLenth(L_Joints[27], L_Joints[29], L_Bones[19]);
            #endregion
    
            #region Palm
            BoneLenth(L_Joints[0], L_Joints[8], L_Meta[0]);
            BoneLenth(L_Joints[8], L_Joints[16], L_Meta[1]);
            BoneLenth(L_Joints[16], L_Joints[24], L_Meta[2]);
            BoneLenth(L_Joints[24], L_Joints[32], L_Meta[3]);
            BoneLenth(L_Joints[9], L_Joints[17], L_Meta[4]);
            BoneLenth(L_Joints[17], L_Joints[25], L_Meta[5]);
            BoneLenth(L_Joints[25], L_Joints[33], L_Meta[6]);
            BoneLenth(L_Joints[0], L_Joints[32], L_Meta[7]);
            #endregion
    
            #region Arm
            BoneLenth(L_Arm[0], L_Arm[1], L_Meta[8]);
            BoneLenth(L_Arm[0], L_Arm[2], L_Meta[10]);
            BoneLenth(L_Arm[2], L_Arm[3], L_Meta[9]);
            BoneLenth(L_Arm[1], L_Arm[3], L_Meta[11]);
            #endregion
    
            #endregion
    
            #region RightHand
            #region Thumb
            BoneLenth(R_Joints[0], R_Joints[0], R_Bones[0]);
            BoneLenth(R_Joints[1], R_Joints[3], R_Bones[1]);
            BoneLenth(R_Joints[3], R_Joints[5], R_Bones[2]);
            BoneLenth(R_Joints[5], R_Joints[7], R_Bones[3]);
            #endregion
    
            #region Index
            BoneLenth(R_Joints[0], R_Joints[9], R_Bones[4]);
            BoneLenth(R_Joints[9], R_Joints[11], R_Bones[5]);
            BoneLenth(R_Joints[11], R_Joints[13], R_Bones[6]);
            BoneLenth(R_Joints[13], R_Joints[15], R_Bones[7]);
            #endregion
    
            #region Middle
            BoneLenth(R_Joints[16], R_Joints[17], R_Bones[8]);
            BoneLenth(R_Joints[17], R_Joints[19], R_Bones[9]);
            BoneLenth(R_Joints[19], R_Joints[21], R_Bones[10]);
            BoneLenth(R_Joints[21], R_Joints[23], R_Bones[11]);
            #endregion
    
            #region Ring
            BoneLenth(R_Joints[24], R_Joints[25], R_Bones[12]);
            BoneLenth(R_Joints[25], R_Joints[27], R_Bones[13]);
            BoneLenth(R_Joints[27], R_Joints[29], R_Bones[14]);
            BoneLenth(R_Joints[29], R_Joints[31], R_Bones[15]);
            #endregion
    
            #region Pinky
            BoneLenth(R_Joints[32], R_Joints[33], R_Bones[16]);
            BoneLenth(R_Joints[33], R_Joints[35], R_Bones[17]);
            BoneLenth(R_Joints[35], R_Joints[37], R_Bones[18]);
            BoneLenth(R_Joints[27], R_Joints[29], R_Bones[19]);
            #endregion
    
            #region Palm
            BoneLenth(R_Joints[0], R_Joints[8], R_Meta[0]);
            BoneLenth(R_Joints[8], R_Joints[16], R_Meta[1]);
            BoneLenth(R_Joints[16], R_Joints[24], R_Meta[2]);
            BoneLenth(R_Joints[24], R_Joints[32], R_Meta[3]);
            BoneLenth(R_Joints[9], R_Joints[17], R_Meta[4]);
            BoneLenth(R_Joints[17], R_Joints[25], R_Meta[5]);
            BoneLenth(R_Joints[25], R_Joints[33], R_Meta[6]);
            BoneLenth(R_Joints[0], R_Joints[32], R_Meta[7]);
            #endregion
    
            #region Arm
            BoneLenth(R_Arm[0], R_Arm[1], R_Meta[8]);
            BoneLenth(R_Arm[0], R_Arm[2], R_Meta[10]);
            BoneLenth(R_Arm[2], R_Arm[3], R_Meta[9]);
            BoneLenth(R_Arm[1], R_Arm[3], R_Meta[11]);
            #endregion
    
            #endregion
        }
        private void BoneLenth(GameObject J0, GameObject J1, GameObject Bone)
        {
            Vector3 from = new Vector3(0.0f, 1.0f, 0.0f);//开始轴线的方向
            Vector3 to = (J0.transform.position - J1.transform.position);//读取轴线的方向
            Vector3 zhou = Vector3.Cross(from, to);//两个向量的叉积
            float angle = Vector3.Angle(from, to);//默认夹角为0-180
            // b 到 a 的夹角
            float sign = Mathf.Sign(Vector3.Dot(zhou.normalized, Vector3.Cross(to.normalized, from.normalized)));//判断夹角的正负
            float signed_angle = angle * sign;
            Bone.transform.rotation = Quaternion.AngleAxis(angle, zhou);
            double distance = (Vector3.Distance(J0.transform.position, J1.transform.position)) / 2.0;
            float Dis = (float)distance;
            Bone.transform.localScale
                = new Vector3(Bone.transform.localScale.x, Dis, Bone.transform.localScale.z);
            Bone.transform.position = (J0.transform.position + J1.transform.position) / 2;
        }
        private void LoadRemoteLeftHand(byte[] frame)//左手解码,赋值
        {
            int index = 0;
    
            Hand.Arm.Direction.x= (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.z = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.w = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            
            Hand.Wrist.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Wrist.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Wrist.z = (float)BitConverter.ToDouble(frame, index);
            L_Wrist[0].transform.position = new Vector3(Hand.Wrist.x, Hand.Wrist.y, Hand.Wrist.z);
    
            index += sizeof(double);
            Hand.Palm.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Palm.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Palm.z = (float)BitConverter.ToDouble(frame, index);
            L_Palm[0].transform.position = new Vector3(Hand.Palm.x, Hand.Palm.y, Hand.Palm.z);
    
            index += sizeof(double);
            Hand.Arm.WristPosition.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.WristPosition.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.WristPosition.z = (float)BitConverter.ToDouble(frame, index);
            L_Joints[40].transform.position = new Vector3(Hand.Arm.WristPosition.x, Hand.Arm.WristPosition.y, Hand.Arm.WristPosition.z);
            L_Joints[40].transform.rotation = new Quaternion(Hand.Arm.Direction.x, Hand.Arm.Direction.y, Hand.Arm.Direction.z, Hand.Arm.Direction.w);
    
            index += sizeof(double);
            Hand.Arm.ElbowPosition.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.ElbowPosition.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.ElbowPosition.z = (float)BitConverter.ToDouble(frame, index);
            L_Joints[41].transform.position = new Vector3(Hand.Arm.ElbowPosition.x, Hand.Arm.ElbowPosition.y, Hand.Arm.ElbowPosition.z);
            L_Joints[41].transform.rotation = new Quaternion(Hand.Arm.Direction.x, Hand.Arm.Direction.y, Hand.Arm.Direction.z, Hand.Arm.Direction.w);
    
            for (int i = 0; i < 40; i++)
            {
            float point_x=0, point_y=0, point_z=0;
    
            index += sizeof(double);
            point_x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            point_y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            point_z = (float)BitConverter.ToDouble(frame, index);
            L_Joints[i].transform.position = new Vector3(point_x, point_y, point_z);
            }
        }
        private void LoadRemoteRightHand(byte[] frame)//右手解码,赋值
        {
            int index = 0;
    
            Hand.Arm.Direction.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.z = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.Direction.w = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
    
            Hand.Wrist.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Wrist.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Wrist.z = (float)BitConverter.ToDouble(frame, index);
            R_Wrist[0].transform.position = new Vector3(Hand.Wrist.x, Hand.Wrist.y, Hand.Wrist.z);
    
            index += sizeof(double);
            Hand.Palm.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Palm.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Palm.z = (float)BitConverter.ToDouble(frame, index);
            R_Palm[0].transform.position = new Vector3(Hand.Palm.x, Hand.Palm.y, Hand.Palm.z);
    
            index += sizeof(double);
            Hand.Arm.WristPosition.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.WristPosition.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.WristPosition.z = (float)BitConverter.ToDouble(frame, index);
            R_Joints[40].transform.position = new Vector3(Hand.Arm.WristPosition.x, Hand.Arm.WristPosition.y, Hand.Arm.WristPosition.z);
            R_Joints[40].transform.rotation = new Quaternion(Hand.Arm.Direction.x, Hand.Arm.Direction.y, Hand.Arm.Direction.z, Hand.Arm.Direction.w);
    
            index += sizeof(double);
            Hand.Arm.ElbowPosition.x = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.ElbowPosition.y = (float)BitConverter.ToDouble(frame, index);
            index += sizeof(double);
            Hand.Arm.ElbowPosition.z = (float)BitConverter.ToDouble(frame, index);
            R_Joints[41].transform.position = new Vector3(Hand.Arm.ElbowPosition.x, Hand.Arm.ElbowPosition.y, Hand.Arm.ElbowPosition.z);
            R_Joints[41].transform.rotation = new Quaternion(Hand.Arm.Direction.x, Hand.Arm.Direction.y, Hand.Arm.Direction.z, Hand.Arm.Direction.w);
    
            for (int i = 0; i < 40; i++)
            {
                float point_x = 0, point_y = 0, point_z = 0;
    
                index += sizeof(double);
                point_x = (float)BitConverter.ToDouble(frame, index);
                index += sizeof(double);
                point_y = (float)BitConverter.ToDouble(frame, index);
                index += sizeof(double);
                point_z = (float)BitConverter.ToDouble(frame, index);
                R_Joints[i].transform.position = new Vector3(point_x, point_y, point_z);
            }
        }
    }

    手势一个关节一个小球,中间用杆相连。

    以上完成了手势数据的共享,但在远程端需要自己建手的三维模型

    分为两步,一个是各关节点,一个是关节点的连杆。

    两个关节点构成中间的连杆,连杆的

     

    展开全文
  • 手势。。。

    2019-07-28 04:53:13
    UITouch 1.UITouch *touch = [touches anyObject];//找到触摸事件 if([touch.view isKindOfClass:[UIImageView class]]){ CGPoint point = [touch locationInView:self.view];//找到点击事件在self.view里的......

    UITouch

    1.UITouch *touch = [touches anyObject];//找到触摸事件

       if([touch.view isKindOfClass:[UIImageView class]]){

                  CGPoint point = [touch locationInView:self.view];//找到点击事件在self.view里的坐标

                  CGFloat xMove = point.x - _recordPoint.x;

                  CGFloat yMove = point.y - _recordPoint.y;//计算运动轨迹

          touch.view.center = CGPointMake(touch.view.center.x +xMove,touch.view.center.y + yMove);//根据运动轨迹移动到点击到的视图

          _recordPoint = [touch locationInView:self.view];//每次移动以后都修改记录

    2.根据点击的次数来监听

       - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

         {

                UITouch *touch = [touches anyObject];
        
                    NSLog(@"====%ld",touch.tapCount);
                   //连续点击的次数
        
                     if ([touch.view isKindOfClass:[UIImageView class]]) {
                    if (touch.tapCount == 2) {
                CGRect rect = touch.view.frame;
                rect.origin.x -= 5;
                rect.size.width += 10;
                touch.view.frame = rect;
                //修改frame
            }
        }
    }

     

    各种手势

    1.点击手势(类似于btn的点击)

           UITapGestureRecognizer *tapGR = [[UITapgestureRecognizer alloc] initWithTarget:self action:@selector(tapGR:)];

           [view addGestureRecognizer:tapGR];

           - (void)tapGR:(UITapGestureRecognizer *)tapGR

             {

                [self.view bringSubViewToFront:tapGR.view];//将手势对应的view移到最上层

             }

    2.移动手势

            UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGR:)];

            [view addGestureRecognizer:panGR];

     1 - (void)panGR:(UIPanGestureRecognizer *)panGR
     2 {
     3     CGPoint translation = [panGR translationInView:self.view];
     4     //获取手势移动的轨迹
     5     
     6     panGR.view.center = CGPointMake(panGR.view.center.x + translation.x, panGR.view.center.y + translation.y);
     7     //根据手势的轨迹移动view
     8     
     9     [panGR setTranslation:CGPointZero inView:self.view];
    10     //每次移动以后都清空手势记录的轨迹
    11 }

     

           

    3.捏合手势

            UIPinchGestureRecognizer *pinchGR = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGR:)];
             [view addGestureRecognizer:pinchGR];

       

    1 - (void)pinchGR:(UIPinchGestureRecognizer *)pinchGR
    2 {
    3     pinchGR.view.transform = CGAffineTransformScale(pinchGR.view.transform, pinchGR.scale, pinchGR.scale);
    4     //让view随着手势的缩放而缩放
    5     
    6     pinchGR.scale = 1;
    7     //缩放以后需要还原手势中记录的倍数
    8 }

     

    4.旋转手势

            UIRotationGestureRecognizer *rotationGR = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGR:)];
        [view addGestureRecognizer:rotationGR];

     

    1 - (void)rotationGR:(UIRotationGestureRecognizer *)rotationGR
    2 {
    3     rotationGR.view.transform = CGAffineTransformRotate(rotationGR.view.transform, rotationGR.rotation);
    4     //让view随着手势的旋转而旋转
    5     
    6     rotationGR.rotation = 0;
    7     //旋转以后还原记录
    8 }

     

    5.长按手势

           UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGR:)];
        [view addGestureRecognizer:longGR];

       

     1 - (void)longGR:(UILongPressGestureRecognizer *)longGR
     2 {
     3     NSLog(@"===%ld",longGR.state);
     4     //打印手势的状态(开始响应,改变,结束响应)
     5     
     6     if (longGR.state == UIGestureRecognizerStateBegan) {
     7         //长按手势开始响应时触发
     8         
     9         CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    10         //创建一个基础动画
    11         
    12         basicAnimation.fromValue = [NSNumber numberWithFloat:0.5];
    13         basicAnimation.toValue = @2;
    14         //从哪里来,到哪里去
    15         
    16         basicAnimation.autoreverses = YES;
    17         //是否以动画方式返回
    18         
    19         basicAnimation.duration = 0.1;
    20         //单次动画时间
    21         
    22         basicAnimation.repeatCount = 99;
    23         //重复次数
    24         
    25         [longGR.view.layer addAnimation:basicAnimation forKey:@"aa"];
    26         //添加动画
    27     }
    28 }

     

    6.轻扫手势(和移动手势有冲突)

            UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGR:)];
            //轻扫手势(和pan移动有冲突的)
             swipeGR.direction = UISwipeGestureRecognizerDirectionUp;
            //设置轻扫的方向
             [view addGestureRecognizer:swipeGR];

            如果想实现多个方向的轻扫手势,需要创建多个,然后设置不同的方向。。。。。

           

     1 - (void)swipeGR:(UISwipeGestureRecognizer *)swipeGR
     2 {
     3     CGRect rect = swipeGR.view.frame;
     4     
     5     //判断方向
     6     if (swipeGR.direction == UISwipeGestureRecognizerDirectionUp) {
     7         rect.origin.y -= 5;
     8         rect.size.height += 5;
     9     }
    10     
    11     //& 按位与判断(这种用法只能是枚举值后面有1<<2这种位操作的)
    12     if (swipeGR.direction & UISwipeGestureRecognizerDirectionLeft) {
    13         rect.origin.x -= 5;
    14         rect.size.width += 5;
    15     }
    16     
    17     swipeGR.view.frame = rect;
    18 }

     

    转载于:https://www.cnblogs.com/Angelone/p/4388209.html

    展开全文
  • 手势

    2017-07-10 20:39:23
    手势
  • iOS_手势的添加及使用

    2018-01-18 16:42:31
    代码以imageview为例,给imageview添加点击事件: //图片这种类型的view默认是没有点击事件的,所以要把用户交互的属性打开 _imageView.userInteractionEnabled = YES; ... UITapGestureRecognizer *click = [[UITap
  • 可穿戴手势识别控制器 2016年电子技术应用第7期  作者:徐军,刘春花,孟月霞,马静  摘 要: 随着可穿戴电子设备的发展,基于手势识别的人机交互技术已经成为研究热点。为减小可穿戴设备的体积...
  • iOS中手势的使用

    2016-05-27 20:46:35
    在iOS中添加手势比较简单,可以归纳为以下几个步骤: 创建对应的手势对象; 设置手势识别属性【可选】; 附加手势到指定的对象; 编写手势操作方法; 为了帮助大家理解,下面以一个图片查看程序演示一下上面几种...
  • 在写移动端页面的交互效果的时候,我么难免要接触一些复杂的手势,而不仅仅像pc端那样简单的鼠标事件。手势实际上是一种输入模式。我们现在在直观意义上理解的人机交互是指人与机器之间的互动方式,这种互动方式经历...
  • 七大手势

    2018-04-01 09:59:38
    在设置手势之前一定要将用户交互打开self.userInteractionEnabled = YES;若是在做相册的话 设置捏合以及旋转手势之后 想让其在切换之后恢复原样 要抓住切换图片这个时机 切换图片设置的时候一般是轻扫和轻拍 要设置...
  • 1、UIGestureRecognizer介绍 手势识别在iOS上非常重要,手势操作移动设备的重要特征,...手势识别UIGestureRecognizer类是个抽象类,下面的子类是具体的手势,开发这可以直接使用这些手势识别。 UITapGestureRecog...
  • 今天偶遇以github上gesturelock关于手势锁的一个例子(有兴趣的去搜索下看看),于是下载下来研究,无奈基本没有注释,代码上存在一些问题(当设置gravity=center_vertical无法进行手势选择,无意中发现的),于是借鉴...
  • 本文参考:...一个基于视觉手势识别系统的构成应包括:图像的采集,预处理,特征提取和选择,分类器的设计,以及手势识别。其流程大致如下: 其中有三个步骤是识别系统的关键,分别是预处理时手势的分
  • 这是我的本科毕设题目,刚开始接触机器学习这方面,感谢CSDN和GitHub上的大佬,...项目简介:基于Win10 + Python3.7的环境,利用Python的OpenCV、Sklearn和PyQt5等库搭建了一个较为完整的手势识别系统,用于识别日...
  • 本文对当今静态手势识别技术中的各种方法进行了详细的分析,并在此基础上,设计 并实现了一套可以进行实时识别的静态手势识别系统。本系统共分为四个模块:手势图像 捕捉、图像预处理、特征提取以及手势的分类识别。...
  • 本文将介绍一种直观的基于颜色和几何信息的手势识别的方法。当然这种方法并不是完美的,还有很多瑕疵。但是还是分享出来,供大家交流使用。 1 待解决的问题 本文的任务是设计一个手势识别系统。输入数据是包含有...
  • 一步步做一个数字手势识别APP   这篇博客主要基于我做的一个数字手势识别APP,具体分享下如何一步步训练一个卷积神经网络模型(CNN)模型,然后把模型集成到Android Studio中,开发一个数字手势识别APP。整个...
  • 上一结主要介绍了如何继承高德地图,以及地图的几种不同的显示方式,那么本节我们接着往下看,这一节主要介绍地图的手势交互功能,其中包括滑动手势(地图是否可以滑动)、缩放手势(是否可以通过手势放大缩小地图)...
  • 普适计算技术和可穿戴设备的快速发展为自然的手势识别技术提出了新的挑战:应能使用户尽可能摆脱对环境和输入设备的束缚,与环境进行自然而有效的手势交互。凌空手势(mid-air gestures)识别是应对新挑战的一类有效...
  • 前言随着 Hybrid 应用的丰富,HTML5 工程师们已经不满足于把桌面端体验简单移植到...基于此,我们可以做出自己的手势库。手势常用的 HTML5 手势可以分为两类,单点手势和两点手势。单点手势有 tap(单击),double
1 2 3 4 5 ... 20
收藏数 97,154
精华内容 38,861
热门标签
关键字:

手势