JavaFX和Mapsforge
在桌面应用程序中嵌入脱机地图是非常必要的。我看到的最好的是Mapsforge。但我遇到了一个小问题。我使用JavaFX(Kotlin-TornadoFX),不能使用那里使用的AWT。我试着通过JPanel和Swingnode来做这件事。地图没有显示 我的代码(如果需要):JavaFX和Mapsforge,java,javafx,openstreetmap,tornadofx,mapsforge,Java,Javafx,Openstreetmap,Tornadofx,Mapsforge,在桌面应用程序中嵌入脱机地图是非常必要的。我看到的最好的是Mapsforge。但我遇到了一个小问题。我使用JavaFX(Kotlin-TornadoFX),不能使用那里使用的AWT。我试着通过JPanel和Swingnode来做这件事。地图没有显示 我的代码(如果需要): class MyApp : App(SecondView::class, Styles::class) { private val GRAPHIC_FACTORY = AwtGraphicFactory.INSTAN
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
}
}
class MyApp:App(SecondView::class,Styles::class){
private val GRAPHIC_FACTORY=awtgraphic FACTORY.INSTANCE
private val SHOW_DEBUG_LAYERS=false
私有val显示\光栅\映射=假
覆盖乐趣开始(阶段:阶段){
val swingNode=swingNode()
创建SwingContent(swingNode)
val pane=StackPane()
pane.children.add(swingNode)
stage.title=“在KotlinFX中摆动”
stage.scene=场景(窗格,800.0600.0)
舞台秀
}
私人娱乐创建SwingContent(swingNode:swingNode){
SwingUtilities.invokeLater{
val jPanel=jPanel()
//主管道
org.mapsforge.core.util.Parameters.NUMBER_OF_线程=2
org.mapsforge.core.util.Parameters.SQUARE\u FRAME\u BUFFER=false
var hillsCfg:HillsRenderConfig?=null
var args=arrayOf(“/Users/dev/Documents/maps/world.map”)
var demFolder=getDemFolder(args)
如果(demFolder!=null){
var tileSource=memorycachinghtreadertilesource(devfolder,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(地图视图、地图文件、hillsCfg)
jPanel.add(地图视图)
swignode.content=jPanel
}
}
private fun addLayers(mapView:mapView,mapFiles:List?,HillRenderConfig:HillRenderConfig?):BoundingBox{
val layers=mapView.layerManager.layers
val tileSize=if(显示光栅图)256 else 512
//磁贴缓存
val tileCache=AwtUtil.createTileCache(
瓷砖化,
mapView.model.frameBufferModel.overdrawFactor,
1024,
文件(System.getProperty(“java.io.tmpdir”)、UUID.randomUUID().toString())
val边界框:边界框
if(显示栅格地图){
//光栅
mapView.model.displayModel.SetFixedTitleSize(波浪大小)
val tileSource=openstreetmappnik.INSTANCE
val tileDownloadLayer=createTileDownloadLayer(tileCache,mapView.model.mapViewPosition,tileSource)
图层。添加(平铺下载图层)
tileDownloadLayer.start()
mapView.setZoomLevelMin(tileSource.zoomLevelMin)
mapView.setZoomLevelMax(tileSource.zoomLevelMax)
boundingBox=边界框(LatLongUtils.LATITUDE\u MIN、LatLongUtils.LONGITUDE\u MIN、LatLongUtils.LATITUDE\u MAX、LatLongUtils.LONGITUDE\u MAX)
}否则{
//载体
mapView.model.displayModel.SetFixedTitleSize(波浪大小)
val mapDataStore=MultiMapDataStore(MultiMapDataStore.DataPolicy.RETURN_ALL)
if(mapFiles!=null){
用于(mapFiles中的文件){
addMapDataStore(映射文件,false,false)
}
}
val TilerenderLayer=CreateTilerenderLayer(tileCache,mapDataStore,mapView.model.mapViewPosition,hillsRenderConfig)
图层。添加(TilerEnderLayer)
boundingBox=mapDataStore.boundingBox()
}
//调试
如果(显示调试层){
添加(TileGridLayer(图形工厂,mapView.model.displayModel))
图层.添加(TileCoordinatesLayer(图形工厂,mapView.model.displayModel))
}
返回边界框
}
private fun createMapView():MapView{
val mapView=mapView()
mapView.mapScaleBar.isVisible=true
如果(显示调试层){
mapView.fpsCounter.isVisible=true
}
返回地图视图
}
private fun createTileDownloadLayer(tileCache:tileCache,mapViewPosition:IMapViewPosition,tileSource:tileSource):TileDownloadLayer{
返回对象:TileDownloadLayer(tileCache、mapViewPosition、tileSource、GRAPHIC_FACTORY){
趣味onTap(tapLatLong:LatLong,layerXY:Point,tapXY:Point):布尔值{
println(“点击:$tapLatLong”)
返回真值
}
覆盖趣味onTap(tapLatLong:LatLong?、layerXY:org.mapsforge.core.model.Point?、tapXY:org.mapsforge.core.model.Point?):布尔值{
println(“Tap1 on:$tapLatLong”)
返回super.onTap(tapLatLong、layerXY、tapXY)
}
}
}
private fun CreateTilerEnderLayer(tileCache:tileCache,mapDataStore:mapDataStore,mapViewPosition:IMapViewPosition,HillRenderConfig:HillRenderConfig?):TilerEnderLayer{
val TilerEnderLayer=对象:TilerEnderLayer(tileCache、mapDataStore、mapViewPosition、false、true、false、GRAPHIC_FACTORY、HillRenderConfig){
覆盖趣味onTap(tapLatLong:LatLong?、layerXY:org.mapsforge.core.model.Point?、tapXY:org.mapsforge.core.model.Point?):布尔值{
println(“点击:$tapLatLong”)
返回真值
}
}
TilerEnderLayer.setXmlRenderTheme(InternalRenderTheme.DEFAULT)
返回TilerEnderLayer
}
私有有趣的getDemFolder(args:Array):文件{
如果(args.size==0){
返回if(显示栅格地图){
无效的
}否则{
抛出IllegalArgumentException(“MSI