276 lines
5.0 KiB
Go
276 lines
5.0 KiB
Go
//package name
|
|
package layer
|
|
|
|
//package imports
|
|
import (
|
|
"../mymath"
|
|
"math"
|
|
)
|
|
|
|
/////////////////////////
|
|
//private structure/types
|
|
/////////////////////////
|
|
|
|
type dims struct {
|
|
width int
|
|
height int
|
|
}
|
|
|
|
type point struct {
|
|
x float32
|
|
y float32
|
|
}
|
|
|
|
type line struct {
|
|
p1 point
|
|
p2 point
|
|
radius float32
|
|
gap float32
|
|
}
|
|
|
|
type record struct {
|
|
id int
|
|
line line
|
|
}
|
|
|
|
type aabb struct {
|
|
minx int
|
|
miny int
|
|
maxx int
|
|
maxy int
|
|
}
|
|
|
|
type bucket []*record
|
|
type buckets []bucket
|
|
|
|
//layer object
|
|
type layer struct {
|
|
width int
|
|
height int
|
|
scale float32
|
|
buckets buckets
|
|
test int
|
|
}
|
|
|
|
//layer methods
|
|
|
|
/////////////////
|
|
//private methods
|
|
/////////////////
|
|
|
|
func newlayer(dims dims, s float32) *layer {
|
|
l := layer{}
|
|
l.init(dims, s)
|
|
return &l
|
|
}
|
|
|
|
func (self *layer) init(dims dims, s float32) {
|
|
self.width = dims.width
|
|
self.height = dims.height
|
|
self.scale = s
|
|
self.buckets = make(buckets, (self.width * self.height), (self.width * self.height))
|
|
for i := 0; i < (self.width * self.height); i++ {
|
|
self.buckets[i] = bucket{}
|
|
}
|
|
self.test = 0
|
|
return
|
|
}
|
|
|
|
func (self *layer) aabb(l *line) *aabb {
|
|
x1, y1, x2, y2 := l.p1.x, l.p1.y, l.p2.x, l.p2.y
|
|
if x1 > x2 {
|
|
x1, x2 = x2, x1
|
|
}
|
|
if y1 > y2 {
|
|
y1, y2 = y2, y1
|
|
}
|
|
r := l.radius + l.gap
|
|
minx := int(math.Floor(float64((x1 - r) * self.scale)))
|
|
miny := int(math.Floor(float64((y1 - r) * self.scale)))
|
|
maxx := int(math.Ceil(float64((x2 + r) * self.scale)))
|
|
maxy := int(math.Ceil(float64((y2 + r) * self.scale)))
|
|
if minx < 0 {
|
|
minx = 0
|
|
}
|
|
if miny < 0 {
|
|
miny = 0
|
|
}
|
|
if maxx > self.width {
|
|
maxx = self.width
|
|
}
|
|
if maxy > self.height {
|
|
maxy = self.height
|
|
}
|
|
return &aabb{minx, miny, maxx, maxy}
|
|
}
|
|
|
|
func lines_equal(l1, l2 *line) bool {
|
|
if l1.p1.x != l2.p1.x {
|
|
return false
|
|
}
|
|
if l1.p1.y != l2.p1.y {
|
|
return false
|
|
}
|
|
if l1.p2.x != l2.p2.x {
|
|
return false
|
|
}
|
|
if l1.p2.y != l2.p2.y {
|
|
return false
|
|
}
|
|
if l1.radius != l2.radius {
|
|
return false
|
|
}
|
|
if l1.gap != l2.gap {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (self *layer) add_line(l *line) {
|
|
new_record := record{0, *l}
|
|
bb := self.aabb(l)
|
|
for y := bb.miny; y < bb.maxy; y++ {
|
|
for x := bb.minx; x < bb.maxx; x++ {
|
|
b := y*self.width + x
|
|
found := false
|
|
for _, record := range self.buckets[b] {
|
|
if lines_equal(&record.line, l) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
self.buckets[b] = append(self.buckets[b], &new_record)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (self *layer) sub_line(l *line) {
|
|
bb := self.aabb(l)
|
|
for y := bb.miny; y < bb.maxy; y++ {
|
|
for x := bb.minx; x < bb.maxx; x++ {
|
|
b := y*self.width + x
|
|
for i := len(self.buckets[b]) - 1; i >= 0; i-- {
|
|
if lines_equal(&self.buckets[b][i].line, l) {
|
|
self.buckets[b] = append(self.buckets[b][:i], self.buckets[b][i+1:]...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (self *layer) hit_line(l *line) bool {
|
|
self.test += 1
|
|
bb := self.aabb(l)
|
|
l1_p1 := mymath.Point{l.p1.x, l.p1.y}
|
|
l1_p2 := mymath.Point{l.p2.x, l.p2.y}
|
|
l2_p1 := mymath.Point{0.0, 0.0}
|
|
l2_p2 := mymath.Point{0.0, 0.0}
|
|
for y := bb.miny; y < bb.maxy; y++ {
|
|
for x := bb.minx; x < bb.maxx; x++ {
|
|
for _, record := range self.buckets[y*self.width+x] {
|
|
if record.id != self.test {
|
|
record.id = self.test
|
|
r := l.radius + record.line.radius
|
|
if l.gap >= record.line.gap {
|
|
r += l.gap
|
|
} else {
|
|
r += record.line.gap
|
|
}
|
|
l2_p1[0], l2_p1[1] = record.line.p1.x, record.line.p1.y
|
|
l2_p2[0], l2_p2[1] = record.line.p2.x, record.line.p2.y
|
|
if mymath.Collide_thick_lines_2d(&l1_p1, &l1_p2, &l2_p1, &l2_p2, r) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
/////////////////////////
|
|
//public structures/types
|
|
/////////////////////////
|
|
|
|
type Dims struct {
|
|
Width int
|
|
Height int
|
|
Depth int
|
|
}
|
|
|
|
//layers object
|
|
type Layers struct {
|
|
depth int
|
|
layers []*layer
|
|
}
|
|
|
|
//layers methods
|
|
|
|
////////////////
|
|
//public methods
|
|
////////////////
|
|
|
|
func NewLayers(dims Dims, s float32) *Layers {
|
|
l := Layers{}
|
|
l.Init(dims, s)
|
|
return &l
|
|
}
|
|
|
|
func (self *Layers) Init(dm Dims, s float32) *Layers {
|
|
width := dm.Width
|
|
height := dm.Height
|
|
self.depth = dm.Depth
|
|
self.layers = make([]*layer, self.depth, self.depth)
|
|
for z := 0; z < self.depth; z++ {
|
|
self.layers[z] = newlayer(dims{width, height}, s)
|
|
}
|
|
return self
|
|
}
|
|
|
|
func (self *Layers) Add_line(pp1, pp2 *mymath.Point, r, g float32) {
|
|
p1 := *pp1
|
|
p2 := *pp2
|
|
z1 := int(p1[2])
|
|
z2 := int(p2[2])
|
|
if z1 > z2 {
|
|
z1, z2 = z2, z1
|
|
}
|
|
line := line{point{p1[0], p1[1]}, point{p2[0], p2[1]}, r, g}
|
|
for z := z1; z <= z2; z++ {
|
|
self.layers[z].add_line(&line)
|
|
}
|
|
}
|
|
|
|
func (self *Layers) Sub_line(pp1, pp2 *mymath.Point, r, g float32) {
|
|
p1 := *pp1
|
|
p2 := *pp2
|
|
z1 := int(p1[2])
|
|
z2 := int(p2[2])
|
|
if z1 > z2 {
|
|
z1, z2 = z2, z1
|
|
}
|
|
line := line{point{p1[0], p1[1]}, point{p2[0], p2[1]}, r, g}
|
|
for z := z1; z <= z2; z++ {
|
|
self.layers[z].sub_line(&line)
|
|
}
|
|
}
|
|
|
|
func (self *Layers) Hit_line(pp1, pp2 *mymath.Point, r, g float32) bool {
|
|
p1 := *pp1
|
|
p2 := *pp2
|
|
z1 := int(p1[2])
|
|
z2 := int(p2[2])
|
|
if z1 > z2 {
|
|
z1, z2 = z2, z1
|
|
}
|
|
line := line{point{p1[0], p1[1]}, point{p2[0], p2[1]}, r, g}
|
|
for z := z1; z <= z2; z++ {
|
|
if self.layers[z].hit_line(&line) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|