-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
laplacian_smoothing.go
119 lines (93 loc) · 2.95 KB
/
laplacian_smoothing.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
package meshops
import (
"fmt"
"github.com/EliCDavis/polyform/modeling"
"github.com/EliCDavis/polyform/nodes"
"github.com/EliCDavis/vector/vector3"
)
type LaplacianSmoothTransformer struct {
Attribute string
Iterations int
SmoothingFactor float64
}
func (lst LaplacianSmoothTransformer) attribute() string {
return lst.Attribute
}
func (lst LaplacianSmoothTransformer) Transform(m modeling.Mesh) (results modeling.Mesh, err error) {
attribute := getAttribute(lst, modeling.PositionAttribute)
if err = RequireV3Attribute(m, attribute); err != nil {
return
}
return LaplacianSmooth(m, attribute, lst.Iterations, lst.SmoothingFactor), nil
}
func LaplacianSmooth(m modeling.Mesh, attribute string, iterations int, smoothingFactor float64) modeling.Mesh {
if !m.HasFloat3Attribute(attribute) {
panic(fmt.Errorf("attempting to apply laplacian smoothing to a mesh without the attribute: %s", attribute))
}
lut := m.VertexNeighborTable()
oldVertices := m.Float3Attribute(attribute)
vertices := make([]vector3.Float64, oldVertices.Len())
for i := range vertices {
vertices[i] = oldVertices.At(i)
}
for i := 0; i < iterations; i++ {
for vi, vertex := range vertices {
var sum vector3.Float64
for vn := range lut.Lookup(vi) {
sum = sum.Add(vertices[vn])
}
vertices[vi] = vertex.Add(
sum.
DivByConstant(float64(lut.Count(vi))).
Sub(vertex).
Scale(smoothingFactor))
}
}
return m.SetFloat3Attribute(attribute, vertices)
}
func LaplacianSmoothAlongAxis(m modeling.Mesh, attribute string, iterations int, smoothingFactor float64, axis vector3.Float64) modeling.Mesh {
if !m.HasFloat3Attribute(attribute) {
panic(fmt.Errorf("attempting to apply laplacian smoothing to a mesh without the attribute: %s", attribute))
}
cleanedAxis := axis.Normalized().Abs()
lut := m.VertexNeighborTable()
oldVertices := m.Float3Attribute(attribute)
vertices := make([]vector3.Float64, oldVertices.Len())
for i := range vertices {
vertices[i] = oldVertices.At(i)
}
for i := 0; i < iterations; i++ {
for vi, vertex := range vertices {
var sum vector3.Float64
for vn := range lut.Lookup(vi) {
sum = sum.Add(vertices[vn])
}
vertices[vi] = vertex.Add(
sum.
DivByConstant(float64(lut.Count(vi))).
Sub(vertex).
Scale(smoothingFactor).
MultByVector(cleanedAxis))
}
}
return m.SetFloat3Attribute(attribute, vertices)
}
type LaplacianSmoothNode = nodes.StructNode[modeling.Mesh, LaplacianSmoothNodeData]
type LaplacianSmoothNodeData struct {
Mesh nodes.NodeOutput[modeling.Mesh]
Attribute nodes.NodeOutput[string]
Iterations nodes.NodeOutput[int]
SmoothingFactor nodes.NodeOutput[float64]
}
func (lp LaplacianSmoothNodeData) Process() (modeling.Mesh, error) {
atrr := modeling.PositionAttribute
if lp.Attribute != nil {
atrr = lp.Attribute.Value()
}
return LaplacianSmooth(
lp.Mesh.Value(),
atrr,
lp.Iterations.Value(),
lp.SmoothingFactor.Value(),
), nil
}