专栏首页腾讯位置服务腾讯位置服务GPS轨迹回放-安卓篇
原创

腾讯位置服务GPS轨迹回放-安卓篇

前言

当我们使用地图进行开发时,利用已经录制好的轨迹进行轨迹回放来检查导航的准确性是十分常用的手段,并且上一篇已经讲完了关于地图使用时GPS轨迹文件的录制,现在对于安卓系统下使用腾讯导航SDK进行轨迹回放做一个分享

前期准备

腾讯导航SDK依赖于腾讯地图SDK、腾讯定位SDK,具体权限的开通需要去lbs.qq.com 的官网控制台去操作,另外导航SDK的权限可以联系小助手咨询(如下图所示),这里就不多做探讨

16222560693250.jpg

轨迹回放正片

系统架构

16224265311888.jpg

GPS回放系统分成两部分:GPSPlaybackActivity 和 GPSPlaybackEngine。

GPSPlayback负责和外界的交互,主要是信息的传递和导航SDK的交互,而GPSPlaybackEngine负责具体的读取文件和将定位点通过多线程runnable机制灌入listener。

开始轨迹回放

BaseNaviActivity.java

baseNaviActivity 主要是对于导航SDK naviView部分的生命周期的管理,必须实现,否则不能进行导航!

/**
 * 导航 SDK {@link CarNaviView} 初始化与周期管理类。
 */
public abstract class BaseNaviActivity {

    private static Context mApplicationContext;

    protected CarNaviView mCarNaviView;

    // 建立了TencentCarNaviManager 单例模式,也可以直接调用TencentCarNaviManager来建立自己的carNaviManager
    public static final Singleton<TencentCarNaviManager> mCarManagerSingleton =
            new Singleton<TencentCarNaviManager>() {
                @Override
                protected TencentCarNaviManager create() {
                    return new TencentCarNaviManager(mApplicationContext);
                }
            };

    public static TencentCarNaviManager getCarNaviManager(Context appContext) {
        mApplicationContext = appContext;
        return mCarManagerSingleton.get();
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutID());
        super.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mApplicationContext = getApplicationContext();
        mCarNaviView = findViewById(R.id.tnk_car_navi_view);
        mCarManagerSingleton.get().addNaviView(mCarNaviView);
    }

    public int getLayoutID() {
        return R.layout.tnk_activity_navi_base;
    }

    protected View getCarNaviViewChaild() {
        final int count = mCarNaviView.getChildCount();
        if (0 >= count) {
            return mCarNaviView;
        }
        return mCarNaviView.getChildAt(count - 1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (!isDestoryMap()) {
            return;
        }
        mCarManagerSingleton.get().removeAllNaviViews();
        if (mCarNaviView != null) {
            mCarNaviView.onDestroy();
        }
//        mCarManagerSingleton.destory();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mCarNaviView != null) {
            mCarNaviView.onStart();
        }
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        if (mCarNaviView != null) {
            mCarNaviView.onRestart();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mCarNaviView != null) {
            mCarNaviView.onResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mCarNaviView != null) {
            mCarNaviView.onPause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mCarNaviView != null) {
            mCarNaviView.onStop();
        }
    }

    protected boolean isDestoryMap() {
        return true;
    }
}

GPSPlaybackActivity.java

这一部分主要是对于导航 SDK的交互和添加导航UI部分初始化工作。注意导航sdk一定要先算路,再开始导航。算路可以取得GPS文件的首行为起点,末行为终点。

用到的fields

    private static final String LOG_TAG = "[GpsPlayback]";

    // gps 文件路径
    private String mGpsTrackPath;
    // gps 轨迹的起终点
    private NaviPoi mFrom, mTo;

    // 是否是84坐标系
    private boolean isLocation84 = true;

因为在GPSPlaybackEngine已经进行了listener监听,所以需要对于导航SDK进行灌点

