基於地理位置的Android AR app項目簡述

(一)需求分析

1、項目背景

 基於當今的社會需求,沒有人再會小看營銷的重要性。而二維圖像和視頻等營銷方式已經吸引不了客戶的眼球。隨着支付寶AR紅包和任天堂的《精靈寶可夢》遊戲的火速走紅,AR已經成爲了營銷者中的新寵兒。公司主營業務便是VR相關,但是爲了更好的開展業務和增加技術儲備。於是,一種新型的基於地理位置的AR App便誕生了。

2、本項目應用場景
  • 旅遊景點
  • 房地產看房
  • AR地圖導航
  • 其他
3、用戶使用場景描述
  • 用於旅遊景點
     用戶來到景區,通過掃描相應的二維碼,系統反饋帶有AR效果的標籤,比如可以看附近的公廁、停車場或者其他標誌性建築物,用戶點擊標籤,會進入VR場景,查看相應標籤做對應的景點或建築物。
  • 用於房地產看房
     用戶買房一般非現房,用戶想知道建成之後什麼效果。用戶僅需要掃描二維碼或者通過圖像識別接口掃描實物,系統反饋AR效果的房間內物品標籤,用戶點擊可查看建成後效果圖(VR圖片或視頻展示或其他廣告展示)
  • 用於地圖導航
     用戶使用該軟件搜索目的地進行AR導航(導航部分還未開發)
4、技術&商業價值
  • 可廣泛用於當前新式廣告營銷
  • 可儲備相應技術,迎接5G時代,與5G結合
  • 爲以後開發AR/VR相關產品做技術積累

(二)概要設計

1、用戶操作流程圖設計

下面是完整的設計思路。

在這裏插入圖片描述
注:該程序上述部分功能還未實現(圖片識別、導航、看全景),不過已經在其他開發的APP中實現,本文主要介紹顯示動態標籤功能實現。

2、APP端設計

在這裏插入圖片描述

3、服務端設計

在這裏插入圖片描述

4、數據庫設計

主要是由三張表組成,分別是掃描信息詳情表、位置信息詳情表、人員詳情表。
在這裏插入圖片描述

(三)實現所用主要技術

1、APP端
2、服務端
  • springboot後端開發框架
  • lombok插件
  • mysql jdbc
  • maven項目管理工具
  • jpa
  • junit單元測試工具
  • IDEA
  • Java Web開發技術
3、數據庫
  • MySQL5.7
  • Navicat for Mysql5.7
4、其他
  • xmind
  • processOn

(四)詳細設計&實現難點

1、APP端核心模塊功能分析
  • 解析後端發來的數據
     主要是json格式的解析
  /**
     * 數據解析操作
     */
    public class HandleResultData implements Runnable{
        @Override
        public  void run(){
            String RequestUrl="http://uae5f2.natappfree.cc/ar/client/location/show?scanId=1";
            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
                    //第一個參數,請求的網址
                    RequestUrl,
                    //第二個參數
                    null,
                    //響應正確時的處理
                    new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            Log.d("TAG", response.toString());
                            /**
                             * 解析Json爲Object
                             */
                            String mJSON = response.toString();
                            ResultBean resultBean=new ResultBean();
                            resultBean = JSON.parseObject(mJSON,ResultBean.class);

                    //響應錯誤時的處理
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            Log.e("TAG", error.getMessage(), error);
                            mHandler.obtainMessage(MSG_FAILURE).sendToTarget();
                        }
                    });
            //把這個請求加到Volley隊列即可
            jsonObjectRequest.setTag(TAG);
            mQueue.add(jsonObjectRequest);

        }

  • AR浮窗效果實現
     主要是將導航座標顯示在浮層上以實現AR效果。
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (currentLocation == null) {
            return;
        }

        final int radius = 30;
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
        paint.setTextSize(60);

        for (int i = 0; i < arPoints.size(); i ++) {
            float[] currentLocationInECEF = LocationHelper.WSG84toECEF(currentLocation);
            float[] pointInECEF = LocationHelper.WSG84toECEF(arPoints.get(i).getLocation());
            float[] pointInENU = LocationHelper.ECEFtoENU(currentLocation, currentLocationInECEF, pointInECEF);

            float[] cameraCoordinateVector = new float[4];
            Matrix.multiplyMV(cameraCoordinateVector, 0, rotatedProjectionMatrix, 0, pointInENU, 0);

            // cameraCoordinateVector[2] is z, that always less than 0 to display on right position
            // if z > 0, the point will display on the opposite
            if (cameraCoordinateVector[2] < 0) {
                float x  = (0.5f + cameraCoordinateVector[0]/cameraCoordinateVector[3]) * canvas.getWidth();
                float y = (0.5f - cameraCoordinateVector[1]/cameraCoordinateVector[3]) * canvas.getHeight();

                canvas.drawCircle(x, y, radius, paint);
                canvas.drawText(arPoints.get(i).getName(), x - (30 * arPoints.get(i).getName().length() / 2), y - 80, paint);
            }
        }
    }
