✨ 部分shape函数转移到rectangle,并且由固定类型改为泛型
This commit is contained in:
parent
e14c871ff0
commit
d972261164
|
@ -38,6 +38,32 @@ func (slf Point[V]) Copy() Point[V] {
|
|||
return CoordinateArrayCopy(slf)
|
||||
}
|
||||
|
||||
// NewPointCap 创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
|
||||
func NewPointCap[V generic.Number, D any](x, y V) PointCap[V, D] {
|
||||
return PointCap[V, D]{
|
||||
Point: NewPoint(x, y),
|
||||
}
|
||||
}
|
||||
|
||||
// NewPointCapWithData 通过设置数据的方式创建一个由 x、y 坐标组成的点,这个点具有一个数据容量
|
||||
func NewPointCapWithData[V generic.Number, D any](x, y V, data D) PointCap[V, D] {
|
||||
return PointCap[V, D]{
|
||||
Point: NewPoint(x, y),
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// PointCap 表示了一个由 x、y 坐标组成的点,这个点具有一个数据容量
|
||||
type PointCap[V generic.Number, D any] struct {
|
||||
Point[V]
|
||||
Data D
|
||||
}
|
||||
|
||||
// GetData 获取数据
|
||||
func (slf PointCap[V, D]) GetData() D {
|
||||
return slf.Data
|
||||
}
|
||||
|
||||
// CoordinateToCoordinateArray 将坐标转换为x、y的坐标数组
|
||||
func CoordinateToCoordinateArray[V generic.Number](x, y V) Point[V] {
|
||||
return [2]V{x, y}
|
||||
|
|
|
@ -189,3 +189,106 @@ func GetShapeCoverageAreaWithPos[V generic.Number](width V, positions ...V) (lef
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CoverageAreaBoundless 将一个图形覆盖矩形范围设置为无边的
|
||||
// - 无边化表示会将多余的部分进行裁剪,例如图形左边从 2 开始的时候,那么左边将会被裁剪到从 0 开始
|
||||
func CoverageAreaBoundless[V generic.Number](l, r, t, b V) (left, right, top, bottom V) {
|
||||
differentX := 0 - l
|
||||
differentY := 0 - t
|
||||
left = l + differentX
|
||||
right = r + differentX
|
||||
top = t + differentY
|
||||
bottom = b + differentY
|
||||
return
|
||||
}
|
||||
|
||||
// GenerateShapeOnRectangle 生成一组二维坐标的形状
|
||||
// - 这个形状将被在一个刚好能容纳形状的矩形中表示
|
||||
// - 为 true 的位置表示了形状的每一个点
|
||||
func GenerateShapeOnRectangle[V generic.Number](xys ...Point[V]) (result []PointCap[V, bool]) {
|
||||
left, r, top, b := GetShapeCoverageAreaWithCoordinateArray(xys...)
|
||||
_, right, _, bottom := CoverageAreaBoundless(left, r, top, b)
|
||||
w, h := right+1, bottom+1
|
||||
result = make([]PointCap[V, bool], int(w*h))
|
||||
for _, xy := range xys {
|
||||
x, y := xy.GetXY()
|
||||
sx := x - (r - right)
|
||||
sy := y - (b - bottom)
|
||||
pos := CoordinateToPos(w, sx, sy)
|
||||
pointCap := &result[int(pos)]
|
||||
pointCap.Point[0] = sx
|
||||
pointCap.Point[1] = sy
|
||||
pointCap.Data = true
|
||||
}
|
||||
for pos, pointCap := range result {
|
||||
if !pointCap.Data {
|
||||
pointCap := &result[pos]
|
||||
sx, sy := PosToCoordinate(w, V(pos))
|
||||
pointCap.Point[0] = sx
|
||||
pointCap.Point[1] = sy
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetExpressibleRectangleBySize 获取一个宽高可表达的所有特定尺寸以上的矩形形状
|
||||
// - 返回值表示了每一个矩形右下角的x,y位置(左上角始终为0, 0)
|
||||
// - 矩形尺寸由大到小
|
||||
func GetExpressibleRectangleBySize[V generic.Number](width, height, minWidth, minHeight V) (result []Point[V]) {
|
||||
sourceWidth := width
|
||||
if width == 0 || height == 0 {
|
||||
return nil
|
||||
}
|
||||
if width < minWidth || height < minHeight {
|
||||
return nil
|
||||
}
|
||||
width--
|
||||
height--
|
||||
for {
|
||||
rightBottom := NewPoint(width, height)
|
||||
result = append(result, rightBottom)
|
||||
if width == 0 && height == 0 || (width < minWidth && height < minHeight) {
|
||||
return
|
||||
}
|
||||
if width == height {
|
||||
width--
|
||||
} else if width < height {
|
||||
if width+1 == sourceWidth {
|
||||
height--
|
||||
} else {
|
||||
width++
|
||||
height--
|
||||
}
|
||||
} else if width > height {
|
||||
width--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetExpressibleRectangle 获取一个宽高可表达的所有矩形形状
|
||||
// - 返回值表示了每一个矩形右下角的x,y位置(左上角始终为0, 0)
|
||||
// - 矩形尺寸由大到小
|
||||
func GetExpressibleRectangle[V generic.Number](width, height V) (result []Point[V]) {
|
||||
return GetExpressibleRectangleBySize(width, height, 1, 1)
|
||||
}
|
||||
|
||||
// GetRectangleFullPointsByXY 通过开始结束坐标获取一个矩形包含的所有点
|
||||
// - 例如 1,1 到 2,2 的矩形结果为 1,1 2,1 1,2 2,2
|
||||
func GetRectangleFullPointsByXY[V generic.Number](startX, startY, endX, endY V) (result []Point[V]) {
|
||||
for x := startX; x <= endX; x++ {
|
||||
for y := startY; y <= endY; y++ {
|
||||
result = append(result, NewPoint(x, y))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetRectangleFullPoints 获取一个矩形包含的所有点
|
||||
func GetRectangleFullPoints[V generic.Number](width, height V) (result []Point[V]) {
|
||||
for x := V(0); x < width; x++ {
|
||||
for y := V(0); y < height; y++ {
|
||||
result = append(result, NewPoint(x, y))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -31,3 +31,19 @@ func ExampleGetShapeCoverageAreaWithPos() {
|
|||
|
||||
// left: 1, right: 2, top: 1, bottom: 2
|
||||
}
|
||||
|
||||
func ExampleCoverageAreaBoundless() {
|
||||
// # # #
|
||||
// # X #
|
||||
// # X X
|
||||
|
||||
// ↓
|
||||
|
||||
// X #
|
||||
// X X
|
||||
|
||||
left, right, top, bottom := geometry.CoverageAreaBoundless(1, 2, 1, 2)
|
||||
fmt.Println(fmt.Sprintf("left: %v, right: %v, top: %v, bottom: %v", left, right, top, bottom))
|
||||
|
||||
// left: 0, right: 1, top: 0, bottom: 1
|
||||
}
|
||||
|
|
|
@ -32,3 +32,42 @@ func TestGetShapeCoverageAreaWithPos(t *testing.T) {
|
|||
So(bottom, ShouldEqual, 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCoverageAreaBoundless(t *testing.T) {
|
||||
Convey("TestCoverageAreaBoundless", t, func() {
|
||||
left, right, top, bottom := geometry.CoverageAreaBoundless(1, 2, 1, 2)
|
||||
|
||||
So(left, ShouldEqual, 0)
|
||||
So(right, ShouldEqual, 1)
|
||||
So(top, ShouldEqual, 0)
|
||||
So(bottom, ShouldEqual, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateShapeOnRectangle(t *testing.T) {
|
||||
Convey("TestGenerateShapeOnRectangle", t, func() {
|
||||
var points []geometry.Point[int]
|
||||
points = append(points, geometry.NewPoint(1, 1))
|
||||
points = append(points, geometry.NewPoint(2, 1))
|
||||
points = append(points, geometry.NewPoint(2, 2))
|
||||
|
||||
ps := geometry.GenerateShapeOnRectangle(points...)
|
||||
|
||||
So(ps[0].GetX(), ShouldEqual, 0)
|
||||
So(ps[0].GetY(), ShouldEqual, 0)
|
||||
So(ps[0].GetData(), ShouldEqual, true)
|
||||
|
||||
So(ps[1].GetX(), ShouldEqual, 1)
|
||||
So(ps[1].GetY(), ShouldEqual, 0)
|
||||
So(ps[1].GetData(), ShouldEqual, true)
|
||||
|
||||
So(ps[2].GetX(), ShouldEqual, 0)
|
||||
So(ps[2].GetY(), ShouldEqual, 1)
|
||||
So(ps[2].GetData(), ShouldEqual, false)
|
||||
|
||||
So(ps[3].GetX(), ShouldEqual, 1)
|
||||
So(ps[3].GetY(), ShouldEqual, 1)
|
||||
So(ps[3].GetData(), ShouldEqual, true)
|
||||
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue