OGS
MinimalBoundingSphere.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <Eigen/Geometry>
7#include <ctime>
8
10#include "MathLib/MathTools.h"
11#include "MathLib/Point3d.h"
12
13namespace GeoLib
14{
16
18 double radius)
19 : _radius(radius), _center(p)
20{
21}
22
24 MathLib::Point3d const& q)
25 : _radius(std::numeric_limits<double>::epsilon()), _center(p)
26{
27 Eigen::Vector3d const a = q.asEigenVector3d() - p.asEigenVector3d();
28
29 Eigen::Vector3d o = a / 2;
30 _radius = o.norm() + std::numeric_limits<double>::epsilon();
31 o += p.asEigenVector3d();
32 _center = MathLib::Point3d{{o[0], o[1], o[2]}};
33}
34
36 MathLib::Point3d const& q,
37 MathLib::Point3d const& r)
38{
39 auto const& vp = p.asEigenVector3d();
40 Eigen::Vector3d const a = r.asEigenVector3d() - vp;
41 Eigen::Vector3d const b = q.asEigenVector3d() - vp;
42 Eigen::Vector3d const axb = a.cross(b);
43
44 if (axb.squaredNorm() > 0)
45 {
46 double const denom = 2.0 * axb.dot(axb);
47 Eigen::Vector3d o =
48 (b.dot(b) * axb.cross(a) + a.dot(a) * b.cross(axb)) / denom;
49 _radius = o.norm() + std::numeric_limits<double>::epsilon();
50 o += vp;
51 _center = MathLib::Point3d{{o[0], o[1], o[2]}};
52 }
53 else
54 {
55 MinimalBoundingSphere two_pnts_sphere;
56 if (a.squaredNorm() > b.squaredNorm())
57 {
58 two_pnts_sphere = MinimalBoundingSphere(p, r);
59 }
60 else
61 {
62 two_pnts_sphere = MinimalBoundingSphere(p, q);
63 }
64 _radius = two_pnts_sphere.getRadius();
65 _center = two_pnts_sphere.getCenter();
66 }
67}
68
70 MathLib::Point3d const& q,
71 MathLib::Point3d const& r,
72 MathLib::Point3d const& s)
73{
74 Eigen::Vector3d const va = q.asEigenVector3d() - p.asEigenVector3d();
75 Eigen::Vector3d const vb = r.asEigenVector3d() - p.asEigenVector3d();
76 Eigen::Vector3d const vc = s.asEigenVector3d() - p.asEigenVector3d();
77
78 if (!MathLib::isCoplanar(p, q, r, s))
79 {
80 double const denom = 2.0 * va.cross(vb).dot(vc);
81 Eigen::Vector3d o =
82 (vc.dot(vc) * va.cross(vb) + vb.dot(vb) * vc.cross(va) +
83 va.dot(va) * vb.cross(vc)) /
84 denom;
85
86 _radius = o.norm() + std::numeric_limits<double>::epsilon();
87 o += p.asEigenVector3d();
88 _center = MathLib::Point3d({o[0], o[1], o[2]});
89 }
90 else
91 {
92 MinimalBoundingSphere const pqr(p, q, r);
93 MinimalBoundingSphere const pqs(p, q, s);
94 MinimalBoundingSphere const prs(p, r, s);
95 MinimalBoundingSphere const qrs(q, r, s);
96 _radius = pqr.getRadius();
97 _center = pqr.getCenter();
98 if (_radius < pqs.getRadius())
99 {
100 _radius = pqs.getRadius();
101 _center = pqs.getCenter();
102 }
103 if (_radius < prs.getRadius())
104 {
105 _radius = prs.getRadius();
106 _center = prs.getCenter();
107 }
108 if (_radius < qrs.getRadius())
109 {
110 _radius = qrs.getRadius();
111 _center = qrs.getCenter();
112 }
113 }
114}
115
117 std::vector<MathLib::Point3d*> const& points)
118 : _radius(-1), _center({0, 0, 0})
119{
120 const std::vector<MathLib::Point3d*>& sphere_points(points);
121 MinimalBoundingSphere const bounding_sphere =
122 recurseCalculation(sphere_points, 0, sphere_points.size(), 0);
123 _center = bounding_sphere.getCenter();
124 _radius = bounding_sphere.getRadius();
125}
126
128 std::vector<MathLib::Point3d*> sphere_points,
129 std::size_t start_idx,
130 std::size_t length,
131 std::size_t n_boundary_points)
132{
134 switch (n_boundary_points)
135 {
136 case 0:
137 sphere = MinimalBoundingSphere();
138 break;
139 case 1:
140 sphere = MinimalBoundingSphere(*sphere_points[start_idx - 1]);
141 break;
142 case 2:
143 sphere = MinimalBoundingSphere(*sphere_points[start_idx - 1],
144 *sphere_points[start_idx - 2]);
145 break;
146 case 3:
147 sphere = MinimalBoundingSphere(*sphere_points[start_idx - 1],
148 *sphere_points[start_idx - 2],
149 *sphere_points[start_idx - 3]);
150 break;
151 case 4:
152 sphere = MinimalBoundingSphere(
153 *sphere_points[start_idx - 1], *sphere_points[start_idx - 2],
154 *sphere_points[start_idx - 3], *sphere_points[start_idx - 4]);
155 return sphere;
156 }
157
158 for (std::size_t i = 0; i < length; ++i)
159 {
160 // current point is located outside of sphere
161 if (sphere.pointDistanceSquared(*sphere_points[start_idx + i]) > 0)
162 {
163 if (i > start_idx)
164 {
165 using DiffType =
166 std::vector<MathLib::Point3d*>::iterator::difference_type;
167 std::vector<MathLib::Point3d*> const tmp_ps(
168 sphere_points.cbegin() + static_cast<DiffType>(start_idx),
169 sphere_points.cbegin() +
170 static_cast<DiffType>(start_idx + i + 1));
171 std::copy(tmp_ps.cbegin(), --tmp_ps.cend(),
172 sphere_points.begin() +
173 static_cast<DiffType>(start_idx + 1));
174 sphere_points[start_idx] = tmp_ps.back();
175 }
176 sphere = recurseCalculation(sphere_points, start_idx + 1, i,
177 n_boundary_points + 1);
178 }
179 }
180 return sphere;
181}
182
184 MathLib::Point3d const& pnt) const
185{
186 return MathLib::sqrDist(_center, pnt) - (_radius * _radius);
187}
188
189} // namespace GeoLib
MinimalBoundingSphere(MathLib::Point3d const &p, double radius=std::numeric_limits< double >::epsilon())
Point-Sphere.
static MinimalBoundingSphere recurseCalculation(std::vector< MathLib::Point3d * > sphere_points, std::size_t start_idx, std::size_t length, std::size_t n_boundary_points)
MinimalBoundingSphere()
Constructor using no points.
double getRadius() const
Returns the radius of the sphere.
MathLib::Point3d getCenter() const
Returns the center point of the sphere.
double pointDistanceSquared(MathLib::Point3d const &pnt) const
Eigen::Vector3d const & asEigenVector3d() const
Definition Point3d.h:55
bool isCoplanar(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
Checks if the four given points are located on a plane.
double sqrDist(MathLib::Point3d const &p0, MathLib::Point3d const &p1)
Definition Point3d.cpp:19