feat: 增加路口渲染

This commit is contained in:
xiaoyan 2023-06-25 10:11:24 +08:00
parent f6346acb89
commit a5e964efbb
7 changed files with 385 additions and 43 deletions

View File

@ -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":{

View File

@ -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<String> = 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<KParameter, Any>(
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<String> = 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<KParameter, Any>(
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
}

View File

@ -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 "限时长",
)
}

View File

@ -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的keyb为对应的值
* */
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<Coordinate>(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)
}
}
}
}

View File

@ -174,7 +174,8 @@
<!-- omdb -->
<style-line id="boundaryType" stipple-width="0.1" width="0.1" />
<style-line id="s2e" dasharray="1,1" repeat-gap="3" repeat-start="0" stroke="#14582c"
width="0.1" />
<!--###### ASSIGNMENT ######-->
<m e="way" k="natural" v="issea|sea">
@ -1799,13 +1800,41 @@
symbol-width="76"></symbol>
</m>
<m k="type" v="s_2_e">
<line dasharray="1,1" repeat-gap="3" repeat-start="0" stroke="#14582c"
width="0.1" />
<line use="s2e" />
</m>
</m>
<!--电子眼-->
<m v="OMDB_RESTRICTION">
<m k="angle">
<symbol repeat="false" repeat-start="0" rotate="false"
src="assets:symbols/volcano.svg" symbol-height="69" symbol-width="69"></symbol>
</m>
<m k="type" v="angle">
<symbol repeat="false" repeat-gap="2000" repeat-start="0" rotate="true"
src="assets:omdb/icon_arrow_right.svg" symbol-height="76"
symbol-width="76"></symbol>
</m>
<m k="type" v="s_2_e">
<line use="s2e" />
</m>
<text use="road" dy="30"></text>
</m>
<!-- 路口 -->
<m v="OMDB_INTERSECTION">
<m k="type" v="node">
<symbol src="assets:symbols/dot_blue_dark.svg"></symbol>
</m>
<m k="intersectionPid">
<symbol src="assets:symbols/dot_magenta.svg"></symbol>
</m>
</m>
<!-- 道路名 -->
<m v="OMDB_LINK_NAME">
<text use="road"></text>
</m>
<!-- 车信 -->
<m v="OMDB_LANEINFO">
<text use="road"></text>
</m>
</m>
</rendertheme>

View File

@ -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);

2
vtm

@ -1 +1 @@
Subproject commit 1ee201a41f78f169873848209a3f3bdac36f185a
Subproject commit c6ba77aa0eb90a84fb19377706eb6792ec4a42b6