@@ -2,45 +2,19 @@ package earth.worldwind.formats.kml
22
33import earth.worldwind.MR
44import earth.worldwind.formats.*
5- import earth.worldwind.formats.DEFAULT_DENSITY
6- import earth.worldwind.formats.DEFAULT_FILL_COLOR
7- import earth.worldwind.formats.DEFAULT_IMAGE_SCALE
8- import earth.worldwind.formats.DEFAULT_LINE_COLOR
9- import earth.worldwind.formats.HIGHLIGHT_INCREMENT
10- import earth.worldwind.formats.forceHttps
11- import earth.worldwind.formats.isValidHttpsUrl
12- import earth.worldwind.formats.kml.models.Geometry
13- import earth.worldwind.formats.kml.models.GroundOverlay
14- import earth.worldwind.formats.kml.models.Icon
15- import earth.worldwind.formats.kml.models.IconStyle
16- import earth.worldwind.formats.kml.models.LabelStyle
17- import earth.worldwind.formats.kml.models.LatLonBox
18- import earth.worldwind.formats.kml.models.LineString
19- import earth.worldwind.formats.kml.models.LineStyle
20- import earth.worldwind.formats.kml.models.LinearRing
21- import earth.worldwind.formats.kml.models.MultiGeometry
5+ import earth.worldwind.formats.kml.models.*
6+ import earth.worldwind.formats.kml.models.AltitudeMode as KMLAltitudeMode
227import earth.worldwind.formats.kml.models.Placemark
23- import earth.worldwind.formats.kml.models.Point
24- import earth.worldwind.formats.kml.models.PolyStyle
258import earth.worldwind.formats.kml.models.Polygon
26- import earth.worldwind.formats.kml.models.Style
9+ import earth.worldwind.geom.*
2710import earth.worldwind.geom.AltitudeMode
28- import earth.worldwind.geom.Angle
29- import earth.worldwind.geom.Offset
11+ import earth.worldwind.geom.Angle.Companion.degrees
3012import earth.worldwind.geom.OffsetMode.FRACTION
3113import earth.worldwind.geom.OffsetMode.PIXELS
32- import earth.worldwind.geom.Position
33- import earth.worldwind.geom.Sector
3414import earth.worldwind.render.Color
3515import earth.worldwind.render.Renderable
3616import earth.worldwind.render.image.ImageSource
37- import earth.worldwind.shape.AbstractShape
38- import earth.worldwind.shape.Label
39- import earth.worldwind.shape.Path
40- import earth.worldwind.shape.PathType
41- import earth.worldwind.shape.ShapeAttributes
42- import earth.worldwind.shape.SurfaceImage
43- import earth.worldwind.shape.TextAttributes
17+ import earth.worldwind.shape.*
4418
4519internal class KmlToRenderableConverter {
4620
@@ -54,12 +28,12 @@ internal class KmlToRenderableConverter {
5428 /* *
5529 * optimized method to get coordinates from a string
5630 */
57- private fun extractPoints (input : String? , altitudeOffset : Double? = 0.0): List <Position > {
31+ private fun extractPoints (input : String , altitudeOffset : Double = 0.0): List <Position > {
5832 // Normalize input by trimming leading/trailing whitespaces
5933 // and replacing all forms of space with a single space
60- val normalizedInput = input? .trim()? .replace(spaceCharsRegex, " " )
34+ val normalizedInput = input.trim().replace(spaceCharsRegex, " " )
6135
62- if (normalizedInput.isNullOrBlank ()) return emptyList()
36+ if (normalizedInput.isBlank ()) return emptyList()
6337
6438 val result = mutableListOf<Position >()
6539 val length = normalizedInput.length
@@ -107,7 +81,7 @@ internal class KmlToRenderableConverter {
10781 i++ // Skip the comma
10882 start = i
10983 while (i < length && normalizedInput[i] != ' ' ) i++
110- alt = parseDouble(start, i) + ( altitudeOffset ? : 0.0 )
84+ alt = parseDouble(start, i) + altitudeOffset
11185 }
11286
11387 result.add(Position .fromDegrees(lat, lon, alt ? : 0.0 ))
@@ -137,7 +111,7 @@ internal class KmlToRenderableConverter {
137111 placemark : Placemark ,
138112 definedStyle : Style ? = null,
139113 ): List <Renderable > {
140- val style = placemark.stylesList?.firstOrNull() ? : definedStyle
114+ val style = placemark.styleSelector as ? Style ? : definedStyle // TODO Add support of StyleMap
141115 val geometry: Geometry = placemark.geometryList?.firstOrNull() ? : return emptyList()
142116 return getRenderableFrom(geometry, style, placemark.name)
143117 }
@@ -186,7 +160,7 @@ internal class KmlToRenderableConverter {
186160 lineString : LineString ,
187161 style : Style ? ,
188162 name : String?
189- ) = Path (extractPoints(lineString.coordinates? .value, lineString.altitudeOffset)).apply {
163+ ) = Path (extractPoints(lineString.coordinates.value, lineString.altitudeOffset)).apply {
190164 altitudeMode = getAltitudeModeFrom(lineString.altitudeMode)
191165 isExtrude = lineString.extrude == true
192166 isFollowTerrain = lineString.tessellate == true
@@ -204,7 +178,7 @@ internal class KmlToRenderableConverter {
204178 linearRing : LinearRing ,
205179 style : Style ? ,
206180 name : String?
207- ) = Path (extractPoints(linearRing.coordinates? .value, linearRing.altitudeOffset)).apply {
181+ ) = Path (extractPoints(linearRing.coordinates.value, linearRing.altitudeOffset)).apply {
208182 altitudeMode = getAltitudeModeFrom(linearRing.altitudeMode)
209183 isExtrude = linearRing.extrude == true
210184 isFollowTerrain = linearRing.tessellate == true
@@ -232,18 +206,14 @@ internal class KmlToRenderableConverter {
232206 maximumIntermediatePoints = 0 // Disable intermediate point for performance reasons
233207
234208 polygon.outerBoundaryIs?.let {
235- it.value?.forEach { linearRing ->
236- linearRing.coordinates?.value?.let { value ->
237- addBoundary(extractPoints(value, linearRing.altitudeOffset))
238- }
209+ it.value.let { linearRing ->
210+ addBoundary(extractPoints(linearRing.coordinates.value, linearRing.altitudeOffset))
239211 }
240212 }
241213
242214 polygon.innerBoundaryIs?.let {
243- it.value?.forEach { linearRing ->
244- linearRing.coordinates?.value?.let { value ->
245- addBoundary(extractPoints(value, linearRing.altitudeOffset))
246- }
215+ it.value.forEach { linearRing ->
216+ addBoundary(extractPoints(linearRing.coordinates.value, linearRing.altitudeOffset))
247217 }
248218 }
249219
@@ -266,10 +236,10 @@ internal class KmlToRenderableConverter {
266236 }
267237
268238 private fun createPlacemark (point : Point , style : Style ? , name : String? ): Renderable ? {
269- val position = extractPoints(point.coordinates? .value).firstOrNull() ? : return null
239+ val position = extractPoints(point.coordinates.value).firstOrNull() ? : return null
270240
271- val iconStyle = style?.stylesList ?.filterIsInstance<IconStyle >()?.firstOrNull()
272- val labelStyle = style?.stylesList ?.filterIsInstance<LabelStyle >()?.firstOrNull()
241+ val iconStyle = style?.styles ?.filterIsInstance<IconStyle >()?.firstOrNull()
242+ val labelStyle = style?.styles ?.filterIsInstance<LabelStyle >()?.firstOrNull()
273243
274244 return if (iconStyle?.scale == 0.0 ) {
275245 Label (position, name).apply {
@@ -286,7 +256,8 @@ internal class KmlToRenderableConverter {
286256 imageSource = iconStyle?.icon?.toImageSource()?.also { imageScale * = density }
287257 ? : ImageSource .fromResource(MR .images.kml_placemark) // Do not scale default placemark
288258 imageColor = iconStyle?.color?.let { fromHexABRG(it) } ? : defaultIconColor
289- imageOffset = if (altitudeMode == AltitudeMode .CLAMP_TO_GROUND ) Offset .bottomCenter() else Offset .center()
259+ imageOffset = iconStyle?.hotSpot?.let { Offset (getOffsetModeFrom(it.xunits), it.x, getOffsetModeFrom(it.yunits), it.y) }
260+ ? : if (altitudeMode == AltitudeMode .CLAMP_TO_GROUND ) Offset .bottomCenter() else Offset .center()
290261
291262 attributes.isDrawLeader = point.extrude == true
292263
@@ -312,27 +283,14 @@ internal class KmlToRenderableConverter {
312283 }
313284 }
314285
315- private fun LatLonBox.toSector (): Sector ? {
316- val north = north ? : return null
317- val south = south ? : return null
318- val east = east ? : return null
319- val west = west ? : return null
320-
321- return Sector (
322- Angle .fromDegrees(south),
323- Angle .fromDegrees(north),
324- Angle .fromDegrees(west),
325- Angle .fromDegrees(east)
326- )
327- }
286+ private fun LatLonBox.toSector () = Sector (south.degrees, north.degrees, west.degrees, east.degrees)
328287
329288 private fun TextAttributes.applyStyle (labelStyle : LabelStyle ? ) {
330289 apply {
331290 labelStyle?.color?.let {
332291 textColor = fromHexABRG(it)
333292 outlineColor = textColor.toContrastColor()
334293 }
335- labelStyle?.width?.let { outlineWidth = it }
336294 textOffset = Offset .center()
337295 }
338296 }
@@ -344,8 +302,8 @@ internal class KmlToRenderableConverter {
344302
345303 private fun AbstractShape.applyStyleOnShapeAttributes (style : Style ? ) {
346304 attributes.apply {
347- val lineStyle = style?.stylesList ?.filterIsInstance<LineStyle >()?.firstOrNull()
348- val polyStyle = style?.stylesList ?.filterIsInstance<PolyStyle >()?.firstOrNull()
305+ val lineStyle = style?.styles ?.filterIsInstance<LineStyle >()?.firstOrNull()
306+ val polyStyle = style?.styles ?.filterIsInstance<PolyStyle >()?.firstOrNull()
349307
350308 outlineColor = lineStyle?.color?.let { fromHexABRG(it) } ? : defaultLineColor
351309 interiorColor = polyStyle?.color?.let { fromHexABRG(it) } ? : defaultFillColor
@@ -360,10 +318,16 @@ internal class KmlToRenderableConverter {
360318 }
361319 }
362320
363- private fun getAltitudeModeFrom (value : String ? ) = when (value) {
364- " absolute" -> AltitudeMode .ABOVE_SEA_LEVEL
365- " clampToGround" -> AltitudeMode .CLAMP_TO_GROUND
366- " relativeToGround" -> AltitudeMode .RELATIVE_TO_GROUND
321+ private fun getAltitudeModeFrom (value : KMLAltitudeMode ? ) = when (value) {
322+ KMLAltitudeMode . absolute -> AltitudeMode .ABOVE_SEA_LEVEL
323+ KMLAltitudeMode . clampToGround -> AltitudeMode .CLAMP_TO_GROUND
324+ KMLAltitudeMode . relativeToGround -> AltitudeMode .RELATIVE_TO_GROUND
367325 else -> AltitudeMode .CLAMP_TO_GROUND
368326 }
327+
328+ private fun getOffsetModeFrom (value : HotSpotUnits ) = when (value) {
329+ HotSpotUnits .pixels -> OffsetMode .PIXELS
330+ HotSpotUnits .fraction -> OffsetMode .FRACTION
331+ HotSpotUnits .insetPixels -> OffsetMode .INSET_PIXELS
332+ }
369333}
0 commit comments