OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::AdaptiveInfillField Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Fill/AdaptiveInfillField.hpp>

Collaboration diagram for Slic3r::AdaptiveInfillField:

Classes

struct  Slice
struct  Radial
struct  Lobe
struct  Body

Public Types

using Radials = std::array<Radial, 2 * MaxMorph>

Public Member Functions

 AdaptiveInfillField (const std::vector< Slice > &slices, const BoundingBox &bbox, AdaptiveInfillMode mode, const std::function< void()> &throw_if_canceled)
bool empty () const
size_t radial (const Vec3d &pt, Radials &out) const
int axis () const
AdaptiveInfillMode mode () const
double depth (const Vec3d &pt) const

Static Public Attributes

static constexpr size_t MaxMorph = 4

Private Member Functions

double radial (const Lobe &lobe, const Vec3d &pt) const
size_t body_radial (size_t node, const Vec3d &pt, float weight, Radial *out) const
Vec3d offset (const Vec3d &pt, const Vec3d &center) const
int directions () const

Private Attributes

AdaptiveInfillMode m_mode
int m_axis
Vec3d m_origin
double m_cell
Vec3i32 m_size
std::vector< int > m_body
std::vector< Body > m_bodies
std::vector< Lobe > m_lobes
std::vector< int > m_section
std::vector< float > m_depth

Static Private Attributes

static constexpr int Polar = 24
static constexpr int Azimuth = 48

Detailed Description


Class Documentation

◆ Slic3r::AdaptiveInfillField::Slice

struct Slic3r::AdaptiveInfillField::Slice
Collaboration diagram for Slic3r::AdaptiveInfillField::Slice:
Class Members
coordf_t bottom_z
const ExPolygons * expolygons
coordf_t top_z

◆ Slic3r::AdaptiveInfillField::Radial

struct Slic3r::AdaptiveInfillField::Radial
Class Members
Vec3d center
double t
float weight

◆ Slic3r::AdaptiveInfillField::Lobe

struct Slic3r::AdaptiveInfillField::Lobe
Collaboration diagram for Slic3r::AdaptiveInfillField::Lobe:
Class Members
Vec3d center
double depth
vector< float > mean_depth
vector< float > reach

◆ Slic3r::AdaptiveInfillField::Body

struct Slic3r::AdaptiveInfillField::Body
Class Members
double depth
size_t first_lobe
size_t lobes

Member Typedef Documentation

◆ Radials

Constructor & Destructor Documentation

◆ AdaptiveInfillField()

