Skip to content

Commit

Permalink
Move clipping functions out of Matrix4
Browse files Browse the repository at this point in the history
clipPoint/clipTriangle/clipLine are utility functions that use a Matrix4 to
transform points, but do not access any private members of Matrix4 and
therefore do not need to be methods. These are now free functions in the
BestPoint.h header, near to the code which is using them (here and in
SelectionVolume.h).
  • Loading branch information
Matthew Mott committed Mar 24, 2021
1 parent 7f14d55 commit af675be
Show file tree
Hide file tree
Showing 4 changed files with 385 additions and 444 deletions.
322 changes: 1 addition & 321 deletions libs/math/Matrix4.cpp
Expand Up @@ -390,324 +390,4 @@ void Matrix4::translateBy(const Vector3& translation)
void Matrix4::scaleBy(const Vector3& scale)
{
multiplyBy(getScale(scale));
}

namespace
{

class Vector4ClipLT
{
public:
static bool compare(const Vector4& self, std::size_t index)
{
return self[index] < self[3];
}

static double scale(const Vector4& self, const Vector4& other, std::size_t index)
{
return (self[index] - self[3]) / (other[3] - other[index]);
}
};

class Vector4ClipGT
{
public:
static bool compare(const Vector4& self, std::size_t index)
{
return self[index] > -self[3];
}

static double scale(const Vector4& self, const Vector4& other, std::size_t index)
{
return (self[index] + self[3]) / (-other[3] - other[index]);
}

};

template<typename ClipPlane>
class Vector4ClipPolygon
{
public:
typedef Vector4* iterator;
typedef const Vector4* const_iterator;

static std::size_t apply(const_iterator first, const_iterator last, iterator out, std::size_t index)
{
const_iterator next = first, i = last - 1;
iterator tmp(out);
bool b0 = ClipPlane::compare(*i, index);
while(next != last)
{
bool b1 = ClipPlane::compare(*next, index);
if(b0 ^ b1)
{
*out = *next - *i;

double scale = ClipPlane::scale(*i, *out, index);

(*out)[0] = (*i)[0] + scale*((*out)[0]);
(*out)[1] = (*i)[1] + scale*((*out)[1]);
(*out)[2] = (*i)[2] + scale*((*out)[2]);
(*out)[3] = (*i)[3] + scale*((*out)[3]);

++out;
}

if(b1)
{
*out = *next;
++out;
}

i = next;
++next;
b0 = b1;
}

return out - tmp;
}
};

#define CLIP_X_LT_W(p) (Vector4ClipLT::compare(p, 0))
#define CLIP_X_GT_W(p) (Vector4ClipGT::compare(p, 0))
#define CLIP_Y_LT_W(p) (Vector4ClipLT::compare(p, 1))
#define CLIP_Y_GT_W(p) (Vector4ClipGT::compare(p, 1))
#define CLIP_Z_LT_W(p) (Vector4ClipLT::compare(p, 2))
#define CLIP_Z_GT_W(p) (Vector4ClipGT::compare(p, 2))

inline ClipResult homogenous_clip_point(const Vector4& clipped)
{
ClipResult result = c_CLIP_FAIL;

if (CLIP_X_LT_W(clipped)) result &= ~c_CLIP_LT_X; // X < W
if (CLIP_X_GT_W(clipped)) result &= ~c_CLIP_GT_X; // X > -W
if (CLIP_Y_LT_W(clipped)) result &= ~c_CLIP_LT_Y; // Y < W
if (CLIP_Y_GT_W(clipped)) result &= ~c_CLIP_GT_Y; // Y > -W
if (CLIP_Z_LT_W(clipped)) result &= ~c_CLIP_LT_Z; // Z < W
if (CLIP_Z_GT_W(clipped)) result &= ~c_CLIP_GT_Z; // Z > -W

return result;
}

inline std::size_t homogenous_clip_line(Vector4 clipped[2])
{
const Vector4& p0 = clipped[0];
const Vector4& p1 = clipped[1];

// early out
{
ClipResult mask0 = homogenous_clip_point(clipped[0]);
ClipResult mask1 = homogenous_clip_point(clipped[1]);

if ((mask0 | mask1) == c_CLIP_PASS) // both points passed all planes
{
return 2;
}

if (mask0 & mask1) // both points failed any one plane
{
return 0;
}
}

{
const bool index = CLIP_X_LT_W(p0);

if (index ^ CLIP_X_LT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[0] - p0[3]) / (clip[3] - clip[0]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if(index == 0)
{
return 0;
}
}

{
const bool index = CLIP_X_GT_W(p0);

if (index ^ CLIP_X_GT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[0] + p0[3]) / (-clip[3] - clip[0]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if(index == 0)
{
return 0;
}
}

{
const bool index = CLIP_Y_LT_W(p0);

if (index ^ CLIP_Y_LT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[1] - p0[3]) / (clip[3] - clip[1]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if (index == 0)
{
return 0;
}
}

{
const bool index = CLIP_Y_GT_W(p0);

if (index ^ CLIP_Y_GT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[1] + p0[3]) / (-clip[3] - clip[1]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if (index == 0)
{
return 0;
}
}

{
const bool index = CLIP_Z_LT_W(p0);

if (index ^ CLIP_Z_LT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[2] - p0[3]) / (clip[3] - clip[2]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if (index == 0)
{
return 0;
}
}

{
const bool index = CLIP_Z_GT_W(p0);

if (index ^ CLIP_Z_GT_W(p1))
{
Vector4 clip(p1 - p0);

double scale = (p0[2] + p0[3]) / (-clip[3] - clip[2]);

clip[0] = p0[0] + scale * clip[0];
clip[1] = p0[1] + scale * clip[1];
clip[2] = p0[2] + scale * clip[2];
clip[3] = p0[3] + scale * clip[3];

clipped[index] = clip;
}
else if (index == 0)
{
return 0;
}
}

return 2;
}

inline std::size_t homogenous_clip_triangle(Vector4 clipped[9])
{
Vector4 buffer[9];
std::size_t count = 3;

count = Vector4ClipPolygon< Vector4ClipLT >::apply(clipped, clipped + count, buffer, 0);
count = Vector4ClipPolygon< Vector4ClipGT >::apply(buffer, buffer + count, clipped, 0);
count = Vector4ClipPolygon< Vector4ClipLT >::apply(clipped, clipped + count, buffer, 1);
count = Vector4ClipPolygon< Vector4ClipGT >::apply(buffer, buffer + count, clipped, 1);
count = Vector4ClipPolygon< Vector4ClipLT >::apply(clipped, clipped + count, buffer, 2);

return Vector4ClipPolygon< Vector4ClipGT >::apply(buffer, buffer + count, clipped, 2);
}

} // namespace

ClipResult Matrix4::clipPoint(const Vector3& point, Vector4& clipped) const
{
clipped[0] = point[0];
clipped[1] = point[1];
clipped[2] = point[2];
clipped[3] = 1;

clipped = transform(clipped);

return homogenous_clip_point(clipped);
}

std::size_t Matrix4::clipTriangle(const Vector3& p0, const Vector3& p1, const Vector3& p2, Vector4 clipped[9]) const
{
clipped[0][0] = p0[0];
clipped[0][1] = p0[1];
clipped[0][2] = p0[2];
clipped[0][3] = 1;
clipped[1][0] = p1[0];
clipped[1][1] = p1[1];
clipped[1][2] = p1[2];
clipped[1][3] = 1;
clipped[2][0] = p2[0];
clipped[2][1] = p2[1];
clipped[2][2] = p2[2];
clipped[2][3] = 1;

clipped[0] = transform(clipped[0]);
clipped[1] = transform(clipped[1]);
clipped[2] = transform(clipped[2]);

return homogenous_clip_triangle(clipped);
}

std::size_t Matrix4::clipLine(const Vector3& p0, const Vector3& p1, Vector4 clipped[2]) const
{
clipped[0][0] = p0[0];
clipped[0][1] = p0[1];
clipped[0][2] = p0[2];
clipped[0][3] = 1;
clipped[1][0] = p1[0];
clipped[1][1] = p1[1];
clipped[1][2] = p1[2];
clipped[1][3] = 1;

clipped[0] = transform(clipped[0]);
clipped[1] = transform(clipped[1]);

return homogenous_clip_line(clipped);
}
}
21 changes: 0 additions & 21 deletions libs/math/Matrix4.h
Expand Up @@ -424,27 +424,6 @@ class Matrix4
* This matrix must be affine and orthogonal to produce a meaningful result.
*/
Vector3 getScale() const;

/**
* Transforms and clips the line formed by p0, p1 by this canonical matrix.
* Stores the resulting line in clipped.
*
* @returns: the number of points in the resulting line.
*/
std::size_t clipLine(const Vector3& p0, const Vector3& p1, Vector4 clipped[2]) const;

/**
* Clips point by this canonical matrix and stores the result in clipped.
* Returns a bitmask indicating which clip-planes the point was outside.
*/
ClipResult clipPoint(const Vector3& point, Vector4& clipped) const;

/**
* Transforms and clips the triangle formed by p0, p1, p2 by this canonical matrix.
* Stores the resulting polygon in clipped.
* Returns the number of points in the resulting polygon.
*/
std::size_t clipTriangle(const Vector3& p0, const Vector3& p1, const Vector3& p2, Vector4 clipped[9]) const;
};

// ===========================================================================
Expand Down

0 comments on commit af675be

Please sign in to comment.