draw optimizations
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
package world
|
||||
|
||||
// torusShortestLineSegmentsInto converts a Line primitive into 1..4 canonical segments
|
||||
// inside [0..worldW) x [0..worldH) that represent the torus-shortest polyline.
|
||||
//
|
||||
// It appends results into dst using tmp as an intermediate buffer.
|
||||
// No allocations occur if dst/tmp have sufficient capacity (>=4).
|
||||
func torusShortestLineSegmentsInto(dst, tmp []lineSeg, l Line, worldW, worldH int) ([]lineSeg, []lineSeg) {
|
||||
dst = dst[:0]
|
||||
tmp = tmp[:0]
|
||||
|
||||
// Step 1: choose the torus-shortest representation in unwrapped space.
|
||||
ax, bx := shortestWrappedDelta(l.X1, l.X2, worldW)
|
||||
ay, by := shortestWrappedDelta(l.Y1, l.Y2, worldH)
|
||||
|
||||
// Step 2: shift so that A is inside canonical [0..W) x [0..H).
|
||||
shiftX := floorDiv(ax, worldW) * worldW
|
||||
shiftY := floorDiv(ay, worldH) * worldH
|
||||
|
||||
ax -= shiftX
|
||||
bx -= shiftX
|
||||
ay -= shiftY
|
||||
by -= shiftY
|
||||
|
||||
dst = append(dst, lineSeg{x1: ax, y1: ay, x2: bx, y2: by})
|
||||
|
||||
// Step 3: split by X boundary if needed (jump-aware).
|
||||
tmp = splitSegmentsByXInto(tmp, dst, worldW)
|
||||
|
||||
// Step 4: split by Y boundary if needed (jump-aware).
|
||||
dst = splitSegmentsByYInto(dst, tmp, worldH)
|
||||
|
||||
return dst, tmp
|
||||
}
|
||||
|
||||
// torusShortestLineSegments is a compatibility wrapper that allocates.
|
||||
// Prefer torusShortestLineSegmentsInto in hot paths.
|
||||
func torusShortestLineSegments(l Line, worldW, worldH int) []lineSeg {
|
||||
dst := make([]lineSeg, 0, 4)
|
||||
tmp := make([]lineSeg, 0, 4)
|
||||
dst, _ = torusShortestLineSegmentsInto(dst, tmp, l, worldW, worldH)
|
||||
return dst
|
||||
}
|
||||
|
||||
// splitSegmentsByXInto appends 1..2 segments for each input segment into out, without allocating.
|
||||
// out is reset to length 0 by this function.
|
||||
func splitSegmentsByXInto(out []lineSeg, segs []lineSeg, worldW int) []lineSeg {
|
||||
out = out[:0]
|
||||
|
||||
for _, s := range segs {
|
||||
x1, y1, x2, y2 := s.x1, s.y1, s.x2, s.y2
|
||||
|
||||
// After normalization, x1 is expected inside [0..worldW). Only x2 may be outside.
|
||||
if x2 >= 0 && x2 < worldW {
|
||||
out = append(out, s)
|
||||
continue
|
||||
}
|
||||
|
||||
dx := x2 - x1
|
||||
dy := y2 - y1
|
||||
if dx == 0 {
|
||||
out = append(out, s)
|
||||
continue
|
||||
}
|
||||
|
||||
if x2 >= worldW {
|
||||
// Crosses the right boundary at x=worldW, then reappears at x=0.
|
||||
bx := worldW
|
||||
num := bx - x1
|
||||
iy := y1 + (dy*num)/dx
|
||||
|
||||
s1 := lineSeg{x1: x1, y1: y1, x2: worldW, y2: iy}
|
||||
s2 := lineSeg{x1: 0, y1: iy, x2: x2 - worldW, y2: y2}
|
||||
out = append(out, s1, s2)
|
||||
continue
|
||||
}
|
||||
|
||||
// x2 < 0: crosses the left boundary at x=0, then reappears at x=worldW.
|
||||
bx := 0
|
||||
num := bx - x1
|
||||
iy := y1 + (dy*num)/dx
|
||||
|
||||
s1 := lineSeg{x1: x1, y1: y1, x2: 0, y2: iy}
|
||||
s2 := lineSeg{x1: worldW, y1: iy, x2: x2 + worldW, y2: y2}
|
||||
out = append(out, s1, s2)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// splitSegmentsByYInto appends 1..2 segments for each input segment into out, without allocating.
|
||||
// out is reset to length 0 by this function.
|
||||
func splitSegmentsByYInto(out []lineSeg, segs []lineSeg, worldH int) []lineSeg {
|
||||
out = out[:0]
|
||||
|
||||
for _, s := range segs {
|
||||
x1, y1, x2, y2 := s.x1, s.y1, s.x2, s.y2
|
||||
|
||||
// After normalization, y1 is expected inside [0..worldH). Only y2 may be outside.
|
||||
if y2 >= 0 && y2 < worldH {
|
||||
out = append(out, s)
|
||||
continue
|
||||
}
|
||||
|
||||
dx := x2 - x1
|
||||
dy := y2 - y1
|
||||
if dy == 0 {
|
||||
out = append(out, s)
|
||||
continue
|
||||
}
|
||||
|
||||
if y2 >= worldH {
|
||||
// Crosses the top boundary at y=worldH, then reappears at y=0.
|
||||
by := worldH
|
||||
num := by - y1
|
||||
ix := x1 + (dx*num)/dy
|
||||
|
||||
s1 := lineSeg{x1: x1, y1: y1, x2: ix, y2: worldH}
|
||||
s2 := lineSeg{x1: ix, y1: 0, x2: x2, y2: y2 - worldH}
|
||||
out = append(out, s1, s2)
|
||||
continue
|
||||
}
|
||||
|
||||
// y2 < 0: crosses the bottom boundary at y=0, then reappears at y=worldH.
|
||||
by := 0
|
||||
num := by - y1
|
||||
ix := x1 + (dx*num)/dy
|
||||
|
||||
s1 := lineSeg{x1: x1, y1: y1, x2: ix, y2: 0}
|
||||
s2 := lineSeg{x1: ix, y1: worldH, x2: x2, y2: y2 + worldH}
|
||||
out = append(out, s1, s2)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user