Medusa  1.1
Coordinate Free Mehless Method implementation
GeneralSurfaceFill.hpp
Go to the documentation of this file.
1 #ifndef MEDUSA_BITS_DOMAINS_GENERALSURFACEFILL_HPP_
2 #define MEDUSA_BITS_DOMAINS_GENERALSURFACEFILL_HPP_
3 
11 #include "compute_normal_fwd.hpp"
12 
18 #include <random>
19 
20 namespace mm {
21 
22 template <typename vec_t, typename param_vec_t>
23 GeneralSurfaceFill<vec_t, param_vec_t>::GeneralSurfaceFill() : seed_(get_seed()) {}
24 
25 template <typename vec_t, typename param_vec_t>
26 template <typename param_func_t, typename jm_func_t, typename spacing_func_t>
28  param_domain_t& param_domain, const param_func_t& param_function,
29  const jm_func_t& param_jacobian, const spacing_func_t& spacing_function, int type) const {
30  assert_msg(domain.size() >= param_domain.size(),
31  "Domain must contain all points corresponding to the parameters in the "
32  "parametric domain. ");
33  KDTreeMutable<vec_t> tree(domain.positions());
34  operator()(domain, param_domain, param_function, param_jacobian, spacing_function, tree, type);
35 }
36 template <typename vec_t, typename param_vec_t>
37 template <typename param_func_t, typename jm_func_t, typename spacing_func_t>
39  DomainShape<param_vec_t>& param_domain_shape, const param_func_t& param_function,
40  const jm_func_t& param_jacobian, const spacing_func_t& spacing_function, int type) const {
41  DomainDiscretization<param_vec_t> param_domain(param_domain_shape);
42  operator()(domain, param_domain, param_function, param_jacobian, spacing_function, type);
43 }
44 
45 template <typename vec_t, typename param_vec_t>
46 template <typename param_func_t, typename jm_func_t, typename search_t, typename spacing_func_t>
48  param_domain_t& param_domain, const param_func_t& param_function,
49  const jm_func_t& param_jacobian, const spacing_func_t& spacing_function, search_t& tree,
50  int type) const {
51  auto param = [&param_function, &param_jacobian](param_vec_t t) {
52  return std::make_pair(param_function(t), param_jacobian(t));
53  };
54  fillParametrization(domain, param_domain, param, spacing_function, tree, type);
55 }
56 
57 template <typename vec_t, typename param_vec_t>
58 template <typename param_func_t, typename search_t, typename spacing_func_t>
60  param_domain_t& param_domain, const param_func_t& param,
61  const spacing_func_t& spacing_function, search_t& tree, int type) const {
62  if (type == 0) type = -1;
63  std::mt19937 gen(seed_);
64  KDTree<param_vec_t> param_boundary_search;
65  param_domain.makeDiscreteContainsStructure(param_boundary_search);
66 
67  int cur_node = 0;
68  int end_node = param_domain.size();
69  if (end_node == 0) {
70  assert_msg(param_domain.shape().hasContains(),
71  "Parametric domain shape must have `contains` method implemented if empty "
72  "parametric domain is given. Try supplying an initial point.");
73  // If parameter domain is empty, pick a random node inside it.
74  param_vec_t lo_bound, hi_bound, random_node;
75  std::tie(lo_bound, hi_bound) = param_domain.shape().bbox();
76  std::vector<std::uniform_real_distribution<scalar_t>> distributions;
77  for (int j = 0; j < param_dim; ++j) distributions.emplace_back(lo_bound[j], hi_bound[j]);
78  int count = 0;
79  scalar_t d_sq, check_radius;
80  vec_t point;
81  Eigen::Matrix<scalar_t, dim, param_dim> jm;
82  do {
83  for (int j = 0; j < param_dim; ++j) { random_node[j] = distributions[j](gen); }
84  // Node must be at least spacing_function(random_node) away from other nodes
85  std::tie(point, jm) = param(random_node);
86  check_radius = spacing_function(point);
87  d_sq = tree.size() == 0 ? 10 * check_radius * check_radius :
88  tree.query(point).second[0];
89  if (++count >= 10000) {
90  std::string message = "No suitable node in parametric domain could be found after "
91  "10000 tries. This might happen if parametric domain volume "
92  "is very small compared to the volume of the bounding box or"
93  " if there are a lot of nodes in input domain.";
94  throw std::runtime_error(message);
95  }
96  } while (!param_domain.contains(random_node, param_boundary_search) ||
97  !(d_sq >= (zeta * check_radius) * (zeta * check_radius)));
98  param_domain.addInternalNode(random_node, 1);
99  vec_t normal = surface_fill_internal::compute_normal(jm);
100  tree.insert(point);
101  domain.addBoundaryNode(point, type, normal);
102  end_node = 1;
103  }
104 
105  // Main algorithm loop.
106  while (cur_node < end_node && end_node < max_points) {
107  param_vec_t param_point = param_domain.pos(cur_node);
108  vec_t initial_pt;
109  Eigen::Matrix<scalar_t, dim, param_dim> jm;
110  std::tie(initial_pt, jm) = param(param_point);
111 
113  construct(1, n_samples, gen);
114 
115  // Filter unit_candidates regarding the domain and proximity criteria.
116  for (const auto& u_cand : unit_candidates) {
117  scalar_t alpha = spacing_function(initial_pt) / (jm * u_cand).norm();
118  param_vec_t node = param_point + alpha * u_cand; // Shift center to point `param_point`
119  if (!param_domain.contains(node, param_boundary_search)) continue;
120 
121  vec_t new_pt;
122  Eigen::Matrix<scalar_t, dim, param_dim> new_jm;
123  std::tie(new_pt, new_jm) = param(node);
124 
125  scalar_t d_sq = tree.query(new_pt).second[0];
126  // Check radius must be new radius, otherwise algorithm might terminate in 2d.
127  scalar_t check_radius = (new_pt - initial_pt).norm();
128  // Check if node is far enough from other nodes.
129  if (d_sq < (zeta * check_radius) * (zeta * check_radius)) continue;
130 
131  // Insert into param domain.
132  param_domain.addInternalNode(node, 1);
133  // Insert into kd tree.
134  tree.insert(new_pt);
135  // Inser into domain.
136  vec_t normal = surface_fill_internal::compute_normal(jm);
137  domain.addBoundaryNode(new_pt, type, normal);
138 
139  end_node++;
140  }
141  cur_node++;
142  }
143  if (end_node >= max_points) {
144  std::cerr << "Maximum number of points reached, fill may be incomplete." << std::endl;
145  }
146 }
147 
148 template <typename vec_t, typename param_vec_t>
150  scalar_t zeta) {
151  assert_msg((0 < zeta && zeta < 1), "Zeta must be between 0 and 1, got %f.", zeta);
152  this->zeta = zeta;
153  return *this;
154 }
155 } // namespace mm
156 
157 #endif // MEDUSA_BITS_DOMAINS_GENERALSURFACEFILL_HPP_
mm::GeneralSurfaceFill::operator()
void operator()(domain_t &domain, param_domain_t &param_domain, const param_func_t &param_function, const jm_func_t &param_jacobian, const spacing_func_t &spacing_function, search_t &tree, int type=0) const
Fills the parametrically given surface with a quality node distribution according to the spacing_func...
Definition: GeneralSurfaceFill.hpp:47
mm
Root namespace for the whole library.
Definition: Gaussian.hpp:14
mm::DomainDiscretization
Class representing domain discretization along with an associated shape.
Definition: DomainDiscretization_fwd.hpp:46
mm::KDTree
Class representing a static k-d tree data structure.
Definition: KDTree_fwd.hpp:36
mm::KDTreeMutable
A k-d tree data structure that supports dynamic insertions and lazy-removal.
Definition: HalfLinksRefine_fwd.hpp:18
randutils.hpp
mm::GeneralSurfaceFill::scalar_t
vec_t::scalar_t scalar_t
Scalar type.
Definition: GeneralSurfaceFill_fwd.hpp:54
mm::DomainDiscretization::positions
const Range< vec_t > & positions() const
Returns positions of all nodes.
Definition: DomainDiscretization_fwd.hpp:127
assert_msg
#define assert_msg(cond,...)
Assert with better error reporting.
Definition: assert.hpp:75
mm::DomainShape
Base class for geometric shapes of domains.
Definition: DomainShape_fwd.hpp:52
mm::DomainDiscretization::size
int size() const
Returns N, the number of nodes in this discretization.
Definition: DomainDiscretization_fwd.hpp:189
compute_normal_fwd.hpp
KDTreeMutable.hpp
mm::DomainDiscretization::shape
const DomainShape< vec_t > & shape() const
Returns geometric shape of the underlying domain.
Definition: DomainDiscretization_fwd.hpp:162
mm::DomainDiscretization::contains
bool contains(const vec_t &point) const
Returns true if point is inside the domain.
Definition: DomainDiscretization.hpp:315
mm::DomainDiscretization::makeDiscreteContainsStructure
void makeDiscreteContainsStructure(search_structure_t &search) const
Fills the search structure search with boundary points for use with contains() or discreteContains().
Definition: DomainDiscretization.hpp:342
mm::get_seed
unsigned int get_seed()
Return a random seed.
Definition: randutils.hpp:25
KDTree.hpp
assert.hpp
mm::DomainDiscretization::addInternalNode
int addInternalNode(const vec_t &point, int type)
Adds a single interior node with specified type to this discretization.
Definition: DomainDiscretization.hpp:49
mm::DomainDiscretization::pos
const vec_t & pos(int i) const
Returns the position of i-th node.
Definition: DomainDiscretization_fwd.hpp:129
discretization_helpers.hpp
mm::surface_fill_internal::compute_normal
Vec< scalar_t, dim_to > compute_normal(Eigen::Matrix< scalar_t, dim_to, dim_from > J)
Compute normal from given Jacobian.
mm::GeneralSurfaceFill::proximityTolerance
GeneralSurfaceFill & proximityTolerance(scalar_t zeta)
Set proximity tolerance.
Definition: GeneralSurfaceFill.hpp:149
mm::GeneralSurfaceFill::fillParametrization
void fillParametrization(domain_t &domain, param_domain_t &param_domain, const param_func_t &param, const spacing_func_t &spacing_function, search_t &tree, int type=0) const
Version with single function returning a pair of point and jacobian.
Definition: GeneralSurfaceFill.hpp:59
mm::discretization_helpers::SphereDiscretization::construct
static std::vector< Eigen::Matrix< scalar_t, dim, 1 >, Eigen::aligned_allocator< Eigen::Matrix< scalar_t, dim, 1 > > > construct(scalar_t radius, int num_samples, generator_t &generator)
Construct a randomized discretization.
Definition: discretization_helpers.hpp:85
GeneralSurfaceFill_fwd.hpp
Range.hpp
mm::DomainDiscretization::addBoundaryNode
int addBoundaryNode(const vec_t &point, int type, const vec_t &normal)
Adds a boundary node with given type and normal to the domain.
Definition: DomainDiscretization.hpp:56
mm::GeneralSurfaceFill
Implements general n-d node placing algorithm for parametrically given d-d surfaces,...
Definition: GeneralSurfaceFill_fwd.hpp:49