From e14c871ff05b0366fee92f4ce4832d4ec057dae1 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 16 Jun 2023 17:29:13 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E9=80=9A=E8=BF=87=E4=BC=A0?= =?UTF-8?q?=E5=85=A5=E7=9A=84=E4=B8=80=E7=BB=84=E5=9D=90=E6=A0=87=20xys=20?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E4=B8=80=E4=B8=AA=E5=9B=BE=E5=BD=A2=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E7=9A=84=E7=9F=A9=E5=BD=A2=E8=8C=83=E5=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 6 + go.sum | 12 ++ utils/g2d/shape.go | 151 ----------------------- utils/geometry/rectangle.go | 46 +++++++ utils/geometry/rectangle_example_test.go | 33 +++++ utils/geometry/rectangle_test.go | 34 +++++ 6 files changed, 131 insertions(+), 151 deletions(-) create mode 100644 utils/geometry/rectangle_example_test.go create mode 100644 utils/geometry/rectangle_test.go diff --git a/go.mod b/go.mod index b34543e..d765c8b 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,9 @@ require ( github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jonboulle/clockwork v0.3.0 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/reedsolomon v1.11.7 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -43,6 +45,8 @@ require ( github.com/nats-io/nuid v1.0.1 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/smartystreets/assertions v1.13.1 // indirect + github.com/smartystreets/goconvey v1.8.0 // indirect github.com/templexxx/cpu v0.0.9 // indirect github.com/templexxx/xorsimd v0.4.1 // indirect github.com/tidwall/match v1.1.1 // indirect @@ -55,9 +59,11 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect + golang.org/x/mod v0.9.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.7.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect diff --git a/go.sum b/go.sum index e037390..f572a41 100644 --- a/go.sum +++ b/go.sum @@ -60,12 +60,16 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU= github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= @@ -124,6 +128,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= +github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= +github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w= +github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg= github.com/sony/sonyflake v1.1.0 h1:wnrEcL3aOkWmPlhScLEGAXKkLAIslnBteNUq4Bw6MM4= github.com/sony/sonyflake v1.1.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -202,6 +210,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -254,6 +264,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/utils/g2d/shape.go b/utils/g2d/shape.go index 807d183..b5130aa 100644 --- a/utils/g2d/shape.go +++ b/utils/g2d/shape.go @@ -1,140 +1,10 @@ package g2d import ( - "github.com/kercylan98/minotaur/utils/g2d/shape" "github.com/kercylan98/minotaur/utils/geometry" "sort" ) -type MatrixShapeSearchResult[Mark any] struct { - Shape *shape.Shape[Mark] - Points []shape.Point -} - -// MatrixShapeSearchWithYX 二维矩阵形状搜索 -func MatrixShapeSearchWithYX[T any, Mark any](matrix [][]T, shapes []*shape.Shape[Mark], checkMatchHandle func(val T) bool) []MatrixShapeSearchResult[Mark] { - record := map[int]map[int]bool{} - width := len(matrix[0]) - height := len(matrix) - for x := 0; x < width; x++ { - for y := 0; y < height; y++ { - record[x] = map[int]bool{y: true} - } - } - - var result []MatrixShapeSearchResult[Mark] - - for _, s := range shapes { - points := s.GetPoints() - x, y := 0, 0 - mx, my := s.GetMaxXY() - for { - if x+mx >= width { - x = 0 - y++ - } - if y+my >= height { - break - } - var count int - for _, point := range points { - px, py := point.GetXY() - px, py = px+x, py+y - if record[px][py] { - break - } - if checkMatchHandle(matrix[py][px]) { - count++ - } else { - break - } - } - if count == len(points) { - target := MatrixShapeSearchResult[Mark]{ - Shape: s, - } - for _, point := range points { - px, py := point.GetXY() - px, py = px+x, py+y - ys, exist := record[px] - if !exist { - ys = map[int]bool{} - record[px] = ys - } - ys[py] = true - target.Points = append(target.Points, shape.NewPoint(px, py)) - } - result = append(result, target) - } - x++ - } - } - - return result -} - -// MatrixShapeSearchWithXY 二维矩阵形状搜索 -func MatrixShapeSearchWithXY[T any, Mark any](matrix [][]T, shapes []*shape.Shape[Mark], checkMatchHandle func(val T) bool) []MatrixShapeSearchResult[Mark] { - width := len(matrix) - height := len(matrix[0]) - record := map[int]map[int]bool{} - for x := 0; x < width; x++ { - for y := 0; y < height; y++ { - record[x] = map[int]bool{y: true} - } - } - - var result []MatrixShapeSearchResult[Mark] - - for _, s := range shapes { - points := s.GetPoints() - x, y := 0, 0 - mx, my := s.GetMaxXY() - for { - if x+mx >= width { - x = 0 - y++ - } - if y+my >= height { - break - } - var count int - for _, point := range points { - px, py := point.GetXY() - px, py = px+x, py+y - if record[px][py] { - break - } - if checkMatchHandle(matrix[px][py]) { - count++ - } else { - break - } - } - if count == len(points) { - target := MatrixShapeSearchResult[Mark]{ - Shape: s, - } - for _, point := range points { - px, py := point.GetXY() - px, py = px+x, py+y - ys, exist := record[px] - if !exist { - ys = map[int]bool{} - record[px] = ys - } - ys[py] = true - target.Points = append(target.Points, shape.NewPoint(px, py)) - } - result = append(result, target) - } - x++ - } - } - - return result -} - // SearchNotRepeatCross 在一组二维坐标中从大到小搜索不重复交叉(十字)线 // - 不重复指一个位置被使用后将不会被其他交叉线(十字)使用 func SearchNotRepeatCross(xys ...[2]int) (result [][][2]int) { @@ -949,24 +819,3 @@ func CoverageAreaBoundless(l, r, t, b int) (left, right, top, bottom int) { bottom = b + differentY return } - -// GetShapeCoverageArea 获取一个图形覆盖的范围 -func GetShapeCoverageArea(xys ...[2]int) (left, right, top, bottom int) { - left, top = -1, -1 - for _, xy := range xys { - x, y := geometry.CoordinateArrayToCoordinate(xy) - if x < left || left == -1 { - left = x - } - if x > right { - right = x - } - if y < top || top == -1 { - top = y - } - if y > bottom { - bottom = y - } - } - return -} diff --git a/utils/geometry/rectangle.go b/utils/geometry/rectangle.go index d60302e..9fb5298 100644 --- a/utils/geometry/rectangle.go +++ b/utils/geometry/rectangle.go @@ -143,3 +143,49 @@ func CoordinateMatrixToPosMatrix[V any](matrix [][]V) (width int, posMatrix []V) } return } + +// GetShapeCoverageAreaWithCoordinateArray 通过传入的一组坐标 xys 计算一个图形覆盖的矩形范围 +func GetShapeCoverageAreaWithCoordinateArray[V generic.Number](xys ...Point[V]) (left, right, top, bottom V) { + hasLeft, hasTop := false, false + for _, xy := range xys { + x, y := CoordinateArrayToCoordinate(xy) + if x < left || !hasLeft { + hasLeft = true + left = x + } + if x > right { + right = x + } + if y < top || !hasTop { + hasTop = true + top = y + } + if y > bottom { + bottom = y + } + } + return +} + +// GetShapeCoverageAreaWithPos 通过传入的一组坐标 xys 计算一个图形覆盖的矩形范围 +func GetShapeCoverageAreaWithPos[V generic.Number](width V, positions ...V) (left, right, top, bottom V) { + hasLeft, hasTop := false, false + for _, pos := range positions { + x, y := PosToCoordinate(width, pos) + if x < left || !hasLeft { + hasLeft = true + left = x + } + if x > right { + right = x + } + if y < top || !hasTop { + hasTop = true + top = y + } + if y > bottom { + bottom = y + } + } + return +} diff --git a/utils/geometry/rectangle_example_test.go b/utils/geometry/rectangle_example_test.go new file mode 100644 index 0000000..a8b52f6 --- /dev/null +++ b/utils/geometry/rectangle_example_test.go @@ -0,0 +1,33 @@ +package geometry_test + +import ( + "fmt" + "github.com/kercylan98/minotaur/utils/geometry" +) + +func ExampleGetShapeCoverageAreaWithCoordinateArray() { + // # # # + // # X # + // # X X + + 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)) + + left, right, top, bottom := geometry.GetShapeCoverageAreaWithCoordinateArray(points...) + fmt.Println(fmt.Sprintf("left: %v, right: %v, top: %v, bottom: %v", left, right, top, bottom)) + + // left: 1, right: 2, top: 1, bottom: 2 +} + +func ExampleGetShapeCoverageAreaWithPos() { + // # # # 0 1 2 + // # X # 3 4 5 + // # X X 6 7 8 + + left, right, top, bottom := geometry.GetShapeCoverageAreaWithPos(3, 4, 7, 8) + fmt.Println(fmt.Sprintf("left: %v, right: %v, top: %v, bottom: %v", left, right, top, bottom)) + + // left: 1, right: 2, top: 1, bottom: 2 +} diff --git a/utils/geometry/rectangle_test.go b/utils/geometry/rectangle_test.go new file mode 100644 index 0000000..0e548a2 --- /dev/null +++ b/utils/geometry/rectangle_test.go @@ -0,0 +1,34 @@ +package geometry_test + +import ( + "github.com/kercylan98/minotaur/utils/geometry" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +func TestGetShapeCoverageAreaWithCoordinateArray(t *testing.T) { + Convey("TestGetShapeCoverageAreaWithCoordinateArray", 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)) + + left, right, top, bottom := geometry.GetShapeCoverageAreaWithCoordinateArray(points...) + + So(left, ShouldEqual, 1) + So(right, ShouldEqual, 2) + So(top, ShouldEqual, 1) + So(bottom, ShouldEqual, 2) + }) +} + +func TestGetShapeCoverageAreaWithPos(t *testing.T) { + Convey("TestGetShapeCoverageAreaWithPos", t, func() { + left, right, top, bottom := geometry.GetShapeCoverageAreaWithPos(3, 4, 7, 8) + + So(left, ShouldEqual, 1) + So(right, ShouldEqual, 2) + So(top, ShouldEqual, 1) + So(bottom, ShouldEqual, 2) + }) +}