mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
Prevent whole-globe land fills
This commit is contained in:
parent
6edd361ed3
commit
0d7f8cef10
@ -684,19 +684,18 @@ private fun DrawScope.fillPolygonClipped(
|
|||||||
cx: Float, cy: Float, r: Float,
|
cx: Float, cy: Float, r: Float,
|
||||||
color: Color,
|
color: Color,
|
||||||
clip: ClipRect,
|
clip: ClipRect,
|
||||||
centerInsideRing: Boolean
|
invertFill: Boolean = false,
|
||||||
|
preparedPolygon: List<Pair<Float, Float>>? = null
|
||||||
) {
|
) {
|
||||||
if (pts.none { it.front }) return
|
if (pts.none { it.front }) return
|
||||||
val poly = buildFillPolygon(pts, cx, cy, r)
|
val poly = preparedPolygon ?: buildFillPolygon(pts, cx, cy, r)
|
||||||
if (poly.size < 3) return
|
if (poly.size < 3) return
|
||||||
val clipped = clipPolygon(poly, clip)
|
val clipped = clipPolygon(poly, clip)
|
||||||
if (clipped.size < 3) return
|
if (clipped.size < 3) return
|
||||||
val path = Path()
|
val path = Path()
|
||||||
val projectedCenterInside = polygonContains(clipped, cx, cy)
|
if (invertFill) {
|
||||||
if (projectedCenterInside != centerInsideRing) {
|
|
||||||
// Orthographic projection can choose the wrong side of the horizon closure for
|
// Orthographic projection can choose the wrong side of the horizon closure for
|
||||||
// very large rings. Even-odd filling with the globe disc flips it back to the
|
// very large rings. Even-odd filling with the globe disc flips that one ring.
|
||||||
// side that agrees with the original geographic polygon.
|
|
||||||
path.fillType = PathFillType.EvenOdd
|
path.fillType = PathFillType.EvenOdd
|
||||||
path.addOval(Rect(cx - r, cy - r, cx + r, cy + r))
|
path.addOval(Rect(cx - r, cy - r, cx + r, cy + r))
|
||||||
}
|
}
|
||||||
@ -708,6 +707,46 @@ private fun DrawScope.fillPolygonClipped(
|
|||||||
drawPath(path, color)
|
drawPath(path, color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun projectedFillNeedsInversion(
|
||||||
|
polygon: List<Pair<Float, Float>>,
|
||||||
|
ring: LandData.Ring,
|
||||||
|
cx: Float,
|
||||||
|
cy: Float,
|
||||||
|
r: Float,
|
||||||
|
centerLat: Double,
|
||||||
|
centerLon: Double
|
||||||
|
): Boolean {
|
||||||
|
// A single center-point check is ambiguous for a large polygon and caused an
|
||||||
|
// occasional whole-disc fill. Compare several visible points with the original
|
||||||
|
// geographic ring, and invert only when the opposite fill wins clearly.
|
||||||
|
val samples = arrayOf(
|
||||||
|
0f to 0f,
|
||||||
|
-0.5f to 0f,
|
||||||
|
0.5f to 0f,
|
||||||
|
0f to -0.5f,
|
||||||
|
0f to 0.5f,
|
||||||
|
-0.35f to -0.35f,
|
||||||
|
0.35f to -0.35f,
|
||||||
|
-0.35f to 0.35f,
|
||||||
|
0.35f to 0.35f
|
||||||
|
)
|
||||||
|
var normalErrors = 0
|
||||||
|
var invertedErrors = 0
|
||||||
|
for ((nx, ny) in samples) {
|
||||||
|
val location = GlobeMath.unproject(
|
||||||
|
x = nx.toDouble(),
|
||||||
|
y = ny.toDouble(),
|
||||||
|
centerLatDeg = centerLat,
|
||||||
|
centerLonDeg = centerLon
|
||||||
|
) ?: continue
|
||||||
|
val geographicInside = ringContainsLocation(ring, location.first, location.second)
|
||||||
|
val projectedInside = polygonContains(polygon, cx + nx * r, cy + ny * r)
|
||||||
|
if (projectedInside != geographicInside) normalErrors++
|
||||||
|
if (!projectedInside != geographicInside) invertedErrors++
|
||||||
|
}
|
||||||
|
return invertedErrors < normalErrors
|
||||||
|
}
|
||||||
|
|
||||||
internal fun polygonContains(
|
internal fun polygonContains(
|
||||||
polygon: List<Pair<Float, Float>>,
|
polygon: List<Pair<Float, Float>>,
|
||||||
x: Float,
|
x: Float,
|
||||||
@ -892,11 +931,16 @@ private fun DrawScope.drawLandFill(
|
|||||||
if (n < 3 || n * 3 > scratch.size) return null
|
if (n < 3 || n * 3 > scratch.size) return null
|
||||||
|
|
||||||
var anyFront = false
|
var anyFront = false
|
||||||
|
var anyBack = false
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
val sourceIndex = (i * pointStride).coerceAtMost(ring.size - 1)
|
val sourceIndex = (i * pointStride).coerceAtMost(ring.size - 1)
|
||||||
projector.project(ring.projectionTerms, sourceIndex * 4, scratch, i * 3)
|
projector.project(ring.projectionTerms, sourceIndex * 4, scratch, i * 3)
|
||||||
if (scratch[i * 3 + 2] >= 0f) anyFront = true
|
if (scratch[i * 3 + 2] >= 0f) {
|
||||||
|
anyFront = true
|
||||||
|
} else {
|
||||||
|
anyBack = true
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if (!anyFront) return null
|
if (!anyFront) return null
|
||||||
@ -908,6 +952,7 @@ private fun DrawScope.drawLandFill(
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
val runs = buildFrontRuns(pts)
|
val runs = buildFrontRuns(pts)
|
||||||
|
val polygon = buildFillPolygon(pts, cx, cy, r)
|
||||||
fillPolygonClipped(
|
fillPolygonClipped(
|
||||||
pts = pts,
|
pts = pts,
|
||||||
cx = cx,
|
cx = cx,
|
||||||
@ -915,7 +960,16 @@ private fun DrawScope.drawLandFill(
|
|||||||
r = r,
|
r = r,
|
||||||
color = colors.land,
|
color = colors.land,
|
||||||
clip = clip,
|
clip = clip,
|
||||||
centerInsideRing = ringContainsLocation(ring, centerLat, centerLon)
|
invertFill = anyBack && projectedFillNeedsInversion(
|
||||||
|
polygon = polygon,
|
||||||
|
ring = ring,
|
||||||
|
cx = cx,
|
||||||
|
cy = cy,
|
||||||
|
r = r,
|
||||||
|
centerLat = centerLat,
|
||||||
|
centerLon = centerLon
|
||||||
|
),
|
||||||
|
preparedPolygon = polygon
|
||||||
)
|
)
|
||||||
return runs
|
return runs
|
||||||
}
|
}
|
||||||
@ -974,15 +1028,13 @@ private fun DrawScope.drawGeohashGrid(
|
|||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
fillPolygonClipped(
|
fillPolygonClipped(
|
||||||
discPts, cx, cy, r, colors.accent.copy(alpha = 0.20f), clip,
|
discPts, cx, cy, r, colors.accent.copy(alpha = 0.20f), clip
|
||||||
centerInsideRing = true
|
|
||||||
)
|
)
|
||||||
strokeRuns(runs, cx, cy, r, colors.accent.copy(alpha = 0.35f), 7f, clip)
|
strokeRuns(runs, cx, cy, r, colors.accent.copy(alpha = 0.35f), 7f, clip)
|
||||||
strokeRuns(runs, cx, cy, r, colors.accent, 3.2f, clip)
|
strokeRuns(runs, cx, cy, r, colors.accent, 3.2f, clip)
|
||||||
} else {
|
} else {
|
||||||
fillPolygonClipped(
|
fillPolygonClipped(
|
||||||
discPts, cx, cy, r, colors.grid.copy(alpha = 0.05f), clip,
|
discPts, cx, cy, r, colors.grid.copy(alpha = 0.05f), clip
|
||||||
centerInsideRing = false
|
|
||||||
)
|
)
|
||||||
strokeRuns(runs, cx, cy, r, colors.grid, 1.6f, clip)
|
strokeRuns(runs, cx, cy, r, colors.grid, 1.6f, clip)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user