【问题标题】:Adding many symbol icons from geojson using a loop in Mapbox Android?使用 Mapbox Android 中的循环从 geojson 添加许多符号图标?
【发布时间】:2021-07-22 20:59:28
【问题描述】:

我有一张包含 500 个符号图标的地图。我想知道是否有一种方法可以使用遍历我的 geojson 信息并获取所需功能的函数或循环来添加这些标记。就目前而言,我正在单独添加每个标记,这使我的 mapbox 活动长达数千行。这一切都很完美,但我觉得如果可能的话清理代码会很好。这是我目前所拥有的:

添加我的图标可绘制对象我为每个图标单独执行此操作:

loadedMapStyle.addImage(
        Constants.ICON_ID_1_GREEN, BitmapFactory.decodeResource(
            this.resources, R.drawable.green_icon_1
        )
    )

有没有办法通过 for 循环或其他方式添加所有这些资源?

然后通过 SymbolLayer 和 match 表达式添加每个图标:

loadedMapStyle.addLayer(
        SymbolLayer("route-location-layer-id", Constants.SOURCE_ID)
            .withProperties(
                iconImage(
                    match(
                        get("icon_property"), literal(Constants.ICON_ID_1_GREEN),
                        stop(literal(Constants.ICON_ID_41_GREEN), Constants.ICON_ID_41_GREEN),
                        stop(literal(Constants.ICON_ID_40_GREEN), Constants.ICON_ID_40_GREEN),
                        stop(literal(Constants.ICON_ID_39_GREEN), Constants.ICON_ID_39_GREEN),
                        stop(literal(Constants.ICON_ID_38_GREEN), Constants.ICON_ID_38_GREEN),
                        stop(literal(Constants.ICON_ID_37_GREEN), Constants.ICON_ID_37_GREEN),
                        stop(literal(Constants.ICON_ID_36_GREEN), Constants.ICON_ID_36_GREEN),

                        ),
                ),
                iconOpacity(0.0f),
                textField(get(Constants.ICON_NAME)),
                textColor(Color.WHITE),
                textVariableAnchor(
                    arrayOf(TEXT_ANCHOR_TOP)
                ),
                textJustify(TEXT_JUSTIFY_AUTO),
                textRadialOffset(.5f),
                textAllowOverlap(true),
                textSizePropertyValue,
                iconAllowOverlap(true),
                iconOffset(arrayOf(0f, -16.5f)),
                iconSize(
                    match(
                        toString(get(Constants.PROPERTY_SELECTED)),
                        literal(1.0f),
                        stop("true", 2.0f),
                        stop("false", 1.0)
                    )
                )
            )

为了这篇文章,我删掉了上面的很多代码,因为它是每个图标的重复代码。

我使用 fromJson() 方法将 GeoJSON 文件转换为可用的 FeatureCollection 对象

@get:Throws(IOException::class)
private val featureCollectionFromJson: Unit
    get() {
        try {
            // Use fromJson() method to convert the GeoJSON file into a usable FeatureCollection object
            featureCollection = "list_of_climbing_routes.geojson".loadGeoJsonFromAsset()?.let {
                FeatureCollection.fromJson(
                    it
                )
            }
        } catch (exception: Exception) {
            Log.e("MapBoxActivity", "getFeatureCollectionFromJson: $exception")
        }
    }

最后是我的 geojson 代码的 sn-p。此时我正在访问 geojson 的坐标和 icon_property 属性:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "id":"1",
        "name":"Bump That",
        "climbingRouteNum":"1",
        "climbingRouteVRating":3,
        "climbingRouteBoulder":"Vandala Boulder",
        "area":"Front Area",
        "image_url":"https://routes/13/vandala_1_4.jpg",
        "ratingImageUrl":"https://routes/13/onestar.png",
        "climbingRouteBeta":"Another great squeeze problem. Stand start, surf to high sloping sidepulls, then squeeze your way continuously to better holds.",
        "vRating":"V3",
        "climbingRouteTickbox":"false",
        "selected":"false",
        "icon_property":"ICON_ID_1_GREEN"
      },
      "geometry": {
        "type": "Point",
       "coordinates": [
         -86.30726135484986,
         33.92127026676458
        ]
      }
    },

