math/geometry: add support for 3-coordinate-space clipping
This commit is contained in:
parent
92428711e4
commit
0b41a5138d
@ -4,7 +4,7 @@
|
||||
|
||||
namespace geometry {
|
||||
|
||||
template <int L, typename T>
|
||||
template <typename T, int L>
|
||||
constexpr inline
|
||||
T line_plane_intersection_d(const vec<L, T>& plane_point, // p0
|
||||
const vec<L, T>& plane_normal, // n
|
||||
@ -19,7 +19,7 @@ T line_plane_intersection_d(const vec<L, T>& plane_point, // p0
|
||||
return intersection;
|
||||
}
|
||||
|
||||
template <int L, typename T>
|
||||
template <typename T, int L>
|
||||
constexpr inline
|
||||
vec<L, T> line_plane_intersection(const vec<L, T>& plane_point, // p0
|
||||
const vec<L, T>& plane_normal, // n
|
||||
@ -34,32 +34,19 @@ vec<L, T> line_plane_intersection(const vec<L, T>& plane_point, // p0
|
||||
return line_start + line_vector * intersection;
|
||||
}
|
||||
|
||||
template <int L, typename T, int M>
|
||||
template <typename T, int L>
|
||||
constexpr inline
|
||||
std::tuple<vec<L, T>, vec<M, T>> line_plane_intersection_two_lines(const vec<L, T>& plane_point, // p0
|
||||
const vec<L, T>& plane_normal, // n
|
||||
const vec<L, T>& line_start, // l0
|
||||
vec<L, T> interpolate(const vec<L, T>& line_start,
|
||||
const vec<L, T>& line_end,
|
||||
const vec<M, T>& line2_start,
|
||||
const vec<M, T>& line2_end
|
||||
T intersection
|
||||
)
|
||||
{
|
||||
/* it is assumed that line and line2 are the same line, but in different
|
||||
coordinates spaces. It is therefore possible to re-use the same
|
||||
interpolation value on either line vector.
|
||||
*/
|
||||
|
||||
const auto line_vector = line_end - line_start; // l
|
||||
const auto line2_vector = line2_end - line2_start;
|
||||
|
||||
const T intersection = line_plane_intersection_d(plane_point, plane_normal, line_start, line_vector); // d
|
||||
|
||||
return { line_start + line_vector * intersection
|
||||
, line2_start + line2_vector * intersection
|
||||
};
|
||||
return line_start + line_vector * intersection;
|
||||
}
|
||||
|
||||
template <int L, typename T>
|
||||
template <typename T, int L>
|
||||
T clip_boundary(const vec<L, T>& plane_point, // X
|
||||
const vec<L, T>& plane_normal, // Nc
|
||||
const vec<L, T>& line_point
|
||||
@ -74,7 +61,7 @@ inline T positive_modulo(T a, T b)
|
||||
return (a % b + b) % b;
|
||||
}
|
||||
|
||||
template <int polygon_len, int L, typename T>
|
||||
template <int polygon_len, typename T, int L>
|
||||
inline int clip_polygon1(vec<L, T> * output,
|
||||
const vec<L, T> plane_point,
|
||||
const vec<L, T> plane_normal,
|
||||
@ -86,7 +73,7 @@ inline int clip_polygon1(vec<L, T> * output,
|
||||
const vec<L, T>& s = polygon[ix_s];
|
||||
const vec<L, T>& f = polygon[ix_f];
|
||||
|
||||
bool this_inside = 0.f < clip_boundary<L, T>(plane_point,
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f);
|
||||
|
||||
@ -98,7 +85,7 @@ inline int clip_polygon1(vec<L, T> * output,
|
||||
case 0b01: // I, F
|
||||
length = 2;
|
||||
{
|
||||
const auto i = line_plane_intersection<L, T>(plane_point, plane_normal, s, f);
|
||||
const auto i = line_plane_intersection<T, L>(plane_point, plane_normal, s, f);
|
||||
*output++ = i;
|
||||
*output++ = f;
|
||||
}
|
||||
@ -106,7 +93,7 @@ inline int clip_polygon1(vec<L, T> * output,
|
||||
case 0b10: // I
|
||||
length = 1;
|
||||
{
|
||||
const auto i = line_plane_intersection<L, T>(plane_point, plane_normal, s, f);
|
||||
const auto i = line_plane_intersection<T, L>(plane_point, plane_normal, s, f);
|
||||
*output++ = i;
|
||||
}
|
||||
break;
|
||||
@ -119,7 +106,7 @@ inline int clip_polygon1(vec<L, T> * output,
|
||||
bool end_of_polygon = ix_f == (polygon_len - 1);
|
||||
if (!end_of_polygon) {
|
||||
return length +
|
||||
clip_polygon1<polygon_len, L, T>(output,
|
||||
clip_polygon1<polygon_len, T, L>(output,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon,
|
||||
@ -142,11 +129,11 @@ int clip_polygon(vec<L, T> * output,
|
||||
|
||||
// It would be nice to remove the extra dot product, but the
|
||||
// alternative seems likely uglier.
|
||||
bool this_inside = 0.f < clip_boundary<L, T>(plane_point,
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f);
|
||||
|
||||
return clip_polygon1<polygon_len, L, T>(output,
|
||||
return clip_polygon1<polygon_len, T, L>(output,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon,
|
||||
@ -155,70 +142,70 @@ int clip_polygon(vec<L, T> * output,
|
||||
this_inside);
|
||||
}
|
||||
|
||||
template <int polygon_len, int L, typename T, int M>
|
||||
inline int clip_polygon1_uv(vec<L, T> * output,
|
||||
vec<M, T> * output_uv,
|
||||
template <int polygon_len, typename T, int L, int M>
|
||||
inline int clip_polygon1_2(vec<L, T> * output_1,
|
||||
vec<M, T> * output_2,
|
||||
const vec<L, T> plane_point,
|
||||
const vec<L, T> plane_normal,
|
||||
const vec<L, T> * polygon,
|
||||
const vec<M, T> * polygon_uv,
|
||||
const vec<L, T> * polygon_1,
|
||||
const vec<M, T> * polygon_2,
|
||||
const int ix_s,
|
||||
const int ix_f,
|
||||
const bool last_inside)
|
||||
{
|
||||
const vec<L, T>& s = polygon[ix_s];
|
||||
const vec<L, T>& f = polygon[ix_f];
|
||||
const vec<L, T>& s_1 = polygon_1[ix_s];
|
||||
const vec<L, T>& f_1 = polygon_1[ix_f];
|
||||
|
||||
const vec<M, T>& s_uv = polygon_uv[ix_s];
|
||||
const vec<M, T>& f_uv = polygon_uv[ix_f];
|
||||
const vec<M, T>& s_2 = polygon_2[ix_s];
|
||||
const vec<M, T>& f_2 = polygon_2[ix_f];
|
||||
|
||||
bool this_inside = 0.f < clip_boundary<L, T>(plane_point,
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f);
|
||||
f_1);
|
||||
|
||||
int length = 0;
|
||||
switch ((last_inside << 1) | (this_inside << 0)) {
|
||||
int control = (last_inside << 1) | (this_inside << 0);
|
||||
switch (control) {
|
||||
case 0b00: // no output
|
||||
length = 0;
|
||||
break;
|
||||
case 0b01: // I, F
|
||||
length = 2;
|
||||
{
|
||||
auto [i, i_uv] = line_plane_intersection_two_lines<L, T, M>(plane_point, plane_normal,
|
||||
s, f,
|
||||
s_uv, f_uv);
|
||||
*output++ = i;
|
||||
*output_uv++ = i_uv;
|
||||
*output++ = f;
|
||||
*output_uv++ = f_uv;
|
||||
}
|
||||
break;
|
||||
case 0b10: // I
|
||||
length = 1;
|
||||
[[fallthrough]];
|
||||
case 0b01: // I, F
|
||||
{
|
||||
auto [i, i_uv] = line_plane_intersection_two_lines<L, T, M>(plane_point, plane_normal,
|
||||
s, f,
|
||||
s_uv, f_uv);
|
||||
*output++ = i;
|
||||
*output_uv++ = i_uv;
|
||||
const auto& i_1_start = s_1;
|
||||
const auto i_1_vector = f_1 - s_1; // l
|
||||
const T intersection = line_plane_intersection_d<T, L>(plane_point, plane_normal,
|
||||
i_1_start, i_1_vector);
|
||||
const vec<L, T> i_1 = i_1_start + i_1_vector * intersection;
|
||||
|
||||
*output_1++ = i_1;
|
||||
*output_2++ = interpolate(s_2, f_2, intersection);
|
||||
|
||||
if (control == 0b01) { // I, F
|
||||
*output_1++ = f_1;
|
||||
*output_2++ = f_2;
|
||||
length = 2;
|
||||
} else {
|
||||
length = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0b11: // F
|
||||
*output_1++ = f_1;
|
||||
*output_2++ = f_2;
|
||||
length = 1;
|
||||
*output++ = f;
|
||||
*output_uv++ = f_uv;
|
||||
break;
|
||||
}
|
||||
|
||||
bool end_of_polygon = ix_f == (polygon_len - 1);
|
||||
if (!end_of_polygon) {
|
||||
return length +
|
||||
clip_polygon1_uv<polygon_len, L, T, M>(output,
|
||||
output_uv,
|
||||
clip_polygon1_2<polygon_len, T, L, M>(output_1,
|
||||
output_2,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon,
|
||||
polygon_uv,
|
||||
polygon_1,
|
||||
polygon_2,
|
||||
ix_f,
|
||||
ix_f + 1,
|
||||
this_inside);
|
||||
@ -227,29 +214,144 @@ inline int clip_polygon1_uv(vec<L, T> * output,
|
||||
}
|
||||
}
|
||||
|
||||
template <int polygon_len, int L, typename T, int M>
|
||||
int clip_polygon_uv(vec<L, T> * output,
|
||||
vec<M, T> * output_uv,
|
||||
template <int polygon_len, typename T, int L, int M>
|
||||
int clip_polygon_2(vec<L, T> * output_1,
|
||||
vec<M, T> * output_2,
|
||||
const vec<L, T>& plane_point,
|
||||
const vec<L, T>& plane_normal,
|
||||
const vec<L, T> * polygon,
|
||||
const vec<M, T> * polygon_uv
|
||||
const vec<L, T> * polygon_1,
|
||||
const vec<M, T> * polygon_2
|
||||
)
|
||||
{
|
||||
const vec<L, T> f = polygon[polygon_len - 1];
|
||||
const vec<L, T> f = polygon_1[polygon_len - 1];
|
||||
|
||||
// It would be nice to remove the extra dot product, but the
|
||||
// alternative seems likely uglier.
|
||||
bool this_inside = 0.f < clip_boundary<L, T>(plane_point,
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f);
|
||||
|
||||
return clip_polygon1_uv<polygon_len, L, T, M>(output,
|
||||
output_uv,
|
||||
return clip_polygon1_2<polygon_len, T, L, M>(output_1,
|
||||
output_2,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon,
|
||||
polygon_uv,
|
||||
polygon_1,
|
||||
polygon_2,
|
||||
polygon_len - 1, // ix_s
|
||||
0, // ix_f
|
||||
this_inside);
|
||||
}
|
||||
|
||||
template <int polygon_len, typename T, int L, int M, int N>
|
||||
inline int clip_polygon1_3(vec<L, T> * output_1,
|
||||
vec<M, T> * output_2,
|
||||
vec<N, T> * output_3,
|
||||
const vec<L, T> plane_point,
|
||||
const vec<L, T> plane_normal,
|
||||
const vec<L, T> * polygon_1,
|
||||
const vec<M, T> * polygon_2,
|
||||
const vec<N, T> * polygon_3,
|
||||
const int ix_s,
|
||||
const int ix_f,
|
||||
const bool last_inside)
|
||||
{
|
||||
const vec<L, T>& s_1 = polygon_1[ix_s];
|
||||
const vec<L, T>& f_1 = polygon_1[ix_f];
|
||||
|
||||
const vec<M, T>& s_2 = polygon_2[ix_s];
|
||||
const vec<M, T>& f_2 = polygon_2[ix_f];
|
||||
|
||||
const vec<N, T>& s_3 = polygon_3[ix_s];
|
||||
const vec<N, T>& f_3 = polygon_3[ix_f];
|
||||
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f_1);
|
||||
|
||||
int length = 0;
|
||||
int control = (last_inside << 1) | (this_inside << 0);
|
||||
switch (control) {
|
||||
case 0b00: // no output
|
||||
length = 0;
|
||||
break;
|
||||
case 0b10: // I
|
||||
[[fallthrough]];
|
||||
case 0b01: // I, F
|
||||
{
|
||||
const auto& i_1_start = s_1;
|
||||
const auto i_1_vector = f_1 - s_1; // l
|
||||
const T intersection = line_plane_intersection_d<T, L>(plane_point, plane_normal,
|
||||
i_1_start, i_1_vector);
|
||||
const vec<L, T> i_1 = i_1_start + i_1_vector * intersection;
|
||||
|
||||
*output_1++ = i_1;
|
||||
*output_2++ = interpolate(s_2, f_2, intersection);
|
||||
*output_3++ = interpolate(s_3, f_3, intersection);
|
||||
|
||||
if (control == 0b01) { // I, F
|
||||
*output_1++ = f_1;
|
||||
*output_2++ = f_2;
|
||||
*output_3++ = f_3;
|
||||
length = 2;
|
||||
} else {
|
||||
length = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0b11: // F
|
||||
*output_1++ = f_1;
|
||||
*output_2++ = f_2;
|
||||
*output_3++ = f_3;
|
||||
length = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
bool end_of_polygon = ix_f == (polygon_len - 1);
|
||||
if (!end_of_polygon) {
|
||||
return length +
|
||||
clip_polygon1_3<polygon_len, T, L, M, N>(output_1,
|
||||
output_2,
|
||||
output_3,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon_1,
|
||||
polygon_2,
|
||||
polygon_3,
|
||||
ix_f,
|
||||
ix_f + 1,
|
||||
this_inside);
|
||||
} else {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
template <int polygon_len, typename T, int L, int M, int N>
|
||||
int clip_polygon_3(vec<L, T> * output_1,
|
||||
vec<M, T> * output_2,
|
||||
vec<N, T> * output_3,
|
||||
const vec<L, T>& plane_point,
|
||||
const vec<L, T>& plane_normal,
|
||||
const vec<L, T> * polygon_1,
|
||||
const vec<M, T> * polygon_2,
|
||||
const vec<N, T> * polygon_3
|
||||
)
|
||||
{
|
||||
const vec<L, T> f = polygon_1[polygon_len - 1];
|
||||
|
||||
// It would be nice to remove the extra dot product, but the
|
||||
// alternative seems likely uglier.
|
||||
bool this_inside = 0.f < clip_boundary<T, L>(plane_point,
|
||||
plane_normal,
|
||||
f);
|
||||
|
||||
return clip_polygon1_3<polygon_len, T, L, M>(output_1,
|
||||
output_2,
|
||||
output_3,
|
||||
plane_point,
|
||||
plane_normal,
|
||||
polygon_1,
|
||||
polygon_2,
|
||||
polygon_3,
|
||||
polygon_len - 1, // ix_s
|
||||
0, // ix_f
|
||||
this_inside);
|
||||
|
Loading…
x
Reference in New Issue
Block a user