mirror of
https://github.com/recp/cglm.git
synced 2025-10-04 17:09:40 +00:00
curve: cubic hermite intrpolation
This commit is contained in:
@@ -8,13 +8,17 @@
|
|||||||
#ifndef cglm_bezier_h
|
#ifndef cglm_bezier_h
|
||||||
#define cglm_bezier_h
|
#define cglm_bezier_h
|
||||||
|
|
||||||
#define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \
|
#define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \
|
||||||
{ 3.0f, -6.0f, 3.0f, 0.0f}, \
|
{ 3.0f, -6.0f, 3.0f, 0.0f}, \
|
||||||
{-3.0f, 3.0f, 0.0f, 0.0f}, \
|
{-3.0f, 3.0f, 0.0f, 0.0f}, \
|
||||||
{ 1.0f, 0.0f, 0.0f, 0.0f}}
|
{ 1.0f, 0.0f, 0.0f, 0.0f}}
|
||||||
|
#define GLM_HERMITE_MAT_INIT {{ 2.0f, -3.0f, 0.0f, 1.0f}, \
|
||||||
|
{-2.0f, 3.0f, 0.0f, 0.0f}, \
|
||||||
|
{ 1.0f, -2.0f, 1.0f, 0.0f}, \
|
||||||
|
{ 1.0f, -1.0f, 0.0f, 0.0f}}
|
||||||
/* for C only */
|
/* for C only */
|
||||||
#define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT)
|
#define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT)
|
||||||
|
#define GLM_HERMITE_MAT ((mat4)GLM_HERMITE_MAT_INIT)
|
||||||
|
|
||||||
#define CGLM_DECASTEL_EPS 1e-9
|
#define CGLM_DECASTEL_EPS 1e-9
|
||||||
#define CGLM_DECASTEL_MAX 1000
|
#define CGLM_DECASTEL_MAX 1000
|
||||||
@@ -54,10 +58,46 @@ glm_bezier(float s, float p0, float c0, float c1, float p1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief iterative way to solve cubic equation
|
* @brief cubic hermite interpolation
|
||||||
|
*
|
||||||
|
* Formula:
|
||||||
|
* H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s)
|
||||||
|
* + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2)
|
||||||
|
*
|
||||||
|
* similar result using matrix:
|
||||||
|
* H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1})
|
||||||
|
*
|
||||||
|
* glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE
|
||||||
*
|
*
|
||||||
* @param[in] s parameter between 0 and 1
|
* @param[in] s parameter between 0 and 1
|
||||||
* @param[in] p0 begin point
|
* @param[in] p0 begin point
|
||||||
|
* @param[in] t0 tangent 1
|
||||||
|
* @param[in] t1 tangent 2
|
||||||
|
* @param[in] p1 end point
|
||||||
|
*
|
||||||
|
* @return B(s)
|
||||||
|
*/
|
||||||
|
CGLM_INLINE
|
||||||
|
float
|
||||||
|
glm_hermite(float s, float p0, float t0, float t1, float p1) {
|
||||||
|
float ss, d, a, b, c, e, f;
|
||||||
|
|
||||||
|
ss = s * s;
|
||||||
|
a = ss + ss;
|
||||||
|
c = a + ss;
|
||||||
|
b = a * s;
|
||||||
|
d = s * ss;
|
||||||
|
f = d - ss;
|
||||||
|
e = b - c;
|
||||||
|
|
||||||
|
return p0 * (e + 1.0f) + t0 * (f - ss + s) + t1 * f - p1 * e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief iterative way to solve cubic equation
|
||||||
|
*
|
||||||
|
* @param[in] prm parameter between 0 and 1
|
||||||
|
* @param[in] p0 begin point
|
||||||
* @param[in] c0 control point 1
|
* @param[in] c0 control point 1
|
||||||
* @param[in] c1 control point 2
|
* @param[in] c1 control point 2
|
||||||
* @param[in] p1 end point
|
* @param[in] p1 end point
|
||||||
@@ -112,7 +152,7 @@ glm_decasteljau(float prm, float p0, float c0, float c1, float p1) {
|
|||||||
/*!
|
/*!
|
||||||
* @brief solve cubic bezier equation
|
* @brief solve cubic bezier equation
|
||||||
*
|
*
|
||||||
* @param[in] s parameter between 0 and 1
|
* @param[in] prm parameter between 0 and 1
|
||||||
* @param[in] p0 begin point
|
* @param[in] p0 begin point
|
||||||
* @param[in] c0 control point 1
|
* @param[in] c0 control point 1
|
||||||
* @param[in] c1 control point 2
|
* @param[in] c1 control point 2
|
||||||
|
@@ -17,6 +17,10 @@ CGLM_EXPORT
|
|||||||
float
|
float
|
||||||
glmc_bezier(float s, float p0, float c0, float c1, float p1);
|
glmc_bezier(float s, float p0, float c0, float c1, float p1);
|
||||||
|
|
||||||
|
CGLM_EXPORT
|
||||||
|
float
|
||||||
|
glmc_hermite(float s, float p0, float t0, float t1, float p1);
|
||||||
|
|
||||||
CGLM_EXPORT
|
CGLM_EXPORT
|
||||||
float
|
float
|
||||||
glmc_decasteljau(float prm, float p0, float c0, float c1, float p1);
|
glmc_decasteljau(float prm, float p0, float c0, float c1, float p1);
|
||||||
|
12
makefile.am
12
makefile.am
@@ -58,7 +58,8 @@ cglm_HEADERS = include/cglm/version.h \
|
|||||||
include/cglm/project.h \
|
include/cglm/project.h \
|
||||||
include/cglm/sphere.h \
|
include/cglm/sphere.h \
|
||||||
include/cglm/ease.h \
|
include/cglm/ease.h \
|
||||||
include/cglm/curve.h
|
include/cglm/curve.h \
|
||||||
|
include/cglm/bezier.h
|
||||||
|
|
||||||
cglm_calldir=$(includedir)/cglm/call
|
cglm_calldir=$(includedir)/cglm/call
|
||||||
cglm_call_HEADERS = include/cglm/call/mat4.h \
|
cglm_call_HEADERS = include/cglm/call/mat4.h \
|
||||||
@@ -76,7 +77,8 @@ cglm_call_HEADERS = include/cglm/call/mat4.h \
|
|||||||
include/cglm/call/project.h \
|
include/cglm/call/project.h \
|
||||||
include/cglm/call/sphere.h \
|
include/cglm/call/sphere.h \
|
||||||
include/cglm/call/ease.h \
|
include/cglm/call/ease.h \
|
||||||
include/cglm/call/curve.h
|
include/cglm/call/curve.h \
|
||||||
|
include/cglm/call/bezier.h
|
||||||
|
|
||||||
cglm_simddir=$(includedir)/cglm/simd
|
cglm_simddir=$(includedir)/cglm/simd
|
||||||
cglm_simd_HEADERS = include/cglm/simd/intrin.h \
|
cglm_simd_HEADERS = include/cglm/simd/intrin.h \
|
||||||
@@ -112,7 +114,8 @@ libcglm_la_SOURCES=\
|
|||||||
src/project.c \
|
src/project.c \
|
||||||
src/sphere.c \
|
src/sphere.c \
|
||||||
src/ease.c \
|
src/ease.c \
|
||||||
src/curve.c
|
src/curve.c \
|
||||||
|
src/bezier.c
|
||||||
|
|
||||||
test_tests_SOURCES=\
|
test_tests_SOURCES=\
|
||||||
test/src/test_common.c \
|
test/src/test_common.c \
|
||||||
@@ -126,7 +129,8 @@ test_tests_SOURCES=\
|
|||||||
test/src/test_vec4.c \
|
test/src/test_vec4.c \
|
||||||
test/src/test_vec3.c \
|
test/src/test_vec3.c \
|
||||||
test/src/test_mat3.c \
|
test/src/test_mat3.c \
|
||||||
test/src/test_affine.c
|
test/src/test_affine.c \
|
||||||
|
test/src/test_bezier.c
|
||||||
|
|
||||||
all-local:
|
all-local:
|
||||||
sh ./post-build.sh
|
sh ./post-build.sh
|
||||||
|
@@ -14,6 +14,12 @@ glmc_bezier(float s, float p0, float c0, float c1, float p1) {
|
|||||||
return glm_bezier(s, p0, c0, c1, p1);
|
return glm_bezier(s, p0, c0, c1, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGLM_EXPORT
|
||||||
|
float
|
||||||
|
glmc_hermite(float s, float p0, float t0, float t1, float p1) {
|
||||||
|
return glm_hermite(s, p0, t0, t1, p1);
|
||||||
|
}
|
||||||
|
|
||||||
CGLM_EXPORT
|
CGLM_EXPORT
|
||||||
float
|
float
|
||||||
glmc_decasteljau(float prm, float p0, float c0, float c1, float p1) {
|
glmc_decasteljau(float prm, float p0, float c0, float c1, float p1) {
|
||||||
|
@@ -21,6 +21,20 @@ test_bezier_plain(float s, float p0, float c0, float c1, float p1) {
|
|||||||
return p0 * xxx + 3.0f * (c0 * s * xx + c1 * ss * x) + p1 * sss;
|
return p0 * xxx + 3.0f * (c0 * s * xx + c1 * ss * x) + p1 * sss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGLM_INLINE
|
||||||
|
float
|
||||||
|
test_hermite_plain(float s, float p0, float t0, float t1, float p1) {
|
||||||
|
float ss, sss;
|
||||||
|
|
||||||
|
ss = s * s;
|
||||||
|
sss = ss * s;
|
||||||
|
|
||||||
|
return p0 * (2.0f * sss - 3.0f * ss + 1.0f)
|
||||||
|
+ t0 * (sss - 2.0f * ss + s)
|
||||||
|
+ p1 * (-2.0f * sss + 3.0f * ss)
|
||||||
|
+ t1 * (sss - ss);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_bezier(void **state) {
|
test_bezier(void **state) {
|
||||||
float s, p0, p1, c0, c1, smc, Bs, Bs_plain;
|
float s, p0, p1, c0, c1, smc, Bs, Bs_plain;
|
||||||
@@ -31,6 +45,7 @@ test_bezier(void **state) {
|
|||||||
c0 = test_rand();
|
c0 = test_rand();
|
||||||
c1 = test_rand();
|
c1 = test_rand();
|
||||||
|
|
||||||
|
/* test cubic bezier */
|
||||||
smc = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1});
|
smc = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1});
|
||||||
Bs = glm_bezier(s, p0, c0, c1, p1);
|
Bs = glm_bezier(s, p0, c0, c1, p1);
|
||||||
Bs_plain = test_bezier_plain(s, p0, c0, c1, p1);
|
Bs_plain = test_bezier_plain(s, p0, c0, c1, p1);
|
||||||
@@ -38,4 +53,13 @@ test_bezier(void **state) {
|
|||||||
assert_true(glm_eq(Bs, Bs_plain));
|
assert_true(glm_eq(Bs, Bs_plain));
|
||||||
assert_true(glm_eq(smc, Bs_plain));
|
assert_true(glm_eq(smc, Bs_plain));
|
||||||
assert_true(glm_eq(Bs, smc));
|
assert_true(glm_eq(Bs, smc));
|
||||||
|
|
||||||
|
/* test cubic hermite */
|
||||||
|
smc = glm_smc(s, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1});
|
||||||
|
Bs = glm_hermite(s, p0, c0, c1, p1);
|
||||||
|
Bs_plain = test_hermite_plain(s, p0, c0, c1, p1);
|
||||||
|
|
||||||
|
assert_true(glm_eq(Bs, Bs_plain));
|
||||||
|
assert_true(glm_eq(smc, Bs_plain));
|
||||||
|
assert_true(glm_eq(Bs, smc));
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\affine.c" />
|
<ClCompile Include="..\src\affine.c" />
|
||||||
|
<ClCompile Include="..\src\bezier.c" />
|
||||||
<ClCompile Include="..\src\box.c" />
|
<ClCompile Include="..\src\box.c" />
|
||||||
<ClCompile Include="..\src\cam.c" />
|
<ClCompile Include="..\src\cam.c" />
|
||||||
<ClCompile Include="..\src\curve.c" />
|
<ClCompile Include="..\src\curve.c" />
|
||||||
@@ -40,9 +41,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\include\cglm\affine-mat.h" />
|
<ClInclude Include="..\include\cglm\affine-mat.h" />
|
||||||
<ClInclude Include="..\include\cglm\affine.h" />
|
<ClInclude Include="..\include\cglm\affine.h" />
|
||||||
|
<ClInclude Include="..\include\cglm\bezier.h" />
|
||||||
<ClInclude Include="..\include\cglm\box.h" />
|
<ClInclude Include="..\include\cglm\box.h" />
|
||||||
<ClInclude Include="..\include\cglm\call.h" />
|
<ClInclude Include="..\include\cglm\call.h" />
|
||||||
<ClInclude Include="..\include\cglm\call\affine.h" />
|
<ClInclude Include="..\include\cglm\call\affine.h" />
|
||||||
|
<ClInclude Include="..\include\cglm\call\bezier.h" />
|
||||||
<ClInclude Include="..\include\cglm\call\box.h" />
|
<ClInclude Include="..\include\cglm\call\box.h" />
|
||||||
<ClInclude Include="..\include\cglm\call\cam.h" />
|
<ClInclude Include="..\include\cglm\call\cam.h" />
|
||||||
<ClInclude Include="..\include\cglm\call\curve.h" />
|
<ClInclude Include="..\include\cglm\call\curve.h" />
|
||||||
|
@@ -87,6 +87,9 @@
|
|||||||
<ClCompile Include="..\src\curve.c">
|
<ClCompile Include="..\src\curve.c">
|
||||||
<Filter>src</Filter>
|
<Filter>src</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\bezier.c">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\src\config.h">
|
<ClInclude Include="..\src\config.h">
|
||||||
@@ -248,5 +251,11 @@
|
|||||||
<ClInclude Include="..\include\cglm\curve.h">
|
<ClInclude Include="..\include\cglm\curve.h">
|
||||||
<Filter>include\cglm</Filter>
|
<Filter>include\cglm</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\cglm\bezier.h">
|
||||||
|
<Filter>include\cglm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\cglm\call\bezier.h">
|
||||||
|
<Filter>include\cglm\call</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Reference in New Issue
Block a user