2、服務端核心模塊功能分析
  • 請求數據API
     我設計了一個數據請求的API格式,data鏈表中夾雜着一個locationlist鏈表,雙層鏈表實現。
{
   "code":0,
   "msg":"success",
   "data":{
        "name": "黃河路",
        "type": 1,
              "locationList":[
                {
                  "id":"123456",
                  "name":"丹尼斯",
                  "latitude":12.335,
                  "longitude":34.225,
                  "altitude":5.2,
                  "description":"一個購物的地方",
                  "icon":"http://www.dennis.com.cn/u/cms/www/201707/191157482x37.jpg",
                  "link":"http://122.114.223.188/toShow?VRourEditor=206",
                  "people":[
                        {
                          "name":"jack",
                          "responsibility":"doctor",
                          "phone":"13052312154"
                        },
                        {
                          "name":"evan",
                          "responsibility":"護士",
                          "phone":"13565667488"
                        }
                  ]
                },
                {
                  "id":"123457",
                  "name":"微阿科技",
                  "latitude":44.123,
                  "longtitude":33.124,
                  "altitude":5.2,
                  "description":"公司",
                  "icon":"http://www.dennis.com.cn/u/cms/www/201707/191157482x37.jpg",
                  "link":"http://122.114.223.188/toShow?VRourEditor=206",
                  "people":[
                        {
                          "name":"linda",
                          "responsibility":"doctor",
                          "phone":"1325355555"
                        },
                        {
                          "name":"tim",
                          "responsibility":"護士",
                          "phone":"13561125488"
                        }
                  ]
                }
              ]
        }
 }
3、核心算法分析
  • 將gps座標轉換成手機導航座標實現
    其實就是先將GPS座標即大地中心繫WGS84(WorldGeodeticCoordinateSystem1984)轉化爲地球中心座標系ECEF(Earth-Centered, Earth-Fixed),然後再將地球中心座標系ECEF轉換成局部切線平面ENU(東、北、天)座標系,再將其轉化爲手機導航座標系x、y軸。
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

上述圖片參考:無人機常見座標系


更詳細的介紹我放在了我的項目中,可以參考:
https://github.com/Evanlovea/AR-App/tree/master/ARNavigation/app/src/main/res/docs

/**
     * 將GPS座標系轉換爲ECEF
     * (ECEF(Earth-Centered,Earth-Fixed),以地球爲中心,符合地球,
     * 是一個笛卡爾座標系,也稱爲“普通地表”系統)
     * @param location
     * @return
     */
    public static float[] WSG84toECEF(Location location) {
        double radLat = Math.toRadians(location.getLatitude());
        double radLon = Math.toRadians(location.getLongitude());

        float clat = (float) Math.cos(radLat);
        float slat = (float) Math.sin(radLat);
        float clon = (float) Math.cos(radLon);
        float slon = (float) Math.sin(radLon);

        float N = (float) (WGS84_A / Math.sqrt(1.0 - WGS84_E2 * slat * slat));

        float x = (float) ((N + location.getAltitude()) * clat * clon);
        float y = (float) ((N + location.getAltitude()) * clat * slon);
        float z = (float) ((N * (1.0 - WGS84_E2) + location.getAltitude()) * slat);

        return new float[] {x , y, z};
    }

    /**
     * 將ECEF座標系轉換爲ENU(站心座標系)座標系
     *
     * @param currentLocation
     * @param ecefCurrentLocation
     * @param ecefPOI
     * @return
     */
    public static float[] ECEFtoENU(Location currentLocation, float[] ecefCurrentLocation, float[] ecefPOI) {
        double radLat = Math.toRadians(currentLocation.getLatitude());
        double radLon = Math.toRadians(currentLocation.getLongitude());

        float clat = (float)Math.cos(radLat);
        float slat = (float)Math.sin(radLat);
        float clon = (float)Math.cos(radLon);
        float slon = (float)Math.sin(radLon);

        float dx = ecefCurrentLocation[0] - ecefPOI[0];
        float dy = ecefCurrentLocation[1] - ecefPOI[1];
        float dz = ecefCurrentLocation[2] - ecefPOI[2];

        float east = -slon*dx + clon*dy;

        float north = -slat*clon*dx - slat*slon*dy + clat*dz;

        float up = clat*clon*dx + clat*slon*dy + slat*dz;

        return new float[] {east , north, up, 1};
    }
4、效果展示

 下面是某商業APP的圖,我的沒它那麼花裏胡哨的(我做的UI比較簡單 ),不過原理應該差不多,不過這個APP實現應該是基於某地圖的SDK的,而我的可以動態添加地理位置信息,不知道它的可不可以。可參考。(主要是我懶得搭服務器部署運行了 )。
在這裏插入圖片描述

5、其他模塊實現

 可以參考我的github地址:基於地理位置的AR app項目

(五)參考文獻

【1】http://www.gogocity.cn/flash/video2.mp4
【2】無人導航常見座標系
【3】DSTO-TN-0432.pdf
【4】Android開發技術指南

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章