Skip to content

Commit

Permalink
Add Graticule line style support.
Browse files Browse the repository at this point in the history
  • Loading branch information
ComBatVision committed Dec 23, 2023
1 parent 2911993 commit 341e6f3
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,6 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
// private var terrainConformance = 50.0

companion object {
// /**
// * Solid line rendering style. This style specifies that a line will be drawn without any breaks. <br></br>
// * <pre>`_________`</pre>
// * <br></br> is an example of a solid line.
// */
// val LINE_STYLE_SOLID = GraticuleRenderingParams.VALUE_LINE_STYLE_SOLID
// /**
// * Dashed line rendering style. This style specifies that a line will be drawn as a series of long strokes, with
// * space in between. <br></br>
// * <pre>`- - - - -`</pre>
// * <br></br> is an example of a dashed line.
// */
// val LINE_STYLE_DASHED = GraticuleRenderingParams.VALUE_LINE_STYLE_DASHED
// /**
// * Dotted line rendering style. This style specifies that a line will be drawn as a series of evenly spaced "square"
// * dots. <br></br>
// * <pre>`. . . . .`</pre>
// * is an example of a dotted line.
// */
// val LINE_STYLE_DOTTED = GraticuleRenderingParams.VALUE_LINE_STYLE_DOTTED
private const val LOOK_AT_LATITUDE_PROPERTY = "look_at_latitude"
private const val LOOK_AT_LONGITUDE_PROPERTY = "look_at_longitude"
private const val GRATICULE_PIXEL_SIZE_PROPERTY = "graticule_pixel_size"
Expand Down Expand Up @@ -124,25 +104,25 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
* @param lineWidth width of the graticule lines.
* @param key the rendering parameters key.
*/
fun setGraticuleLineWidth(lineWidth: Double, key: String) { getRenderingParams(key).lineWidth = lineWidth }

// /**
// * Returns the graticule line rendering style.
// *
// * @param key the rendering parameters key.
// *
// * @return rendering style of the graticule lines.
// */
// fun getGraticuleLineStyle(key: String) = getRenderingParams(key).lineStyle
//
// /**
// * Sets the graticule line rendering style.
// *
// * @param lineStyle rendering style of the graticule lines. One of LINE_STYLE_SOLID, LINE_STYLE_DASHED, or
// * LINE_STYLE_DOTTED.
// * @param key the rendering parameters key.
// */
// fun setGraticuleLineStyle(lineStyle: String, key: String) { getRenderingParams(key).lineStyle = lineStyle }
fun setGraticuleLineWidth(lineWidth: Float, key: String) { getRenderingParams(key).lineWidth = lineWidth }

/**
* Returns the graticule line rendering style.
*
* @param key the rendering parameters key.
*
* @return rendering style of the graticule lines.
*/
fun getGraticuleLineStyle(key: String) = getRenderingParams(key).lineStyle

/**
* Sets the graticule line rendering style.
*
* @param lineStyle rendering style of the graticule lines.
* One of [LineStyle.SOLID], [LineStyle.DASHED], [LineStyle.DOTTED] or [LineStyle.DASH_DOTTED].
* @param key the rendering parameters key.
*/
fun setGraticuleLineStyle(lineStyle: LineStyle, key: String) { getRenderingParams(key).lineStyle = lineStyle }

/**
* Returns whether graticule labels will be rendered.
Expand Down Expand Up @@ -267,29 +247,8 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
lastVerticalExaggeration = rc.verticalExaggeration
// lastGlobe = rc.globe
// if (rc.is2DGlobe) lastProjection = (rc.globe as Globe2D).projection
// terrainConformance = computeTerrainConformance(rc)
// applyTerrainConformance()
}

// private fun computeTerrainConformance(rc: RenderContext): Double {
// var value = 100
// val alt = rc.camera.position.altitude
// when {
// alt < 10e3 -> value = 20
// alt < 50e3 -> value = 30
// alt < 100e3 -> value = 40
// alt < 1000e3 -> value = 60
// }
// return value.toDouble()
// }
//
// private fun applyTerrainConformance() {
// val graticuleType = getOrderedTypes()
// for (type in graticuleType) {
// getRenderingParams(type)[GraticuleRenderingParams.KEY_LINE_CONFORMANCE] = terrainConformance
// }
// }

fun computeLabelOffset(rc: RenderContext): Location {
return if (hasLookAtPos(rc)) {
val labelOffsetDegrees = getLabelOffset(rc)
Expand All @@ -307,9 +266,8 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {

fun createLineRenderable(positions: List<Position>, pathType: PathType) = Path(positions).apply {
this.pathType = pathType
isFollowTerrain = true
// terrainConformance = 1.0 // TODO Why not terrainConformance?
altitudeMode = AltitudeMode.CLAMP_TO_GROUND
isFollowTerrain = true
}

@Suppress("UNUSED_PARAMETER")
Expand Down Expand Up @@ -360,9 +318,9 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
fun computeTruncatedSegment(p1: Position, p2: Position, sector: Sector, positions: MutableList<Position>) {
val p1In = sector.contains(p1.latitude, p1.longitude)
val p2In = sector.contains(p2.latitude, p2.longitude)
if (!p1In && !p2In) return // whole segment is (likely) outside
if (!p1In && !p2In) return // the whole segment is (likely) outside
if (p1In && p2In) {
// whole segment is (likely) inside
// the whole segment is (likely) inside
positions.add(p1)
positions.add(p2)
} else {
Expand Down Expand Up @@ -422,7 +380,7 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
val deltaLon = getDeltaLongitude(p1, p2.longitude)
if (getDeltaLongitude(p1, longitude) < deltaLon && getDeltaLongitude(p2, longitude) < deltaLon) {
var count = 0
val precision = 1.0 / 6378137.0 // 1m angle in radians
val precision = 1.0 / Ellipsoid.WGS84.semiMajorAxis // 1m angle in radians
var a = p1
var b = p2
var midPoint = greatCircleMidPoint(a, b)
Expand Down Expand Up @@ -451,7 +409,7 @@ abstract class AbstractGraticuleLayer(name: String): AbstractLayer(name) {
var pos: Location? = null
if (sign(p1.latitude.inDegrees - latitude.inDegrees) != sign(p2.latitude.inDegrees - latitude.inDegrees)) {
var count = 0
val precision = 1.0 / 6378137.0 // 1m angle in radians
val precision = 1.0 / Ellipsoid.WGS84.semiMajorAxis // 1m angle in radians
var a = p1
var b = p2
var midPoint = greatCircleMidPoint(a, b)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ class GraticuleRenderingParams: MutableMap<String, Any?> by HashMap() {
var lineColor: Color?
get() = get(KEY_LINE_COLOR) as? Color
set(color) { put(KEY_LINE_COLOR, color) }
var lineWidth: Double
get() = get(KEY_LINE_WIDTH) as? Double ?: 0.0
var lineWidth: Float
get() = get(KEY_LINE_WIDTH) as? Float ?: 0.0f
set(lineWidth) { put(KEY_LINE_WIDTH, lineWidth) }
// var lineStyle: String?
// get() = get(KEY_LINE_STYLE) as? String
// set(lineStyle) { put(KEY_LINE_STYLE, lineStyle) }
var lineStyle: LineStyle
get() = get(KEY_LINE_STYLE) as? LineStyle ?: LineStyle.SOLID
set(lineStyle) { put(KEY_LINE_STYLE, lineStyle) }
var isDrawLabels: Boolean
get() = get(KEY_DRAW_LABELS) as? Boolean ?: false
set(drawLabels) { put(KEY_DRAW_LABELS, drawLabels) }
Expand All @@ -26,26 +26,13 @@ class GraticuleRenderingParams: MutableMap<String, Any?> by HashMap() {
get() = get(KEY_LABEL_FONT) as? Font
set(font) { put(KEY_LABEL_FONT, font) }

fun getStringValue(key: String) = this[key]?.toString()

fun getFloatValue(key: String): Float? {
val o = get(key) ?: return null
if (o is Float) return o
val v = getStringValue(key)
return v?.toFloat()
}

companion object {
const val KEY_DRAW_LINES = "DrawGraticule"
const val KEY_LINE_COLOR = "GraticuleLineColor"
const val KEY_LINE_WIDTH = "GraticuleLineWidth"
// const val KEY_LINE_STYLE = "GraticuleLineStyle";
// const val KEY_LINE_CONFORMANCE = "GraticuleLineConformance";
const val KEY_LINE_STYLE = "GraticuleLineStyle";
const val KEY_DRAW_LABELS = "DrawLabels"
const val KEY_LABEL_COLOR = "LabelColor"
const val KEY_LABEL_FONT = "LabelFont"
// const val VALUE_LINE_STYLE_SOLID = "LineStyleSolid";
// const val VALUE_LINE_STYLE_DASHED = "LineStyleDashed";
// const val VALUE_LINE_STYLE_DOTTED = "LineStyleDotted";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_DR
import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_LABEL_COLOR
import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_LABEL_FONT
import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_LINE_COLOR
import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_LINE_STYLE
import earth.worldwind.layer.graticule.GraticuleRenderingParams.Companion.KEY_LINE_WIDTH
import earth.worldwind.render.*
import earth.worldwind.render.image.ImageSource
import earth.worldwind.shape.Label
import earth.worldwind.shape.Path
import earth.worldwind.shape.ShapeAttributes
Expand Down Expand Up @@ -60,7 +62,7 @@ internal class GraticuleSupport {
if (params[KEY_DRAW_LINES] == null) params[KEY_DRAW_LINES] = true
if (params[KEY_LINE_COLOR] == null) params[KEY_LINE_COLOR] = Color(255, 255, 255) // White
if (params[KEY_LINE_WIDTH] == null) params[KEY_LINE_WIDTH] = .5f
// if (params[KEY_LINE_STYLE] == null) params[KEY_LINE_STYLE] = GraticuleRenderingParams.VALUE_LINE_STYLE_SOLID
if (params[KEY_LINE_STYLE] == null) params[KEY_LINE_STYLE] = LineStyle.SOLID
if (params[KEY_DRAW_LABELS] == null) params[KEY_DRAW_LABELS] = true
if (params[KEY_LABEL_COLOR] == null) params[KEY_LABEL_COLOR] = Color(255, 255, 255) // White
if (params[KEY_LABEL_FONT] == null) params[KEY_LABEL_FONT] = Font("arial", FontWeight.BOLD, 12)
Expand Down Expand Up @@ -98,27 +100,14 @@ internal class GraticuleSupport {
attrs.isDrawOutline = true

// Apply "line" properties.
val o = params[KEY_LINE_COLOR]
if (o is Color) attrs.outlineColor = applyOpacity(o, opacity)
val lineWidth = params.getFloatValue(KEY_LINE_WIDTH)
if (lineWidth != null) attrs.outlineWidth = lineWidth
// val s = params.getStringValue(KEY_LINE_STYLE)
// when {
// VALUE_LINE_STYLE_SOLID.equals(s, true) -> {
// attrs.outlineStipplePattern = 0xAAAA.toShort()
// attrs.outlineStippleFactor = 0
// }
// VALUE_LINE_STYLE_DASHED.equals(s, true) -> {
// val baseFactor = lineWidth?.roundToInt() ?: 1
// attrs.outlineStipplePattern = 0xAAAA.toShort()
// attrs.outlineStippleFactor = 3 * baseFactor
// }
// VALUE_LINE_STYLE_DOTTED.equals(s, true) -> {
// val baseFactor = lineWidth?.roundToInt() ?: 1
// attrs.outlineStipplePattern =0xAAAA.toShort()
// attrs.outlineStippleFactor = baseFactor
// }
// }
val color = params[KEY_LINE_COLOR]
if (color is Color) attrs.outlineColor = applyOpacity(color, opacity)
val lineWidth = params[KEY_LINE_WIDTH]
if (lineWidth is Float) attrs.outlineWidth = lineWidth
val style = params[KEY_LINE_STYLE]
if (style is LineStyle && style.factor > 0) {
attrs.outlineImageSource = ImageSource.fromLineStipple(style.factor, style.pattern)
}
return attrs
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package earth.worldwind.layer.graticule

/**
* A line stipple pattern.
*
* @param factor specifies the number of times each bit in the pattern is repeated before the next bit is used. For
* example, if the factor is 3, each bit is repeated three times before using the next bit. The
* specified factor must be either zero or an integer greater than 0. A factor of 0 indicates no
* stippling.
* @param pattern specifies a number whose lower 16 bits define a pattern of which pixels in the image are white and
* which are transparent. Each bit corresponds to a pixel, and the pattern repeats after every n*16
* pixels, where n is the factor. For example, if the factor is 3, each bit in the pattern is
* repeated three times before using the next bit.
*/
enum class LineStyle(val factor: Int, val pattern: Short) {
SOLID(0, 0x0000),
DASHED(1, 0xFFE0.toShort()),
DOTTED(2, 0xCCCC.toShort()),
DASH_DOTTED(2, 0xFFCC.toShort())
}

0 comments on commit 341e6f3

Please sign in to comment.