转载请注明来自于:http://blog.csdn.net/strangenightmare/article/details/52885058
之前无聊同事和我讨论关于手机上如何实现手势画圆这个功能。我就也突然来了兴趣。今天上班正好闲着,就实现一下嘛。改天就研究下三角形怎么实现。嘿嘿。
我的思路主要是这样:首先记录下开始点的坐标A,然后计算这个点距离所有手指移动过的点的距离(当然是利用距离公式啦)。距离A点最远的当然是直径了。然后记录距离A点最远的点C,利用中点公式计算出中心点B。这样确定了原点和半径radius,只需要取手势划过的点和中心B点的距离和半径radius对比就好了。完全重合当然不可能啦。毕竟是手画的。我就取了差值在15以下认为是圆,这个可以根据需求后期调整,是否要精确一个圆。然后目标取样个数点我取了手指划过点的15-30个作为取样(手指停留越短,取样点越多)。
缺点:无法识别圆弧,半圆,和圆的关系。这个应该优化一下,通过周长公式就可以搞定。我是懒得弄啦。
Demo样式:
下面是核心代码部分,具体需要Demo的可以去我的git仓库下载来看效果。git仓库地址:git@git.oschina.net:coolnan/Finger_Cycle.git
package com.test.xiaonanfingercycle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by playcrab on 16/10/20.
*/
public class MainActivity extends AppCompatActivity {
private static final float RADIUS_OFFSET = 15.0f; //半径取样偏移值
private static Point first_point;
private static Point far_point;
private static Point center_point;
private float distance;
private List<Point> points;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) this.findViewById(R.id.tv);
points = new ArrayList<Point>();
}
/**
*
* @param event
* @return true
* 触摸事件拦截
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
tv.setText("");
far_point = null;
distance = 0.0f;
first_point = new Point(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
Point pt = new Point(event.getX(),event.getY());
float temp = getDistance(first_point,pt);
if(distance <= temp){
distance = temp;
far_point = new Point(pt.getPositionX(),pt.getPositionY());
}
points.add(pt);
break;
case MotionEvent.ACTION_UP:
center_point = new Point((first_point.getPositionX()+far_point.getPositionX())/2,(first_point.getPositionY()+far_point.getPositionY())/2);
boolean cycle = isCycle(center_point,points);
tv.setText(tv.getText().toString()+"\n"+"是否划圆:"+ cycle);
break;
}
return true;
}
/**
*
* @param A
* @param B
* @return distance
* 计算两点之间距离
*/
private float getDistance(Point A,Point B){
float dis = (A.getPositionX()-B.getPositionX())*(A.getPositionX()-B.getPositionX())+(A.getPositionY()-B.getPositionY())*(A.getPositionY()-B.getPositionY());
return (float) Math.sqrt(dis);
}
/**
*
* @param ct_point
* @param p
* @return 是否为圆
* 计算圆心到散列点之间的距离
*/
private boolean isCycle(Point ct_point,List<Point> p){
boolean isCycle = false;
int size = p.size();
if(size >30){
size = size/2;
}
int not_cycle =0,is_cycle = 0;
for(int i=0;i<size;i++){
Point tmp = p.get(i);
float radiu = getDistance(ct_point,tmp);
if(Math.abs(distance/2-radiu)<=RADIUS_OFFSET){
is_cycle++;
}else{
not_cycle++;
}
tv.setText("半径:"+distance/2+" 半径差值:"+Math.abs(distance/2-radiu)+" 取样点个数:"+size+" 达到半径:"+is_cycle+" 不达半径:"+not_cycle);
}
if(not_cycle > is_cycle){
isCycle = false;
}else{
isCycle = true;
}
p.clear();
return isCycle;
}
}