added flags to track if the path is convex
This commit is contained in:
parent
cb3e694671
commit
deaa8f87b6
3 changed files with 87 additions and 6 deletions
|
@ -402,3 +402,57 @@ func TestText(t *testing.T) {
|
||||||
cv.StrokeText("D EF", 0, 90)
|
cv.StrokeText("D EF", 0, 90)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvex(t *testing.T) {
|
||||||
|
run(t, func(cv *canvas.Canvas) {
|
||||||
|
cv.SetFillStyle("#F00")
|
||||||
|
cv.BeginPath()
|
||||||
|
cv.MoveTo(10, 10)
|
||||||
|
cv.LineTo(20, 10)
|
||||||
|
cv.LineTo(20, 20)
|
||||||
|
cv.LineTo(10, 20)
|
||||||
|
cv.LineTo(10, 10)
|
||||||
|
cv.ClosePath()
|
||||||
|
cv.Fill()
|
||||||
|
|
||||||
|
cv.SetFillStyle("#0F0")
|
||||||
|
cv.BeginPath()
|
||||||
|
cv.MoveTo(30, 10)
|
||||||
|
cv.LineTo(40, 10)
|
||||||
|
cv.LineTo(40, 15)
|
||||||
|
cv.LineTo(35, 15)
|
||||||
|
cv.LineTo(35, 20)
|
||||||
|
cv.LineTo(40, 20)
|
||||||
|
cv.LineTo(40, 25)
|
||||||
|
cv.LineTo(30, 25)
|
||||||
|
cv.ClosePath()
|
||||||
|
cv.Fill()
|
||||||
|
|
||||||
|
cv.SetFillStyle("#00F")
|
||||||
|
cv.BeginPath()
|
||||||
|
cv.MoveTo(50, 10)
|
||||||
|
cv.LineTo(50, 25)
|
||||||
|
cv.LineTo(60, 25)
|
||||||
|
cv.LineTo(60, 20)
|
||||||
|
cv.LineTo(55, 20)
|
||||||
|
cv.LineTo(55, 15)
|
||||||
|
cv.LineTo(60, 15)
|
||||||
|
cv.LineTo(60, 10)
|
||||||
|
cv.ClosePath()
|
||||||
|
cv.Fill()
|
||||||
|
|
||||||
|
cv.SetFillStyle("#FFF")
|
||||||
|
cv.BeginPath()
|
||||||
|
cv.MoveTo(20, 35)
|
||||||
|
cv.LineTo(80, 35)
|
||||||
|
cv.ArcTo(90, 35, 90, 45, 10)
|
||||||
|
cv.LineTo(90, 80)
|
||||||
|
cv.ArcTo(90, 90, 80, 90, 10)
|
||||||
|
cv.LineTo(20, 90)
|
||||||
|
cv.ArcTo(10, 90, 10, 80, 10)
|
||||||
|
cv.LineTo(10, 45)
|
||||||
|
cv.ArcTo(10, 35, 20, 35, 10)
|
||||||
|
cv.ClosePath()
|
||||||
|
cv.Fill()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
39
paths.go
39
paths.go
|
@ -6,7 +6,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type path struct {
|
type path struct {
|
||||||
p []pathPoint
|
p []pathPoint
|
||||||
|
move vec
|
||||||
|
cwSum float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type pathPoint struct {
|
type pathPoint struct {
|
||||||
|
@ -23,6 +25,7 @@ const (
|
||||||
pathAttach
|
pathAttach
|
||||||
pathIsRect
|
pathIsRect
|
||||||
pathIsConvex
|
pathIsConvex
|
||||||
|
pathIsClockwise
|
||||||
)
|
)
|
||||||
|
|
||||||
// BeginPath clears the current path and starts a new one
|
// BeginPath clears the current path and starts a new one
|
||||||
|
@ -44,13 +47,12 @@ func (cv *Canvas) MoveTo(x, y float64) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: tf, flags: pathMove})
|
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: tf, flags: pathMove})
|
||||||
|
cv.path.cwSum = 0
|
||||||
|
cv.path.move = vec{x, y}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LineTo adds a line to the end of the path
|
// LineTo adds a line to the end of the path
|
||||||
func (cv *Canvas) LineTo(x, y float64) {
|
func (cv *Canvas) LineTo(x, y float64) {
|
||||||
// cv.strokeLineTo(x, y)
|
|
||||||
// cv.fillLineTo(x, y)
|
|
||||||
|
|
||||||
if len(cv.path.p) > 0 && isSamePoint(cv.path.p[len(cv.path.p)-1].tf, cv.tf(vec{x, y}), 0.1) {
|
if len(cv.path.p) > 0 && isSamePoint(cv.path.p[len(cv.path.p)-1].tf, cv.tf(vec{x, y}), 0.1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -58,10 +60,35 @@ func (cv *Canvas) LineTo(x, y float64) {
|
||||||
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: cv.tf(vec{x, y}), flags: pathMove})
|
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: cv.tf(vec{x, y}), flags: pathMove})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
prev := &cv.path.p[len(cv.path.p)-1]
|
||||||
tf := cv.tf(vec{x, y})
|
tf := cv.tf(vec{x, y})
|
||||||
cv.path.p[len(cv.path.p)-1].next = tf
|
prev.next = tf
|
||||||
cv.path.p[len(cv.path.p)-1].flags |= pathAttach
|
prev.flags |= pathAttach
|
||||||
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: tf})
|
cv.path.p = append(cv.path.p, pathPoint{pos: vec{x, y}, tf: tf})
|
||||||
|
newp := &cv.path.p[len(cv.path.p)-1]
|
||||||
|
|
||||||
|
px, py := prev.pos[0], prev.pos[1]
|
||||||
|
cv.path.cwSum += (x - px) * (y + py)
|
||||||
|
cwTotal := cv.path.cwSum
|
||||||
|
cwTotal += (cv.path.move[0] - x) * (cv.path.move[1] + y)
|
||||||
|
if cwTotal <= 0 {
|
||||||
|
newp.flags |= pathIsClockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cv.path.p) < 4 {
|
||||||
|
newp.flags |= pathIsConvex
|
||||||
|
} else if prev.flags&pathIsConvex > 0 {
|
||||||
|
prev2 := &cv.path.p[len(cv.path.p)-3]
|
||||||
|
cw := (newp.flags & pathIsClockwise) > 0
|
||||||
|
|
||||||
|
ln := prev.pos.sub(prev2.pos)
|
||||||
|
lo := vec{ln[1], -ln[0]}
|
||||||
|
dot := newp.pos.sub(prev2.pos).dot(lo)
|
||||||
|
|
||||||
|
if (cw && dot <= 0) || (!cw && dot >= 0) {
|
||||||
|
newp.flags |= pathIsConvex
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arc adds a circle segment to the end of the path. x/y is the center, radius
|
// Arc adds a circle segment to the end of the path. x/y is the center, radius
|
||||||
|
|
BIN
testdata/Convex.png
vendored
Executable file
BIN
testdata/Convex.png
vendored
Executable file
Binary file not shown.
After Width: | Height: | Size: 408 B |
Loading…
Reference in a new issue