如果需要,我可以发布更多代码。认为这将是一个好的开始。谢谢!!

好的,所以我想知道我是否走在正确的轨道上。我不知道如何让它与停止一起工作,但我可以使用这个循环函数来获取一些信息。我只是不确定如何在我的匹配表达式中应用它。这是我的功能:

        private fun getLoadingSymbolStops(): Array<Stop?> {
    val stops: MutableList<Stop> = ArrayList()
    val featureList: List<Feature> = featureCollection!!.features() as List<Feature>

    for (x in featureList.indices) {
        val iconProperty = featureList[x].getStringProperty("icon_property")

        stops.add(stop(x, x))

                Log.d("tag", "${stops.toTypedArray()}")
                Log.d("tag", iconProperty)
    }
    return stops.toTypedArray()
}

//也试过了:

stops.add(stop(x, iconProperty))

//也试过了:

stops.add(stop(iconProperty, iconProperty))

也不行

这是我根据 @Sergio 链接到的 mapbox 示例尝试使用它的方式。虽然它没有崩溃,但它也没有设置我的任何图标。这是我的loadedMapStyle.addLayer 代码:

        loadedMapStyle.addLayer(
        SymbolLayer("route-location-layer-id", Constants.SOURCE_ID)
            .withProperties(
                iconImage(
                    match(
                        get("icon_property"), literal(Constants.ICON_ID_1_GREEN),
                        stop(literal(getLoadingSymbolStops()), getLoadingSymbolStops()),

                        ),
                ),
                iconOpacity(0.0f),
                textField(get(Constants.ICON_NAME)),
                textColor(Color.WHITE),
                textVariableAnchor(
                    arrayOf(TEXT_ANCHOR_TOP)
                ),
                textJustify(TEXT_JUSTIFY_AUTO),
                textRadialOffset(.5f),
                textAllowOverlap(true),
                textSizePropertyValue,
                iconAllowOverlap(true),
                iconOffset(arrayOf(0f, -16.5f)),
                iconSize(
                    match(
                        toString(get(Constants.PROPERTY_SELECTED)),
                        literal(1.0f),
                        stop("true", 2.0f),
                        stop("false", 1.0)
                    )
                )
            )
    )

这是我的 logcat 中的一个 sn-p:

