mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
Merge upstream main: center of mass markers, adaptive TPMS, texture bake color mixing, post-processing preview fix, GLEW/OpenCSG removal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
#include "PrintBase.hpp"
|
||||
#include "ConnectedBodies.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "enum_bitmask.hpp"
|
||||
#include "libslic3r.h"
|
||||
@@ -2563,6 +2564,156 @@ WipeTowerType GCode::wipe_tower_type()
|
||||
return WipeTowerType::Type2;
|
||||
}
|
||||
|
||||
// Numbers the object instances and the connected bodies of the instances of several, for the processor to find those an
|
||||
// extrusion lies in.
|
||||
static void set_mass_locator(GCodeProcessor &processor, const Print &print)
|
||||
{
|
||||
struct Object
|
||||
{
|
||||
const PrintObject *object;
|
||||
int first_instance;
|
||||
// No bodies for an object of one.
|
||||
size_t bodies_count;
|
||||
int first_body;
|
||||
std::vector<coordf_t> print_zs;
|
||||
// Per layer, the body of each island and a locator whose boxes are widened for walls reaching past them.
|
||||
std::vector<std::vector<size_t>> bodies;
|
||||
std::vector<IslandLocator> islands;
|
||||
// Per instance, whether its widened box reaches another's, so that the box of an island proves nothing.
|
||||
std::vector<bool> crowded;
|
||||
};
|
||||
std::vector<Object> objects;
|
||||
std::vector<GCodeProcessorResult::ObjectMass> object_masses;
|
||||
int bodies_total = 0;
|
||||
for (const PrintObject *object : print.objects()) {
|
||||
const auto layers = object->layers();
|
||||
if (layers.empty())
|
||||
continue;
|
||||
// Bodies for assemblies only, as the Prepare tab counts them: those separated infills found, if it needed them.
|
||||
const ModelVolumePtrs &volumes = object->model_object()->volumes;
|
||||
const bool assembly = std::count_if(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return v->is_model_part(); }) > 1 ||
|
||||
std::any_of(volumes.begin(), volumes.end(), [](const ModelVolume *v) { return v->is_negative_volume(); });
|
||||
size_t count = 0;
|
||||
std::vector<std::vector<size_t>> bodies;
|
||||
if (assembly) {
|
||||
count = object->separated_body_bboxes().size();
|
||||
if (count > 0 && std::all_of(layers.begin(), layers.end(), [](const Layer *l) { return l->lslices_separated_component_ids.size() == l->lslices.size(); }))
|
||||
for (const Layer *layer : layers)
|
||||
bodies.emplace_back(layer->lslices_separated_component_ids);
|
||||
else {
|
||||
std::vector<const ExPolygons *> islands;
|
||||
for (const Layer *layer : layers)
|
||||
islands.emplace_back(&layer->lslices);
|
||||
bodies = connected_bodies(islands, count);
|
||||
}
|
||||
}
|
||||
if (count < 2) {
|
||||
count = 0;
|
||||
bodies.assign(layers.size(), {});
|
||||
}
|
||||
Object &o = objects.emplace_back(Object{ object, int(object_masses.size()), count, bodies_total, {}, std::move(bodies), {}, {} });
|
||||
object_masses.resize(object_masses.size() + object->instances().size());
|
||||
for (size_t instance = 0; instance < object->instances().size(); ++instance)
|
||||
object_masses[o.first_instance + instance].assembly = assembly;
|
||||
bodies_total += int(count * object->instances().size());
|
||||
for (const Layer *layer : layers) {
|
||||
o.print_zs.emplace_back(layer->print_z);
|
||||
o.islands.emplace_back(layer->lslices, scaled<coord_t>(1.));
|
||||
}
|
||||
}
|
||||
if (objects.empty())
|
||||
return;
|
||||
std::vector<BoundingBox> boxes;
|
||||
for (const Object &o : objects) {
|
||||
BoundingBox box;
|
||||
for (const IslandLocator &islands : o.islands)
|
||||
for (const BoundingBox &island : islands.boxes())
|
||||
box.merge(island);
|
||||
for (const PrintInstance &instance : o.object->instances()) {
|
||||
BoundingBox &moved = boxes.emplace_back(box);
|
||||
moved.translate(instance.shift);
|
||||
}
|
||||
}
|
||||
for (Object &o : objects)
|
||||
for (size_t instance = 0; instance < o.object->instances().size(); ++instance) {
|
||||
const size_t i = o.first_instance + instance;
|
||||
o.crowded.emplace_back(false);
|
||||
for (size_t j = 0; j < boxes.size() && !o.crowded.back(); ++j)
|
||||
o.crowded.back() = j != i && boxes[i].overlap(boxes[j]);
|
||||
}
|
||||
|
||||
struct Hit
|
||||
{
|
||||
size_t object{ 0 }, instance{ 0 }, layer{ 0 }, island{ 0 };
|
||||
};
|
||||
auto locate = [objects = std::move(objects), footprints = std::move(boxes),
|
||||
last = std::optional<Hit>()](const Vec3d &point, bool support) mutable -> GCodeProcessor::MassLocation {
|
||||
// Supports stand below and around their object: the instance whose footprint holds the point, the one whose center
|
||||
// is nearest among several, else the nearest footprint.
|
||||
if (support) {
|
||||
const Point p(scaled(point.x()), scaled(point.y()));
|
||||
int found = -1;
|
||||
bool inside = false;
|
||||
double best = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < footprints.size(); ++i) {
|
||||
const BoundingBox &box = footprints[i];
|
||||
const double gap = Point((box.min - p).cwiseMax(p - box.max).cwiseMax(0)).cast<double>().squaredNorm();
|
||||
const bool in = gap == 0.;
|
||||
const double d = in ? (box.center() - p).cast<double>().squaredNorm() : gap;
|
||||
if ((in && !inside) || (in == inside && d < best)) {
|
||||
found = int(i);
|
||||
inside = in;
|
||||
best = d;
|
||||
}
|
||||
}
|
||||
return { found, -1 };
|
||||
}
|
||||
constexpr double z_tolerance = 0.002;
|
||||
const auto local = [&point, &objects](size_t object, size_t instance) {
|
||||
return Point(Point(scaled(point.x()), scaled(point.y())) - objects[object].object->instances()[instance].shift);
|
||||
};
|
||||
const auto location = [&objects, &last](const Hit &hit) {
|
||||
last = hit;
|
||||
const Object &o = objects[hit.object];
|
||||
return GCodeProcessor::MassLocation{ o.first_instance + int(hit.instance),
|
||||
o.bodies_count == 0 ? -1 : o.first_body + int(hit.instance * o.bodies_count + o.bodies[hit.layer][hit.island]) };
|
||||
};
|
||||
// A point lies on the first layer at or above it, as spiral vase rises through each layer.
|
||||
// Extrusions mostly follow each other on one island.
|
||||
if (last) {
|
||||
const Object &o = objects[last->object];
|
||||
if (point.z() <= o.print_zs[last->layer] + z_tolerance &&
|
||||
(last->layer == 0 || point.z() > o.print_zs[last->layer - 1] + z_tolerance) &&
|
||||
o.islands[last->layer].holds(last->island, local(last->object, last->instance), o.crowded[last->instance]))
|
||||
return location(*last);
|
||||
}
|
||||
// Outside the islands of instances crowding each other, the nearest outline.
|
||||
std::optional<Hit> nearest;
|
||||
double distance = std::numeric_limits<double>::max();
|
||||
for (size_t object = 0; object < objects.size(); ++object) {
|
||||
const Object &o = objects[object];
|
||||
const auto z = std::lower_bound(o.print_zs.begin(), o.print_zs.end(), point.z() - z_tolerance);
|
||||
if (z == o.print_zs.end())
|
||||
continue;
|
||||
const size_t layer = size_t(z - o.print_zs.begin());
|
||||
for (size_t instance = 0; instance < o.object->instances().size(); ++instance) {
|
||||
const auto [island, d] = o.islands[layer].find(local(object, instance), o.crowded[instance]);
|
||||
if (island < 0)
|
||||
continue;
|
||||
const Hit hit{ object, instance, layer, size_t(island) };
|
||||
if (d == 0. || !o.crowded[instance])
|
||||
return location(hit);
|
||||
if (d < distance) {
|
||||
distance = d;
|
||||
nearest = hit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearest ? location(*nearest) : GCodeProcessor::MassLocation{};
|
||||
};
|
||||
processor.set_mass_locator(std::move(locate), std::move(object_masses));
|
||||
}
|
||||
|
||||
void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
{
|
||||
PROFILE_CLEAR();
|
||||
@@ -3117,6 +3268,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// modifies m_silent_time_estimator_enabled
|
||||
DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled,
|
||||
print.get_layered_nozzle_group_result());
|
||||
set_mass_locator(m_processor, print);
|
||||
const bool is_bbl_printers = print.is_BBL_printer();
|
||||
const bool skip_config_block = print.config().gcode_skip_config_block;
|
||||
const WipeTowerType wipe_tower_type = print.wipe_tower_type();
|
||||
|
||||
Reference in New Issue
Block a user