From a5e964efbb0e0a93376187163836dd27c07d0298 Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Sun, 25 Jun 2023 10:11:24 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=B7=AF?= =?UTF-8?q?=E5=8F=A3=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/omdb_config.json | 71 +++++- .../com/navinfo/omqs/bean/ImportConfig.kt | 40 ++- .../java/com/navinfo/omqs/db/Code2NameMap.kt | 43 ++++ .../com/navinfo/omqs/db/ImportPreProcess.kt | 235 +++++++++++++++--- .../src/main/assets/editormarker.xml | 35 ++- .../collect/library/utils/GeometryTools.java | 2 +- vtm | 2 +- 7 files changed, 385 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/com/navinfo/omqs/db/Code2NameMap.kt diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index 994a1511..0800ec23 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -101,7 +101,12 @@ "code": 4001, "name": "路口", "transformer": [ - + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateIntersectionReference()" + } ] }, "4002": { @@ -170,7 +175,25 @@ "k": "geometry", "v": "~", "klib": "geometry", - "vlib": "generateRestrictionRerference()" + "vlib": "translateBack()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "translateRight()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateS2EReferenceLine()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateDirectReferenceLine()" } ] }, @@ -179,7 +202,30 @@ "code": 4010, "name": "电子眼", "transformer": [ - + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "translateRight()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateS2EReferenceLine()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateDirectReferenceLine()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateElectronName()" + } ] }, "4022": { @@ -200,7 +246,24 @@ "code": 4601, "name": "车信", "transformer": [ - + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "translateBack()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "translateRight()" + }, + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generateDirectReferenceLine()" + } ] }, "5001":{ diff --git a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt index 1e15ce0d..5a8e099e 100644 --- a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt +++ b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt @@ -2,6 +2,8 @@ package com.navinfo.omqs.bean import com.navinfo.collect.library.data.entity.RenderEntity import com.navinfo.omqs.db.ImportPreProcess +import kotlin.reflect.KFunction +import kotlin.reflect.KParameter import kotlin.reflect.full.declaredMemberFunctions @@ -36,16 +38,46 @@ class ImportConfig { for (v in processKeyOrValue(value)) { if ("~" == v ) { // ~符可以匹配任意元素 if (valuelib.endsWith("()")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 - val method = preProcess::class.declaredMemberFunctions.first { it.name == valuelib.replace("()", "") } - method.call(preProcess, renderEntity) + // 获取方法名 + val methodName = valuelib.substringBefore("(") + // 获取参数 + val params: List = valuelib.substringAfter("(").substringBefore(")").split(",").filter{ it.isNotEmpty() }.map { it.trim() } + val method = preProcess::class.members.filter { it.name == methodName }.first() as KFunction<*> + + val methodParams = method.parameters + val callByParams = mutableMapOf( + methodParams[0] to preProcess, + methodParams[1] to renderEntity + ) + for ((index, value) in params.withIndex()) { + if (methodParams.size>index+1) { + callByParams[methodParams[index+1]] = value + } + } + method.callBy(callByParams) } else { renderEntity.properties[keylib] = valuelib } break@m } else if (renderEntity.properties[k] == v) { // 完全匹配 if (valuelib.endsWith("()")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 - val method = preProcess::class.declaredMemberFunctions.first { it.name == valuelib.replace("()", "") } - method.call(preProcess, renderEntity) + // 获取方法名 + val methodName = valuelib.substringBefore("(") + // 获取参数 + val params: List = valuelib.substringAfter("(").substringBefore(")").split(",").filter{ it.isNotEmpty() }.map { it.trim() } + val method = preProcess::class.members.filter { it.name == methodName }.first() as KFunction<*> + + val methodParams = method.parameters + val callByParams = mutableMapOf( + methodParams[0] to preProcess, + methodParams[1] to renderEntity + ) + for ((index, value) in params.withIndex()) { + if (methodParams.size>index+1) { + callByParams[methodParams[index+1]] = value + } + } + method.callBy(callByParams) } else { renderEntity.properties[keylib] = valuelib } diff --git a/app/src/main/java/com/navinfo/omqs/db/Code2NameMap.kt b/app/src/main/java/com/navinfo/omqs/db/Code2NameMap.kt new file mode 100644 index 00000000..40a09740 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/db/Code2NameMap.kt @@ -0,0 +1,43 @@ +package com.navinfo.omqs.db + +class Code2NameMap { + val electronEyeKindMap = mapOf( + 1 to "超高", + 2 to "超低", + 3 to "移动", + 4 to "可变", + 5 to "分车道", + 6 to "分车种", + 7 to "车灯", + 8 to "占车道", + 9 to "过路口", + 10 to "闯红灯", + 11 to "路况", + 12 to "单行", + 13 to "非机动", + 14 to "出入口", + 15 to "公交", + 16 to "禁转", + 17 to "掉头", + 18 to "应急", + 19 to "标线", + 20 to "区间S", + 21 to "区间E", + 22 to "停车", + 23 to "尾号", + 24 to "环保", + 25 to "安全带", + 26 to "手机", + 27 to "行人", + 28 to "禁令", + 29 to "鸣笛", + 30 to "年检", + 31 to "尾气", + 32 to "交通灯", + 33 to "专用", + 34 to "标线", + 35 to "违章", + 36 to "卡车", + 37 to "限时长", + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt index 55b5d4b7..3f2d8749 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt @@ -13,29 +13,36 @@ import org.oscim.core.GeoPoint class ImportPreProcess { - /** - * 预处理所需要的函数 - * */ - fun foo(renderEntity: RenderEntity): RenderEntity { - println("foo") - renderEntity.properties["foo"] = "bar" - return renderEntity - } - + val code2NameMap = Code2NameMap() /** * 计算指定数据指定方向的坐标 + * @param direction 判断当前数据是否为逆向,给定的应该是一个a=b的表达式,a为对应的properties的key,b为对应的值 * */ - fun translateRight(renderEntity: RenderEntity): RenderEntity { + fun translateRight(renderEntity: RenderEntity, direction: String = "") { // 获取当前renderEntity的geometry val geometry = renderEntity.wkt var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 var point = Coordinate(geometry?.coordinate) + var isReverse = false // 是否为逆向 + if (direction.isNotEmpty()) { + val paramDirections = direction.split("=") + if (paramDirections.size>=2 && renderEntity.properties[paramDirections[0].trim()] == paramDirections[1].trim()) { + isReverse = true; + } + } if (Geometry.TYPENAME_POINT == geometry?.geometryType) { - val angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! + var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! + if (isReverse) { + angle += 180 + } radian = Math.toRadians(angle) } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { - val p1: Coordinate = geometry.coordinates.get(geometry.coordinates.size - 2) - val p2: Coordinate = geometry.coordinates.get(geometry.coordinates.size - 1) + var coordinates = geometry.coordinates + if (isReverse) { + coordinates = coordinates.reversedArray() + } + val p1: Coordinate = coordinates.get(coordinates.size - 2) + val p2: Coordinate = coordinates.get(coordinates.size - 1) // 计算线段的方向 radian = Angle.angle(p1, p2) point = p2 @@ -52,46 +59,126 @@ class ImportPreProcess { // 将这个点记录在数据中 val geometryTranslate: Geometry = GeometryTools.createGeometry(doubleArrayOf(coord.x, coord.y)) renderEntity.geometry = geometryTranslate.toString() - return renderEntity } /** - * 将要素按照点位角度的垂直方向右移5米,并生成一个按照垂直角度指向方向的线段,用以显示有方向的图标 + * 向方向对应的反方向偏移 * */ - fun translateRightWithAngle(renderEntity: RenderEntity): RenderEntity { + fun translateBack(renderEntity: RenderEntity, direction: String = "") { // 获取当前renderEntity的geometry val geometry = renderEntity.wkt + var isReverse = false // 是否为逆向 + if (direction.isNotEmpty()) { + val paramDirections = direction.split("=") + if (paramDirections.size>=2 && renderEntity.properties[paramDirections[0].trim()] == paramDirections[1].trim()) { + isReverse = true; + } + } var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 var point = Coordinate(geometry?.coordinate) if (Geometry.TYPENAME_POINT == geometry?.geometryType) { - // angle为正北方向夹角,需要将其转换为与正东方向夹角 var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! - angle-=90 + if (isReverse) { + angle += 180 + } radian = Math.toRadians(angle) } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { - val p1: Coordinate = geometry.coordinates.get(geometry.coordinates.size - 2) - val p2: Coordinate = geometry.coordinates.get(geometry.coordinates.size - 1) + var coordinates = geometry.coordinates + if (isReverse) { + coordinates = coordinates.reversedArray() + } + val p1: Coordinate = coordinates.get(coordinates.size - 2) + val p2: Coordinate = coordinates.get(coordinates.size - 1) // 计算线段的方向 radian = Angle.angle(p1, p2) point = p2 } - // 根据角度计算偏移距离 + // 计算偏移距离 val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) // 计算偏移后的点 -// val coordMid = -// Coordinate(point.getX() + dy, point.getY() - dx) - // 计算指定距离外与当前位置成90度夹角的点位 - val pointStart = GeoPoint(point.getY() - dx, point.getX() + dy) -// val pointStart = GeoPoint(pointMid.latitude-dy, pointMid.longitude-dx) - val pointEnd = GeoPoint(pointStart.latitude- dx, pointStart.longitude+ dy) + val coord = + Coordinate(point.getX() - dx, point.getY() - dy) - // 将这个线记录在数据中 - val geometryTranslate: Geometry = GeometryTools.createLineString(listOf(pointStart, pointEnd)) + // 将这个点记录在数据中 + val geometryTranslate: Geometry = GeometryTools.createGeometry(doubleArrayOf(coord.x, coord.y)) renderEntity.geometry = geometryTranslate.toString() - return renderEntity + } + + /** + * 生成偏移后数据的起终点参考线 + * */ + fun generateS2EReferenceLine(renderEntity: RenderEntity) { + // 获取当前renderEntity的geometry,该坐标为偏移后坐标,即为终点 + val translateGeometry = renderEntity.wkt + val startGeometry = GeometryTools.createGeometry(renderEntity.properties["geometry"]) + + val pointEnd = translateGeometry!!.coordinates[translateGeometry.numPoints-1] // 获取这个geometry对应的结束点坐标 + val pointStart = startGeometry!!.coordinates[startGeometry.numPoints-1] // 获取这个geometry对应的结束点坐标 + + // 将这个起终点的线记录在数据中 + val startEndReference = ReferenceEntity() + startEndReference.renderEntityId = renderEntity.id + startEndReference.name = "${renderEntity.name}参考线" + startEndReference.table = renderEntity.table + // 起终点坐标组成的线 + startEndReference.geometry = GeometryTools.createLineString(arrayOf(pointStart, pointEnd)).toString() + startEndReference.properties["qi_table"] = renderEntity.table + startEndReference.properties["type"] = "s_2_e" + Realm.getDefaultInstance().insert(startEndReference) + } + + /** + * 生成与对应方向相同的方向线,用以绘制方向箭头 + * */ + fun generateDirectReferenceLine(renderEntity: RenderEntity, direction: String = "") { + // 根据数据或angle计算方向对应的角度和偏移量 + val geometry = renderEntity.wkt + var isReverse = false // 是否为逆向 + if (direction.isNotEmpty()) { + val paramDirections = direction.split("=") + if (paramDirections.size>=2 && renderEntity.properties[paramDirections[0].trim()] == paramDirections[1].trim()) { + isReverse = true; + } + } + var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 + var point = Coordinate(geometry?.coordinate) + if (Geometry.TYPENAME_POINT == geometry?.geometryType) { + point = Coordinate(geometry?.coordinate) + var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! + if (isReverse) { + angle += 180 + } + radian = Math.toRadians(angle) + } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { + var coordinates = geometry.coordinates + if (isReverse) { + coordinates = coordinates.reversedArray() + } + val p1: Coordinate = coordinates.get(coordinates.size - 2) + val p2: Coordinate = coordinates.get(coordinates.size - 1) + // 计算线段的方向 + radian = Angle.angle(p1, p2) + point = p2 + } + + // 计算偏移距离 + val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) + val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) + + val coorEnd = Coordinate(point.getX() + dy, point.getY() - dx) + + val angleReference = ReferenceEntity() + angleReference.renderEntityId = renderEntity.id + angleReference.name = "${renderEntity.name}参考方向" + angleReference.table = renderEntity.table + // 与原有方向指向平行的线 + angleReference.geometry = GeometryTools.createLineString(arrayOf(point, coorEnd)).toString() + angleReference.properties["qi_table"] = renderEntity.table + angleReference.properties["type"] = "angle" + Realm.getDefaultInstance().insert(angleReference) } fun addAngleFromGeometry(renderEntity: RenderEntity): String { @@ -143,6 +230,7 @@ class ImportPreProcess { } } + /** * 自动生成普通交限的参考数据 * */ @@ -191,6 +279,58 @@ class ImportPreProcess { Realm.getDefaultInstance().insert(angleReference) } + /** + * 自动生成电子眼的参考数据 + * */ + fun generateElectronicEyeRerference(renderEntity: RenderEntity) { + // 获取当前renderEntity的geometry + val geometry = renderEntity.wkt + var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 + var point = Coordinate(geometry?.coordinate) + if (Geometry.TYPENAME_POINT == geometry?.geometryType) { + var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! + radian = Math.toRadians(angle) + } + + // 计算偏移距离 + val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) + val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) + + // 计算偏移后的点 + val pointTranS = + GeoPoint(point.getY() - dx, point.getX() + dy) // 向右偏移的点 + + // 计算与原有方向平行的终点坐标 + val pointTranE = GeoPoint(pointTranS.latitude + dy, pointTranS.longitude + dx) + + renderEntity.geometry = GeometryTools.createGeometry(pointTranS).toString() + + // 记录参考数据,绘制电子眼方向 + val startEndReference = ReferenceEntity() + startEndReference.renderEntityId = renderEntity.id + startEndReference.name = "电子眼参考线" + startEndReference.table = renderEntity.table + // 起终点坐标组成的线 + startEndReference.geometry = GeometryTools.createLineString(listOf(GeoPoint(point.y, point.x), pointTranS)).toString() + startEndReference.properties["qi_table"] = renderEntity.table + startEndReference.properties["type"] = "s_2_e" + Realm.getDefaultInstance().insert(startEndReference) + + val angleReference = ReferenceEntity() + angleReference.renderEntityId = renderEntity.id + angleReference.name = "电子眼参考方向" + angleReference.table = renderEntity.table + // 与原有方向指向平行的线 + angleReference.geometry = GeometryTools.createLineString(listOf(pointTranS, pointTranE)).toString() + angleReference.properties["qi_table"] = renderEntity.table + angleReference.properties["type"] = "angle" + Realm.getDefaultInstance().insert(angleReference) + } + + + /** + * 生成默认道路名数据 + * */ fun generateRoadName(renderEntity: RenderEntity) { // LinkName的真正名称数据,是保存在properties的shapeList中的,因此需要解析shapeList数据 var shape :JSONObject? = null @@ -217,4 +357,39 @@ class ImportPreProcess { renderEntity.properties["name"] = "" } } + + /** + * 生成电子眼对应的渲染名称 + * */ + fun generateElectronName(renderEntity: RenderEntity) { + // 解析电子眼的kind,将其转换为渲染的简要名称 + var shape :JSONObject? = null + if (renderEntity.properties.containsKey("kind")) { + renderEntity.properties["name"] = code2NameMap.electronEyeKindMap[renderEntity.properties["kind"].toString().toInt()] + } else { + renderEntity.properties["name"] = "" + } + } + + /** + * 生成默认路口数据的参考数据 + * */ + fun generateIntersectionReference(renderEntity: RenderEntity) { + // 路口数据的其他点位,是保存在nodeList对应的数组下 + if (renderEntity.properties.containsKey("nodeList")) { + val nodeListJsonArray: JSONArray = JSONArray(renderEntity.properties["nodeList"]) + for (i in 0 until nodeListJsonArray.length()) { + val nodeJSONObject = nodeListJsonArray.getJSONObject(i) + val intersectionReference = ReferenceEntity() + intersectionReference.renderEntityId = renderEntity.id + intersectionReference.name = "${renderEntity.name}参考点" + intersectionReference.table = renderEntity.table + // 与原有方向指向平行的线 + intersectionReference.geometry = GeometryTools.createGeometry(nodeJSONObject["geometry"].toString()).toString() + intersectionReference.properties["qi_table"] = renderEntity.table + intersectionReference.properties["type"] = "node" + Realm.getDefaultInstance().insert(intersectionReference) + } + } + } } \ No newline at end of file diff --git a/collect-library/src/main/assets/editormarker.xml b/collect-library/src/main/assets/editormarker.xml index fadfe6ab..e4be6b84 100644 --- a/collect-library/src/main/assets/editormarker.xml +++ b/collect-library/src/main/assets/editormarker.xml @@ -174,7 +174,8 @@ - + @@ -1799,13 +1800,41 @@ symbol-width="76"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java index e0855bb1..44271835 100644 --- a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java +++ b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java @@ -293,7 +293,7 @@ public class GeometryTools { * @param coords [] * @return Geometry */ - public LineString createLineString(Coordinate[] coords) { + public static LineString createLineString(Coordinate[] coords) { LineString lineString = null; GeometryFactory factory = new GeometryFactory(); lineString = factory.createLineString(coords); diff --git a/vtm b/vtm index 1ee201a4..c6ba77aa 160000 --- a/vtm +++ b/vtm @@ -1 +1 @@ -Subproject commit 1ee201a41f78f169873848209a3f3bdac36f185a +Subproject commit c6ba77aa0eb90a84fb19377706eb6792ec4a42b6 From e9af1785f8709fd56530f76e4e62f93b0cd8f19c Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Sun, 25 Jun 2023 16:49:25 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=99=AE=E9=80=9A?= =?UTF-8?q?=E4=BA=A4=E9=99=90=E5=85=A5=E5=BA=93=E8=A7=84=E5=88=99=EF=BC=8C?= =?UTF-8?q?=E9=A6=96=E5=B0=BE=E7=9B=B8=E6=8E=A5=E6=95=B0=E6=8D=AE=E4=B8=8D?= =?UTF-8?q?=E5=85=A5=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/omdb_config.json | 6 +++ .../com/navinfo/omqs/bean/ImportConfig.kt | 17 +++++-- .../com/navinfo/omqs/db/ImportOMDBHelper.kt | 51 ++++++++++--------- .../com/navinfo/omqs/db/ImportPreCacheData.kt | 5 ++ .../com/navinfo/omqs/db/ImportPreProcess.kt | 18 +++++++ .../personalcenter/PersonalCenterFragment.kt | 2 +- .../src/main/assets/editormarker.xml | 2 +- 7 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/com/navinfo/omqs/db/ImportPreCacheData.kt diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index 0800ec23..db3273a8 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -171,6 +171,12 @@ "code": 4006, "name": "普通交限", "transformer": [ + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "checkCircleRoad()" + }, { "k": "geometry", "v": "~", diff --git a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt index 5a8e099e..1d74d315 100644 --- a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt +++ b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt @@ -13,7 +13,7 @@ class ImportConfig { var checked : Boolean = true val preProcess: ImportPreProcess = ImportPreProcess() - fun transformProperties(renderEntity: RenderEntity): RenderEntity { + fun transformProperties(renderEntity: RenderEntity): RenderEntity? { val transformList = tableMap[renderEntity.code.toString()]?.transformer if (transformList.isNullOrEmpty()) { return renderEntity @@ -31,6 +31,7 @@ class ImportConfig { // 如果key和value都为空,说明当前数据需要增加一个新字段 if (key.isNullOrEmpty()&&value.isNullOrEmpty()&&!renderEntity.properties.containsKey(keylib)) { renderEntity.properties[keylib] = valuelib + continue } // 开始解析key和value,并对数据进行匹配 m@ for (k in processKeyOrValue(key)) { @@ -54,7 +55,12 @@ class ImportConfig { callByParams[methodParams[index+1]] = value } } - method.callBy(callByParams) + when(val result = method.callBy(callByParams)) { // 如果方法返回的数据类型是boolean,且返回为false,则该数据不处理 + is Boolean -> + if (!result) { + return null + } + } } else { renderEntity.properties[keylib] = valuelib } @@ -77,7 +83,12 @@ class ImportConfig { callByParams[methodParams[index+1]] = value } } - method.callBy(callByParams) + when(val result = method.callBy(callByParams)) { + is Boolean -> + if (!result) { + return null + } + } } else { renderEntity.properties[keylib] = valuelib } diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt index ae976c3c..64ac2675 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt @@ -146,7 +146,7 @@ class ImportOMDBHelper @AssistedInject constructor( it.name == currentConfig.table } - val listResult = mutableListOf>() + val listResult = mutableListOf() currentConfig?.let { val list = FileIOUtils.readFile2List(txtFile, "UTF-8") Log.d("ImportOMDBHelper", "开始解析:${txtFile?.name}") @@ -159,33 +159,38 @@ class ImportOMDBHelper @AssistedInject constructor( map["qi_table"] = currentConfig.table map["qi_name"] = currentConfig.name map["qi_code"] = if (currentConfig.code == 0) currentConfig.code else currentEntry.key - listResult.add(map) + + // 先查询这个mesh下有没有数据,如果有则跳过即可 + // val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst() + val renderEntity = RenderEntity() + renderEntity.code = map["qi_code"].toString().toInt() + renderEntity.name = map["qi_name"].toString() + renderEntity.table = map["qi_table"].toString() + // 其他数据插入到Properties中 + renderEntity.geometry = map["geometry"].toString() + for ((key, value) in map) { + when (value) { + is String -> renderEntity.properties.put(key, value) + is Int -> renderEntity.properties.put(key, value.toInt().toString()) + is Double -> renderEntity.properties.put(key, value.toDouble().toString()) + else -> renderEntity.properties.put(key, value.toString()) + } + } + listResult.add(renderEntity) + // 对renderEntity做预处理后再保存 + val resultEntity = importConfig.transformProperties(renderEntity) + if (resultEntity!=null) { + Realm.getDefaultInstance().insert(renderEntity) + } } } } - for (map in listResult) { // 每一个map就是Realm的一条数据 - // 先查询这个mesh下有没有数据,如果有则跳过即可 -// val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst() - val renderEntity = RenderEntity() - renderEntity.code = map["qi_code"].toString().toInt() - renderEntity.name = map["qi_name"].toString() - renderEntity.table = map["qi_table"].toString() - // 其他数据插入到Properties中 - renderEntity.geometry = map["geometry"].toString() - for ((key, value) in map) { - when (value) { - is String -> renderEntity.properties.put(key, value) - is Int -> renderEntity.properties.put(key, value.toInt().toString()) - is Double -> renderEntity.properties.put(key, value.toDouble().toString()) - else -> renderEntity.properties.put(key, value.toString()) - } - } - // 对renderEntity做预处理后再保存 - importConfig.transformProperties(renderEntity) - Realm.getDefaultInstance().copyToRealm(renderEntity) - } // 1个文件发送一次flow流 emit("${index + 1}/${importConfig.tableMap.size}") + // 如果当前解析的是OMDB_RD_LINK数据,将其缓存在预处理类中,以便后续处理其他要素时使用 + if (currentConfig.table == "OMDB_RD_LINK") { + importConfig.preProcess.cacheRdLink = listResult.associateBy { it.properties["linkPid"] } + } } Realm.getDefaultInstance().commitTransaction() } catch (e: Exception) { diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportPreCacheData.kt b/app/src/main/java/com/navinfo/omqs/db/ImportPreCacheData.kt new file mode 100644 index 00000000..2eacb95f --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/db/ImportPreCacheData.kt @@ -0,0 +1,5 @@ +package com.navinfo.omqs.db + +class ImportPreCacheData { + +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt index 3f2d8749..f556e19c 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt @@ -1,5 +1,6 @@ package com.navinfo.omqs.db +import android.util.Log import com.navinfo.collect.library.data.entity.ReferenceEntity import com.navinfo.collect.library.data.entity.RenderEntity import com.navinfo.collect.library.utils.GeometryTools @@ -14,6 +15,23 @@ import org.oscim.core.GeoPoint class ImportPreProcess { val code2NameMap = Code2NameMap() + lateinit var cacheRdLink: Map + + fun checkCircleRoad(renderEntity: RenderEntity): Boolean { + val linkInId = renderEntity.properties["linkIn"] + val linkOutId = renderEntity.properties["linkOut"] + // 根据linkIn和linkOut获取对应的link数据 + val linkInEntity = cacheRdLink[linkInId] + val linkOutEntity = cacheRdLink[linkOutId] + Log.d("checkCircleRoad", "LinkInEntity: ${linkInId}- ${linkInEntity?.properties?.get("snodePid")},LinkOutEntity: ${linkOutId}- ${linkOutEntity?.properties?.get("enodePid")}") + // 查询linkIn的sNode和linkOut的eNode是否相同,如果相同,认为数据是环形路口,返回false + if (linkInEntity!=null&&linkOutEntity!=null) { + if ((linkInEntity.properties["snodePid"] == linkOutEntity.properties["enodePid"]) || linkInEntity.properties["enodePid"] == linkOutEntity.properties["snodePid"] + || linkInEntity.properties["snodePid"] == linkOutEntity.properties["snodePid"]|| linkInEntity.properties["enodePid"] == linkOutEntity.properties["enodePid"]) + return false + } + return true + } /** * 计算指定数据指定方向的坐标 * @param direction 判断当前数据是否为逆向,给定的应该是一个a=b的表达式,a为对应的properties的key,b为对应的值 diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt index df128d20..69881185 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt @@ -112,7 +112,7 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) : viewModel.readRealmData() // 定位到指定位置 niMapController.mMapView.vtmMap.animator() - .animateTo(GeoPoint( 39.80392140200183, 116.51446703352337 )) + .animateTo(GeoPoint( 39.80130797136839, 116.51808677349096 )) } // R.id.personal_center_menu_task_list -> { // findNavController().navigate(R.id.TaskManagerFragment) diff --git a/collect-library/src/main/assets/editormarker.xml b/collect-library/src/main/assets/editormarker.xml index e4be6b84..6348342d 100644 --- a/collect-library/src/main/assets/editormarker.xml +++ b/collect-library/src/main/assets/editormarker.xml @@ -1804,7 +1804,7 @@ - + From 3d4d6c13a7c2e8ad47831702f5faf6baa15b6d97 Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Sun, 25 Jun 2023 17:12:02 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=E6=B3=A8=E9=87=8A=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/assets/editormarker.xml | 148 +++++++++--------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/collect-library/src/main/assets/editormarker.xml b/collect-library/src/main/assets/editormarker.xml index 6348342d..543f0a22 100644 --- a/collect-library/src/main/assets/editormarker.xml +++ b/collect-library/src/main/assets/editormarker.xml @@ -1479,83 +1479,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + From 8551ce43a7665ffadf8dc2bf233cfa1b05808634 Mon Sep 17 00:00:00 2001 From: xiaoyan Date: Mon, 26 Jun 2023 14:56:29 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E5=AE=8C=E5=96=84=E8=B7=AF=E5=8F=A3?= =?UTF-8?q?=E5=92=8C=E7=94=B5=E5=AD=90=E7=9C=BC=E6=B8=B2=E6=9F=93=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/omdb_config.json | 8 +- .../com/navinfo/omqs/bean/ImportConfig.kt | 14 ++- .../com/navinfo/omqs/db/ImportPreProcess.kt | 108 ++---------------- .../omqs/ui/activity/map/MainActivity.kt | 2 +- .../personalcenter/PersonalCenterFragment.kt | 2 +- .../src/main/assets/editormarker.xml | 6 +- 6 files changed, 23 insertions(+), 117 deletions(-) diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index db3273a8..a211f51e 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -224,7 +224,7 @@ "k": "geometry", "v": "~", "klib": "geometry", - "vlib": "generateDirectReferenceLine()" + "vlib": "generateDirectReferenceLine(direct=3)" }, { "k": "geometry", @@ -239,12 +239,6 @@ "code": 4022, "name": "交通灯", "transformer": [ - { - "k": "angle", - "v": "~", - "klib": "angle", - "vlib": "0" - } ] }, "4601":{ diff --git a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt index 1d74d315..5c6683b2 100644 --- a/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt +++ b/app/src/main/java/com/navinfo/omqs/bean/ImportConfig.kt @@ -38,7 +38,7 @@ class ImportConfig { if (renderEntity.properties.containsKey(k)) { // json配置的key可以匹配到数据 for (v in processKeyOrValue(value)) { if ("~" == v ) { // ~符可以匹配任意元素 - if (valuelib.endsWith("()")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 + if (valuelib.endsWith(")")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 // 获取方法名 val methodName = valuelib.substringBefore("(") // 获取参数 @@ -51,8 +51,9 @@ class ImportConfig { methodParams[1] to renderEntity ) for ((index, value) in params.withIndex()) { - if (methodParams.size>index+1) { - callByParams[methodParams[index+1]] = value + // 前2个参数确定为对象本身和RenderEntity,因此自定义参数从index+2开始设置 + if (methodParams.size>index+2) { + callByParams[methodParams[index+2]] = value } } when(val result = method.callBy(callByParams)) { // 如果方法返回的数据类型是boolean,且返回为false,则该数据不处理 @@ -66,7 +67,7 @@ class ImportConfig { } break@m } else if (renderEntity.properties[k] == v) { // 完全匹配 - if (valuelib.endsWith("()")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 + if (valuelib.endsWith(")")) { // 以()结尾,说明该value配置是一个function,需要通过反射调用指定方法 // 获取方法名 val methodName = valuelib.substringBefore("(") // 获取参数 @@ -79,8 +80,9 @@ class ImportConfig { methodParams[1] to renderEntity ) for ((index, value) in params.withIndex()) { - if (methodParams.size>index+1) { - callByParams[methodParams[index+1]] = value + // 前2个参数确定为对象本身和RenderEntity,因此自定义参数从index+2开始设置 + if (methodParams.size>index+2) { + callByParams[methodParams[index+2]] = value } } when(val result = method.callBy(callByParams)) { diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt index f556e19c..de475584 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt @@ -26,7 +26,7 @@ class ImportPreProcess { Log.d("checkCircleRoad", "LinkInEntity: ${linkInId}- ${linkInEntity?.properties?.get("snodePid")},LinkOutEntity: ${linkOutId}- ${linkOutEntity?.properties?.get("enodePid")}") // 查询linkIn的sNode和linkOut的eNode是否相同,如果相同,认为数据是环形路口,返回false if (linkInEntity!=null&&linkOutEntity!=null) { - if ((linkInEntity.properties["snodePid"] == linkOutEntity.properties["enodePid"]) || linkInEntity.properties["enodePid"] == linkOutEntity.properties["snodePid"] + if (linkInEntity.properties["snodePid"] == linkOutEntity.properties["enodePid"] || linkInEntity.properties["enodePid"] == linkOutEntity.properties["snodePid"] || linkInEntity.properties["snodePid"] == linkOutEntity.properties["snodePid"]|| linkInEntity.properties["enodePid"] == linkOutEntity.properties["enodePid"]) return false } @@ -48,11 +48,13 @@ class ImportPreProcess { isReverse = true; } } - if (Geometry.TYPENAME_POINT == geometry?.geometryType) { + if (Geometry.TYPENAME_POINT == geometry?.geometryType) { // angle为与正北方向的顺时针夹角 var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! if (isReverse) { angle += 180 } + // angle角度为与正北方向的顺时针夹角,将其转换为与X轴正方向的逆时针夹角,即为正东方向的夹角 + angle=(450-angle)%360 radian = Math.toRadians(angle) } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { var coordinates = geometry.coordinates @@ -99,6 +101,8 @@ class ImportPreProcess { if (isReverse) { angle += 180 } + // angle角度为与正北方向的顺时针夹角,将其转换为与X轴正方向的逆时针夹角,即为正东方向的夹角 + angle=(450-angle)%360 radian = Math.toRadians(angle) } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { var coordinates = geometry.coordinates @@ -169,6 +173,8 @@ class ImportPreProcess { if (isReverse) { angle += 180 } + // angle角度为与正北方向的顺时针夹角,将其转换为与X轴正方向的逆时针夹角,即为正东方向的夹角 + angle=(450-angle)%360 radian = Math.toRadians(angle) } else if (Geometry.TYPENAME_LINESTRING == geometry?.geometryType) { var coordinates = geometry.coordinates @@ -186,7 +192,7 @@ class ImportPreProcess { val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) - val coorEnd = Coordinate(point.getX() + dy, point.getY() - dx) + val coorEnd = Coordinate(point.getX() + dx, point.getY() + dy) val angleReference = ReferenceEntity() angleReference.renderEntityId = renderEntity.id @@ -249,102 +255,6 @@ class ImportPreProcess { } - /** - * 自动生成普通交限的参考数据 - * */ - fun generateRestrictionRerference(renderEntity: RenderEntity) { - // 获取当前renderEntity的geometry - val geometry = renderEntity.wkt - var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 - var point = Coordinate(geometry?.coordinate) - if (Geometry.TYPENAME_POINT == geometry?.geometryType) { - var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! - radian = Math.toRadians(angle) - } - - // 计算偏移距离 - val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) - val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) - - // 计算偏移后的点 - val pointTranS = - GeoPoint(point.getY() - dx, point.getX() + dy) // 向右偏移的点 - - // 计算与原有方向平行的终点坐标 - val pointTranE = GeoPoint(pointTranS.latitude + dy, pointTranS.longitude + dx) - - renderEntity.geometry = GeometryTools.createGeometry(pointTranS).toString() - - // 将这个点记录在数据中 - val startEndReference = ReferenceEntity() - startEndReference.renderEntityId = renderEntity.id - startEndReference.name = "普通交限参考线" - startEndReference.table = renderEntity.table - // 起终点坐标组成的线 - startEndReference.geometry = GeometryTools.createLineString(listOf(GeoPoint(point.y, point.x), pointTranS)).toString() - startEndReference.properties["qi_table"] = renderEntity.table - startEndReference.properties["type"] = "s_2_e" - Realm.getDefaultInstance().insert(startEndReference) - - val angleReference = ReferenceEntity() - angleReference.renderEntityId = renderEntity.id - angleReference.name = "普通交限参考方向" - angleReference.table = renderEntity.table - // 与原有方向指向平行的线 - angleReference.geometry = GeometryTools.createLineString(listOf(pointTranS, pointTranE)).toString() - angleReference.properties["qi_table"] = renderEntity.table - angleReference.properties["type"] = "angle" - Realm.getDefaultInstance().insert(angleReference) - } - - /** - * 自动生成电子眼的参考数据 - * */ - fun generateElectronicEyeRerference(renderEntity: RenderEntity) { - // 获取当前renderEntity的geometry - val geometry = renderEntity.wkt - var radian = 0.0 // geometry的角度,如果是点,获取angle,如果是线,获取最后两个点的方向 - var point = Coordinate(geometry?.coordinate) - if (Geometry.TYPENAME_POINT == geometry?.geometryType) { - var angle = if(renderEntity?.properties?.get("angle") == null) 0.0 else renderEntity?.properties?.get("angle")?.toDouble()!! - radian = Math.toRadians(angle) - } - - // 计算偏移距离 - val dx: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.sin(radian) - val dy: Double = GeometryTools.convertDistanceToDegree(3.0, geometry?.coordinate?.y!!) * Math.cos(radian) - - // 计算偏移后的点 - val pointTranS = - GeoPoint(point.getY() - dx, point.getX() + dy) // 向右偏移的点 - - // 计算与原有方向平行的终点坐标 - val pointTranE = GeoPoint(pointTranS.latitude + dy, pointTranS.longitude + dx) - - renderEntity.geometry = GeometryTools.createGeometry(pointTranS).toString() - - // 记录参考数据,绘制电子眼方向 - val startEndReference = ReferenceEntity() - startEndReference.renderEntityId = renderEntity.id - startEndReference.name = "电子眼参考线" - startEndReference.table = renderEntity.table - // 起终点坐标组成的线 - startEndReference.geometry = GeometryTools.createLineString(listOf(GeoPoint(point.y, point.x), pointTranS)).toString() - startEndReference.properties["qi_table"] = renderEntity.table - startEndReference.properties["type"] = "s_2_e" - Realm.getDefaultInstance().insert(startEndReference) - - val angleReference = ReferenceEntity() - angleReference.renderEntityId = renderEntity.id - angleReference.name = "电子眼参考方向" - angleReference.table = renderEntity.table - // 与原有方向指向平行的线 - angleReference.geometry = GeometryTools.createLineString(listOf(pointTranS, pointTranE)).toString() - angleReference.properties["qi_table"] = renderEntity.table - angleReference.properties["type"] = "angle" - Realm.getDefaultInstance().insert(angleReference) - } - /** * 生成默认道路名数据 diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt index c46932f7..d1a82fbd 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt @@ -230,7 +230,7 @@ class MainActivity : BaseActivity() { } //监听地图中点变化 viewModel.liveDataCenterPoint.observe(this) { - Log.e("qj", "${it.longitude}") +// Log.e("qj", "${it.longitude}") try { if (it != null && it.longitude != null && it.latitude != null) { binding.mainActivityGeometry.text = "经纬度:${ diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt index 69881185..3c687be0 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt @@ -112,7 +112,7 @@ class PersonalCenterFragment(private var backListener: (() -> Unit?)? = null) : viewModel.readRealmData() // 定位到指定位置 niMapController.mMapView.vtmMap.animator() - .animateTo(GeoPoint( 39.80130797136839, 116.51808677349096 )) + .animateTo(GeoPoint( 39.799624915997725, 116.51407667184905 )) } // R.id.personal_center_menu_task_list -> { // findNavController().navigate(R.id.TaskManagerFragment) diff --git a/collect-library/src/main/assets/editormarker.xml b/collect-library/src/main/assets/editormarker.xml index 543f0a22..29d2d7b1 100644 --- a/collect-library/src/main/assets/editormarker.xml +++ b/collect-library/src/main/assets/editormarker.xml @@ -1809,6 +1809,7 @@ + - - - + +