增加圆形相关处理函数

This commit is contained in:
kercylan98 2023-06-20 17:39:35 +08:00
parent d10c05dfe1
commit c0570392bf
10 changed files with 99 additions and 23 deletions

View File

@ -123,7 +123,7 @@ func (slf *Moving2D) handle() {
if interval == 0 { if interval == 0 {
continue continue
} }
distance := geometry.CalcDistance(x, y, entity.x, entity.y) distance := geometry.CalcDistanceWithCoordinate(x, y, entity.x, entity.y)
moveDistance := interval * (entity.GetSpeed() / (slf.timeUnit / 1000 / 1000)) moveDistance := interval * (entity.GetSpeed() / (slf.timeUnit / 1000 / 1000))
if moveDistance >= distance || (x == entity.x && y == entity.y) { if moveDistance >= distance || (x == entity.x && y == entity.y) {
entity.SetPosition(entity.x, entity.y) entity.SetPosition(entity.x, entity.y)

View File

@ -177,7 +177,7 @@ func (slf *AOI2D) refresh(entity game.AOIEntity2D) {
focus := slf.focus[guid] focus := slf.focus[guid]
for eg, e := range focus { for eg, e := range focus {
ex, ey := e.GetPosition() ex, ey := e.GetPosition()
if geometry.CalcDistance(x, y, ex, ey) > vision { if geometry.CalcDistanceWithCoordinate(x, y, ex, ey) > vision {
delete(focus, eg) delete(focus, eg)
delete(slf.focus[eg], guid) delete(slf.focus[eg], guid)
} }
@ -243,13 +243,13 @@ func (slf *AOI2D) rangeVisionAreaEntities(entity game.AOIEntity2D, handle func(g
} else { } else {
areaY = y areaY = y
} }
areaDistance := geometry.CalcDistance(x, y, areaX, areaY) areaDistance := geometry.CalcDistanceWithCoordinate(x, y, areaX, areaY)
if areaDistance <= vision { if areaDistance <= vision {
for eg, e := range slf.areas[w][h] { for eg, e := range slf.areas[w][h] {
if eg == guid { if eg == guid {
continue continue
} }
if ex, ey := e.GetPosition(); geometry.CalcDistance(x, y, ex, ey) > vision { if ex, ey := e.GetPosition(); geometry.CalcDistanceWithCoordinate(x, y, ex, ey) > vision {
continue continue
} }
handle(eg, e) handle(eg, e)

View File

@ -37,9 +37,9 @@ func ExampleFind() {
} }
paths := astar.Find[geometry.Point[int], int](graph, geometry.NewPoint(1, 1), geometry.NewPoint(8, 6), func(a, b geometry.Point[int]) int { paths := astar.Find[geometry.Point[int], int](graph, geometry.NewPoint(1, 1), geometry.NewPoint(8, 6), func(a, b geometry.Point[int]) int {
return geometry.CalcDistance(geometry.DoublePointToCoordinate(a, b)) return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a, b))
}, func(a, b geometry.Point[int]) int { }, func(a, b geometry.Point[int]) int {
return geometry.CalcDistance(geometry.DoublePointToCoordinate(a, b)) return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a, b))
}) })
for _, path := range paths { for _, path := range paths {

View File

@ -5,8 +5,53 @@ import (
"math" "math"
) )
// Circle 圆形
type Circle[V generic.SignedNumber] struct {
Shape[V]
radius V
centroid Point[V]
initCentroid bool
}
// Radius 获取圆形半径
func (slf Circle[V]) Radius() V {
if slf.radius > V(-0) {
return slf.radius
}
for _, point := range slf.Points() {
slf.radius = CalcDistanceWithPoint(slf.Centroid(), point)
return slf.radius
}
panic("circle without any points")
}
// Centroid 获取圆形质心位置
func (slf Circle[V]) Centroid() Point[V] {
if slf.initCentroid {
return slf.centroid
}
slf.centroid = CalcRectangleCentroid(slf.Shape)
slf.initCentroid = true
return slf.centroid
}
// Overlap 与另一个圆是否发生重叠
func (slf Circle[V]) Overlap(circle Circle[V]) bool {
return CalcDistanceWithPoint(slf.Centroid(), circle.Centroid())/2 > slf.radius
}
// Area 获取圆形面积
func (slf Circle[V]) Area() V {
return V(math.Pi * math.Pow(float64(slf.Radius()), 2))
}
// Length 获取圆的周长
func (slf Circle[V]) Length() V {
return V(2 * math.Pi * float64(slf.Radius()))
}
// GenerateCircle 通过传入圆的半径和需要的点数量,生成一个圆 // GenerateCircle 通过传入圆的半径和需要的点数量,生成一个圆
func GenerateCircle[V generic.SignedNumber](radius V, points int) Shape[V] { func GenerateCircle[V generic.SignedNumber](radius V, points int) Circle[V] {
angle := 2.0 * math.Pi / float64(points) angle := 2.0 * math.Pi / float64(points)
var shape = make(Shape[V], points) var shape = make(Shape[V], points)
for i := 0; i < points; i++ { for i := 0; i < points; i++ {
@ -15,5 +60,5 @@ func GenerateCircle[V generic.SignedNumber](radius V, points int) Shape[V] {
y := radius * V(math.Sin(curAngle)) y := radius * V(math.Sin(curAngle))
shape = append(shape, NewPoint(x, y)) shape = append(shape, NewPoint(x, y))
} }
return shape return shape.ToCircle()
} }

View File

@ -109,11 +109,16 @@ func CalcDirection[V generic.SignedNumber](x1, y1, x2, y2 V) Direction {
return DirectionUnknown return DirectionUnknown
} }
// CalcDistance 计算两点之间的距离 // CalcDistanceWithCoordinate 计算两点之间的距离
func CalcDistance[V generic.SignedNumber](x1, y1, x2, y2 V) V { func CalcDistanceWithCoordinate[V generic.SignedNumber](x1, y1, x2, y2 V) V {
return V(math.Sqrt(math.Pow(float64(x2-x1), 2) + math.Pow(float64(y2-y1), 2))) return V(math.Sqrt(math.Pow(float64(x2-x1), 2) + math.Pow(float64(y2-y1), 2)))
} }
// CalcDistanceWithPoint 计算两点之间的距离
func CalcDistanceWithPoint[V generic.SignedNumber](point1, point2 Point[V]) V {
return CalcDistanceWithCoordinate(DoublePointToCoordinate(point1, point2))
}
// CalcDistanceSquared 计算两点之间的平方距离 // CalcDistanceSquared 计算两点之间的平方距离
// - 这个函数的主要用途是在需要计算两点之间距离的情况下,但不需要得到实际的距离值,而只需要比较距离大小。因为平方根运算相对较为耗时,所以在只需要比较大小的情况下,通常会使用平方距离。 // - 这个函数的主要用途是在需要计算两点之间距离的情况下,但不需要得到实际的距离值,而只需要比较距离大小。因为平方根运算相对较为耗时,所以在只需要比较大小的情况下,通常会使用平方距离。
func CalcDistanceSquared[V generic.SignedNumber](x1, y1, x2, y2 V) V { func CalcDistanceSquared[V generic.SignedNumber](x1, y1, x2, y2 V) V {

View File

@ -54,7 +54,7 @@ func (slf LineSegment[V]) GetEnd() Point[V] {
// GetLength 获取该线段的长度 // GetLength 获取该线段的长度
func (slf LineSegment[V]) GetLength() V { func (slf LineSegment[V]) GetLength() V {
return CalcDistance(DoublePointToCoordinate(slf.GetStart(), slf.GetEnd())) return CalcDistanceWithCoordinate(DoublePointToCoordinate(slf.GetStart(), slf.GetEnd()))
} }
// PointOnLineSegmentWithCoordinate 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上 // PointOnLineSegmentWithCoordinate 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上

View File

@ -74,7 +74,7 @@ func (slf *NavMesh[V]) Find(point geometry.Point[V], maxDistance V) (distance V,
break break
} }
br := geometry.CalcBoundingRadius(meshShape.Shape) br := geometry.CalcBoundingRadius(meshShape.Shape)
distance := geometry.CalcDistance(geometry.DoublePointToCoordinate( distance := geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(
geometry.CalcRectangleCentroid(meshShape.Shape), geometry.CalcRectangleCentroid(meshShape.Shape),
point, point,
)) ))
@ -111,13 +111,13 @@ func (slf *NavMesh[V]) FindPath(start, end geometry.Point[V]) (result []geometry
for _, meshShape := range slf.meshShapes { for _, meshShape := range slf.meshShapes {
br := meshShape.BoundingRadius() br := meshShape.BoundingRadius()
distance := geometry.CalcDistance(geometry.DoublePointToCoordinate(meshShape.Centroid(), start)) distance := geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(meshShape.Centroid(), start))
if (distance <= startDistance || startDistance == V(-1)) && distance <= br && meshShape.Contains(start) { if (distance <= startDistance || startDistance == V(-1)) && distance <= br && meshShape.Contains(start) {
startShape = meshShape startShape = meshShape
startDistance = distance startDistance = distance
} }
distance = geometry.CalcDistance(geometry.DoublePointToCoordinate(meshShape.Centroid(), end)) distance = geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(meshShape.Centroid(), end))
if (distance <= endDistance || endDistance == V(-1)) && distance <= br && meshShape.Contains(end) { if (distance <= endDistance || endDistance == V(-1)) && distance <= br && meshShape.Contains(end) {
endShape = meshShape endShape = meshShape
endDistance = distance endDistance = distance
@ -127,7 +127,7 @@ func (slf *NavMesh[V]) FindPath(start, end geometry.Point[V]) (result []geometry
if endShape == nil && slf.meshShrinkAmount > V(0) { if endShape == nil && slf.meshShrinkAmount > V(0) {
for _, meshShape := range slf.meshShapes { for _, meshShape := range slf.meshShapes {
br := meshShape.BoundingRadius() + slf.meshShrinkAmount br := meshShape.BoundingRadius() + slf.meshShrinkAmount
distance := geometry.CalcDistance(geometry.DoublePointToCoordinate(meshShape.Centroid(), end)) distance := geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(meshShape.Centroid(), end))
if distance <= br { if distance <= br {
_, projectionDistance := geometry.ProjectionPointToShape(end, meshShape.Shape) _, projectionDistance := geometry.ProjectionPointToShape(end, meshShape.Shape)
if projectionDistance <= slf.meshShrinkAmount && projectionDistance < endDistance { if projectionDistance <= slf.meshShrinkAmount && projectionDistance < endDistance {
@ -145,7 +145,7 @@ func (slf *NavMesh[V]) FindPath(start, end geometry.Point[V]) (result []geometry
if startShape == nil && slf.meshShrinkAmount > 0 { if startShape == nil && slf.meshShrinkAmount > 0 {
for _, meshShape := range slf.meshShapes { for _, meshShape := range slf.meshShapes {
br := meshShape.BoundingRadius() + slf.meshShrinkAmount br := meshShape.BoundingRadius() + slf.meshShrinkAmount
distance := geometry.CalcDistance(geometry.DoublePointToCoordinate(meshShape.Centroid(), start)) distance := geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(meshShape.Centroid(), start))
if distance <= br { if distance <= br {
_, projectionDistance := geometry.ProjectionPointToShape(start, meshShape.Shape) _, projectionDistance := geometry.ProjectionPointToShape(start, meshShape.Shape)
if projectionDistance <= slf.meshShrinkAmount && projectionDistance < startDistance { if projectionDistance <= slf.meshShrinkAmount && projectionDistance < startDistance {
@ -165,9 +165,9 @@ func (slf *NavMesh[V]) FindPath(start, end geometry.Point[V]) (result []geometry
} }
path := astar.Find[*shape[V], V](slf, startShape, endShape, func(a, b *shape[V]) V { path := astar.Find[*shape[V], V](slf, startShape, endShape, func(a, b *shape[V]) V {
return geometry.CalcDistance(geometry.DoublePointToCoordinate(a.centroid, b.centroid)) return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a.centroid, b.centroid))
}, func(a, b *shape[V]) V { }, func(a, b *shape[V]) V {
return geometry.CalcDistance(geometry.DoublePointToCoordinate(a.centroid, b.centroid)) return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(a.centroid, b.centroid))
}) })
if len(path) == 0 { if len(path) == 0 {
@ -223,7 +223,7 @@ func (slf *NavMesh[V]) generateLink() {
targetShapePkg := slf.meshShapes[t] targetShapePkg := slf.meshShapes[t]
targetShapeCentroid := targetShapePkg.Centroid() targetShapeCentroid := targetShapePkg.Centroid()
targetShapeBoundingRadius := targetShapePkg.BoundingRadius() targetShapeBoundingRadius := targetShapePkg.BoundingRadius()
centroidDistance := geometry.CalcDistance(geometry.DoublePointToCoordinate(shapeCentroid, targetShapeCentroid)) centroidDistance := geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(shapeCentroid, targetShapeCentroid))
if centroidDistance > shapeBoundingRadius+targetShapeBoundingRadius { if centroidDistance > shapeBoundingRadius+targetShapeBoundingRadius {
continue continue
} }

View File

@ -45,5 +45,5 @@ func (slf *shape[V]) IsWall() bool {
} }
func (slf *shape[V]) GetCost(point geometry.Point[V]) V { func (slf *shape[V]) GetCost(point geometry.Point[V]) V {
return geometry.CalcDistance(geometry.DoublePointToCoordinate(slf.Centroid(), point)) return geometry.CalcDistanceWithCoordinate(geometry.DoublePointToCoordinate(slf.Centroid(), point))
} }

View File

@ -59,6 +59,26 @@ func (slf Point[V]) Copy() Point[V] {
return PointCopy(slf) return PointCopy(slf)
} }
// Add 得到加上 point 后的点
func (slf Point[V]) Add(point Point[V]) Point[V] {
return slf.GetOffset(point.GetXY())
}
// Sub 得到减去 point 后的点
func (slf Point[V]) Sub(point Point[V]) Point[V] {
return NewPoint(slf.GetX()-point.GetX(), slf.GetY()-point.GetY())
}
// Mul 得到乘以 point 后的点
func (slf Point[V]) Mul(point Point[V]) Point[V] {
return NewPoint(slf.GetX()*point.GetX(), slf.GetY()*point.GetY())
}
// Div 得到除以 point 后的点
func (slf Point[V]) Div(point Point[V]) Point[V] {
return NewPoint(slf.GetX()/point.GetX(), slf.GetY()/point.GetY())
}
// NewPointCap 创建一个由 x、y 坐标组成的点,这个点具有一个数据容量 // NewPointCap 创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
func NewPointCap[V generic.SignedNumber, D any](x, y V) PointCap[V, D] { func NewPointCap[V generic.SignedNumber, D any](x, y V) PointCap[V, D] {
return PointCap[V, D]{ return PointCap[V, D]{

View File

@ -84,6 +84,12 @@ func (slf Shape[V]) Contains(point Point[V]) bool {
return inside return inside
} }
// ToCircle 将形状转换为圆形进行处理
// - 当形状非圆形时将会产生意外情况
func (slf Shape[V]) ToCircle() Circle[V] {
return Circle[V]{slf}
}
// String 将该形状转换为可视化的字符串进行返回 // String 将该形状转换为可视化的字符串进行返回
func (slf Shape[V]) String() string { func (slf Shape[V]) String() string {
var result string var result string
@ -412,7 +418,7 @@ func CalcBoundingRadius[V generic.SignedNumber](shape Shape[V]) V {
var boundingRadius V var boundingRadius V
var centroid = CalcRectangleCentroid(shape) var centroid = CalcRectangleCentroid(shape)
for _, point := range shape.Points() { for _, point := range shape.Points() {
distance := CalcDistance(DoublePointToCoordinate(centroid, point)) distance := CalcDistanceWithCoordinate(DoublePointToCoordinate(centroid, point))
if distance > boundingRadius { if distance > boundingRadius {
boundingRadius = distance boundingRadius = distance
} }
@ -424,7 +430,7 @@ func CalcBoundingRadius[V generic.SignedNumber](shape Shape[V]) V {
func CalcBoundingRadiusWithCentroid[V generic.SignedNumber](shape Shape[V], centroid Point[V]) V { func CalcBoundingRadiusWithCentroid[V generic.SignedNumber](shape Shape[V], centroid Point[V]) V {
var boundingRadius V var boundingRadius V
for _, point := range shape.Points() { for _, point := range shape.Points() {
distance := CalcDistance(DoublePointToCoordinate(centroid, point)) distance := CalcDistanceWithCoordinate(DoublePointToCoordinate(centroid, point))
if distance > boundingRadius { if distance > boundingRadius {
boundingRadius = distance boundingRadius = distance
} }
@ -459,7 +465,7 @@ func ProjectionPointToShape[V generic.SignedNumber](point Point[V], shape Shape[
for _, edge := range shape.Edges() { for _, edge := range shape.Edges() {
projectedPoint := CalcProjectionPoint(edge, point) projectedPoint := CalcProjectionPoint(edge, point)
distance := CalcDistance(DoublePointToCoordinate(point, projectedPoint)) distance := CalcDistanceWithCoordinate(DoublePointToCoordinate(point, projectedPoint))
if !hasClosestProjection || distance < closestDistance { if !hasClosestProjection || distance < closestDistance {
closestDistance = distance closestDistance = distance
closestProjection = projectedPoint closestProjection = projectedPoint