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