Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/manifold/src/shared.h
9903 views
1
// Copyright 2021 The Manifold Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#pragma once
16
17
#include "parallel.h"
18
#include "utils.h"
19
#include "vec.h"
20
21
namespace manifold {
22
23
inline vec3 SafeNormalize(vec3 v) {
24
v = la::normalize(v);
25
return std::isfinite(v.x) ? v : vec3(0.0);
26
}
27
28
inline double MaxEpsilon(double minEpsilon, const Box& bBox) {
29
double epsilon = std::max(minEpsilon, kPrecision * bBox.Scale());
30
return std::isfinite(epsilon) ? epsilon : -1;
31
}
32
33
inline int NextHalfedge(int current) {
34
++current;
35
if (current % 3 == 0) current -= 3;
36
return current;
37
}
38
39
inline mat3 NormalTransform(const mat3x4& transform) {
40
return la::inverse(la::transpose(mat3(transform)));
41
}
42
43
/**
44
* By using the closest axis-aligned projection to the normal instead of a
45
* projection along the normal, we avoid introducing any rounding error.
46
*/
47
inline mat2x3 GetAxisAlignedProjection(vec3 normal) {
48
vec3 absNormal = la::abs(normal);
49
double xyzMax;
50
mat3x2 projection;
51
if (absNormal.z > absNormal.x && absNormal.z > absNormal.y) {
52
projection = mat3x2({1.0, 0.0, 0.0}, //
53
{0.0, 1.0, 0.0});
54
xyzMax = normal.z;
55
} else if (absNormal.y > absNormal.x) {
56
projection = mat3x2({0.0, 0.0, 1.0}, //
57
{1.0, 0.0, 0.0});
58
xyzMax = normal.y;
59
} else {
60
projection = mat3x2({0.0, 1.0, 0.0}, //
61
{0.0, 0.0, 1.0});
62
xyzMax = normal.x;
63
}
64
if (xyzMax < 0) projection[0] *= -1.0;
65
return la::transpose(projection);
66
}
67
68
inline vec3 GetBarycentric(const vec3& v, const mat3& triPos,
69
double tolerance) {
70
const mat3 edges(triPos[2] - triPos[1], triPos[0] - triPos[2],
71
triPos[1] - triPos[0]);
72
const vec3 d2(la::dot(edges[0], edges[0]), la::dot(edges[1], edges[1]),
73
la::dot(edges[2], edges[2]));
74
const int longSide = d2[0] > d2[1] && d2[0] > d2[2] ? 0
75
: d2[1] > d2[2] ? 1
76
: 2;
77
const vec3 crossP = la::cross(edges[0], edges[1]);
78
const double area2 = la::dot(crossP, crossP);
79
const double tol2 = tolerance * tolerance;
80
81
vec3 uvw(0.0);
82
for (const int i : {0, 1, 2}) {
83
const vec3 dv = v - triPos[i];
84
if (la::dot(dv, dv) < tol2) {
85
// Return exactly equal if within tolerance of vert.
86
uvw[i] = 1;
87
return uvw;
88
}
89
}
90
91
if (d2[longSide] < tol2) { // point
92
return vec3(1, 0, 0);
93
} else if (area2 > d2[longSide] * tol2) { // triangle
94
for (const int i : {0, 1, 2}) {
95
const int j = Next3(i);
96
const vec3 crossPv = la::cross(edges[i], v - triPos[j]);
97
const double area2v = la::dot(crossPv, crossPv);
98
// Return exactly equal if within tolerance of edge.
99
uvw[i] = area2v < d2[i] * tol2 ? 0 : la::dot(crossPv, crossP);
100
}
101
uvw /= (uvw[0] + uvw[1] + uvw[2]);
102
return uvw;
103
} else { // line
104
const int nextV = Next3(longSide);
105
const double alpha =
106
la::dot(v - triPos[nextV], edges[longSide]) / d2[longSide];
107
uvw[longSide] = 0;
108
uvw[nextV] = 1 - alpha;
109
const int lastV = Next3(nextV);
110
uvw[lastV] = alpha;
111
return uvw;
112
}
113
}
114
115
/**
116
* The fundamental component of the halfedge data structure used for storing and
117
* operating on the Manifold.
118
*/
119
struct Halfedge {
120
int startVert, endVert;
121
int pairedHalfedge;
122
int propVert;
123
bool IsForward() const { return startVert < endVert; }
124
bool operator<(const Halfedge& other) const {
125
return startVert == other.startVert ? endVert < other.endVert
126
: startVert < other.startVert;
127
}
128
};
129
130
struct Barycentric {
131
int tri;
132
vec4 uvw;
133
};
134
135
struct TriRef {
136
/// The unique ID of the mesh instance of this triangle. If .meshID and .tri
137
/// match for two triangles, then they are coplanar and came from the same
138
/// face.
139
int meshID;
140
/// The OriginalID of the mesh this triangle came from. This ID is ideal for
141
/// reapplying properties like UV coordinates to the output mesh.
142
int originalID;
143
/// Probably the triangle index of the original triangle this was part of:
144
/// Mesh.triVerts[tri], but it's an input, so just pass it along unchanged.
145
int faceID;
146
/// Triangles with the same coplanar ID are coplanar.
147
int coplanarID;
148
149
bool SameFace(const TriRef& other) const {
150
return meshID == other.meshID && coplanarID == other.coplanarID &&
151
faceID == other.faceID;
152
}
153
};
154
155
/**
156
* This is a temporary edge structure which only stores edges forward and
157
* references the halfedge it was created from.
158
*/
159
struct TmpEdge {
160
int first, second, halfedgeIdx;
161
162
TmpEdge() {}
163
TmpEdge(int start, int end, int idx) {
164
first = std::min(start, end);
165
second = std::max(start, end);
166
halfedgeIdx = idx;
167
}
168
169
bool operator<(const TmpEdge& other) const {
170
return first == other.first ? second < other.second : first < other.first;
171
}
172
};
173
174
Vec<TmpEdge> inline CreateTmpEdges(const Vec<Halfedge>& halfedge) {
175
Vec<TmpEdge> edges(halfedge.size());
176
for_each_n(autoPolicy(edges.size()), countAt(0), edges.size(),
177
[&edges, &halfedge](const int idx) {
178
const Halfedge& half = halfedge[idx];
179
edges[idx] = TmpEdge(half.startVert, half.endVert,
180
half.IsForward() ? idx : -1);
181
});
182
183
size_t numEdge =
184
remove_if(edges.begin(), edges.end(),
185
[](const TmpEdge& edge) { return edge.halfedgeIdx < 0; }) -
186
edges.begin();
187
DEBUG_ASSERT(numEdge == halfedge.size() / 2, topologyErr, "Not oriented!");
188
edges.resize(numEdge);
189
return edges;
190
}
191
192
#ifdef MANIFOLD_DEBUG
193
inline std::ostream& operator<<(std::ostream& stream, const Halfedge& edge) {
194
return stream << "startVert = " << edge.startVert
195
<< ", endVert = " << edge.endVert
196
<< ", pairedHalfedge = " << edge.pairedHalfedge
197
<< ", propVert = " << edge.propVert;
198
}
199
200
inline std::ostream& operator<<(std::ostream& stream, const Barycentric& bary) {
201
return stream << "tri = " << bary.tri << ", uvw = " << bary.uvw;
202
}
203
204
inline std::ostream& operator<<(std::ostream& stream, const TriRef& ref) {
205
return stream << "meshID: " << ref.meshID
206
<< ", originalID: " << ref.originalID
207
<< ", faceID: " << ref.faceID
208
<< ", coplanarID: " << ref.coplanarID;
209
}
210
#endif
211
} // namespace manifold
212
213