This commit is contained in:
sunsets
2024-05-17 14:39:34 +08:00
13 changed files with 96 additions and 50 deletions

View File

@@ -343,6 +343,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
// Use ipEnsuring pattern for all internal Solids.
//w11
if (layer.object()->config().detect_narrow_internal_solid_infill) {
//w29
size_t surface_fills_size = surface_fills.size();
for (size_t i = 0; i < surface_fills_size; i++) {
if (surface_fills[i].surface.surface_type != stInternalSolid)
@@ -354,12 +355,13 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
for (size_t j = 0; j < expolygons_size; j++)
if (is_narrow_infill_area(surface_fills[i].expolygons[j]))
narrow_expolygons_index.push_back(j);
//w29
if (narrow_expolygons_index.size() == 0) {
continue;
} else if (narrow_expolygons_index.size() == expolygons_size) {
surface_fills[i].params.pattern = ipConcentric;
} else {
//w29
params = surface_fills[i].params;
params.pattern = ipConcentric;
surface_fills.emplace_back(params);
@@ -575,6 +577,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.anchor_length_max = surface_fill.params.anchor_length_max;
params.resolution = resolution;
//w14
//w29
params.use_arachne = (perimeter_generator == PerimeterGeneratorType::Arachne && surface_fill.params.pattern == ipConcentric) || surface_fill.params.pattern == ipEnsuring || surface_fill.params.pattern == ipConcentric;
params.layer_height = layerm.layer()->height;
//w29
@@ -643,6 +646,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
delete eec;
thick_polylines.clear();
} else {
//w29
extrusion_entities_append_paths(eec->entities, std::move(polylines),
ExtrusionAttributes{surface_fill.params.extrusion_role,
ExtrusionFlow{flow_mm3_per_mm, float(flow_width),
@@ -699,43 +703,41 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
}
for (LayerSlice &lslice : this->lslices_ex)
for (LayerIsland &island : lslice.islands) {
if (!island.thin_fills.empty()) {
// Copy thin fills into fills packed as a collection.
// Fills are always stored as collections, the rest of the pipeline (wipe into infill, G-code generator) relies on it.
LayerRegion & layerm = *this->get_region(island.perimeters.region());
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
layerm.m_fills.entities.push_back(&collection);
collection.entities.reserve(island.thin_fills.size());
for (uint32_t fill_id : island.thin_fills)
collection.entities.push_back(layerm.thin_fills().entities[fill_id]->clone());
island.add_fill_range(
{island.perimeters.region(), {uint32_t(layerm.m_fills.entities.size() - 1), uint32_t(layerm.m_fills.entities.size())}});
}
// Sort the fills by region ID.
std::sort(island.fills.begin(), island.fills.end(),
[](auto &l, auto &r) { return l.region() < r.region() || (l.region() == r.region() && *l.begin() < *r.begin()); });
// Compress continuous fill ranges of the same region.
{
size_t k = 0;
for (size_t i = 0; i < island.fills.size();) {
uint32_t region_id = island.fills[i].region();
uint32_t begin = *island.fills[i].begin();
uint32_t end = *island.fills[i].end();
size_t j = i + 1;
for (; j < island.fills.size() && island.fills[j].region() == region_id && *island.fills[j].begin() == end; ++j)
end = *island.fills[j].end();
island.fills[k++] = {region_id, {begin, end}};
i = j;
}
island.fills.erase(island.fills.begin() + k, island.fills.end());
}
}
for (LayerIsland &island : lslice.islands) {
if (! island.thin_fills.empty()) {
// Copy thin fills into fills packed as a collection.
// Fills are always stored as collections, the rest of the pipeline (wipe into infill, G-code generator) relies on it.
LayerRegion &layerm = *this->get_region(island.perimeters.region());
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
layerm.m_fills.entities.push_back(&collection);
collection.entities.reserve(island.thin_fills.size());
for (uint32_t fill_id : island.thin_fills)
collection.entities.push_back(layerm.thin_fills().entities[fill_id]->clone());
island.add_fill_range({ island.perimeters.region(), { uint32_t(layerm.m_fills.entities.size() - 1), uint32_t(layerm.m_fills.entities.size()) } });
}
// Sort the fills by region ID.
std::sort(island.fills.begin(), island.fills.end(), [](auto &l, auto &r){ return l.region() < r.region() || (l.region() == r.region() && *l.begin() < *r.begin()); });
// Compress continuous fill ranges of the same region.
{
size_t k = 0;
for (size_t i = 0; i < island.fills.size();) {
uint32_t region_id = island.fills[i].region();
uint32_t begin = *island.fills[i].begin();
uint32_t end = *island.fills[i].end();
size_t j = i + 1;
for (; j < island.fills.size() && island.fills[j].region() == region_id && *island.fills[j].begin() == end; ++ j)
end = *island.fills[j].end();
island.fills[k ++] = { region_id, { begin, end } };
i = j;
}
island.fills.erase(island.fills.begin() + k, island.fills.end());
}
}
#ifndef NDEBUG
for (LayerRegion *layerm : m_regions)
for (const ExtrusionEntity *e : layerm->fills())
assert(dynamic_cast<const ExtrusionEntityCollection *>(e) != nullptr);
for (LayerRegion *layerm : m_regions)
for (const ExtrusionEntity *e : layerm->fills())
assert(dynamic_cast<const ExtrusionEntityCollection*>(e) != nullptr);
#endif
}
//w21
@@ -1100,11 +1102,13 @@ void Layer::make_ironing()
// Layer::id() returns layer ID including raft layers, subtract them to make the infill direction independent
// from raft.
//FIXME ironing does not take fill angle into account. Shall it? Does it matter?
//w33
//fill.layer_id = this->id() - this->object()->get_layer(0)->id();
//fill.z = this->print_z;
//fill.overlap = 0;
fill_params.density = 1.;
fill_params.monotonic = true;
//w33
InfillPattern f_pattern = ipRectilinear;
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(f_pattern));
f->set_bounding_box(this->object()->bounding_box());

View File

@@ -6,15 +6,18 @@
namespace Slic3r {
//w36
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
//w36
static coordf_t triWave(coordf_t pos, coordf_t gridSize)
{
float t = (pos / (gridSize * 2.)) + 0.25;
t = t - (int)t;
return((1. - abs(t * 8. - 4.)) * (gridSize / 4.) + (gridSize / 4.));
}
//w36
static coordf_t troctWave(coordf_t pos, coordf_t gridSize, coordf_t Zpos)
{
coordf_t Zcycle = triWave(Zpos, gridSize);
@@ -22,6 +25,7 @@ static coordf_t troctWave(coordf_t pos, coordf_t gridSize, coordf_t Zpos)
coordf_t y = triWave(pos, gridSize);
return ((abs(y) > abs(perpOffset)) ? (sgn(y) * perpOffset) : (y * sgn(perpOffset)));
}
//w36
static std::vector<coordf_t> getCriticalPoints(coordf_t Zpos, coordf_t gridSize)
{
std::vector<coordf_t> res = {0.};
@@ -50,22 +54,27 @@ Credits: David Eccles (gringer).
// basic printing line (i.e. Y points for columns, X points for rows)
// Note: a negative offset only causes a change in the perpendicular
// direction
//w36
static std::vector<coordf_t> colinearPoints(const coordf_t Zpos, coordf_t gridSize, std::vector<coordf_t> critPoints,
const size_t baseLocation, size_t gridLength)
{
//w36
std::vector<coordf_t> points;
//w36
points.push_back(baseLocation);
for (coordf_t cLoc = baseLocation; cLoc < gridLength; cLoc += (gridSize * 2)) {
for (size_t pi = 0; pi < critPoints.size(); pi++) {
points.push_back(baseLocation + cLoc + critPoints[pi]);
}
}
//w36
points.push_back(gridLength);
return points;
}
// Generate an array of points for the dimension that is perpendicular to
// the basic printing line (i.e. X points for columns, Y points for rows)
//w36
static std::vector<coordf_t> perpendPoints(const coordf_t Zpos,
coordf_t gridSize,
std::vector<coordf_t> critPoints,
@@ -74,7 +83,9 @@ static std::vector<coordf_t> perpendPoints(const coordf_t Zpos,
size_t offsetBase,
coordf_t perpDir)
{
//w36
std::vector<coordf_t> points;
//w36
points.push_back(offsetBase);
for (coordf_t cLoc = baseLocation; cLoc < gridLength; cLoc += gridSize * 2) {
for (size_t pi = 0; pi < critPoints.size(); pi++) {
@@ -82,6 +93,7 @@ static std::vector<coordf_t> perpendPoints(const coordf_t Zpos,
points.push_back(offsetBase + (offset * perpDir));
}
}
//w36
points.push_back(offsetBase);
return points;
}
@@ -110,8 +122,10 @@ static inline Pointfs zip(const std::vector<coordf_t> &x, const std::vector<coor
// horizontal slice of a truncated regular octahedron with edge length 1.
// curveType specifies which lines to print, 1 for vertical lines
// (columns), 2 for horizontal lines (rows), and 3 for both.
//w36
static std::vector<Pointfs> makeActualGrid(coordf_t Zpos, coordf_t gridSize, size_t boundsX, size_t boundsY)
{
//w36
std::vector<Pointfs> points;
std::vector<coordf_t> critPoints = getCriticalPoints(Zpos, gridSize);
coordf_t zCycle = fmod(Zpos + gridSize / 2, gridSize * 2.) / (gridSize * 2.);
@@ -143,14 +157,17 @@ static std::vector<Pointfs> makeActualGrid(coordf_t Zpos, coordf_t gridSize, siz
// Generate a set of curves (array of array of 2d points) that describe a
// horizontal slice of a truncated regular octahedron with a specified
// grid square size.
//w36
static Polylines makeGrid(coordf_t z, coordf_t gridSize, coordf_t boundWidth, coordf_t boundHeight, bool fillEvenly)
{
//w36
std::vector<Pointfs> polylines = makeActualGrid(z, gridSize, boundWidth, boundHeight);
Polylines result;
result.reserve(polylines.size());
for (std::vector<Pointfs>::const_iterator it_polylines = polylines.begin(); it_polylines != polylines.end(); ++it_polylines) {
result.push_back(Polyline());
Polyline &polyline = result.back();
//w36
for (Pointfs::const_iterator it = it_polylines->begin(); it != it_polylines->end(); ++it)
polyline.points.push_back(Point(coord_t((*it)(0)), coord_t((*it)(1))));
}
@@ -165,13 +182,16 @@ void Fill3DHoneycomb::_fill_surface_single(
Polylines &polylines_out)
{
// no rotation is supported for this infill pattern
//w36
auto infill_angle = float(this->angle);
if (std::abs(infill_angle) >= EPSILON)
expolygon.rotate(-infill_angle);
BoundingBox bb = expolygon.contour.bounding_box();
//w36
// align bounding box to a multiple of our honeycomb grid module
// (a module is 2*$distance since one $distance half-module is
// growing while the other $distance half-module is shrinking)
//w36
coordf_t zScale = sqrt(2);
coordf_t gridSize = (scale_(this->spacing) * ((zScale + 1.) / 2.) / params.density);

View File

@@ -16,6 +16,7 @@ public:
~Fill3DHoneycomb() override {}
// require bridge flow since most of this pattern hangs in air
//w36
protected:

View File

@@ -125,7 +125,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
}
//w29
void Fill::variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector<ExtrusionEntity *> &out)
{
const float tolerance = float(scale_(0.05));
@@ -141,6 +141,7 @@ void Fill::variable_width(const ThickPolylines &polylines, ExtrusionRole role, c
}
}
}
//w29
ExtrusionPaths Fill::thick_polyline_to_extrusion_paths_2(const ThickPolyline &thick_polyline,
ExtrusionRole role,
const Flow & flow,

View File

@@ -425,6 +425,7 @@ ExpansionResult expand_expolygons(
// Extract bridging surfaces from "surfaces", expand them into "shells" using expansion_params,
// detect bridges.
// Trim "shells" by the expanded bridges.
//w36
Surfaces expand_bridges_detect_orientations(Surfaces & surfaces,
ExPolygons & shells,
const Algorithm::RegionExpansionParameters &expansion_params_into_solid_infill,
@@ -434,12 +435,14 @@ Surfaces expand_bridges_detect_orientations(Surfaces &
{
using namespace Slic3r::Algorithm;
//w36
double thickness;
ExPolygons bridges_ex = fill_surfaces_extract_expolygons(surfaces, {stBottomBridge}, thickness);
if (bridges_ex.empty())
return {};
// Calculate bridge anchors and their expansions in their respective shell region.
//w36
WaveSeeds bridge_anchors = wave_seeds(bridges_ex, shells, expansion_params_into_solid_infill.tiny_expansion, true);
std::vector<RegionExpansionEx> bridge_expansions = propagate_waves_ex(bridge_anchors, shells, expansion_params_into_solid_infill);
bool expanded_into_shells = !bridge_expansions.empty();
@@ -564,6 +567,7 @@ Surfaces expand_bridges_detect_orientations(Surfaces &
}
// Merge the groups with the same group id, produce surfaces by merging source overhangs with their newly expanded anchors.
//w36
Surfaces out;
{
Polygons acc;
@@ -603,6 +607,7 @@ Surfaces expand_bridges_detect_orientations(Surfaces &
}
// Clip by the expanded bridges.
//w36
if (expanded_into_shells)
shells = diff_ex(shells, out);
if (expanded_into_sparse)
@@ -610,6 +615,7 @@ Surfaces expand_bridges_detect_orientations(Surfaces &
return out;
}
//w36
static Surfaces expand_merge_surfaces(Surfaces & surfaces,
SurfaceType surface_type,
ExPolygons & shells,
@@ -626,6 +632,8 @@ static Surfaces expand_merge_surfaces(Surfaces &
if (src.empty())
return {};
//w36
std::vector<RegionExpansion> expansions = propagate_waves(src, shells, expansion_params_into_solid_infill);
bool expanded_into_shells = !expansions.empty();
bool expanded_into_sparse = false;
@@ -645,6 +653,7 @@ static Surfaces expand_merge_surfaces(Surfaces &
// look for narrow_ensure_vertical_wall_thickness_region_radius filter.
expanded = closing_ex(expanded, closing_radius);
// Trim the shells by the expanded expolygons.
//w36
if (expanded_into_shells)
shells = diff_ex(shells, expanded);
if (expanded_into_sparse)
@@ -697,13 +706,16 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// Expand the top / bottom / bridge surfaces into the shell thickness solid infills.
double layer_thickness;
//w36
ExPolygons shells = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, {stInternalSolid}, layer_thickness));
ExPolygons sparse = union_ex(fill_surfaces_extract_expolygons(m_fill_surfaces.surfaces, {stInternal}, layer_thickness));
SurfaceCollection bridges;
//w36
const auto expansion_params_into_sparse_infill = RegionExpansionParameters::build(expansion_min, expansion_step, max_nr_expansion_steps);
{
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges. layer" << this->layer()->print_z;
//w36
const double custom_angle = this->region().config().bridge_angle.value;
const auto expansion_params_into_solid_infill = RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step,
max_nr_expansion_steps);
@@ -721,6 +733,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
}
#endif
}
//w36
Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, shells,
RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps),
@@ -731,15 +744,18 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternal, stInternalSolid });
m_fill_surfaces.clear();
//w36
reserve_more(m_fill_surfaces.surfaces, shells.size() + sparse.size() + bridges.size() + bottoms.size() + tops.size());
{
Surface solid_templ(stInternalSolid, {});
solid_templ.thickness = layer_thickness;
//w36
m_fill_surfaces.append(std::move(shells), solid_templ);
}
{
Surface sparse_templ(stInternal, {});
sparse_templ.thickness = layer_thickness;
//w36
m_fill_surfaces.append(std::move(sparse), sparse_templ);
}
m_fill_surfaces.append(std::move(bridges.surfaces));

View File

@@ -90,7 +90,7 @@ int Point::nearest_point_index(const Points &points) const
p.push_back(&*it);
return this->nearest_point_index(p);
}
//w29
int Point::nearest_point_index(const PointConstPtrs &points) const
{
int idx = -1;
@@ -118,7 +118,7 @@ int Point::nearest_point_index(const PointConstPtrs &points) const
return idx;
}
//w29
int Point::nearest_point_index(const PointPtrs &points) const
{
PointConstPtrs p;

View File

@@ -3225,6 +3225,7 @@ void PrintConfigDef::init_fff_params()
def->label = L("Synchronize with object layers");
def->category = L("Support material");
// TRN PrintSettings : "Synchronize with object layers"
//w34
def->tooltip = L("If not checked, support layers to use layer heights that are independent of the object layer.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));

View File

@@ -774,6 +774,7 @@ void PrintObject::slice_volumes()
float(scale_(m_config.elefant_foot_compensation.value)) :
0.f;
// Uncompensated slices for the first layer in case the Elephant foot compensation is applied.
//w24
std::vector<ExPolygons> lslices_elfoot_uncompensated;
//w26
lslices_elfoot_uncompensated.resize(elephant_foot_compensation_scaled > 0 ? std::min(m_config.elefant_foot_compensation_layers.value, (int)m_layers.size()) : 0);
@@ -786,6 +787,7 @@ void PrintObject::slice_volumes()
m_print->throw_if_canceled();
Layer *layer = m_layers[layer_id];
//w24
//w26
float elfoot = elephant_foot_compensation_scaled > 0 && layer_id < m_config.elefant_foot_compensation_layers.value ?
elephant_foot_compensation_scaled - (elephant_foot_compensation_scaled / m_config.elefant_foot_compensation_layers.value) * layer_id :
0.f;
@@ -795,15 +797,18 @@ void PrintObject::slice_volumes()
//w24
ExPolygons expolygons_to_compensate = to_expolygons(std::move(layerm->slices().surfaces));
if (xy_contour_scaled > 0 || xy_hole_scaled > 0) {
//w24
expolygons_to_compensate = _shrink_contour_holes(std::max(0.f, xy_contour_scaled),
std::max(0.f, xy_hole_scaled),
expolygons_to_compensate);
}
if (xy_contour_scaled < 0 || xy_hole_scaled < 0) {
//w24
expolygons_to_compensate = _shrink_contour_holes(std::min(0.f, xy_contour_scaled),
std::min(0.f, xy_hole_scaled),
expolygons_to_compensate);
}
//w24
lslices_elfoot_uncompensated[layer_id] = expolygons_to_compensate;
layerm->m_slices.set(
union_ex(
@@ -817,13 +822,11 @@ void PrintObject::slice_volumes()
if (xy_contour_scaled != 0.0f || xy_hole_scaled != 0.0f) {
ExPolygons expolygons = to_expolygons(std::move(layerm->m_slices.surfaces));
if (xy_contour_scaled > 0 || xy_hole_scaled > 0) {
expolygons = _shrink_contour_holes(std::max(0.f, xy_contour_scaled),
std::max(0.f, xy_hole_scaled),
expolygons = _shrink_contour_holes(std::max(0.f, xy_contour_scaled), std::max(0.f, xy_hole_scaled),
expolygons);
}
if (xy_contour_scaled < 0 || xy_hole_scaled < 0) {
expolygons = _shrink_contour_holes(std::min(0.f, xy_contour_scaled),
std::min(0.f, xy_hole_scaled),
expolygons = _shrink_contour_holes(std::min(0.f, xy_contour_scaled), std::min(0.f, xy_hole_scaled),
expolygons);
}
layerm->m_slices.set(std::move(expolygons), stInternal);
@@ -856,6 +859,7 @@ void PrintObject::slice_volumes()
ExPolygons trimming;
static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
if (elfoot > 0.f) {
//w24
ExPolygons expolygons_to_compensate = offset_ex(layer->merged(eps), -eps);
lslices_elfoot_uncompensated[layer_id] = expolygons_to_compensate;
trimming = Slic3r::elephant_foot_compensation(expolygons_to_compensate,
@@ -864,9 +868,7 @@ void PrintObject::slice_volumes()
trimming = layer->merged(float(SCALED_EPSILON));
}
if (min_growth < 0.0f)
trimming = _shrink_contour_holes(std::min(0.f, xy_contour_scaled),
std::min(0.f, xy_hole_scaled),
trimming);
trimming = _shrink_contour_holes(std::min(0.f, xy_contour_scaled), std::min(0.f, xy_hole_scaled), trimming);
for (size_t region_id = 0; region_id < layer->regions().size(); ++region_id) {
ExPolygons contour_exp = to_expolygons(std::move(layer->regions()[region_id]->m_slices.surfaces));

View File

@@ -125,6 +125,7 @@ SlicingParameters SlicingParameters::create_from_config(
if (params.gap_object_support <= 0)
params.gap_object_support = params.gap_support_object;
//w34
if (object_config.support_material_synchronize_layers) {
params.gap_raft_object = std::round(params.gap_raft_object / object_config.layer_height + EPSILON) * object_config.layer_height;
params.gap_object_support = std::round(params.gap_object_support / object_config.layer_height + EPSILON) *

View File

@@ -167,10 +167,11 @@ void adjust_layer_height_profile(
// Produce object layers as pairs of low / high layer boundaries, stored into a linear vector.
// The object layers are based at z=0, ignoring the raft layers.
//w27
std::vector<coordf_t> generate_object_layers(
const SlicingParameters &slicing_params,
const std::vector<coordf_t> &layer_height_profile,
//w27
bool is_precise_z_height);
// Check whether the layer height profile describes a fixed layer height profile.

View File

@@ -207,10 +207,10 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
double max_bridge_length = scale_(config.max_bridge_length.value);
bool bridge_break = (config.max_bridge_length.value > 0) && (config.support_material_style == smsOrganic);
//w28
size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size()));
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
[&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
//w28
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, &throw_on_cancel, &out,bridge_break,max_bridge_length]
(const tbb::blocked_range<LayerIndex> &range) {
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {

View File

@@ -619,10 +619,10 @@ void GLCanvas3D::LayersEditing::generate_layer_height_texture()
m_layers_texture.data.assign(m_layers_texture.width * m_layers_texture.height * 5, 0);
}
//w27
bool level_of_detail_2nd_level = true;
m_layers_texture.cells = Slic3r::generate_layer_height_texture(
*m_slicing_parameters,
//w27
Slic3r::generate_object_layers(*m_slicing_parameters, m_layer_height_profile,false),
m_layers_texture.data.data(), m_layers_texture.height, m_layers_texture.width, level_of_detail_2nd_level);
m_layers_texture.valid = true;

View File

@@ -5626,7 +5626,6 @@ std::vector<std::pair<std::string, std::vector<std::string>>> material_overrides
{"Corrections", {
"relative_correction",
"elefant_foot_compensation"
}}
};