Compare commits

...
12 Commits
Author SHA1 Message Date
Ian Chua 67a16dabca fix: prompt for permission when plugin tries to create a thread (#16248)
* fix: prompt for permission when plugin tries to create a thread

* fix: request permission on main thread
2026-10-08 23:49:33 +08:00
Ian Bassi 59fc97fb28 Extend Separated Infills (#16274) 2026-10-08 09:43:46 -03:00
LixNix 7d44b60ae4 H2D X2D Multi Nozzle Size Printing Support (#14125) 2026-10-08 20:28:32 +08:00
ExPikaPakaandExPikaPaka 776ca6a3e4 build_linux.sh: add -J to build several dependencies at once (#16282)
* build_linux.sh: add -J to build several dependencies at once

The top-level deps build is fixed at -j1, so one dependency compiles at a
time while the small ones leave most cores idle. -J N raises that level.

-j still applies in full to each dependency, so the worst case is -J times
-j compile jobs: ninja has no job server to share a pool across the nested
builds. Without -J nothing changes.

* Quote the job count for shellcheck (SC2086)

---------

Co-authored-by: ExPikaPaka <mrfsfyt@gmail.com>
2026-10-08 18:56:02 +08:00
SoftFeverandxxxsam ee26e94170 Fix H2D prints rejected for a missing Filament Track Switch
Fixes #15927

Co-authored-by: xxxsam <31843242+xxxsam92123@users.noreply.github.com>
2026-10-08 17:49:04 +08:00
Ian Chua d401d4f837 revert: profile changes made for OTA testing (#16280) 2026-10-08 16:13:12 +08:00
HanifKoh 18b70844d1 Defer Plugin Dock Panes Until the Plater Is Shown (#16257)
A plugin enabled at startup loads before the main frame exists, so a
dock panel it opens from on_load was dropped by the one-shot CallAfter
that found no plater. Opened a moment later, before the frame was laid
out, the pane was sized against the unsized frame and track_docked_size
kept that width. Poll until the plater is shown on screen, then build
the pane; release the reserved id instead when the app is closing.
2026-10-08 14:18:51 +08:00
HanifKoh c8f2498681 Keep GLCanvas3D Building With SLIC3R_CAD Off (#16256)
The bed-axes toggle added for the Design tab's reference planes reads
m_design_sketch_tool, which only exists under SLIC3R_CAD. Compute the
flag once and read the sketch tool inside the same guard as its other
uses.
2026-10-08 14:02:34 +08:00
HanifKoh 30902561c0 Stop Exporting Names Through Usings in the Remaining Headers (#16250)
The last headers with a using or namespace alias at namespace scope:

- TCPConsole.hpp imported boost::asio::ip::tcp into Slic3r::Utils for
  two member declarations. The alias is now a private member of the
  class.
- WebSocketClient.hpp declared four namespace aliases and a tcp alias
  at global scope, each used only by the header. The names are spelled
  out.
- Repair.hpp aliased CGAL::Polygon_mesh_processing as PMP in
  Slic3r::tex2color. The three functions that use it declare the alias
  themselves.
- PreciseSeam.hpp, Thumbnails.hpp and MarchingSquares.hpp used a
  using-declaration or directive for one or two spots each; those spots
  are qualified. Thumbnails.hpp's "PNG"sv default argument becomes
  "PNG", which converts to the std::string_view parameter the same way.
- tests/sla_print/sla_test_utils.hpp had "using namespace Slic3r;" and
  tests/filament_group/fg_test_serialization.hpp "using json =
  nlohmann::json;" at global scope. The headers qualify their own names;
  the two SLA test sources get the directive themselves.

Also removed: twelve type aliases in headers that nothing references
(ConflictObjName, CircleSqf, CircleSqd, TRawBuffer, DistanceFunction,
SamePair, ExtruderNozzleInfos, Vec2dEvent, Vec2dsEvent, Vec3dEvent,
t_option, t_optgroups, Plater::fs_path) and a duplicate
fn_ft_job_msg_destroy alias in FileTransferUtils.hpp.
2026-10-08 13:59:12 +08:00
HanifKoh 3fc515f48d Prompt for Permission When a Plugin Calls os.exec (#16254)
* Prompt for Permission When a Plugin Calls os.exec

* Add a ProcessReplace Audit Category for os.exec
2026-10-08 13:52:09 +08:00
HanifKoh 6cd5feed79 Remove Duplicate Includes and the Dead GCodeSender Sources (#16249)
46 files include the same header twice at file scope, outside any #if,
66 times in all:
Model.cpp included Model.hpp twice, Utils.hpp <algorithm> and
<string_view> twice, seven GUI headers <wx/dataview.h> and
<wx/artprov.h> twice. The second include of each is removed.

GCodeSender.cpp and GCodeSender.hpp have been commented out of
libslic3r/CMakeLists.txt since 2022 and their only two includes are
commented out as well. Both files go, with the commented lines, and
the CMake entry for SLA/SupportTreeIGL.cpp, a file that no longer
exists.
2026-10-08 13:51:50 +08:00
HanifKoh 09530ef7c4 Size a Project's Mixed-Colour Metadata to the Filaments in the CLI (#16247)
The mixed-colour metadata options are parallel per-slot arrays in the project
config. A project saved before they were sized per slot stores a single value
for the gradient ones, and one saved before they existed stores none. The GUI
sizes all seven to the filament count when it opens a project; the CLI kept
the stored arrays and exported one-element defaults for absent ones, so a
project it exported carried one-element arrays where the GUI writes one entry
per filament. Slicing is unaffected, every reader treats a missing entry as
not mixed / no gradient, but the GUI-vs-CLI comparison reported the four
gradient keys on every mixed-filament project.

The resize helper moves from PresetBundle.cpp, where it was file-local, to
PrintConfig.cpp next to set_filament_dev_options(). It creates an option the
config lacks before sizing it, a no-op for the bundle's project config where
all seven always exist. The CLI calls it with its filament count once the
project and loaded filaments are merged, after the check that every mixed
slot has a filament of its own.
2026-10-08 13:40:36 +08:00
116 changed files with 1037 additions and 1136 deletions
+36 -3
View File
@@ -8,9 +8,10 @@ SCRIPT_PATH=$(dirname "$(readlink -f "${0}")")
pushd "${SCRIPT_PATH}" > /dev/null
function usage() {
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-p][-r][-s][-t][-u][-l][-L]"
echo "Usage: ./${SCRIPT_NAME} [-1][-b][-c][-d][-D][-e][-F][-g][-h][-i][-j N][-J N][-p][-r][-s][-t][-u][-l][-L]"
echo " -1: limit builds to one core (where possible)"
echo " -j N: limit builds to N cores (where possible)"
echo " -J N: build up to N dependencies at a time, each still using -j jobs (default: 1)"
echo " -b: build in Debug mode"
echo " -c: force a clean build"
echo " -C: enable ANSI-colored compile output (GNU/Clang only)"
@@ -36,12 +37,13 @@ function usage() {
}
SLIC3R_PRECOMPILED_HEADERS="ON"
DEPS_PARALLEL=""
unset name
BUILD_DIR=build
BUILD_CONFIG=Release
FORWARDED_ARGS=()
while getopts ":1j:bcCdDeFghiprstulL" opt ; do
while getopts ":1j:J:bcCdDeFghiprstulL" opt ; do
case ${opt} in
1 )
export CMAKE_BUILD_PARALLEL_LEVEL=1
@@ -51,6 +53,10 @@ while getopts ":1j:bcCdDeFghiprstulL" opt ; do
export CMAKE_BUILD_PARALLEL_LEVEL=$OPTARG
FORWARDED_ARGS+=("-j" "$OPTARG")
;;
J )
DEPS_PARALLEL=$OPTARG
FORWARDED_ARGS+=("-J" "$OPTARG")
;;
b )
BUILD_DIR=build-dbg
BUILD_CONFIG=Debug
@@ -135,6 +141,11 @@ if [[ -n "${CLEAN_DOCKER_IMAGE}" ]] && [[ -z "${USE_DOCKER}" ]] ; then
exit 1
fi
if [[ -n "${DEPS_PARALLEL}" ]] && ! [[ "${DEPS_PARALLEL}" =~ ^[1-9][0-9]*$ ]] ; then
echo "Error: -J expects a positive integer."
exit 1
fi
function check_available_memory_and_disk() {
FREE_MEM_GB=$(free --gibi --total | grep 'Mem' | rev | cut --delimiter=" " --fields=1 | rev)
MIN_MEM_GB=10
@@ -537,7 +548,29 @@ if [[ -n "${BUILD_DEPS}" ]] ; then
fi
print_and_run cmake -S deps -B deps/$BUILD_DIR "${CMAKE_C_CXX_COMPILER_CLANG[@]}" "${CMAKE_LLD_LINKER_ARGS[@]}" "${CMAKE_CCACHE_ARGS[@]}" -G Ninja "${COLORED_OUTPUT}" "${BUILD_ARGS[@]}"
print_and_run cmake --build deps/$BUILD_DIR -j1
# The top-level build runs one dependency at a time by default, which keeps the console
# output readable and lets that dependency's own build use all of CMAKE_BUILD_PARALLEL_LEVEL.
# -J raises the top level instead, and -j still applies in full to every dependency, so the
# worst case is -J times -j compile jobs at once. Ninja has no job server to share a pool
# across the nested builds, so that ceiling is not enforced anywhere: pick -J to suit the RAM.
DEPS_JOBS=1
if [[ -n "${DEPS_PARALLEL}" ]] ; then
DEPS_JOBS=${DEPS_PARALLEL}
SAVED_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL-}
export CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL:-$(nproc)}
echo "Building up to ${DEPS_JOBS} dependencies at a time, ${CMAKE_BUILD_PARALLEL_LEVEL} jobs each: up to $(( DEPS_JOBS * CMAKE_BUILD_PARALLEL_LEVEL )) compile jobs at once."
fi
print_and_run cmake --build deps/$BUILD_DIR -j"${DEPS_JOBS}"
if [[ -n "${DEPS_PARALLEL}" ]] ; then
# Give the whole -j back to the OrcaSlicer build below.
if [[ -n "${SAVED_PARALLEL_LEVEL}" ]] ; then
export CMAKE_BUILD_PARALLEL_LEVEL=${SAVED_PARALLEL_LEVEL}
else
unset CMAKE_BUILD_PARALLEL_LEVEL
fi
fi
fi
if [[ -n "${BUILD_ORCA}" ]] || [[ -n "${BUILD_TESTS}" ]] ; then
+90
View File
@@ -0,0 +1,90 @@
# Separated infills — High Level Design
## Purpose and scope
An object's infill patterns are laid out from one reference point, the center
of the object. When an object groups several parts that do not touch, every
part cuts the same object-wide pattern at a different place, so equal parts get
different infill. `separated_infills` lays the infill of every connected body
out from the center of that body instead, as if the body were sliced on its own.
The option covers sparse infill, internal solid infill and bridges. Top and
bottom surfaces are left to `center_of_surface_pattern`, which centers the
Archimedean Chords and Octagram Spiral surface patterns. The option is off by
default; with it off, or for an object made of a single body, no fill changes.
Adaptive Cubic and Support Cubic do not depend on the option: they always fill
each body on its own (see Octree infill).
## Bodies
`PrintObject::prepare_infill()` groups the islands of every layer (`lslices`)
into 3D connected bodies before bridges are detected, so bridge anchors and
printed infill share one origin. Islands on adjacent layers belong to one body
when their slices overlap. Parts that touch or overlap form one body. Separate
parts, disconnected islands of one mesh, and interleaved parts that never touch,
such as chain links, each form their own. Every island stores the index of its
body in `Layer::lslices_separated_component_ids`, and
`PrintObject::separated_body_bboxes()` holds the bounding box of each body over
all its layers.
The pass runs when a region uses separated infills, per-model surface centering
or an octree infill pattern. It is skipped when the object has one model part
that cannot be split, since a single body already shares the object center.
## Centering a fill
`infill_body()` matches each fill region to the island it overlaps most, among
the islands whose bounding boxes overlap it, and the filler takes the bounding
box of that island's body instead of the object's. The box covers every layer
of the body, which is the box the body gets when sliced alone, so patterns that
depend on its extent as well as its center come out the same too. Bridge
anchoring (`Layer::generate_sparse_infill_polylines_for_anchoring()`) makes the
same choice, so the anchors match the printed infill.
The patterns follow the body's box in one of two ways:
- Rectilinear and its variants, Line, Grid, Triangles, Tri-hexagon, Cubic,
Quarter Cubic, Lateral Lattice, Lateral Honeycomb and the plane-path patterns
(Hilbert Curve, Archimedean Chords, Octagram Spiral) are laid out from the
box: they phase their lines through its center, and Hilbert Curve and the Zig
Zag links start from its corner. `Fill::extended_object_bounding_box()`
extends the box about its center, so it also serves a box that is not
centered on the origin.
- Honeycomb, 3D Honeycomb, Cross Hatch, Gyroid, TPMS-D and TPMS-FK are laid out
from the coordinate origin, which is the object center. They return true from
`Fill::aligned_to_origin()`, and `Fill::fill_surface()` moves each region so
that the box center lands on the origin, fills it, and moves the paths back.
With the default box the center is the origin, so nothing moves.
`is_separable_infill_pattern()` lists these patterns. The settings show the
option only when the sparse infill pattern is one of them.
## Octree infill
Adaptive Cubic and Support Cubic take their lines from an octree, laid out from
the center of the mesh it is built from and refined near its surfaces. An
octree of the whole object would lay every part out from the object's center
and refine it near the other parts, so these patterns
(`is_octree_infill_pattern()`) always fill each body on its own, and the
settings hide the option for them.
For an object of several bodies, `PrintObject::prepare_adaptive_infill_data()`
builds one octree per body (`FillAdaptive::Octrees`) from the triangles of that
body only, which is the octree the body gets when sliced alone. Each connected
component of the mesh goes to the body that most of a few sampled triangles lie
on. A sample is taken a layer height inside the solid, behind the triangle, and
looked up in the islands of the nearest layer. Each internal bridge surface goes
to the body of its island. The fill takes the octree of the region's body, from
the same `infill_body()`. The octree of the whole object is built only for an
object of a single body, or when some body received no triangles, which then
uses it.
## Patterns left out
Lightning grows its trees over the whole object, so moving a reference point
cannot center it on one body. Concentric and Spiral Inset follow the outline of
each region and need no centering.
Solid infill at full density spaces its lines over the extent of each region,
so it is already independent of the other bodies. Only bridges, which keep
their line spacing, and the plane-path solid patterns depend on the center.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Elegoo",
"version": "02.04.00.12",
"version": "02.04.00.11",
"force_update": "0",
"description": "Elegoo configurations",
"machine_model_list": [
@@ -15,6 +15,6 @@
"Elegoo"
],
"filament_start_gcode": [
"; Elegoo PLA filament start gcode\n"
"; filament start gcode\n"
]
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "Orca Arena Printer",
"url": "",
"version": "02.04.00.08",
"version": "02.04.00.07",
"force_update": "0",
"description": "Orca Arena configuration files",
"machine_model_list": [
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "OrcaFilamentLibrary",
"version": "02.04.00.19",
"version": "02.04.00.15",
"force_update": "0",
"description": "Orca Filament Library",
"filament_list": [
@@ -39,7 +39,7 @@
"60"
],
"filament_start_gcode": [
"; Elegoo PLA filament start gcode\n"
"; filament start gcode\n"
],
"filament_end_gcode": [
"; filament end gcode \n"
+2
View File
@@ -4094,6 +4094,8 @@ int CLI::run(int argc, char **argv)
flush_and_exit(CLI_MIXED_FILAMENT_INVALID);
}
}
if (filament_count > 0)
resize_mixed_filament_metadata(m_print_config, size_t(filament_count), size_t(filament_count));
m_print_config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology", true)->value = printer_technology;
-1
View File
@@ -84,7 +84,6 @@
#include <cmath>
#include <cctype>
#include <cstdio>
#include <functional>
#include <gp_XY.hxx>
#include <initializer_list>
#include <math.h>
-3
View File
@@ -261,8 +261,6 @@ set(lisbslic3r_sources
GCode/PreciseSeam.cpp
GCode/PreciseSeam.hpp
GCode/PreciseSeamInternal.hpp
#GCodeSender.cpp
#GCodeSender.hpp
GCode/SmallAreaInfillFlowCompensator.cpp
GCode/SmallAreaInfillFlowCompensator.hpp
GCode/SpiralVase.cpp
@@ -447,7 +445,6 @@ set(lisbslic3r_sources
SLA/SupportTreeBuildsteps.hpp
SLA/SupportTree.cpp
SLA/SupportTree.hpp
#SLA/SupportTreeIGL.cpp
SLA/SupportTreeMesher.cpp
SLA/SupportTreeMesher.hpp
SlicesToTriangleMesh.cpp
-1
View File
@@ -2589,7 +2589,6 @@ void priv::create_face_types(FaceTypeMap &map,
}
#include <CGAL/Polygon_mesh_processing/clip.h>
#include <CGAL/Polygon_mesh_processing/corefinement.h>
bool priv::clip_cut(SurfacePatch &cut, CutMesh clipper)
{
CutMesh& tm = cut.mesh;
-1
View File
@@ -15,7 +15,6 @@
#include "Emboss.hpp"
#include <optional>
#include <stdio.h>
#include <numeric>
#include <cstdlib>
#include <boost/nowide/convert.hpp>
#include <boost/log/trivial.hpp>
+31 -25
View File
@@ -29,6 +29,7 @@
#include "ExtrusionEntity.hpp"
#include "Fill.hpp"
#include "libslic3r/Fill/FillBase.hpp"
#include "FillAdaptive.hpp"
#include "FillRectilinear.hpp"
#include "FillLightning.hpp"
#include "FillConcentricInternal.hpp"
@@ -926,7 +927,6 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.lateral_lattice_angle_2 = region_config.lateral_lattice_angle_2;
params.infill_overhang_angle = region_config.infill_overhang_angle;
params.center_of_surface_pattern = region_config.center_of_surface_pattern;
params.separated_infills = region_config.separated_infills;
if (params.pattern == ipLockedZag) {
params.infill_lock_depth = scale_(region_config.infill_lock_depth);
params.skin_infill_depth = scale_(region_config.skin_infill_depth);
@@ -999,6 +999,9 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
// (which would unnecessarily split fill batching).
// Stored on SurfaceFillParams; copied to FillParams during conversion.
params.gyroid_optimized = (params.pattern == ipGyroid) && region_config.gyroid_optimized;
// Orca: Likewise separated_infills only where it can move the pattern.
params.separated_infills = region_config.separated_infills && is_separable_infill_pattern(params.pattern) &&
params.extrusion_role != erTopSolidInfill && params.extrusion_role != erBottomSurface;
if (params.extrusion_role == erInternalInfill) {
params.angle = calculate_infill_rotation_angle(layer.object(), layer.id(), region_config.infill_direction.value,
@@ -1073,7 +1076,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
//get locked region param
if (params.pattern == ipLockedZag){
const PrintObject *object = layerm.layer()->object();
auto nozzle_diameter = float(object->print()->config().nozzle_diameter.get_at(layerm.region().extruder(extrusion_role) - 1));
auto nozzle_diameter = float(nozzle_diameter_for_filament(object->print()->config(), layerm.region().extruder(extrusion_role), object->print()->is_BBL_printer()));
Flow skin_flow = params.bridge ? params.flow : Flow::new_from_config_width(extrusion_role, region_config.skin_infill_line_width, nozzle_diameter, float((surface.thickness == -1) ? layer.height : surface.thickness));
//add skin flow
append_flow_param(lock_param.skin_flow_params, skin_flow, surface.expolygon);
@@ -1271,29 +1274,28 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
// Orca: Anchors and printed infill must share the same body origin. Keep the choice
// here so per-model surface centering and separated sparse infill cannot drift apart.
static BoundingBox infill_bounding_box(const Layer &layer, const SurfaceFill &fill, const ExPolygon &expoly, BoundingBox bbox)
// Returns the connected body the fill region is laid out on, or -1 to keep the object's origin.
static int infill_body(const Layer &layer, const SurfaceFill &fill, const ExPolygon &expoly)
{
const auto &params = fill.params;
const auto &config = layer.regions()[fill.region_id]->region().config();
const bool external = params.extrusion_role == erTopSolidInfill || params.extrusion_role == erBottomSurface;
const bool per_model = external && params.center_of_surface_pattern == CenterOfSurfacePattern::Each_Model &&
const bool per_model = (params.extrusion_role == erTopSolidInfill || params.extrusion_role == erBottomSurface) &&
params.center_of_surface_pattern == CenterOfSurfacePattern::Each_Model &&
(params.pattern == ipArchimedeanChords || params.pattern == ipOctagramSpiral);
const bool separate = !external && params.separated_infills &&
(is_separable_infill_pattern(params.pattern) || !config.solid_infill_rotate_template.value.empty() ||
!config.sparse_infill_rotate_template.value.empty());
if (per_model || separate) {
double best_overlap = 0.;
for (size_t i = 0; i < layer.lslices.size() && i < layer.lslices_separated_component_bboxes.size(); ++i) {
int body = -1;
if (per_model || params.separated_infills || is_octree_infill_pattern(params.pattern)) {
const BoundingBox box = get_extents(expoly);
double best_overlap = 0.;
for (size_t i = 0; i < layer.lslices.size() && i < layer.lslices_separated_component_ids.size(); ++i) {
if (! layer.lslices_bboxes[i].overlap(box))
continue;
const double overlap = area(intersection_ex(layer.lslices[i], expoly));
if (overlap > best_overlap) {
best_overlap = overlap;
const Point center = layer.lslices_separated_component_bboxes[i].center();
bbox = layer.object()->bounding_box();
bbox.translate(center.x(), center.y());
body = int(layer.lslices_separated_component_ids[i]);
}
}
}
return bbox;
return body;
}
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
@@ -1318,7 +1320,7 @@ void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill>
#endif
// friend to Layer
void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator)
void Layer::make_fills(const FillAdaptive::Octrees* adaptive_fill_octrees, const FillAdaptive::Octrees* support_fill_octrees, FillLightning::Generator* lightning_generator)
{
for (LayerRegion *layerm : m_regions)
layerm->fills.clear();
@@ -1351,7 +1353,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->fixed_angle = surface_fill.params.fixed_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
const FillAdaptive::Octrees *octrees = surface_fill.params.pattern == ipSupportCubic ? support_fill_octrees : adaptive_fill_octrees;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipConcentricInternal) {
@@ -1443,8 +1445,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
params.can_reverse = false;
for (ExPolygon& expoly : surface_fill.expolygons) {
// Orca: Reuse the body origin used for bridge anchoring, resetting it for each surface.
f->set_bounding_box(infill_bounding_box(*this, surface_fill, expoly, bbox));
// Orca: Reuse the body box and octree used for bridge anchoring, resetting them for each surface.
const int body = infill_body(*this, surface_fill, expoly);
f->set_bounding_box(body >= 0 ? this->object()->separated_body_bboxes()[body] : bbox);
f->adapt_fill_octree = octrees ? octrees->get(body) : nullptr;
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
if (params.symmetric_infill_y_axis) {
@@ -1512,7 +1516,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
* - For lightning/adaptive patterns, the respective generators are wired so their
* polylines match the final infill layout.
*/
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(const FillAdaptive::Octrees* adaptive_fill_octrees, const FillAdaptive::Octrees* support_fill_octrees, FillLightning::Generator* lightning_generator) const
{
LockRegionParam skin_inner_param;
std::vector<SurfaceFill> surface_fills = group_fills(*this, skin_inner_param);
@@ -1570,7 +1574,7 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
f->z = this->print_z;
f->angle = surface_fill.params.angle;
f->fixed_angle = surface_fill.params.fixed_angle;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
const FillAdaptive::Octrees *octrees = surface_fill.params.pattern == ipSupportCubic ? support_fill_octrees : adaptive_fill_octrees;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
@@ -1617,8 +1621,10 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Oc
params.extrusion_role = surface_fill.params.extrusion_role;
for (ExPolygon &expoly : surface_fill.expolygons) {
// Orca: Match the per-body origin of make_fills() before generating physical anchors.
f->set_bounding_box(infill_bounding_box(*this, surface_fill, expoly, bbox));
// Orca: Match the per-body box and octree of make_fills() before generating physical anchors.
const int body = infill_body(*this, surface_fill, expoly);
f->set_bounding_box(body >= 0 ? this->object()->separated_body_bboxes()[body] : bbox);
f->adapt_fill_octree = octrees ? octrees->get(body) : nullptr;
// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
f->spacing = surface_fill.params.spacing;
surface_fill.surface.expolygon = std::move(expoly);
@@ -1788,7 +1794,7 @@ void Layer::make_ironing()
// Create the ironing extrusions for regions <i, j)
ExPolygons ironing_areas;
double nozzle_dmr = this->object()->print()->config().nozzle_diameter.get_at(ironing_params.extruder - 1);
double nozzle_dmr = nozzle_diameter_for_filament(this->object()->print()->config(), ironing_params.extruder, this->object()->print()->is_BBL_printer());
if (ironing_params.just_infill) {
//TODO just_infill is currently not used.
// Just infill.
+1
View File
@@ -25,6 +25,7 @@ public:
// pattern is placed on top of previous layers
bool use_bridge_flow() const override { return false; }
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
protected:
void _fill_surface_single(
+22
View File
@@ -14,6 +14,7 @@
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/ExPolygon.hpp"
#include "FillBase.hpp"
#include <cstddef>
#include <memory>
#include <utility>
#include <Eigen/Geometry>
@@ -37,6 +38,27 @@ struct Octree;
struct OctreeDeleter { void operator()(Octree *p); };
using OctreePtr = std::unique_ptr<Octree, OctreeDeleter>;
// Orca: One octree per body (see Layer::lslices_separated_component_ids), and one of the whole object
// for objects of a single body or with a body that has none of its own.
struct Octrees
{
OctreePtr object;
std::vector<OctreePtr> bodies;
// A body without an octree, or body -1, uses the object's, or any body's when the object has none.
Octree *get(int body) const
{
if (body >= 0 && size_t(body) < bodies.size() && bodies[body])
return bodies[body].get();
if (object)
return object.get();
for (const OctreePtr &octree : bodies)
if (octree)
return octree.get();
return nullptr;
}
};
// Calculate line spacing for
// 1) adaptive cubic infill
// 2) adaptive internal support cubic infill
+12 -2
View File
@@ -128,6 +128,9 @@ Polylines Fill::fill_surface(const Surface *surface, const FillParams &params)
{
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
// Orca: Separated infills move the box center onto each body; origin-aligned patterns follow it.
const Point shift = this->aligned_to_origin() && ! empty(this->bounding_box) ? this->bounding_box.center() : Point::Zero();
translate(expp, -shift);
// Create the infills for each of the regions.
Polylines polylines_out;
for (size_t i = 0; i < expp.size(); ++ i)
@@ -137,6 +140,8 @@ Polylines Fill::fill_surface(const Surface *surface, const FillParams &params)
_infill_direction(surface),
std::move(expp[i]),
polylines_out);
for (Polyline &pl : polylines_out)
pl.translate(shift);
return polylines_out;
}
@@ -1591,13 +1596,18 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox Fill::extended_object_bounding_box() const
{
BoundingBox out = bounding_box;
// Orca: Extend about the box center, which separated infills move off the origin.
const Point c = this->bounding_box.center();
BoundingBox out = this->bounding_box;
out.translate(-c.x(), -c.y());
out.merge(Point(out.min.y(), out.min.x()));
out.merge(Point(out.max.y(), out.max.x()));
// The bounding box is scaled by sqrt(2.) to ensure that the bounding box
// covers any possible rotations.
return out.scaled(sqrt(2.));
out = out.scaled(sqrt(2.));
out.translate(c.x(), c.y());
return out;
}
void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
+3
View File
@@ -188,6 +188,9 @@ public:
// Return true if infill has a consistent pattern between layers.
virtual bool has_consistent_pattern() const { return false; }
// Orca: Is the pattern laid out from the origin instead of the bounding box center?
virtual bool aligned_to_origin() const { return false; }
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual ThickPolylines fill_surface_arachne(const Surface* surface, const FillParams& params);
+1
View File
@@ -19,6 +19,7 @@ public:
Fill *clone() const override { return new FillCrossHatch(*this); };
~FillCrossHatch() override {}
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
protected:
void _fill_surface_single(
+1
View File
@@ -20,6 +20,7 @@ public:
// require bridge flow since most of this pattern hangs in air
bool use_bridge_flow() const override { return false; }
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
// Correction applied to regular infill angle to maximize printing
// speed in default configuration (degrees)
+1
View File
@@ -20,6 +20,7 @@ class FillHoneycomb : public Fill
public:
~FillHoneycomb() override {}
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
protected:
Fill* clone() const override { return new FillHoneycomb(*this); };
+7 -18
View File
@@ -2750,23 +2750,6 @@ static void polylines_from_paths(const std::vector<MonotonicRegionLink> &path, c
}
}
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox FillRectilinear::extended_object_bounding_box() const {
// Build the extension around the box center. The transpose merge and the sqrt(2.) scaling
// (which covers any possible rotation) are both defined about the origin, so a box that is not
// origin-centered — e.g. a separated-infill box re-centered on a single assembly part — would be
// distorted. Shift to the origin first and back afterwards; for the default origin-centered box
// the two translations cancel and this is identical to the original behavior.
const Point c = this->bounding_box.center();
BoundingBox out = this->bounding_box;
out.translate(-c.x(), -c.y());
out.merge(Point(out.min.y(), out.min.x()));
out.merge(Point(out.max.y(), out.max.x()));
out = out.scaled(sqrt(2.));
out.translate(c.x(), c.y());
return out;
}
bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out)
{
// At the end, only the new polylines will be rotated back.
@@ -2801,7 +2784,13 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
// For infill that needs to be consistent between layers (like Zig Zag),
// we use bounding box of whole object to match vertical lines between layers.
BoundingBox bounding_box_src = poly_with_offset.bounding_box_src();
BoundingBox bounding_box = this->has_consistent_pattern() ? this->extended_object_bounding_box() : bounding_box_src;
BoundingBox bounding_box = bounding_box_src;
if (this->has_consistent_pattern()) {
// Orca: The polygons are rotated about the origin, so follow the box center to where it was rotated.
const Point c = this->bounding_box.center();
bounding_box = this->extended_object_bounding_box();
bounding_box.translate(c.rotated(- rotate_vector.first) - c);
}
// define flow spacing according to requested density
if (params.full_infill() && !params.dont_adjust) {
-3
View File
@@ -42,9 +42,6 @@ protected:
};
bool fill_surface_by_multilines(const Surface *surface, FillParams params, const std::initializer_list<SweepParams> &sweep_params, Polylines &polylines_out);
bool fill_surface_trapezoidal(const Surface *surface, FillParams params, Polylines &polylines_out, int Pattern_type);
// The extended bounding box of the whole object that covers any rotation of every layer.
BoundingBox extended_object_bounding_box() const;
};
class FillAlignedRectilinear : public FillRectilinear
+1
View File
@@ -31,6 +31,7 @@ public:
Polylines& polylines_out) override;
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
// Density adjustment to have a good %of weight.
static constexpr double DensityAdjust = 2.1;
+1
View File
@@ -31,6 +31,7 @@ public:
Polylines& polylines_out) override;
bool is_self_crossing() override { return false; }
bool aligned_to_origin() const override { return true; }
};
+4 -4
View File
@@ -241,14 +241,14 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config().support_line_width.value > 0) ? object->config().support_line_width : object->config().line_width,
// if object->config().support_filament == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament-1)),
float(nozzle_diameter_for_filament(object->print()->config(), object->config().support_filament, object->print()->is_BBL_printer())),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
}
//BBS
Flow support_transition_flow(const PrintObject* object)
{
//BBS: support transition of tree support is bridge flow
float dmr = float(object->print()->config().nozzle_diameter.get_at(object->config().support_filament - 1));
float dmr = float(nozzle_diameter_for_filament(object->print()->config(), object->config().support_filament, object->print()->is_BBL_printer()));
return Flow::bridging_flow(dmr, dmr);
}
@@ -260,7 +260,7 @@ Flow support_material_1st_layer_flow(const PrintObject *object, float layer_heig
frSupportMaterial,
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(width.value > 0) ? width : object->config().line_width,
float(print_config.nozzle_diameter.get_at(object->config().support_filament-1)),
float(nozzle_diameter_for_filament(print_config, object->config().support_filament, object->print()->is_BBL_printer())),
(layer_height > 0.f) ? layer_height : float(print_config.initial_layer_print_height.value));
}
@@ -271,7 +271,7 @@ Flow support_material_interface_flow(const PrintObject *object, float layer_heig
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
(object->config().support_line_width > 0) ? object->config().support_line_width : object->config().line_width,
// if object->config().support_interface_filament == 0 (which means to not trigger tool change, but use the current extruder instead), get_at will return the 0th component.
float(object->print()->config().nozzle_diameter.get_at(object->config().support_interface_filament-1)),
float(nozzle_diameter_for_filament(object->print()->config(), object->config().support_interface_filament, object->print()->is_BBL_printer())),
(layer_height > 0.f) ? layer_height : float(object->config().layer_height.value));
}
-1
View File
@@ -55,7 +55,6 @@
#include "TDataStd_Name.hxx"
#include "BRepBuilderAPI_Transform.hxx"
#include "TopExp_Explorer.hxx"
#include "TopExp_Explorer.hxx"
#include "BRep_Tool.hxx"
#include "BRepTools.hxx"
#include <IMeshTools_Parameters.hxx>
+41 -65
View File
@@ -43,7 +43,6 @@
#include "Print.hpp"
#include "Utils.hpp"
#include "ClipperUtils.hpp"
#include "libslic3r.h"
#include "LocalesUtils.hpp"
#include "libslic3r/format.hpp"
#include "Time.hpp"
@@ -155,14 +154,9 @@ static const float g_purge_volume_one_time = 135.f;
static const int g_max_flush_count = 4;
static const size_t g_max_label_object = 64;
static bool is_bambu_x2d_printer(const FullPrintConfig &config)
{
return config.printer_model.value == "Bambu Lab X2D";
}
// Multi-nozzle printer predicate: an extruder carries a nozzle cluster (extruder_max_nozzle_count
// entry > 1). Today only H2C profiles trip it, so every existing single- and dual-extruder printer
// is excluded and keeps its historic placeholder values.
// is excluded and keeps its historic first-filament marker.
static bool is_multi_nozzle_printer(const FullPrintConfig &config)
{
return std::any_of(config.extruder_max_nozzle_count.values.begin(),
@@ -170,33 +164,20 @@ static bool is_multi_nozzle_printer(const FullPrintConfig &config)
[](int v) { return v > 1; });
}
static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config, int hotend_id)
// current_hotend / next_hotend value. On a BBL printer: the real nozzle id only while the print uses a
// dynamic nozzle map (a filament moves between nozzles across layers), else -1. Bambu firmware reads an
// explicit hotend index as a request for the Filament Track Switch and rejects the job on a printer
// without one. group_result may be null on slicing paths that don't populate it, which resolves to -1.
// Any other printer has no firmware hotend selection and gets the filament's extruder index, whatever
// its nozzle map, so existing custom G-code keeps its values.
static int hotend_id_for_gcode_placeholder(const std::shared_ptr<MultiNozzleUtils::LayeredNozzleGroupResult> &group_result,
bool is_bbl_printer, int filament_id, int extruder_id, int layer_id = -1)
{
return is_bambu_x2d_printer(config) ? -1 : hotend_id;
}
// current_hotend / next_hotend value. For multi-nozzle printers a dynamic nozzle map yields the real
// nozzle id, a static map yields -1:
// - multi-nozzle (H2C): dynamic nozzle map -> real nozzle id; static -> -1.
// The dynamic branch is dormant today: the selector create() overload that sets the flag has no
// callers yet (deferred with the nozzle-assignment pipeline), so H2C currently resolves to -1.
// - X2D: keeps its historic -1 (single-nozzle -> falls through to the fallback helper).
// - every other (existing single-nozzle) printer: keeps its historic extruder-id value, so
// existing g-code stays byte-identical.
// group_result may be null on slicing paths that don't populate it -> the dynamic branch is simply
// skipped, so we never dereference null.
static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config,
const std::shared_ptr<MultiNozzleUtils::LayeredNozzleGroupResult> &group_result,
int filament_id,
int extruder_id,
int layer_id = -1)
{
if (is_multi_nozzle_printer(config)) {
if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0)
return group_result->get_nozzle_id(filament_id, layer_id);
return -1;
}
return hotend_id_for_gcode_placeholder(config, extruder_id);
if (!is_bbl_printer)
return extruder_id;
if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0)
return group_result->get_nozzle_id(filament_id, layer_id);
return -1;
}
// Logical nozzle id for the *_nozzle_id placeholders. Null-safe: falls back to the
@@ -211,24 +192,20 @@ static int nozzle_id_for_gcode_placeholder(const std::shared_ptr<MultiNozzleUtil
// Init variants: the start-gcode init sites (first_non_support_hotend / initial_no_support_hotend /
// current_hotend / initial_nozzle_id / filament_start current_nozzle_id) use get_first_nozzle_for_filament
// (the nozzle a filament FIRST uses) rather than the layer-based get_nozzle_id. Same hotend-value semantics
// as hotend_id_for_gcode_placeholder above (multi-nozzle static -> -1; dynamic branch dormant;
// existing printers -> extruder id; X2D -> -1); they differ from the layer-based helper only on the dormant
// dynamic path for a filament first used after layer 0.
static int first_hotend_id_for_gcode_placeholder(const FullPrintConfig &config,
const std::shared_ptr<MultiNozzleUtils::LayeredNozzleGroupResult> &group_result,
int filament_id,
int extruder_id)
// (the nozzle a filament FIRST uses) rather than the layer-based get_nozzle_id. Same hotend-value rule
// as hotend_id_for_gcode_placeholder above; they differ from the layer-based helper only on the dynamic
// path for a filament first used after layer 0.
static int first_hotend_id_for_gcode_placeholder(const std::shared_ptr<MultiNozzleUtils::LayeredNozzleGroupResult> &group_result,
bool is_bbl_printer, int filament_id, int extruder_id)
{
if (is_multi_nozzle_printer(config)) {
if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0) {
auto nozzle = group_result->get_first_nozzle_for_filament(filament_id);
if (nozzle)
return nozzle->group_id;
}
return -1;
if (!is_bbl_printer)
return extruder_id;
if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0) {
auto nozzle = group_result->get_first_nozzle_for_filament(filament_id);
if (nozzle)
return nozzle->group_id;
}
return hotend_id_for_gcode_placeholder(config, extruder_id);
return -1;
}
static int first_nozzle_id_for_gcode_placeholder(const std::shared_ptr<MultiNozzleUtils::LayeredNozzleGroupResult> &group_result,
@@ -1215,12 +1192,11 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
config.set_key_value("next_extruder", new ConfigOptionInt(new_filament_id));
// current_hotend/next_hotend (see hotend_id_for_gcode_placeholder): multi-nozzle H2C -> -1
// (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id.
const bool is_bbl_printer = gcodegen.m_print->is_BBL_printer();
config.set_key_value("current_hotend", new ConfigOptionInt(
hotend_id_for_gcode_placeholder(gcodegen.m_config, group_result, old_filament_id, old_extruder_id, m_layer_idx)));
hotend_id_for_gcode_placeholder(group_result, is_bbl_printer, old_filament_id, old_extruder_id, m_layer_idx)));
config.set_key_value("next_hotend", new ConfigOptionInt(
hotend_id_for_gcode_placeholder(gcodegen.m_config, group_result, new_filament_id, (int) gcodegen.get_extruder_id(new_filament_id), m_layer_idx)));
hotend_id_for_gcode_placeholder(group_result, is_bbl_printer, new_filament_id, (int) gcodegen.get_extruder_id(new_filament_id), m_layer_idx)));
config.set_key_value("current_nozzle_id", new ConfigOptionInt(old_nozzle_id));
config.set_key_value("next_nozzle_id", new ConfigOptionInt(next_nozzle_id));
config.set_key_value("current_filament_id", new ConfigOptionInt(old_filament_id));
@@ -1499,7 +1475,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
gcodegen.placeholder_parser().set("current_nozzle_id",
nozzle_id_for_gcode_placeholder(group_result, new_filament_id, new_extruder_id, m_layer_idx));
gcodegen.placeholder_parser().set("current_hotend",
hotend_id_for_gcode_placeholder(gcodegen.m_config, group_result, new_filament_id, new_extruder_id, m_layer_idx));
hotend_id_for_gcode_placeholder(group_result, gcodegen.m_print->is_BBL_printer(), new_filament_id, new_extruder_id, m_layer_idx));
{
size_t fi = gcodegen.get_filament_config_index(new_filament_id);
gcodegen.placeholder_parser().set("retraction_distance_when_cut", gcodegen.m_config.retraction_distances_when_cut.get_at(fi));
@@ -3310,20 +3286,19 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
first_non_support_hotends.reserve(first_non_support_filaments.size());
for (int filament_id : first_non_support_filaments)
first_non_support_hotends.push_back(filament_id < 0 ? -1 :
first_hotend_id_for_gcode_placeholder(m_config, group_result, filament_id, (int) get_extruder_id(filament_id)));
first_hotend_id_for_gcode_placeholder(group_result, is_bbl_printers, filament_id, (int) get_extruder_id(filament_id)));
this->placeholder_parser().set("first_non_support_tools", new ConfigOptionInts(first_non_support_filaments));
this->placeholder_parser().set("first_non_support_filaments", new ConfigOptionInts(first_non_support_filaments));
this->placeholder_parser().set("first_non_support_hotend", new ConfigOptionInts(first_non_support_hotends));
this->placeholder_parser().set("initial_no_support_tool", initial_non_support_extruder_id);
this->placeholder_parser().set("initial_no_support_extruder", initial_non_support_extruder_id);
// initial_no_support_hotend/current_hotend (see first_hotend_id_for_gcode_placeholder): multi-nozzle
// H2C -> -1 (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id.
this->placeholder_parser().set("initial_no_support_hotend",
first_hotend_id_for_gcode_placeholder(m_config, group_result, (int) initial_non_support_extruder_id, (int) get_extruder_id(initial_non_support_extruder_id)));
first_hotend_id_for_gcode_placeholder(group_result, is_bbl_printers, (int) initial_non_support_extruder_id,
(int) get_extruder_id(initial_non_support_extruder_id)));
this->placeholder_parser().set("current_extruder", initial_extruder_id);
this->placeholder_parser().set("current_hotend",
first_hotend_id_for_gcode_placeholder(m_config, group_result, (int) initial_extruder_id, extruder_id));
first_hotend_id_for_gcode_placeholder(group_result, is_bbl_printers, (int) initial_extruder_id, extruder_id));
this->placeholder_parser().set("current_filament_id", (int) initial_extruder_id);
this->placeholder_parser().set("current_extruder_id", extruder_id);
this->placeholder_parser().set("current_nozzle_id",
@@ -3832,7 +3807,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
file.writeln(filament_start_gcode);
// Mark the first filament used in print. Multi-nozzle printers (H2C) get ";VT%d H%d" where
// H = dynamic ? nozzle_id : -1; existing single-nozzle printers keep the bare ";VT%d" so their
// g-code stays byte-identical. (The dynamic branch is dormant, so H2C currently emits H-1.)
// g-code stays byte-identical.
if (is_multi_nozzle_printer(m_config)) {
int initial_nozzle_id = -1;
if (group_result && group_result->is_support_dynamic_nozzle_map()) {
@@ -9616,6 +9591,9 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
this->placeholder_parser().set("current_extruder_id", new_extruder_id);
this->placeholder_parser().set("current_nozzle_id",
nozzle_id_for_gcode_placeholder(m_print->get_layered_nozzle_group_result(), (int) new_filament_id, new_extruder_id, m_layer_index));
this->placeholder_parser().set("current_hotend",
hotend_id_for_gcode_placeholder(m_print->get_layered_nozzle_group_result(), m_print->is_BBL_printer(), (int) new_filament_id,
new_extruder_id, m_layer_index));
{
size_t fi = get_filament_config_index(new_filament_id);
this->placeholder_parser().set("retraction_distance_when_ec", m_config.retraction_distances_when_ec.get_at(fi));
@@ -9794,12 +9772,10 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
dyn_config.set_key_value("outer_wall_volumetric_speed", new ConfigOptionFloat(outer_wall_volumetric_speed));
dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id));
dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int)new_filament_id));
// current_hotend/next_hotend (see hotend_id_for_gcode_placeholder): multi-nozzle H2C -> -1
// (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id.
dyn_config.set_key_value("current_hotend", new ConfigOptionInt(
hotend_id_for_gcode_placeholder(m_config, group_result, old_filament_id, old_extruder_id, m_layer_index)));
hotend_id_for_gcode_placeholder(group_result, m_print->is_BBL_printer(), old_filament_id, old_extruder_id, m_layer_index)));
dyn_config.set_key_value("next_hotend", new ConfigOptionInt(
hotend_id_for_gcode_placeholder(m_config, group_result, (int) new_filament_id, new_extruder_id, m_layer_index)));
hotend_id_for_gcode_placeholder(group_result, m_print->is_BBL_printer(), (int) new_filament_id, new_extruder_id, m_layer_index)));
dyn_config.set_key_value("current_nozzle_id", new ConfigOptionInt(old_nozzle_id));
dyn_config.set_key_value("next_nozzle_id", new ConfigOptionInt(next_nozzle_id));
dyn_config.set_key_value("current_filament_id", new ConfigOptionInt(old_filament_id));
@@ -9977,7 +9953,7 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
this->placeholder_parser().set("current_extruder", new_filament_id);
this->placeholder_parser().set("current_hotend",
hotend_id_for_gcode_placeholder(m_config, group_result, (int) new_filament_id, new_extruder_id, m_layer_index));
hotend_id_for_gcode_placeholder(group_result, m_print->is_BBL_printer(), (int) new_filament_id, new_extruder_id, m_layer_index));
// Orca: keep the global current-tool identity coherent for later contexts (see append_tcr).
this->placeholder_parser().set("current_filament_id", (int) new_filament_id);
this->placeholder_parser().set("current_extruder_id", new_extruder_id);
-2
View File
@@ -148,8 +148,6 @@ struct ConflictComputeResult
using ConflictComputeOpt = std::optional<ConflictComputeResult>;
using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
struct ConflictChecker
{
static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional<const FakeWipeTower *> wtdptr);
-2
View File
@@ -27,8 +27,6 @@
#include "../PrintConfig.hpp"
#include "../Utils.hpp"
#include "Print.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/libslic3r.h"
#include <boost/log/trivial.hpp>
#include <string>
+1 -4
View File
@@ -22,9 +22,6 @@
namespace Slic3r {
namespace PreciseSeam {
// Import EnforcedBlockedSeamPoint from SeamPlacerImpl namespace for convenience
using SeamPlacerImpl::EnforcedBlockedSeamPoint;
// Geometry and its exterior bounds are prepared together, then treated as read-only.
struct ModifierRegion {
ExPolygon polygon;
@@ -137,7 +134,7 @@ SegmentExtraction extract_perimeter_segments(const PreparedPerimeter &prepared,
// Result of weak modifier segment processing
struct WeakModifierSegment {
EnforcedBlockedSeamPoint type; // Enforced/Blocked/Neutral
SeamPlacerImpl::EnforcedBlockedSeamPoint type; // Enforced/Blocked/Neutral
Point left_point; // Coordinates of left (first) point of segment
PerimeterPosition left_position; // Position on the source perimeter before insertion/refinement.
Point right_point; // Coordinates of right (last) point of segment
+1 -2
View File
@@ -40,8 +40,7 @@ std::string get_error_string(const ThumbnailErrors& errors);
typedef std::vector<std::pair<GCodeThumbnailsFormat, Vec2d>> GCodeThumbnailDefinitionsList;
using namespace std::literals;
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const std::string& thumbnails_string, const std::string_view def_ext = "PNG"sv);
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const std::string& thumbnails_string, const std::string_view def_ext = "PNG");
std::pair<GCodeThumbnailDefinitionsList, ThumbnailErrors> make_and_check_thumbnail_list(const ConfigBase &config);
-580
View File
@@ -1,580 +0,0 @@
#include "GCodeSender.hpp"
#include <iostream>
#include <istream>
#include <string>
#include <thread>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
#if defined(__APPLE__) || defined(__OpenBSD__)
#include <termios.h>
#endif
#ifdef __APPLE__
#include <sys/ioctl.h>
#include <IOKit/serial/ioss.h>
#endif
#ifdef __linux__
#include <sys/ioctl.h>
#include <fcntl.h>
#include "/usr/include/asm-generic/ioctls.h"
/* The following definitions are kindly borrowed from:
/usr/include/asm-generic/termbits.h
Unfortunately we cannot just include that one because
it would redefine the "struct termios" already defined
the <termios.h> already included by Boost.ASIO. */
#define K_NCCS 19
struct termios2 {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[K_NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
#define BOTHER CBAUDEX
#endif
//#define DEBUG_SERIAL
#ifdef DEBUG_SERIAL
#include <cstdlib>
#include <fstream>
std::fstream fs;
#endif
#define KEEP_SENT 20
namespace Slic3r {
GCodeSender::GCodeSender()
: io(), serial(io), can_send(false), sent(0), open(false), error(false),
connected(false), queue_paused(false)
{
#ifdef DEBUG_SERIAL
std::srand(std::time(nullptr));
#endif
}
GCodeSender::~GCodeSender()
{
this->disconnect();
}
bool
GCodeSender::connect(std::string devname, unsigned int baud_rate)
{
this->disconnect();
this->set_error_status(false);
try {
this->serial.open(devname);
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::odd));
this->serial.set_option(boost::asio::serial_port_base::character_size(boost::asio::serial_port_base::character_size(8)));
this->serial.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));
this->serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
this->set_baud_rate(baud_rate);
this->serial.close();
this->serial.open(devname);
this->serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
// set baud rate again because set_option overwrote it
this->set_baud_rate(baud_rate);
this->open = true;
this->reset();
} catch (boost::system::system_error &) {
this->set_error_status(true);
return false;
}
// a reset firmware expect line numbers to start again from 1
this->sent = 0;
this->last_sent.clear();
/* Initialize debugger */
#ifdef DEBUG_SERIAL
fs.open("serial.txt", std::fstream::out | std::fstream::trunc);
#endif
// this gives some work to the io_service before it is started
// (post() runs the supplied function in its thread)
this->io.post(boost::bind(&GCodeSender::do_read, this));
// start reading in the background thread
boost::thread t(boost::bind(&boost::asio::io_service::run, &this->io));
this->background_thread.swap(t);
// always send a M105 to check for connection because firmware might be silent on connect
//FIXME Vojtech: This is being sent too early, leading to line number synchronization issues,
// from which the GCodeSender never recovers.
// this->send("M105", true);
return true;
}
void
GCodeSender::set_baud_rate(unsigned int baud_rate)
{
try {
// This does not support speeds > 115200
this->serial.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
} catch (boost::system::system_error &) {
boost::asio::serial_port::native_handle_type handle = this->serial.native_handle();
#if __APPLE__
termios ios;
::tcgetattr(handle, &ios);
::cfsetspeed(&ios, baud_rate);
speed_t newSpeed = baud_rate;
ioctl(handle, IOSSIOSPEED, &newSpeed);
::tcsetattr(handle, TCSANOW, &ios);
#elif __linux__
termios2 ios;
if (ioctl(handle, TCGETS2, &ios))
printf("Error in TCGETS2: %s\n", strerror(errno));
ios.c_ispeed = ios.c_ospeed = baud_rate;
ios.c_cflag &= ~CBAUD;
ios.c_cflag |= BOTHER | CLOCAL | CREAD;
ios.c_cc[VMIN] = 1; // Minimum of characters to read, prevents eof errors when 0 bytes are read
ios.c_cc[VTIME] = 1;
if (ioctl(handle, TCSETS2, &ios))
printf("Error in TCSETS2: %s\n", strerror(errno));
#elif __OpenBSD__
struct termios ios;
::tcgetattr(handle, &ios);
::cfsetspeed(&ios, baud_rate);
if (::tcsetattr(handle, TCSAFLUSH, &ios) != 0)
printf("Failed to set baud rate: %s\n", strerror(errno));
#else
//throw Slic3r::InvalidArgument("OS does not currently support custom bauds");
#endif
}
}
void
GCodeSender::disconnect()
{
if (!this->open) return;
this->open = false;
this->connected = false;
this->io.post(boost::bind(&GCodeSender::do_close, this));
this->background_thread.join();
this->io.reset();
/*
if (this->error_status()) {
throw(boost::system::system_error(boost::system::error_code(),
"Error while closing the device"));
}
*/
#ifdef DEBUG_SERIAL
fs << "DISCONNECTED" << std::endl << std::flush;
fs.close();
#endif
}
bool
GCodeSender::is_connected() const
{
return this->connected;
}
bool
GCodeSender::wait_connected(unsigned int timeout) const
{
using namespace boost::posix_time;
ptime t0 = second_clock::local_time() + seconds(timeout);
while (!this->connected) {
if (second_clock::local_time() > t0) return false;
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
return true;
}
size_t
GCodeSender::queue_size() const
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
return this->queue.size();
}
void
GCodeSender::pause_queue()
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
this->queue_paused = true;
}
void
GCodeSender::resume_queue()
{
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
this->queue_paused = false;
}
this->send();
}
void
GCodeSender::purge_queue(bool priority)
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
if (priority) {
// clear priority queue
std::list<std::string> empty;
std::swap(this->priqueue, empty);
} else {
// clear queue
std::queue<std::string> empty;
std::swap(this->queue, empty);
this->queue_paused = false;
}
}
// purge log and return its contents
std::vector<std::string>
GCodeSender::purge_log()
{
boost::lock_guard<boost::mutex> l(this->log_mutex);
std::vector<std::string> retval;
retval.reserve(this->log.size());
while (!this->log.empty()) {
retval.push_back(this->log.front());
this->log.pop();
}
return retval;
}
std::string
GCodeSender::getT() const
{
boost::lock_guard<boost::mutex> l(this->log_mutex);
return this->T;
}
std::string
GCodeSender::getB() const
{
boost::lock_guard<boost::mutex> l(this->log_mutex);
return this->B;
}
void
GCodeSender::do_close()
{
this->set_error_status(false);
boost::system::error_code ec;
this->serial.cancel(ec);
if (ec) this->set_error_status(true);
this->serial.close(ec);
if (ec) this->set_error_status(true);
}
void
GCodeSender::set_error_status(bool e)
{
boost::lock_guard<boost::mutex> l(this->error_mutex);
this->error = e;
}
bool
GCodeSender::error_status() const
{
boost::lock_guard<boost::mutex> l(this->error_mutex);
return this->error;
}
void
GCodeSender::do_read()
{
// read one line
boost::asio::async_read_until(
this->serial,
this->read_buffer,
'\n',
boost::bind(
&GCodeSender::on_read,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
}
void
GCodeSender::on_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
this->set_error_status(false);
if (error) {
#ifdef __APPLE__
if (error.value() == 45) {
// OS X bug: http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html
this->do_read();
return;
}
#endif
// printf("ERROR: [%d] %s\n", error.value(), error.message().c_str());
// error can be true even because the serial port was closed.
// In this case it is not a real error, so ignore.
if (this->open) {
this->do_close();
this->set_error_status(true);
}
return;
}
std::istream is(&this->read_buffer);
std::string line;
std::getline(is, line);
if (!line.empty()) {
#ifdef DEBUG_SERIAL
fs << "<< " << line << std::endl << std::flush;
#endif
// note that line might contain \r at its end
// parse incoming line
if (!this->connected
&& (boost::starts_with(line, "start")
|| boost::starts_with(line, "Grbl ")
|| boost::starts_with(line, "ok")
|| boost::contains(line, "T:"))) {
this->connected = true;
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
this->can_send = true;
}
this->send();
} else if (boost::starts_with(line, "ok")) {
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
this->can_send = true;
}
this->send();
} else if (boost::istarts_with(line, "resend") // Marlin uses "Resend: "
|| boost::istarts_with(line, "rs")) {
// extract the first number from line
boost::algorithm::trim_left_if(line, !boost::algorithm::is_digit());
size_t toresend = boost::lexical_cast<size_t>(line.substr(0, line.find_first_not_of("0123456789")));
#ifdef DEBUG_SERIAL
fs << "!! line num out of sync: toresend = " << toresend << ", sent = " << sent << ", last_sent.size = " << last_sent.size() << std::endl;
#endif
if (toresend > this->sent - this->last_sent.size() && toresend <= this->sent) {
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
const auto lines_to_resend = this->sent - toresend + 1;
#ifdef DEBUG_SERIAL
fs << "!! resending " << lines_to_resend << " lines" << std::endl;
#endif
// move the unsent lines to priqueue
this->priqueue.insert(
this->priqueue.begin(), // insert at the beginning
this->last_sent.begin() + this->last_sent.size() - lines_to_resend,
this->last_sent.end()
);
// we can empty last_sent because it's not useful anymore
this->last_sent.clear();
// start resending with the requested line number
this->sent = toresend - 1;
this->can_send = true;
}
this->send();
} else {
printf("Cannot resend %zu (oldest we have is %zu)\n", toresend, this->sent - this->last_sent.size());
}
} else if (boost::starts_with(line, "wait")) {
// ignore
} else {
// push any other line into the log
boost::lock_guard<boost::mutex> l(this->log_mutex);
this->log.push(line);
}
// parse temperature info
{
size_t pos = line.find("T:");
if (pos != std::string::npos && line.size() > pos + 2) {
// we got temperature info
boost::lock_guard<boost::mutex> l(this->log_mutex);
this->T = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2));
pos = line.find("B:");
if (pos != std::string::npos && line.size() > pos + 2) {
// we got bed temperature info
this->B = line.substr(pos+2, line.find_first_not_of("0123456789.", pos+2) - (pos+2));
}
}
}
}
this->do_read();
}
void
GCodeSender::send(const std::vector<std::string> &lines, bool priority)
{
// append lines to queue
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
for (std::vector<std::string>::const_iterator line = lines.begin(); line != lines.end(); ++line) {
if (priority) {
this->priqueue.push_back(*line);
} else {
this->queue.push(*line);
}
}
}
this->send();
}
void
GCodeSender::send(const std::string &line, bool priority)
{
// append line to queue
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
if (priority) {
this->priqueue.push_back(line);
} else {
this->queue.push(line);
}
}
this->send();
}
void
GCodeSender::send()
{
this->io.post(boost::bind(&GCodeSender::do_send, this));
}
void
GCodeSender::do_send()
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
// printer is not connected or we're still waiting for the previous ack
if (!this->can_send) return;
std::string line;
while (!this->priqueue.empty() || (!this->queue.empty() && !this->queue_paused)) {
if (!this->priqueue.empty()) {
line = this->priqueue.front();
this->priqueue.pop_front();
} else {
line = this->queue.front();
this->queue.pop();
}
// strip comments
size_t comment_pos = line.find_first_of(';');
if (comment_pos != std::string::npos)
line.erase(comment_pos, std::string::npos);
boost::algorithm::trim(line);
// if line is not empty, send it
if (!line.empty()) break;
// if line is empty, process next item in queue
}
if (line.empty()) return;
// compute full line
++ this->sent;
#ifndef DEBUG_SERIAL
const auto line_num = this->sent;
#else
// In DEBUG_SERIAL mode, test line re-synchronization by sending bad line number 1/4 of the time
const auto line_num = std::rand() < RAND_MAX/4 ? 0 : this->sent;
#endif
std::string full_line = "N" + boost::lexical_cast<std::string>(line_num) + " " + line;
// calculate checksum
int cs = 0;
for (std::string::const_iterator it = full_line.begin(); it != full_line.end(); ++it)
cs = cs ^ *it;
// write line to device
full_line += "*";
full_line += boost::lexical_cast<std::string>(cs);
full_line += "\n";
#ifdef DEBUG_SERIAL
fs << ">> " << full_line << std::flush;
#endif
this->last_sent.push_back(line);
this->can_send = false;
while (this->last_sent.size() > KEEP_SENT) {
this->last_sent.pop_front();
}
// we can't supply boost::asio::buffer(full_line) to async_write() because full_line is on the
// stack and the buffer would lose its underlying storage causing memory corruption
std::ostream os(&this->write_buffer);
os << full_line;
boost::asio::async_write(this->serial, this->write_buffer, boost::bind(&GCodeSender::on_write, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void
GCodeSender::on_write(const boost::system::error_code& error,
size_t bytes_transferred)
{
this->set_error_status(false);
if (error) {
if (this->open) {
this->do_close();
this->set_error_status(true);
}
return;
}
this->do_send();
}
void
GCodeSender::set_DTR(bool on)
{
#if defined(_WIN32) && !defined(__SYMBIAN32__)
boost::asio::serial_port_service::native_handle_type handle = this->serial.native_handle();
if (on)
EscapeCommFunction(handle, SETDTR);
else
EscapeCommFunction(handle, CLRDTR);
#else
int fd = this->serial.native_handle();
int status;
ioctl(fd, TIOCMGET, &status);
if (on)
status |= TIOCM_DTR;
else
status &= ~TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);
#endif
}
void
GCodeSender::reset()
{
set_DTR(false);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
set_DTR(true);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
set_DTR(false);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
} // namespace Slic3r
-81
View File
@@ -1,81 +0,0 @@
#ifndef slic3r_GCodeSender_hpp_
#define slic3r_GCodeSender_hpp_
#include "libslic3r.h"
#include <queue>
#include <boost/core/noncopyable.hpp>
#include <cstddef>
#include <boost/asio/io_service.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/asio/streambuf.hpp>
#include <list>
#include <deque>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
#include <boost/bind/bind.hpp>
#include <boost/thread.hpp>
namespace Slic3r {
namespace asio = boost::asio;
class GCodeSender : private boost::noncopyable {
public:
GCodeSender();
~GCodeSender();
bool connect(std::string devname, unsigned int baud_rate);
void send(const std::vector<std::string> &lines, bool priority = false);
void send(const std::string &s, bool priority = false);
void disconnect();
bool error_status() const;
bool is_connected() const;
bool wait_connected(unsigned int timeout = 3) const;
size_t queue_size() const;
void pause_queue();
void resume_queue();
void purge_queue(bool priority = false);
std::vector<std::string> purge_log();
std::string getT() const;
std::string getB() const;
void set_DTR(bool on);
void reset();
private:
asio::io_service io;
asio::serial_port serial;
boost::thread background_thread;
boost::asio::streambuf read_buffer, write_buffer;
bool open; // whether the serial socket is connected
bool connected; // whether the printer is online
bool error;
mutable boost::mutex error_mutex;
// this mutex guards queue, priqueue, can_send, queue_paused, sent, last_sent
mutable boost::mutex queue_mutex;
std::queue<std::string> queue;
std::list<std::string> priqueue;
bool can_send;
bool queue_paused;
size_t sent;
std::deque<std::string> last_sent;
// this mutex guards log, T, B
mutable boost::mutex log_mutex;
std::queue<std::string> log;
std::string T, B;
void set_baud_rate(unsigned int baud_rate);
void set_error_status(bool e);
void do_send();
void on_write(const boost::system::error_code& error, size_t bytes_transferred);
void do_close();
void do_read();
void on_read(const boost::system::error_code& error, size_t bytes_transferred);
void send();
};
} // namespace Slic3r
#endif /* slic3r_GCodeSender_hpp_ */
-2
View File
@@ -94,8 +94,6 @@ struct Circle {
using Circlef = Circle<Vec2f>;
using Circled = Circle<Vec2d>;
using CircleSqf = CircleSq<Vec2f>;
using CircleSqd = CircleSq<Vec2d>;
/// Find the center of the circle corresponding to the vector of Points as an arc.
Point circle_center_taubin_newton(const Points::const_iterator& input_start, const Points::const_iterator& input_end, size_t cycles = 20);
-1
View File
@@ -1,7 +1,6 @@
#include <boost/log/trivial.hpp>
#include "MedialAxis.hpp"
#include <boost/log/trivial.hpp>
#include <boost/polygon/polygon.hpp>
#include <cassert>
#include <cmath>
+8 -8
View File
@@ -33,7 +33,7 @@ class PrintObject;
class Print;
namespace FillAdaptive {
struct Octree;
struct Octrees;
};
namespace FillLightning {
@@ -170,10 +170,10 @@ public:
ExPolygons lslices;
ExPolygons lslices_extrudable; // BBS: the extrudable part of lslices used for tree support
std::vector<BoundingBox> lslices_bboxes;
// Orca: for separated infills / per-model centering. Aligned with lslices: for each island, the
// full bounding box of the 3D connected body (across all layers) it belongs to. Populated by
// PrintObject::infill() only when the feature is used; empty otherwise.
std::vector<BoundingBox> lslices_separated_component_bboxes;
// Orca: for separated infills / per-model centering / octree infills. Aligned with lslices: for each
// island, the 3D connected body (across all layers) it belongs to, indexing
// PrintObject::separated_body_bboxes(). Populated by PrintObject::prepare_infill() only when needed.
std::vector<size_t> lslices_separated_component_ids;
// BBS
ExPolygons loverhangs;
@@ -208,9 +208,9 @@ public:
void make_perimeters();
// Phony version of make_fills() without parameters for Perl integration only.
void make_fills() { this->make_fills(nullptr, nullptr); }
void make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator = nullptr);
Polylines generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
void make_fills(const FillAdaptive::Octrees* adaptive_fill_octrees, const FillAdaptive::Octrees* support_fill_octrees, FillLightning::Generator* lightning_generator = nullptr);
Polylines generate_sparse_infill_polylines_for_anchoring(const FillAdaptive::Octrees *adaptive_fill_octrees,
const FillAdaptive::Octrees *support_fill_octrees,
FillLightning::Generator* lightning_generator) const;
void make_ironing();
// Returns the filament id (1-based) the region is ironed with, or -1 when the
+1 -1
View File
@@ -62,7 +62,7 @@ Flow LayerRegion::bridging_flow(FlowRole role, bool thick_bridge) const
const PrintObject &print_object = *this->layer()->object();
Flow bridge_flow;
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will fall back to zero'th element, so everything is all right.
auto nozzle_diameter = float(print_object.print()->config().nozzle_diameter.get_at(region.extruder(role) - 1));
auto nozzle_diameter = float(nozzle_diameter_for_filament(print_object.print()->config(), region.extruder(role), print_object.print()->is_BBL_printer()));
const ConfigOptionFloatOrPercent& bridge_width_opt = region_config.bridge_line_width;
const double bridge_width = bridge_width_opt.get_abs_value(nozzle_diameter);
const bool has_bridge_width = bridge_width > 0.;
+3 -4
View File
@@ -154,13 +154,12 @@ template<class ExecutionPolicy, class Enable = void> struct _Loop
};
// Add Specialization for using ExecutionTBB for parallel loops.
using namespace Slic3r;
template<> struct _Loop<ExecutionTBB>
template<> struct _Loop<Slic3r::ExecutionTBB>
{
template<class It, class Fn> static void for_each_idx(It from, It to, Fn&& fn)
{
execution::for_each(
ex_tbb, size_t(0), size_t(to - from), [&from, &fn](size_t i) { fn(from[i], i); }, execution::max_concurrency(ex_tbb));
Slic3r::execution::for_each(
Slic3r::ex_tbb, size_t(0), size_t(to - from), [&from, &fn](size_t i) { fn(from[i], i); }, Slic3r::execution::max_concurrency(Slic3r::ex_tbb));
}
};
+3 -1
View File
@@ -22,7 +22,6 @@
#include "Format/AssimpImport.hpp"
#include "ClipperUtils.hpp"
#include "Exception.hpp"
#include "Model.hpp"
#include "ModelArrange.hpp"
#include "Arrange.hpp"
#include "Geometry.hpp"
@@ -1697,6 +1696,9 @@ indexed_triangle_set ModelObject::raw_indexed_triangle_set() const
size_t j = out.indices.size();
append(out.vertices, v->mesh().its.vertices);
append(out.indices, v->mesh().its.indices);
// Orca: Point the volume's triangles at its own vertices, which follow those of the volumes before it.
for (size_t k = j; k < out.indices.size(); ++ k)
out.indices[k] += stl_triangle_vertex_indices::Constant(int(i));
const Transform3d& m = v->get_matrix();
for (; i < out.vertices.size(); ++ i)
out.vertices[i] = (m * out.vertices[i].cast<double>()).cast<float>().eval();
-1
View File
@@ -18,7 +18,6 @@
#include "TriangleMesh.hpp"
#include "CustomGCode.hpp"
#include "calib.hpp"
#include "enum_bitmask.hpp"
#include "TextConfiguration.hpp"
#include "EmbossShape.hpp"
#include "TriangleSelector.hpp"
-18
View File
@@ -3593,24 +3593,6 @@ void PresetBundle::export_selections(AppConfig &config)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": printer %1%, print %2%, filaments[0] %3% ")%printers.get_selected_preset_name() % prints.get_selected_preset_name() %filament_presets[0];
}
// Preserve metadata only for existing colour slots; new slots get false/empty defaults.
static void resize_mixed_filament_metadata(DynamicPrintConfig &config, size_t old_slot_count, size_t new_slot_count)
{
auto resize = [old_slot_count, new_slot_count](auto *opt) {
if (opt) {
opt->values.resize(std::min(old_slot_count, opt->values.size()));
opt->values.resize(new_slot_count);
}
};
resize(config.option<ConfigOptionBools>("filament_is_mixed"));
resize(config.option<ConfigOptionStrings>("filament_mixed_components"));
resize(config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios"));
resize(config.option<ConfigOptionBools>("filament_mixed_gradient"));
resize(config.option<ConfigOptionStrings>("filament_mixed_gradient_range"));
resize(config.option<ConfigOptionStrings>("filament_mixed_gradient_curve"));
resize(config.option<ConfigOptionBools>("filament_mixed_gradient_per_part"));
}
void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
{
unsigned old_filament_count = this->filament_presets.size();
+9 -8
View File
@@ -2229,7 +2229,7 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
for (const PrintRegion &region : object->all_regions()) {
const auto &bridge_width_opt = region.config().bridge_line_width;
for (FlowRole bridge_role : { frPerimeter, frInfill, frSolidInfill, frTopSolidInfill }) {
const double nozzle_diameter = m_config.nozzle_diameter.get_at(region.extruder(bridge_role) - 1);
const double nozzle_diameter = nozzle_diameter_for_filament(m_config, region.extruder(bridge_role), this->is_BBL_printer());
const double bridge_width = bridge_width_opt.get_abs_value(nozzle_diameter);
if (bridge_width <= 0.)
continue;
@@ -2606,7 +2606,7 @@ Flow Print::brim_flow() const
frPerimeter,
// Flow::new_from_config_width takes care of the percent to value substitution
width,
(float)m_config.nozzle_diameter.get_at(m_print_regions.front()->config().outer_wall_filament_id-1),
(float)nozzle_diameter_for_filament(m_config, m_print_regions.front()->config().outer_wall_filament_id, this->is_BBL_printer()),
(float)this->skirt_first_layer_height());
}
@@ -2623,12 +2623,13 @@ Flow Print::skirt_flow() const
extruders and take the one with, say, the smallest index;
The same logic should be applied to the code that selects the extruder during G-code
generation as well. */
return Flow::new_from_config_width(frPerimeter,
// Flow::new_from_config_width takes care of the percent to value substitution
width,
(float) m_config.nozzle_diameter.get_at(
m_objects.empty() ? 0 : m_objects.front()->config().support_filament - 1),
(float) this->skirt_first_layer_height());
return Flow::new_from_config_width(
frPerimeter,
// Flow::new_from_config_width takes care of the percent to value substitution
width,
// ORCA: resolve the actual nozzle the support filament is printed with (dual-nozzle printers).
(float)nozzle_diameter_for_filament(m_config, m_objects.empty() ? 0 : m_objects.front()->config().support_filament, this->is_BBL_printer()),
(float)this->skirt_first_layer_height());
}
bool Print::has_support_material() const
+6 -3
View File
@@ -375,6 +375,8 @@ public:
Transform3d trafo_centered() const
{ Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale<double>(m_center_offset.x()), - unscale<double>(m_center_offset.y()), 0)); return t; }
const PrintInstances& instances() const { return m_instances; }
// Orca: Bounding box of each connected body, indexed by Layer::lslices_separated_component_ids.
const std::vector<BoundingBox>& separated_body_bboxes() const { return m_separated_body_bboxes; }
PrintInstances &instances() { return m_instances; }
// Whoever will get a non-const pointer to PrintObject will be able to modify its layers.
@@ -581,8 +583,8 @@ private:
void discover_horizontal_shells();
void combine_infill();
void _generate_support_material();
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface*, float>>& surfaces_w_bottom_z) const;
std::pair<FillAdaptive::Octrees, FillAdaptive::Octrees> prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface*, const Layer*>>& surfaces_w_layer) const;
FillLightning::GeneratorPtr prepare_lightning_infill_data();
// BBS
@@ -614,7 +616,8 @@ private:
// so that next call to make_perimeters() performs a union() before computing loops
bool m_typed_slices = false;
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> m_adaptive_fill_octrees;
std::pair<FillAdaptive::Octrees, FillAdaptive::Octrees> m_adaptive_fill_octrees;
std::vector<BoundingBox> m_separated_body_bboxes;
FillLightning::GeneratorPtr m_lightning_generator;
std::vector < VolumeSlices > firstLayerObjSliceByVolume;
+26 -2
View File
@@ -133,6 +133,15 @@ size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id)
return 0;
}
double nozzle_diameter_for_filament(const PrintConfig& config, int filament_id, bool is_bbl_printer)
{
int extruder = filament_id;
if (is_bbl_printer && config.nozzle_diameter.size() > 1 &&
filament_id >= 1 && static_cast<size_t>(filament_id - 1) < config.filament_map.size())
extruder = config.filament_map.get_at(filament_id - 1);
return config.nozzle_diameter.get_at(extruder - 1);
}
// Orca: input shaping values types by flavor
std::vector<std::string> get_shaper_type_values_for_flavor(GCodeFlavor flavor)
@@ -7602,8 +7611,8 @@ void PrintConfigDef::init_fff_params()
"whole assembly. Parts that touch or overlap are treated as one body and share a center; separate parts "
"(or distinct 3D objects) each get their own.\n"
"Useful when an assembly groups several objects that should each keep a consistent, self-centered infill.\n"
"Affects line and grid patterns and rotation-template infills.\n"
"Patterns locked to global coordinates (Gyroid, Honeycomb, TPMS, ...) are unaffected.");
"Adaptive Cubic and Support Cubic always center each part on itself, and Lightning infill is generated for "
"the whole object and is unaffected.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
@@ -10845,6 +10854,21 @@ void set_filament_dev_options(DynamicPrintConfig &config, const std::vector<cons
}
}
void resize_mixed_filament_metadata(DynamicPrintConfig &config, size_t old_slot_count, size_t new_slot_count)
{
auto resize = [old_slot_count, new_slot_count](auto *opt) {
opt->values.resize(std::min(old_slot_count, opt->values.size()));
opt->values.resize(new_slot_count);
};
resize(config.option<ConfigOptionBools>("filament_is_mixed", true));
resize(config.option<ConfigOptionStrings>("filament_mixed_components", true));
resize(config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios", true));
resize(config.option<ConfigOptionBools>("filament_mixed_gradient", true));
resize(config.option<ConfigOptionStrings>("filament_mixed_gradient_range", true));
resize(config.option<ConfigOptionStrings>("filament_mixed_gradient_curve", true));
resize(config.option<ConfigOptionBools>("filament_mixed_gradient_per_part", true));
}
//used for object/region config
//use the smallest of multiple to single
+19 -4
View File
@@ -136,25 +136,31 @@ enum InfillPattern : int {
ipCount,
};
// Orca: Infill patterns whose alignment origin follows the fill bounding box, so the
// "separated_infills" option can re-center them per connected body. Patterns evaluated in
// absolute/global coordinates (Gyroid, TPMS, Honeycomb, CrossHatch, ...) or that are shape-relative
// (Concentric) ignore that bounding box and are therefore excluded.
// Orca: Infill patterns that the "separated_infills" option can center on each connected body.
inline bool is_separable_infill_pattern(InfillPattern pattern)
{
switch (pattern) {
case ipMonotonic:
case ipMonotonicLine:
case ipRectilinear:
case ipAlignedRectilinear:
case ipZigZag:
case ipCrossZag:
case ipLockedZag:
case ipLine:
case ipGrid:
case ipTriangles:
case ipStars: // tri-hexagon
case ipCubic:
case ipQuarterCubic:
case ipHoneycomb:
case ip3DHoneycomb:
case ipLateralHoneycomb:
case ipLateralLattice:
case ipCrossHatch:
case ipTpmsD:
case ipTpmsFK:
case ipGyroid:
case ipHilbertCurve:
case ipArchimedeanChords:
case ipOctagramSpiral:
@@ -164,6 +170,9 @@ inline bool is_separable_infill_pattern(InfillPattern pattern)
}
}
// Orca: Infill patterns laid out by an octree, which each connected body always gets of its own.
inline bool is_octree_infill_pattern(InfillPattern pattern) { return pattern == ipAdaptiveCubic || pattern == ipSupportCubic; }
// Orca: Infill patterns that round their corners by the "sparse_infill_smooth_factor" option.
// Grid, Triangles and Tri-hexagon only do so in their trapezoidal form, which is generated with more
// than one line per infill wall; a single line makes them plain crossing lines with nothing to round.
@@ -933,6 +942,10 @@ extern std::set<std::string> filament_dev_options;
// filament_configs, one config per filament in slot order, as the filaments' values one after another.
void set_filament_dev_options(DynamicPrintConfig &config, const std::vector<const DynamicPrintConfig *> &filament_configs);
// Orca: sizes the per-slot mixed-colour metadata options to new_slot_count, keeping the first
// old_slot_count values; an option the config lacks is created.
void resize_mixed_filament_metadata(DynamicPrintConfig &config, size_t old_slot_count, size_t new_slot_count);
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
extern void compute_filament_override_value(const std::string& opt_key, const ConfigOption *opt_old_machine, const ConfigOption *opt_new_machine, const ConfigOption *opt_new_filament, const DynamicPrintConfig& new_full_config,
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_map_indices);
@@ -2562,6 +2575,8 @@ static bool has_zero_flush_volume_for_used_filaments(const std::vector<T> &fv_ma
size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id);
double nozzle_diameter_for_filament(const PrintConfig& config, int filament_id, bool is_bbl_printer);
} // namespace Slic3r
// Serialization through the Cereal library
+125 -34
View File
@@ -67,6 +67,7 @@
#include <utility>
#include <boost/log/trivial.hpp>
#include <Eigen/Core>
#include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
@@ -719,7 +720,8 @@ void PrintObject::prepare_infill()
bool needs_separated_components = false;
for (size_t i = 0; i < this->num_printing_regions(); ++ i) {
const PrintRegionConfig &rc = this->printing_region(i).config();
if (rc.separated_infills || rc.center_of_surface_pattern == CenterOfSurfacePattern::Each_Model) {
if (rc.separated_infills || rc.center_of_surface_pattern == CenterOfSurfacePattern::Each_Model ||
(rc.sparse_infill_density > 0 && is_octree_infill_pattern(rc.sparse_infill_pattern))) {
needs_separated_components = true;
break;
}
@@ -736,8 +738,9 @@ void PrintObject::prepare_infill()
if (parts <= 1 && ! (first_part != nullptr && first_part->is_splittable()))
needs_separated_components = false;
}
m_separated_body_bboxes.clear();
for (Layer *layer : m_layers)
layer->lslices_separated_component_bboxes.clear();
layer->lslices_separated_component_ids.clear();
if (needs_separated_components) {
const size_t nl = m_layers.size();
std::vector<size_t> offset(nl + 1, 0); // Orca: flat index of the first island of each layer
@@ -788,17 +791,20 @@ void PrintObject::prepare_infill()
});
}
}
// Orca: Full bounding box of each body, indexed by its union-find root.
std::vector<BoundingBox> body_bbox(nreg);
for (size_t i = 0; i < nl; ++ i)
for (size_t a = 0; a < m_layers[i]->lslices.size(); ++ a)
body_bbox[find(offset[i] + a)].merge(m_layers[i]->lslices_bboxes[a]);
// Orca: Store the body bbox for every island.
// Orca: Number the bodies by their first island and merge the bounding boxes of their islands.
std::vector<size_t> body_of_root(nreg, size_t(-1));
for (size_t i = 0; i < nl; ++ i) {
Layer *layer = m_layers[i];
layer->lslices_separated_component_bboxes.resize(layer->lslices.size());
for (size_t a = 0; a < layer->lslices.size(); ++ a)
layer->lslices_separated_component_bboxes[a] = body_bbox[find(offset[i] + a)];
layer->lslices_separated_component_ids.resize(layer->lslices.size());
for (size_t a = 0; a < layer->lslices.size(); ++ a) {
size_t &body = body_of_root[find(offset[i] + a)];
if (body == size_t(-1)) {
body = m_separated_body_bboxes.size();
m_separated_body_bboxes.emplace_back();
}
m_separated_body_bboxes[body].merge(layer->lslices_bboxes[a]);
layer->lslices_separated_component_ids[a] = body;
}
}
}
@@ -836,16 +842,13 @@ void PrintObject::infill()
if (this->set_started(posInfill)) {
m_print->set_status(35, L("Generating infill toolpath"));
const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first;
const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this, &adaptive_fill_octree = adaptive_fill_octree, &support_fill_octree = support_fill_octree](const tbb::blocked_range<size_t>& range) {
[this](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
m_print->throw_if_canceled();
m_layers[layer_idx]->make_fills(adaptive_fill_octree.get(), support_fill_octree.get(), this->m_lightning_generator.get());
m_layers[layer_idx]->make_fills(&m_adaptive_fill_octrees.first, &m_adaptive_fill_octrees.second, this->m_lightning_generator.get());
}
}
);
@@ -1110,14 +1113,69 @@ void PrintObject::simplify_extrusion_path()
}
}
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface *, float>> &surfaces_w_bottom_z) const
// Orca: Separated body of the island containing a point of a layer, else of the island outline nearest within 1 mm, or -1.
static int separated_body_at(const Layer &layer, const Point &point)
{
int body = -1;
double best = scaled<double>(1.);
for (size_t i = 0; i < layer.lslices.size() && i < layer.lslices_separated_component_ids.size() && best > 0.; ++ i) {
BoundingBox bbox = layer.lslices_bboxes[i];
bbox.offset(coord_t(best));
if (! bbox.contains(point))
continue;
const double dist = layer.lslices[i].contains(point) ? 0. : (layer.lslices[i].point_projection(point) - point).cast<double>().norm();
if (dist < best) {
best = dist;
body = int(layer.lslices_separated_component_ids[i]);
}
}
return body;
}
// Orca: The object mesh in the octree frame split by separated body. Each connected component goes to the body
// most of its sampled triangles lie on, sampled a layer height inside the solid at the layer nearest to them.
static std::vector<indexed_triangle_set> split_mesh_by_body(const PrintObject &object, const indexed_triangle_set &mesh, size_t num_bodies)
{
const Eigen::Matrix3d to_object = FillAdaptive::transform_to_world().toRotationMatrix();
const double inset = object.config().layer_height.value;
std::vector<indexed_triangle_set> bodies(num_bodies);
for (const indexed_triangle_set &component : its_split(mesh)) {
std::vector<size_t> votes(num_bodies, 0);
const size_t step = std::max<size_t>(1, component.indices.size() / 8);
for (size_t i = 0; i < component.indices.size(); i += step) {
const stl_triangle_vertex_indices &tri = component.indices[i];
const Vec3d a = component.vertices[tri[0]].cast<double>(), b = component.vertices[tri[1]].cast<double>(),
d = component.vertices[tri[2]].cast<double>();
const Vec3d normal = (b - a).cross(d - a);
const double area2 = normal.norm();
const Vec3d c = to_object * ((a + b + d) / 3. - (area2 > 0. ? Vec3d(normal * (inset / area2)) : Vec3d::Zero()));
size_t lo = 0, hi = object.layer_count();
while (lo < hi) {
const size_t mid = (lo + hi) / 2;
if (object.get_layer(int(mid))->slice_z < c.z())
lo = mid + 1;
else
hi = mid;
}
if (lo == object.layer_count() || (lo > 0 && c.z() - object.get_layer(int(lo) - 1)->slice_z < object.get_layer(int(lo))->slice_z - c.z()))
-- lo;
if (const int body = separated_body_at(*object.get_layer(int(lo)), Point(scaled<coord_t>(c.x()), scaled<coord_t>(c.y()))); body >= 0)
++ votes[body];
}
if (const auto best = std::max_element(votes.begin(), votes.end()); *best > 0)
its_merge(bodies[best - votes.begin()], component);
}
return bodies;
}
std::pair<FillAdaptive::Octrees, FillAdaptive::Octrees> PrintObject::prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface *, const Layer *>> &surfaces_w_layer) const
{
using namespace FillAdaptive;
auto [adaptive_line_spacing, support_line_spacing] = adaptive_fill_line_spacing(*this);
if ((adaptive_line_spacing == 0. && support_line_spacing == 0.) || this->layers().empty())
return std::make_pair(OctreePtr(), OctreePtr());
return {};
indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set();
// Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
@@ -1125,27 +1183,60 @@ std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare
its_transform(mesh, to_octree * this->trafo_centered(), true);
// Triangulate internal bridging surfaces.
std::vector<std::vector<Vec3d>> overhangs(std::max(surfaces_w_bottom_z.size(), size_t(1)));
std::vector<std::vector<Vec3d>> overhangs(std::max(surfaces_w_layer.size(), size_t(1)));
// ^ make sure vector is not empty, even with no briding surfaces we still want to build the adaptive trees later, some continue normally
tbb::parallel_for(tbb::blocked_range<int>(0, surfaces_w_bottom_z.size()),
[this, &to_octree, &overhangs, &surfaces_w_bottom_z](const tbb::blocked_range<int> &range) {
tbb::parallel_for(tbb::blocked_range<int>(0, surfaces_w_layer.size()),
[this, &to_octree, &overhangs, &surfaces_w_layer](const tbb::blocked_range<int> &range) {
PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
for (int surface_idx = range.begin(); surface_idx < range.end(); ++surface_idx) {
std::vector<Vec3d> &out = overhangs[surface_idx];
m_print->throw_if_canceled();
append(out, triangulate_expolygon_3d(surfaces_w_bottom_z[surface_idx].first->expolygon,
surfaces_w_bottom_z[surface_idx].second));
append(out, triangulate_expolygon_3d(surfaces_w_layer[surface_idx].first->expolygon,
float(surfaces_w_layer[surface_idx].second->bottom_z())));
for (Vec3d &p : out)
p = (to_octree * p).eval();
}
});
// Orca: Each body gets the octree it has when sliced on its own, from its own triangles.
std::pair<Octrees, Octrees> octrees;
const size_t num_bodies = m_separated_body_bboxes.size();
bool need_object = num_bodies <= 1;
if (num_bodies > 1) {
const std::vector<indexed_triangle_set> body_meshes = split_mesh_by_body(*this, mesh, num_bodies);
need_object = std::any_of(body_meshes.begin(), body_meshes.end(), [](const indexed_triangle_set &its) { return its.indices.empty(); });
std::vector<std::vector<Vec3d>> body_overhangs(num_bodies);
for (size_t i = 0; i < surfaces_w_layer.size(); ++ i)
if (const int body = separated_body_at(*surfaces_w_layer[i].second, surfaces_w_layer[i].first->expolygon.contour.points.front()); body >= 0)
append(body_overhangs[body], overhangs[i]);
if (adaptive_line_spacing)
octrees.first.bodies.resize(num_bodies);
if (support_line_spacing)
octrees.second.bodies.resize(num_bodies);
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_bodies), [&, adaptive_spacing = adaptive_line_spacing, support_spacing = support_line_spacing](
const tbb::blocked_range<size_t> &range) {
for (size_t body = range.begin(); body < range.end(); ++ body) {
m_print->throw_if_canceled();
if (body_meshes[body].indices.empty())
continue;
if (adaptive_spacing)
octrees.first.bodies[body] = build_octree(body_meshes[body], body_overhangs[body], adaptive_spacing, false);
if (support_spacing)
octrees.second.bodies[body] = build_octree(body_meshes[body], body_overhangs[body], support_spacing, true);
}
});
}
// and gather them.
for (size_t i = 1; i < overhangs.size(); ++ i)
append(overhangs.front(), std::move(overhangs[i]));
return std::make_pair(
adaptive_line_spacing ? build_octree(mesh, overhangs.front(), adaptive_line_spacing, false) : OctreePtr(),
support_line_spacing ? build_octree(mesh, overhangs.front(), support_line_spacing, true) : OctreePtr());
// Orca: The object's octree only serves bodies that have none of their own.
if (need_object && adaptive_line_spacing)
octrees.first.object = build_octree(mesh, overhangs.front(), adaptive_line_spacing, false);
if (need_object && support_line_spacing)
octrees.second.object = build_octree(mesh, overhangs.front(), support_line_spacing, true);
return octrees;
}
FillLightning::GeneratorPtr PrintObject::prepare_lightning_infill_data()
@@ -2963,14 +3054,14 @@ void PrintObject::bridge_over_infill()
std::map<size_t, Polylines> infill_lines;
// SECTION to generate infill polylines
{
std::vector<std::pair<const Surface *, float>> surfaces_w_bottom_z;
std::vector<std::pair<const Surface *, const Layer *>> surfaces_w_layer;
for (const auto &pair : surfaces_by_layer) {
for (const CandidateSurface &c : pair.second) {
surfaces_w_bottom_z.emplace_back(c.original_surface, c.region->m_layer->bottom_z());
surfaces_w_layer.emplace_back(c.original_surface, c.region->m_layer);
}
}
this->m_adaptive_fill_octrees = this->prepare_adaptive_infill_data(surfaces_w_bottom_z);
this->m_adaptive_fill_octrees = this->prepare_adaptive_infill_data(surfaces_w_layer);
std::vector<size_t> layers_to_generate_infill;
for (const auto &pair : surfaces_by_layer) {
@@ -2986,8 +3077,8 @@ void PrintObject::bridge_over_infill()
for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
size_t lidx = layers_to_generate_infill[job_idx];
infill_lines.at(
lidx) = po->get_layer(lidx)->generate_sparse_infill_polylines_for_anchoring(po->m_adaptive_fill_octrees.first.get(),
po->m_adaptive_fill_octrees.second.get(),
lidx) = po->get_layer(lidx)->generate_sparse_infill_polylines_for_anchoring(&po->m_adaptive_fill_octrees.first,
&po->m_adaptive_fill_octrees.second,
po->m_lightning_generator.get());
}
});
@@ -4467,8 +4558,8 @@ void PrintObject::combine_infill()
// Limit the number of combined layers to the maximum height allowed by this regions' nozzle.
//FIXME limit the layer height to max_layer_height
double nozzle_diameter = std::min(
this->print()->config().nozzle_diameter.get_at(region.config().sparse_infill_filament_id.value - 1),
this->print()->config().nozzle_diameter.get_at(region.config().internal_solid_filament_id.value - 1));
nozzle_diameter_for_filament(this->print()->config(), region.config().sparse_infill_filament_id.value, this->print()->is_BBL_printer()),
nozzle_diameter_for_filament(this->print()->config(), region.config().internal_solid_filament_id.value, this->print()->is_BBL_printer()));
//Orca: Limit combination of infill to up to infill_combination_max_layer_height
const double infill_combination_max_layer_height = region.config().infill_combination_max_layer_height.get_abs_value(nozzle_diameter);
+1 -1
View File
@@ -57,7 +57,7 @@ Flow PrintRegion::flow(const PrintObject &object, FlowRole role, double layer_he
// Get the configured nozzle_diameter for the extruder associated to the flow role requested.
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.
auto nozzle_diameter = float(print_config.nozzle_diameter.get_at(this->extruder(role) - 1));
auto nozzle_diameter = float(nozzle_diameter_for_filament(print_config, this->extruder(role), object.print()->is_BBL_printer()));
return Flow::new_from_config_width(role, config_width, nozzle_diameter, float(layer_height));
}
-1
View File
@@ -49,7 +49,6 @@ public:
using TColor = typename PixelRenderer::color_type;
using TValue = typename TColor::value_type;
using TPixel = typename PixelRenderer::pixel_type;
using TRawBuffer = agg::rendering_buffer;
protected:
-1
View File
@@ -44,7 +44,6 @@
#include "TDataStd_Name.hxx"
#include "BRepBuilderAPI_Transform.hxx"
#include "TopExp_Explorer.hxx"
#include "TopExp_Explorer.hxx"
#include "BRep_Tool.hxx"
#include "Font_BRepFont.hxx"
#include "Font_BRepTextBuilder.hxx"
+1 -1
View File
@@ -2180,7 +2180,7 @@ SupportGeneratorLayersPtr PrintObjectSupportMaterial::top_contact_layers(
// check if the sharp tails should be extended higher
bool detect_first_sharp_tail_only = false;
const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(object.print()->config().nozzle_diameter.get_at(object.config().support_interface_filament-1));
const coordf_t extrusion_width = m_object_config->line_width.get_abs_value(nozzle_diameter_for_filament(object.print()->config(), object.config().support_interface_filament, object.print()->is_BBL_printer()));
const coordf_t extrusion_width_scaled = scale_(extrusion_width);
if (is_auto(m_object_config->support_type.value) && g_config_support_sharp_tails && !detect_first_sharp_tail_only) {
for (size_t layer_nr = layer_id_start; layer_nr < num_layers; layer_nr++) {
+1 -1
View File
@@ -1399,7 +1399,7 @@ void TreeSupport::generate_toolpaths()
{
const PrintObjectConfig &object_config = m_object->config();
coordf_t support_extrusion_width = m_support_params.support_extrusion_width;
coordf_t nozzle_diameter = m_print_config->nozzle_diameter.get_at(object_config.support_filament - 1);
coordf_t nozzle_diameter = nozzle_diameter_for_filament(*m_print_config, object_config.support_filament, m_object->print()->is_BBL_printer());
coordf_t layer_height = object_config.layer_height.value;
const size_t wall_count = object_config.tree_support_wall_count.value;
@@ -17,9 +17,6 @@ typedef std::vector<Color> ColorList;
typedef std::array<double, 3> ColorDouble;
typedef std::array<std::size_t, 3> RGB;
// Function pointer type that points to a specific color-difference function based on the chosen method.
using DistanceFunction = double (*)(const Color&, const Color&);
// Color space used for computing color differences.
enum struct ColorDifferenceMethod : std::size_t {
RGB = 0, // Simplest and fastest
+3 -2
View File
@@ -24,8 +24,6 @@
namespace Slic3r { namespace tex2color {
namespace PMP = CGAL::Polygon_mesh_processing;
// Default upper bound on the number of half-edges in any single boundary cycle
// that CloseBoundariesAndRepairManifoldness will attempt to triangulate. The
// cost of triangulate_hole grows non-linearly with cycle length, so this caps
@@ -61,6 +59,7 @@ struct BoundaryEdgeStats
// any pre-processing (e.g. stitch_borders) needed for the count to be meaningful.
inline BoundaryEdgeStats ComputeBoundaryEdgeStats(const cgalutils::CGALMesh& cgal_mesh)
{
namespace PMP = CGAL::Polygon_mesh_processing;
using CGALMesh = cgalutils::CGALMesh;
using HalfedgeDescriptor = boost::graph_traits<CGALMesh>::halfedge_descriptor;
@@ -87,6 +86,7 @@ inline BoundaryEdgeStats ComputeBoundaryEdgeStats(const cgalutils::CGALMesh& cga
// boundary statistics; entering this function always triggers triangulation.
inline void CloseBoundariesAndRepairManifoldness(cgalutils::CGALMesh& cgal_mesh)
{
namespace PMP = CGAL::Polygon_mesh_processing;
using CGALMesh = cgalutils::CGALMesh;
using HalfedgeDescriptor = boost::graph_traits<CGALMesh>::halfedge_descriptor;
using FaceDescriptor = boost::graph_traits<CGALMesh>::face_descriptor;
@@ -112,6 +112,7 @@ inline bool RepairMesh(const TriMesh& mesh,
AlgoCancelCallback cancel_callback = nullptr,
const RepairSetting& setting = RepairSetting{})
{
namespace PMP = CGAL::Polygon_mesh_processing;
using Clock = std::chrono::steady_clock;
auto elapsed_ms = [](Clock::time_point t0) {
return std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - t0).count();
-2
View File
@@ -25,8 +25,6 @@
#include <initializer_list>
#include <string_view>
#include <regex>
#include <string_view>
#include <algorithm>
#include <boost/system/error_code.hpp>
#include <boost/algorithm/string.hpp>
-2
View File
@@ -432,8 +432,6 @@ inline IntegerOnly<I, I> fast_round_up(double a)
return a == 0.49999999999999994 ? I(0) : I(floor(a + 0.5));
}
template<class T> using SamePair = std::pair<T, T>;
} // namespace Slic3r
#endif
+8 -2
View File
@@ -1012,7 +1012,10 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi
float machine_diameter = obj->GetExtderSystem()->GetNozzleDiameter(0);
if (machine_diameter == 0.0f && preset_bundle) {
const ConfigOption *opt = preset_bundle->printers.get_selected_preset().config.option("nozzle_diameter");
if (opt) machine_diameter = static_cast<const ConfigOptionFloats *>(opt)->values[0];
if (opt) {
const auto &nd = static_cast<const ConfigOptionFloats *>(opt)->values;
if (!nd.empty()) machine_diameter = nd.size() > 1 ? nd[1] : nd[0];
}
}
stream << std::fixed << std::setprecision(1) << machine_diameter;
std::string nozzle_diameter_str = stream.str();
@@ -1291,7 +1294,10 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt)
float machine_diameter = obj->GetExtderSystem()->GetNozzleDiameter(0);
if (machine_diameter == 0.0f) {
const ConfigOption *opt = preset_bundle->printers.get_selected_preset().config.option("nozzle_diameter");
if (opt) machine_diameter = static_cast<const ConfigOptionFloats *>(opt)->values[0];
if (opt) {
const auto &nd = static_cast<const ConfigOptionFloats *>(opt)->values;
if (!nd.empty()) machine_diameter = nd.size() > 1 ? nd[1] : nd[0];
}
}
stream << std::fixed << std::setprecision(1) << machine_diameter;
}
-2
View File
@@ -17,7 +17,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -30,7 +29,6 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include "GUI_Utils.hpp"
-3
View File
@@ -19,20 +19,17 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/grid.h>
#include <wx/dataview.h>
#include <wx/panel.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
#include <wx/statbox.h>
#include <wx/tglbtn.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <map>
-3
View File
@@ -28,7 +28,6 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/grid.h>
#include <wx/dataview.h>
#include <wx/panel.h>
@@ -36,14 +35,12 @@
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/statbox.h>
#include <wx/tglbtn.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/webrequest.h>
#include <map>
#include <vector>
-1
View File
@@ -8,7 +8,6 @@
#include <memory>
#include <string>
#include <functional>
#include <string>
#include "Jobs/ProgressIndicator.hpp"
-1
View File
@@ -10,7 +10,6 @@
#include <memory>
#include <string>
#include <functional>
#include <string>
#include <wx/string.h>
#include "Jobs/ProgressIndicator.hpp"
-1
View File
@@ -9,7 +9,6 @@
#include <memory>
#include <string>
#include <functional>
#include <string>
#include <wx/hyperlink.h>
#include "Jobs/ProgressIndicator.hpp"
-1
View File
@@ -9,7 +9,6 @@
#include <memory>
#include <string>
#include <functional>
#include <string>
#include <wx/hyperlink.h>
#include "Jobs/ProgressIndicator.hpp"
@@ -18,7 +18,6 @@
#include <wx/string.h>
#include <wx/toplevel.h>
#include <wx/timer.h>
#include "Widgets/Button.hpp"
#include "CapsuleButton.hpp"
namespace Slic3r::GUI { struct IntEvent; }
-1
View File
@@ -46,7 +46,6 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/Polygon.hpp"
#include "MainFrame.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
#include "Jobs/BoostThreadWorker.hpp"
#include "Jobs/PlaterWorker.hpp"
-1
View File
@@ -29,7 +29,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/Utils/Bonjour.hpp"
#include "slic3r/GUI/Widgets/DialogButtons.hpp"
-2
View File
@@ -11,7 +11,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -24,7 +23,6 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include "GUI_Utils.hpp"
+1 -5
View File
@@ -1,4 +1,3 @@
// #include "libslic3r/GCodeSender.hpp"
#include "ConfigManipulation.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
@@ -872,10 +871,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, in
toggle_line("center_of_surface_pattern", has_centered_surface);
// Orca: separate infills
bool is_internal_infill_separable = is_separable_infill_pattern(config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value) ||
config->opt_string("sparse_infill_rotate_template") != "" ||
config->opt_string("solid_infill_rotate_template") != "";
toggle_line("separated_infills", is_internal_infill_separable);
toggle_line("separated_infills", is_separable_infill_pattern(pattern));
// Fill order is only meaningful for the center-based surface fill patterns; hide it otherwise.
auto is_centered_fill = [](InfillPattern p) { return p == ipConcentric || p == ipSpiralInset || p == ipArchimedeanChords || p == ipOctagramSpiral; };
-3
View File
@@ -198,6 +198,3 @@ template<> struct std::hash<NozzleDef>
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
};
};
// key(extruder_id) -> { key1(nozzle type info), val1( number of the nozzle type)}
using ExtruderNozzleInfos = std::unordered_map<int, std::unordered_map<NozzleDef, int>>;
@@ -15,7 +15,6 @@
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <wx/string.h>
#include <wx/colour.h>
-1
View File
@@ -11,7 +11,6 @@
#include "GUI_App.hpp"
#include "DeviceErrorDialog.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
#include "ReleaseNote.hpp"
#include <string>
#include <boost/log/trivial.hpp>
+9 -5
View File
@@ -2427,11 +2427,15 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
if (m_canvas_type == ECanvasType::CanvasView3D) {
// m_show_bed gates the plate list too: hiding the bed but leaving its grid and outline
// floating would read as a rendering fault rather than a deliberate view option.
// Design tab: while its reference planes are up they draw their own axes from the modeling
// origin, where the bed's triad would otherwise sit on top of them.
if (show_bed)
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(),
m_show_world_axes && !(m_design_sketch_tool != nullptr && m_design_sketch_tool->draws_reference_axes()));
if (show_bed) {
bool show_axes = m_show_world_axes;
#ifdef SLIC3R_CAD
// Design tab: while its reference planes are up they draw their own axes from the modeling
// origin, where the bed's triad would otherwise sit on top of them.
show_axes = show_axes && !(m_design_sketch_tool != nullptr && m_design_sketch_tool->draws_reference_axes());
#endif
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
}
m_frame_profiler.mark("bed");
if (show_bed) //BBS: add outline logic
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid);
-3
View File
@@ -183,13 +183,10 @@ wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_NAME_CHANGE, SimpleEvent);
//BBS: declare EVT_GLCANVAS_PLATE_SELECT
wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_SELECT, SimpleEvent);
using Vec2dEvent = Event<Vec2d>;
// _bool_ value is used as a indicator of selection in the 3DScene
using RBtnEvent = Event<std::pair<Vec2d, bool>>;
using RBtnPlateEvent = Event<std::pair<Vec2d, int>>;
template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
using Vec3dEvent = Event<Vec3d>;
template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
-1
View File
@@ -46,7 +46,6 @@
#include "nanosvg/nanosvgrast.h"
#include "libslic3r/Utils.hpp"
#include "GUI_App.hpp"
#include <boost/log/trivial.hpp>
#include <wx/dcgraph.h>
#include <wx/dcmemory.h>
-1
View File
@@ -50,7 +50,6 @@
#include "AboutDialog.hpp"
#include "MsgDialog.hpp"
#include "Plater.hpp"
#include "format.hpp"
#include "WebUserLoginDialog.hpp"
-2
View File
@@ -172,12 +172,10 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/I18N.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/InstanceLock.hpp"
#include "libslic3r/Thread.hpp"
#include "libslic3r/miniz_extension.hpp"
#include "libslic3r/Utils.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "slic3r/plugin/host/PluginHostUi.hpp"
#include "slic3r/plugin/PythonInterpreter.hpp"
-1
View File
@@ -11,7 +11,6 @@
#include "libslic3r/Config.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Preset.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/PrintConfig.hpp"
#include <cstdint>
-1
View File
@@ -66,7 +66,6 @@
#include <nanosvg/nanosvg.h>
#include <nanosvg/nanosvgrast.h>
#include "OpenGLManager.hpp"
#include "GUI_App.hpp"
namespace Slic3r {
namespace GUI {
-1
View File
@@ -113,7 +113,6 @@
#include "MsgDialog.hpp"
#include "Notebook.hpp"
#include "GUI_Factories.hpp"
#include "GUI_ObjectList.hpp"
#include "NotificationManager.hpp"
#include "MarkdownTip.hpp"
#include "NetworkTestDialog.hpp"
-1
View File
@@ -21,7 +21,6 @@
#include "wx/evtloop.h"
#include "MainFrame.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
using json = nlohmann::json;
-1
View File
@@ -45,7 +45,6 @@
#include "MainFrame.hpp"
#include "MediaPlayCtrl.h"
#include "MediaFilePanel.h"
#include "Plater.hpp"
#include "BindDialog.hpp"
#include "DeviceCore/DevManager.h"
-3
View File
@@ -23,7 +23,6 @@
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/grid.h>
#include <wx/dataview.h>
#include <wx/panel.h>
@@ -31,14 +30,12 @@
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/statbox.h>
#include <wx/tglbtn.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/webrequest.h>
#include <map>
#include <vector>
-1
View File
@@ -4,7 +4,6 @@
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "I18N.hpp"
#include "libslic3r_version.h"
#include "slic3r/Utils/Http.hpp"
#include "libslic3r/AppConfig.hpp"
-1
View File
@@ -54,7 +54,6 @@ struct Option {
Option(const ConfigOptionDef& _opt, t_config_option_key id) :
opt(_opt), opt_id(id) {}
};
using t_option = std::unique_ptr<Option>; //!
/// Represents option lines
class Line : public UndoValueUIManager
+21 -21
View File
@@ -1862,27 +1862,22 @@ bool Sidebar::priv::switch_diameter(bool single)
auto diameter_left = left_extruder->combo_diameter->GetValue();
auto diameter_right = right_extruder->combo_diameter->GetValue();
if (diameter_left != diameter_right) {
std::string printer_type = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
auto left_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
auto right_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
MessageDialog dlg(this->plater,
_L("The software does not support using different diameter of nozzles for one print. "
"If the left and right nozzles are inconsistent, we can only proceed with single-head printing. "
"Please confirm which nozzle you would like to use for this project."),
_L("Switch diameter"), wxYES_NO | wxNO_DEFAULT);
dlg.SetButtonLabel(wxID_YES, wxString::Format("%s: %smm", left_name, diameter_left));
dlg.SetButtonLabel(wxID_NO, wxString::Format("%s: %smm", right_name, diameter_right));
int result = dlg.ShowModal();
if (result == wxID_YES)
diameter = diameter_left;
else if (result == wxID_NO)
diameter = diameter_right;
else
double left_value = 0.0, right_value = 0.0;
if (!diameter_left.ToCDouble(&left_value) || !diameter_right.ToCDouble(&right_value))
return false;
Tab* printer_tab = wxGetApp().get_tab(Preset::TYPE_PRINTER);
DynamicPrintConfig new_conf = wxGetApp().preset_bundle->printers.get_edited_preset().config;
auto* nozzle_diameter_opt = new_conf.option<ConfigOptionFloats>("nozzle_diameter");
if (printer_tab == nullptr || nozzle_diameter_opt == nullptr || nozzle_diameter_opt->size() < 2)
return false;
nozzle_diameter_opt->values[0] = left_value;
nozzle_diameter_opt->values[1] = right_value;
printer_tab->load_config(new_conf);
return true;
}
else {
diameter = diameter_left;
}
diameter = diameter_left;
}
return switch_diameter_to(diameter);
@@ -1892,15 +1887,20 @@ bool Sidebar::priv::switch_diameter_to(const wxString &diameter)
{
// ORCA: Check if the selected diameter matches the current nozzle diameter in the config
Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"));
// ORCA: the left/right combos of a BBL multi-nozzle printer set the nozzles apart without leaving
// the preset (see switch_diameter), so there the preset is only kept while every nozzle matches.
const bool nozzles_apart = nozzle_diameter && nozzle_diameter->size() > 1 && wxGetApp().preset_bundle->is_bbl_vendor() &&
std::any_of(nozzle_diameter->values.begin(), nozzle_diameter->values.end(),
[&diameter](double value) { return get_diameter_string(value) != diameter.ToStdString(); });
// The combo lists printer variants, and the variant of a mixed-nozzle machine ("0.4+0.6") is no
// single extruder's diameter, so the preset's own variant answers first.
const std::string &printer_variant = printer_preset.config.opt_string("printer_variant");
if (printer_variant == diameter.ToStdString()) {
if (printer_variant == diameter.ToStdString() && !nozzles_apart) {
return true;
}
// A named variant ("0.4 High Flow") shares its diameter with the standard profile, which selecting
// the plain diameter switches back to, so only a preset naming no variant is kept by its diameter.
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(printer_preset.config.option("nozzle_diameter"));
if (printer_variant.empty() && nozzle_diameter && nozzle_diameter->size() > 0) {
auto current_nozzle_dia = get_diameter_string(nozzle_diameter->values[0]);
// If the selected diameter is the same as current nozzle, don't switch profiles
-2
View File
@@ -108,7 +108,6 @@ class PlaterPresetComboBox;
class PartPlateList;
class SyncNozzleAndAmsDialog;
class FinishSyncAmsDialog;
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
class Plater;
enum class ActionButtonType : int;
@@ -325,7 +324,6 @@ private:
class Plater: public wxPanel
{
public:
using fs_path = boost::filesystem::path;
Plater(wxWindow *parent, MainFrame *main_frame);
Plater(Plater &&) = delete;
-1
View File
@@ -30,7 +30,6 @@
#include "MainFrame.hpp"
#include <miniz.h>
#include <OrcaCloudServiceAgent.hpp>
#include <wx/event.h>
#include <wx/utils.h>
using json = nlohmann::json;
-1
View File
@@ -79,7 +79,6 @@
#include "libslic3r_version.h"
#include "wxExtensions.hpp"
#include <nlohmann/json.hpp>
#include "libslic3r/Preset.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/Widgets/Button.hpp"
-1
View File
@@ -4,7 +4,6 @@
#include <memory>
#include <string>
#include <functional>
#include <string>
#include "Jobs/ProgressIndicator.hpp"
-3
View File
@@ -19,7 +19,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -32,10 +31,8 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include <wx/event.h>
#include <wx/hyperlink.h>
#include <wx/richtext/richtextctrl.h>
#include "AmsMappingPopup.hpp"
-2
View File
@@ -25,7 +25,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -38,7 +37,6 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include <wx/srchctrl.h>
-2
View File
@@ -16,7 +16,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -29,7 +28,6 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include <wx/srchctrl.h>
-2
View File
@@ -20,7 +20,6 @@
#include <wx/dataview.h>
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/dataview.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
@@ -33,7 +32,6 @@
#include <wx/dialog.h>
#include <wx/popupwin.h>
#include <wx/spinctrl.h>
#include <wx/artprov.h>
#include <wx/wrapsizer.h>
#include <wx/srchctrl.h>
+2 -4
View File
@@ -1,4 +1,3 @@
// #include "libslic3r/GCodeSender.hpp"
//#include "slic3r/Utils/Serial.hpp"
#include "Tab.hpp"
#include "PresetHints.hpp"
@@ -102,8 +101,6 @@
#include "Widgets/MultiNozzleSync.hpp"
#include "Widgets/SwitchButton.hpp"
#include "Widgets/TabCtrl.hpp"
#include "Widgets/ComboBox.hpp"
#include "Search.hpp"
#include "BedShapeDialog.hpp"
#include "libslic3r/GCode/Thumbnails.hpp"
#include "WipeTowerDialog.hpp"
@@ -5836,7 +5833,8 @@ if (is_marlin_flavor)
// The page edits the extruder selected on the variant switch.
const size_t extruder_idx = size_t(get_current_active_extruder());
bool is_SEMM = m_config->opt_bool("single_extruder_multi_material");
if (is_SEMM && m_extruders_count > 1 && boost::starts_with(opt_key, "nozzle_diameter"))
bool independent_nozzles = m_preset_bundle && m_preset_bundle->is_bbl_vendor() && m_extruders_count > 1;
if (is_SEMM && m_extruders_count > 1 && !independent_nozzles && boost::starts_with(opt_key, "nozzle_diameter"))
{
SuppressBackgroundProcessingUpdate sbpu;
const double new_nd = boost::any_cast<double>(value);
-2
View File
@@ -20,8 +20,6 @@
#include "../GUI/DeviceCore/DevConfig.h"
#include "../GUI/DeviceCore/DevExtruderSystem.h"
#include "../GUI/DeviceCore/DevManager.h"
#include "../GUI/DeviceCore/DevStorage.h"
#include "libslic3r/FlushVolCalc.hpp"
#include "../GUI/Plater.hpp"
#include <memory>
#include "slic3r/GUI/Jobs/Worker.hpp"
-3
View File
@@ -365,7 +365,6 @@ void StyleManager::init_trunc_names(float max_width) {
#include "slic3r/GUI/Plater.hpp"
// for get DPI
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp"
@@ -554,8 +553,6 @@ bool StyleManager::set_wx_font(const wxFont &wx_font, std::unique_ptr<FontFile>
return true;
}
#include <libslic3r/AppConfig.hpp>
#include "WxFontUtils.hpp"
#include "fast_float/fast_float.h"
// StylesSerializable
-1
View File
@@ -89,7 +89,6 @@ using fn_ft_job_get_result = ft_err(FT_CALL *)(FT_JobHandle *, uint32_t timeo
using fn_ft_tunnel_start_job = ft_err(FT_CALL *)(FT_TunnelHandle *, FT_JobHandle *);
using fn_ft_job_cancel = ft_err(FT_CALL *)(FT_JobHandle *);
using fn_ft_job_msg_destroy = void(FT_CALL *)(ft_job_msg *);
using fn_ft_job_set_msg_cb = ft_err(FT_CALL *)(FT_JobHandle *, void(FT_CALL *)(void *user, ft_job_msg msg), void *user);
using fn_ft_job_try_get_msg = ft_err(FT_CALL *)(FT_JobHandle *, ft_job_msg *out_msg);
using fn_ft_job_get_msg = ft_err(FT_CALL *)(FT_JobHandle *, uint32_t timeout_ms, ft_job_msg *out_msg);
-1
View File
@@ -48,7 +48,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/UpdateDialogs.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/NotificationManager.hpp"
+2 -2
View File
@@ -16,12 +16,12 @@
namespace Slic3r {
namespace Utils {
using boost::asio::ip::tcp;
// Generic command / response TCP telnet like console class.
// Used by the MKS host to send G-code commands to test connection ("M105") and to start printing ("M23 filename", "M24").
class TCPConsole
{
using tcp = boost::asio::ip::tcp;
public:
TCPConsole() : m_resolver(m_io_context), m_socket(m_io_context) { set_defaults(); }
TCPConsole(const std::string& host_name, const std::string& port_name) : m_resolver(m_io_context), m_socket(m_io_context)
+11 -16
View File
@@ -16,11 +16,6 @@
#include <iostream>
#include <string>
#include <chrono>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
class WebSocketClient {
public:
@@ -36,7 +31,7 @@ public:
}
try {
// Close the WebSocket connection
ws_.close(websocket::close_code::normal);
ws_.close(boost::beast::websocket::close_code::normal);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
@@ -49,7 +44,7 @@ public:
auto const results = resolver_.resolve(host, port);
// Make the connection on the IP address we get from a lookup
auto ep = net::connect(ws_.next_layer(), results);
auto ep = boost::asio::connect(ws_.next_layer(), results);
std::string _host = host;
//if _host last char is '/', remove it
if(_host.size()>0&&_host[host.size()-1] == '/'){
@@ -58,10 +53,10 @@ public:
// _host += ':' + std::to_string(ep.port());
// Set a decorator to change the User-Agent of the handshake
ws_.set_option(websocket::stream_base::decorator(
[](websocket::request_type& req)
ws_.set_option(boost::beast::websocket::stream_base::decorator(
[](boost::beast::websocket::request_type& req)
{
req.set(http::field::user_agent,"ElegooSlicer");
req.set(boost::beast::http::field::user_agent,"ElegooSlicer");
}));
// Perform the WebSocket handshake
ws_.handshake(_host, path);
@@ -70,25 +65,25 @@ public:
void send(const std::string& message){
// Send a message
ws_.write(net::buffer(message));
ws_.write(boost::asio::buffer(message));
}
std::string receive(int timeout = 0){
// This buffer will hold the incoming message
beast::flat_buffer buffer;
boost::beast::flat_buffer buffer;
// Read a message into our buffer
ws_.read(buffer);
// Return the message as a string
return beast::buffers_to_string(buffer.data());
return boost::beast::buffers_to_string(buffer.data());
}
private:
net::io_context ioc_;
tcp::resolver resolver_;
websocket::stream<tcp::socket> ws_;
boost::asio::io_context ioc_;
boost::asio::ip::tcp::resolver resolver_;
boost::beast::websocket::stream<boost::asio::ip::tcp::socket> ws_;
bool is_connect;
};

Some files were not shown because too many files have changed in this diff Show More