D/tag: [Lcom.mapbox.mapboxsdk.style.expressions.Expression$Stop;@6dad284
D/tag: ICON_ID_1_GREEN
D/tag: [Lcom.mapbox.mapboxsdk.style.expressions.Expression$Stop;@d680a6d
D/tag: ICON_ID_2_YELLOW
D/tag: [Lcom.mapbox.mapboxsdk.style.expressions.Expression$Stop;@5c7d6a2
D/tag: ICON_ID_3_YELLOW

等等……

我的日志显示我正在循环遍历我的所有 icon_properties,我需要这些属性来进行停靠,并且我还显示该函数正在返回 stop.toTypedArray。我从这里去哪里?任何人?谢谢!

这是 Expressions.java 的停止代码:

  public static Stop stop(@NonNull Object stop, @NonNull Object value) {
return new Stop(stop, value);

}

/**

  • 通过评估由成对定义的分段常数函数来生成离散的阶梯式结果
  • 输入和输出值(“停止”)。 input 可以是任何数字表达式(例如,[\"get\", \"population\"])。
  • 停止输入必须是严格按升序排列的数字文字。
  • 返回停止的输出值刚好小于输入,
  • 如果输入小于第一个停止,则为第一个输入。
  • 使用示例:
  • {@code
  • CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
  • circleLayer.setProperties(
  • circleRadius(
    
  •     step(zoom(), literal(0.0f),
    
  •     literal(1.0f), literal(2.5f),
    
  •     literal(10.0f), literal(5.0f))
    
  • )
    
  • );
  • }
  • @param 输入输入值
  • @param defaultOutput 默认输出表达式
  • @param 停止输入和输出值对
  • @return 表达式
  • @见Style specification */

【问题讨论】:

  • 正如你所说,由于代码隐藏了很多细节,但是,有一个叫做记忆的概念,它是关于将以前的结果保存在内存中以避免重复一个过程,here there是一个关于 Memoization 的例子
  • 谢谢你,Wilson,但我不知道如何将那篇文章中的内容应用到我的代码中。这对我来说太先进了。只是希望遍历geojson并获取icon_property数据并将其全部应用到表达式中。或者也许我应该将其中的一些代码移动到另一个文件/类中并从我的主要活动中访问它?那可能吗?很抱歉造成混淆。代码一切正常。它只是一个活动中的很多代码行。再次感谢。
  • 我认为记忆力会很高级。并且可能不是 100% 确定它是否适合这种特定情况。回到您的问题:(1)如果您之前在 JSON 中定义/添加图像,我非常有信心您的 loadedMapStyle.addImage() 可以通过 For 循环或类似方式进行迭代。 (2) 你的止损也许也是可能的。我从来没有遇到过太多的兴趣点,所以从来没有强硬过。但是,请检查此链接:docs.mapbox.com/android/maps/examples/symbollayer-mapillary(特别是对getLoadingAnimationStops() 的代码引用)。希望它有所帮助:)
  • @Sergio 我在上面添加了我的最新尝试。它仍然没有用,但也许我正朝着正确的方向前进?感谢您的 cmets 和帮助。

标签: android mapbox geojson


【解决方案1】:

根据文档,您应该只需要提供 Stops 数组,而不是使用更改参数的表达式。你应该试试这个:

loadedMapStyle.addLayer(
  SymbolLayer("route-location-layer-id", Constants.SOURCE_ID)
      .withProperties(
          iconImage(
             match(
                get("icon_property"),
                literal(Constants.ICON_ID_1_GREEN),
                // Instead of stop() based on array of stops, just add stops' array
                *getLoadingSymbolStops()
             ),
          ),
          /* Remaining Properties*/
      )
)

【讨论】:

  • 我之前曾想过尝试这个答案,但是当我这样做时,我得到一个匹配错误,上面写着:不能使用提供的参数调用以下函数。 match(Expression, Expression, vararg Expression.Stop!) 在 com.mapbox.mapboxsdk.style.expressions.Expression 中定义 match(vararg Expression!) 在 com.mapbox.mapboxsdk.style.expressions.Expression 中定义
  • 似乎匹配表达式将 getLoadingSymbolStops() 识别为停止表达式的第一个参数,而不是停止数组。
  • @tommybomb 你能在打电话时尝试指定*getLoadingSymbolStops()吗?注意*。我的错,它是 Kotlin 的 vararg,它不会占用数组本身。使用扩展运算符(即*)时,您需要将其作为参数解包。
  • 我试过了,现在它被匹配接受了。但是我仍然无法让它显示我的图标。我已经尝试了 stop.add 的几种不同变体,但唯一能做任何事情的是这个:stops.add(stop(literal(x), iconProperty)) 但是所有标记都显示为默认 ICON_ID_1_GREEN 所以似乎不是读取返回的stops.toTyped 数组。如果有任何帮助,我正在编辑我的帖子并在 Expressions.java 文件中添加停止代码。非常感谢你的帮助。这让我头疼!
  • stops.add(stop("Constants.$iconProperty", "Constants.$iconProperty")) 这实际上是正确的,并且在我的代码中显示为正确。但是,当我在应用程序中运行代码时,它不显示任何图标。可能是因为我的 ICON_ID 字符串位于单独的 Constants 文件夹中吗?
猜你喜欢
  • 2017-03-24
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-24
  • 1970-01-01
  • 2019-08-27
相关资源
最近更新 更多