搜索
您的当前位置:首页正文

仿小米指南针,实现电子罗盘

来源:好走旅游网

1、电子罗盘

项目需要,需要实现一个电子罗盘。现如今,手机传感器越来越灵敏,借助于手机实现电子罗盘,大大方便了野外工作人员。利用手机,可以实现岩层走向和倾向的测量,且精度也能得到一定的保证。利用方向传感器(之前使用的接口),现在换成磁场和加速度传感器联合求解三个方向,然后得到结构。

         //获取传感器
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mag_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        acc_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        //给传感器注册监听:
        sensorManager.registerListener(this, acc_sensor, SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, mag_sensor, SensorManager.SENSOR_DELAY_NORMAL);

 @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            accValues = event.values;
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magValues = event.values;
        }else if (event.sensor.getType() == Sensor.TYPE_PRESSURE) {
            preValues = event.values;
        }

        SensorManager.getRotationMatrix(r, null, accValues, magValues);
        SensorManager.getOrientation(r, values);  //此处的values与方向传感器结果一致,
         //values[0] 手机的方位,正北为0°,顺时针180°为正,逆时针180°为负
        //values[1] 手机上下倾斜程度
        //values[2] 手机左右倾斜程度
    }

2、UI设计

一个好的UI展示,往往能受到大家的喜欢。要想完全自定义一个UI,完全超出了我一个小草鸟的能力,而且时间不够,于是百度搜索,发现大佬们早已经写好,自己只需要改动部分代码,然后传入自己的值就行。在这里,对***ChaosAlaska***表示感谢感谢感谢,另外贴出大佬的:https://www.jianshu.com/p/cee9b7c3abe8?utm_source=oschina-app

想要了解的可以自己去看看,写的很详细,再次感谢。

2、界面的代码和上文贴出的大佬的基本一致,就是刻度以及参数的传入自己进行了设置,这里就不贴出重复的了,只贴出不同的部分,希望给到有需要的人。

2.1 计算产状

   //传入 方向参数,数组的形式,上面获取到的
  public void setValues(float [] values){
        if(!isSave){
            this.values = values;
            val  = Math.round(values[0]*180.0/Math.PI);
            valStrike = Math.round(calculatedip(values));
            invalidate();
        }
    }
    //根据方向参数进行计算产状
      private float calculatedip(float[] values) {
        float caculated_dia, caculated_dip;
        float dip;
        double values0;
        caculated_dip = (float) Math.acos(1 /Math.sqrt(Math.tan(values[1]) *Math.tan(values[1]) +Math.tan(values[2]) *Math.tan(values[2]) +1));
        if(values[0] > 0)
            values0 = (double) values[0];
        else
            values0 = 2 *Math.PI +values[0];
        if(values[2] < 0)
            caculated_dia = (float) (values0 -Math.acos(Math.tan(values[1]) /Math.tan(caculated_dip)));
        else
            caculated_dia = (float) (values0 +Math.acos(Math.tan(values[1]) /Math.tan(caculated_dip)));
        if(caculated_dia < 0)
            while (caculated_dia < 0)
                caculated_dia += 2 *Math.PI;
        else if(caculated_dia > 2 *Math.PI)
            while (caculated_dia > 2 *Math.PI)
                caculated_dia -= 2 *Math.PI;
        float temp_dip = (float) Math.toDegrees(caculated_dip);
        this.dip = String.format("%.2f",temp_dip);
        caculated_dia = (float) Math.toDegrees(caculated_dia);
        return caculated_dia;
    }
    //按钮 ”测量“ 功能的实现
    public void setIsSave(boolean isSave){
        this.isSave = isSave;
    }

2.2 画产状线和倾向线

     //产状和倾向画笔的初始化以及产状数字画笔初始化
     mdiPaint = new Paint();
        mdiPaint.setStyle(Paint.Style.FILL);
        mdiPaint.setAntiAlias(true);
        mdiPaint.setColor(context.getResources().getColor(R.color.dip));

        mstrikePaint = new Paint();
        mstrikePaint.setStyle(Paint.Style.FILL);
        mstrikePaint.setAntiAlias(true);
        mstrikePaint.setColor(context.getResources().getColor(R.color.strike));

         mOccurrencePaint = new Paint();
        mOccurrencePaint.setStyle(Paint.Style.STROKE);
        mOccurrencePaint.setAntiAlias(true);
        mOccurrencePaint.setTextSize(50);
        mOccurrencePaint.setColor(context.getResources().getColor(R.color.white));
        //定义方法
          //画产状数字
        drawOccuroceText();
        //画走向
        drawStrikeLine();
        //画倾向线
        drawDipLine();

      //走向线
      /*
   因为走向线与倾向线始终垂直
   所以此时,我们将strke要旋转-valstrike-90度才能绘制出来
    */
    private void drawStrikeLine() {
        mCanvas.save();
        int mTriangleHeight=(mOutSideRadius-mCircumRadius)/2;
        mCanvas.rotate(valStrike+90-val,mCenterX,mOutSideRadius+mTextHeight);
        mstrikeTriangle.moveTo(width/2,mOutSideRadius+mTextHeight-mCircumRadius+20);
        //内接三角形的边长,简单数学运算
        float mTriangleSide = (float) ((mTriangleHeight/(Math.sqrt(3)))*2);
        mstrikeTriangle.lineTo(width/2-20,mOutSideRadius+mTextHeight);
        mstrikeTriangle.lineTo(width/2,mOutSideRadius+mTextHeight+mCircumRadius-20);
        mstrikeTriangle.lineTo(width/2+20,mOutSideRadius+mTextHeight);
        mstrikeTriangle.close();
        mCanvas.drawPath(mstrikeTriangle,mstrikePaint);
        mCanvas.restore();
    }
    //倾向线
    private void drawDipLine() {
        mCanvas.save();
        mCanvas.rotate(valStrike-val,mCenterX,mOutSideRadius+mTextHeight);
        mdipTriangle.moveTo(width/2,mOutSideRadius+mTextHeight-mCircumRadius+20);
        mdipTriangle.lineTo(width/2-20,mOutSideRadius+mTextHeight);
        mdipTriangle.lineTo(width/2+20,mOutSideRadius+mTextHeight);
        mdipTriangle.close();
        mCanvas.drawPath(mdipTriangle,mdiPaint);
        mCanvas.restore();
    }
    //产状示数
     private void drawOccuroceText() {
        String occurouce = "产状:"+ valStrike+"°"+ "∠"+ dip+"°";
        mOccurrencePaint.getTextBounds(occurouce,0,occurouce.length(),mOccuTextRect);
        int owidth = mOccuTextRect.width();
        int height = mOccuTextRect.height();
        mCanvas.drawText(occurouce,width/2-owidth,mTextHeight+mOutSideRadius*2+height*3,mOccurrencePaint);
    }

3、使用

像控件一样使用,初始化即可。

 //在布局里面设置
 <com.example.view.MyView
        android:id="@+id/miui"
        android:layout_gravity="center"
        android:background="@color/black"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
 //调用方法,传入参数即可
 miui.setValues(values);

因篇幅问题不能全部显示,请点此查看更多更全内容

Top