Skip to content

Commit

Permalink
Fix path intersection code with point-closes, fixes #277
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Feb 23, 2024
1 parent 30365e1 commit 9e2641d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 24 deletions.
42 changes: 22 additions & 20 deletions path_intersection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,26 +808,28 @@ func TestIntersections(t *testing.T) {
Epsilon = origEpsilon
}

//func TestSelfIntersections(t *testing.T) {
// var tts = []struct {
// p string
// zs Intersections
// }{
// {"L10 10L10 0L0 10z", Intersections{
// {Point{5.0, 5.0}, 1, 3, 0.5, 0.5, 0.25 * math.Pi, 0.75 * math.Pi, BintoA, NoParallel, false},
// }},
// }
// for _, tt := range tts {
// t.Run(fmt.Sprint(tt.p), func(t *testing.T) {
// p := MustParseSVGPath(tt.p)
// zs := p.SelfIntersections()
// test.T(t, len(zs), len(tt.zs))
// for i := range zs {
// test.T(t, zs[i], tt.zs[i])
// }
// })
// }
//}
func TestSelfIntersections(t *testing.T) {
var tts = []struct {
p string
zs []PathIntersection
}{
//{"L10 10L10 0L0 10z", Intersections{ {Point{5.0, 5.0}, 1, 3, 0.5, 0.5, 0.25 * math.Pi, 0.75 * math.Pi, BintoA, NoParallel, false},
//}},

/// bugs
{"M3.512162397982181 1.239754268684486L3.3827323986701674 1.1467946944092953L3.522449858001167 1.2493787337129587A0.21166666666666667 0.21166666666666667 0 0 1 3.5121623979821806 1.2397542686844856z", []PathIntersection{}},
}
for _, tt := range tts {
t.Run(fmt.Sprint(tt.p), func(t *testing.T) {
p := MustParseSVGPath(tt.p)
zs, _ := pathIntersections(p, nil, true, true)
test.T(t, len(zs), len(tt.zs))
for i := range zs {
test.T(t, zs[i], tt.zs[i])
}
})
}
}

func TestPathCut(t *testing.T) {
var tts = []struct {
Expand Down
29 changes: 25 additions & 4 deletions path_intersection_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,13 @@ func intersectionPath(p, q *Path) (Intersections, []int, []int) {
segP, segQ := 1, 1
for i := 4; i < len(p.d); {
pn := cmdLen(p.d[i])
if self && p.d[i] == CubeToCmd {
p0 := Point{p.d[i-3], p.d[i-2]}
if p.d[i] == CloseCmd && p0.Equals(Point{p.d[i+1], p.d[i+2]}) {
// point-closed
i += pn
segP++
continue
} else if self && p.d[i] == CubeToCmd {
// TODO: find intersections in Cube after we support non-flat paths
}

Expand All @@ -808,14 +814,29 @@ func intersectionPath(p, q *Path) (Intersections, []int, []int) {
}
for j < len(q.d) {
qn := cmdLen(q.d[j])
p0, q0 := Point{p.d[i-3], p.d[i-2]}, Point{q.d[j-3], q.d[j-2]}
q0 := Point{q.d[j-3], q.d[j-2]}
if q.d[j] == CloseCmd && q0.Equals(Point{q.d[j+1], q.d[j+2]}) {
// point-closed
j += qn
segQ++
continue
}

k := len(zs)
zs = intersectionSegment(zs, p0, p.d[i:i+pn], q0, q.d[j:j+qn])
if self && (i+pn == j || i == 4 && q.d[j] == CloseCmd) {
if self && (i+pn == j || i == 4) {
// remove tangent intersections for adjacent segments on the same subpath
for k1 := len(zs) - 1; k <= k1; k1-- {
if zs[k1].Tangent && (i+pn == j && Equal(zs[k1].T[0], 1.0) && Equal(zs[k1].T[1], 0.0) || i == 4 && q.d[j] == CloseCmd && Equal(zs[k1].T[0], 0.0) && Equal(zs[k1].T[1], 1.0)) {
if !zs[k1].Tangent {
continue
}

// segments are joined if either j comes after i, or if i is first and j is last (or before last if last is point-closed)
joined := i+pn == j && Equal(zs[k1].T[0], 1.0) && Equal(zs[k1].T[1], 0.0) ||
i == 4 && Equal(zs[k1].T[0], 0.0) && Equal(zs[k1].T[1], 1.0) &&
(q.d[j] == CloseCmd || j+qn < len(q.d) && q.d[j+qn] == CloseCmd &&
Point{q.d[j+qn-3], q.d[j+qn-2]}.Equals(Point{q.d[j+qn+1], q.d[j+qn+2]}))
if joined {
zs = append(zs[:k1], zs[k1+1:]...)
}
}
Expand Down

0 comments on commit 9e2641d

Please sign in to comment.