common: add shrink and clip poly funcs

This commit is contained in:
Eric Wasylishen 2017-02-12 00:20:38 -07:00
parent 7300aacdff
commit 3a20d5410b
3 changed files with 140 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include <common/cmdlib.hh>
#include <common/mathlib.hh>
#include <common/polylib.hh>
#include <assert.h>
#include <tuple>
@ -482,3 +483,58 @@ std::pair<bool, glm::vec3> GLM_InterpolateNormal(const std::vector<glm::vec3> &p
return make_pair(false, vec3(0));
}
static winding_t *glm_to_winding(const std::vector<glm::vec3> &poly)
{
const int N = poly.size();
winding_t *winding = AllocWinding(N);
for (int i=0; i<N; i++) {
glm_to_vec3_t(poly.at(i), winding->p[i]);
}
winding->numpoints = N;
return winding;
}
static std::vector<glm::vec3> winding_to_glm(const winding_t *w)
{
if (w == nullptr)
return {};
std::vector<glm::vec3> res;
for (int i=0; i<w->numpoints; i++) {
res.push_back(vec3_t_to_glm(w->p[i]));
}
return res;
}
/// Returns (front part, back part)
std::pair<std::vector<glm::vec3>,std::vector<glm::vec3>> GLM_ClipPoly(const std::vector<glm::vec3> &poly, const glm::vec4 &plane)
{
vec3_t normal;
winding_t *front = nullptr;
winding_t *back = nullptr;
if (poly.empty())
return make_pair(vector<vec3>(),vector<vec3>());
winding_t *w = glm_to_winding(poly);
glm_to_vec3_t(vec3(plane), normal);
ClipWinding(w, normal, plane.w, &front, &back);
const auto res = make_pair(winding_to_glm(front), winding_to_glm(back));
free(front);
free(back);
return res;
}
std::vector<glm::vec3> GLM_ShrinkPoly(const std::vector<glm::vec3> &poly, const float amount) {
const vector<vec4> edgeplanes = GLM_MakeInwardFacingEdgePlanes(poly);
vector<vec3> clipped = poly;
for (const vec4 &edge : edgeplanes) {
const vec4 shrunkEdgePlane(vec3(edge), edge.w + 1);
clipped = GLM_ClipPoly(clipped, shrunkEdgePlane).first;
}
return clipped;
}

View File

@ -332,4 +332,8 @@ std::pair<int, glm::vec3> GLM_ClosestPointOnPolyBoundary(const std::vector<glm::
std::pair<bool, glm::vec3> GLM_InterpolateNormal(const std::vector<glm::vec3> &points,
const std::vector<glm::vec3> &normals,
const glm::vec3 &point);
std::vector<glm::vec3> GLM_ShrinkPoly(const std::vector<glm::vec3> &poly, const float amount);
/// Returns (front part, back part)
std::pair<std::vector<glm::vec3>,std::vector<glm::vec3>> GLM_ClipPoly(const std::vector<glm::vec3> &poly, const glm::vec4 &plane);
#endif /* __COMMON_MATHLIB_H__ */

View File

@ -411,3 +411,83 @@ TEST(mathlib, InterpolateNormals) {
// Outside poly
EXPECT_FALSE(GLM_InterpolateNormal(poly, normals, vec3(-0.1, 0, 0)).first);
}
static bool pointsEqualEpsilon(const vec3 &a, const vec3 &b) {
return all(epsilonEqual(a, b, vec3(POINT_EQUAL_EPSILON)));
}
static bool polysEqual(const vector<vec3> &p1, const vector<vec3> &p2) {
if (p1.size() != p2.size())
return false;
for (int i=0; i<p1.size(); i++) {
if (!pointsEqualEpsilon(p1[i], p2[i]))
return false;
}
return true;
}
TEST(mathlib, ClipPoly1) {
const vector<vec3> poly {
{ 0,0,0 },
{ 0,64,0 },
{ 64,64,0 },
{ 64,0,0 }
};
const vector<vec3> frontRes {
{ 0,0,0 },
{ 0,64,0 },
{ 32,64,0 },
{ 32,0,0 }
};
const vector<vec3> backRes {
{ 32,64,0 },
{ 64,64,0 },
{ 64,0,0 },
{ 32,0,0 }
};
auto clipRes = GLM_ClipPoly(poly, vec4(-1,0,0,-32));
EXPECT_TRUE(polysEqual(frontRes, clipRes.first));
EXPECT_TRUE(polysEqual(backRes, clipRes.second));
}
TEST(mathlib, ShrinkPoly1) {
const vector<vec3> poly {
{ 0,0,0 },
{ 0,64,0 },
{ 64,64,0 },
{ 64,0,0 }
};
const vector<vec3> shrunkPoly {
{ 1,1,0 },
{ 1,63,0 },
{ 63,63,0 },
{ 63,1,0 }
};
const auto actualShrunk = GLM_ShrinkPoly(poly, 1.0f);
EXPECT_TRUE(polysEqual(shrunkPoly, actualShrunk));
}
TEST(mathlib, ShrinkPoly2) {
const vector<vec3> poly {
{ 0,0,0 },
{ 64,64,0 },
{ 64,0,0 }
};
const vector<vec3> shrunkPoly {
{ 1.0f + sqrtf(2.0f), 1.0f, 0.0f },
{ 63.0f, 63.0f - sqrtf(2.0f), 0.0f },
{ 63,1,0 },
};
const auto actualShrunk = GLM_ShrinkPoly(poly, 1.0f);
EXPECT_TRUE(polysEqual(shrunkPoly, actualShrunk));
}