部分shape函数转移到rectangle,并且由固定类型改为泛型

This commit is contained in:
kercylan98 2023-06-16 18:47:16 +08:00
parent e14c871ff0
commit d972261164
4 changed files with 184 additions and 0 deletions

View File

@ -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}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
})
}