SATCH AR SDKのcompassを使ってみました。

これで何をしようかと、つらつら考え思いついたのが、

これで、対象物の「距離」と「高さ」を測ってみましょう...ということ。

対象は室内レベルですが、精度はそこそこ出て.....います(多分)。

あとこれを拡張して、AR表現(どこでもドア)をする予定です(^^)。
できれば、スマホではなくヘッドマウントディスプレイやグーグル・グラス
みたいなもんでやりたいです(^^)。

こんなアプリです

画面はこんな感じ。






適用範囲

●屋内限定
●高さは、ご自分の目線より高いもののみ
●Android 2.3.3以上









X,Y,Zの値は、それぞれ以下のような意味。





X:方位角

Y:傾き角

Z:端末の回転角(ポートレートかランドスケープかの判断に使用)


使い方

このような、収納スペースのドアの高さを計測してみます。





アプリ起動後、以下のボタンをタップしてご自分の身長を登録します。この値が基準になります。








収納スペースのドアの下端に赤い線を合わせます。

スマホを少し見下ろす感じで持ち、Yの値のブレが安定したら、 (メニュ)をクリック





収納スペースのドアの上端に赤い線を合わせてます。

スマホを少し見上げる感じで持ち、Yの値のブレが安定したら、 (メニュ)をクリック





計測値は184cm

因みに、実測値は190cm


リセット

をタップするか、(メニュ)をクリック


終了

(バック)をクリック
インストール



TOP

SATCH側のコード

目安として画面中央の赤いライン
SATCH_TESTのバーコード(testBarCodePlugin)の赤いライン(オーバーレイ)を流用

オーバーレイの実装(以下の3つのファイルを使います)
barcode.overlay、barcode.material、barcode_red.png

SATCH Studioを起動

Add -> 2D Elements -> Overlay

Nameは任意ですが、Overlay nameは、barcode.overlayに記述されている「BarCode/Visor」を使用。

【Luaコード】

local scene = getCurrentScene()

local componentInterface = getComponentInterface()

local inputManager = getInputManager()
local lTextCompass_1 = Text2D(scene:getObjectByName("text1"))
local lTextCompass_2 = Text2D(scene:getObjectByName("text2"))
local lTextCompass_3 = Text2D(scene:getObjectByName("text3"))

if isCompassDeviceAvailable() then

    local lcompass = Compass(inputManager:getDevice(TIINPUT_COMPASSDEVICE))
    lcompass:acquire()
    
    --local entity = Entity(scene:getObjectByName("frame"))
    
    repeat
        compass_x = lcompass:getOrientationX()
        compass_y = lcompass:getOrientationY()
        compass_z = lcompass:getOrientationZ()
        --str = "Compass: " .. compass_x .. ", " ..  compass_y .. ", " .. compass_z
        
        str_1 = "X: " .. compass_x
        lTextCompass_1:setText(str_1)
        
        str_2 = "Y: " ..  compass_y
        lTextCompass_2:setText(str_2)
        
        str_3 = "Z: " .. compass_z
        lTextCompass_3:setText(str_3)
        
        --entity:setOrientationEuler(0.0,0.0, compass_x) -- not the best use...
    
        componentInterface:executeAppFunc("setCompassStatus",compass_x .. "," ..  compass_y .. "," .. compass_z)
    
        
    
        isCommand, command = componentInterface:pullCommand()
            if isCommand then
                if command["CommandName"] == "object" then
                    --
                    --componentInterface:executeAppFunc("sendLog","receive command")
                    
                    local s_type = command["arg0"]
                    if s_type == "show" then
                        --
                    elseif s_type == "hide" then
                        --
                    end
                    
                end
            end
    
    
    until coroutine.yield()
else
    lTextCompass_1:setText("Compass device is not available!")
    lTextCompass_2:setText("")
    lTextCompass_3:setText("")
end



TOP

Java側のコード

vvvvv,xxxxx,yyyyy,zzzzzは適当に読み替えてください。

因みに、継承クラスのパッケージ名(com.kddi.satch.vvvvv)は、SATCHのアプリケーションIDと一致させてください。

【抽象クラス】

package com.kddi.satch.xxxxx;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;


import com.kddi.satch.LoadScenarioStatus;
import com.kddi.satch.ARViewer;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.widget.EditText;
import android.widget.Toast;

//
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.view.View.OnClickListener; 
import android.view.Gravity;