Slic3r::AdaptiveInfillField::AdaptiveInfillField ( const std::vector< Slice > & slices,
const BoundingBox & bbox,
AdaptiveInfillMode mode,
const std::function< void()> & throw_if_canceled )
217 : m_mode(mode)
219{
220 assert(!slices.empty() && mode != AdaptiveInfillMode::Disabled);
221 const Vec3d min(unscaled(bbox.min.x()), unscaled(bbox.min.y()), slices.front().bottom_z);
222 const Vec3d extent = Vec3d(unscaled(bbox.max.x()), unscaled(bbox.max.y()), slices.back().top_z) - min;
223
224 // Padded by a node on each side, so that the border of the grid is outside.
225 m_cell = std::max(MinCellSize, std::cbrt(extent.prod() / MaxNodes));
226 auto nodes = [this](double length) { return int(std::ceil(length / m_cell)) + 3; };
227 while (double(nodes(extent.x())) * nodes(extent.y()) * nodes(extent.z()) > MaxNodes)
228 m_cell *= 1.1;
229 m_size = Vec3i32(nodes(extent.x()), nodes(extent.y()), nodes(extent.z()));
230 m_origin = min - Vec3d::Constant(m_cell);
231
232 const size_t sy = size_t(m_size.x());
233 const size_t sz = sy * m_size.y();
234 std::vector<float> depth(sz * m_size.z(), 0.f);
235 tbb::parallel_for(tbb::blocked_range<int>(0, m_size.z()), [&](const tbb::blocked_range<int> &range) {
236 for (int k = range.begin(); k < range.end(); ++k) {
237 const double z = m_origin.z() + k * m_cell;
238 auto it = std::lower_bound(slices.begin(), slices.end(), z, [](const Slice &s, double z) { return s.top_z < z; });
239 if (it != slices.end() && z > it->bottom_z)
240 rasterize(*it->expolygons, m_origin.head<2>(), m_cell, m_size.x(), m_size.y(), depth.data() + k * sz);
241 }
242 throw_if_canceled();
243 });
244 for (int axis = 0; axis < 3; ++axis)
245 if (axis != m_axis)
246 distance_transform_axis(depth, m_size, axis, throw_if_canceled);
247
248 auto position = [this, sy, sz](size_t i) {
249 return Vec3d(m_origin + m_cell * Vec3d(double(i % sy), double(i / sy % m_size.y()), double(i / sz)));
250 };
251 const std::array<std::ptrdiff_t, 6> steps{1, -1, std::ptrdiff_t(sy), -std::ptrdiff_t(sy), std::ptrdiff_t(sz), -std::ptrdiff_t(sz)};
252
253 auto node_of = [this, sy, sz](const Vec3d &pt) -> std::ptrdiff_t {
254 const Vec3d f = (pt - m_origin) / m_cell;
255 const long x = std::lround(f.x()), y = std::lround(f.y()), z = std::lround(f.z());
256 if (x < 0 || y < 0 || z < 0 || x >= m_size.x() || y >= m_size.y() || z >= m_size.z())
257 return -1;
258 return std::ptrdiff_t(size_t(z) * sz + size_t(y) * sy + size_t(x));
259 };
260 // In the 2D modes, the steps within a section.
261 auto in_section = [this](size_t step) { return int(step / 2) != m_axis; };
262 std::vector<std::ptrdiff_t> neighbours;
263 for (int dz = -1; dz <= 1; ++dz)
264 for (int dy = -1; dy <= 1; ++dy)
265 for (int dx = -1; dx <= 1; ++dx)
266 if ((dx != 0 || dy != 0 || dz != 0) && (m_axis < 0 || Vec3i32(dx, dy, dz)[m_axis] == 0))
267 neighbours.push_back(std::ptrdiff_t(dz) * std::ptrdiff_t(sz) + std::ptrdiff_t(dy) * std::ptrdiff_t(sy) + dx);
268
269 // Bodies are the connected inside nodes, none of which is on the border. The deepest nodes of a body are the
270 // centers of its lobes, unless the depth between them stays above NeckRatio; where the depth ties, the center
271 // is the node nearest to the middle of the tied nodes.
273 m_body.assign(depth.size(), -1);
274 std::vector<size_t> body_nodes;
275 for (size_t seed = 0; seed < depth.size(); ++seed) {
276 if (depth[seed] == 0.f || m_body[seed] >= 0)
277 continue;
278 const int id = int(m_bodies.size());
279 body_nodes.assign(1, seed);
280 m_body[seed] = id;
281 float max_depth = 0.f;
282 for (size_t k = 0; k < body_nodes.size(); ++k) {
283 max_depth = std::max(max_depth, depth[body_nodes[k]]);
284 for (size_t s = 0; s < steps.size(); ++s)
285 if (const size_t j = body_nodes[k] + steps[s]; in_section(s) && depth[j] > 0.f && m_body[j] < 0) {
286 m_body[j] = id;
287 body_nodes.push_back(j);
288 }
289 }
290 m_bodies.push_back({m_lobes.size(), 0, (std::sqrt(double(max_depth)) - 0.5) * m_cell});
291 if (!lobes)
292 continue;
293
294 std::vector<size_t> peaks;
295 for (size_t i : body_nodes)
296 if (depth[i] >= sqr(MinLobeRatio) * max_depth &&
297 std::all_of(neighbours.begin(), neighbours.end(), [&](std::ptrdiff_t n) { return depth[i + n] <= depth[i]; }))
298 peaks.push_back(i);
299 std::sort(peaks.begin(), peaks.end(), [&depth](size_t a, size_t b) { return depth[a] > depth[b] || (depth[a] == depth[b] && a < b); });
300 auto necked = [&](size_t a, size_t b) {
301 const Vec3d pa = position(a), pb = position(b);
302 const double limit = sqr(NeckRatio) * std::min(depth[a], depth[b]);
303 const int samples = int(std::ceil((pb - pa).norm() / (0.5 * m_cell)));
304 for (int s = 1; s < samples; ++s)
305 if (depth[node_of(pa + (pb - pa) * (double(s) / samples))] < limit)
306 return true;
307 return false;
308 };
309 // A peak joins the first lobe it sees without a neck, if it is as deep. The lobes are made one at a time,
310 // from the first remaining peak, testing the others in parallel.
311 std::vector<std::vector<size_t>> ties;
312 while (!peaks.empty()) {
313 const size_t front = peaks.front();
314 std::vector<char> joins(peaks.size(), 0);
315 tbb::parallel_for(tbb::blocked_range<size_t>(1, peaks.size()), [&](const tbb::blocked_range<size_t> &range) {
316 for (size_t k = range.begin(); k < range.end(); ++k)
317 if (!necked(front, peaks[k]))
318 joins[k] = std::sqrt(depth[peaks[k]]) >= std::sqrt(depth[front]) - 1.f ? 1 : 2;
319 });
320 std::vector<size_t> &tied = ties.emplace_back(1, front);
321 std::vector<size_t> remaining;
322 for (size_t k = 1; k < peaks.size(); ++k)
323 if (joins[k] == 0)
324 remaining.push_back(peaks[k]);
325 else if (joins[k] == 1)
326 tied.push_back(peaks[k]);
327 peaks = std::move(remaining);
328 }
329 m_bodies.back().lobes = ties.size();
330 for (const std::vector<size_t> &tied : ties) {
331 Vec3d middle(0., 0., 0.);
332 for (size_t i : tied)
333 middle += position(i);
334 middle /= double(tied.size());
335 Vec3d center = position(tied.front());
336 for (size_t i : tied)
337 if ((position(i) - middle).squaredNorm() < (center - middle).squaredNorm())
338 center = position(i);
339 m_lobes.push_back({center, (std::sqrt(double(depth[tied.front()])) - 0.5) * m_cell, {}});
340 }
341 }
342 throw_if_canceled();
343
345 m_depth.assign(depth.size(), 0.f);
346 for (size_t i = 0; i < depth.size(); ++i)
347 if (m_body[i] >= 0)
348 m_depth[i] = float(std::min(1., std::max(0., std::sqrt(double(depth[i])) - 0.5) * m_cell / m_bodies[m_body[i]].depth));
349 }
350
351 // The reach of a lobe is the first exit along each direction from its center, smoothed over the directions.
352 // It is shortened towards a neighbouring lobe, from where the point is nearer to the other lobe relative to their depths.
353 std::vector<int> lobe_body(m_lobes.size());
354 for (size_t id = 0; id < m_bodies.size(); ++id)
355 std::fill_n(lobe_body.begin() + m_bodies[id].first_lobe, m_bodies[id].lobes, int(id));
356 const int rows = this->directions() / Azimuth;
357 auto direction = [this](int i, int j) {
358 const double azimuth = j * 2. * PI / Azimuth;
359 Vec3d dir = Vec3d::Zero();
360 if (m_axis < 0) {
361 const double polar = (i + 0.5) * PI / Polar;
362 dir = Vec3d(std::sin(polar) * std::cos(azimuth), std::sin(polar) * std::sin(azimuth), std::cos(polar));
363 } else {
364 dir[(m_axis + 1) % 3] = std::cos(azimuth);
365 dir[(m_axis + 2) % 3] = std::sin(azimuth);
366 }
367 return dir;
368 };
369 // Two passes of a box filter over the neighbouring directions, for each of the values of a direction.
370 auto smooth = [rows](std::vector<double> &values, size_t count) {
371 for (int pass = 0; pass < 2; ++pass) {
372 std::vector<double> smoothed(values.size(), 0.);
373 for (int i = 0; i < rows; ++i)
374 for (int j = 0; j < Azimuth; ++j)
375 for (size_t k = 0; k < count; ++k) {
376 double &sum = smoothed[size_t(i * Azimuth + j) * count + k];
377 for (int di = -1; di <= 1; ++di)
378 for (int dj = -1; dj <= 1; ++dj)
379 sum += values[size_t(std::clamp(i + di, 0, rows - 1) * Azimuth + (j + dj + Azimuth) % Azimuth) * count + k];
380 sum /= 9.;
381 }
382 values = std::move(smoothed);
383 }
384 };
385 tbb::parallel_for(tbb::blocked_range<size_t>(0, m_lobes.size()), [&](const tbb::blocked_range<size_t> &range) {
386 for (size_t l = range.begin(); l < range.end(); ++l) {
387 const int id = lobe_body[l];
388 const Body &body = m_bodies[id];
389 Lobe &lobe = m_lobes[l];
390 // The other lobes of the body, by the distance from the center beyond which they may be nearer.
391 std::vector<std::pair<double, size_t>> others;
392 for (size_t k = body.first_lobe; k < body.first_lobe + body.lobes; ++k)
393 if (k != l)
394 others.emplace_back((m_lobes[k].center - lobe.center).norm() / (1. + m_lobes[k].depth / lobe.depth), k);
395 std::sort(others.begin(), others.end());
396 auto nearer_lobe = [&](const Vec3d &pt, double r) {
397 for (auto it = others.begin(); it != others.end() && it->first < r; ++it)
398 if ((pt - m_lobes[it->second].center).norm() / m_lobes[it->second].depth < r / lobe.depth)
399 return true;
400 return false;
401 };
402 const double step = 0.5 * m_cell;
403 std::vector<double> log_reach(this->directions());
404 for (int i = 0; i < rows; ++i)
405 for (int j = 0; j < Azimuth; ++j) {
406 const Vec3d dir = direction(i, j);
407 double r = 0.;
408 double limit = InfD;
409 for (;;) {
410 const Vec3d pt = lobe.center + (r + step) * dir;
411 const std::ptrdiff_t n = node_of(pt);
412 if (n < 0 || depth[n] == 0.f || m_body[n] != id || r + step >= limit)
413 break;
414 if (limit == InfD && nearer_lobe(pt, r + step))
415 limit = LobeReach * (r + step);
416 r += step;
417 }
418 log_reach[i * Azimuth + j] = std::log(std::min(r + 0.5 * step, limit));
419 }
420 smooth(log_reach, 1);
421 lobe.reach.resize(log_reach.size());
422 std::transform(log_reach.begin(), log_reach.end(), lobe.reach.begin(), [](double v) { return float(std::exp(v)); });
423
424 if (m_mode == AdaptiveInfillMode::DistanceWarp) {
425 std::vector<double> mean(log_reach.size() * (Samples + 1));
426 for (size_t d = 0; d < log_reach.size(); ++d) {
427 const Vec3d dir = direction(int(d) / Azimuth, int(d) % Azimuth);
428 double integral = 0.;
429 double previous = this->depth(lobe.center);
430 mean[d * (Samples + 1)] = previous;
431 for (int k = 1; k <= Samples; ++k) {
432 // Exact for a depth linear between the samples, a + b * tau, weighted by tau^2.
433 const double t0 = double(k - 1) / Samples;
434 const double t1 = double(k) / Samples;
435 const double d1 = this->depth(lobe.center + t1 * lobe.reach[d] * dir);
436 const double b = (d1 - previous) * Samples;
437 const double a = previous - b * t0;
438 integral += a * (std::pow(t1, 3) - std::pow(t0, 3)) / 3. + b * (std::pow(t1, 4) - std::pow(t0, 4)) / 4.;
439 previous = d1;
440 mean[d * (Samples + 1) + k] = 3. * integral / std::pow(t1, 3);
441 }
442 }
443 // Smoothed like the reach: sharper profiles shear the pattern across the layer, adding lines.
444 smooth(mean, Samples + 1);
445 lobe.mean_depth.assign(mean.begin(), mean.end());
446 }
447 }
448 throw_if_canceled();
449 });
450
451 // Every other node belongs to its nearest body, within its section in the 2D modes.
452 if (m_axis >= 0) {
453 std::vector<bool> has_body(m_size[m_axis], false);
454 for (size_t i = 0; i < m_body.size(); ++i)
455 if (m_body[i] >= 0)
456 has_body[m_axis == 0 ? i % sy : m_axis == 1 ? i / sy % m_size.y() : i / sz] = true;
457 m_section.assign(m_size[m_axis], -1);
458 for (int k = 0; k < m_size[m_axis]; ++k)
459 for (int d = 0; d < m_size[m_axis] && m_section[k] < 0; ++d)
460 if (k - d >= 0 && has_body[k - d])
461 m_section[k] = k - d;
462 else if (k + d < m_size[m_axis] && has_body[k + d])
463 m_section[k] = k + d;
464 }
465 // Stepped shells and Smooth blend only look up the depth.
466 if (!lobes) {
467 m_body = {};
468 return;
469 }
470 if (m_bodies.size() == 1) {
471 std::fill(m_body.begin(), m_body.end(), 0);
472 return;
473 }
474 std::deque<size_t> queue;
475 for (size_t i = 0; i < m_body.size(); ++i)
476 if (m_body[i] >= 0)
477 queue.push_back(i);
478 while (!queue.empty()) {
479 const size_t i = queue.front();
480 queue.pop_front();
481 const size_t x = i % sy, y = i / sy % m_size.y(), z = i / sz;
482 const std::array<bool, 6> valid{x + 1 < sy, x > 0, y + 1 < size_t(m_size.y()), y > 0, z + 1 < size_t(m_size.z()), z > 0};
483 for (size_t k = 0; k < steps.size(); ++k)
484 if (valid[k] && in_section(k) && m_body[i + steps[k]] < 0) {
485 m_body[i + steps[k]] = m_body[i];
486 queue.push_back(i + steps[k]);
487 }
488 }
489}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
static constexpr int Azimuth
Definition AdaptiveInfillField.hpp:92
std::vector< int > m_section
Definition AdaptiveInfillField.hpp:104
Vec3d m_origin
Definition AdaptiveInfillField.hpp:96
double m_cell
Definition AdaptiveInfillField.hpp:97
std::vector< Body > m_bodies
Definition AdaptiveInfillField.hpp:101
double depth(const Vec3d &pt) const
Definition AdaptiveInfillField.cpp:491
int axis() const
Definition AdaptiveInfillField.hpp:58
AdaptiveInfillMode m_mode
Definition AdaptiveInfillField.hpp:94
Vec3i32 m_size
Definition AdaptiveInfillField.hpp:98
int directions() const
Definition AdaptiveInfillField.hpp:88
std::vector< Lobe > m_lobes
Definition AdaptiveInfillField.hpp:102
std::vector< int > m_body
Definition AdaptiveInfillField.hpp:100
int m_axis
Definition AdaptiveInfillField.hpp:95
std::vector< float > m_depth
Definition AdaptiveInfillField.hpp:106
AdaptiveInfillMode mode() const
Definition AdaptiveInfillField.hpp:59
static constexpr int Polar
Definition AdaptiveInfillField.hpp:91
static constexpr double PI
Definition libslic3r.h:81
void distance_transform_axis(std::vector< float > &grid, const Vec3i32 &size, int axis, const std::function< void()> &throw_if_canceled)
Definition AdaptiveInfillField.cpp:86
double length(const Points &pts)
Definition MultiPoint.hpp:181
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
@ SmoothBlend
Definition PrintConfig.hpp:293
@ NormalX
Definition PrintConfig.hpp:298
@ SteppedShells
Definition PrintConfig.hpp:294
@ NormalZ
Definition PrintConfig.hpp:296
@ DistanceWarp
Definition PrintConfig.hpp:292
@ Disabled
Definition PrintConfig.hpp:291
@ NormalY
Definition PrintConfig.hpp:297
auto range(Cont &&cont)
Definition libslic3r.h:405
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::Point &v) noexcept
Definition Arrange.cpp:81
constexpr T sqr(T x)
Definition libslic3r.h:301
Eigen::Matrix< int32_t, 3, 1, Eigen::DontAlign > Vec3i32
Definition Point.hpp:59
void step(Coord &crd, const Dir d, const long n=1)
Definition MarchingSquares.hpp:213
size_t rows(const T &raster)
Definition MarchingSquares.hpp:171

