65.9K
CodeProject 正在变化。 阅读更多。
Home

扫描数据可视化:以逼真的雷达屏幕显示您的数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (5投票s)

2016 年 9 月 6 日

CPOL

4分钟阅读

viewsIcon

13631

downloadIcon

509

使用简单的代码绘制逼真的雷达屏幕。

Sample Image

引言

这是一个 Android 应用程序,用于使用用户的数据(例如来自传感器的数据)绘制雷达屏幕。 您可以使用此控件简单地绘制逼真的雷达屏幕。

此控件将显示三种数据,第一种是先前扫描阶段的数据,第二种是当前扫描阶段的数据,最后一种是先前值和当前值的平均值。 如果需要,它可以更改为控制形状,即具有 0~180 度操作范围的半圆屏幕或具有 0~360 度的全圆。

背景

在我的项目中构建移动机器人系统,我需要可视化来自传感器的数据。 同时,我在互联网上寻找类似的项目。 我发现的是 Larry 的主页 (http://luckylarry.co.uk) 但该示例对我没有用处,因为该程序是基于 PC 的代码,带有 processing (由非营利基金会开发的编译器)。 所以,我决定新开发一个基于 Android 系统的数据可视化程序,因为计划开发一个由移动设备远程控制的机器人系统。 但是,由于 Larry 的主页提供了很多帮助,我向 Larry 先生表示感谢。

Using the Code

此代码可简单地用于您的项目。 首先,将RadarView.java添加到您的项目。 然后,您编辑要显示的活动文件的资源文件。

定义

enum radarColor{LAY, PREVSWEEP,

CURSWEEP, AVRSWEEP}

这是用于设置扫描值的颜色的enum值。

void setDisplayColor(radarColor what,

int color)

颜色变量将通过Color.argb()设置,它具有 alpha、red、green、blue 的属性。

void setDrawMode(boolean bPreSweep,

boolean bCurSweep,boolean bAvrSweep)

这是三种数据的每个值是否可见的选项。
bPreSweep:启用或禁用先前的数据可视化
bCurSweep:启用或禁用当前的数据可视化
bAvrSweep:启用或禁用平均数据可视化 [平均值 = (先前数据+当前数据)/2]
void setHalfSweep(boolean ck) 如果输入变量为 true,则显示屏幕将为半圆,否则将为全圆。 半圆的显示数据范围为 0 到 180 度,全圆的显示数据范围为 0 到 360 度。
[input: true] 半圆模式
[input: false] 全圆模式
void setMaxDistance(int val) 此函数用于设置检测距离的最大指示值。
val:最大距离。
void setValue(int index, int val) 这是用于设置当前值的函数。
index:扫描角度,以度为单位
val:距离的检测值

Resource

在您的layout.xml文件中添加如下代码的资源。 您必须更改此包名称 (com.example.bskim)。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
	....
    tools:context="com.example.myradarctrlapp.MainActivity">

	
    <com.example.bskim.RadarView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/RadarView"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true">
	
</RelativeLayout>

实现

Sample Image Sample Image
                     全扫描                                      半扫描

RadarView 类 (RadarView.java)

扫描数据由从原点到传感点的实线描述。 线长是传感器和任何物体之间的距离,线的角度是从基线(x 轴)检测到的方向。
检测物体的扫描运动由扇形实现。

public class RadarView extends View {
	......

    void DrawDisplay(Canvas canvas, int radius, int centerx, int centery) {
        float x, y;
        boolean clockwise = false;

        float ratio = (float)radius/ (float)widthp*3.0f;
        int textsize = (int)(25.0* ratio);

        if ( (dectAngle - oldDectAngle) >= 0) {
            clockwise = false;
        } else {
            clockwise = true;
        }

        Paint paint=new Paint();
        paint.setStyle(Paint.Style.FILL_AND_STROKE);

        // previous sweep
        if(mbPrevSweep == true) {
            paint.setARGB(64, 0, 32, 0);
            Path path1st = new Path();
            path1st.reset();
            path1st.moveTo(centerx, centery);
            for (int i = 0; i < sweepAngle; i++) {
                x = centerx + (int) (Math.cos(Math.toRadians((-i))) * ((float) oldDistValue[i]));
                y = centery + (int) (Math.sin(Math.toRadians((-i))) * ((float) oldDistValue[i]));
                path1st.lineTo(x, y);
            }
            canvas.drawPath(path1st, paint);
        }

        // current sweep
        if(mbCurSweep == true) {
            paint.setARGB(128, 0, 200, 0);
            Path path2nd = new Path();
            path2nd.reset();
            path2nd.moveTo(centerx, centery);
            for (int i = 0; i < sweepAngle; i++) {
                x = centerx + (int) (Math.cos(Math.toRadians((-i))) * ((float) distValue[i]));
                y = centery + (int) (Math.sin(Math.toRadians((-i))) * ((float) distValue[i]));
                path2nd.lineTo(x, y);
            }
            canvas.drawPath(path2nd, paint);
        }

        // average
        if(mbAvrSweep == true) {
            paint.setStyle(Paint.Style.STROKE);
            paint.setARGB(255, 0, 0, 255);
            Path pathavg = new Path();
            pathavg.reset();
            pathavg.moveTo(centerx, centery);
            for (int i = 0; i < sweepAngle; i++) {
                x = centerx + (int) (Math.cos(Math.toRadians((-i))) * 
                ((float) ((distValue[i] + oldDistValue[i]) / 2)));
                y = centery + (int) (Math.sin(Math.toRadians((-i))) * 
                ((float) ((distValue[i] + oldDistValue[i]) / 2)));
                pathavg.lineTo(x, y);
            }
            canvas.drawPath(pathavg, paint);
        }

        //sweep motion
        if(mbSweepMotion==true) {
            //sweep motion
            paint.setAntiAlias(true);
            paint.setStrokeWidth(7);

            int gradationAngle = 30;
            if(dectAngle < gradationAngle) gradationAngle = dectAngle;
            if(dectAngle> (sweepAngle-gradationAngle)) gradationAngle = sweepAngle-dectAngle;
            //scan motion drawing
            if (clockwise == false) {
                for (int i = gradationAngle; i >= 0; i--) {
                    if(i==0)
                        paint.setColor(mLayColor);
                    else paint.setARGB(128, 150+(100/gradationAngle * i), 
                    150+(100/gradationAngle * i), 150+(100/gradationAngle * i));
                    canvas.drawLine(centerx, centery, centerx + 
                    (int)(Math.cos(Math.toRadians(-dectAngle + (i))) * 
                    (float)radius), centery + (int) (Math.sin(Math.toRadians(-dectAngle + (i))) * 
                    (float)radius), paint);
                }
            } else {
                for (int i = 0; i <= gradationAngle; i++) {
                    if(i==0)
                        paint.setColor(mLayColor);
                    else paint.setARGB(128, 150+(100/gradationAngle * i), 
                    150+(100/gradationAngle * i), 150+(100/gradationAngle * i));
                    canvas.drawLine(centerx, centery, centerx + 
                    (int) (Math.cos(Math.toRadians(-dectAngle + (-i))) * (float) radius), 
                    centery + (int) (Math.sin(Math.toRadians(-dectAngle + (-i))) * 
                    (float) radius), paint);
                }
            }
        }

		......

    }
}

通过更改扫描方向,扫描运动的阴影方向将发生变化。

Sample Image

顺时针扫描 (180o,179o,....,2o,1o,0o)                     逆时针扫描 (0o,1o,2o,....,179o,180o)

创建视图和此用法的示例

创建RadarView的对象实例并配置其属性。
例如,全圆模式,扫描线颜色为绿色。 扫描距离范围由常量值MAX_DISTANCE设置,我们可以使用findViewById()从预定义的 XML 文件中获取资源。 R.id.RadarViewlayout.xml中定义为android:id="@+id/RadarView"

    RadarView mRadarView;

    mRadarView = (RadarView) findViewById(R.id.RadarView);
    mRadarView.setHalfSweep(false);
    mRadarView.setDisplayColor(RadarView.radarColor.LAY, Color.argb(255,0,255,0));
    mRadarView.setMaxDistance(MAX_DISTANCE);
    mRadarView.setSweepMotion(true);

以下代码显示了此类的用法。 要绘制的数据缓冲区由setValue(..)填充,并且使用处理程序,以便安全地更新视图。

    TimerTask mTask;
    Timer mTimer;
	
    mTask = new TimerTask() {
        @Override
        public void run() {
            if(mRadarView.isHalfMode()==true) {
                if (angle > 180) flag = 0;
                if (angle <= 0) flag = 1;
                if (flag == 0) angle--;
                else angle++;
            }else {
                if(angle>360) angle = 0;
                else angle++;
            }
            int distance = mRandVal.nextInt(MAX_DISTANCE);
			
            mRadarView.setValue(angle, distance);
            RadarViewInvalidate();
			
        }
    };
    mTimer = new Timer();
    mTimer.schedule(mTask, 500, 100);    //every 100ms after 500ms.

在使用setValue(..)从传感器输入新数据后,应调用RadaViewInvalidate()以更新视图。

    Handler mDrawHandler = new Handler();
	
    private void RadarViewInvalidate() {
        mDrawHandler.post(new Runnable() {
            @Override
            public void run() {
                mRadarView.invalidate();
            }
        });
    }

就是这样!我希望你能轻松地理解我。 感谢大家阅读本文。

关注点

我想注意创建一个新的图形视图类和一个资源。

历史

本文将很快更新。

© . All rights reserved.