public abstract class yyyyy extends Activity {
    protected abstract String getSampleScenarioName();
    protected abstract String getSampleLogTag();
    protected boolean _isInitializedCorrectly;
    protected ARViewer _kddiComponent;
    protected FrameLayout _frameLayout;
    
    public TextView Text_View;
    public LinearLayout textLayout;
    
    public int click_count = -1;
    
    public double MyTall = 163;
    private Handler mHandler;
    public double distance_cm = 0;
    public double height = 0;
    public double upper_Y = 0;
    //public double standard_Y = 0;
    public double standard_Y = 90;
    //public double delta_Y = 0;
    public double lower_Y = 0;
    
    public double max_X = 0;
    public double min_X = 0;
    
    public double[] lower_list = new double[3];
    public int lower_index = 0;
    public double[] upper_list = new double[3];
    public int upper_index = 0;
    
    
    //private double max_Z = 0;
    //private double min_Z = 0;
    
    public int img_id1 = 0;
    public int img_id2 = 0;
    
    public void resetMembers(){
        _isInitializedCorrectly = false;
        _frameLayout = null;
        _kddiComponent = null;
    }
    private static final int DIALOG_EXIT = 0;
    
    public void initComponent(){
        _isInitializedCorrectly = false;
        _kddiComponent = new ARViewer(this);
        // This FrameLayout must be empty (but initialized) when you pass it to the kddiComponent.initialize() method.
        _frameLayout = new FrameLayout(this);
        _kddiComponent.initialize(_frameLayout);
        _isInitializedCorrectly = true;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Add null to AR Viewer Library compornent's reference.
        resetMembers();
        
        
        
    }
    
    @Override
    public void onRestart() {
        super.onRestart();
    }
    
    @Override
    public void onStart() {
        super.onStart();
        // Create AR Viewer Library compornent.
        initComponent();
        postInitComponent();
        initContentView();
        if (_isInitializedCorrectly) {
            // Do authorize and madia is loaded.
            // You must call loadScenario() method.
            loadScenario();
        }
        
        
        
    }
    
    @Override
    public void onResume(){
        super.onResume();
        if (_isInitializedCorrectly) {
            // GL context is recreated and media is reloaded.
            _kddiComponent.onResume();
            reservePlayScenario();
        }
    }
    
    @Override
    public void onPause() {
        // When the activity is paused the GL context is destroyed, so all media is unloaded.
        if (_isInitializedCorrectly) {
            cancelReservePlayScenario();
        if (_kddiComponent.checkLoadScenarioStatus() == LoadScenarioStatus.COMPLETE) {
            _kddiComponent.pauseScenario();
        }
            _kddiComponent.onPause();
        }
        super.onPause();
    }
    
    @Override
    public void onStop() {
        releaseContentView();
        // Destroy AR Viewer Library Objects.
        if (_isInitializedCorrectly){
            _kddiComponent.terminate();
            _kddiComponent = null;
            _frameLayout = null;
        }
        super.onStop();
    }
    
    @Override
    public void onDestroy() {
        // Destroy AR Viewer Library Objects.
        if (_isInitializedCorrectly){
            _frameLayout = null;
            _kddiComponent = null;
        }
        super.onDestroy();
        resetMembers(); // forced clean
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg){
        switch(keyCode){
            case android.view.KeyEvent.KEYCODE_MENU :
                //showDialog( DIALOG_EXIT );
                click_count++;
                if (click_count == 2) {
                    click_count = 0;
                    reset_data();
                }
                
                calc_it();
                return true;
            
            
            case android.view.KeyEvent.KEYCODE_BACK :
                showDialog( DIALOG_EXIT );
                return true;
            
            
            
            
            
        }
        return false;
    }
    