References depth(), Slic3r::Disabled, Slic3r::length(), m_axis, m_cell, m_mode, m_origin, m_size, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, mode(), Slic3r::range(), and Slic3r::unscaled().

Here is the call graph for this function:

Member Function Documentation

◆ axis()

int Slic3r::AdaptiveInfillField::axis ( ) const
inline
58{ return m_axis; }

References m_axis.

Referenced by radial().

Here is the caller graph for this function:

◆ body_radial()

size_t Slic3r::AdaptiveInfillField::body_radial ( size_t node,
const Vec3d & pt,
float weight,
Radial * out ) const
private
592{
593 const Body &body = m_bodies[m_body[node]];
594 if (body.lobes == 1) {
595 const Lobe &lobe = m_lobes[body.first_lobe];
596 out[0] = {lobe.center, radial(lobe, pt), weight};
597 return 1;
598 }
599
600 // The lobes nearest relative to their depth; they morph into each other near the sides where they are as near.
601 std::array<std::pair<double, size_t>, MaxMorph> nearest;
602 size_t count = 0;
603 for (size_t l = body.first_lobe; l < body.first_lobe + body.lobes; ++l) {
604 const double d = this->offset(pt, m_lobes[l].center).norm() / m_lobes[l].depth;
605 if (count < MaxMorph)
606 nearest[count++] = {d, l};
607 else if (d < nearest.back().first)
608 nearest.back() = {d, l};
609 else
610 continue;
611 for (size_t k = count - 1; k > 0 && nearest[k].first < nearest[k - 1].first; --k)
612 std::swap(nearest[k], nearest[k - 1]);
613 }
614 std::array<double, MaxMorph> blend;
615 double total = 0.;
616 size_t morphs = 0;
617 for (; morphs < count; ++morphs) {
618 const double u = 0.5 - (nearest[morphs].first - nearest[0].first) / LobeMorph;
619 if (u <= 0.)
620 break;
621 blend[morphs] = u * u * (3. - 2. * u);
622 total += blend[morphs];
623 }
624 for (size_t k = 0; k < morphs; ++k) {
625 const Lobe &lobe = m_lobes[nearest[k].second];
626 out[k] = {lobe.center, radial(lobe, pt), float(weight * blend[k] / total)};
627 }
628 return morphs;
629}
Vec3d offset(const Vec3d &pt, const Vec3d &center) const
Definition AdaptiveInfillField.cpp:511
size_t radial(const Vec3d &pt, Radials &out) const
Definition AdaptiveInfillField.cpp:565
static constexpr size_t MaxMorph
Definition AdaptiveInfillField.hpp:46
Definition AdaptiveInfillField.hpp:67
Definition AdaptiveInfillField.hpp:77

