Commit f33024a4cd6ca3fe50e32220f54cd6b9fa3f4619

Authored by 张志伟
1 parent 2e5e1e1b

封装地图路线规划

lib/android/src/main/java/cn/feewee/amap3d/AMap3DPackage.kt
... ... @@ -5,6 +5,7 @@ import com.facebook.react.bridge.NativeModule
5 5 import com.facebook.react.bridge.ReactApplicationContext
6 6 import com.facebook.react.uimanager.ViewManager
7 7 import cn.feewee.amap3d.map_view.*
  8 +import cn.feewee.amap3d.map_view.route.DrivingRouteManager
8 9 import cn.feewee.amap3d.modules.SdkModule
9 10 import cn.feewee.amap3d.modules.AMapGeolocationModule
10 11  
... ... @@ -24,7 +25,8 @@ class AMap3DPackage : ReactPackage {
24 25 PolygonManager(),
25 26 CircleManager(),
26 27 HeatMapManager(),
27   - MultiPointManager()
  28 + MultiPointManager(),
  29 + DrivingRouteManager()
28 30 )
29 31 }
30 32 }
... ...
lib/android/src/main/java/cn/feewee/amap3d/Utils.kt
1 1 package cn.feewee.amap3d
2 2  
  3 +import android.content.Context
3 4 import android.content.res.Resources
4 5 import android.graphics.Bitmap
5 6 import android.graphics.Point
6 7 import android.location.Location
7 8 import android.view.View
  9 +import android.widget.Toast
8 10 import com.amap.api.maps.model.*
  11 +import com.amap.api.services.core.AMapException
  12 +import com.amap.api.services.core.LatLonPoint
9 13 import com.facebook.drawee.backends.pipeline.Fresco
10 14 import com.facebook.imagepipeline.common.ResizeOptions
11 15 import com.facebook.imagepipeline.request.BasePostprocessor
... ... @@ -15,100 +19,236 @@ import com.facebook.react.bridge.ReadableArray
15 19 import com.facebook.react.bridge.ReadableMap
16 20 import com.facebook.react.bridge.WritableMap
17 21 import com.facebook.react.views.imagehelper.ImageSource
  22 +import kotlin.math.asin
  23 +import kotlin.math.cos
  24 +import kotlin.math.sin
  25 +import kotlin.math.sqrt