    public void postInitComponent(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            _kddiComponent.activateAutoFocusOnDownEvent(true);
        }
    }
    
    public void initContentView(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            // you'll probably use some other UI object as the content view that itself will embed the component's frame layout -- here you can change all this
            // by default, the frame layout containing DFusion will be the activity content view
            setContentView(_frameLayout);
        }
        
        
        LinearLayout linear_LayoutL = new LinearLayout(this);
        linear_LayoutL.setOrientation(LinearLayout.HORIZONTAL);
        linear_LayoutL.setGravity(Gravity.LEFT|Gravity.BOTTOM);
        addContentView(linear_LayoutL, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        
        
        LinearLayout linear_LayoutC = new LinearLayout(this);
        linear_LayoutC.setOrientation(LinearLayout.HORIZONTAL);
        linear_LayoutC.setGravity(Gravity.CENTER|Gravity.BOTTOM);
        addContentView(linear_LayoutC, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        
        
        
        LinearLayout linear_LayoutR = new LinearLayout(this);
        linear_LayoutR.setOrientation(LinearLayout.HORIZONTAL);
        linear_LayoutR.setGravity(Gravity.RIGHT|Gravity.BOTTOM);
        addContentView(linear_LayoutR, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        
        
        //reset
        ImageButton imgbtn_reset  = new ImageButton(this);
        imgbtn_reset.setImageResource(img_id2);
        //imgbtn_B.setAlpha(50);
        imgbtn_reset.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                ButtonReset_OnClick();
            }
        });
        linear_LayoutR.addView(imgbtn_reset, new LinearLayout.LayoutParams(72,72));
        
        
        textLayout = new LinearLayout(this);
        Text_View = new TextView(this);
        Text_View.setTextColor(Color.YELLOW);
        Text_View.setText("data");
        linear_LayoutC.addView(Text_View, new LinearLayout.LayoutParams(250,72));
        
        //height
        ImageButton imgbtn_height  = new ImageButton(this);
        imgbtn_height.setImageResource(img_id1);
        //imgbtn_C.setAlpha(50);
        imgbtn_height.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                ButtonHeight_OnClick();
            }
        });   
        linear_LayoutR.addView(imgbtn_height, new LinearLayout.LayoutParams(72,72));
        
    }
    
    
    private void ButtonReset_OnClick(){
        reset_data();
    }
    
    private void ButtonHeight_OnClick(){
        input_yourtall();
    }
    
    public void releaseContentView(){
        // override this if you need to do some special handling on the component after standard initialization
        if (_isInitializedCorrectly) {
            // do here the release of the your UI instances (if customized)
        }
    }
    
    public void loadScenario(){
        ApplicationInfo appInfo = null;
        PackageManager packMgmr = getApplicationContext().getPackageManager();
        try {
            appInfo = packMgmr.getApplicationInfo(getPackageName(), 0);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("Unable to locate assets, aborting...");
        }
        String dpdfile = appInfo.sourceDir + getSampleScenarioName();
        _kddiComponent.loadScenario(dpdfile);
    }
    
    // Set polling rate for loading the media.
    private final int REPEAT_INTERVAL = 100;
    private Handler handler = new Handler();
    private Runnable runnable = null;
    
    
    //
    private void reservePlayScenario(){
        if (runnable == null){
            runnable = new Runnable(){
                @Override
                public void run(){
                    LoadScenarioStatus status = _kddiComponent.checkLoadScenarioStatus();
                    if (status == LoadScenarioStatus.CANCEL){
                        // cancel(appli suspend)
                    }else if (status == LoadScenarioStatus.COMPLETE){
                        // Ready to play scenario
                        _frameLayout.setVisibility(View.VISIBLE);
                        _kddiComponent.playScenario();
                    }else if (
                        status == LoadScenarioStatus.ERROR_NETWORK_UNUSABLE ||
                        // faild to load a media becase of no network connection.
                        status == LoadScenarioStatus.ERROR_NETWORK ||
                        // faild to load a media becase of network error.
                        status == LoadScenarioStatus.ERROR_SOFTWAREKEY ||
                        // faild to load a media becase software key has not be found on server.
                        status == LoadScenarioStatus.ERROR_CONTENT_STOPPED ||
                        // faild to load a media becase content has stopped.
                        status == LoadScenarioStatus.ERROR_SERVER ||
                        // faild to load a media becase of server error.
                        status == LoadScenarioStatus.ERROR_ETC
                        // faild to load a media becase of another error.
                        ){
                    // error
                    }else{
                        handler.postDelayed(this, REPEAT_INTERVAL);
                    }
                }
            };
            handler.postDelayed(runnable, REPEAT_INTERVAL);
        }
    }
    
    //
    
    private void cancelReservePlayScenario(){
        if (handler != null && runnable != null){
            handler.removeCallbacks(runnable);
            runnable = null;
        }
    }
    
    protected Dialog onCreateDialog(int id) {
        Dialog dialog;
        switch(id) {
            case DIALOG_EXIT:
            {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(
                    "Really want to quit the application?"
                )
                .setCancelable(true)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        finish();
                    }})
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }});
                    dialog = builder.create();
                    break;
            }
            default:
            dialog = null;
        }
        return dialog;
    }
    
    public void input_yourtall(){
        //
        final EditText editView = new EditText(yyyyy.this);
        editView.setText("163");
        new AlertDialog.Builder(yyyyy.this)
            .setIcon(android.R.drawable.ic_dialog_info)
            .setTitle("身長をcmで入力")
            //
            .setView(editView)
            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    //
                    
                    if (editView.getText().toString().equals("")) {
                    } else{
                        MyTall = Double.parseDouble(editView.getText().toString());
                    }
                }
            })
            .setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                }
            })
            .show();

    }
    
    
    
    
    public void calc_it(){
        Log.i("CAL","OK");
        double rad = 0;
        String mes = "";
        
        if (click_count == 0) {
            height = MyTall - 33;
            //Text_View.setText(String.valueOf(max_data));
            
            lower_Y = (lower_list[0] + lower_list[1] + lower_list[2]) / 3;
            
            
            double sieta = 90 - Math.abs(standard_Y - lower_Y);
            
            Log.i("ANGLE",sieta + "");
            
            
            rad = Math.toRadians(sieta);
            
            distance_cm = Math.round(height / Math.tan(rad));
            
            //int distance_cm = (int)Math.round(height / Math.tan(rad));
            
            //double distance_m = distance_cm / 100;
            mes = "距離:" + String.valueOf(distance_cm) + " cm:" + sieta;
            Text_View.setText(mes);
            
        }
        
            
        if (click_count == 1) {
            height = MyTall - 5;
            
            upper_Y = (upper_list[0] + upper_list[1] + upper_list[2]) / 3;
            
            double gamma = Math.abs(upper_Y) - 90;
            rad = Math.toRadians(gamma);
            
            double M = distance_cm * Math.tan(rad);
            double H = Math.round(M + height);
            
            mes = "距離:" + String.valueOf(distance_cm) + " cm" + "\n" + "高さ:" + String.valueOf(H) + " cm";
            Text_View.setText(mes);
            
        }
    }
    
    private void reset_data(){
        //
        click_count = -1;
        standard_Y = 0;
        lower_Y = 0;
        upper_Y = 0;
        distance_cm = 0;
        
        Text_View.setText("");
    }
    
}