// 腾讯定位sdk的listener
    private TencentLocationListener listener = new TencentLocationListener() {
        @Override
        public void onLocationChanged(TencentLocation tencentLocation, int error, String reason) {
            if (error != TencentLocation.ERROR_OK || tencentLocation == null) {
                return;
            }
            Log.d(LOG_TAG, "onLocationChanged : "
                    + ", latitude" + tencentLocation.getLatitude()
                    + ", longitude: " + tencentLocation.getLongitude()
                    + ", provider: " + tencentLocation.getProvider()
                    + ", accuracy: " + tencentLocation.getAccuracy());

            // 将定位点灌入导航SDK
            // mCarManagerSingleton是使用导航SDK的carNaviManager创建的单例,开发者可以自己实现
            mCarManagerSingleton.get().updateLocation(ConvertHelper
                    .convertToGpsLocation(tencentLocation), error, reason);
        }

        @Override
        public void onStatusUpdate(String provider, int status, String description) {
            Log.d(LOG_TAG, "onStatusUpdate provider: " + provider
                    + ", status: " + status
                    + ", desc: " + description);

            // 更新GPS状态.
            mCarManagerSingleton.get().updateGpsStatus(provider, status, description);
        }
    };

onCreate方法初始化UI和添加callback

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 获取GPS文件轨迹路径,这里可以由开发者自己获取
        mGpsTrackPath = getIntent().getStringExtra("gpsTrackPath");
        if (mGpsTrackPath == null || mGpsTrackPath.isEmpty()) {
            return;
        }

        initUi();
        addTencentCallback();

        new Handler().post(() -> {
        
            // 目的获取每条轨迹的arraylist
            ArrayList<String> gpsLineStrs = readGpsFile(mGpsTrackPath);
            if (gpsLineStrs == null || gpsLineStrs.isEmpty()) {
                return;
            }
            // 获取起终点
            getFromAndTo(gpsLineStrs);
            if (mFrom == null || mTo == null) {
                return;
            }
            final Handler handlerUi = new Handler(Looper.getMainLooper());
            handlerUi.post(() -> searchAndStartNavigation());
        });

    }
    

private void initUi() {
        mCarManagerSingleton.get().setInternalTtsEnabled(true);

        final int margin = CommonUtils.dip2px(this, 36);
        // 全览模式的路线边距
        mCarNaviView.setVisibleRegionMargin(margin, margin, margin, margin);
        mCarNaviView.setAutoScaleEnabled(true);
        mCarManagerSingleton.get().setMulteRoutes(true);
        mCarNaviView.setNaviMapActionCallback(mCarManagerSingleton.get());

        // 使用默认UI
        CarNaviInfoPanel carNaviInfoPanel = mCarNaviView.showNaviInfoPanel();
        carNaviInfoPanel.setOnNaviInfoListener(() -> {
            mCarManagerSingleton.get().stopNavi();
            finish();
        });
        CarNaviInfoPanel.NaviInfoPanelConfig config = new CarNaviInfoPanel.NaviInfoPanelConfig();
        config.setRerouteViewEnable(true);             // 重算按钮
        carNaviInfoPanel.setNaviInfoPanelConfig(config);
    }

    private void addTencentCallback() {
        mCarManagerSingleton.get().addTencentNaviCallback(mTencentCallback);
    }
    
    private TencentNaviCallback mTencentCallback = new TencentNaviCallback() {
        @Override
        public void onStartNavi() { }

        @Override
        public void onStopNavi() { }

        @Override
        public void onOffRoute() { }

        @Override
        public void onRecalculateRouteSuccess(int recalculateType,
                                              ArrayList<RouteData> routeDataList) { }
        @Override
        public void onRecalculateRouteSuccessInFence(int recalculateType) { }

        @Override
        public void onRecalculateRouteFailure(int recalculateType,
                                              int errorCode, String errorMessage) { }

        @Override
        public void onRecalculateRouteStarted(int recalculateType) { }

        @Override
        public void onRecalculateRouteCanceled() { }

        @Override
        public int onVoiceBroadcast(NaviTts tts) {
            return 0;
        }

        @Override
        public void onArrivedDestination() { }

        @Override
        public void onPassedWayPoint(int passPointIndex) { }

        @Override
        public void onUpdateRoadType(int roadType) { }

        @Override
        public void onUpdateParallelRoadStatus(ParallelRoadStatus parallelRoadStatus) {

        }

        @Override
        public void onUpdateAttachedLocation(AttachedLocation location) { }

        @Override
        public void onFollowRouteClick(String routeId, ArrayList<LatLng> latLngArrayList) { }
    };

readGpsFile方法

