HyperBallBoundary<dim,spacedim>::get_new_point(const std::vector<Point<spacedim> > &surrounding_points,
const std::vector<double> &weights) const
{
- Point<spacedim> middle = FlatManifold<spacedim>::get_new_point(surrounding_points, weights);
- middle -= center;
+ // Special cases where the points are vertices in one or two dimensions
+ switch(surrounding_points.size()) {
+ case 2:
+ return get_intermediate_point(surrounding_points[0], surrounding_points[1], weights[1]);
+ break;
+ case 4:
+ {
+ Point<spacedim> v[2];
+ // Coordinates of the point in the reference element
+ double xi1 = weights[1]+weights[3]; // = x
+ double xi2 = weights[2]+weights[3]; // = y
+
+ v[0] = get_intermediate_point(surrounding_points[0],
+ surrounding_points[1],
+ xi1);
+ v[1] = get_intermediate_point(surrounding_points[2],
+ surrounding_points[3],
+ xi1);
+ return get_intermediate_point(v[0], v[1], xi2);
+ }
+ break;
+ default:
+ {
+ Point<spacedim> middle = FlatManifold<spacedim>::get_new_point(surrounding_points, weights);
+ middle -= center;
+
+ double r=0;
+ if (compute_radius_automatically)
+ {
+ const Point<spacedim> vertex_relative = surrounding_points[0] - center;
+ r = std::sqrt(vertex_relative.square());
+ }
+ else
+ r=radius;
+ // project to boundary
+ middle *= r / std::sqrt(middle.square());
+ middle += center;
+ return middle;
+ }
+ break;
+ }
+}
+
+
+template <int dim, int spacedim>
+Point<spacedim>
+HyperBallBoundary<dim,spacedim>::get_intermediate_point(const Point<spacedim> &p0,
+ const Point<spacedim> &p1,
+ const double xi) const {
+ const Point<spacedim> v0=p0-center,
+ v1=p1-center;
+ const double length=std::sqrt((v1-v0).square());
+
+ double eps=1e-12;
double r=0;
if (compute_radius_automatically)
{
- const Point<spacedim> vertex_relative = surrounding_points[0] - center;
+ const Point<spacedim> vertex_relative = p0 - center;
r = std::sqrt(vertex_relative.square());
}
else
r=radius;
- // project to boundary
- middle *= r / std::sqrt(middle.square());
- middle += center;
- return middle;
+
+ const double r2=r*r;
+ Assert(std::fabs(v0.square()-r2)<eps*r2, ExcInternalError());
+ Assert(std::fabs(v1.square()-r2)<eps*r2, ExcInternalError());
+
+ const double alpha=std::acos((v0*v1)/std::sqrt(v0.square()*v1.square()));
+ const Point<spacedim> pm=0.5*(v0+v1);
+
+ const double h=std::sqrt(pm.square());
+
+ const double beta = alpha * (xi-0.5);
+ const double d=h*std::tan(beta);
+ Point<spacedim> p=pm+d/length*(v1-v0);
+
+ p *= r / std::sqrt(p.square());
+ p += center;
+
+ return p;
}