-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcut_mesh.go
123 lines (107 loc) · 3.16 KB
/
cut_mesh.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package helpers
import (
. "github.com/l1va/goosli/primitives"
// "fmt"
"log"
)
//CutMesh mesh in two meshes, first that inFront of plane, second - outFront
func CutMesh(mesh *Mesh, p Plane) (*Mesh, *Mesh, error) {
if mesh == nil || len(mesh.Triangles) == 0 {
return &Mesh{}, &Mesh{}, nil //fmt.Errorf("mesh is empty, nothing to cut")
}
var up []Triangle
var down []Triangle
inters := []Path{}
for _, t := range mesh.Triangles { //TODO: make it more beautiful
var inFront []Point
var outFront []Point
if p.PointInFront(t.P1) {
inFront = append(inFront, t.P1)
} else {
outFront = append(outFront, t.P1)
}
if p.PointInFront(t.P2) {
inFront = append(inFront, t.P2)
} else {
outFront = append(outFront, t.P2)
}
if p.PointInFront(t.P3) {
inFront = append(inFront, t.P3)
} else {
outFront = append(outFront, t.P3)
}
if len(inFront) == 3 {
up = append(up, t)
} else if len(inFront) == 2 {
line := p.IntersectTriangle(&t)
if line == nil {
log.Printf("failed to intersect triangle by plane2, skip it: %v, %v\n", t, p)
continue
}
inters = append(inters, Path{Points: []Point{line.P1, line.P2}})
ts := splitOnThree(outFront[0], *line, t)
up = append(up, ts[1])
up = append(up, ts[2])
down = append(down, ts[0])
} else if len(inFront) == 1 {
line := p.IntersectTriangle(&t)
if line == nil {
log.Printf("failed to intersect triangle by plane1, skip it: %v, %v\n", t, p)
continue
}
inters = append(inters, Path{Points: []Point{line.P1, line.P2}})
ts := splitOnThree(inFront[0], *line, t)
up = append(up, ts[0])
down = append(down, ts[1])
down = append(down, ts[2])
} else {
down = append(down, t)
}
}
//if len(up) == 0 || len(down) == 0 {
// return nil, nil, fmt.Errorf("one of meshes is empty")
//}
joined := JoinPaths3AndMinimize(inters)
println("cut mesh, init and joined", len(inters), len(joined))
//debug.RecreateFile()
for _, pth := range joined { //generate addition triangles to close the cut
//debug.AddPath(pth, debug.GreenColor)
for j := 1; j < len(pth.Points)-1; j++ {
t := NewTriangle(pth.Points[0], pth.Points[j], pth.Points[j+1])
t2 := NewTriangle(pth.Points[j+1], pth.Points[j], pth.Points[0]) //with reverse normal
if t.N.CodirectedWith(p.N) { //triangle normal should go inside the mesh
up = append(up, t2)
down = append(down, t)
} else {
up = append(up, t)
down = append(down, t2)
}
}
}
resUp := NewMesh(up)
resDown := NewMesh(down)
return &resUp, &resDown, nil
}
// p1 - point that from triangle 1
// ans consist of 3 triangle: 1 leaves as triangle, 2 and 3 - triangles from quadrangle
func splitOnThree(p1 Point, line Line, t Triangle) []Triangle {
var ans []Triangle
lp1 := line.P1
lp2 := line.P2
t1 := t.P1
t2 := t.P2
t3 := t.P3
if t2.Equal(p1) {
t1, t2, t3 = t2, t3, t1
} else if t3.Equal(p1) {
t1, t2, t3 = t3, t1, t2
}
if AlmostZero(t1.VectorTo(t2).Cross(t1.VectorTo(lp2)).Length()) {
// lp2 lies on t1->t2 vector, but should lp1 lie
lp1, lp2 = lp2, lp1
}
ans = append(ans, NewTriangle(t1, lp1, lp2))
ans = append(ans, NewTriangle(lp1, t2, t3))
ans = append(ans, NewTriangle(t3, lp2, lp1))
return ans
}