References body_radial(), Slic3r::AdaptiveInfillField::Lobe::center, Slic3r::center(), count, Slic3r::AdaptiveInfillField::Body::first_lobe, Slic3r::AdaptiveInfillField::Body::lobes, m_bodies, m_body, m_lobes, MaxMorph, offset(), and radial().

Referenced by body_radial(), and radial().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ depth()

double Slic3r::AdaptiveInfillField::depth ( const Vec3d & pt) const
492{
493 assert(!m_depth.empty());
494 const Vec3d f = (pt - m_origin) / m_cell;
495 std::array<int, 3> n0;
496 std::array<double, 3> w;
497 for (int a = 0; a < 3; ++a) {
498 n0[a] = std::clamp(int(std::floor(f[a])), 0, m_size[a] - 2);
499 w[a] = std::clamp(f[a] - n0[a], 0., 1.);
500 }
501 const size_t sy = size_t(m_size.x());
502 const size_t sz = sy * size_t(m_size.y());
503 double value = 0.;
504 for (int c = 0; c < 8; ++c) {
505 const size_t n = size_t(n0[2] + (c >> 2)) * sz + size_t(n0[1] + (c >> 1 & 1)) * sy + size_t(n0[0] + (c & 1));
506 value += (c & 1 ? w[0] : 1. - w[0]) * (c >> 1 & 1 ? w[1] : 1. - w[1]) * (c >> 2 ? w[2] : 1. - w[2]) * m_depth[n];
507 }
508 return value;
509}

