Очень необходимо встраивать автономные карты в настольное приложение.Лучшее, на что я смотрю - это Mapsforge.Но я столкнулся с небольшой проблемой.Я использую JavaFX (Kotlin - TornadoFX) и не могу использовать используемый там AWT.Я пытаюсь сделать это через JPanel и Swingnode.Карта не показана.
Мой код, если необходимо:
class MyApp : App(SecondView::class, Styles::class) {
private val GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE
private val SHOW_DEBUG_LAYERS = false
private val SHOW_RASTER_MAP = false
override fun start(stage: Stage) {
val swingNode = SwingNode()
createSwingContent(swingNode)
val pane = StackPane()
pane.children.add(swingNode)
stage.title = "Swing in KotlinFX"
stage.scene = Scene(pane, 800.0, 600.0)
stage.show()
}
private fun createSwingContent(swingNode: SwingNode) {
SwingUtilities.invokeLater {
val jPanel = JPanel()
//это с main
org.mapsforge.core.util.Parameters.NUMBER_OF_THREADS = 2
org.mapsforge.core.util.Parameters.SQUARE_FRAME_BUFFER = false
var hillsCfg:HillsRenderConfig? = null
var args = arrayOf("/Users/dev/Documents/maps/world.map")
var demFolder = getDemFolder(args)
if (demFolder!=null) {
var tileSource = MemoryCachingHgtReaderTileSource(demFolder, DiffuseLightShadingAlgorithm(), AwtGraphicFactory.INSTANCE)
tileSource.isEnableInterpolationOverlap = true
hillsCfg = HillsRenderConfig(tileSource)
hillsCfg.indexOnThread()
args = Arrays.copyOfRange(args,1,args.size)
}
var mapFiles = if (SHOW_RASTER_MAP) {null} else {getMapFiles(args)}
val mapView = createMapView()
mapView.model.mapViewPosition.mapPosition = MapPosition(LatLong(0.0, 0.0),14.toByte())
val boundingBox = addLayers(mapView, mapFiles,hillsCfg)
jPanel.add(mapView)
swingNode.content = jPanel
}
}
private fun addLayers(mapView: MapView, mapFiles: List<File>?, hillsRenderConfig: HillsRenderConfig?): BoundingBox {
val layers = mapView.layerManager.layers
val tileSize = if (SHOW_RASTER_MAP) 256 else 512
// Tile cache
val tileCache = AwtUtil.createTileCache(
tileSize,
mapView.model.frameBufferModel.overdrawFactor,
1024,
File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()))
val boundingBox: BoundingBox
if (SHOW_RASTER_MAP) {
// Raster
mapView.model.displayModel.setFixedTileSize(tileSize)
val tileSource = OpenStreetMapMapnik.INSTANCE
val tileDownloadLayer = createTileDownloadLayer(tileCache, mapView.model.mapViewPosition, tileSource)
layers.add(tileDownloadLayer)
tileDownloadLayer.start()
mapView.setZoomLevelMin(tileSource.zoomLevelMin)
mapView.setZoomLevelMax(tileSource.zoomLevelMax)
boundingBox = BoundingBox(LatLongUtils.LATITUDE_MIN, LatLongUtils.LONGITUDE_MIN, LatLongUtils.LATITUDE_MAX, LatLongUtils.LONGITUDE_MAX)
} else {
// Vector
mapView.model.displayModel.setFixedTileSize(tileSize)
val mapDataStore = MultiMapDataStore(MultiMapDataStore.DataPolicy.RETURN_ALL)
if (mapFiles!=null) {
for (file in mapFiles) {
mapDataStore.addMapDataStore(MapFile(file), false, false)
}
}
val tileRendererLayer = createTileRendererLayer(tileCache, mapDataStore, mapView.model.mapViewPosition, hillsRenderConfig)
layers.add(tileRendererLayer)
boundingBox = mapDataStore.boundingBox()
}
// Debug
if (SHOW_DEBUG_LAYERS) {
layers.add(TileGridLayer(GRAPHIC_FACTORY, mapView.model.displayModel))
layers.add(TileCoordinatesLayer(GRAPHIC_FACTORY, mapView.model.displayModel))
}
return boundingBox
}
private fun createMapView(): MapView {
val mapView = MapView()
mapView.mapScaleBar.isVisible = true
if (SHOW_DEBUG_LAYERS) {
mapView.fpsCounter.isVisible = true
}
return mapView
}
private fun createTileDownloadLayer(tileCache: TileCache, mapViewPosition: IMapViewPosition, tileSource: TileSource): TileDownloadLayer {
return object : TileDownloadLayer(tileCache, mapViewPosition, tileSource, GRAPHIC_FACTORY) {
fun onTap(tapLatLong: LatLong, layerXY: Point, tapXY: Point): Boolean {
println("Tap on: $tapLatLong")
return true
}
override fun onTap(tapLatLong: LatLong?, layerXY: org.mapsforge.core.model.Point?, tapXY: org.mapsforge.core.model.Point?): Boolean {
println("Tap1 on: $tapLatLong")
return super.onTap(tapLatLong, layerXY, tapXY)
}
}
}
private fun createTileRendererLayer(tileCache: TileCache, mapDataStore: MapDataStore, mapViewPosition: IMapViewPosition, hillsRenderConfig: HillsRenderConfig?): TileRendererLayer {
val tileRendererLayer = object : TileRendererLayer(tileCache, mapDataStore, mapViewPosition, false, true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
override fun onTap(tapLatLong: LatLong?, layerXY: org.mapsforge.core.model.Point?, tapXY: org.mapsforge.core.model.Point?): Boolean {
println("TAP on: $tapLatLong")
return true
}
}
tileRendererLayer.setXmlRenderTheme(InternalRenderTheme.DEFAULT)
return tileRendererLayer
}
private fun getDemFolder(args: Array<String>): File? {
if (args.size == 0) {
return if (SHOW_RASTER_MAP) {
null
} else {
throw IllegalArgumentException("missing argument: <mapFile>")
}
}
val demFolder = File(args[0])
return if (demFolder.exists() && demFolder.isDirectory && demFolder.canRead()) {
demFolder
} else null
}
private fun getMapFiles(args:Array<String>): List<File> {
if (args.size == 0) {
throw IllegalStateException("missing argument: <mapFile>")
}
var result = ArrayList<File>()
for (arg in args) {
var mapFile = File(arg)
if (!mapFile.exists()) {
throw IllegalArgumentException("file does not exist: " + mapFile);
} else if (!mapFile.isFile()) {
throw IllegalArgumentException("not a file: " + mapFile);
} else if (!mapFile.canRead()) {
throw IllegalArgumentException("cannot read file: " + mapFile);
}
result.add(mapFile)
}
return result
}
}
Или есть какое-то простое использование карт для JavaX и Openstreetmap?