Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenlib/intern/math_geom.c')
-rw-r--r--source/blender/blenlib/intern/math_geom.c155
1 files changed, 118 insertions, 37 deletions
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 9cf1341b16a..2b0018e7662 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1418,7 +1418,7 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
/**
* \param l1, l2: Coordinates (point of line).
- * \param sp, r: Coordinate and radius (sphere).
+ * \param sp, r: Coordinate and radius (sphere).
* \return r_p1, r_p2: Intersection coordinates.
*
* \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
@@ -2298,6 +2298,81 @@ bool isect_plane_plane_v3(const float plane_a[4],
}
/**
+ * Intersect all planes, calling `callback_fn` for each point that intersects
+ * 3 of the planes that isn't outside any of the other planes.
+ *
+ * This can be thought of as calculating a convex-hull from an array of planes.
+ *
+ * \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
+ * \param eps_isect: Epsilon for testing of a point is behind any of the planes.
+ *
+ * \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
+ *
+ * \note This function could be optimized by some spatial structure.
+ */
+bool isect_planes_v3_fn(
+ const float planes[][4],
+ const int planes_len,
+ const float eps_coplanar,
+ const float eps_isect,
+ void (*callback_fn)(const float co[3], int i, int j, int k, void *user_data),
+ void *user_data)
+{
+ bool found = false;
+
+ float n1n2[3], n2n3[3], n3n1[3];
+
+ for (int i = 0; i < planes_len; i++) {
+ const float *n1 = planes[i];
+ for (int j = i + 1; j < planes_len; j++) {
+ const float *n2 = planes[j];
+ cross_v3_v3v3(n1n2, n1, n2);
+ if (len_squared_v3(n1n2) <= eps_coplanar) {
+ continue;
+ }
+ for (int k = j + 1; k < planes_len; k++) {
+ const float *n3 = planes[k];
+ cross_v3_v3v3(n2n3, n2, n3);
+ if (len_squared_v3(n2n3) <= eps_coplanar) {
+ continue;
+ }
+
+ cross_v3_v3v3(n3n1, n3, n1);
+ if (len_squared_v3(n3n1) <= eps_coplanar) {
+ continue;
+ }
+ const float quotient = -dot_v3v3(n1, n2n3);
+ if (fabsf(quotient) < eps_coplanar) {
+ continue;
+ }
+ const float co_test[3] = {
+ ((n2n3[0] * n1[3]) + (n3n1[0] * n2[3]) + (n1n2[0] * n3[3])) / quotient,
+ ((n2n3[1] * n1[3]) + (n3n1[1] * n2[3]) + (n1n2[1] * n3[3])) / quotient,
+ ((n2n3[2] * n1[3]) + (n3n1[2] * n2[3]) + (n1n2[2] * n3[3])) / quotient,
+ };
+ int i_test;
+ for (i_test = 0; i_test < planes_len; i_test++) {
+ const float *np_test = planes[i_test];
+ if (((dot_v3v3(np_test, co_test) + np_test[3]) > eps_isect)) {
+ /* For low epsilon values the point could intersect it's own plane. */
+ if (!ELEM(i_test, i, j, k)) {
+ break;
+ }
+ }
+ }
+
+ if (i_test == planes_len) { /* ok */
+ callback_fn(co_test, i, j, k, user_data);
+ found = true;
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
+/**
* Intersect two triangles.
*
* \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
@@ -2322,16 +2397,16 @@ bool isect_tri_tri_v3_ex(const float tri_a[3][3],
} range[2];
float side[2][3];
- float ba[3], bc[3], plane_a[4], plane_b[4];
+ double ba[3], bc[3], plane_a[4], plane_b[4];
*r_tri_a_edge_isect_count = 0;
- sub_v3_v3v3(ba, tri_a[0], tri_a[1]);
- sub_v3_v3v3(bc, tri_a[2], tri_a[1]);
- cross_v3_v3v3(plane_a, ba, bc);
- plane_a[3] = -dot_v3v3(tri_a[1], plane_a);
- side[1][0] = plane_point_side_v3(plane_a, tri_b[0]);
- side[1][1] = plane_point_side_v3(plane_a, tri_b[1]);
- side[1][2] = plane_point_side_v3(plane_a, tri_b[2]);
+ sub_v3db_v3fl_v3fl(ba, tri_a[0], tri_a[1]);
+ sub_v3db_v3fl_v3fl(bc, tri_a[2], tri_a[1]);
+ cross_v3_v3v3_db(plane_a, ba, bc);
+ plane_a[3] = -dot_v3db_v3fl(plane_a, tri_a[1]);
+ side[1][0] = (float)(dot_v3db_v3fl(plane_a, tri_b[0]) + plane_a[3]);
+ side[1][1] = (float)(dot_v3db_v3fl(plane_a, tri_b[1]) + plane_a[3]);
+ side[1][2] = (float)(dot_v3db_v3fl(plane_a, tri_b[2]) + plane_a[3]);
if (!side[1][0] && !side[1][1] && !side[1][2]) {
/* Coplanar case is not supported. */
@@ -2345,13 +2420,14 @@ bool isect_tri_tri_v3_ex(const float tri_a[3][3],
return false;
}
- sub_v3_v3v3(ba, tri_b[0], tri_b[1]);
- sub_v3_v3v3(bc, tri_b[2], tri_b[1]);
- cross_v3_v3v3(plane_b, ba, bc);
- plane_b[3] = -dot_v3v3(tri_b[1], plane_b);
- side[0][0] = plane_point_side_v3(plane_b, tri_a[0]);
- side[0][1] = plane_point_side_v3(plane_b, tri_a[1]);
- side[0][2] = plane_point_side_v3(plane_b, tri_a[2]);
+ sub_v3db_v3fl_v3fl(ba, tri_b[0], tri_b[1]);
+ sub_v3db_v3fl_v3fl(bc, tri_b[2], tri_b[1]);
+ cross_v3_v3v3_db(plane_b, ba, bc);
+ plane_b[3] = -dot_v3db_v3fl(plane_b, tri_b[1]);
+ side[0][0] = (float)(dot_v3db_v3fl(plane_b, tri_a[0]) + plane_b[3]);
+ side[0][1] = (float)(dot_v3db_v3fl(plane_b, tri_a[1]) + plane_b[3]);
+ side[0][2] = (float)(dot_v3db_v3fl(plane_b, tri_a[2]) + plane_b[3]);
+
if ((side[0][0] && side[0][1] && side[0][2]) && (side[0][0] < 0.0f) == (side[0][1] < 0.0f) &&
(side[0][0] < 0.0f) == (side[0][2] < 0.0f)) {
/* All vertices of the 1st triangle are positioned on the same side to the
@@ -2360,8 +2436,8 @@ bool isect_tri_tri_v3_ex(const float tri_a[3][3],
}
/* Direction of the line that intersects the planes of the triangles. */
- float isect_dir[3];
- cross_v3_v3v3(isect_dir, plane_a, plane_b);
+ double isect_dir[3];
+ cross_v3_v3v3_db(isect_dir, plane_a, plane_b);
for (int i = 0; i < 2; i++) {
const float(*tri)[3] = i == 0 ? tri_a : tri_b;
/* Rearrange the triangle so that the vertex that is alone on one side
@@ -2383,37 +2459,35 @@ bool isect_tri_tri_v3_ex(const float tri_a[3][3],
tri_i[2] = 2;
}
- float dot_b = dot_v3v3(isect_dir, tri[tri_i[1]]);
- range[i].min = dot_b;
- range[i].max = dot_b;
-
+ double dot_b = dot_v3db_v3fl(isect_dir, tri[tri_i[1]]);
float sidec = side[i][tri_i[1]];
if (sidec) {
- float dot_a = dot_v3v3(isect_dir, tri[tri_i[0]]);
- float dot_c = dot_v3v3(isect_dir, tri[tri_i[2]]);
+ double dot_a = dot_v3db_v3fl(isect_dir, tri[tri_i[0]]);
+ double dot_c = dot_v3db_v3fl(isect_dir, tri[tri_i[2]]);
float fac0 = sidec / (sidec - side[i][tri_i[0]]);
float fac1 = sidec / (sidec - side[i][tri_i[2]]);
- float offset0 = fac0 * (dot_a - dot_b);
- float offset1 = fac1 * (dot_c - dot_b);
+ double offset0 = fac0 * (dot_a - dot_b);
+ double offset1 = fac1 * (dot_c - dot_b);
if (offset0 > offset1) {
/* Sort min max. */
- SWAP(float, offset0, offset1);
+ SWAP(double, offset0, offset1);
SWAP(float, fac0, fac1);
SWAP(int, tri_i[0], tri_i[2]);
}
- range[i].min += offset0;
- range[i].max += offset1;
+ range[i].min = (float)(dot_b + offset0);
+ range[i].max = (float)(dot_b + offset1);
interp_v3_v3v3(range[i].loc[0], tri[tri_i[1]], tri[tri_i[0]], fac0);
interp_v3_v3v3(range[i].loc[1], tri[tri_i[1]], tri[tri_i[2]], fac1);
}
else {
+ range[i].min = range[i].max = (float)dot_b;
copy_v3_v3(range[i].loc[0], tri[tri_i[1]]);
copy_v3_v3(range[i].loc[1], tri[tri_i[1]]);
}
}
- if ((range[0].max >= range[1].min) && (range[0].min <= range[1].max)) {
+ if ((range[0].max > range[1].min) && (range[0].min < range[1].max)) {
/* The triangles intersect because they overlap on the intersection line.
* Now identify the two points of intersection that are in the middle to get the actual
* intersection between the triangles. (B--C from A--B--C--D) */
@@ -3290,10 +3364,16 @@ float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3],
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
{
- float h[2], u[2], lambda;
+ float h[2], u[2], lambda, denom;
sub_v2_v2v2(u, l2, l1);
sub_v2_v2v2(h, p, l1);
- lambda = dot_v2v2(u, h) / dot_v2v2(u, u);
+ denom = dot_v2v2(u, u);
+ if (denom == 0.0f) {
+ r_close[0] = l1[0];
+ r_close[1] = l1[1];
+ return 0.0f;
+ }
+ lambda = dot_v2v2(u, h) / denom;
r_close[0] = l1[0] + u[0] * lambda;
r_close[1] = l1[1] + u[1] * lambda;
return lambda;
@@ -3308,12 +3388,12 @@ double closest_to_line_v2_db(double r_close[2],
sub_v2_v2v2_db(u, l2, l1);
sub_v2_v2v2_db(h, p, l1);
denom = dot_v2v2_db(u, u);
- if (denom < DBL_EPSILON) {
+ if (denom == 0.0) {
r_close[0] = l1[0];
r_close[1] = l1[1];
return 0.0;
}
- lambda = dot_v2v2_db(u, h) / dot_v2v2_db(u, u);
+ lambda = dot_v2v2_db(u, h) / denom;
r_close[0] = l1[0] + u[0] * lambda;
r_close[1] = l1[1] + u[1] * lambda;
return lambda;
@@ -3403,7 +3483,7 @@ float line_plane_factor_v3(const float plane_co[3],
/**
* Ensure the distance between these points is no greater than 'dist'.
- * If it is, scale then both into the center.
+ * If it is, scale them both into the center.
*/
void limit_dist_v3(float v1[3], float v2[3], const float dist)
{
@@ -4176,6 +4256,7 @@ int interp_sparse_array(float *array, const int list_size, const float skipval)
return 1;
}
+/* -------------------------------------------------------------------- */
/** \name interp_weights_poly_v2, v3
* \{ */
@@ -4469,7 +4550,7 @@ void interp_cubic_v3(float x[3],
*
* Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
*
- * \note same basic result as #barycentric_weights_v2, see it's comment for details.
+ * \note same basic result as #barycentric_weights_v2, see its comment for details.
*/
void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
@@ -5491,7 +5572,7 @@ void vcloud_estimate_transform_v3(const int list_size,
stunt[1] = q[1][1];
stunt[2] = q[2][2];
/* renormalizing for numeric stability */
- mul_m3_fl(q, 1.f / len_v3(stunt));
+ mul_m3_fl(q, 1.0f / len_v3(stunt));
/* this is pretty much Polardecompose 'inline' the algo based on Higham's thesis */
/* without the far case ... but seems to work here pretty neat */