References depth(), Slic3r::f(), m_cell, m_depth, m_origin, and m_size.

Referenced by AdaptiveInfillField(), and depth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ directions()

int Slic3r::AdaptiveInfillField::directions ( ) const
inlineprivate
88{ return m_axis < 0 ? Polar * Azimuth : Azimuth; }

References Azimuth, m_axis, and Polar.

◆ empty()

bool Slic3r::AdaptiveInfillField::empty ( ) const
inline
50{ return m_bodies.empty(); }

References m_bodies.

Referenced by radial().

Here is the caller graph for this function:

◆ mode()

AdaptiveInfillMode Slic3r::AdaptiveInfillField::mode ( ) const
inline
59{ return m_mode; }

References m_mode.

Referenced by AdaptiveInfillField().

Here is the caller graph for this function:

◆ offset()

Vec3d Slic3r::AdaptiveInfillField::offset ( const Vec3d & pt,
const Vec3d & center ) const
private
512{
513 Vec3d d = pt - center;
514 if (m_axis >= 0)
515 d[m_axis] = 0.;
516 return d;
517}

References Slic3r::center(), m_axis, and offset().

Referenced by body_radial(), offset(), and radial().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ radial() [1/2]

double Slic3r::AdaptiveInfillField::radial ( const Lobe & lobe,
const Vec3d & pt ) const
private
520{
521 const Vec3d d = this->offset(pt, lobe.center);
522 const double r = d.norm();
523 // Distance warp: the radial coordinate of the linear profile with the same mean depth, which is 1 - 3/4 of it.
524 auto warp = [](double mean_depth) { return std::max(0., 4. / 3. * (1. - mean_depth)); };
525 if (r < EPSILON)
526 return lobe.mean_depth.empty() ? 0. : warp(lobe.mean_depth.front());
527 int i = 0;
528 double fi = 0.;
529 double azimuth;
530 if (m_axis < 0) {
531 const double polar = std::clamp(std::acos(std::clamp(d.z() / r, -1., 1.)) / PI * Polar - 0.5, 0., double(Polar - 1));
532 i = std::min(int(polar), Polar - 2);
533 fi = polar - i;
534 azimuth = std::atan2(d.y(), d.x());
535 } else
536 azimuth = std::atan2(d[(m_axis + 2) % 3], d[(m_axis + 1) % 3]);
537 azimuth *= Azimuth / (2. * PI);
538 if (azimuth < 0.)
539 azimuth += Azimuth;
540 const int j0 = int(azimuth) % Azimuth;
541 const int j1 = (j0 + 1) % Azimuth;
542 const double fj = azimuth - std::floor(azimuth);
543 auto at = [&lobe](int i, int j) { return double(lobe.reach[i * Azimuth + j]); };
544 double reach = at(i, j0) * (1. - fj) + at(i, j1) * fj;
545 if (fi > 0.)
546 reach = reach * (1. - fi) + (at(i + 1, j0) * (1. - fj) + at(i + 1, j1) * fj) * fi;
547 const double tau = r / reach;
548 if (lobe.mean_depth.empty())
549 return tau;
550 // Beyond the surface, the depth is zero.
551 auto mean_at = [&lobe, tau](int i, int j) {
552 const float *mean = lobe.mean_depth.data() + size_t(i * Azimuth + j) * (Samples + 1);
553 if (tau >= 1.)
554 return double(mean[Samples]) / (tau * tau * tau);
555 const double x = tau * Samples;
556 const int k = std::min(int(x), Samples - 1);
557 return mean[k] + (mean[k + 1] - mean[k]) * (x - k);
558 };
559 double mean = mean_at(i, j0) * (1. - fj) + mean_at(i, j1) * fj;
560 if (fi > 0.)
561 mean = mean * (1. - fi) + (mean_at(i + 1, j0) * (1. - fj) + mean_at(i + 1, j1) * fj) * fi;
562 return warp(mean);
563}
#define EPSILON
Definition ColorUtils.cpp:64
constexpr int Samples
Definition AdaptiveInfillField.cpp:50

