123 lines
2.5 KiB
Go
123 lines
2.5 KiB
Go
package shapes
|
|
|
|
import (
|
|
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/math"
|
|
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/types/records"
|
|
"slices"
|
|
)
|
|
|
|
type PathSegment[T ~float64 | ~int64] []VisitedPoint[T]
|
|
|
|
func NewPathSegment[T ~float64 | ~int64](start math.Vector2[T]) PathSegment[T] {
|
|
return PathSegment[T]{
|
|
VisitedPoint[T]{
|
|
Pos: start,
|
|
IsBezierControl: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Flip
|
|
// Flips the direction of the path segment.
|
|
// Flash fill paths are dual-sided, with fill style 1 indicating the positive side
|
|
// and fill style 0 indicating the negative. We have to flip fill style 0 paths
|
|
// in order to link them to fill style 1 paths.
|
|
func (s *PathSegment[T]) Flip() {
|
|
slices.Reverse(*s)
|
|
}
|
|
|
|
func (s *PathSegment[T]) AddPoint(p VisitedPoint[T]) {
|
|
*s = append(*s, p)
|
|
}
|
|
|
|
func (s *PathSegment[T]) Start() math.Vector2[T] {
|
|
return (*s)[0].Pos
|
|
}
|
|
|
|
func (s *PathSegment[T]) End() math.Vector2[T] {
|
|
return (*s)[len(*s)-1].Pos
|
|
}
|
|
|
|
func (s *PathSegment[T]) IsEmpty() bool {
|
|
return len(*s) <= 1
|
|
}
|
|
|
|
func (s *PathSegment[T]) IsClosed() bool {
|
|
return s.Start().Equals(s.End())
|
|
}
|
|
|
|
func (s *PathSegment[T]) Swap(o *PathSegment[T]) {
|
|
*s, *o = *o, *s
|
|
}
|
|
|
|
func (s *PathSegment[T]) Merge(o PathSegment[T]) {
|
|
*s = append(*s, o[1:]...)
|
|
}
|
|
|
|
func (s *PathSegment[T]) TryMerge(o *PathSegment[T], isDirected bool) bool {
|
|
if o.End().Equals(s.Start()) {
|
|
s.Swap(o)
|
|
s.Merge(*o)
|
|
return true
|
|
} else if s.End().Equals(o.Start()) {
|
|
s.Merge(*o)
|
|
return true
|
|
} else if !isDirected && s.End().Equals(o.End()) {
|
|
o.Flip()
|
|
s.Merge(*o)
|
|
return true
|
|
} else if !isDirected && s.Start().Equals(o.Start()) {
|
|
o.Flip()
|
|
s.Swap(o)
|
|
s.Merge(*o)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (s *PathSegment[T]) GetShape() (shape Shape) {
|
|
if s.IsEmpty() {
|
|
panic("not possible")
|
|
}
|
|
|
|
shape = make(Shape, 0, len(*s)-1)
|
|
|
|
points := *s
|
|
|
|
next := func() VisitedPoint[T] {
|
|
point := points[0]
|
|
points = points[1:]
|
|
return point
|
|
}
|
|
|
|
lastPos := next().Pos.Float64()
|
|
//lastPos := points[0].Pos.Float64()
|
|
|
|
for len(points) > 0 {
|
|
point := next()
|
|
|
|
if !point.IsBezierControl {
|
|
shape = append(shape, records.LineRecord{
|
|
To: point.Pos.Float64(),
|
|
Start: lastPos,
|
|
})
|
|
lastPos = point.Pos.Float64()
|
|
} else {
|
|
if len(points) == 0 {
|
|
panic("Bezier without endpoint")
|
|
}
|
|
end := next()
|
|
|
|
shape = append(shape, records.QuadraticCurveRecord{
|
|
Control: point.Pos.Float64(),
|
|
Anchor: end.Pos.Float64(),
|
|
Start: lastPos,
|
|
})
|
|
lastPos = end.Pos.Float64()
|
|
}
|
|
}
|
|
|
|
return shape
|
|
}
|