✨ 图形搜索增强
This commit is contained in:
parent
78ab5ac7fe
commit
016332b6be
|
@ -17,9 +17,25 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
Directions = []Direction{DirectionUp, DirectionDown, DirectionLeft, DirectionRight} // 上下左右四个方向的数组
|
||||
DirectionUDLR = []Direction{DirectionUp, DirectionDown, DirectionLeft, DirectionRight} // 上下左右四个方向的数组
|
||||
DirectionLRUD = []Direction{DirectionLeft, DirectionRight, DirectionUp, DirectionDown} // 左右上下四个方向的数组
|
||||
)
|
||||
|
||||
// GetOppositionDirection 获取特定方向的对立方向
|
||||
func GetOppositionDirection(direction Direction) Direction {
|
||||
switch direction {
|
||||
case DirectionUp:
|
||||
return DirectionDown
|
||||
case DirectionDown:
|
||||
return DirectionUp
|
||||
case DirectionLeft:
|
||||
return DirectionRight
|
||||
case DirectionRight:
|
||||
return DirectionLeft
|
||||
}
|
||||
return DirectionUnknown
|
||||
}
|
||||
|
||||
// GetDirectionNextWithCoordinate 获取特定方向上的下一个坐标
|
||||
func GetDirectionNextWithCoordinate[V generic.Number](direction Direction, x, y V) (nx, ny V) {
|
||||
switch direction {
|
||||
|
|
|
@ -38,6 +38,11 @@ func (slf Point[V]) GetOffset(x, y V) Point[V] {
|
|||
return NewPoint(slf.GetX()+x, slf.GetY()+y)
|
||||
}
|
||||
|
||||
// Negative 返回该点是否是一个负数坐标
|
||||
func (slf Point[V]) Negative() bool {
|
||||
return slf.GetX() < V(0) || slf.GetY() < V(0)
|
||||
}
|
||||
|
||||
// Equal 返回两个点是否相等
|
||||
func (slf Point[V]) Equal(point Point[V]) bool {
|
||||
return slf.GetX() == point.GetX() && slf.GetY() == point.GetY()
|
||||
|
|
|
@ -7,6 +7,10 @@ import (
|
|||
"sort"
|
||||
)
|
||||
|
||||
var (
|
||||
ShapeStringHasBorder = false // 控制 Shape.String 是否拥有边界
|
||||
)
|
||||
|
||||
// Shape 通过多个点表示了一个形状
|
||||
type Shape[V generic.Number] []Point[V]
|
||||
|
||||
|
@ -21,22 +25,42 @@ func (slf Shape[V]) String() string {
|
|||
left, right, top, bottom := GetShapeCoverageAreaWithCoordinateArray(slf.Points()...)
|
||||
width := right - left + 1
|
||||
height := bottom - top + 1
|
||||
for y := top; y < top+height; y++ {
|
||||
for x := left; x < left+width; x++ {
|
||||
exist := false
|
||||
for _, p := range slf {
|
||||
if x == p.GetX() && y == p.GetY() {
|
||||
exist = true
|
||||
break
|
||||
if !ShapeStringHasBorder {
|
||||
for y := top; y < top+height; y++ {
|
||||
for x := left; x < left+width; x++ {
|
||||
exist := false
|
||||
for _, p := range slf {
|
||||
if x == p.GetX() && y == p.GetY() {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if exist {
|
||||
result += "X "
|
||||
} else {
|
||||
result += "# "
|
||||
}
|
||||
}
|
||||
if exist {
|
||||
result += "X "
|
||||
} else {
|
||||
result += "# "
|
||||
}
|
||||
result += "\r\n"
|
||||
}
|
||||
} else {
|
||||
for y := V(0); y < top+height; y++ {
|
||||
for x := V(0); x < left+width; x++ {
|
||||
exist := false
|
||||
for _, p := range slf {
|
||||
if x == p.GetX() && y == p.GetY() {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if exist {
|
||||
result += "X "
|
||||
} else {
|
||||
result += "# "
|
||||
}
|
||||
}
|
||||
result += "\r\n"
|
||||
}
|
||||
result += "\r\n"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -50,7 +74,7 @@ func (slf Shape[V]) String() string {
|
|||
func (slf Shape[V]) ShapeSearch(options ...ShapeSearchOption) (result []Shape[V]) {
|
||||
opt := &shapeSearchOptions{upperLimit: math.MaxInt}
|
||||
opt.directionCountUpper = map[Direction]int{}
|
||||
for _, d := range Directions {
|
||||
for _, d := range DirectionUDLR {
|
||||
opt.directionCountUpper[d] = math.MaxInt
|
||||
}
|
||||
|
||||
|
@ -122,41 +146,9 @@ func (slf Shape[V]) getAllGraphicComposition(opt *shapeSearchOptions) (result []
|
|||
rectangleShape := GenerateShapeOnRectangle(slf.Points()...)
|
||||
records := make(map[V]struct{})
|
||||
|
||||
// 通过每个点扩散图形
|
||||
for _, point := range slf.Points() {
|
||||
// 搜索四个方向
|
||||
var next = -1
|
||||
var directionPoint = point
|
||||
var links = Shape[V]{point}
|
||||
var directionCount = map[Direction]int{}
|
||||
for {
|
||||
var direction Direction
|
||||
next, direction = slice.NextLoop(Directions, next)
|
||||
for {
|
||||
directionPoint = GetDirectionNextWithCoordinateArray(direction, directionPoint)
|
||||
if px, py := directionPoint.GetXY(); px < 0 || px >= areaWidth || py < 0 || py >= areaHeight {
|
||||
break
|
||||
}
|
||||
if offsetPos := int(CoordinateArrayToPos(width, directionPoint.GetOffset(-left, -top))); offsetPos < 0 || offsetPos >= len(rectangleShape) || !rectangleShape[offsetPos].Data {
|
||||
break
|
||||
}
|
||||
links = append(links, directionPoint)
|
||||
directionCount[direction]++
|
||||
pos := directionPoint.GetPos(areaWidth)
|
||||
if _, exist := records[pos]; !exist {
|
||||
result = append(result, Shape[V]{directionPoint})
|
||||
records[pos] = struct{}{}
|
||||
}
|
||||
|
||||
}
|
||||
if direction == DirectionRight {
|
||||
break
|
||||
}
|
||||
directionPoint = point
|
||||
}
|
||||
|
||||
var match = func(links Shape[V], directionCount map[Direction]int, count int) bool {
|
||||
match := true
|
||||
for _, direction := range Directions {
|
||||
for _, direction := range DirectionUDLR {
|
||||
c := directionCount[direction]
|
||||
if c < opt.directionCountLower[direction] || c > opt.directionCountUpper[direction] {
|
||||
match = false
|
||||
|
@ -164,17 +156,86 @@ func (slf Shape[V]) getAllGraphicComposition(opt *shapeSearchOptions) (result []
|
|||
}
|
||||
}
|
||||
|
||||
if match && opt.directionCount > 0 && len(directionCount) != opt.directionCount {
|
||||
if opt.directionCount > 0 && len(directionCount) != opt.directionCount {
|
||||
match = false
|
||||
}
|
||||
|
||||
if match && (directionCount[DirectionUp] > 0 && directionCount[DirectionDown] > 0) || (directionCount[DirectionLeft] > 0 && directionCount[DirectionRight] > 0) {
|
||||
if directionCount[GetOppositionDirection(opt.oppositionDirection)] > 0 {
|
||||
match = false
|
||||
}
|
||||
|
||||
if opt.ra {
|
||||
match = false
|
||||
if directionCount[DirectionLeft] > 0 && directionCount[DirectionUp] > 0 && count == directionCount[DirectionLeft]+directionCount[DirectionUp] {
|
||||
match = true
|
||||
} else if directionCount[DirectionUp] > 0 && directionCount[DirectionRight] > 0 && count == directionCount[DirectionUp]+directionCount[DirectionRight] {
|
||||
match = true
|
||||
} else if directionCount[DirectionRight] > 0 && directionCount[DirectionDown] > 0 && count == directionCount[DirectionRight]+directionCount[DirectionDown] {
|
||||
match = true
|
||||
} else if directionCount[DirectionDown] > 0 && directionCount[DirectionLeft] > 0 && count == directionCount[DirectionDown]+directionCount[DirectionLeft] {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
|
||||
if match {
|
||||
result = append(result, links)
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
// 通过每个点扩散图形
|
||||
for _, point := range slf.Points() {
|
||||
// 搜索四个方向
|
||||
var next = -1
|
||||
var directionPoint = point
|
||||
var links = Shape[V]{point}
|
||||
var directionCount = map[Direction]int{}
|
||||
var count = 0
|
||||
for i, directions := range [][]Direction{DirectionUDLR, DirectionLRUD} {
|
||||
var direction Direction
|
||||
next, direction = slice.NextLoop(directions, next)
|
||||
for {
|
||||
directionPoint = GetDirectionNextWithCoordinateArray(direction, directionPoint)
|
||||
if px, py := directionPoint.GetXY(); px < 0 || px >= areaWidth || py < 0 || py >= areaHeight {
|
||||
break
|
||||
}
|
||||
offset := directionPoint.GetOffset(-left, -top)
|
||||
if offset.Negative() {
|
||||
break
|
||||
}
|
||||
offsetPos := int(offset.GetPos(width))
|
||||
if offsetPos < 0 || offsetPos >= len(rectangleShape) || !rectangleShape[offsetPos].Data {
|
||||
break
|
||||
}
|
||||
links = append(links, directionPoint)
|
||||
directionCount[direction]++
|
||||
count++
|
||||
match(links, directionCount, count)
|
||||
pos := directionPoint.GetPos(areaWidth)
|
||||
if _, exist := records[pos]; !exist {
|
||||
result = append(result, Shape[V]{directionPoint})
|
||||
records[pos] = struct{}{}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
finish := false
|
||||
switch i {
|
||||
case 0:
|
||||
if direction == DirectionRight {
|
||||
finish = true
|
||||
}
|
||||
case 1:
|
||||
if direction == DirectionDown {
|
||||
finish = true
|
||||
}
|
||||
}
|
||||
if finish {
|
||||
break
|
||||
}
|
||||
directionPoint = point
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
@ -9,11 +9,19 @@ type shapeSearchOptions struct {
|
|||
directionCountUpper map[Direction]int
|
||||
directionCount int
|
||||
oppositionDirection Direction
|
||||
ra bool
|
||||
}
|
||||
|
||||
// ShapeSearchOption 图形搜索可选项,用于 Shape.ShapeSearch 搜索支持
|
||||
type ShapeSearchOption func(options *shapeSearchOptions)
|
||||
|
||||
// WithShapeSearchRightAngle 通过直角的方式进行搜索
|
||||
func WithShapeSearchRightAngle() ShapeSearchOption {
|
||||
return func(options *shapeSearchOptions) {
|
||||
options.ra = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithShapeSearchOppositionDirection 通过限制对立方向的方式搜索
|
||||
// - 对立方向例如上不能与下共存
|
||||
func WithShapeSearchOppositionDirection(direction Direction) ShapeSearchOption {
|
||||
|
|
|
@ -13,6 +13,8 @@ func TestShape_Search(t *testing.T) {
|
|||
shape = append(shape, geometry.NewPoint(1, 1))
|
||||
shape = append(shape, geometry.NewPoint(1, 2))
|
||||
shape = append(shape, geometry.NewPoint(2, 2))
|
||||
shape = append(shape, geometry.NewPoint(1, 3))
|
||||
geometry.ShapeStringHasBorder = true
|
||||
|
||||
fmt.Println("形状:")
|
||||
fmt.Println(shape)
|
||||
|
@ -21,7 +23,7 @@ func TestShape_Search(t *testing.T) {
|
|||
geometry.WithShapeSearchDesc(),
|
||||
geometry.WithShapeSearchDeduplication(),
|
||||
geometry.WithShapeSearchPointCountLowerLimit(3),
|
||||
geometry.WithShapeSearchDirectionCount(1),
|
||||
geometry.WithShapeSearchRightAngle(),
|
||||
)
|
||||
|
||||
for _, shape := range shapes {
|
||||
|
|
Loading…
Reference in New Issue