References Azimuth, Slic3r::AdaptiveInfillField::Lobe::center, EPSILON, m_axis, Slic3r::AdaptiveInfillField::Lobe::mean_depth, offset(), PI, Polar, radial(), and Slic3r::AdaptiveInfillField::Lobe::reach.

Here is the call graph for this function:

◆ radial() [2/2]

size_t Slic3r::AdaptiveInfillField::radial ( const Vec3d & pt,
Radials & out ) const
566{
567 assert(!this->empty());
568 Vec3i32 idx;
569 for (int axis = 0; axis < 3; ++axis)
570 idx[axis] = std::clamp<int>(int(std::lround((pt[axis] - m_origin[axis]) / m_cell)), 0, m_size[axis] - 1);
571 auto node = [this](const Vec3i32 &idx) { return (size_t(idx.z()) * m_size.y() + idx.y()) * m_size.x() + idx.x(); };
572 if (m_axis < 0)
573 return this->body_radial(node(idx), pt, 1.f, out.data());
574
575 // The sections around pt, or the nearest ones with a body.
576 const double f = std::clamp((pt[m_axis] - m_origin[m_axis]) / m_cell, 0., double(m_size[m_axis] - 1));
577 const int k = std::min(int(f), m_size[m_axis] - 2);
578 const float w = float(f - k);
579 size_t count = 0;
580 if (w < 1.f) {
581 idx[m_axis] = m_section[k];
582 count += this->body_radial(node(idx), pt, 1.f - w, out.data());
583 }
584 if (w > 0.f) {
585 idx[m_axis] = m_section[k + 1];
586 count += this->body_radial(node(idx), pt, w, out.data() + count);
587 }
588 return count;
589}
bool empty() const
Definition AdaptiveInfillField.hpp:50
size_t body_radial(size_t node, const Vec3d &pt, float weight, Radial *out) const
Definition AdaptiveInfillField.cpp:591