18 26  
19 27 fun Float.toPx(): Int {
20   - return (this * Resources.getSystem().displayMetrics.density).toInt()
  28 + return (this * Resources.getSystem().displayMetrics.density).toInt()
21 29 }
22 30  
23 31 fun Int.toPx(): Int {
24   - return (this * Resources.getSystem().displayMetrics.density).toInt()
  32 + return (this * Resources.getSystem().displayMetrics.density).toInt()
25 33 }
26 34  
27 35 fun ReadableMap.toPoint(): Point {
28   - return Point(getDouble("x").toFloat().toPx(), getDouble("y").toFloat().toPx())
  36 + return Point(getDouble("x").toFloat().toPx(), getDouble("y").toFloat().toPx())
29 37 }
30 38  
31 39 fun ReadableMap.toLatLng(): LatLng {
32   - return LatLng(getDouble("latitude"), getDouble("longitude"))
  40 + return LatLng(getDouble("latitude"), getDouble("longitude"))
  41 +}
  42 +
  43 +fun ReadableMap.toLatLonPoint(): LatLonPoint {
  44 + return LatLonPoint(getDouble("latitude"), getDouble("longitude"))
33 45 }
34 46  
35 47 fun ReadableArray.toLatLngList(): List<LatLng> {
36   - return (0 until size()).map {
37   - // @todo 暂时兼容 0.63
38   - @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
39   - getMap(it)!!.toLatLng()
40   - }
  48 + return (0 until size()).map {
  49 + getMap(it)!!.toLatLng()
  50 + }
41 51 }
42 52  
43 53 fun LatLng.toJson(): WritableMap {
44   - return Arguments.createMap().apply {
45   - putDouble("latitude", latitude)
46   - putDouble("longitude", longitude)
47   - }
  54 + return Arguments.createMap().apply {
  55 + putDouble("latitude", latitude)
  56 + putDouble("longitude", longitude)
  57 + }
48 58 }
49 59  
50 60 fun Poi.toJson(): WritableMap {
51   - return Arguments.createMap().apply {
52   - putMap("position", coordinate.toJson())
53   - putString("id", poiId)
54   - putString("name", name)
55   - }
  61 + return Arguments.createMap().apply {
  62 + putMap("position", coordinate.toJson())
  63 + putString("id", poiId)
  64 + putString("name", name)
  65 + }
56 66 }
57 67  
58 68 fun CameraPosition.toJson(): WritableMap {
59   - return Arguments.createMap().apply {
60   - putMap("target", target.toJson())
61   - putDouble("zoom", zoom.toDouble())
62   - putDouble("tilt", tilt.toDouble())
63   - putDouble("bearing", bearing.toDouble())
64   - }
  69 + return Arguments.createMap().apply {
  70 + putMap("target", target.toJson())
  71 + putDouble("zoom", zoom.toDouble())
  72 + putDouble("tilt", tilt.toDouble())
  73 + putDouble("bearing", bearing.toDouble())
  74 + }
65 75 }
66 76  
67 77 fun Location.toJson(): WritableMap {
68   - return Arguments.createMap().apply {
69   - putDouble("timestamp", time.toDouble())
70   - putMap("coords", Arguments.createMap().apply {
71   - putDouble("latitude", latitude)
72   - putDouble("longitude", longitude)
73   - putDouble("latitude", latitude)
74   - putDouble("accuracy", accuracy.toDouble())
75   - putDouble("heading", bearing.toDouble())
76   - putDouble("speed", speed.toDouble())
77   - })
78   - }
  78 + return Arguments.createMap().apply {
  79 + putDouble("timestamp", time.toDouble())
  80 + putMap("coords", Arguments.createMap().apply {
  81 + putDouble("latitude", latitude)
  82 + putDouble("longitude", longitude)
  83 + putDouble("latitude", latitude)
  84 + putDouble("accuracy", accuracy.toDouble())
  85 + putDouble("heading", bearing.toDouble())
  86 + putDouble("speed", speed.toDouble())
  87 + })
  88 + }
79 89 }
80 90  
81 91 fun LatLngBounds.toJson(): WritableMap {
82   - return Arguments.createMap().apply {
83   - putMap("southwest", southwest.toJson())
84   - putMap("northeast", northeast.toJson())
85   - }
  92 + return Arguments.createMap().apply {
  93 + putMap("southwest", southwest.toJson())
  94 + putMap("northeast", northeast.toJson())
  95 + }
86 96 }
87 97  
88 98 fun ReadableMap.getFloat(key: String): Float? {
89   - if (hasKey(key)) return getDouble(key).toFloat()
90   - return null
  99 + if (hasKey(key)) return getDouble(key).toFloat()
  100 + return null
91 101 }
92 102  
93 103 fun getEventTypeConstants(vararg list: String): Map<String, Any> {
94   - return list.associateWith { mapOf("phasedRegistrationNames" to mapOf("bubbled" to it)) }
  104 + return list.associateWith { mapOf("phasedRegistrationNames" to mapOf("bubbled" to it)) }
95 105 }
96 106  
97 107 fun View.fetchImage(source: ReadableMap, callback: (BitmapDescriptor) -> Unit) {
98   - val uri = ImageSource(context, source.getString("uri")).uri
99   - val request = ImageRequestBuilder.newBuilderWithSource(uri).let {
100   - it.postprocessor = object : BasePostprocessor() {
101   - override fun process(bitmap: Bitmap) {
102   - callback(BitmapDescriptorFactory.fromBitmap(bitmap))
103   - }
  108 + val uri = ImageSource(context, source.getString("uri")).uri
  109 + val request = ImageRequestBuilder.newBuilderWithSource(uri).let {
  110 + it.postprocessor = object : BasePostprocessor() {
  111 + override fun process(bitmap: Bitmap) {
  112 + callback(BitmapDescriptorFactory.fromBitmap(bitmap))
  113 + }
  114 + }
  115 + if (source.hasKey("width") && source.hasKey("height")) {
  116 + it.resizeOptions = ResizeOptions.forDimensions(
  117 + source.getInt("width").toPx(),
  118 + source.getInt("height").toPx()
  119 + )
  120 + }
  121 + it.build()
  122 + }
  123 + Fresco.getImagePipeline().fetchDecodedImage(request, this)
  124 +}
  125 +
  126 +/**
  127 + * 把LatLonPoint对象转化为LatLon对象
  128 + */
  129 +fun LatLonPoint.convertToLatLng(): LatLng {
  130 + return LatLng(latitude, longitude)
  131 +}
  132 +
  133 +/**
  134 + * 把LatLng对象转化为LatLonPoint对象
  135 + */
  136 +fun LatLng.convertToLatLonPoint(): LatLonPoint {
  137 + return LatLonPoint(latitude, longitude)
  138 +}
  139 +
  140 +/**
  141 + * 计算两点之间的距离
  142 + */
  143 +fun calculateDistance(start: LatLng, end: LatLng): Int {
  144 + var x1 = start.longitude
  145 + var y1 = start.latitude
  146 + var x2 = end.longitude
  147 + var y2 = end.latitude
  148 + val NF_pi = 0.01745329251994329 // 弧度 PI/180
  149 + x1 *= NF_pi
  150 + y1 *= NF_pi
  151 + x2 *= NF_pi
  152 + y2 *= NF_pi
  153 + val sinx1 = sin(x1)
  154 + val siny1 = sin(y1)
  155 + val cosx1 = cos(x1)
  156 + val cosy1 = cos(y1)
  157 + val sinx2 = sin(x2)
  158 + val siny2 = sin(y2)
  159 + val cosx2 = cos(x2)
  160 + val cosy2 = cos(y2)
  161 + val v1 = DoubleArray(3)
  162 + v1[0] = cosy1 * cosx1 - cosy2 * cosx2
  163 + v1[1] = cosy1 * sinx1 - cosy2 * sinx2
  164 + v1[2] = siny1 - siny2
  165 + val dist = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2])
  166 + return (asin(dist / 2) * 12742001.5798544).toInt()
  167 +}
  168 +
  169 +fun show(context: Context, info: String) {
  170 + Toast.makeText(context.applicationContext, info, Toast.LENGTH_LONG).show()
  171 +}
  172 +
  173 +fun show(context: Context, info: Int) {
  174 + Toast.makeText(context.applicationContext, info, Toast.LENGTH_LONG).show()
  175 +}
  176 +
  177 +fun showerror(context: Context, rCode: Int) {
  178 + fun logError(info: String, errorCode: Int) {
  179 + val sb = StringBuilder()
  180 + for (i in 0 until 80) {
  181 + sb.append("=")
  182 + }
  183 + print(sb.toString())
  184 + print(" 错误信息 ")
  185 + print(sb.toString())
  186 + print(info)
  187 + print("错误码: $errorCode")
  188 + print(" ")
  189 + print("如果需要更多信息,请根据错误码到以下地址进行查询")
  190 + print(" http://lbs.amap.com/api/android-sdk/guide/map-tools/error-code/")
  191 + print("如若仍无法解决问题,请将全部log信息提交到工单系统,多谢合作")
  192 + print(sb.toString())
104 193 }
105   - if (source.hasKey("width") && source.hasKey("height")) {
106   - it.resizeOptions = ResizeOptions.forDimensions(
107   - source.getInt("width").toPx(),
108   - source.getInt("height").toPx()
109   - )
  194 +
  195 + try {
  196 + when (rCode) {
  197 + 1001 -> throw AMapException(AMapException.AMAP_SIGNATURE_ERROR)
  198 + 1002 -> throw AMapException(AMapException.AMAP_INVALID_USER_KEY)
  199 + 1003 -> throw AMapException(AMapException.AMAP_SERVICE_NOT_AVAILBALE)
  200 + 1004 -> throw AMapException(AMapException.AMAP_DAILY_QUERY_OVER_LIMIT)
  201 + 1005 -> throw AMapException(AMapException.AMAP_ACCESS_TOO_FREQUENT)
  202 + 1006 -> throw AMapException(AMapException.AMAP_INVALID_USER_IP)
  203 + 1007 -> throw AMapException(AMapException.AMAP_INVALID_USER_DOMAIN)
  204 + 1008 -> throw AMapException(AMapException.AMAP_INVALID_USER_SCODE)
  205 + 1009 -> throw AMapException(AMapException.AMAP_USERKEY_PLAT_NOMATCH)
  206 + 1010 -> throw AMapException(AMapException.AMAP_IP_QUERY_OVER_LIMIT)
  207 + 1011 -> throw AMapException(AMapException.AMAP_NOT_SUPPORT_HTTPS)
  208 + 1012 -> throw AMapException(AMapException.AMAP_INSUFFICIENT_PRIVILEGES)
  209 + 1013 -> throw AMapException(AMapException.AMAP_USER_KEY_RECYCLED)
  210 + 1100 -> throw AMapException(AMapException.AMAP_ENGINE_RESPONSE_ERROR)
  211 + 1101 -> throw AMapException(AMapException.AMAP_ENGINE_RESPONSE_DATA_ERROR)
  212 + 1102 -> throw AMapException(AMapException.AMAP_ENGINE_CONNECT_TIMEOUT)
  213 + 1103 -> throw AMapException(AMapException.AMAP_ENGINE_RETURN_TIMEOUT)
  214 + 1200 -> throw AMapException(AMapException.AMAP_SERVICE_INVALID_PARAMS)
  215 + 1201 -> throw AMapException(AMapException.AMAP_SERVICE_MISSING_REQUIRED_PARAMS)
  216 + 1202 -> throw AMapException(AMapException.AMAP_SERVICE_ILLEGAL_REQUEST)
  217 + 1203 -> throw AMapException(AMapException.AMAP_SERVICE_UNKNOWN_ERROR)
  218 + 1800 -> throw AMapException(AMapException.AMAP_CLIENT_ERRORCODE_MISSSING)
  219 + 1801 -> throw AMapException(AMapException.AMAP_CLIENT_ERROR_PROTOCOL)
  220 + 1802 -> throw AMapException(AMapException.AMAP_CLIENT_SOCKET_TIMEOUT_EXCEPTION)
  221 + 1803 -> throw AMapException(AMapException.AMAP_CLIENT_URL_EXCEPTION)
  222 + 1804 -> throw AMapException(AMapException.AMAP_CLIENT_UNKNOWHOST_EXCEPTION)
  223 + 1806 -> throw AMapException(AMapException.AMAP_CLIENT_NETWORK_EXCEPTION)
  224 + 1900 -> throw AMapException(AMapException.AMAP_CLIENT_UNKNOWN_ERROR)
  225 + 1901 -> throw AMapException(AMapException.AMAP_CLIENT_INVALID_PARAMETER)
  226 + 1902 -> throw AMapException(AMapException.AMAP_CLIENT_IO_EXCEPTION)
  227 + 1903 -> throw AMapException(AMapException.AMAP_CLIENT_NULLPOINT_EXCEPTION)
  228 + 2000 -> throw AMapException(AMapException.AMAP_SERVICE_TABLEID_NOT_EXIST)
  229 + 2001 -> throw AMapException(AMapException.AMAP_ID_NOT_EXIST)
  230 + 2002 -> throw AMapException(AMapException.AMAP_SERVICE_MAINTENANCE)
  231 + 2003 -> throw AMapException(AMapException.AMAP_ENGINE_TABLEID_NOT_EXIST)
  232 + 2100 -> throw AMapException(AMapException.AMAP_NEARBY_INVALID_USERID)
  233 + 2101 -> throw AMapException(AMapException.AMAP_NEARBY_KEY_NOT_BIND)
  234 + 2200 -> throw AMapException(AMapException.AMAP_CLIENT_UPLOADAUTO_STARTED_ERROR)
  235 + 2201 -> throw AMapException(AMapException.AMAP_CLIENT_USERID_ILLEGAL)
  236 + 2202 -> throw AMapException(AMapException.AMAP_CLIENT_NEARBY_NULL_RESULT)
  237 + 2203 -> throw AMapException(AMapException.AMAP_CLIENT_UPLOAD_TOO_FREQUENT)
  238 + 2204 -> throw AMapException(AMapException.AMAP_CLIENT_UPLOAD_LOCATION_ERROR)
  239 + 3000 -> throw AMapException(AMapException.AMAP_ROUTE_OUT_OF_SERVICE)
  240 + 3001 -> throw AMapException(AMapException.AMAP_ROUTE_NO_ROADS_NEARBY)
  241 + 3002 -> throw AMapException(AMapException.AMAP_ROUTE_FAIL)
  242 + 3003 -> throw AMapException(AMapException.AMAP_OVER_DIRECTION_RANGE)
  243 + 4000 -> throw AMapException(AMapException.AMAP_SHARE_LICENSE_IS_EXPIRED)
  244 + 4001 -> throw AMapException(AMapException.AMAP_SHARE_FAILURE)
  245 + else -> {
  246 + Toast.makeText(context, "查询失败:$rCode", Toast.LENGTH_LONG).show()
  247 + logError("查询失败", rCode)
  248 + }
  249 + }
  250 + } catch (e: Exception) {
  251 + Toast.makeText(context.applicationContext, e.message, Toast.LENGTH_LONG).show()
  252 + e.message?.let { logError(it, rCode) }
110 253 }
111   - it.build()
112   - }
113   - Fresco.getImagePipeline().fetchDecodedImage(request, this)
114 254 }
115 255 \ No newline at end of file
... ...
lib/android/src/main/java/cn/feewee/amap3d/map_view/route/DrivingRoute.kt 0 → 100644
  1 +package cn.feewee.amap3d.map_view.route
  2 +
  3 +import android.content.Context
  4 +import android.graphics.Color
  5 +import android.widget.Toast
  6 +import cn.feewee.amap3d.*
  7 +import cn.feewee.amap3d.R
  8 +import com.amap.api.maps.AMap
  9 +import com.amap.api.maps.model.*
  10 +import com.amap.api.services.core.AMapException
  11 +import com.amap.api.services.route.*
  12 +import com.facebook.react.bridge.ReadableArray
  13 +
  14 +class DrivingRoute(context: Context) : RouteOverlay(context) {
  15 + private var drivePath: DrivePathV2? = null
  16 + private var throughPointList: List<LatLng> = emptyList()
  17 + private var isColorfulline = true
  18 + private var throughPointMarkerList: ArrayList<Marker> = ArrayList()
  19 + private var throughPointMarkerVisible = true
  20 + private var mPolylineOptions: PolylineOptions? = null
  21 + private var mPolylineOptionsColor: PolylineOptions? = null
  22 +
  23 + init {
  24 + try {
  25 + mRouteSearch = RouteSearchV2(context)
  26 + } catch (e: AMapException) {
  27 + e.printStackTrace()
  28 + }
  29 + }
  30 +
  31 + fun setThroughPointList(throughPoints: List<LatLng>) {
  32 + if (throughPoints.size > 6) {
  33 + throughPointList = throughPoints.take(6)
  34 + return
  35 + }
  36 + throughPointList = throughPoints
  37 + }
  38 +
  39 + fun setIsColorfulline(iscolorfulline: Boolean) {
  40 + isColorfulline = iscolorfulline
  41 + }
  42 +
  43 + fun setThroughPointMarkerVisible(visible: Boolean) {
  44 + try {
  45 + throughPointMarkerVisible = visible
  46 + if (this.throughPointMarkerList.isNotEmpty()) {
  47 + for (i in this.throughPointMarkerList.indices) {
  48 + this.throughPointMarkerList[i].isVisible = visible
  49 + }
  50 + }
  51 + } catch (e: Throwable) {
  52 + e.printStackTrace()
  53 + }
  54 + }
  55 +
  56 + override fun add(map: AMap) {
  57 + this.map = map
  58 + searchRouteResult()
  59 + }
  60 +
  61 + override fun remove() {
  62 + removeMarkerFromMap()
  63 + removeLineFromMap()
  64 + try {
  65 + if (throughPointMarkerList.size > 0) {
  66 + for (i in throughPointMarkerList.indices) {
  67 + throughPointMarkerList[i].remove()
  68 + }
  69 + throughPointMarkerList.clear()
  70 + }
  71 + } catch (e: Throwable) {
  72 + e.printStackTrace()
  73 + }
  74 + }
  75 +
  76 + private fun addToMap() {
  77 + initPolylineOptions()
  78 + if (getRouteWidth() == 0f || drivePath == null) {
  79 + return
  80 + }
  81 +
  82 + val mLatLngsOfPath = ArrayList<LatLng>()
  83 + val tmcs = ArrayList<TMC>()
  84 + val drivePaths = drivePath?.steps
  85 +
  86 + for (step in drivePaths!!) {
  87 + val latlonPoints = step.polyline
  88 + val tmclist = step.tmCs
  89 + tmcs.addAll(tmclist)
  90 + addDrivingStationMarkers(step, latlonPoints[0].convertToLatLng())
  91 + for (latlonpoint in latlonPoints) {
  92 + mPolylineOptions?.add(latlonpoint.convertToLatLng())
  93 + mLatLngsOfPath.add(latlonpoint.convertToLatLng())
  94 + }
  95 + }
  96 + addStartAndEndMarker()
  97 + addThroughPointMarker()
  98 + if (isColorfulline && tmcs.size > 0) {
  99 + colorWayUpdate(tmcs)
  100 + addPolyLine(mPolylineOptionsColor)
  101 + } else {
  102 + addPolyLine(mPolylineOptions)
  103 + }
  104 + }
  105 +
  106 + /**
  107 + * 初始化线段属性
  108 + */
  109 + private fun initPolylineOptions() {
  110 + mPolylineOptions = PolylineOptions()
  111 + .color(getRoadColor())
  112 + .setCustomTexture(getRoadLine())
  113 + .width(getRouteWidth())
  114 + }
  115 +
  116 + /**
  117 + * 根据不同的路段拥堵情况展示不同的颜色
  118 + *
  119 + * @param tmcSection
  120 + */
  121 + private fun colorWayUpdate(tmcSection: List<TMC>) {
  122 + var segmentTrafficStatus: TMC
  123 + mPolylineOptionsColor = PolylineOptions().width(getRouteWidth())
  124 + mPolylineOptionsColor?.add(tmcSection[0].polyline[0].convertToLatLng())
  125 +
  126 + val colorList: MutableList<Int> = ArrayList()
  127 + colorList.add(getRoadColor())
  128 + for (i in tmcSection.indices) {
  129 + segmentTrafficStatus = tmcSection[i]
  130 + val color: Int = getColor(segmentTrafficStatus.status)
  131 + val mployline = segmentTrafficStatus.polyline
  132 + for (j in 1 until mployline.size) {
  133 + mPolylineOptionsColor?.add(mployline[j].convertToLatLng())
  134 + colorList.add(color)
  135 + }
  136 + }
  137 + colorList.add(getRoadColor())
  138 + mPolylineOptionsColor?.colorValues(colorList)
  139 + }
  140 +
  141 + private fun getColor(status: String): Int {
  142 + return when (status) {
  143 + "畅通" -> {
  144 + Color.GREEN
  145 + }
  146 + "缓行" -> {
  147 + Color.YELLOW
  148 + }
  149 + "拥堵" -> {
  150 + Color.RED
  151 + }
  152 + "严重拥堵" -> {
  153 + Color.parseColor("#990033")
  154 + }
  155 + else -> {
  156 + Color.parseColor("#537edc")
  157 + }
  158 + }
  159 + }
  160 +
  161 + /**
  162 + * @param driveStep
  163 + * @param latLng
  164 + */
  165 + private fun addDrivingStationMarkers(driveStep: DriveStepV2, latLng: LatLng) {
  166 + addStationMarker(
  167 + MarkerOptions()
  168 + .position(latLng)
  169 + .title("\u65B9\u5411:" + driveStep.instruction + "\n\u9053\u8DEF:" + driveStep.road)
  170 + .snippet(driveStep.instruction).visible(nodeIconVisible)
  171 + .anchor(0.5f, 0.5f).icon(getDriveBit())
  172 + )
  173 + }
  174 +
  175 + /**
  176 + * 添加途经点marker
  177 + */
  178 + private fun addThroughPointMarker() {
  179 + if (throughPointList.isNotEmpty()) {
  180 + for (i in throughPointList.indices) {
  181 + val latLonPoint = throughPointList[i]
  182 + throughPointMarkerList.add(
  183 + map.addMarker(
  184 + MarkerOptions()
  185 + .position(latLonPoint)
  186 + .visible(throughPointMarkerVisible)
  187 + .icon(getThroughBit())
  188 + .title("\u9014\u7ECF\u70B9")
  189 + )
  190 + )
  191 + }
  192 + }
  193 + }
  194 +
  195 + override fun searchRouteResult() {
  196 + if (mRouteSearch == null) {
  197 + return
  198 + }
  199 + val fromAndTo = createFromAndTo() ?: return
  200 + try {
  201 + showProgressDialog()
  202 + val driveRouteResult = mRouteSearch!!.calculateDriveRoute(
  203 + RouteSearchV2.DriveRouteQuery(
  204 + fromAndTo,
  205 + RouteSearchV2.DrivingStrategy.DEFAULT,
  206 + throughPointList.map { r -> r.convertToLatLonPoint() },
  207 + null,
  208 + null
  209 + )
  210 + )
  211 + onDriveRouteSearched(driveRouteResult)
  212 + } catch (e: AMapException) {
  213 + dissmissProgressDialog()
  214 + showerror(context, e.errorCode)
  215 + }
  216 +
  217 + }
  218 +
  219 + private fun onDriveRouteSearched(result: DriveRouteResultV2) {
  220 + dissmissProgressDialog()
  221 + map.clear()
  222 + if (result.paths != null) {
  223 + if (result.paths.size > 0) {
  224 + drivePath = result.paths[0] ?: return
  225 + remove()
  226 + addToMap()
  227 + zoomToSpan()
  228 +
  229 + } else if (result.paths == null) {
  230 + show(context, R.string.no_result)
  231 + }
  232 + } else {
  233 + show(context, R.string.no_result)
  234 + }
  235 + }
  236 +
  237 +
  238 + fun searchRoute(args: ReadableArray?) {
  239 + val start = args?.getMap(0)?.toLatLonPoint()
  240 + val end = args?.getMap(1)?.toLatLonPoint()
  241 + val through = args?.getArray(2)?.toLatLngList()
  242 + if (start == null) {
  243 + Toast.makeText(context, "起点不能为空", Toast.LENGTH_LONG).show()
  244 + return
  245 + }
  246 + if (end == null) {
  247 + Toast.makeText(context, "终点不能为空", Toast.LENGTH_LONG).show()
  248 + return
  249 + }
  250 + setStartPoint(start)
  251 + setEndPoint(end)
  252 + if (through?.isNotEmpty() == true) {
  253 + setThroughPointList(through)
  254 + }
  255 + searchRouteResult()
  256 + }
  257 +
  258 +}
