diff --git a/miniball.py b/miniball.py index 8b1bc0a..07fa4e8 100644 --- a/miniball.py +++ b/miniball.py @@ -23,7 +23,7 @@ __author__ = "Alexandre Devert " -__version__ = "1.2.0" +__version__ = "1.2.1" def get_circumsphere(S): @@ -79,7 +79,8 @@ def get_bounding_ball(S, epsilon=1e-7, rng=numpy.random.default_rng()): def circle_contains(D, p): c, r2 = D - return numpy.square(p - c).sum() <= r2 + distance = numpy.square(p - c).sum() + return distance <= r2 or numpy.isclose(distance, r2) def get_boundary(R): if len(R) == 0: diff --git a/test_miniball.py b/test_miniball.py index 13d077f..5b23576 100644 --- a/test_miniball.py +++ b/test_miniball.py @@ -94,3 +94,44 @@ def test_bounding_ball_optimality(): # equivalent up to machine precision. assert numpy.allclose(r2, r2_support) assert numpy.allclose(C, C_support) + + +def test_bounding_ball_3D_coplanar_cases(): + coplanar_points = [ + [numpy.array([[0.025728409071614222, 0.372152791836762, 0.3313301933484486], + [0.2531163257212625, 0.9836838066044385, 0.2053900271644188], + [0.01222939518218047, 0.8318221612473629, 0.6333422846064242], + [0.15230829793039352, 0.45195218214902, 0.10645228460244449] + ]), + [numpy.array([0.114472, 0.70108076, 0.33578222]), 0.11608885468045413]], + [numpy.array([[0.019703769768801283, 0.22959782389636796, 0.9347328105384431], + [0.025728409071614222, 0.372152791836762, 0.3313301933484486], + [0.07256394493759732, 0.18814654709738765, 0.6659776158852926], + [-0.28448686909485404, 0.9845638879736157, 0.4729161039578733], + [-0.29051150839766654, 0.8420089200332219, 1.0763187211478678], + [-0.3373470442636498, 1.0260151647725961, 0.7416712986110239] + ]), + [numpy.array([-0.13239155, 0.60708086, 0.70382446]), 0.2189450932893729]], + [numpy.array([[0.6230334535523369, 0.10461020463586657, 0.6246333540949156], + [0.4368180091809194, 0.47867605481000886, 0.4940056593092361], + [0.19956709139681328, 0.3156469527895308, 0.46603709980425945], + [0.19258810832074413, 0.00570894472836192, 0.77173157151973], + [0.07256394493759732, 0.18814654709738765, 0.6659776158852926], + [0.14079426383352756, 0.46309890200523474, 0.8713935666594159], + [0.3270097082049448, 0.08903305183109245, 1.0020212614450952], + [0.22415372406335649, -0.014249183710294266, 0.7522170325705094], + [0.2311327071394254, 0.29568882435087457, 0.4465225608550386], + [0.2954212758833918, 0.06960900045054658, 0.506756030291579] + ]), + [numpy.array([0.37123437, 0.27549227, 0.73929129]), 0.10574990180985341]], + [numpy.array([[165.9375, 90.9375, 39.19999933], + [169.6875, 87.1875, 39.19999933], + [165.9375, 87.1875, 39.19999933], + [169.6875, 90.9375, 39.19999933]]), + [numpy.array([167.8125, 89.0625, 39.19999933]), 7.031250000000002]], + ] + + for input, expected in coplanar_points: + C, r2 = miniball.get_bounding_ball(input) + assert numpy.allclose(C, expected[0]) + assert numpy.allclose(r2, expected[1])