Fix contour clockwise direction
This commit is contained in:
parent
c2bfa9313e
commit
eb0cb3a505
3
go.mod
3
go.mod
|
@ -9,7 +9,7 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/ctessum/geom v0.2.12
|
||||
github.com/ctessum/polyclip-go v1.1.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||
golang.org/x/text v0.14.0
|
||||
|
@ -17,7 +17,6 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/ctessum/polyclip-go v1.1.0 // indirect
|
||||
github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82 // indirect
|
||||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect
|
||||
)
|
||||
|
|
91
go.sum
91
go.sum
|
@ -1,26 +1,5 @@
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/ctessum/geom v0.2.12 h1:xkdGPIFFIj+6b8moCRg5rDJ2m2gKl4qKBlB/4YqAWg4=
|
||||
github.com/ctessum/geom v0.2.12/go.mod h1:7mOBGcEdKBQaI9y1umx14/eHDv3TUqYm+9i4YUQwoGo=
|
||||
github.com/ctessum/polyclip-go v1.1.0 h1:TGMfwMynNykXwCZCxI+CHdjo/ZE9JThup/gmrgigGEE=
|
||||
github.com/ctessum/polyclip-go v1.1.0/go.mod h1:e/Lh1JOGyynZwLr0M4tZGIyx07wXw9T+pu6hFut+kFQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
|
||||
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
|
||||
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
|
||||
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
|
||||
github.com/go-gl/gl v0.0.0-20180407155706-68e253793080/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
||||
github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82 h1:EvokxLQsaaQjcWVWSV38221VAK7qc2zhaO17bKys/18=
|
||||
github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg=
|
||||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 h1:8jtTdc+Nfj9AR+0soOeia9UZSvYBvETVHZrugUowJ7M=
|
||||
|
@ -29,85 +8,15 @@ github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0=
|
|||
github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
|
||||
github.com/jonas-p/go-shp v0.1.2-0.20190401125246-9fd306ae10a6/go.mod h1:MRIhyxDQ6VVp0oYeD7yPGr5RSTNScUFKCDsI5DR7PtI=
|
||||
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/llgcode/draw2d v0.0.0-20180817132918-587a55234ca2/go.mod h1:mVa0dA29Db2S4LVqDYLlsePDzRJLDfdhVZiI15uY0FA=
|
||||
github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb/go.mod h1:1l8ky+Ew27CMX29uG+a2hNOKpeNYEQjjtiALiBlFQbY=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/paulmach/orb v0.1.6/go.mod h1:pPwxxs3zoAyosNSbNKn1jiXV2+oovRDObDKfTvRegDI=
|
||||
github.com/paulmach/osm v0.1.1/go.mod h1:/UEV7XqKKTG3/46W+MtSmIl81yjV7cGoLkpol3S094I=
|
||||
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
|
||||
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
|
||||
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
|
||||
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
|
||||
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"math"
|
||||
)
|
||||
|
@ -54,6 +55,10 @@ func (r CubicCurveRecord) IsFlat() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (r CubicCurveRecord) String() string {
|
||||
return fmt.Sprintf("c %s %s %s", r.Control1, r.Control2, r.Anchor)
|
||||
}
|
||||
|
||||
func CubicCurveFromQuadraticRecord(q QuadraticCurveRecord) CubicCurveRecord {
|
||||
return CubicCurveRecord{
|
||||
Control1: q.Start.AddVector(q.Control.Multiply(2)).Divide(3),
|
||||
|
|
|
@ -58,3 +58,7 @@ func (r CubicSplineCurveRecord) SameType(other Record) bool {
|
|||
func (r CubicSplineCurveRecord) IsFlat() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r CubicSplineCurveRecord) String() string {
|
||||
return "todo"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
)
|
||||
|
||||
|
@ -55,3 +56,7 @@ func (r LineRecord) SameType(other Record) bool {
|
|||
func (r LineRecord) IsFlat() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r LineRecord) String() string {
|
||||
return fmt.Sprintf("l %s", r.To)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
)
|
||||
|
||||
|
@ -46,3 +47,7 @@ func (r MoveRecord) SameType(other Record) bool {
|
|||
func (r MoveRecord) IsFlat() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r MoveRecord) String() string {
|
||||
return fmt.Sprintf("m %s", r.To)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package records
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
math2 "git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"math"
|
||||
)
|
||||
|
@ -52,6 +53,10 @@ func (r QuadraticCurveRecord) IsFlat() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (r QuadraticCurveRecord) String() string {
|
||||
return fmt.Sprintf("q %s %s", r.Control, r.Anchor)
|
||||
}
|
||||
|
||||
func QuadraticCurveFromLineRecord(l LineRecord) QuadraticCurveRecord {
|
||||
delta := l.To.SubVector(l.Start)
|
||||
return QuadraticCurveRecord{
|
||||
|
|
|
@ -17,6 +17,8 @@ type Record interface {
|
|||
ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) Record
|
||||
|
||||
IsFlat() bool
|
||||
|
||||
String() string
|
||||
}
|
||||
|
||||
type CurvedRecord interface {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/binary"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/settings"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"github.com/ctessum/geom"
|
||||
"github.com/ctessum/polyclip-go"
|
||||
"github.com/nfnt/resize"
|
||||
"golang.org/x/exp/maps"
|
||||
"image"
|
||||
|
@ -155,12 +155,12 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
|
|||
var wg sync.WaitGroup
|
||||
var x atomic.Uint64
|
||||
|
||||
results := make([]map[math.PackedColor]geom.Polygonal, runtime.NumCPU())
|
||||
results := make([]map[math.PackedColor]polyclip.Polygon, runtime.NumCPU())
|
||||
for n := 0; n < runtime.NumCPU(); n++ {
|
||||
wg.Add(1)
|
||||
go func(n int) {
|
||||
defer wg.Done()
|
||||
myResults := make(map[math.PackedColor]geom.Polygonal)
|
||||
myResults := make(map[math.PackedColor]polyclip.Polygon)
|
||||
for {
|
||||
iX := x.Add(1) - 1
|
||||
if iX >= uint64(size.X) {
|
||||
|
@ -171,14 +171,14 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
|
|||
r, g, b, a := i.At(int(iX), y).RGBA()
|
||||
|
||||
p := math.NewPackedColor(uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8))
|
||||
poly := geom.Polygon{{
|
||||
poly := polyclip.Polygon{{
|
||||
{float64(iX), float64(y)},
|
||||
{float64(iX), float64(y + 1)},
|
||||
{float64(iX + 1), float64(y + 1)},
|
||||
{float64(iX + 1), float64(y)},
|
||||
}}
|
||||
if existingColor, ok := myResults[p]; ok {
|
||||
u := existingColor.Union(poly).Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
|
||||
u := existingColor.Construct(polyclip.UNION, poly).Simplify()
|
||||
myResults[p] = u
|
||||
} else {
|
||||
myResults[p] = poly
|
||||
|
@ -192,7 +192,7 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
|
|||
|
||||
var hasAlpha bool
|
||||
|
||||
colors := make(map[math.PackedColor]geom.Polygonal)
|
||||
colors := make(map[math.PackedColor]polyclip.Polygon)
|
||||
|
||||
for _, r := range results {
|
||||
for k, c := range r {
|
||||
|
@ -204,22 +204,28 @@ func ConvertBitmapToDrawPathList(i image.Image) (r DrawPathList) {
|
|||
continue
|
||||
}
|
||||
if existingColor, ok := colors[k]; ok {
|
||||
u := existingColor.Union(c).Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
|
||||
u := existingColor.Construct(polyclip.UNION, c).Simplify()
|
||||
colors[k] = u
|
||||
} else {
|
||||
colors[k] = c.Simplify(PolygonSimplifyTolerance).(geom.Polygonal)
|
||||
colors[k] = c.Simplify()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Sort from the highest area to lowest
|
||||
//Sort from the highest size to lowest
|
||||
keys := maps.Keys(colors)
|
||||
getSize := func(p polyclip.Polygon) (r int) {
|
||||
for _, c := range p {
|
||||
r += c.Len()
|
||||
}
|
||||
return r
|
||||
}
|
||||
slices.SortFunc(keys, func(a, b math.PackedColor) int {
|
||||
areaA := colors[a].Area()
|
||||
areaB := colors[b].Area()
|
||||
if areaA > areaB {
|
||||
sizeA := getSize(colors[a])
|
||||
sizeB := getSize(colors[b])
|
||||
if sizeA > sizeB {
|
||||
return -1
|
||||
} else if areaB > areaA {
|
||||
} else if sizeB > sizeA {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
|
|
|
@ -2,7 +2,7 @@ package shapes
|
|||
|
||||
import (
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"github.com/ctessum/geom"
|
||||
"github.com/ctessum/polyclip-go"
|
||||
"slices"
|
||||
)
|
||||
|
||||
|
@ -19,7 +19,7 @@ func NewClipPath(shape Shape) *ClipPath {
|
|||
}
|
||||
|
||||
func (c *ClipPath) AddShape(shape Shape) {
|
||||
c.Clip.Pol = c.Clip.Pol.Union(NewPolygonFromShape(shape))
|
||||
c.Clip = c.Clip.Merge(ComplexPolygon{Pol: NewPolygonFromShape(shape)})
|
||||
}
|
||||
|
||||
func (c *ClipPath) GetShape() Shape {
|
||||
|
@ -27,22 +27,22 @@ func (c *ClipPath) GetShape() Shape {
|
|||
}
|
||||
|
||||
func (c *ClipPath) ApplyMatrixTransform(transform math.MatrixTransform, applyTranslation bool) *ClipPath {
|
||||
pol, err := c.Clip.Pol.Transform(func(X, Y float64) (x, y float64, err error) {
|
||||
out := transform.ApplyToVector(math.NewVector2(X, Y), applyTranslation)
|
||||
return out.X, out.Y, nil
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if newPol, ok := pol.(geom.Polygonal); !ok {
|
||||
panic("invalid result")
|
||||
} else {
|
||||
return &ClipPath{
|
||||
Clip: ComplexPolygon{
|
||||
Pol: newPol,
|
||||
},
|
||||
pol := make(polyclip.Polygon, len(c.Clip.Pol))
|
||||
for i, contour := range c.Clip.Pol {
|
||||
pol[i] = make(polyclip.Contour, len(contour))
|
||||
for j, p := range contour {
|
||||
out := transform.ApplyToVector(math.NewVector2(p.X, p.Y), applyTranslation)
|
||||
pol[i][j] = polyclip.Point{
|
||||
X: out.X,
|
||||
Y: out.Y,
|
||||
}
|
||||
}
|
||||
}
|
||||
return &ClipPath{
|
||||
Clip: ComplexPolygon{
|
||||
Pol: pol,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClipPath) Merge(o *ClipPath) *ClipPath {
|
||||
|
@ -59,9 +59,9 @@ func (c *ClipPath) ClipShape(o Shape, recover bool) (r Shape) {
|
|||
}).GetShape()
|
||||
}
|
||||
flatShape, correspondence := o.FlattenWithCorrespondence()
|
||||
outShape := c.Clip.Intersect(ComplexPolygon{
|
||||
outShape := ComplexPolygon{
|
||||
Pol: NewPolygonFromShape(flatShape),
|
||||
}).GetShape()
|
||||
}.Intersect(c.Clip).GetShape()
|
||||
|
||||
for i := 0; i < len(outShape); i++ {
|
||||
var found bool
|
||||
|
|
|
@ -3,47 +3,50 @@ package shapes
|
|||
import (
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
|
||||
"github.com/ctessum/geom"
|
||||
"github.com/ctessum/polyclip-go"
|
||||
math2 "math"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type ComplexPolygon struct {
|
||||
Pol geom.Polygonal
|
||||
Pol polyclip.Polygon
|
||||
}
|
||||
|
||||
func (p ComplexPolygon) Merge(o ComplexPolygon) ComplexPolygon {
|
||||
return ComplexPolygon{
|
||||
Pol: p.Pol.Union(o.Pol),
|
||||
Pol: p.Pol.Construct(polyclip.UNION, o.Pol),
|
||||
}
|
||||
}
|
||||
|
||||
func (p ComplexPolygon) Intersect(o ComplexPolygon) ComplexPolygon {
|
||||
return ComplexPolygon{
|
||||
Pol: p.Pol.Intersection(o.Pol),
|
||||
Pol: p.Pol.Construct(polyclip.INTERSECTION, o.Pol),
|
||||
}
|
||||
}
|
||||
|
||||
const PolygonSimplifyTolerance = 0.01
|
||||
|
||||
func (p ComplexPolygon) GetShape() (r Shape) {
|
||||
for _, pol := range p.Pol.Polygons() {
|
||||
for _, path := range pol.Simplify(PolygonSimplifyTolerance).(geom.Polygon) {
|
||||
//pol = pol.Simplify(PolygonSimplifyTolerance).(geom.Polygon)
|
||||
err := fixOrientation(p.Pol)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, contour := range p.Pol {
|
||||
r = append(r, records.LineRecord{
|
||||
To: math.NewVector2(contour[1].X, contour[1].Y),
|
||||
Start: math.NewVector2(contour[0].X, contour[0].Y),
|
||||
})
|
||||
for _, point := range contour[2:] {
|
||||
r = append(r, records.LineRecord{
|
||||
To: math.NewVector2(path[1].X, path[1].Y),
|
||||
Start: math.NewVector2(path[0].X, path[0].Y),
|
||||
To: math.NewVector2(point.X, point.Y),
|
||||
Start: r[len(r)-1].GetEnd(),
|
||||
})
|
||||
for _, point := range path[2:] {
|
||||
r = append(r, records.LineRecord{
|
||||
To: math.NewVector2(point.X, point.Y),
|
||||
Start: r[len(r)-1].GetEnd(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func NewPolygonFromShape(shape Shape) (g geom.Polygon) {
|
||||
func NewPolygonFromShape(shape Shape) (g polyclip.Polygon) {
|
||||
flat := shape.Flatten()
|
||||
|
||||
var edges []records.LineRecord
|
||||
|
@ -52,7 +55,7 @@ func NewPolygonFromShape(shape Shape) (g geom.Polygon) {
|
|||
|
||||
for _, record := range flat {
|
||||
if lastEdge != nil && !lastEdge.GetEnd().Equals(record.GetStart()) {
|
||||
g = append(g, NewPathFromEdges(edges))
|
||||
g = append(g, NewContourFromEdges(edges))
|
||||
edges = edges[:0]
|
||||
}
|
||||
|
||||
|
@ -65,39 +68,188 @@ func NewPolygonFromShape(shape Shape) (g geom.Polygon) {
|
|||
}
|
||||
|
||||
if len(edges) > 0 {
|
||||
g = append(g, NewPathFromEdges(edges))
|
||||
g = append(g, NewContourFromEdges(edges))
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func NewPathFromEdges(edges []records.LineRecord) (p geom.Path) {
|
||||
p = make(geom.Path, 0, len(edges)+1)
|
||||
func NewContourFromEdges(edges []records.LineRecord) (p polyclip.Contour) {
|
||||
p = make(polyclip.Contour, 0, len(edges)+1)
|
||||
start := edges[0].Start
|
||||
to := edges[0].To
|
||||
|
||||
p = append(p, geom.Point{
|
||||
p = append(p, polyclip.Point{
|
||||
X: start.X,
|
||||
Y: start.Y,
|
||||
})
|
||||
|
||||
if !start.Equals(to) {
|
||||
p = append(p, geom.Point{
|
||||
p = append(p, polyclip.Point{
|
||||
X: to.X,
|
||||
Y: to.Y,
|
||||
})
|
||||
}
|
||||
|
||||
for _, e := range edges[1:] {
|
||||
p = append(p, geom.Point{
|
||||
p = append(p, polyclip.Point{
|
||||
X: e.To.X,
|
||||
Y: e.To.Y,
|
||||
})
|
||||
}
|
||||
|
||||
/*if p[0] == p[len(p)-1] { //closed
|
||||
p = p[:len(p)-1]
|
||||
}*/
|
||||
|
||||
if p[0] != p[len(p)-1] { //not closed
|
||||
p = append(p, p[0])
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// isLeft: test if a point is Left|On|Right of an infinite 2D line.
|
||||
//
|
||||
// Input: three points P0, P1, and P2
|
||||
// Return: >0 for P2 left of the line through P0 to P1
|
||||
// =0 for P2 on the line
|
||||
// <0 for P2 right of the line
|
||||
// From http://geomalgorithms.com/a01-_area.html#isLeft()
|
||||
func isLeft(P0, P1, P2 polyclip.Point) float64 {
|
||||
return (P1.X-P0.X)*(P2.Y-P0.Y) -
|
||||
(P2.X-P0.X)*(P1.Y-P0.Y)
|
||||
}
|
||||
|
||||
// orientation: test the orientation of a simple 2D polygon
|
||||
//
|
||||
// Input: Point* V = an array of n+1 vertex points with V[n]=V[0]
|
||||
// Return: >0 for counterclockwise
|
||||
// =0 for none (degenerate)
|
||||
// <0 for clockwise
|
||||
// Note: this algorithm is faster than computing the signed area.
|
||||
// From http://geomalgorithms.com/a01-_area.html#orientation2D_Polygon()
|
||||
func orientation(V polyclip.Polygon) []float64 {
|
||||
// first find rightmost lowest vertex of the polygon
|
||||
out := make([]float64, len(V))
|
||||
for j, r := range V {
|
||||
rmin := 0
|
||||
xmin := r[0].X
|
||||
ymin := r[0].Y
|
||||
for i, p := range r {
|
||||
if p.Y > ymin {
|
||||
continue
|
||||
} else if p.Y == ymin { // just as low
|
||||
if p.X < xmin { // and to left
|
||||
continue
|
||||
}
|
||||
}
|
||||
rmin = i // a new rightmost lowest vertex
|
||||
xmin = p.X
|
||||
ymin = p.Y
|
||||
}
|
||||
|
||||
// test orientation at the rmin vertex
|
||||
// ccw <=> the edge leaving V[rmin] is left of the entering edge
|
||||
if rmin == 0 || rmin == len(r)-1 {
|
||||
out[j] = isLeft(r[len(r)-2], r[0], r[1])
|
||||
} else {
|
||||
out[j] = isLeft(r[rmin-1], r[rmin], r[rmin+1])
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func polyInPoly(outer, inner polyclip.Contour) bool {
|
||||
for _, p := range inner {
|
||||
if pointInPoly(p, outer) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const tolerance = 1.e-9
|
||||
|
||||
func floatEquals(f1, f2 float64) bool {
|
||||
//return (f1 == f2)
|
||||
return (f1 == f2) ||
|
||||
(math2.Abs(f1-f2)/math2.Abs(f1+f2) < tolerance)
|
||||
}
|
||||
|
||||
// returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
// See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
|
||||
// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
func pointInPoly(pt polyclip.Point, path polyclip.Contour) int {
|
||||
result := 0
|
||||
cnt := len(path)
|
||||
if cnt < 3 {
|
||||
return 0
|
||||
}
|
||||
ip := path[0]
|
||||
for i := 1; i <= cnt; i++ {
|
||||
var ipNext polyclip.Point
|
||||
if i == cnt {
|
||||
ipNext = path[0]
|
||||
} else {
|
||||
ipNext = path[i]
|
||||
}
|
||||
if floatEquals(ipNext.Y, pt.Y) {
|
||||
if floatEquals(ipNext.X, pt.X) || (floatEquals(ip.Y, pt.Y) &&
|
||||
((ipNext.X-pt.X > -tolerance) == (ip.X-pt.X < tolerance))) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if (ip.Y-pt.Y < tolerance) != (ipNext.Y-pt.Y < tolerance) {
|
||||
if ip.X-pt.X >= -tolerance {
|
||||
if ipNext.X-pt.X > -tolerance {
|
||||
result = 1 - result
|
||||
} else {
|
||||
d := (ip.X-pt.X)*(ipNext.Y-pt.Y) -
|
||||
(ipNext.X-pt.X)*(ip.Y-pt.Y)
|
||||
if floatEquals(d, 0) {
|
||||
return -1
|
||||
} else if (d > -tolerance) == (ipNext.Y-ip.Y > -tolerance) {
|
||||
result = 1 - result
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ipNext.X-pt.X > -tolerance {
|
||||
d := (ip.X-pt.X)*(ipNext.Y-pt.Y) -
|
||||
(ipNext.X-pt.X)*(ip.Y-pt.Y)
|
||||
if floatEquals(d, 0) {
|
||||
return -1
|
||||
} else if (d > -tolerance) == (ipNext.Y-ip.Y > -tolerance) {
|
||||
result = 1 - result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ip = ipNext
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func fixOrientation(p polyclip.Polygon) error {
|
||||
o := orientation(p)
|
||||
for i, inner := range p {
|
||||
numInside := 0
|
||||
for j, outer := range p {
|
||||
if i != j {
|
||||
if polyInPoly(outer, inner) {
|
||||
numInside++
|
||||
}
|
||||
}
|
||||
}
|
||||
if numInside%2 == 1 && o[i] > 0. {
|
||||
slices.Reverse(inner)
|
||||
} else if numInside%2 == 0 && o[i] < 0. {
|
||||
slices.Reverse(inner)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p ComplexPolygon) Draw() Shape {
|
||||
return p.GetShape()
|
||||
}
|
||||
|
|
|
@ -79,11 +79,10 @@ func InterpolateGradient(gradient Gradient, gradientSlices int) (result []Gradie
|
|||
items := gradient.GetItems()
|
||||
//TODO: spread modes
|
||||
|
||||
first := items[0]
|
||||
last := items[len(items)-1]
|
||||
|
||||
interpolationMode := gradient.GetInterpolationMode()
|
||||
|
||||
first := items[0]
|
||||
last := items[len(items)-1]
|
||||
if first.Ratio != 0 {
|
||||
first = GradientItem{
|
||||
Ratio: 0,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package shapes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
||||
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
|
||||
)
|
||||
|
@ -109,6 +110,21 @@ func (s Shape) Equals(o Shape) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (s Shape) String() (r string) {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
var pos math.Vector2[float64]
|
||||
for _, rec := range s {
|
||||
if !rec.GetStart().Equals(pos) {
|
||||
r += fmt.Sprintf("m %s\n", rec.GetStart())
|
||||
}
|
||||
r += rec.String() + "\n"
|
||||
pos = rec.GetEnd()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func IterateMorphShape(start, end Shape) (r []records.RecordPair) {
|
||||
|
||||
var prevStart, prevEnd records.Record
|
||||
|
|
Loading…
Reference in a new issue