private ArrayList<String> readGpsFile(String fileName) {
        ArrayList<String> gpsLineStrs = new ArrayList<>();
        BufferedReader reader = null;
        try {
            File file = new File(fileName);
            InputStream is = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(is));

            String line;
            while ((line = reader.readLine()) != null) {
                gpsLineStrs.add(line);
            }
            return gpsLineStrs;
        } catch (Exception e) {
            Log.e(LOG_TAG, "startMockTencentLocation Exception", e);
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                Log.e(LOG_TAG, "startMockTencentLocation Exception", e);
                e.printStackTrace();
            }
        }
        return null;
    }

getFromAndTo方法,获取起终点为进行算路

    private void getFromAndTo(ArrayList<String> gpsLineStrs) {
        final int size;
        if ((size = gpsLineStrs.size()) < 2) {
            return;
        }
        final String firstLine = gpsLineStrs.get(0);
        final String endLine = gpsLineStrs.get(size - 1);
        try {
            final String[] fromParts = firstLine.split(",");
            mFrom = new NaviPoi(Double.valueOf(fromParts[1]), Double.valueOf(fromParts[0]));
            final String[] endParts = endLine.split(",");
            mTo = new NaviPoi(Double.valueOf(endParts[1]), Double.valueOf(endParts[0]));
        } catch (Exception e) {
            mFrom = null;
            mTo = null;
        }
    }

算路searchAndStartNavigation()

可以使用导航SDK的算路方法并且获取算路成功和失败的回调


    private void searchAndStartNavigation() {
        mCarManagerSingleton.get()
                .searchRoute(new TencentRouteSearchCallback() {
                    @Override
                    public void onRouteSearchFailure(int i, String s) {
                        toast("路线规划失败");
                    }

                    @Override
                    public void onRouteSearchSuccess(ArrayList<RouteData> arrayList) {
                        if (arrayList == null || arrayList.isEmpty()) {
                            toast("未能召回路线");
                            return;
                        }
                        handleGpsPlayback();
                    }
                });
    }
    

调用GpsPlaybackEngine方法,进行listen定位,然后开始导航

    private void handleGpsPlayback() {

// 与GpsPlaybackEngine 进行交互, 添加locationListener
GpsPlaybackEngine.getInstance().addTencentLocationListener(listener);

//与GpsPlaybackEngine 进行交互,开始定位
        GpsPlaybackEngine.getInstance().startMockTencentLocation(mGpsTrackPath, isLocation84);
        try {
            mCarManagerSingleton.get().startNavi(0);
        } catch (Exception e) {
            toast(e.getMessage());
        }
    }

结束导航

    @Override
    protected void onDestroy() {
// 与GpsPlaybackEngine 进行交互, removelocationListener
mCarManagerSingleton.get().removeTencentNaviCallback(mTencentCallback);
//与GpsPlaybackEngine 进行交互,结束定位GpsPlaybackEngine.getInstance().removeTencentLocationListener(listener);
        GpsPlaybackEngine.getInstance().stopMockLocation();
        if (mCarManagerSingleton.get().isNavigating()) {
        // 结束导航
            mCarManagerSingleton.get().stopNavi();
        }
        super.onDestroy();
    }

GPSPlaybackEngine.java

这一部分主要是对于GPS文件进行读取并且提供外界可用的add/removelistener方法,start/stopMockLocation方法

因为要让engine运行在自己的线程,所以使用runnable机制

public class GpsPlaybackEngine implements Runnable{

            // 代码在下方
}

而使用到的fields

// Tencent轨迹Mock, TencentLocationListener需要利用腾讯定位SDK获取
private ArrayList<TencentLocationListener> mTencentLocationListeners = new ArrayList<>();
    
// 获取的location数据
private List<String> mDatas = new ArrayList<String>();
     
private boolean mIsReplaying = false;

private boolean mIsMockTencentLocation = true;

private Thread mMockGpsProviderTask = null;

// 是否已经暂停
private boolean mPause = false;

private double lastPointTime = 0;
private double sleepTime = 0;

