java - IndoorAtlas Android SDK 1.4.2-132 : getting the floorplan image/bitmap in fullscreen + with rotation

标签 java android xml bitmap indoor-positioning-system

所以,显然我是 Java 的新手,以下是我的故事: 我一直在与 IndoorAtlas(提供室内定位解决方案的公司)Android SDK 1.4.2-132 合作,当我在手机上测试该应用程序时,我没有得到我想要的结果。 这是我的完整 JAVA 代码,主要是从这个链接“Show FloorPlan and get Location with IndoorAtlas”获得的:

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import com.indooratlas.android.CalibrationState;
import com.indooratlas.android.FloorPlan;
import com.indooratlas.android.FutureResult;
import com.indooratlas.android.ImagePoint;
import com.indooratlas.android.IndoorAtlas;
import com.indooratlas.android.IndoorAtlasException;
import com.indooratlas.android.IndoorAtlasFactory;
import com.indooratlas.android.ResultCallback;
import com.indooratlas.android.ServiceState;
import com.indooratlas.android.IndoorAtlasListener;

import java.io.IOException;

public class FloorPlanLoader extends Activity implements IndoorAtlasListener
{
    private IndoorAtlas ia;
    private FloorPlan floorPlan; //here it says private field "floorplan" is never assigned.
    private FloorPlan mFloorPlan; // here it says private field "mFloorPlan" is assigned but never accessed.
    private ImageView imageView;

    String venueId = "xxx";
    String floorId = "xxx";
    String floorPlanId = "xxx";
    String apiKey = "xxx";
    String apiSecret = "xxx";

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.indoor_positioning);
        initIndoorAtlas();
    }
    public void initIndoorAtlas() //method to initialize indooratlas instance
    {
        try
        {
            ia = IndoorAtlasFactory.createIndoorAtlas(getApplicationContext(), this, apiKey, apiSecret);
        }
        catch (IndoorAtlasException ex)
        {
            Log.e("IndoorAtlas", "initialisation failed", ex);
            log();
        }
        FutureResult<FloorPlan> result = ia.fetchFloorPlan(floorPlanId); //obtains instance of floor plan
        result.setCallback(new ResultCallback<FloorPlan>() {
            @Override
            public void onResult(final FloorPlan result) {
                mFloorPlan = result;
                loadFloorPlanImage(result);
            }

            @Override
            public void onSystemError(IOException e) {

            }

            @Override
            public void onApplicationError(IndoorAtlasException e) {

            }
        });
    }
    public void loadFloorPlanImage(FloorPlan floorPlan)  //Method to load floor plan from the server
    {
        BitmapFactory.Options options = createBitmapOptions(floorPlan);
        FutureResult<Bitmap> result= ia.fetchFloorPlanImage(floorPlan, options);
        result.setCallback(new ResultCallback<Bitmap>()
        {
            @Override
            public void onResult(final Bitmap result)
            {
                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run() {

                        imageView = (ImageView) findViewById(R.id.imageView);
                        imageView.setImageBitmap(result);
                    }
                });
                updateImageViewInUiThread();
            }

            @Override
            public void onSystemError(IOException e)
            {
                log();
            }

            @Override
            public void onApplicationError(IndoorAtlasException e)
            {
                log();
            }
        });
        try
        {
            ia.startPositioning(venueId, floorId, floorPlanId);
        }
        catch (IndoorAtlasException e)
        {
            log();
        }
    }

   private BitmapFactory.Options createBitmapOptions(FloorPlan floorPlan)
   {
       BitmapFactory.Options options = new BitmapFactory.Options();
       int reqWidth = 2048;
       int reqHeight = 2048;

       final int width = (int) floorPlan.dimensions[0];
       final int height = (int) floorPlan.dimensions[1];
       int inSampleSize = 1;

       if (height > reqHeight || width > reqWidth) {

           final int halfHeight = height / 2;
           final int halfWidth = width / 2;

           while ((halfHeight / inSampleSize) > reqHeight
                   && (halfWidth / inSampleSize) > reqWidth) {
               inSampleSize *= 2;
           }

       }
       options.inSampleSize = inSampleSize;
       return options;
   }

    public void updateImageViewInUiThread() {}

    public void onServiceUpdate(ServiceState state) //method to show blue dot
    {
        int i = state.getImagePoint().getI();
        int j = state.getImagePoint().getJ();
        setImagePoint(state.getImagePoint());
        PointF scaledPoint = new PointF();
        Util.calculateScaledPoint((int) floorPlan.dimensions[0], (int) floorPlan.dimensions[1], i, j, imageView, scaledPoint);
        drawNewPositionInUiThread();
    }

    private void setImagePoint(final ImagePoint imgPt) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ImageView imagePoint = (ImageView) findViewById(R.id.bluedottwo);
                imagePoint.setX(imgPt.getI());
                imagePoint.setY(imgPt.getJ());
            }
        });
    }

    private void drawNewPositionInUiThread() {

    }
    public static class Util {
        public static float calculateScaleFactor(int originalWidth, int originalHeight,
                                                 ImageView imageView) {
            if (imageView.getScaleType() != ImageView.ScaleType.CENTER_INSIDE) {
                throw new IllegalArgumentException("only scale type of CENTER_INSIDE supported, was: "
                        + imageView.getScaleType());
            }

            final int availableX = imageView.getWidth()
                    - (imageView.getPaddingLeft() + imageView.getPaddingRight());
            final int availableY = imageView.getHeight()
                    - (imageView.getPaddingTop() + imageView.getPaddingBottom());

            if (originalWidth > availableX || originalHeight > availableY) {
                // original image would not fit without scaling
                return originalWidth > availableX
                        ? availableX / (float) originalWidth
                        : availableY / (float) originalHeight;
            } else {
                return 1f; // no scaling required
            }

        }
        public static void calculateScaledPoint(int originalWidth, int originalHeight,
                                                int x, int y,
                                                ImageView imageView,
                                                PointF point) {


            final float scale = calculateScaleFactor(originalWidth, originalHeight, imageView);
            final float scaledWidth = originalWidth * scale;
            final float scaledHeight = originalHeight * scale;

            // when image inside view is smaller than the view itself and image is centered (assumption)
            // there will be some empty space around the image (here offset)
            final float offsetX = Math.max(0, (imageView.getWidth() - scaledWidth) / 2);
            final float offsetY = Math.max(0, (imageView.getHeight() - scaledHeight) / 2);

            point.x = offsetX + (x * scale);
            point.y = offsetY + (y * scale);
        }
    }

    public void onServiceFailure(int errorCode, String reason)
    {
        log();
    }

    @Override
    public void onServiceInitializing()
    {
        log();
    }

    @Override
    public void onServiceInitialized()
    {
        log();
    }

    @Override
    public void onInitializationFailed(final String reason)
    {
        log();
    }

    @Override
    public void onServiceStopped()
    {
        log();
    }

    @Override
    public void onCalibrationStatus(CalibrationState calibrationState)
    {
        log();
    }

    @Override
    public void onCalibrationReady()
    {
        log();
    }

    @Override
    public void onNetworkChangeComplete(boolean success)
    {
    }

    @Override
    public void onCalibrationInvalid()
    {
    }

    @Override
    public void onCalibrationFailed(String reason)
    {
    }
    private void log()
    {
        runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {

            }
        });
    }

}

