From 4f05f7f5229b1b2b48166ea9f23c96ac05211a59 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 19 Jun 2023 11:26:20 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=A2=9E=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=AE=A1=E7=AE=97=E5=87=BD=E6=95=B0=20CalcProjectionP?= =?UTF-8?q?oint=20=E8=AE=A1=E7=AE=97=E4=B8=80=E4=B8=AA=E7=82=B9=E5=88=B0?= =?UTF-8?q?=E4=B8=80=E6=9D=A1=E7=BA=BF=E6=AE=B5=E7=9A=84=E6=9C=80=E8=BF=91?= =?UTF-8?q?=E7=82=B9=20DoublePointToCoordinate=20=E5=B0=86=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=E4=BD=8D=E7=BD=AE=E8=BD=AC=E6=8D=A2=E4=B8=BA=20x1,=20?= =?UTF-8?q?y1,=20x2,=20y2=20=E7=9A=84=E5=9D=90=E6=A0=87=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=20CalcDistanceSquared=20=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E4=B8=A4=E7=82=B9=E4=B9=8B=E9=97=B4=E7=9A=84=E5=B9=B3=E6=96=B9?= =?UTF-8?q?=E8=B7=9D=E7=A6=BB=20Clamp=20=E5=B0=86=E7=BB=99=E5=AE=9A?= =?UTF-8?q?=E5=80=BC=E9=99=90=E5=88=B6=E5=9C=A8=E6=9C=80=E5=B0=8F=E5=80=BC?= =?UTF-8?q?=E5=92=8C=E6=9C=80=E5=A4=A7=E5=80=BC=E4=B9=8B=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/geometry/geometry.go | 7 +++++++ utils/geometry/position.go | 16 ++++++++++++++++ utils/maths/math.go | 11 +++++++++++ 3 files changed, 34 insertions(+) diff --git a/utils/geometry/geometry.go b/utils/geometry/geometry.go index 11bb7fd..30d7f45 100644 --- a/utils/geometry/geometry.go +++ b/utils/geometry/geometry.go @@ -114,6 +114,13 @@ func CalcDistance[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))) } +// CalcDistanceSquared 计算两点之间的平方距离 +// - 这个函数的主要用途是在需要计算两点之间距离的情况下,但不需要得到实际的距离值,而只需要比较距离大小。因为平方根运算相对较为耗时,所以在只需要比较大小的情况下,通常会使用平方距离。 +func CalcDistanceSquared[V generic.SignedNumber](x1, y1, x2, y2 V) V { + dx, dy := x2-x1, y2-y1 + return dx*dx + dy*dy +} + // CalcAngle 计算点2位于点1之间的角度 func CalcAngle[V generic.SignedNumber](x1, y1, x2, y2 V) V { return V(math.Atan2(float64(y2-y1), float64(x2-x1)) * 180 / math.Pi) diff --git a/utils/geometry/position.go b/utils/geometry/position.go index 803bf82..c092e97 100644 --- a/utils/geometry/position.go +++ b/utils/geometry/position.go @@ -2,6 +2,7 @@ package geometry import ( "github.com/kercylan98/minotaur/utils/generic" + "github.com/kercylan98/minotaur/utils/maths" "math" ) @@ -157,3 +158,18 @@ func PosToCoordinateArrayWithMulti[V generic.SignedNumber](width V, positions .. func PosSameRow[V generic.SignedNumber](width, pos1, pos2 V) bool { return (pos1 / width) == (pos2 / width) } + +// DoublePointToCoordinate 将两个位置转换为 x1, y1, x2, y2 的坐标进行返回 +func DoublePointToCoordinate[V generic.SignedNumber](point1, point2 Point[V]) (x1, y1, x2, y2 V) { + return point1.GetX(), point1.GetY(), point2.GetX(), point2.GetY() +} + +// CalcProjectionPoint 计算一个点到一条线段的最近点(即投影点)的。这个函数接收一个点和一条线段作为输入,线段由两个端点组成。 +// - 该函数的主要用于需要计算一个点到一条线段的最近点的情况下 +func CalcProjectionPoint[V generic.SignedNumber](linePointA, linePointB, point Point[V]) Point[V] { + ax, ay, bx, by := DoublePointToCoordinate(linePointA, linePointB) + ds := CalcDistanceSquared(ax, ay, bx, by) + px, py := point.GetXY() + clamp := maths.Clamp((px-ax)*(bx-ax)+(py-ay)*(by-ay)/ds, V(0), V(1)) + return NewPoint(ax+clamp*(bx-ax), ay+clamp*(by-ay)) +} diff --git a/utils/maths/math.go b/utils/maths/math.go index 6ba6df3..0117adc 100644 --- a/utils/maths/math.go +++ b/utils/maths/math.go @@ -83,3 +83,14 @@ func MaxMin[V generic.Number](a, b V) (max, min V) { } return b, a } + +// Clamp 将给定值限制在最小值和最大值之间 +func Clamp[V generic.Number](value, min, max V) V { + if value < min { + return min + } + if value > max { + return max + } + return value +}