0 259 \ No newline at end of file
... ...
lib/android/src/main/java/cn/feewee/amap3d/map_view/route/DrivingRouteManager.kt 0 → 100644
  1 +package cn.feewee.amap3d.map_view.route
  2 +
  3 +import cn.feewee.amap3d.toLatLngList
  4 +import cn.feewee.amap3d.toLatLonPoint
  5 +import cn.feewee.amap3d.toPx
  6 +import com.facebook.react.bridge.ReadableArray
  7 +import com.facebook.react.bridge.ReadableMap
  8 +import com.facebook.react.uimanager.SimpleViewManager
  9 +import com.facebook.react.uimanager.ThemedReactContext
  10 +import com.facebook.react.uimanager.annotations.ReactProp
  11 +
  12 +@Suppress("unused")
  13 +class DrivingRouteManager : SimpleViewManager<DrivingRoute>() {
  14 + override fun getName(): String {
  15 + return "DrivingRoute"
  16 + }
  17 +
  18 + override fun createViewInstance(reactContext: ThemedReactContext): DrivingRoute {
  19 + return DrivingRoute(reactContext)
  20 + }
  21 +
  22 + companion object {
  23 + const val searchRoute = 1
  24 + }
  25 +
  26 + override fun getCommandsMap(): Map<String, Int> {
  27 + return mapOf("searchRoute" to searchRoute)
  28 + }
  29 +
  30 + override fun receiveCommand(route: DrivingRoute, commandId: Int, args: ReadableArray?) {
  31 + when (commandId) {
  32 + searchRoute -> route.searchRoute(args)
  33 + }
  34 + }
  35 +
  36 + @ReactProp(name = "startPoint")
  37 + fun setStart(route: DrivingRoute, startPoint: ReadableMap) {
  38 + route.setStartPoint(startPoint.toLatLonPoint())
  39 + }
  40 +
  41 + @ReactProp(name = "endPoint")
  42 + fun setEnd(route: DrivingRoute, endPoint: ReadableMap) {
  43 + route.setEndPoint(endPoint.toLatLonPoint())
  44 + }
  45 +
  46 + @ReactProp(name = "width")
  47 + fun setWidth(route: DrivingRoute, width: Float) {
  48 + route.setRouteWidth(width.toPx().toFloat())
  49 + }
  50 +
  51 + @ReactProp(name = "lineColor", customType = "Color")
  52 + fun setColor(route: DrivingRoute, lineColor: Int) {
  53 + route.setRoadColor(lineColor)
  54 + }
  55 +
  56 + @ReactProp(name = "throughPointVisible")
  57 + fun setThroughPointVisible(route: DrivingRoute, throughPointVisible: Boolean) {
  58 + route.setThroughPointMarkerVisible(throughPointVisible)
  59 + }
  60 +
  61 + @ReactProp(name = "colorFulLine")
  62 + fun setColorFulLine(route: DrivingRoute, colorFulLine: Boolean) {
  63 + route.setIsColorfulline(colorFulLine)
  64 + }
  65 +
  66 + @ReactProp(name = "throughPointList")
  67 + fun setThroughPointList(route: DrivingRoute, position: ReadableArray) {
  68 + route.setThroughPointList(position.toLatLngList())
  69 + }
  70 +
  71 + @ReactProp(name = "driveIcon")
  72 + fun setDriveIcon(route: DrivingRoute, driveIcon: ReadableMap?) {
  73 + driveIcon?.let { route.setDriveBit(it) }
  74 + }
  75 +
  76 + @ReactProp(name = "startIcon")
  77 + fun setStartIcon(route: DrivingRoute, startIcon: ReadableMap?) {
  78 + startIcon?.let { route.setStartBit(it) }
  79 + }
  80 +
  81 + @ReactProp(name = "endIcon")
  82 + fun setEndIcon(route: DrivingRoute, endIcon: ReadableMap?) {
  83 + endIcon?.let { route.setEndBit(it) }
  84 + }
  85 +
  86 + @ReactProp(name = "throughPointIcon")
  87 + fun setThroughPointIcon(route: DrivingRoute, throughPoint: ReadableMap?) {
  88 + throughPoint?.let { route.setThroughPointBitDes(it) }
  89 + }
  90 +
  91 + @ReactProp(name = "roadLine")
  92 + fun setRoadLine(route: DrivingRoute, roadLine: ReadableMap?) {
  93 + roadLine?.let { route.setRoadLine(it) }
  94 + }
  95 +}
