智能手机中的迪拜购物中心,或如何在应用程序中添加建筑物的平面图



上一篇文章中,我讨论了如何使用地图制作移动应用程序。 在“膝盖”系列的继续中,我将与您分享实施平面图的工具。

该问题的初步说明采用简化形式:我希望能够可视化移动应用程序中的布局图,并能够在其上显示特定组织的位置。 我也想查看用户的位置,但是这里的问题出在技术层面上-您需要可以让您获取室内设备坐标的设备。 因此,我们将这一方面放在本文的讨论范围之外,而将重点放在软件部分。

下面,我将向您展示几个选项,您可以使用这些选项来实现上述要求。 这完全取决于您拥有的数据以及应用程序应该能够执行的操作。 我们将从最简单的开始。

第一种选择。 带有数据的就绪API


我们将考虑的第一个选项是使用2GIS中的现成小部件。 可以在api.2gis.ru上查看API描述。 如果您感兴趣的建筑物已在2GIS中显示,并且楼层已在建筑物中绘制,则它将非常适合您。 也就是说,就数据而言,一切都已经完成。 最重要的是,您已经可以上网了,因为此选项仅在Internet上有效。

在这种情况下,要显示地板,几乎不需要您做任何事情。 以Web小部件的形式执行执行,您只需将其放入WebView中即可。

<WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/am_webview" android:layout_marginTop="160dp" /> 

这是我们将放置小部件的容器。 我们将其初始化如下:

 webView = findViewById(R.id.am_webview) webView.settings.javaScriptEnabled = true webView.settings.useWideViewPort = true webView.settings.loadWithOverviewMode = true //webView.settings.setSupportZoom(true) //webView.settings.displayZoomControls = true //webView.settings.builtInZoomControls = true webView.loadUrl("file:///android_asset/map_api.html") webView.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) val js = "initMap('13933647002593772');" // The Dubai Mall webView.evaluateJavascript(js, ValueCallback { }) } } 

我们配置webView本身,请确保启用JavaScript,javaScriptEnabled = true,因为我们将通过它与小部件进行交互。 如有必要,您可以打开滚动条和缩放按钮(请参见注释的代码),但是效果不佳,因此不建议这样做。

