no-wrap option; pivoted exponential zoom

This commit is contained in:
Ilia Denisov
2026-03-07 11:35:18 +02:00
committed by GitHub
parent 1de621c743
commit 477e656008
22 changed files with 605 additions and 81 deletions
+37 -10
View File
@@ -21,6 +21,10 @@ type RenderOptions struct {
Style *RenderStyle
// Incremental controls incremental pan behavior. If nil, defaults are used.
Incremental *IncrementalPolicy
// DisableWrapScroll controls whether the world is treated as a torus (false)
// or as a bounded plane without wrap (true).
// Default is false.
DisableWrapScroll bool
}
var (
@@ -66,7 +70,7 @@ func (p RenderParams) CanvasHeightPx() int { return p.ViewportHeightPx + 2*p.Mar
// CameraZoomFp converts the UI-facing zoom value into the package fixed-point form.
func (p RenderParams) CameraZoomFp() (int, error) {
return cameraZoomToWorldFixed(p.CameraZoom)
return CameraZoomToWorldFixed(p.CameraZoom)
}
// ExpandedCanvasWorldRect returns the world-space half-open rectangle covered by
@@ -210,6 +214,8 @@ func (w *World) Render(drawer PrimitiveDrawer, params RenderParams) error {
layers = params.Options.Layers
}
allowWrap := params.Options == nil || !params.Options.DisableWrapScroll
// --- Try incremental path first when state is initialized and geometry matches ---
dxPx, dyPx, derr := w.ComputePanShiftPx(params)
if derr == nil {
@@ -246,13 +252,13 @@ func (w *World) Render(drawer PrimitiveDrawer, params RenderParams) error {
switch layer {
case RenderLayerPoints:
applyPointStyle(drawer, style)
drawPointsFromPlanWithRadius(drawer, catchUpPlan, w.W, w.H, style.PointRadiusPx)
drawPointsFromPlanWithRadius(drawer, catchUpPlan, w.W, w.H, style.PointRadiusPx, allowWrap)
case RenderLayerCircles:
applyCircleStyle(drawer, style)
drawCirclesFromPlan(drawer, catchUpPlan, w.W, w.H)
drawCirclesFromPlan(drawer, catchUpPlan, w.W, w.H, allowWrap)
case RenderLayerLines:
applyLineStyle(drawer, style)
drawLinesFromPlan(drawer, catchUpPlan, w.W, w.H)
drawLinesFromPlan(drawer, catchUpPlan, w.W, w.H, allowWrap)
default:
panic("render: unknown layer")
}
@@ -319,13 +325,13 @@ func (w *World) Render(drawer PrimitiveDrawer, params RenderParams) error {
switch layer {
case RenderLayerPoints:
applyPointStyle(drawer, style)
drawPointsFromPlanWithRadius(drawer, dirtyPlan, w.W, w.H, style.PointRadiusPx)
drawPointsFromPlanWithRadius(drawer, dirtyPlan, w.W, w.H, style.PointRadiusPx, allowWrap)
case RenderLayerCircles:
applyCircleStyle(drawer, style)
drawCirclesFromPlan(drawer, dirtyPlan, w.W, w.H)
drawCirclesFromPlan(drawer, dirtyPlan, w.W, w.H, allowWrap)
case RenderLayerLines:
applyLineStyle(drawer, style)
drawLinesFromPlan(drawer, dirtyPlan, w.W, w.H)
drawLinesFromPlan(drawer, dirtyPlan, w.W, w.H, allowWrap)
default:
panic("render: unknown layer")
}
@@ -352,13 +358,13 @@ func (w *World) Render(drawer PrimitiveDrawer, params RenderParams) error {
switch layer {
case RenderLayerPoints:
applyPointStyle(drawer, style)
drawPointsFromPlanWithRadius(drawer, plan, w.W, w.H, style.PointRadiusPx)
drawPointsFromPlanWithRadius(drawer, plan, w.W, w.H, style.PointRadiusPx, allowWrap)
case RenderLayerCircles:
applyCircleStyle(drawer, style)
drawCirclesFromPlan(drawer, plan, w.W, w.H)
drawCirclesFromPlan(drawer, plan, w.W, w.H, allowWrap)
case RenderLayerLines:
applyLineStyle(drawer, style)
drawLinesFromPlan(drawer, plan, w.W, w.H)
drawLinesFromPlan(drawer, plan, w.W, w.H, allowWrap)
default:
panic("render: unknown layer")
}
@@ -448,6 +454,27 @@ func tileWorldRect(rect Rect, worldWidthFp, worldHeightFp int) []WorldTile {
return out
}
// tileWorldRectNoWrap returns 0..1 tiles for a bounded world (no wrap).
// It intersects the expanded unwrapped rect with the canonical world [0..W)x[0..H).
func tileWorldRectNoWrap(worldRect Rect, W, H int) []WorldTile {
ix0 := max(worldRect.minX, 0)
iy0 := max(worldRect.minY, 0)
ix1 := min(worldRect.maxX, W)
iy1 := min(worldRect.maxY, H)
if ix0 >= ix1 || iy0 >= iy1 {
return nil
}
return []WorldTile{
{
Rect: Rect{minX: ix0, maxX: ix1, minY: iy0, maxY: iy1},
OffsetX: 0,
OffsetY: 0,
},
}
}
func isEmptyRectPx(r RectPx) bool {
return r.W <= 0 || r.H <= 0
}