关键方法

  • listener相关
    // 添加listener
    public void addTencentLocationListener(TencentLocationListener listener) {
        if (listener != null) {
            mTencentLocationListeners.add(listener);
        }
    }

    // 移除listener 
    public void removeTencentLocationListener(TencentLocationListener listener) {
        if (listener != null) {
            mTencentLocationListeners.remove(listener);
        }
    }
  • 开始/关闭模拟轨迹
    /*
     * 模拟轨迹
     * @param context
     * @param fileName 轨迹文件绝对路径
     */
    public void startMockTencentLocation(String fileName, boolean is84) {

       // 首先清除以前的data
        mDatas.clear();
        // 判断是否是84坐标系
        mIsMockTencentLocation = !is84;
        BufferedReader reader = null;
        try {
            File file = new File(fileName);
            InputStream is = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(is));

            String line;
            while ((line = reader.readLine()) != null) {
                mDatas.add(line);
            }
            if (mDatas.size() > 0) {
                mIsReplaying = true;
                synchronized (this) {
                    mPause = false;
                }
                // 开启异步线程
                mMockGpsProviderTask = new Thread(this);
                mMockGpsProviderTask.start();
            }
        } catch (Exception e) {
            Log.e(TAG, "startMockTencentLocation Exception", e);
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                Log.e(TAG, "startMockTencentLocation Exception", e);
                e.printStackTrace();
            }
        }
    }
    /**
     * 退出应用前也需要调用停止模拟位置,否则手机的正常GPS定位不会恢复
     */
    public void stopMockTencentLocation() {
        try {
            mIsReplaying = false;
            mMockGpsProviderTask.join();
            mMockGpsProviderTask = null;
            lastPointTime = 0;
        } catch (Exception e) {
            Log.e(TAG, "stopMockTencentLocation Exception", e);
            e.printStackTrace();
        }
    }
  • runnable相关
 @Override
    public void run() {
        for (String line : mDatas) {
            if (!mIsReplaying) {
                Log.e(TAG, "stop gps replay");
                break;
            }
            if (TextUtils.isEmpty(line)) {
                continue;
            }

            try {
                Thread.sleep(getSleepTime(line) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean mockResult;
            mockResult = mockTencentLocation(line);
            if (!mockResult) {
                break;
            }

            try {
                checkToPauseThread();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

使用到的private方法

private void checkToPauseThread() throws InterruptedException {
        synchronized (this) {
            while (mPause) {
                wait();
            }
        }
}

private int getSleepTime(String line) {
    try {
        String[] parts = line.split(",");
        double time = Double.valueOf(parts[6]);
        time = (int) Math.floor(time);
        if(lastPointTime != 0) {
            sleepTime = time  - lastPointTime; // 单位s,取整数
        }
        lastPointTime = time;
    }catch (Exception e) {
    
    }
    return (int)sleepTime;
}

private boolean mockTencentLocation(String line) {
    try {
        String[] parts = line.split(",");

        double latitude = Double.valueOf(parts[1]);
        double longitude = Double.valueOf(parts[0]);
        float accuracy = Float.valueOf(parts[2]);
        float bearing = Float.valueOf(parts[3]);
        float speed = Float.valueOf(parts[4]);
        double altitude = Double.valueOf(parts[7]);
        double time = Double.valueOf(parts[6]);

        String buildingId;
        String floorName;
        if (parts.length >= 10) {
            buildingId = parts[8];
            floorName = parts[9];
        } else {
            buildingId = "";
            floorName = "";
        }

        if (!mIsMockTencentLocation) {
            double[] result = CoordinateConverter.wgs84togcj02(longitude, latitude);
            longitude = result[0];
            latitude = result[1];
        }

        GpsPlaybackEngine.MyTencentLocation location = new GpsPlaybackEngine.MyTencentLocation();
        location.setProvider("gps");
        location.setLongitude(longitude);
        location.setLatitude(latitude);
        location.setAccuracy(accuracy);
        location.setDirection(bearing);
        location.setVelocity(speed);
        location.setAltitude(altitude);
        location.setBuildingId(buildingId);
        location.setFloorName(floorName);
        location.setRssi(4);
        location.setTime(System.currentTimeMillis());
//			location.setTime((long) time * 1000);

        for (TencentLocationListener listener : mTencentLocationListeners) {
            if (listener != null) {
                String curTime;
                if (location != null && location.getTime() != 0) {
                    long millisecond = location.getTime();
                    Date date = new Date(millisecond);
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss");
                    curTime = format.format(date);
                } else {
                    curTime = "null";
                }
                Log.e(TAG, "time : " + curTime
                        + ", longitude : " + longitude
                        + " , latitude : " + latitude);

                listener.onLocationChanged(location, 0, "");
                listener.onStatusUpdate(LocationManager.GPS_PROVIDER, mMockGpsStatus, "");
            }
        }
    } catch(Exception e) {
        Log.e(TAG, "Mock Location Exception", e);
        // 如果未开位置模拟,这里可能出异常
        e.printStackTrace();
        return false;
    }
    return true;
}

CoordinateConverter.wg84togcj02

	/**
	 * WGS84转GCJ02(火星坐标系)
	 * 
	 * @param lng WGS84坐标系的经度
	 * @param lat WGS84坐标系的纬度
	 * @return 火星坐标数组
	 */
	public static double[] wgs84togcj02(double lng, double lat) {
		if (out_of_china(lng, lat)) {
			return new double[] { lng, lat };
		}
		double dlat = transformlat(lng - 105.0, lat - 35.0);
		double dlng = transformlng(lng - 105.0, lat - 35.0);
		double radlat = lat / 180.0 * pi;
		double magic = Math.sin(radlat);
		magic = 1 - ee * magic * magic;
		double sqrtmagic = Math.sqrt(magic);
		dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi);
		dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * pi);
		double mglat = lat + dlat;
		double mglng = lng + dlng;
		return new double[] { mglng, mglat };
	}

内部类MyTencentLocation implements 定位sdk的接口

class MyTencentLocation implements TencentLocation {
        /**
         * 纬度
         */
        private double latitude = 0;
        /**
         * 经度
         */
        private double longitude = 0;
        /**
         * 精度
         */
        private float accuracy = 0;
        /**
         * gps方向
         */
        private float direction = -1;
        /**
         * 速度
         */
        private float velocity = 0;
        /**
         * 时间
         */
        private long time = 0;
        /**
         * 海拔高度
         */
        private double altitude = 0;
        /**
         * 定位来源
         */
        private String provider = "";
        /**
         * GPS信号等级
         */
        private int rssi = 0;

        /**
         * 手机的机头方向
         */
        private float phoneDirection = -1;

        private String buildingId = "";

        private String floorName = "";

        private  String fusionProvider = "";

        @Override
        public String getProvider() {
            return provider;
        }

        @Override
        public String getSourceProvider() {
            return null;
        }

        @Override
        public String getFusionProvider() {
            return fusionProvider;
        }

        @Override
        public String getCityPhoneCode() {
            return null;
        }

        @Override
        public double getLatitude() {
            return latitude;
        }

        @Override
        public double getLongitude() {
            return longitude;
        }

        @Override
        public double getAltitude() {
            return latitude;
        }

        @Override
        public float getAccuracy() {
            return accuracy;
        }

        @Override
        public String getName() {
            return null;
        }

        @Override
        public String getAddress() {
            return null;
        }

        @Override
        public String getNation() {
            return null;
        }

        @Override
        public String getProvince() {
            return null;
        }

        @Override
        public String getCity() {
            return null;
        }

        @Override
        public String getDistrict() {
            return null;
        }

        @Override
        public String getTown() {
            return null;
        }

        @Override
        public String getVillage() {
            return null;
        }

        @Override
        public String getStreet() {
            return null;
        }

        @Override
        public String getStreetNo() {
            return null;
        }

        @Override
        public Integer getAreaStat() {
            return null;
        }

        @Override
        public List<TencentPoi> getPoiList() {
            return null;
        }

        @Override
        public float getBearing() {
            return direction;
        }

        @Override
        public float getSpeed() {
            return velocity;
        }

        @Override
        public long getTime() {
            return time;
        }

        @Override
        public long getElapsedRealtime() {
            return time;
        }

        @Override
        public int getGPSRssi() {
            return rssi;
        }

        @Override
        public String getIndoorBuildingId() {
            return buildingId;
        }

        @Override
        public String getIndoorBuildingFloor() {
            return floorName;
        }

        @Override
        public int getIndoorLocationType() {
            return 0;
        }

        @Override
        public double getDirection() {
            return phoneDirection;
        }

        @Override
        public String getCityCode() {
            return null;
        }

        @Override
        public TencentMotion getMotion() {
            return null;
        }

        @Override
        public int getGpsQuality() {
            return 0;
        }

        @Override
        public float getDeltaAngle() {
            return 0;
        }

        @Override
        public float getDeltaSpeed() {
            return 0;
        }

        @Override
        public int getCoordinateType() {
            return 0;
        }

        @Override
        public int getFakeReason() {
            return 0;
        }

        @Override
        public int isMockGps() {
            return 0;
        }

        @Override
        public Bundle getExtra() {
            return null;
        }

        @Override
        public int getInOutStatus() {
            return 0;
        }

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public void setAccuracy(float accuracy) {
            this.accuracy = accuracy;
        }

        public void setDirection(float direction) {
            this.direction = direction;
        }

        public void setVelocity(float velocity) {
            this.velocity = velocity;
        }

        public void setTime(long time) {
            this.time = time;
        }

        public void setAltitude(double altitude) {
            this.altitude = altitude;
        }

        public void setProvider(String provider) {
            this.provider = provider;
        }

        public void setFusionProvider(String fusionProvider) { this.fusionProvider = fusionProvider; }

        public void setRssi(int rssi) {
            this.rssi = rssi;
        }

        public void setPhoneDirection(float phoneDirection) {
            this.phoneDirection = phoneDirection;
        }

        public void setBuildingId(String buildingId) {
            this.buildingId = buildingId;
        }

        public void setFloorName(String floorName) {
            this.floorName = floorName;
        }
    }

效果展示

最终根据已经录制好的轨迹(具体录制方法可以参见上期腾讯位置服务轨迹录制-安卓篇),从中国技术交易大厦到北京西站的gps轨迹进行回放,并通过导航sdk进行展示如下

tutieshi_640x1386_65s.gif

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 腾讯位置服务GPS轨迹录制-安卓篇

    在地图的使用中,尤其在导航场景下,进行GPS轨迹录制是十分必要并且有用的,本文会对于安卓系统下的轨迹录制部分做一个分享。

    腾讯位置服务
  • 腾讯位置服务实现轨迹回放

    在地图接入使用中,很多开发者咨询我们腾讯位置服务是否支持轨迹回放功能,所以今天特意将我们JavaScript API GL的轨迹回放&小车移动示例放到我们本篇文...

    腾讯位置服务
  • 基于腾讯位置服务定位实现物业巡检防作弊场景

    在物业管理中,小区内人员巡检还是非常常见的工作之一,为了降低物业的投入,设计了采用扫描二维码的形式辅助系统检测每个员工巡检的位置,以便进行常规的物业巡检工作。虽...

    腾讯位置服务
  • 【TEG+】乘风破浪

    01引言 自2015年“互联网+”的概念的提出就引起了很大的反响,接着很多互联网+政务的落地让人们看到了各种业务发展生长的可能性,开放的入口、无缝的服务、快速的...

    TEG云端专业号
  • 地图SDK示例中心全新上线,还有一大波功能升级…

    ? “想实现一个微信发送位置这个看似简单的场景,开发起来好像还挺复杂?” “之前没用过地图SDK,但是上线时间紧迫,如何快速搞定地图功能?” “对地图能力不...

    腾讯位置服务
  • 【推荐】这才是真正的物流大数据挖掘思路!

    物流大数据,都是哪些数据? 物流大数据主要包括运单信息的数据和车辆信息的数据,然而关于运单信息往往涉及商业机密,并且信息分布于不同行业企业内部,不宜公开。因此当...

    小莹莹
  • gps信号发生器在某汽车公司的应用方案

    GPS信号发生器在某汽车公司成功投运,为该gps信号发生器提供进行选配惯导仿真组件,可同时模拟GPS定位导航授时信号,用于组合导航接收的研发、生成、检定。同时也...

    时频专家
  • gps信号发生器在某汽车公司的应用方案

    GPS信号发生器在某汽车公司成功投运,为该gps信号发生器提供进行选配惯导仿真组件,可同时模拟GPS定位导航授时信号,用于组合导航接收的研发、生成、检定。同时也...

    时频专家
  • 地图SDK全新版本v4.3.0上线 - 新增多项功能及优化

    腾讯位置服务地图SDK作为地图行业的数字化助手,希望帮助开发者轻松访问腾讯地图服务和数据,构建功能丰富、交互性强、符合各种行业场景的地图类应用程序。在每期更新...

    腾讯位置服务

扫码关注云+社区

领取腾讯云代金券