1 #ifndef MEDUSA_BITS_DOMAINS_NURBSSHAPE_HPP_
2 #define MEDUSA_BITS_DOMAINS_NURBSSHAPE_HPP_
21 template <
typename vec_t,
typename param_vec_t>
23 : patches { patches_in }, seed_(
get_seed()) {
27 for (NURBSPatch<vec_t, param_vec_t>& patch : patches) {
28 patch.computeDerivativeStructure();
32 template <
typename vec_t,
typename param_vec_t>
34 : patches { patches_in }, seed_(
get_seed()) {
38 for (NURBSPatch<vec_t, param_vec_t> &patch : patches) {
39 patch.computeDerivativeStructure();
43 template <
typename vec_t,
typename param_vec_t>
45 const std::function<
scalar_t(vec_t)>& h,
int type)
const {
50 template <
typename vec_t,
typename param_vec_t>
53 assert_msg((0 < zeta && zeta < 1),
"Zeta must be between 0 and 1, got %f.", zeta);
58 template <
typename vec_t,
typename param_vec_t>
61 assert_msg((0 < epsilon && epsilon < 1),
"Epsilon must be between 0 and 1, got %f.", epsilon);
62 this->epsilon = epsilon;
67 template <
typename vec_t>
74 typedef Vec<scalar_t, proj_dim> proj_vec_t;
76 static DomainDiscretization<vec_t> discretizeBoundaryWithDensity(
77 const NURBSShape<vec_t, param_vec_t>& shape,
78 const std::function<
scalar_t(vec_t)>& h,
int type) {
79 if (type == 0) type = -1;
80 std::mt19937 gen(shape.seed_);
82 GeneralSurfaceFill<vec_t, param_vec_t> gsf;
83 gsf.seed(shape.seed_).maxPoints(shape.max_points).proximityTolerance(shape.zeta)
84 .numSamples(shape.n_samples);
87 DomainDiscretization<vec_t> domain(shape);
88 KDTreeMutable<vec_t> tree_global;
91 for (
const NURBSPatch<vec_t, param_vec_t>& patch : shape.patches) {
92 BoxShape<param_vec_t> bs = patch.getDomain();
93 DomainDiscretization<param_vec_t> local_param_d(bs);
96 Range<NURBSPatch<vec_t, Vec<scalar_t, 1>>> boundaries = patch.getBoundaries();
98 for (NURBSPatch<vec_t, Vec<scalar_t, 1>>& boundary : boundaries) {
100 boundary.computeDerivativeStructure();
102 KDTreeMutable<vec_t> tree_local;
104 BoxShape<Vec<scalar_t, 1>> boundary_bs = boundary.getDomain();
105 Vec<scalar_t, 1> t_min = boundary_bs.beg();
106 Vec<scalar_t, 1> t_max = boundary_bs.end();
108 std::uniform_real_distribution<> dis(t_min(0), t_max(0));
109 Vec<scalar_t, 1> t_seed = Vec<scalar_t, 1>(dis(gen));
112 param_vec_t param_seed = patch.getPatchParameterFromBoundaryParameter(t_seed,
115 vec_t pt_seed = boundary.evaluate(t_seed, &w_seed);
116 local_param_d.addInternalNode(param_seed, 1);
117 tree_local.insert(pt_seed);
120 scalar_t check_radius_seed = h(pt_seed);
121 scalar_t d_sq = tree_global.size() == 0 ? 10 * check_radius_seed * check_radius_seed
122 : tree_global.query(pt_seed).second[0];
123 if (d_sq >= (shape.zeta * check_radius_seed) * (shape.zeta * check_radius_seed)) {
126 domain.addBoundaryNode(pt_seed, type, normal_seed);
127 tree_global.insert(pt_seed);
131 int cur_node = local_param_d.size() - 1;
132 int end_node = local_param_d.size();
133 while (cur_node < end_node && end_node < shape.max_points) {
134 param_vec_t param = local_param_d.pos(cur_node);
135 Vec<scalar_t, 1> t = patch.getBoundaryParameterFromPatchParameter(param, i);
137 std::tie(pt, der) = boundary.evaluatePointAndJacobian(t);
139 std::array<Vec<scalar_t, 1>, 2> candidates{Vec<scalar_t, 1>(1),
140 Vec<scalar_t, 1>(-1)};
143 scalar_t alpha = h(pt) / der.norm();
144 for (
const auto& u_cand : candidates) {
145 Vec<scalar_t, 1> t_new = t + alpha * u_cand;
146 param_vec_t param_new = patch.getPatchParameterFromBoundaryParameter(
147 t_new, i, shape.epsilon);
148 if (!local_param_d.contains(param_new))
continue;
151 vec_t pt_new = boundary.evaluate(t_new, &w_new);
154 scalar_t check_radius = (pt - pt_new).norm();
157 scalar_t d_sq_loc = tree_local.query(pt_new).second[0];
158 if (d_sq_loc >= (shape.zeta * check_radius) *
159 (shape.zeta * check_radius)) {
160 local_param_d.addInternalNode(param_new, 1);
161 tree_local.insert(pt_new);
165 scalar_t d_sq_global = tree_global.query(pt_new).second[0];
166 if (d_sq_global >= (shape.zeta * check_radius) *
167 (shape.zeta * check_radius)) {
170 domain.addBoundaryNode(pt_new, type, normal_new);
171 tree_global.insert(pt_new);
181 std::uniform_real_distribution<> dis(0.0, 1.0);
182 param_vec_t param_another = bs.beg() + 0.25 * (bs.end() - bs.beg()) +
183 dis(gen) * 0.25 * (bs.end() - bs.beg());
184 local_param_d.addInternalNode(param_another, 1);
187 vec_t pt_another = patch.evaluate(param_another, &w_another);
188 scalar_t check_radius_another = h(pt_another);
189 scalar_t d_sq_another = tree_global.query(pt_another).second[0];
190 if (d_sq_another >= (shape.zeta * check_radius_another) *
191 (shape.zeta * check_radius_another)) {
193 compute_normal(patch.jacobian(param_another, pt_another, w_another));
194 domain.addBoundaryNode(pt_another, type, normal_another);
195 tree_global.insert(pt_another);
199 auto param = [&patch](
const param_vec_t& t) {
200 return patch.evaluatePointAndJacobian(t);
202 gsf.fillParametrization(domain, local_param_d, param, h, tree_global, type);
209 template <
typename vec_t>
210 struct nurbs_shape_internal::NURBSShapeHelper<vec_t,
Vec<typename vec_t::
scalar_t, 1>>{
211 typedef Vec<typename vec_t::scalar_t, 1> param_vec_t;
216 typedef Vec<scalar_t, proj_dim> proj_vec_t;
218 static DomainDiscretization<vec_t> discretizeBoundaryWithDensity(
219 const NURBSShape<vec_t, param_vec_t>& shape,
220 const std::function<
scalar_t(vec_t)>& h,
int type) {
221 if (type == 0) type = -1;
222 std::mt19937 gen(shape.seed_);
224 GeneralSurfaceFill<vec_t, param_vec_t> gsf;
225 gsf.seed(shape.seed_).maxPoints(shape.max_points).proximityTolerance(shape.zeta)
226 .numSamples(shape.n_samples);
229 DomainDiscretization<vec_t> domain(shape);
230 KDTreeMutable<vec_t> tree_global;
233 for (
const NURBSPatch<vec_t, param_vec_t>& patch : shape.patches) {
234 BoxShape<param_vec_t> bs = patch.getDomain();
235 DomainDiscretization<param_vec_t> local_param_d(bs);
238 std::array<param_vec_t, 2> param_seeds{
239 patch.getPatchParameterFromBoundaryParameter({}, 0, shape.epsilon),
240 patch.getPatchParameterFromBoundaryParameter({}, 1, shape.epsilon)};
245 for (
const Vec1d& param_seed : param_seeds) {
247 vec_t pt_seed = patch.evaluate(param_seed, &w_seed);
248 local_param_d.addInternalNode(param_seed, 1);
251 scalar_t check_radius_seed = h(pt_seed);
252 scalar_t d_sq = tree_global.size() == 0 ? 10 * check_radius_seed * check_radius_seed
253 : tree_global.query(pt_seed).second[0];
254 if (d_sq >= (shape.zeta * check_radius_seed) * (shape.zeta * check_radius_seed)) {
257 domain.addBoundaryNode(pt_seed, type, normal_seed);
258 tree_global.insert(pt_seed);
263 auto param = [&patch](
const param_vec_t& t) {
264 return patch.evaluatePointAndJacobian(t);
266 gsf.fillParametrization(domain, local_param_d, param, h, tree_global, type);
276 #endif // MEDUSA_BITS_DOMAINS_NURBSSHAPE_HPP_