0 96 \ No newline at end of file
... ...
lib/android/src/main/java/cn/feewee/amap3d/map_view/route/RouteOverlay.kt 0 → 100644
  1 +package cn.feewee.amap3d.map_view.route
  2 +
  3 +import android.annotation.SuppressLint
  4 +import android.app.AlertDialog
  5 +import android.content.Context
  6 +import android.graphics.Color
  7 +import android.view.LayoutInflater
  8 +import android.view.View
  9 +import android.widget.TextView
  10 +import cn.feewee.amap3d.*
  11 +import cn.feewee.amap3d.map_view.Overlay
  12 +import com.amap.api.maps.AMap
  13 +import com.amap.api.maps.CameraUpdateFactory
  14 +import com.amap.api.maps.model.*
  15 +import com.amap.api.services.core.LatLonPoint
  16 +import com.amap.api.services.route.*
  17 +import com.facebook.react.bridge.ReadableMap
  18 +import com.facebook.react.views.view.ReactViewGroup
  19 +
  20 +abstract class RouteOverlay(context: Context) : ReactViewGroup(context), Overlay {
  21 + lateinit var map: AMap
  22 + private var stationMarkers: MutableList<Marker> = ArrayList()
  23 + private var allPolyLines: MutableList<Polyline> = ArrayList()
  24 + private var startPoint: LatLng? = null
  25 + private var endPoint: LatLng? = null
  26 + private var startMarker: Marker? = null
  27 + private var endMarker: Marker? = null
  28 + private var roadColor: Int = Color.parseColor("#537edc")
  29 + private var progDialog: AlertDialog? = null
  30 +
  31 + protected var mRouteSearch: RouteSearchV2? = null
  32 +
  33 + abstract fun searchRouteResult()
  34 +
  35 + /**
  36 + * 路段节点图标控制显示接口。
  37 + * @param visible true为显示节点图标,false为不显示。
  38 + * @since V2.3.1
  39 + */
  40 + protected var nodeIconVisible = true
  41 + fun setNodeIconVisibility(visible: Boolean) {
  42 + try {
  43 + nodeIconVisible = visible
  44 + if (stationMarkers.size > 0) {
  45 + for (i in stationMarkers.indices) {
  46 + stationMarkers[i].isVisible = visible
  47 + }
  48 + }
  49 + } catch (e: Throwable) {
  50 + e.printStackTrace()
  51 + }
  52 + }
  53 +
  54 +
  55 + fun setStartPoint(start: LatLonPoint?) {
  56 + start?.let {
  57 + startPoint = start.convertToLatLng()
  58 + }
  59 + }
  60 +
  61 + fun getStartPoint(): LatLng? {
  62 + return startPoint
  63 + }
  64 +
  65 + fun setEndPoint(end: LatLonPoint?) {
  66 + end?.let {
  67 + endPoint = end.convertToLatLng()
  68 + }
  69 + }
  70 +
  71 + fun getEndPoint(): LatLng? {
  72 + return endPoint
  73 + }
  74 +
  75 + /**
  76 + * 起点Marker图标。
  77 + */
  78 + private var startBit: BitmapDescriptor? = null
  79 +
  80 + fun setStartBit(source: ReadableMap) {
  81 + fetchImage(source) {
  82 + startBit = it
  83 + }
  84 + }
  85 +
  86 + fun getStartBit(): BitmapDescriptor {
  87 + return startBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_start)
  88 + }
  89 +
  90 + /**
  91 + * 终点Marker图标。
  92 + */
  93 + private var endBit: BitmapDescriptor? = null
  94 +
  95 + fun setEndBit(source: ReadableMap) {
  96 + fetchImage(source) {
  97 + endBit = it
  98 + }
  99 + }
  100 +
  101 + fun getEndBit(): BitmapDescriptor {
  102 + return endBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_end)
  103 + }
  104 +
  105 + /**
  106 + * 途经点图标
  107 + */
  108 + private var throughBit: BitmapDescriptor? = null
  109 +
  110 + fun setThroughBit(source: ReadableMap) {
  111 + fetchImage(source) {
  112 + throughBit = it
  113 + }
  114 + }
  115 +
  116 + fun getThroughBit(): BitmapDescriptor {
  117 + return throughBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_through)
  118 + }
  119 +
  120 + /**
  121 + * 驾车Marker图标
  122 + */
  123 + private var driveBit: BitmapDescriptor? = null
  124 +
  125 + fun setDriveBit(source: ReadableMap) {
  126 + fetchImage(source) {
  127 + driveBit = it
  128 + }
  129 + }
  130 +
  131 + fun getDriveBit(): BitmapDescriptor {
  132 + return driveBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_car)
  133 + }
  134 +
  135 + /**
  136 + * 骑行Marker图标
  137 + */
  138 + private var rideBit: BitmapDescriptor? = null
  139 +
  140 + fun setRideBit(source: ReadableMap) {
  141 + fetchImage(source) {
  142 + rideBit = it
  143 + }
  144 + }
  145 +
  146 + fun getRideBit(): BitmapDescriptor {
  147 + return rideBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_ride)
  148 + }
  149 +
  150 + /**
  151 + * 公交Marker图标
  152 + */
  153 + private var busBit: BitmapDescriptor? = null
  154 +
  155 + fun setBusBit(source: ReadableMap) {
  156 + fetchImage(source) {
  157 + busBit = it
  158 + }
  159 + }
  160 +
  161 + fun getBusBit(): BitmapDescriptor {
  162 + return busBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_bus)
  163 + }
  164 +
  165 + /**
  166 + * 步行Marker图标
  167 + */
  168 + private var walkBit: BitmapDescriptor? = null
  169 +
  170 + fun setWalkBit(source: ReadableMap) {
  171 + fetchImage(source) {
  172 + walkBit = it
  173 + }
  174 + }
  175 +
  176 + fun getWalkBit(): BitmapDescriptor {
  177 + return walkBit ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_amap_man)
  178 + }
  179 +
  180 + private var roadLine: BitmapDescriptor? = null
  181 +
  182 + fun setRoadLine(source: ReadableMap) {
  183 + fetchImage(source) {
  184 + roadLine = it
  185 + }
  186 + }
  187 +
  188 + fun getRoadLine(): BitmapDescriptor {
  189 + return roadLine ?: BitmapDescriptorFactory.fromResource(R.drawable.cqfw_custtexture)
  190 + }
  191 +
  192 + private var routeWidth: Float = 18F
  193 +
  194 + /**
  195 + * 自定义路线宽度
  196 + * @param width
  197 + */
  198 +
  199 + fun setRouteWidth(width: Float?) {
  200 + width?.let {
  201 + routeWidth = width
  202 + }
  203 + }
  204 +
  205 + fun getRouteWidth(): Float {
  206 + return routeWidth
  207 + }
  208 +
  209 + /**
  210 + * 自定义路线颜色
  211 + *
  212 + * @param color
  213 + */
  214 + fun setRoadColor(color: Int) {
  215 + roadColor = color
  216 + }
  217 +
  218 + fun getRoadColor(): Int {
  219 + return roadColor
  220 + }
  221 +
  222 + protected fun addStartAndEndMarker() {
  223 + removeMarkerFromMap()
  224 + startMarker = map.addMarker(
  225 + MarkerOptions()
  226 + .position(startPoint)
  227 + .icon(getStartBit())
  228 + .title("\u8D77\u70B9")
  229 + )
  230 + endMarker = map.addMarker(
  231 + MarkerOptions()
  232 + .position(endPoint)
  233 + .icon(getEndBit())
  234 + .title("\u7EC8\u70B9")
  235 + )
  236 + }
  237 +
  238 + protected fun addStationMarker(options: MarkerOptions?) {
  239 + if (options == null) {
  240 + return
  241 + }
  242 + val marker = map.addMarker(options)
  243 + if (marker != null) {
  244 + stationMarkers.add(marker)
  245 + }
  246 + }
  247 +
  248 + protected fun addPolyLine(options: PolylineOptions?) {
  249 + if (options == null) {
  250 + return
  251 + }
  252 + val polyline = map.addPolyline(options)
  253 + if (polyline != null) {
  254 + allPolyLines.add(polyline)
  255 + }
  256 + }
  257 +
  258 + /**
  259 + * 移动镜头到当前的视角。
  260 + * @since V2.1.0
  261 + */
  262 + protected fun zoomToSpan() {
  263 + if (startPoint != null) {
  264 + try {
  265 + val bounds = getLatLngBounds()
  266 + map.animateCamera(
  267 + CameraUpdateFactory
  268 + .newLatLngBounds(bounds, 100)
  269 + )
  270 + } catch (e: Throwable) {
  271 + e.printStackTrace()
  272 + }
  273 + }
  274 + }
  275 +
  276 + protected open fun getLatLngBounds(): LatLngBounds {
  277 + return LatLngBounds.builder()
  278 + .include(LatLng(startPoint!!.latitude, startPoint!!.longitude))
  279 + .include(LatLng(endPoint!!.latitude, endPoint!!.longitude))
  280 + .build()
  281 + }
  282 +
  283 + /**
  284 + * 移除所有的Marker。
  285 + */
  286 + protected fun removeMarkerFromMap() {
  287 + startMarker?.destroy()
  288 + endMarker?.destroy()
  289 +
  290 + }
  291 +
  292 + /**
  293 + * 移除所有的路线。
  294 + */
  295 + protected fun removeLineFromMap() {
  296 + for (marker in stationMarkers) {
  297 + marker.destroy()
  298 + }
  299 + for (line in allPolyLines) {
  300 + line.remove()
  301 + }
  302 + }
  303 +
  304 + /**
  305 + * 开始搜索路径规划方案
  306 + */
  307 + protected fun createFromAndTo(): RouteSearchV2.FromAndTo? {
  308 + if (startPoint == null) {
  309 + show(context, "起点未设置")
  310 + return null
  311 + }
  312 + if (endPoint == null) {
  313 + show(context, "终点未设置")
  314 + return null
  315 + }
  316 + return RouteSearchV2.FromAndTo(
  317 + startPoint!!.convertToLatLonPoint(),
  318 + endPoint!!.convertToLatLonPoint()
  319 + )
  320 + }
  321 +
  322 + /**
  323 + * 隐藏进度框
  324 + */
  325 + protected fun dissmissProgressDialog() {
  326 + progDialog?.dismiss()
  327 + }
  328 +
  329 + /**
  330 + * 显示进度框
  331 + */
  332 + protected fun showProgressDialog() {
  333 + if (progDialog == null) {
  334 + progressBarCircleDialog()
  335 + }
  336 + progDialog?.setCanceledOnTouchOutside(false);
  337 + progDialog?.setCancelable(false);
  338 + progDialog?.show();
  339 + }
  340 +
  341 +
  342 + private fun progressBarCircleDialog() {
  343 + val builder = AlertDialog.Builder(
  344 + context,
  345 + AlertDialog.THEME_HOLO_LIGHT
  346 + )
  347 + val inflater = LayoutInflater.from(context);
  348 + @SuppressLint("InflateParams")
  349 + val view: View = inflater.inflate(R.layout.dialog_progressbar_circle, null);
  350 + val tv: TextView = view.findViewById(R.id.tv);
  351 + tv.text = "正在搜索...";
  352 + builder.setView(view);
  353 + progDialog = builder.create();
  354 + }
  355 +}
