Merge branch 'master' into 'master'

Master

See merge request qiji4215/OneMapQS!4
This commit is contained in:
齐济04215 2023-04-19 17:31:09 +08:00
commit 134061533b
17 changed files with 1229 additions and 49 deletions

View File

@ -2,7 +2,6 @@ package com.navinfo.omqs
import android.app.Application
import android.util.Log
import com.navinfo.omqs.db.MyRealmModule
import com.navinfo.omqs.tools.FileManager
import dagger.hilt.android.HiltAndroidApp
import io.realm.Realm
@ -25,7 +24,7 @@ class OMQSApplication : Application() {
.directory(File(Constant.DATA_PATH))
.name("OMQS.realm")
.encryptionKey(password)
.modules(Realm.getDefaultModule(), MyRealmModule())
// .modules(Realm.getDefaultModule(), MyRealmModule())
.schemaVersion(1)
.build()
Realm.setDefaultConfiguration(config)

View File

@ -2,6 +2,6 @@ package com.navinfo.omqs.db
import com.navinfo.collect.library.data.entity.QsRecordBean
@io.realm.annotations.RealmModule(classes = [QsRecordBean::class])
class MyRealmModule {
}
//@io.realm.annotations.RealmModule(classes = [QsRecordBean::class])
//class MyRealmModule {
//}

View File

@ -4,7 +4,6 @@ import com.navinfo.collect.library.utils.GeometryToolsKt
import io.realm.RealmObject
import io.realm.RealmSet
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
/**
@ -14,7 +13,7 @@ import io.realm.annotations.RealmClass
* @Date 2016/1/12
* @Description: ${TODO}(质检对象)
*/
@RealmClass
//@RealmClass
open class QsRecordBean @JvmOverloads constructor(
/**
* id 主键

View File

@ -0,0 +1,24 @@
package com.navinfo.collect.library.map.cluster
import org.oscim.core.GeoPoint
import org.oscim.layers.marker.MarkerItem
/*
*com.nmp.map.cluster
*zhjch
*2021/12/10
*10:51
*说明
*/
class ClusterMarkerItem(uid: Any?, title: String?, description: String?, geoPoint: GeoPoint?) :
MarkerItem(uid, title, description, geoPoint) {
var clusterList: List<Int> = ArrayList()
constructor(title: String?, description: String?, geoPoint: GeoPoint?) : this(
null,
title,
description,
geoPoint
) {
}
}

View File

@ -0,0 +1,471 @@
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2016 Izumi Kawashima
* Copyright 2017 Longri
* Copyright 2017-2018 devemux86
* Copyright 2017 nebular
* Copyright 2017 Wolfgang Schramm
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.navinfo.collect.library.map.cluster
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Rect
import android.text.TextPaint
import android.util.Log
import com.navinfo.collect.library.R
import org.oscim.android.canvas.AndroidBitmap
import org.oscim.backend.CanvasAdapter
import org.oscim.backend.canvas.Bitmap
import org.oscim.core.MercatorProjection
import org.oscim.core.PointF
import org.oscim.core.Tile
import org.oscim.layers.marker.*
import org.oscim.renderer.GLViewport
import org.oscim.renderer.bucket.SymbolItem
import org.oscim.utils.FastMath
import org.oscim.utils.geom.GeometryUtils
/**
* An extension to the MarkerRenderer with item clustering support.
*/
open class ClusterMarkerRenderer : MarkerRenderer {
private var mContext: Context? = null
protected var mStyleBackground = CLUSTER_COLORBACK
protected var mStyleForeground = CLUSTER_COLORTEXT
/**
* Discrete scale step, used to trigger reclustering on significant scale change
*/
private var mScalePow = 0
/**
* Map scale to cluster the marker
*/
private var mClusterScale = 0.0
/**
* We use a flat Sparse array to calculate the clusters. The sparse array models a 2D map where every (x,y) denotes
* a grid slot, ie. 64x64dp. For efficiency I use a linear sparsearray with ARRindex = SLOTypos * max_x + SLOTxpos"
*/
// private final SparseIntArray mGridMap = new SparseIntArray(200); // initial space for 200 markers, that's not a lot of memory, and in most cases will avoid resizing the array
private val mGridMap =
HashMap<Int, Any?>() // initial space for 200 markers, that's not a lot of memory, and in most cases will avoid resizing the array
/**
* Whether to enable clustering or disable the functionality
*/
private val mClusteringEnabled: Boolean
/**
* Constructs a clustered marker renderer
*
* @param markerLayer The owner layer
* @param defaultSymbol The default symbol
* @param style The desired style, or NULL to disable clustering
*/
constructor(
context: Context?,
markerLayer: MarkerLayer?,
defaultSymbol: MarkerSymbol?,
style: ClusterStyle?
) : super(markerLayer, defaultSymbol) {
mContext = context
mClusteringEnabled = style != null
if (mClusteringEnabled) {
setClusterStyle(style!!.foreground, style.background)
for (k in 0..CLUSTER_MAXSIZE) {
// cache bitmaps so render thread never creates them
// we create CLUSTER_MAXSIZE bitmaps. Bigger clusters will show like "+"
getClusterBitmap(k)
}
}
}
private constructor(
markerLayer: MarkerLayer, defaultSymbol: MarkerSymbol, style: ClusterStyle?
) : super(markerLayer, defaultSymbol) {
mClusteringEnabled = style != null
if (mClusteringEnabled) {
setClusterStyle(style!!.foreground, style.background)
for (k in 0..CLUSTER_MAXSIZE) {
// cache bitmaps so render thread never creates them
// we create CLUSTER_MAXSIZE bitmaps. Bigger clusters will show like "+"
getClusterBitmap(k)
}
}
}
/**
* Configures the cluster icon style. This is called by the constructor and cannot be made public because
* we pre-cache the icons at construction time so the renderer does not have to create them while rendering
*
* @param backgroundColor Background color
* @param foregroundColor text & border color
*/
private fun setClusterStyle(foregroundColor: Int, backgroundColor: Int) {
mStyleBackground = backgroundColor
mStyleForeground = foregroundColor
}
protected override fun populate(size: Int) {
repopulateCluster(size, mClusterScale)
}
/**
* Repopulates item list clustering close markers. This is triggered from update() when
* a significant change in scale has happened.
*
* @param size Item list size
* @param scale current map scale
*/
private fun repopulateCluster(size: Int, scale: Double) {
/* the grid slot size in px. increase to group more aggressively. currently set to marker size */
if (mMapPosition.zoomLevel == 15) {
MAP_GRID_SIZE_DP = 128
} else {
MAP_GRID_SIZE_DP = 64
}
val GRIDSIZE = ClusterUtils.getPixels(MAP_GRID_SIZE_DP.toFloat())
/* the factor to map into Grid Coordinates (discrete squares of GRIDSIZE x GRIDSIZE) */
val factor = scale / GRIDSIZE
val tmp = arrayOfNulls<Clustered>(size)
// clear grid map to count items that share the same "grid slot"
mGridMap.clear()
for (i in 0 until size) {
tmp[i] = Clustered()
val it = tmp[i]
it!!.item = mMarkerLayer.createItem(i)
/* pre-project points */MercatorProjection.project(it.item.point, mMapPoint)
it.px = mMapPoint.x
it.py = mMapPoint.y
// items can be declared non-clusterable
if (it.item !is NonClusterable) {
val absposx = (it.px * factor).toInt()
// absolute item X position in the grid
val absposy = (it.py * factor).toInt()
// absolute item Y position
val maxcols = factor.toInt()
// Grid number of columns
val itemGridIndex = absposx + absposy * maxcols // Index in the sparsearray map
// we store in the linear sparsearray the index of the marker,
// ie, index = y * maxcols + x; array[index} = markerIndex
// Lets check if there's already an item in the grid slot
// final int storedIndexInGridSlot = mGridMap.get(itemGridIndex, -1);
var list: ArrayList<Int>? = null
if (mGridMap.containsKey(itemGridIndex)) {
list = mGridMap[itemGridIndex] as ArrayList<Int>?
}
if (list == null) {
list = ArrayList()
list.add(i)
if (it.item is ClusterMarkerItem) {
(it.item as ClusterMarkerItem).clusterList = list
}
mGridMap[itemGridIndex] = list
// no item at that grid position. The grid slot is free so let's
// store this item "i" (we identify every item by its InternalItem index)
// mGridMap.put(itemGridIndex, i);
//Log.v(TAG, "UNclustered item at " + itemGridIndex);
} else {
// at that grid position there's already a marker index
// mark this item as clustered out, so it will be skipped in the update() call
it.clusteredOut = true
list.add(i)
for (n in list) {
val item: MarkerInterface = mMarkerLayer.createItem(n)
if (item is ClusterMarkerItem) {
(item as ClusterMarkerItem).clusterList = list
}
}
// and increment the count on its "parent" that will from now on act as a cluster
tmp[list[0]]!!.clusterSize++
//Log.v(TAG, "Clustered item at " + itemGridIndex + ", \'parent\' size " + (tmp[storedIndexInGridSlot].clusterSize));
}
}
}
/* All ready for update. */synchronized(this) {
mUpdate = true
mItems = tmp
}
}
@Synchronized
override fun update(v: GLViewport) {
val scale: Double = Tile.SIZE * v.pos.scale
if (mClusteringEnabled) {
/*
Clustering check: If clustering is enabled and there's been a significant scale change
trigger repopulation and return. After repopulation, this will be called again
*/
// (int) log of scale gives us adequate steps to trigger clustering
val scalePow = FastMath.log2(scale.toInt())
if (scalePow != mScalePow) {
mScalePow = scalePow
mClusterScale = scale
// post repopulation to the main thread
mMarkerLayer.map().post(Runnable { repopulateCluster(mItems.size, scale) })
// and get out of here
return
}
}
if (!v.changed() && !mUpdate) return
mUpdate = false
val mx: Double = v.pos.x
val my: Double = v.pos.y
//int changesInvisible = 0;
//int changedVisible = 0;
var numVisible = 0
// Increase view to show items that are partially visible
mMarkerLayer.map().viewport().getMapExtents(mBox, (Tile.SIZE shr 1).toFloat())
val flip: Long = (Tile.SIZE * v.pos.scale).toLong() shr 1
if (mItems == null) {
if (buckets.get() != null) {
buckets.clear()
compile()
}
return
}
val angle = Math.toRadians(v.pos.bearing.toDouble())
val cos = Math.cos(angle).toFloat()
val sin = Math.sin(angle).toFloat()
/* check visibility */for (itm in mItems) {
val it = itm as Clustered
it.changes = false
it.x = ((it.px - mx) * scale).toFloat()
it.y = ((it.py - my) * scale).toFloat()
if (it.x > flip) it.x -= (flip shl 1).toFloat() else if (it.x < -flip) it.x += (flip shl 1).toFloat()
if (it.clusteredOut || !GeometryUtils.pointInPoly(it.x, it.y, mBox, 8, 0)) {
// either properly invisible, or clustered out. Items marked as clustered out mean there's another item
// on the same-ish position that will be promoted to cluster marker, so this particular item is considered
// invisible
if (it.visible && !it.clusteredOut) {
// it was previously visible, but now it won't
it.changes = true
// changes to invible
//changesInvisible++;
}
continue
}
// item IS definitely visible
it.dy = sin * it.x + cos * it.y
if (!it.visible) {
it.visible = true
//changedVisible++;
}
numVisible++
}
//log.debug(numVisible + " " + changedVisible + " " + changesInvisible);
/* only update when zoomlevel changed, new items are visible
* or more than 10 of the current items became invisible */
//if ((numVisible == 0) && (changedVisible == 0 && changesInvisible < 10))
// return;
buckets.clear()
if (numVisible == 0) {
compile()
return
}
/* keep position for current state */mMapPosition.copy(v.pos)
mMapPosition.bearing = -mMapPosition.bearing
// why do we sort ? z-index?
sort(mItems, 0, mItems.size)
//log.debug(Arrays.toString(mItems));
for (itm in mItems) {
val it = itm as Clustered
// skip invisible AND clustered-out
if (!it.visible || it.clusteredOut) continue
if (it.changes) {
it.visible = false
continue
}
val s: SymbolItem = SymbolItem.pool.get()
if (it.clusterSize > 0) {
// this item will act as a cluster, just use a proper bitmap
// depending on cluster size, instead of its marker
val bitmap = getClusterBitmap(it.clusterSize + 1)
s.set(it.x, it.y, bitmap, true)
s.offset = PointF(0.5f, 0.5f)
s.billboard = true // could be a parameter
} else {
// normal item, use its marker
var symbol: MarkerSymbol? = it.item.marker
if (symbol == null) symbol = mDefaultMarker
symbol?.let { symbol ->
s.set(it.x, it.y, symbol.bitmap, true)
s.offset = symbol.hotspot
s.billboard = symbol.isBillboard
}
}
mSymbolLayer.pushSymbol(s)
}
buckets.set(mSymbolLayer)
buckets.prepare()
compile()
}
/**
* Gets a bitmap for a given cluster size
*
* @param size The cluster size. Can be greater than CLUSTER_MAXSIZE.
* @return A somewhat cool bitmap to be used as the cluster marker
*/
open fun getClusterBitmap(size: Int): Bitmap? {
var size = size
val strValue: String
if (size >= CLUSTER_MAXSIZE) {
// restrict cluster indicator size. Bigger clusters will show as "+" instead of ie. "45"
size = CLUSTER_MAXSIZE
strValue = "+"
} else {
strValue = size.toString()
}
// return cached bitmap if exists. cache hit !
if (mClusterBitmaps[size] != null) return mClusterBitmaps[size]
// create and cache bitmap. This is unacceptable inside the GL thread,
// so we'll call this routine at the beginning to pre-cache all bitmaps
// Can customize cluster bitmap here
//
// Canvas canvas = new Canvas(bitmap);
// TextPaint textPaint = new TextPaint();
// textPaint.setColor(Color.WHITE);
// int width = (int) Math.ceil(textPaint.measureText(strValue));
// android.graphics.Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
// int height = (int) Math.ceil(Math.abs(fontMetrics.bottom) + Math.abs(fontMetrics.top));
// textPaint.setTextSize(13 * CanvasAdapter.getScale());
// canvas.drawText(strValue, 0, Math.abs(fontMetrics.ascent), textPaint);
val textPaint = TextPaint()
val h: Float = 13 * CanvasAdapter.getScale()
textPaint.textSize = h
textPaint.strokeWidth = 2f
textPaint.color = Color.WHITE
val bitmap = BitmapFactory.decodeResource(
mContext!!.resources, R.mipmap.map_icon_cluster
).copy(android.graphics.Bitmap.Config.ARGB_8888, true)
val canvas = Canvas(bitmap)
val w = textPaint.getTextWidths(strValue, FloatArray(strValue.length))
val textRect = Rect()
textPaint.getTextBounds(strValue, 0, strValue.length, textRect)
canvas.drawText(
strValue,
((bitmap.width - textRect.width()) / 2 - 4).toFloat(),
((bitmap.height + textRect.height()) / 2).toFloat(),
textPaint
)
val bitmapNew: Bitmap = AndroidBitmap(bitmap)
// Canvas canvas = CanvasAdapter.newCanvas();
// canvas.setBitmap(bitmapNew);
// mSize = ClusterUtils.getPixels(sizedp);
// int halfsize = mSize >> 1;
// final int noneClippingRadius = halfsize - getPixels(2);
// Paint mPaintText = CanvasAdapter.newPaint();
// draw the number at the center
// canvas.drawText(strValue,
// (canvas.getWidth() - mPaintText.getTextWidth(strValue)) * 0.5f,
// (canvas.getHeight() + mPaintText.getTextHeight(strValue)) * 0.5f,
// mPaintText);
// ClusterUtils.ClusterDrawable drawable = new ClusterUtils.ClusterDrawable(
// MAP_MARKER_CLUSTER_SIZE_DP - CLUSTER_MAXSIZE + size, // make size dependent on cluster size
// mStyleForeground,
// mStyleBackground,
// strValue
// );
mClusterBitmaps[size] = bitmapNew
return mClusterBitmaps[size]
}
/**
* Class to wrap the cluster icon style properties
*/
class ClusterStyle
/**
* Creates the Cluster style
*
* @param fore Foreground (border and text) color
* @param back Background (circle) color
*/(val foreground: Int, val background: Int)
companion object {
/**
* Max number to display inside a cluster icon
*/
protected const val CLUSTER_MAXSIZE = 999
/**
* default color of number inside the icon. Would be super-cool to cook this into the map theme
*/
private const val CLUSTER_COLORTEXT = -0x7fff40
/**
* default color of circle background
*/
private const val CLUSTER_COLORBACK = -0x1
/**
* Map Cluster Icon Size. This is the biggest size for clusters of CLUSTER_MAXSIZE elements. Smaller clusters will be slightly smaller
*/
protected const val MAP_MARKER_CLUSTER_SIZE_DP = 48
/**
* Clustering grid square size, decrease to cluster more aggresively. Ideally this value is the typical marker size
*/
private var MAP_GRID_SIZE_DP = 64
/**
* cached bitmaps database, we will cache cluster bitmaps from 1 to MAX_SIZE
* and always use same bitmap for efficiency
*/
protected var mClusterBitmaps = arrayOfNulls<Bitmap>(CLUSTER_MAXSIZE + 1)
/**
* Convenience method for instantiating this renderer via a factory, so the layer construction semantic is more pleasing to the eye
*
* @param defaultSymbol Default symbol to use if the Marker is not assigned a symbol
* @param style Cluster icon style, or NULL to disable clustering functionality
* @return A factory to be passed to the ItemizedLayer constructor in order to enable the cluster functionality
*/
fun factory(defaultSymbol: MarkerSymbol, style: ClusterStyle?): MarkerRendererFactory {
return MarkerRendererFactory { markerLayer ->
ClusterMarkerRenderer(
markerLayer, defaultSymbol, style
)
}
}
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright 2017 nebular
* Copyright 2017 devemux86
* Copyright 2017 Wolfgang Schramm
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.navinfo.collect.library.map.cluster
import org.oscim.backend.CanvasAdapter
import org.oscim.backend.canvas.Bitmap
import org.oscim.backend.canvas.Canvas
import org.oscim.backend.canvas.Paint
/**
* A simple utility class to make clustered markers functionality self-contained.
* Includes a method to translate between DPs and PXs and a circular icon generator.
*/
object ClusterUtils {
/**
* Get pixels from DPs
*
* @param dp Value in DPs
* @return Value in PX according to screen density
*/
fun getPixels(dp: Float): Int {
return (CanvasAdapter.getScale() * dp).toInt()
}
class ClusterDrawable(sizedp: Int, foregroundColor: Int, backgroundColor: Int, text: String) {
private val mPaintText = CanvasAdapter.newPaint()
private val mPaintCircle = CanvasAdapter.newPaint()
private val mPaintBorder = CanvasAdapter.newPaint()
private var mSize = 0
private var mText: String? = null
/**
* Generates a circle with a number inside
*
* @param sizedp Size in DPs
* @param foregroundColor Foreground
* @param backgroundColor Background
* @param text Text inside. Will only work for a single character!
*/
init {
setup(sizedp, foregroundColor, backgroundColor)
setText(text)
}
private fun setup(sizedp: Int, foregroundColor: Int, backgroundColor: Int) {
mSize = getPixels(sizedp.toFloat())
mPaintText.setTextSize(getPixels((sizedp * 0.6666666).toInt().toFloat()).toFloat())
mPaintText.color = foregroundColor
mPaintCircle.color = backgroundColor
mPaintCircle.style = Paint.Style.FILL
mPaintBorder.color = foregroundColor
mPaintBorder.style = Paint.Style.STROKE
mPaintBorder.strokeWidth = 2.0f * CanvasAdapter.getScale()
}
private fun setText(text: String) {
mText = text
}
private fun draw(canvas: Canvas) {
val halfsize = mSize shr 1
val noneClippingRadius = halfsize - getPixels(2f)
// fill
canvas.drawCircle(
halfsize.toFloat(),
halfsize.toFloat(),
noneClippingRadius.toFloat(),
mPaintCircle
)
// outline
canvas.drawCircle(
halfsize.toFloat(),
halfsize.toFloat(),
noneClippingRadius.toFloat(),
mPaintBorder
)
// draw the number at the center
canvas.drawText(
mText,
(canvas.width - mPaintText.getTextWidth(mText)) * 0.5f,
(canvas.height + mPaintText.getTextHeight(mText)) * 0.5f,
mPaintText
)
}
val bitmap: Bitmap
get() {
var width = mSize
var height = mSize
width = if (width > 0) width else 1
height = if (height > 0) height else 1
val bitmap = CanvasAdapter.newBitmap(width, height, 0)
val canvas = CanvasAdapter.newCanvas()
canvas.setBitmap(bitmap)
draw(canvas)
return bitmap
}
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2017 nebular
* Copyright 2017 devemux86
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.navinfo.collect.library.map.cluster
import org.oscim.layers.marker.InternalItem
/**
* Extension for clustered items.
*/
class Clustered : InternalItem() {
/**
* If this is >0, this item will be displayed as a cluster circle, with size clusterSize+1.
*/
var clusterSize = 0
/**
* If this is true, this item is hidden (because it's represented by another InternalItem acting as cluster.
*/
var clusteredOut = false
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2017 nebular
* Copyright 2017 devemux86
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.navinfo.collect.library.map.cluster
import org.oscim.core.GeoPoint
import org.oscim.layers.marker.MarkerItem
/**
* If a MarkerItem is created using this convenience class instead of MarkerItem,
* this specific item will not be clusterable.
*/
class NonClusterable : MarkerItem {
constructor(title: String?, description: String?, geoPoint: GeoPoint?) : super(
null,
title,
description,
geoPoint
) {
}
constructor(uid: Any?, title: String?, description: String?, geoPoint: GeoPoint?) : super(
uid,
title,
description,
geoPoint
) {
}
}

View File

@ -1,6 +1,7 @@
package com.navinfo.collect.library.map.handler
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.map.NIMapView
import org.oscim.core.GeoPoint
import org.oscim.core.MapPosition
@ -8,7 +9,7 @@ import org.oscim.core.MapPosition
/**
* 控制地图状态相关操作
*/
open class AnimationHandler(context: Context, mapView: NIMapView) :
open class AnimationHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView) {

View File

@ -1,32 +1,48 @@
package com.navinfo.collect.library.map.handler
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.lifecycleScope
import com.navinfo.collect.library.R
import com.navinfo.collect.library.data.entity.QsRecordBean
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.map.cluster.ClusterMarkerItem
import com.navinfo.collect.library.map.cluster.ClusterMarkerRenderer
import com.navinfo.collect.library.map.layers.MyItemizedLayer
import com.navinfo.collect.library.map.source.NavinfoMultiMapFileTileSource
import com.navinfo.collect.library.system.Constant
import com.navinfo.collect.library.utils.GeometryTools
import io.realm.Realm
import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Cache
import okhttp3.OkHttpClient
import org.locationtech.jts.geom.Geometry
import org.oscim.android.canvas.AndroidBitmap
import org.oscim.backend.CanvasAdapter
import org.oscim.backend.canvas.Bitmap
import org.oscim.backend.canvas.Paint
import org.oscim.core.GeoPoint
import org.oscim.layers.GroupLayer
import org.oscim.layers.marker.*
import org.oscim.layers.tile.buildings.BuildingLayer
import org.oscim.layers.tile.vector.VectorTileLayer
import org.oscim.layers.tile.vector.labeling.LabelLayer
import org.oscim.tiling.source.OkHttpEngine.OkHttpFactory
import org.oscim.tiling.source.mapfile.MapFileTileSource
import java.io.File
import java.util.*
/**
* Layer 操作
*/
class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView) :
open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView) {
private var baseGroupLayer // 用于盛放所有基础底图的图层组,便于统一管理
: GroupLayer? = null
@ -42,6 +58,17 @@ class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView) :
private lateinit var paint: Paint
//画布
private lateinit var canvas: org.oscim.backend.canvas.Canvas
private lateinit var itemizedLayer: MyItemizedLayer
private lateinit var markerRendererFactory: MarkerRendererFactory
private val markerItemsNames = mutableListOf<MarkerInterface>()
/**
* 文字大小
*/
private val NUM_13 = 13
init {
initMap()
}
@ -122,47 +149,356 @@ class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView) :
}
}
/**
* 初始话质检数据图层
*/
private fun initQsRecordDataLayer() {
canvas = CanvasAdapter.newCanvas()
paint = CanvasAdapter.newPaint()
paint.setTypeface(Paint.FontFamily.DEFAULT, Paint.FontStyle.NORMAL)
paint.setTextSize(13 * CanvasAdapter.getScale())
paint.setTextSize(NUM_13 * CanvasAdapter.getScale())
paint.strokeWidth = 2 * CanvasAdapter.getScale()
paint.color = Color.parseColor(mDefaultTextColor)
val bitmapPoi: Bitmap = AndroidBitmap(
BitmapFactory.decodeResource(
mContext.resources,
R.mipmap.map_icon_blue2
)
)
val symbol = MarkerSymbol(bitmapPoi, MarkerSymbol.HotspotPlace.BOTTOM_CENTER)
markerRendererFactory = MarkerRendererFactory { markerLayer ->
object : ClusterMarkerRenderer(
mContext,
markerLayer,
symbol,
ClusterStyle(
org.oscim.backend.canvas.Color.WHITE,
org.oscim.backend.canvas.Color.BLUE
)
) {
// override fun getClusterBitmap(size: Int): Bitmap? {
// return super.getclusterbitmap(size)
// }
}
}
var resId = R.mipmap.map_icon_point_add
mContext.lifecycleScope.launch(Dispatchers.IO) {
var list = mutableListOf<QsRecordBean>()
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val list = realm.where<QsRecordBean>().findAll()
paint.setColor(Color.parseColor(mDefaultTextColor))
val objects =realm.where<QsRecordBean>().findAll()
list = realm.copyFromRealm(objects)
}
realm.close()
itemizedLayer =
MyItemizedLayer(
mMapView.vtmMap,
mutableListOf(),
markerRendererFactory,
object : MyItemizedLayer.OnItemGestureListener {
override fun onItemSingleTapUp(
layer: MyItemizedLayer?,
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
override fun onItemLongPress(
layer: MyItemizedLayer?,
list: MutableList<Int>?,
nearest: Int
): Boolean {
return true
}
})
for (item in list) {
val bitmap: Bitmap = createTextMarkerBitmap(mContext, item.description, resId)
if (item.t_lifecycle != 2) {
val geometry: Geometry? = GeometryTools.createGeometry(item.geometry)
if (geometry != null) {
var geoPoint: GeoPoint? = null
if (geometry.geometryType != null) {
when (geometry.geometryType.uppercase(Locale.getDefault())) {
"POINT" -> geoPoint =
GeoPoint(geometry.coordinate.y, geometry.coordinate.x)
// "LINESTRING" -> {
// val lineString = geometry as LineString
// if (lineString != null && lineString.coordinates.size > 0) {
// geoPoint = GeoPoint(
// lineString.coordinates[0].y,
// lineString.coordinates[0].x
// )
// }
// val drawableLine: Drawable =
// convertGeometry2Drawable(geometry, lineStyle)
// if (drawableLine != null) {
// dataVectorLayer.add(drawableLine)
// }
// }
// "POLYGON" -> {
// val polygon = geometry as Polygon
// if (polygon != null && polygon.coordinates.size > 0) {
// geoPoint = GeoPoint(
// polygon.coordinates[0].y,
// polygon.coordinates[0].x
// )
// }
// val drawablePolygon: Drawable =
// convertGeometry2Drawable(geometry, polygonStyle)
// if (drawablePolygon != null) {
// dataVectorLayer.add(drawablePolygon)
// }
// }
}
}
if (geoPoint != null) {
var geoMarkerItem: MarkerItem
// if (item.getType() === 1) {
geoMarkerItem = ClusterMarkerItem(
1, item.id, item.description, geoPoint
)
// } else {
// geoMarkerItem = MarkerItem(
// ePointTemp.getType(),
// ePointTemp.getId(),
// ePointTemp.getStyleText(),
// geoPoint
// )
// }
markerItemsNames.add(geoMarkerItem)
val markerSymbol =
MarkerSymbol(bitmap, MarkerSymbol.HotspotPlace.CENTER)
geoMarkerItem.marker = markerSymbol
}
}
}
}
itemizedLayer.addItems(markerItemsNames)
addLayer(itemizedLayer, NIMapView.LAYER_GROUPS.OPERATE)
withContext(Dispatchers.Main) {
itemizedLayer.map().updateMap(true)
}
}
}
/**
* 文字和图片拼装文字换行
*
* @param context
* @param text
* @param resId
* @return
*/
private fun createTextMarkerBitmap(context: Context, text: String, resId: Int): Bitmap {
var text: String? = text
return if (text == null || text.trim { it <= ' ' }.isEmpty()) {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val originBitmap = android.graphics.Bitmap.createBitmap(
drawable!!.intrinsicWidth,
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_8888
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
bitmap
} else {
val drawable = ResourcesCompat.getDrawable(context.resources, resId, null)
val textList: MutableList<String> = ArrayList()
val fontSize: Float = NUM_13 * CanvasAdapter.getScale()
paint.setTextSize(fontSize)
var maxWidth = 0f
//最多4行一行7个
if (text.trim { it <= ' ' }.length > 24) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
if (text.trim { it <= ' ' }.length > 28) text = text.substring(0, 26) + "..."
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 7)
textList.add(temp3)
text = text.substring(7)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 21) {
val size = (drawable!!.intrinsicHeight / 4).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
val temp3 = text.substring(0, 6)
textList.add(temp3)
text = text.substring(6)
newWidth = paint.getTextWidth(temp3)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 18) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 7)
textList.add(temp2)
text = text.substring(7)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 14) {
val size = (drawable!!.intrinsicHeight / 3).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
val temp2 = text.substring(0, 6)
textList.add(temp2)
text = text.substring(6)
var newWidth = paint.getTextWidth(temp2)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
textList.add(text)
newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 12) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 7)
textList.add(temp1)
text = text.substring(7)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 10) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 6)
textList.add(temp1)
text = text.substring(6)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else if (text.trim { it <= ' ' }.length > 7) {
val size = (drawable!!.intrinsicHeight / 2).toFloat()
if (size < fontSize) paint.setTextSize(size)
val temp1 = text.substring(0, 5)
textList.add(temp1)
text = text.substring(5)
maxWidth = paint.getTextWidth(temp1)
textList.add(text)
val newWidth = paint.getTextWidth(text)
if (newWidth > maxWidth) {
maxWidth = newWidth
}
} else {
val size = drawable!!.intrinsicHeight.toFloat()
if (size < fontSize) paint.setTextSize(size)
textList.add(text)
maxWidth = paint.getTextWidth(text)
}
paint.color = Color.parseColor(mDefaultTextColor)
val originBitmap = android.graphics.Bitmap.createBitmap(
if (drawable.intrinsicWidth > maxWidth) drawable.intrinsicWidth else maxWidth.toInt(),
drawable.intrinsicHeight * 2,
android.graphics.Bitmap.Config.ARGB_4444
)
val androidCanvas = Canvas(originBitmap)
val startX = (originBitmap.width - drawable.intrinsicWidth) / 2
drawable.setBounds(
startX, 0, startX + drawable.intrinsicWidth, drawable.intrinsicHeight
)
drawable.draw(androidCanvas)
val bitmap: Bitmap = AndroidBitmap(originBitmap)
canvas.setBitmap(bitmap)
var startHeight = (drawable.intrinsicHeight + paint.getTextHeight(text)).toInt()
for (txt in textList) {
canvas.drawText(
txt, (bitmap.width - paint.getTextWidth(txt)) / 2, startHeight.toFloat(), paint
)
startHeight += paint.getTextHeight(txt).toInt()
}
bitmap
}
}
// private fun getRasterTileLayer(
// url: String?,
// tilePath: String?,
// useCache: Boolean
// ): Layer {
// val builder = OkHttpClient.Builder()
// val mTileSource =
// NavinfoMapRastorTileSource.builder(url).tilePath(tilePath)
// .httpFactory(OkHttpFactory(builder)).build()
// // 如果使用缓存
// if (useCache) {
// val cacheDirectory =
// File(Constant.MAP_PATH, "cache")
// val cacheSize = 300 * 1024 * 1024 // 300 MB
// val cache = Cache(cacheDirectory, cacheSize.toLong())
// builder.cache(cache)
// }
//
// return BitmapTileLayer(mMapView.vtmMap, mTileSource)
// }
}
/**
* 基础
*/
@ -170,14 +506,10 @@ enum class BASE_MAP_TYPE(// TransportMap底图
var title: String, var url: String, var tilePath: String
) {
OPEN_STREET_MAP(
"Open Street Map",
"http://a.tile.openstreetmap.org",
"/{Z}}/{X}/{Y}.png"
"Open Street Map", "http://a.tile.openstreetmap.org", "/{Z}}/{X}/{Y}.png"
), // openStreetMap底图
CYCLE_MAP(
"Cycle Map",
"http://c.tile.opencyclemap.org/cycle",
"/{Z}}/{X}/{Y}.png"
"Cycle Map", "http://c.tile.opencyclemap.org/cycle", "/{Z}}/{X}/{Y}.png"
), // cyclemap底图
S_MAP(
"SMap",
@ -185,9 +517,7 @@ enum class BASE_MAP_TYPE(// TransportMap底图
"z={Z}&x={X}&y={Y}"
), // cyclemap底图
TRANSPORT_MAP(
"Transport Map",
"http://b.tile2.opencyclemap.org/transport",
"/{Z}}/{X}/{Y}.png"
"Transport Map", "http://b.tile2.opencyclemap.org/transport", "/{Z}}/{X}/{Y}.png"
);
}

View File

@ -3,6 +3,7 @@ package com.navinfo.collect.library.map.handler
import android.content.Context
import android.graphics.BitmapFactory
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.R
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.utils.GeometryTools
@ -21,7 +22,7 @@ import org.oscim.layers.vector.PathLayer
import org.oscim.layers.vector.geometries.Style
import org.oscim.map.Map
open class LineHandler(context: Context, mapView: NIMapView) :
open class LineHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView), Map.UpdateListener {
private var editIndex: Int = -1;

View File

@ -3,6 +3,7 @@ package com.navinfo.collect.library.map.handler
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
@ -13,7 +14,7 @@ import com.navinfo.collect.library.map.NIMapView
import org.oscim.layers.LocationLayer
class LocationLayerHandler(context: Context, mapView: NIMapView) : BaseHandler(context, mapView) {
class LocationLayerHandler(context: AppCompatActivity, mapView: NIMapView) : BaseHandler(context, mapView) {
private var mCurrentLocation: BDLocation? = null
private var bFirst = true

View File

@ -2,6 +2,7 @@ package com.navinfo.collect.library.map.handler
import android.content.Context
import android.graphics.BitmapFactory
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.R
import com.navinfo.collect.library.map.GeoPoint
import com.navinfo.collect.library.map.NIMapView
@ -16,7 +17,7 @@ import org.oscim.layers.marker.MarkerSymbol
/**
* marker 操作
*/
class MarkHandler(context: Context, mapView: NIMapView) :
class MarkHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView) {
// //默认marker图层

View File

@ -6,6 +6,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.text.TextPaint
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.R
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.map.handler.BaseHandler
@ -29,7 +30,7 @@ import org.oscim.layers.vector.geometries.Style
import org.oscim.map.Map
import java.math.BigDecimal
open class MeasureLayerHandler(context: Context, mapView: NIMapView) :
open class MeasureLayerHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView), Map.UpdateListener {
private var editIndex: Int = -1;//线修型的时候,用来表示是不是正在修型,修的第几个点

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.graphics.BitmapFactory
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.R
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.map.layers.NIPolygonLayer
@ -23,7 +24,7 @@ import org.oscim.layers.vector.PathLayer
import org.oscim.layers.vector.geometries.Style
import org.oscim.map.Map
open class PolygonHandler(context: Context, mapView: NIMapView) :
open class PolygonHandler(context: AppCompatActivity, mapView: NIMapView) :
BaseHandler(context, mapView), Map.UpdateListener {
private var editIndex: Int = -1;

View File

@ -1,12 +1,13 @@
package com.navinfo.collect.library.map.handler
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import com.navinfo.collect.library.map.NIMapView
import com.navinfo.collect.library.utils.GeometryTools
import org.oscim.core.GeoPoint
import org.oscim.core.Point
open class ViewportHandler(context: Context, mapView: NIMapView) : BaseHandler(context, mapView) {
open class ViewportHandler(context: AppCompatActivity, mapView: NIMapView) : BaseHandler(context, mapView) {
/**
* Set pivot horizontal / vertical relative to view center in [-1, 1].
* e.g. pivotY 0.5 is usually preferred for navigation, moving center to 25% of view height.

View File

@ -0,0 +1,162 @@
package com.navinfo.collect.library.map.layers;
import android.util.Log;
import org.oscim.backend.CanvasAdapter;
import org.oscim.core.Box;
import org.oscim.core.Tile;
import org.oscim.event.Gesture;
import org.oscim.event.MotionEvent;
import org.oscim.layers.marker.ItemizedLayer;
import org.oscim.layers.marker.MarkerInterface;
import org.oscim.layers.marker.MarkerRendererFactory;
import org.oscim.layers.marker.MarkerSymbol;
import org.oscim.map.Map;
import org.oscim.map.Viewport;
import java.util.ArrayList;
import java.util.List;
/*
*com.nmp.map.layer
*zhjch
*2021/12/9
*15:32
*说明
*/
public class MyItemizedLayer extends ItemizedLayer {
private OnItemGestureListener mOnItemGestureListener;
private final ActiveItem mActiveItemSingleTap;
private final ActiveItem mActiveItemLongPress;
public MyItemizedLayer(Map map, MarkerSymbol defaultMarker) {
this(map, new ArrayList<>(), defaultMarker, null);
}
public MyItemizedLayer(Map map, List<MarkerInterface> list, MarkerSymbol defaultMarker, OnItemGestureListener listener) {
super(map, list, defaultMarker, null);
mOnItemGestureListener = listener;
this.mActiveItemSingleTap = new NamelessClass_2();
this.mActiveItemLongPress = new NamelessClass_1();
}
public MyItemizedLayer(Map map, MarkerRendererFactory markerRendererFactory) {
this(map, new ArrayList<>(), markerRendererFactory, null);
}
class NamelessClass_2 implements ActiveItem {
NamelessClass_2() {
}
public boolean run(List list1, int nearest) {
if (mOnItemGestureListener != null) {
return mOnItemGestureListener.onItemSingleTapUp(MyItemizedLayer.this, list1, nearest);
}
return false;
}
}
class NamelessClass_1 implements ActiveItem {
NamelessClass_1() {
}
public boolean run(List list1, int nearest) {
if (mOnItemGestureListener != null) {
return mOnItemGestureListener.onItemLongPress(MyItemizedLayer.this, list1, nearest);
}
return false;
}
}
public MyItemizedLayer(Map map, List<MarkerInterface> list, MarkerRendererFactory markerRendererFactory, OnItemGestureListener listener) {
super(map, list, markerRendererFactory, null);
mOnItemGestureListener = listener;
this.mActiveItemSingleTap = new NamelessClass_2();
this.mActiveItemLongPress = new NamelessClass_1();
}
@Override
public boolean onGesture(Gesture g, MotionEvent e) {
if (!this.isEnabled()) {
return false;
} else if (g instanceof Gesture.Tap) {
return this.activateSelectedItems(e, this.mActiveItemSingleTap);
} else {
return g instanceof Gesture.LongPress ? this.activateSelectedItems(e, this.mActiveItemLongPress) : false;
}
}
private boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
int size = this.mItemList.size();
Log.e("jingo", "地图点击 size =" + size);
if (size == 0) {
return false;
} else {
int eventX = (int) event.getX() - this.mMap.getWidth() / 2;
int eventY = (int) event.getY() - this.mMap.getHeight() / 2;
Viewport mapPosition = this.mMap.viewport();
Box box = mapPosition.getBBox((Box) null, Tile.SIZE / 2);
box.map2mercator();
box.scale(1000000.0D);
int nearest = -1;
int inside = -1;
// double insideY = -1.7976931348623157E308D;
double dist = (double) (20.0F * CanvasAdapter.getScale() * 20.0F * CanvasAdapter.getScale());
List list = new ArrayList();
for (int i = 0; i < size; ++i) {
MarkerInterface item = (MarkerInterface) this.mItemList.get(i);
if (box.contains((double) item.getPoint().longitudeE6, (double) item.getPoint().latitudeE6)) {
mapPosition.toScreenPoint(item.getPoint(), this.mTmpPoint);
float dx = (float) ((double) eventX - this.mTmpPoint.x);
float dy = (float) ((double) eventY - this.mTmpPoint.y);
MarkerSymbol it = item.getMarker();
if (it == null) {
continue;
// it = this.mMarkerRenderer.mDefaultMarker;
}
if (it.isInside(dx, dy)) {// && this.mTmpPoint.y > insideY) {
// insideY = this.mTmpPoint.y;
inside = i;
list.add(i);
}
if (inside < 0) {
double d = (double) (dx * dx + dy * dy);
if (d <= dist) {
dist = d;
nearest = i;
}
}
}
}
if (inside >= 0) {
nearest = inside;
}
if (nearest >= 0 && task.run(list, nearest)) {
this.mMarkerRenderer.update();
this.mMap.render();
return true;
} else {
return false;
}
}
}
public interface ActiveItem {
boolean run(List list, int nearest);
}
public void setOnItemGestureListener(OnItemGestureListener listener) {
this.mOnItemGestureListener = listener;
}
public interface OnItemGestureListener {
boolean onItemSingleTapUp(MyItemizedLayer layer, List<Integer> list, int nearest);
boolean onItemLongPress(MyItemizedLayer layer, List<Integer> list, int nearest);
}
}