Skip to content

Commit

Permalink
self intersecting polygon bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
tfriedel6 committed Mar 17, 2020
1 parent 421d388 commit d670f96
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 91 deletions.
64 changes: 32 additions & 32 deletions path2d.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand All @@ -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
}
}
}
}
Expand Down
103 changes: 44 additions & 59 deletions triangulation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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]
}
Expand Down

0 comments on commit d670f96

Please sign in to comment.