-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclipping.cpp
More file actions
224 lines (191 loc) · 10 KB
/
Copy pathclipping.cpp
File metadata and controls
224 lines (191 loc) · 10 KB
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//
// Created by kobedb on 20.05.22.
//
#include "clipping.h"
#include <iostream>
#include <cassert>
using namespace std;
namespace KDBRenderUtils
{
constexpr double vlakSpeling = 0.000000001f;
/// Check if p is on the "inside" of a plane that is parallel with XY with equation: z = planeZ \n
/// p is "inside" the plane if p.z < planeZ (if the inside is defined as the space behind the plane)
bool isInsideXYPlane(const Vector3D& p, double planeZ, bool insideIsBehindPlaneZ)
{
return insideIsBehindPlaneZ? p.z < planeZ + vlakSpeling : p.z > planeZ - vlakSpeling;
}
bool isInsideLeftOrRightPlane(const Vector3D& p, double planeX, double dNear, bool isLeftPlane)
{
return isLeftPlane? (-p.x * dNear / p.z) > planeX - vlakSpeling : (-p.x * dNear / p.z) < planeX + vlakSpeling;
}
bool isInsideBottomOrTopPlane(const Vector3D& p, double planeY, double dNear, bool isBottomPlane)
{
return isBottomPlane ? (-p.y * dNear / p.z) > planeY - vlakSpeling : (-p.y * dNear / p.z) < planeY + vlakSpeling;
}
bool isInsidePlane(const Vector3D& p, const PlaneContext& context)
{
switch(context.planePair) {
case PlaneContext::nearOrFar: {
return isInsideXYPlane(p, context.planeLoc, context.firstKind);
}
case PlaneContext::leftOrRight: {
return isInsideLeftOrRightPlane(p, context.planeLoc, context.dNear, context.firstKind);
}
case PlaneContext::bottomOrTop: {
return isInsideBottomOrTopPlane(p, context.planeLoc, context.dNear, context.firstKind);
}
default: {
cerr << "isInsidePlane: unknown planePair";
return true;
}
}
cerr << "isInsidePlane: how did we even get here?!";
return true;
}
bool triangleCompletelyInsidePlane(const Vector3D& p0, const Vector3D& p1, const Vector3D& p2,
const PlaneContext& context)
{
return isInsidePlane(p0, context) && isInsidePlane(p1, context) && isInsidePlane(p2, context);
}
bool triangleCompletelyOutsidePlane(const Vector3D& p0, const Vector3D& p1, const Vector3D& p2,
const PlaneContext& context)
{
return !isInsidePlane(p0, context) && !isInsidePlane(p1, context) && !isInsidePlane(p2, context);
}
Vector3D calcIntersectionPointWithNearOrFarPlane(const Vector3D& p0, const Vector3D& p1, double planeLoc)
{
// Vector3D pSmallerZ = p0;
// Vector3D pBiggerZ = p1;
// if(p0.z > p1.z) {
// swap(pSmallerZ, pBiggerZ);
// }
double p_line0 = (planeLoc - p1.z) / (p0.z - p1.z);
return p_line0 * p0 + (1 - p_line0) * p1;
}
Vector3D calcIntersectionPointWithLeftOrRightPlane(const Vector3D& p0, const Vector3D& p1, double dVal, double dNear)
{
double p_line0 = (p1.x * dNear + p1.z * dVal) / ((p1.x - p0.x) * dNear + (p1.z - p0.z) * dVal);
return p_line0 * p0 + (1 - p_line0) * p1;
}
Vector3D calcIntersectionPointWithBottomOrTopPlane(const Vector3D& p0, const Vector3D& p1, double dVal, double dNear)
{
double p_line0 = (p1.y * dNear + p1.z * dVal) / ((p1.y - p0.y) * dNear + (p1.z - p0.z) * dVal);
return p_line0 * p0 + (1 - p_line0) * p1;
}
Vector3D calcIntersectionPointWithPlane(const Vector3D& p0, const Vector3D& p1, const PlaneContext& context)
{
switch(context.planePair) {
case PlaneContext::nearOrFar: {
return calcIntersectionPointWithNearOrFarPlane(p0, p1, context.planeLoc);
}
case PlaneContext::leftOrRight: {
return calcIntersectionPointWithLeftOrRightPlane(p0, p1, context.planeLoc, context.dNear);
}
case PlaneContext::bottomOrTop: {
return calcIntersectionPointWithBottomOrTopPlane(p0, p1, context.planeLoc, context.dNear);
}
default: {
cerr << "calcIntersectionPointWithPlane: unknown planePair";
return {};
}
}
cerr << "calcIntersectionPointWithPlane: how did we even get here?!";
return {};
}
/// @pre : only call this method when the triangle lies *partly* outside the plane
/// @pre : p0, p1, p2 are indexes that reference points in fig.vertices
/// @pre : p0, p1, p2 are given in counter-clock wise order
/// @post: the returned vector contains all the points from the given triangle (also indexes in fig.vertices) outside the plane in counter-clock wise order
vector<int> calcPointsInsideOrOutsidePlane(const Figure& fig, int p0, int p1, int p2,
const PlaneContext& context, bool checkInside)
{
vector<int> result; // points stored counter clock wise
if(checkInside ? isInsidePlane(fig.vertices[p0], context) && isInsidePlane(fig.vertices[p2], context) :
!isInsidePlane(fig.vertices[p0], context) && !isInsidePlane(fig.vertices[p2], context))
{
result.push_back(p2);
result.push_back(p0);
}
else {
if(checkInside == isInsidePlane(fig.vertices[p0], context)) result.push_back(p0);
if(checkInside == isInsidePlane(fig.vertices[p1], context)) result.push_back(p1);
if(checkInside == isInsidePlane(fig.vertices[p2], context)) result.push_back(p2);
}
assert(result.size() <= 2);
return result;
}
void clipAgainstPlane(Figure& fig, list<Face>& tris, const PlaneContext& planeContext)
{
for(auto it = tris.begin(); it != tris.end();) {
if(it->point_indexes.size() != 3) {cerr << "Tried to clip a face that is not a triangle\n";continue;}
if(triangleCompletelyInsidePlane(fig.vertices[it->point_indexes[0]],
fig.vertices[it->point_indexes[1]],
fig.vertices[it->point_indexes[2]],
planeContext ))
{
it++;
continue;
}
if(triangleCompletelyOutsidePlane(fig.vertices[it->point_indexes[0]],
fig.vertices[it->point_indexes[1]],
fig.vertices[it->point_indexes[2]],
planeContext ))
{
it = tris.erase(it);
continue;
}
vector<int> pointsOutsidePlane = calcPointsInsideOrOutsidePlane(fig,
it->point_indexes[0],
it->point_indexes[1],
it->point_indexes[2],
planeContext,
false
);
vector<int> pointsInsidePlane = calcPointsInsideOrOutsidePlane(fig,
it->point_indexes[0],
it->point_indexes[1],
it->point_indexes[2],
planeContext,
true
);
if(pointsOutsidePlane.size() == 2) {
Face newTri;
fig.vertices.push_back(calcIntersectionPointWithPlane(fig.vertices[pointsOutsidePlane[0]],
fig.vertices[pointsInsidePlane[0]],
planeContext));
newTri.point_indexes.push_back(fig.vertices.size()-1);
fig.vertices.push_back(calcIntersectionPointWithPlane(fig.vertices[pointsOutsidePlane[1]],
fig.vertices[pointsInsidePlane[0]],
planeContext));
newTri.point_indexes.push_back(fig.vertices.size()-1);
newTri.point_indexes.push_back(pointsInsidePlane[0]);
tris.push_back(newTri);
it = tris.erase(it);
continue;
}
if(pointsOutsidePlane.size() == 1) {
Face newTri0;
Face newTri1;
// First Triangle
newTri0.point_indexes.push_back(pointsInsidePlane[0]);
newTri0.point_indexes.push_back(pointsInsidePlane[1]);
fig.vertices.push_back(calcIntersectionPointWithPlane(fig.vertices[pointsOutsidePlane[0]],
fig.vertices[pointsInsidePlane[1]],
planeContext));
int intersectionPointIndex = fig.vertices.size() - 1;
newTri0.point_indexes.push_back(intersectionPointIndex);
// Second Triangle
newTri1.point_indexes.push_back(pointsInsidePlane[0]);
newTri1.point_indexes.push_back(intersectionPointIndex);
fig.vertices.push_back(calcIntersectionPointWithPlane(fig.vertices[pointsOutsidePlane[0]],
fig.vertices[pointsInsidePlane[0]],
planeContext));
newTri1.point_indexes.push_back(fig.vertices.size() - 1);
tris.push_back(newTri0);
tris.push_back(newTri1);
it = tris.erase(it);
continue;
}
}
}
};