【継承クラス】

package com.kddi.satch.vvvvv;


import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.kddi.satch.xxxxx.yyyyy;


import android.widget.Toast;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;

public class xxxxx extends yyyyy {
    private static final String THIS_CLASS_SHORT_NAME = xxxxx.class.getName().replace("com.kddi.satch.vvvvv.", "");
    private static final String THIS_LOGTAG  = THIS_CLASS_SHORT_NAME;
    // Set AR scenario file path.
    private static final String SCENARIO_NAME = "/assets/Scenario/Scenario_satchcompass/satchCompass.dpd";
    protected String getSampleScenarioName() { return SCENARIO_NAME; }
    protected String getSampleLogTag() { return THIS_LOGTAG;   }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Resources res = getResources();
        img_id1 = res.getIdentifier("height" , "drawable", getPackageName());
        img_id2 = res.getIdentifier("reset" , "drawable", getPackageName());
    }
    
    @Override
    public void postInitComponent(){
        super.postInitComponent();
        
        if (_isInitializedCorrectly) {
            _kddiComponent.activateAutoFocusOnDownEvent(true);
            _kddiComponent.registerCommunicationCallback("setCompassStatus", this, "setCompassStatus");
        }
        
        
        
    }
    
    public void setCompassStatus(String[] arrayOfString) {
        
        
        String[] data_list = new String[3];
        data_list = arrayOfString[0].split(",");
        
        
        //X
        
        
        //Y
        double temp_Y = Double.parseDouble(data_list[1]);
        
        
        
        if (Double.parseDouble(data_list[1]) < -90) {
            upper_list[upper_index] = temp_Y;
            upper_index++;
            if (upper_index == 3) {
                upper_index = 0;
            }
            
            upper_Y = temp_Y;
        }else{
            lower_list[lower_index] = temp_Y;
            lower_index++;
            if (lower_index == 3) {
                lower_index = 0;
            }
            
            
            //lower_Y = temp_Y;
            
        }
        //Z
        if (Math.abs(Double.parseDouble(data_list[2])) < 45) {
            //portrate
        }else{
            //landscape
        }
        
        //------------------------------------------
        
    }
    
  
    
    
   
}


TOP





トップページ| サイトマップ|