这是我完整的 XML 代码“indoor_positioning.xml”:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:weightSum="1">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/idk"
        android:scaleType="fitCenter" />
    <ImageView
        android:id="@+id/bluedottwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/bluedottwo"
        android:contentDescription="@string/bd"/>-->

</LinearLayout>

在Java代码中,我不知道要分配什么以及如何访问这两个名为“floorPlan”和“mFloorPlan”的变量。我也不确定我的 XML 代码是否正确,因为我不确定我应该有 customView 还是那两个 ImageView? 我不知道如何正确使用“Util”类(因为我猜它主要用于缩放图像/位图),以及您可以看到的其他方法,我已将它们留空。 Java 代码并不完整,这就是为什么如果有人知道答案并且知道代码中缺少什么,那就太好了。如果您一直在使用 IndoorAtlas SDk 或使用过此 SDK,或者是使用位图的专家,并且如果您知道答案,那么请指出错误并显示正确的代码来纠正我的 Java 程序。

这是显示我在 Android 手机上得到的实际结果的图像链接:“/image/WPsN4.png

正如您在图像中看到的那样,平面图已加载并显示在屏幕的左上角,内部有蓝点。 当我在手机上运行该应用程序时,首先加载蓝点,然后加载平面图位图,蓝点进入平面图图像/位图下方,然后蓝点进入平面图内。但我想全屏查看平面图图像,并进行旋转,并且平面图图像和蓝点应该同时加载。

提前非常感谢。

最佳答案

回答您的第一个问题:如何处理变量 floorPlanmFloorPlan?此 IAFloorPlan 对象保存平面图的元数据。例如。它是像素尺寸以及如何将公制位置转换为像素位置等信息。您只需要一个,因此删除 floorPlan 变量。

其次,当您在图像上绘制位置时,您需要相对于屏幕上的图像缩放图像点的 I 和 J。例如:如果服务返回像素位置 1024,1024(相对于原始平面图位图,即 2048,2048),那么您的位置位于 map 的中心。如果应用程序 UI 中的位图具有例如大小 1024x1024(原始的一半),您无法绘制到服务返回的相同坐标(1024,1024),但您需要计算比例,此处为 0.5,因此要绘制的坐标将变为:

x = 1024(originalX) * 0.5(scale) => 512
y = 1024(orginalY) * 0.5(scale) => 512

您还应该确保始终保留平面图的原始纵横比。另外,在计算 X&Y 绘制位置时,请考虑可能的填充,如果图像较小,则 View 的 Canvas 需要检查它的位置(例如居中)。

但正如我在对您的问题的评论中添加的那样:我建议使用 IndoorAtlas Android SDK v2.0 以及更好的文档和示例。文档在这里:http://docs.indooratlas.com/android/ ,示例:https://github.com/IndoorAtlas/android-sdk-examples .

关于java - IndoorAtlas Android SDK 1.4.2-132 : getting the floorplan image/bitmap in fullscreen + with rotation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33631938/

相关文章:

java - 如何将 Scala 集合 Seq[(Int, Seq[String])] 转换为 Java 集合 List[(int, List[String])]?

android - 我不断收到验证错误 : client_id provided in the request does not match any of the registered clients

xml - 在 Delphi 中使用 XML 的教程在哪里?

java - Android {Java} 中的 XML 解析

html - 无法在 Scrapy 中使用 XPath 访问 HTML 元素

Mac 上的 Java App 每次都要求允许网络连接

java - 将字符串从缓冲读取器转换为 double

java - 如何创建 "30 second countdown timer"?

android - Android 上的 Xamarin WebView 显示多个实例

Android:Button.setOnClickListener 在运行时出错