0 356 \ No newline at end of file
... ...
lib/android/src/main/res/drawable-hdpi/cqfw_amap_bus.png 0 → 100644

1.05 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_car.png 0 → 100644

1.14 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_end.png 0 → 100644

10.9 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_man.png 0 → 100644

1.26 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_ride.png 0 → 100644

1.3 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_start.png 0 → 100644

10.2 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_through.png 0 → 100644

4.4 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_train.png 0 → 100644

1.08 KB

lib/android/src/main/res/drawable-hdpi/cqfw_amap_truck.png 0 → 100644

1.14 KB

lib/android/src/main/res/drawable-hdpi/cqfw_custtexture.png 0 → 100644

1.46 KB

lib/android/src/main/res/layout/dialog_progressbar_circle.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + xmlns:tools="http://schemas.android.com/tools"
  6 + android:gravity="center"
  7 + android:orientation="horizontal"
  8 + android:padding="10dp">
  9 +
  10 + <ProgressBar
  11 + android:id="@+id/pb"
  12 + android:layout_width="50dp"
  13 + android:layout_height="50dp"
  14 + android:layout_gravity="center"
  15 + android:layout_margin="5dp"
  16 + android:indeterminateDuration="300" />
  17 +
  18 + <!--android:indeterminateDrawable="@drawable/progress_bar"-->
  19 +
  20 + <TextView
  21 + android:id="@+id/tv"
  22 + android:layout_width="0dp"
  23 + android:layout_height="wrap_content"
  24 + android:layout_weight="1"
  25 + android:gravity="left|center"
  26 + android:textSize="22sp"
  27 + tools:ignore="RtlHardcoded" />
  28 +</LinearLayout>
