IndoorAtlas Android SDK 1.4.2-132:以全屏+旋转方式获取平面图图像/位图
Posted
技术标签:
【中文标题】IndoorAtlas Android SDK 1.4.2-132:以全屏+旋转方式获取平面图图像/位图【英文标题】:IndoorAtlas Android SDK 1.4.2-132: getting the floorplan image/bitmap in fullscreen + with rotation 【发布时间】:2015-11-10 14:10:03 【问题描述】:所以,显然我是 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_
android:layout_
android:weightSum="1">
<ImageView
android:id="@+id/imageView"
android:layout_
android:layout_
android:contentDescription="@string/idk"
android:scaleType="fitCenter" />
<ImageView
android:id="@+id/bluedottwo"
android:layout_
android:layout_
android:src="@drawable/bluedottwo"
android:contentDescription="@string/bd"/>-->
</LinearLayout>
在 Java 代码中,我不知道要分配什么以及如何访问这两个名为“floorPlan”和“mFloorPlan”的变量。我也不确定我的 XML 代码是否正确,因为我不确定我应该有 customView 还是那两个 ImageView? 我不知道如何正确使用“Util”类(我猜它主要用于缩放图像/位图),以及您可以看到的其他方法,我将它们留空。 Java 代码不完整,这就是为什么如果有人知道答案并且知道代码中缺少什么,那就太好了。如果您使用过 IndoorAtlas SDK 或使用过此 SDK 或使用位图的专家,如果您知道答案,请通过指出错误并显示正确代码来纠正我的 Java 程序。
这是显示我在我的安卓手机上得到的实际结果的图片链接:“http://i.imgur.com/ySjBt3T.png”
正如您在图像中看到的那样,平面图已加载并显示在屏幕的左上角,里面有一个蓝点。 当我在手机上运行应用程序时,首先加载蓝点,然后加载平面图位图,蓝点位于平面图图像/位图下方,之后,蓝点进入平面图。但我想全屏查看平面图图像,旋转,平面图图像和蓝点应该同时加载。
非常感谢。
【问题讨论】:
如果您开始新的开发,我建议您使用 SDK 的 2.0 版本,因为它在 GitHub 中有完整的示例代码(阅读更多:docs.indooratlas.com/android)而且无论如何使用起来要容易得多。 我已经在我的应用程序中实现了新的 SDK,是的,它更容易实现,但是,当我打开应用程序时,它显示已删除的平面图(我测试并从我的IndoorAtlas 帐户)。我一直在联系 IndoorAtlas 支持,他们告诉我开发团队将很快进行缓存清理,所以在那之前我必须使用旧版 SDK,因为我想在我自己的应用程序中看到正确的平面图,而不是删了一个。 【参考方案1】:回答您的第一个问题:如何处理变量floorPlan
和mFloorPlan
?此 IAFloorPlan 对象包含平面图的元数据。例如。它是像素尺寸和如何将公制位置转换为像素位置等信息。您只需要一个,因此删除floorPlan
变量。
其次,当您在图像上绘制位置时,您需要相对于屏幕上的图像缩放图像点的 I 和 J。例如:如果服务返回像素位置 1024,1024,它与原始平面图位图(即 2048,2048)相关,则您的位置位于地图的中心。如果您的应用程序 UI 中的位图具有例如大小为 1024x1024(原件的一半),您无法绘制到服务返回的相同坐标(1024,1024),但您需要计算这里为 0.5 的比例,因此要绘制的坐标将变为:
x = 1024(originalX) * 0.5(scale) => 512
y = 1024(orginalY) * 0.5(scale) => 512
您还应确保始终保留平面图的原始纵横比。此外,在计算 X&Y 绘制位置时,请考虑可能的填充,如果图像小于该视图的画布,您需要检查它的定位方式(例如居中)。
但正如我在 cmets 中向您的问题添加的那样:我建议使用 v2.0 的 IndoorAtlas Android SDK 以及更好的文档和示例。此处的文档:http://docs.indooratlas.com/android/,示例:https://github.com/IndoorAtlas/android-sdk-examples。
【讨论】:
以上是关于IndoorAtlas Android SDK 1.4.2-132:以全屏+旋转方式获取平面图图像/位图的主要内容,如果未能解决你的问题,请参考以下文章