self intersecting polygon bugfix
This commit is contained in:
parent
421d388f91
commit
d670f964c8
2 changed files with 76 additions and 91 deletions
64
path2d.go
64
path2d.go
|
@ -41,7 +41,7 @@ func (p *Path2D) MoveTo(x, y float64) {
|
|||
if len(p.p) > 0 && isSamePoint(p.p[len(p.p)-1].pos, vec{x, y}, 0.1) {
|
||||
return
|
||||
}
|
||||
p.p = append(p.p, pathPoint{pos: vec{x, y}, flags: pathMove}) // todo more flags probably
|
||||
p.p = append(p.p, pathPoint{pos: vec{x, y}, flags: pathMove | pathIsConvex})
|
||||
p.cwSum = 0
|
||||
p.move = vec{x, y}
|
||||
}
|
||||
|
@ -66,48 +66,48 @@ func (p *Path2D) lineTo(x, y float64, checkSelfIntersection bool) {
|
|||
p.p = append(p.p, pathPoint{pos: vec{x, y}})
|
||||
newp := &p.p[count]
|
||||
|
||||
px, py := prev.pos[0], prev.pos[1]
|
||||
p.cwSum += (x - px) * (y + py)
|
||||
cwTotal := p.cwSum
|
||||
cwTotal += (p.move[0] - x) * (p.move[1] + y)
|
||||
if cwTotal <= 0 {
|
||||
newp.flags |= pathIsClockwise
|
||||
}
|
||||
|
||||
if prev.flags&pathSelfIntersects > 0 {
|
||||
newp.flags |= pathSelfIntersects
|
||||
if prev.flags&pathIsConvex > 0 {
|
||||
px, py := prev.pos[0], prev.pos[1]
|
||||
p.cwSum += (x - px) * (y + py)
|
||||
cwTotal := p.cwSum
|
||||
cwTotal += (p.move[0] - x) * (p.move[1] + y)
|
||||
if cwTotal <= 0 {
|
||||
newp.flags |= pathIsClockwise
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.p) < 4 || Performance.AssumeConvex {
|
||||
newp.flags |= pathIsConvex
|
||||
} else if prev.flags&pathIsConvex > 0 {
|
||||
prev2 := &p.p[count-2]
|
||||
cw := (prev.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
|
||||
}
|
||||
}
|
||||
|
||||
if prev.flags&pathSelfIntersects > 0 {
|
||||
newp.flags |= pathSelfIntersects
|
||||
} else if newp.flags&pathIsConvex == 0 && newp.flags&pathSelfIntersects == 0 && checkSelfIntersection && !Performance.IgnoreSelfIntersections {
|
||||
cuts := false
|
||||
var cutPoint vec
|
||||
if checkSelfIntersection && !Performance.IgnoreSelfIntersections {
|
||||
b0, b1 := prev.pos, vec{x, y}
|
||||
for i := 1; i < count; i++ {
|
||||
a0, a1 := p.p[i-1].pos, p.p[i].pos
|
||||
var r1, r2 float64
|
||||
cutPoint, r1, r2 = lineIntersection(a0, a1, b0, b1)
|
||||
if r1 > 0 && r1 < 1 && r2 > 0 && r2 < 1 {
|
||||
cuts = true
|
||||
break
|
||||
}
|
||||
b0, b1 := prev.pos, vec{x, y}
|
||||
for i := 1; i < count; i++ {
|
||||
a0, a1 := p.p[i-1].pos, p.p[i].pos
|
||||
var r1, r2 float64
|
||||
cutPoint, r1, r2 = lineIntersection(a0, a1, b0, b1)
|
||||
if r1 > 0 && r1 < 1 && r2 > 0 && r2 < 1 {
|
||||
cuts = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if cuts && !isSamePoint(cutPoint, vec{x, y}, samePointTolerance) {
|
||||
newp.flags |= pathSelfIntersects
|
||||
} else {
|
||||
prev2 := &p.p[len(p.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
103
triangulation.go
103
triangulation.go
|
@ -25,24 +25,6 @@ func pointIsRightOfLine(a, b, p vec) (bool, bool) {
|
|||
return p[0] > x, dir
|
||||
}
|
||||
|
||||
func pointIsBelowLine(a, b, p vec) (bool, bool) {
|
||||
if a[0] == b[0] {
|
||||
return false, false
|
||||
}
|
||||
dir := false
|
||||
if a[0] > b[0] {
|
||||
a, b = b, a
|
||||
dir = !dir
|
||||
}
|
||||
if p[0] < a[0] || p[0] > b[0] {
|
||||
return false, false
|
||||
}
|
||||
v := b.sub(a)
|
||||
r := (p[0] - a[0]) / v[0]
|
||||
x := a[1] + r*v[1]
|
||||
return p[1] > x, dir
|
||||
}
|
||||
|
||||
func triangleContainsPoint(a, b, c, p vec) bool {
|
||||
// if point is outside triangle bounds, return false
|
||||
if p[0] < a[0] && p[0] < b[0] && p[0] < c[0] {
|
||||
|
@ -316,61 +298,66 @@ func setPathLeftRightInside(net *tessNet) {
|
|||
a1, b1 := net.verts[e1.a], net.verts[e1.b]
|
||||
diff := b1.pos.sub(a1.pos)
|
||||
mid := a1.pos.add(diff.mulf(0.5))
|
||||
num := 0
|
||||
|
||||
if math.Abs(diff[1]) < math.Abs(diff[0]) {
|
||||
edir := diff[1] > 0
|
||||
|
||||
left, right := 0, 0
|
||||
if math.Abs(diff[1]) > math.Abs(diff[0]) {
|
||||
for j, e2 := range net.edges {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
a2, b2 := net.verts[e2.a], net.verts[e2.b]
|
||||
r, dir := pointIsRightOfLine(a2.pos, b2.pos, mid)
|
||||
if !r {
|
||||
a2, b2 := net.verts[e2.a].pos, net.verts[e2.b].pos
|
||||
if a2[1] == b2[1] {
|
||||
continue
|
||||
}
|
||||
if dir {
|
||||
num++
|
||||
} else {
|
||||
num--
|
||||
if a2[1] > b2[1] {
|
||||
a2, b2 = b2, a2
|
||||
}
|
||||
if mid[1] < a2[1] || mid[1] > b2[1] {
|
||||
continue
|
||||
}
|
||||
v := b2.sub(a2)
|
||||
r := (mid[1] - a2[1]) / v[1]
|
||||
x := a2[0] + r*v[0]
|
||||
if mid[0] > x {
|
||||
left++
|
||||
} else if mid[0] < x {
|
||||
right++
|
||||
}
|
||||
}
|
||||
|
||||
if edir {
|
||||
net.edges[i].leftInside = (num - 1) != 0
|
||||
net.edges[i].rightInside = num != 0
|
||||
} else {
|
||||
net.edges[i].leftInside = num != 0
|
||||
net.edges[i].rightInside = (num + 1) != 0
|
||||
if diff[1] > 0 {
|
||||
left, right = right, left
|
||||
}
|
||||
} else {
|
||||
edir := diff[0] > 0
|
||||
|
||||
for j, e2 := range net.edges {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
a2, b2 := net.verts[e2.a], net.verts[e2.b]
|
||||
b, dir := pointIsBelowLine(a2.pos, b2.pos, mid)
|
||||
if !b {
|
||||
a2, b2 := net.verts[e2.a].pos, net.verts[e2.b].pos
|
||||
if a2[0] == b2[0] {
|
||||
continue
|
||||
}
|
||||
if dir {
|
||||
num++
|
||||
} else {
|
||||
num--
|
||||
if a2[0] > b2[0] {
|
||||
a2, b2 = b2, a2
|
||||
}
|
||||
if mid[0] < a2[0] || mid[0] > b2[0] {
|
||||
continue
|
||||
}
|
||||
v := b2.sub(a2)
|
||||
r := (mid[0] - a2[0]) / v[0]
|
||||
y := a2[1] + r*v[1]
|
||||
if mid[1] > y {
|
||||
left++
|
||||
} else if mid[1] < y {
|
||||
right++
|
||||
}
|
||||
}
|
||||
|
||||
if edir {
|
||||
net.edges[i].leftInside = num != 0
|
||||
net.edges[i].rightInside = (num - 1) != 0
|
||||
} else {
|
||||
net.edges[i].leftInside = (num + 1) != 0
|
||||
net.edges[i].rightInside = num != 0
|
||||
if diff[0] < 0 {
|
||||
left, right = right, left
|
||||
}
|
||||
}
|
||||
|
||||
net.edges[i].leftInside = left%2 == 1
|
||||
net.edges[i].rightInside = right%2 == 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,8 +396,6 @@ func selfIntersectingPathParts(p []pathPoint, partFn func(sp []pathPoint) bool)
|
|||
break
|
||||
}
|
||||
|
||||
// fmt.Println("start", start, from, cur, net.verts[cur], left)
|
||||
|
||||
sp2 = append(sp2, pathPoint{
|
||||
pos: net.verts[cur].pos,
|
||||
flags: pathMove,
|
||||
|
@ -458,13 +443,11 @@ func selfIntersectingPathParts(p []pathPoint, partFn func(sp []pathPoint) bool)
|
|||
next = e.a
|
||||
}
|
||||
any = true
|
||||
// fmt.Println("-", e, nextEdge, next)
|
||||
}
|
||||
}
|
||||
if !any {
|
||||
break
|
||||
}
|
||||
// fmt.Println(start, from, cur, net.verts[cur], nextEdge, next, net.verts[next])
|
||||
if left {
|
||||
net.edges[nextEdge].leftInside = false
|
||||
} else {
|
||||
|
@ -480,9 +463,11 @@ func selfIntersectingPathParts(p []pathPoint, partFn func(sp []pathPoint) bool)
|
|||
}
|
||||
}
|
||||
|
||||
stop := partFn(sp2)
|
||||
if stop {
|
||||
return true
|
||||
if len(sp2) >= 3 {
|
||||
stop := partFn(sp2)
|
||||
if stop {
|
||||
return true
|
||||
}
|
||||
}
|
||||
sp2 = sp2[:0]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue