-
Notifications
You must be signed in to change notification settings - Fork 47
/
FixedWinding.cpp
194 lines (166 loc) · 5.8 KB
/
FixedWinding.cpp
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "FixedWinding.h"
#include "Brush.h"
#include "Winding.h"
#include "itextstream.h"
namespace {
inline bool float_is_largest_absolute(double axis, double other) {
return fabs(axis) > fabs(other);
}
/// \brief Returns the index of the component of \p v that has the largest absolute value.
inline int vector3_largest_absolute_component_index(const Vector3& v) {
return (float_is_largest_absolute(v[1], v[0]))
? (float_is_largest_absolute(v[1], v[2]))
? 1
: 2
: (float_is_largest_absolute(v[0], v[2]))
? 0
: 2;
}
/// \brief Returns the infinite line that is the intersection of \p plane and \p other.
inline DoubleLine plane3_intersect_plane3(const Plane3& plane, const Plane3& other) {
DoubleLine line;
line.direction = plane.normal().crossProduct(other.normal());
switch (vector3_largest_absolute_component_index(line.direction)) {
case 0:
line.origin.x() = 0;
line.origin.y() = (-other.dist() * plane.normal().z() - -plane.dist() * other.normal().z()) / line.direction.x();
line.origin.z() = (-plane.dist() * other.normal().y() - -other.dist() * plane.normal().y()) / line.direction.x();
break;
case 1:
line.origin.x() = (-plane.dist() * other.normal().z() - -other.dist() * plane.normal().z()) / line.direction.y();
line.origin.y() = 0;
line.origin.z() = (-other.dist() * plane.normal().x() - -plane.dist() * other.normal().x()) / line.direction.y();
break;
case 2:
line.origin.x() = (-other.dist() * plane.normal().y() - -plane.dist() * other.normal().y()) / line.direction.z();
line.origin.y() = (-plane.dist() * other.normal().x() - -other.dist() * plane.normal().x()) / line.direction.z();
line.origin.z() = 0;
break;
default:
break;
}
return line;
}
}
void FixedWinding::writeToWinding(Winding& winding)
{
// First, set the target winding to the same size as <self>
winding.resize(size());
// Now copy stuff from this to the target winding
for (std::size_t i = 0; i < size(); ++i)
{
winding[i].vertex[0] = (*this)[i].vertex[0];
winding[i].vertex[1] = (*this)[i].vertex[1];
winding[i].vertex[2] = (*this)[i].vertex[2];
winding[i].adjacent = (*this)[i].adjacent;
}
}
void FixedWinding::createInfinite(const Plane3& plane, double infinity) {
double max = -infinity;
int x = -1;
for (int i = 0; i < 3; i++) {
double d = fabs(plane.normal()[i]);
if (d > max) {
x = i;
max = d;
}
}
if (x == -1) {
rError() << "invalid plane\n";
return;
}
Vector3 vup = g_vector3_identity;
switch (x) {
case 0:
case 1:
vup[2] = 1;
break;
case 2:
vup[0] = 1;
break;
}
vup += plane.normal() * (-vup.dot(plane.normal()));
vup.normalise();
Vector3 org = plane.normal() * plane.dist();
Vector3 vright = vup.crossProduct(plane.normal());
vup *= infinity;
vright *= infinity;
// project a really big axis aligned box onto the plane
DoubleLine r1, r2, r3, r4;
r1.origin = (org - vright) + vup;
r1.direction = vright.getNormalised();
push_back(FixedWindingVertex(r1.origin, r1, c_brush_maxFaces));
r2.origin = org + vright + vup;
r2.direction = (-vup).getNormalised();
push_back(FixedWindingVertex(r2.origin, r2, c_brush_maxFaces));
r3.origin = (org + vright) - vup;
r3.direction = (-vright).getNormalised();
push_back(FixedWindingVertex(r3.origin, r3, c_brush_maxFaces));
r4.origin = (org - vright) - vup;
r4.direction = vup.getNormalised();
push_back(FixedWindingVertex(r4.origin, r4, c_brush_maxFaces));
}
/// \brief Clip \p winding which lies on \p plane by \p clipPlane, resulting in \p clipped.
/// If \p winding is completely in front of the plane, \p clipped will be identical to \p winding.
/// If \p winding is completely in back of the plane, \p clipped will be empty.
/// If \p winding intersects the plane, the edge of \p clipped which lies on \p clipPlane will store the value of \p adjacent.
void FixedWinding::clip(const Plane3& plane, const Plane3& clipPlane, std::size_t adjacent, FixedWinding& clipped)
{
if (size() == 0) {
return; // Degenerate winding, exit
}
PlaneClassification classification = Winding::classifyDistance(clipPlane.distanceToPoint(back().vertex), ON_EPSILON);
PlaneClassification nextClassification;
// for each edge
for (std::size_t next = 0, i = size() - 1;
next != size();
i = next, ++next, classification = nextClassification)
{
nextClassification = Winding::classifyDistance(clipPlane.distanceToPoint((*this)[next].vertex), ON_EPSILON);
const FixedWindingVertex& vertex = (*this)[i];
// if first vertex of edge is ON
if (classification == ePlaneOn) {
// append first vertex to output winding
if (nextClassification == ePlaneBack) {
// this edge lies on the clip plane
clipped.push_back(
FixedWindingVertex(vertex.vertex, plane3_intersect_plane3(plane, clipPlane), adjacent)
);
}
else {
clipped.push_back(vertex);
}
continue;
}
// if first vertex of edge is FRONT
if (classification == ePlaneFront) {
// add first vertex to output winding
clipped.push_back(vertex);
}
// if second vertex of edge is ON
if (nextClassification == ePlaneOn) {
continue;
}
// else if second vertex of edge is same as first
else if (nextClassification == classification) {
continue;
}
// else if first vertex of edge is FRONT and there are only two edges
else if (classification == ePlaneFront && size() == 2) {
continue;
}
// else first vertex is FRONT and second is BACK or vice versa
else {
// append intersection point of line and plane to output winding
Vector3 mid(vertex.edge.intersectPlane(clipPlane));
if (classification == ePlaneFront) {
// this edge lies on the clip plane
clipped.push_back(FixedWindingVertex(mid,
plane3_intersect_plane3(plane, clipPlane), adjacent));
} else {
clipped.push_back(FixedWindingVertex(mid, vertex.edge,
vertex.adjacent));
}
}
}
}