... ...
lib/android/src/main/res/values/strings.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <string name="no_result">对不起,没有搜索到相关数据!</string>
  4 +</resources>
0 5 \ No newline at end of file
... ...
lib/src/index.ts
1 1 export { default as Circle } from "./circle";
2   -export { default as Cluster } from "./cluster";
  2 +export { default as Cluster } from "./cluster/index";
3 3 export { default as HeatMap } from "./heat-map";
4 4 export { default as MapView } from "./map-view";
5 5 export { default as Marker } from "./marker";
  6 +export { default as DrivingRoute } from "./route/driving-route";
6 7 export { default as MultiPoint } from "./multi-point";
7 8 export { default as Polygon } from "./polygon";
8 9 export { default as Polyline } from "./polyline";
... ...
lib/src/route/driving-route.tsx 0 → 100644
  1 +import * as React from "react";
  2 +import { ColorValue, ImageSourcePropType, Platform, processColor, requireNativeComponent } from "react-native";
  3 +import Component from "../component";
  4 +// @ts-ignore
  5 +import resolveAssetSource from "react-native/Libraries/Image/resolveAssetSource";
  6 +import { LatLng } from "../types";
  7 +
  8 +export interface DrivingRouteProps {
  9 + /**
  10 + * 起点
  11 + */
  12 + startPoint: LatLng;
  13 + /**
  14 + * 终点
  15 + */
  16 + endPoint: LatLng;
  17 + /**
  18 + * 途经点
  19 + */
  20 + throughPointList?: LatLng[];
  21 + /**
  22 + * 显示途经点
  23 + */
  24 + throughPointVisible?: boolean;
  25 + /**
  26 + * 根据不同的路段拥堵情况展示不同的颜色
  27 + */
  28 + colorFulLine?: boolean;
  29 + /**
  30 + * 线段宽度
  31 + */
  32 + width?: number;
  33 + /**
  34 + * 路线的纹理
  35 + */
  36 + roadLine?: ImageSourcePropType;
  37 + /**
  38 + * 驾车图标
  39 + */
  40 + driveIcon?: ImageSourcePropType;
  41 + /**
  42 + * 起点图标
  43 + */
  44 + startIcon?: ImageSourcePropType;
  45 + /**
  46 + * 终点图标
  47 + */
  48 + endIcon?: ImageSourcePropType;
  49 + /**
  50 + * 途经点图标
  51 + */
  52 + throughPointIcon?: ImageSourcePropType;
  53 + /**
  54 + * 线段颜色
  55 + */
  56 + lineColor?: ColorValue;
  57 +}
  58 +
  59 +export default class extends Component<DrivingRouteProps> {
  60 + static defaultProps = { with: 14, throughPointVisible: true };
  61 +
  62 + /**
  63 + * 路线规划
  64 + */
  65 + routePlan(start: LatLng, end: LatLng, throughPointList: LatLng[] = []) {
  66 + this.invoke("searchRoute", [start, end, throughPointList]);
  67 + }
  68 +
  69 + render() {
  70 + const props = {
  71 + ...this.props,
  72 + };
  73 + return (
  74 + <NativeDrivingRoute
  75 + {...props}
  76 + driveIcon={resolveAssetSource(props.driveIcon)}
  77 + startIcon={resolveAssetSource(props.startIcon)}
  78 + endIcon={resolveAssetSource(props.endIcon)}
  79 + throughPointIcon={resolveAssetSource(props.throughPointIcon)}
  80 + roadLine={resolveAssetSource(props.roadLine)}
  81 + />
  82 + );
  83 + }
  84 +}
  85 +
  86 +const NativeDrivingRoute = requireNativeComponent<DrivingRouteProps>("DrivingRoute");
... ...