Skip to content

Commit 201fc56

Browse files
committed
clusterizer: Adjust bounding sphere math wrt radii
Both when establishing the initial sphere, and when correcting the sphere for outlier points, we need to move the center point along the edge between the two points. The initial sphere center lies on the midpoint of the edge only if the two radii are the same; otherwise, we need to move it such that the distance between the point and the boundary of both spheres is the same. The computation is easy to derive, for example for initial sphere, the distance from first boundary to the resulting point for unknown k is: r1 + d * k == d * (1 - k) + r2 2d * k == d + r2 - r1 k = (d + r2 - r1) / 2d The derivation for the case where we need to expand the sphere is similar. Note that if the two points are the same or very close, k becomes indeterminate - but it also is irrelevant as the edge reduces to a point, as such there's no need to move anything. We guard against this unlikely case to avoid division by zero.
1 parent 49c1586 commit 201fc56

File tree

1 file changed

+13
-8
lines changed

1 file changed

+13
-8
lines changed

src/clusterizer.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,13 @@ static void computeBoundingSphere(float result[4], const float* points, size_t c
191191
// use the longest segment as the initial sphere diameter
192192
const float* p1 = points + pmin[paxis] * points_stride_float;
193193
const float* p2 = points + pmax[paxis] * points_stride_float;
194+
float r1 = radii[pmin[paxis] * radii_stride_float];
195+
float r2 = radii[pmax[paxis] * radii_stride_float];
194196

195-
float center[3] = {(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2, (p1[2] + p2[2]) / 2};
197+
float paxisd = sqrtf((p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]) + (p2[2] - p1[2]) * (p2[2] - p1[2]));
198+
float paxisk = paxisd > 0 ? (paxisd + r2 - r1) / (2 * paxisd) : 0.f;
199+
200+
float center[3] = {p1[0] + (p2[0] - p1[0]) * paxisk, p1[1] + (p2[1] - p1[1]) * paxisk, p1[2] + (p2[2] - p1[2]) * paxisk};
196201
float radius = paxisdr / 2;
197202

198203
// iteratively adjust the sphere up until all points fit
@@ -202,16 +207,16 @@ static void computeBoundingSphere(float result[4], const float* points, size_t c
202207
float r = radii[i * radii_stride_float];
203208

204209
float d2 = (p[0] - center[0]) * (p[0] - center[0]) + (p[1] - center[1]) * (p[1] - center[1]) + (p[2] - center[2]) * (p[2] - center[2]);
205-
float dr = sqrtf(d2) + r;
210+
float d = sqrtf(d2);
206211

207-
if (dr > radius)
212+
if (d + r > radius)
208213
{
209-
float k = 0.5f + (radius / dr) / 2;
214+
float k = d > 0 ? (d + r - radius) / (2 * d) : 0.f;
210215

211-
center[0] = center[0] * k + p[0] * (1 - k);
212-
center[1] = center[1] * k + p[1] * (1 - k);
213-
center[2] = center[2] * k + p[2] * (1 - k);
214-
radius = (radius + dr) / 2;
216+
center[0] += k * (p[0] - center[0]);
217+
center[1] += k * (p[1] - center[1]);
218+
center[2] += k * (p[2] - center[2]);
219+
radius = (radius + d + r) / 2;
215220
}
216221
}
217222

0 commit comments

Comments
 (0)