References axis(), body_radial(), count, empty(), Slic3r::f(), m_axis, m_cell, m_origin, m_section, m_size, and radial().

Referenced by body_radial(), radial(), and radial().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ Azimuth

int Slic3r::AdaptiveInfillField::Azimuth = 48
staticconstexprprivate

Referenced by directions(), and radial().

◆ m_axis

int Slic3r::AdaptiveInfillField::m_axis
private

◆ m_bodies

std::vector<Body> Slic3r::AdaptiveInfillField::m_bodies
private

Referenced by body_radial(), and empty().

◆ m_body

std::vector<int> Slic3r::AdaptiveInfillField::m_body
private

Referenced by body_radial().

◆ m_cell

double Slic3r::AdaptiveInfillField::m_cell
private

Referenced by AdaptiveInfillField(), depth(), and radial().

◆ m_depth

std::vector<float> Slic3r::AdaptiveInfillField::m_depth
private

Referenced by depth().

◆ m_lobes

std::vector<Lobe> Slic3r::AdaptiveInfillField::m_lobes
private

Referenced by body_radial().

◆ m_mode

AdaptiveInfillMode Slic3r::AdaptiveInfillField::m_mode
private

Referenced by AdaptiveInfillField(), and mode().

◆ m_origin

Vec3d Slic3r::AdaptiveInfillField::m_origin
private

Referenced by AdaptiveInfillField(), depth(), and radial().

◆ m_section

std::vector<int> Slic3r::AdaptiveInfillField::m_section
private

Referenced by radial().

◆ m_size

Vec3i32 Slic3r::AdaptiveInfillField::m_size
private

Referenced by AdaptiveInfillField(), depth(), and radial().

◆ MaxMorph

size_t Slic3r::AdaptiveInfillField::MaxMorph = 4
staticconstexpr

Referenced by body_radial().

◆ Polar

int Slic3r::AdaptiveInfillField::Polar = 24
staticconstexprprivate

Referenced by directions(), and radial().


The documentation for this class was generated from the following files: