feat: 增加几何运算辅助函数
CalcRayIsIntersect 根据给定的位置和角度生成射线,检测射线是否与多边形发生碰撞 CalcRadianWithAngle 根据角度 angle 计算弧度 CalcLineSegmentIsIntersect 计算两条线段是否相交 CalcLineSegmentSlope 计算线段的斜率 CalcLineSegmentIntercept 计算线段的截距 ConvertLineSegmentGeneric 转换线段的泛型类型为特定类型 Point.Min 注释为 Max 的问题修复
This commit is contained in:
parent
269662486b
commit
c7a6e09926
|
@ -8,31 +8,19 @@ import (
|
|||
// 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
|
||||
return CalcDistanceWithPoint(slf.Centroid(), point)
|
||||
}
|
||||
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
|
||||
return CalcRectangleCentroid(slf.Shape)
|
||||
}
|
||||
|
||||
// Overlap 与另一个圆是否发生重叠
|
||||
|
|
|
@ -133,16 +133,17 @@ func CalcAngle[V generic.SignedNumber](x1, y1, x2, y2 V) V {
|
|||
|
||||
// CalcNewCoordinate 根据给定的x、y坐标、角度和距离计算新的坐标
|
||||
func CalcNewCoordinate[V generic.SignedNumber](x, y, angle, distance V) (newX, newY V) {
|
||||
// 将角度转换为弧度
|
||||
radian := CalcRadianWithAngle(angle)
|
||||
newX = x + distance*V(math.Cos(float64(radian)))
|
||||
newY = y + distance*V(math.Sin(float64(radian)))
|
||||
return newX, newY
|
||||
}
|
||||
|
||||
// CalcRadianWithAngle 根据角度 angle 计算弧度
|
||||
func CalcRadianWithAngle[V generic.SignedNumber](angle V) V {
|
||||
var pi = math.Pi
|
||||
var dividend = 180.0
|
||||
radians := angle * V(pi) / V(dividend)
|
||||
|
||||
// 计算新的坐标
|
||||
newX = x + distance*V(math.Cos(float64(radians)))
|
||||
newY = y + distance*V(math.Sin(float64(radians)))
|
||||
|
||||
return newX, newY
|
||||
return angle * V(pi) / V(dividend)
|
||||
}
|
||||
|
||||
// CalcAngleDifference 计算两个角度之间的最小角度差
|
||||
|
@ -155,3 +156,18 @@ func CalcAngleDifference[V generic.SignedNumber](angleA, angleB V) V {
|
|||
t -= V(pi)
|
||||
return t
|
||||
}
|
||||
|
||||
// CalcRayIsIntersect 根据给定的位置和角度生成射线,检测射线是否与多边形发生碰撞
|
||||
func CalcRayIsIntersect[V generic.SignedNumber](x, y, angle V, shape Shape[V]) bool {
|
||||
fx, fy := float64(x), float64(y)
|
||||
radian := CalcRadianWithAngle(float64(angle))
|
||||
end := NewPoint(fx+math.Cos(radian), fy+math.Sin(radian))
|
||||
|
||||
edges := shape.Edges()
|
||||
for i := 0; i < len(edges); i++ {
|
||||
if CalcLineSegmentIsIntersect(NewLineSegment(NewPoint(fx, fy), end), ConvertLineSegmentGeneric[V, float64](edges[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -57,6 +57,13 @@ func (slf LineSegment[V]) GetLength() V {
|
|||
return CalcDistanceWithCoordinate(DoublePointToCoordinate(slf.GetStart(), slf.GetEnd()))
|
||||
}
|
||||
|
||||
// ConvertLineSegmentGeneric 转换线段的泛型类型为特定类型
|
||||
func ConvertLineSegmentGeneric[V generic.SignedNumber, TO generic.SignedNumber](line LineSegment[V]) LineSegment[TO] {
|
||||
x1, y1 := line.GetStart().GetXY()
|
||||
x2, y2 := line.GetEnd().GetXY()
|
||||
return NewLineSegment(NewPoint(TO(x1), TO(y1)), NewPoint(TO(x2), TO(y2)))
|
||||
}
|
||||
|
||||
// PointOnLineSegmentWithCoordinate 通过一个线段两个点的位置和一个点的坐标,判断这个点是否在一条线段上
|
||||
func PointOnLineSegmentWithCoordinate[V generic.SignedNumber](x1, y1, x2, y2, x, y V) bool {
|
||||
return (x-x1)*(y2-y1) == (x2-x1)*(y-y1)
|
||||
|
@ -138,3 +145,37 @@ func CalcLineSegmentIsOverlap[V generic.SignedNumber](line1, line2 LineSegment[V
|
|||
}
|
||||
return NewLineSegment(shapes[1][2].Point, shapes[2][2].Point), true
|
||||
}
|
||||
|
||||
// CalcLineSegmentIsIntersect 计算两条线段是否相交
|
||||
func CalcLineSegmentIsIntersect[V generic.SignedNumber](line1, line2 LineSegment[V]) bool {
|
||||
fl1 := ConvertLineSegmentGeneric[V, float64](line1)
|
||||
fl2 := ConvertLineSegmentGeneric[V, float64](line2)
|
||||
slope1 := CalcLineSegmentSlope(fl1)
|
||||
slope2 := CalcLineSegmentSlope(fl2)
|
||||
|
||||
if slope1 == slope2 {
|
||||
return false
|
||||
}
|
||||
|
||||
intercept1 := CalcLineSegmentIntercept(fl1)
|
||||
intercept2 := CalcLineSegmentIntercept(fl2)
|
||||
|
||||
intersectX := (intercept2 - intercept1) / (slope1 - slope2)
|
||||
|
||||
if intersectX >= maths.Min(fl1.GetStart().GetX(), fl1.GetEnd().GetX()) && intersectX <= maths.Max(fl1.GetStart().GetX(), fl1.GetEnd().GetX()) &&
|
||||
intersectX >= maths.Min(fl2.GetStart().GetX(), fl2.GetEnd().GetX()) && intersectX <= maths.Max(fl2.GetStart().GetX(), fl2.GetEnd().GetX()) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// CalcLineSegmentSlope 计算线段的斜率
|
||||
func CalcLineSegmentSlope[V generic.SignedNumber](line LineSegment[V]) V {
|
||||
return (line.GetEnd().GetY() - line.GetStart().GetY()) / (line.GetEnd().GetX() - line.GetStart().GetX())
|
||||
}
|
||||
|
||||
// CalcLineSegmentIntercept 计算线段的截距
|
||||
func CalcLineSegmentIntercept[V generic.SignedNumber](line LineSegment[V]) V {
|
||||
return line.GetStart().GetY() - CalcLineSegmentSlope(line)*line.GetStart().GetX()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package geometry_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/utils/geometry"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCalcLineSegmentIsIntersect(t *testing.T) {
|
||||
line1 := geometry.NewLineSegment(geometry.NewPoint(1, 1), geometry.NewPoint(3, 5))
|
||||
line2 := geometry.NewLineSegment(geometry.NewPoint(0, 5), geometry.NewPoint(3, 6))
|
||||
fmt.Println(geometry.CalcLineSegmentIsIntersect(line1, line2))
|
||||
}
|
|
@ -97,7 +97,7 @@ func (slf Point[V]) Max(point Point[V]) Point[V] {
|
|||
return NewPoint(x, y)
|
||||
}
|
||||
|
||||
// Max 返回两个位置中每个维度的最小值组成的新的位置
|
||||
// Min 返回两个位置中每个维度的最小值组成的新的位置
|
||||
func (slf Point[V]) Min(point Point[V]) Point[V] {
|
||||
x, y := slf.GetXY()
|
||||
px, py := point.GetXY()
|
||||
|
|
Loading…
Reference in New Issue