最重要的是使用我们的小部件webView.loadUrl(“ file:///android_asset/map_api.html”)加载HTML,并在需要时订阅事件。 在上面的示例中,加载地图后,我们调用map_api.html中定义的initMap方法,传入要显示其楼层的建筑物的标识符。

HTML是非常简单的代码。 调用DG.FloorsWidget.init方法,将包含要初始化的数据的json对象传递到其中。 作为容器,在上面的HTML标记中指定用于声明div的ID。 调整宽度,高度。 在initData中,我们complexId标记中传递建筑信息,并在API文档中找到其他窗口小部件显示参数。 顺便说一下,可以在搜索查询中看到标识符,当您在​​2gis.ru上单击您感兴趣的建筑物时,2GIS将发送该标识符。 在我的示例中,我使用了迪拜购物中心。 但是没有人愿意指出任何其他有楼层的建筑物。

最后一点。 为了转移到特定公司,请调用showFirm方法,并传递公司标识符

 webView.loadUrl("javascript:showFirm('$firmId')") 


很简单 可以在Github上查看现成的实现示例。



考虑选项的优点:

  • 包含平面图和公司数据的现成数据;
  • 在webview上现成的轻量级实现;
  • 根据2GIS准备搜索。

缺点:

  • 需要互联网;
  • 需要具备HTML和JavaScript的基本知识;
  • 只有2GIS数据,并且只有那些已经有楼层的建筑物。

第二种选择。 平面图作为图片


如果带有就绪数据和API的选项不适合您,则可以使用以下选项。

在这种情况下,您将需要图片形式的平面图,例如jpeg或png。 如果需要“戳入图片-打开对象卡”类型的交互性,则也必须进行地理编码,这需要独立实现。 如果捕捉到全局坐标,则应该正确缩放图片,并且应将其中一个角拉到真实坐标,以便可以从中计算出位移。 我们不会在这个问题上详细介绍,我希望这里一切都清楚。

最重要的是在应用程序中显示此图片。 为此, TileView库非常适合我们。 实际上,该库原则上允许显示地图图块。 但它也适合我们,因为它提供了移动和缩放,在指定位置居中,显示标记,变换坐标以及订阅各种事件的功能。

为了使资料库尽可能有效地工作,需要通过将原始图像切成小块来准备原始图像。 有一个非常简单的说明 。 我建议在指定页面的末尾创建一个脚本,该脚本将创建4个tileset。 我们将获得的结果添加到资产中,并通过简单的代码在活动中显示图像:

 tileView.setSize(floorWidth, floorHeight) tileView.setShouldRenderWhilePanning(true) tileView.addDetailLevel(1f, "tiles/floors1/1000/%d_%d.jpg") tileView.addDetailLevel(0.500f, "tiles/floors1/500/%d_%d.jpg") tileView.addDetailLevel(0.250f, "tiles/floors1/250/%d_%d.jpg") tileView.addDetailLevel(0.125f, "tiles/floors1/125/%d_%d.jpg") tileView.defineBounds(0.0, 0.0, floorWidth.toDouble(), floorHeight.toDouble()) tileView.setScaleLimits(0f, 5f) tileView.setMinimumScaleMode(ZoomPanLayout.MinimumScaleMode.FIT) 

一切就绪,显示器准备就绪。 您可以订阅事件并添加必要的逻辑。 例如,可以这样显示标记:

 tileView.setMarkerAnchorPoints(-0.5f, -0.5f) tileView.addMarker(imageView, x, floorHeight - y, null, null) 

Github提供了完整的示例。



优点:

  • 完全脱机的能力;
  • 数据准备相对简单,平面图以图片的形式出现。

缺点:

  • 缺乏动态样式。

第三种选择。 矢量数据


此选项是最高级和最困难的。 假定您已经准备了矢量数据,即在矢量中完全绘制的楼层。 您将需要几种对象。 组织区域,停车场,美食广场,舞台,溜冰场等。 线性物体-主要是墙壁,流向。 点对象:输入/输出,电梯,ATM等。

这是斐济2GIS内部系统中的平面图:



好,对于它们的可视化,我在上一篇文章中谈到的向量引擎mapsforge-vtm非常适合我们。

为了演示该方法,我准备了测试数据:以塞浦路斯阳光岛上的一幢建筑为例,针对多个楼层设置了一组正方形和直线。 为了进行准备,我只是为了简单起见,将建筑物的原始几何形状切割成与几何形状的组件相对应的小块。 如您所知,最困难的部分是准备质量数据。 剩下的就是技术问题了。 您将需要用于切换楼层的按钮,准备用于渲染不同正方形和直线的样式以及用于渲染它们的覆盖图。

此处查看完整代码。

FloorData类包含用于我们的地板的测试地理数据代码,而FloorsManager类旨在呈现它们。

在构造函数中,我们定义正方形和墙壁的样式:

 styles.put(ObjectType.Floor, org.oscim.layers.vector.geometries.Style.builder() .fillColor(Color.GRAY) .build()); 

然后在drawFloor方法中,确定将对象添加到地图上的图层的逻辑:

 public void drawFloor(int floorId) { hideFloors(); indoorLayer = new CustomVectorLayer(this.map); List<GeoData> geoObjects = this.floorData.getFloorData(floorId); for (GeoData geo: geoObjects) { indoorLayer.add(geo.getGeometry(), styles.get(geo.getObjectType())); } this.map.layers().add(indoorLayer); indoorLayer.update(); } 

这里的一切都很基本。 创建一个新的图层IndoorLayer ,添加具有必要样式的预先准备好的楼层数据,然后将该图层添加到地图this.map.layers()。Add(indoorLayer)中

仍然需要添加按钮来切换楼层。 为此,有一个基于RecyclerViewFloorPickerControl ,它可以满足您的需求。 不要浪费时间,请参阅源代码。

这是我们应用程序中的迪拜购物中心。 它还实现了地理对象的编辑。



优点:

  • 同样,完全脱机的能力;
  • 高质量的图片;
  • 各种动态样式化的可能性;
  • 实现数据编辑器的能力。

缺点:

  • 复杂的数据准备。

在本文的结尾,我想说的是,在应用程序中显示楼层平面图的任务并不像乍看起来那样可怕。 优缺点有多种选择,从中可以选择最适合解决问题的方法。

所有引用都放在一个地方:

关于手机地图的文章
API 2地理信息系统
2GIS API示例
TileView库
TileView示例
mapsforge-vtm上的示例

Source: https://habr.com/ru/post/zh-CN476816/


All Articles