Merge some features from BS1.9 beta4 (#5181)

* FIX: linux: fix the building issue on Linux Mint 21.3 Virginia

github: https://github.com/bambulab/BambuStudio/issues/3874
author: https://github.com/lucianoloder

Change-Id: Ia3db6923d5dd68dba532d7bdba6f93f73cc51d59

* FIX: auto-arranging incorrect with rotation enabled

auto-arranging incorrect with rotation enabled and the objects already have been rotated.

jira: STUDIO-6022
Change-Id: I349d663efb1fc71367c8a77aa8ed5047a0bf2017
(cherry picked from commit 75fe40257a274ed83886e1ee20ce8dedd0de48f6)

* ENH: update X1C & X1E start gcode

1.Fix fan problem

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I68ee5be78e142e8a2a210a1a70f5663893390610

* ENH: update A series gcode

1. Update A1 series start gcode and change filament gcode
2. Add G2814 command
3. Add multi-filament extrusion compensation and vibration suppression

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I57d2bc8e98d3e547881dc1369c1fb31413c6205d

* FIX: fix some cali problem of P series

jira: none
Change-Id: Id57ea8d65da22ab653cca49509cb923ff065e43f

* FIX: fix can't enter ',' in multiplicator

github: #3805

Change-Id: I6dd70822d1c2e79d66c70514d6dd580ab029c7ea

* calib wizard

* NEW: FlipLines infill

jira:6701

New infill pattern that combine block lines infill and switching layers for smooth transition.

Change-Id: I2608a2d39b14efcdfe9d39a9437280da350b94c0
(cherry picked from commit 8d0a09c8b763dfc924cbba9913c241e6afadbc7f)

* ENH: add nozzle blob detection and air printing detection

jira: new

Change-Id: Ie4a19a7ad7d0b10a021c516cbc3a84b4ae734302

* FIX: Top surface bridging fail on 3DHC & FL infill

Add 45 degree angle offset when processing the bridge.
Need to raise infill_direction to invalidate posPrepareInfill

jira: 6774
Change-Id: I5e6bef3aa814b01c5f30398ac745937a67e3ef4c
(cherry picked from commit 7b12cab10b88f432a11414f8caa1c6427777a1ba)

* FIX: the error display when reset virtual slot

jira: none
Change-Id: I5ae5899baf1bfc2aaadb832083b277855a669fd5

* FIX: Error "Voronoi cell doesn't contain a sourcepoint"

github: 3859
Change-Id: Idca84992bcba5380bfe05e63ac9a5e40419dcfdf

* fix build error

* FIX: CLI: fix the crash issue caused by get_min_flush_volumes

JIRA: no jira
Change-Id: I0d5bfd605e51ebddac8fddc4d83dab5055b0fbf2

* FIX: can't use support filament in gcode.3mf

1. Add total_filament_volumes, directly access it to get used filaments

github:#3865

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I4fae4f1947b4ebd16e394e0f3cf5fb0e9f979717

* ENH: p series support long retraction

1. P series support long retraction in filament
2. Add long retraction params in common.json

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ib94184fa1f0b5ab151360f1f053d8c8ff92e7e18

* ENH::modify some logs level

jira:[for log]

Change-Id: I6a46b8fcd3a030b4b630e800fe9a9ac5c387f117

* NEW: support multi device

JIRA: STUDIO-6072

Change-Id: Ic514c4097767b0a728368c9ea48ee103c031fbb0
Signed-off-by: Stone Li <stone.li@bambulab.com>

* ENH: update A1 series  gcode

1.Update filament change gcode and machine start gcode for
  A1 and A1 mini

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I2f3be3fd89fef21e717a32f2b89985fc046f7f6e

* FIX: always have 0th filament in ams mapping

1. Only set the filament id in map when flush length is not 0

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I6e0aeaf010f6e6dcbdc3bca5c0034aa60750bb67

* ENH: add filament id in slice info

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ic5fe4632bca8acacc9ffd072ee2ed207c1da37aa

* ENH: refine ui for multi machine

JIRA: STUDIO-6819 STUDIO-6824
1. Shrink the Send Print dialog box
2. add input box for flipping panel

Change-Id: I4174c79ecd239c374ee11478951e12be399c57ce

* FIX: fix Issues with sending multiple devices

JIRA: STUDIO-6876

Signed-off-by: Kunlong Ma <kunlong.ma@bambulab.com>
Change-Id: I33c6a932863fc715c3f0eb5dfd4b299f980a4918

* NEW: support hms error code

Change-Id: Ic256a83cf501fb05bb9d3203f3d24cb1d1290fa4

* FIX:fixed some multi job issue

Change-Id: I338078ad8fcf809888db9d8daeb470a9bf4eab46

* NEW:support pin code binding

Change-Id: Ida5d47881fbd83f3ffedc80369cfe377114d7f13

* ENH:add printable check for devices

Change-Id: I672988fa9cfa986d924bfc64331752f4aef68067
(cherry picked from commit 69de9e5b8334ec94eec7fcee31038b8ff42d1d3b)

* FIX: add more fonts

jira: none
Change-Id: I6bafed3563083858f29e92a3d84906a2e53dcb5c
(cherry picked from commit afbea693e807dcc1c406a59aa5376b9ea2a5d606)

* ENH: load more fonts

this feature is according to Prusa by Filip Sykala<filip.sykala@prusa3d.cz>, thanks to Filip Sykala
jira: none
Change-Id: I55e92f184f750c0b93b679d4382aaa5b164ec5c3
(cherry picked from commit d05522c4cc5d7ee4cac42de398b88d347a55f74b)

* ENH: add ProfileDescription for translate

1.Add ProfileDescription.hpp simply for translating

jira:NEW

Signed-off-by: XunZhangBambu <xun.zhang@bambulab.com>
Change-Id: Iaa3ced1edccf67eaeebde35c1e8b36442d2e9a6f

* ENH: Improve CrossHatch transation layers

jira: 6701

Change name from Flippingline to CrossHatch.

Reduce noise, improve speed by 6.5%. Improve transation layers by
gradually increasing rotation angle and overshoot the transation
layer while direction changed.

Change-Id: I17fcc45b409074d121bf5bb5702e15553d925b51

* UP

* ENH: modify the default config for multi-device

JIRA: STUDIO-6072

Change-Id: If6e7582a8274eb5e685b8b8545f6eab5d17de3f5
Signed-off-by: Stone Li <stone.li@bambulab.com>

* ENH: add long retraction for P series

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I6890695b67e674fc5cdc2a208e89bd9e41404213

* FIX: all plates stats data missing issue

jira: new

Change-Id: I137a2b6d69ad08791f5a9a9788653621960dc63f

* ENH:update pre print options

jira:[for multi]

Change-Id: I2e9bb8a09436a71749af98a0bad94e9922f95c81

* FIX:fixed can't popup pinbind win on macos

jira:[STUDIO-6895]

Change-Id: I664bba78cf27420d736b586df19e3c09c6f8ed21

* FIX:fixed the task of padding cannot be cancelled

Change-Id: I401a22118c14ca7601be7a925cfd8e4796dfc1e9

* ENH:Play video after redirecting to device page

jira:[STUDIO-6884]

Change-Id: Ia5e2ac84e3d71baacfcf941b782dab2325f35d54

* FIX: fix ui bug in send multi machine page for mac

JIRA: STUDIO-6882
Incorrect background color when renaming during multi machine printing

Change-Id: I6c551f5023ffe747e7a7e2f5703b0707c9505922

* FIX: Fix some bugs in maintaining the selected status of local tasks

JIRA: STUDIO-6824

Change-Id: I12c4da3fc56ac5077b3ccd7e89a4b57c3675eaf5

* ENH: local task sort by send time by default

JIRA: STUDIO-6885

Change-Id: I03b5881a39ab2e90c5b9cf46052ba465ee707ccc

* FIX: Clicking to continue printing does not take effect in error code

JIRA: STUDIO-6830
Detected an incomplete printing task error pop-up when power outage occurred. Clicking to continue printing did not take effect

Change-Id: Ie85a1602093dabac861cd1f41ea21e1c312c83e9

* ENH: use designTitle when designId > 0

JIRA: STUDIO-6072

Change-Id: I8342df053edeab16f930522e099e2eef91e5c5a4
Signed-off-by: Stone Li <stone.li@bambulab.com>

* NEW:import vertex and mtl color from obj file

Jira: STUDIO-6805

Change-Id: Iaacb13ee2451effdb83e5aba4b7fe1637b7fc95f

* FIX:change the strategy of merge_ka_kd

Upgrade ui, users can directly ok to proceed to the next step
jira: STUDIO-6805

Change-Id: Ia81019c2eacb503666680c0b8583d026baa0134c
(cherry picked from commit 38a2434753c8e3b422267283b16c75f6ad195b14)

* FIX:use default_strategy after modifed cluster number

jira: STUDIO-6915
Change-Id: I4e0c3d62f5a766f73d48d1e06c4364fc6babe1ac

* FIX: the bug of incorrect button without restarting

JIRA: STUDIO-6824
The bug can cause the user to not restart when opening the multi-device option, but the button of send multi-devices appears

Change-Id: I0837fa79ecc1d8ab5ce98273ad134fa2f830421e

* FIX: wrong default value for long retraction

jira:NEW

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: Ifc2ec57a320fdb14e7ca746e5795501ed146ff32

* FIX: error code pop-up window without retry button in some code

JIRA: STUDIO-6922

Change-Id: I67464bebaba4558618301592c455db8824bbfe30

* FIX: air printing and nozzle blob detection issue

jira: STUDIO-6897

Change-Id: I008ddb24b74119d7e4124ae26310b4b86c42a799

* FIX:fix bugs of algo and read quad in obj file

Jira: STUDIO-6805
Change-Id: I6c33e8197225f27dccdfa0681e64d76d1df14f61

* dd

* ENH:Set the default nozzle diameter to 0.4

jira:[for nozzle]

Change-Id: I74a5c9b0460046496b897eae3d9f917ac1b99052

* FIX:fixed backspace error on macos

Change-Id: I76066391783c04857c1a60a6f8438111501b6d7c

* ENH:Subscription list deduplication

jira:[for mulit]

Change-Id: I10e9d849986c9661b587c7b1a509180c2451816e

* ENH:update wiki url for Pin Code

jira:[pin code]

Change-Id: I95faaa396a839b5b159119ef235b650c76706a84

* NEW:add OpenCV.cmake in deps

jira: none
Change-Id: I1ae4a2bd5618e9e620b08a937904d6af5d00bc41

* FIX:cancel obj import restrictions

jira: none
Change-Id: Iaf3e799ca982ad6aeb3ec76e9a416c4c8e4d100c

* NEW:add multiple printer restrictions

jira:[for multiple]

Change-Id: I0bb5a0c1062a543c42f8d67a9347efa358b0864a

* ENH:Added two entrances for adding devices

jira:[multi device]

Change-Id: Ieb6197e067d422979606f93b22b337a2399aec74

* slic3r: Fix wxFont being undefined

[427/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -c /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp
In file included from /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp:1:
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.hpp:51:21: error: ‘wxFont’ does not name a type
   51 | bool can_load(const wxFont &font);
      |                     ^~~~~~

* slic3r: Fix missing BOOST_LOG_TRIVIAL declaration

[427/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/Utils/FontUtils.cpp.o -c /run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp: In function ‘std::unique_ptr<Slic3r::FontFile> Slic3r::create_font_file(const char*)’:
/run/build/BambuStudio/src/slic3r/Utils/FontUtils.cpp:127:27: error: ‘error’ was not declared in this scope; did you mean ‘perror’?
  127 |         BOOST_LOG_TRIVIAL(error) << "Couldn't open " << file_path << " for reading.";
      |                           ^~~~~
      |                           perror

[447/494] Building CXX object src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o
FAILED: src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o
/usr/bin/c++ -DBOOST_ATOMIC_NO_LIB -DBOOST_CHRONO_NO_LIB -DBOOST_DATE_TIME_NO_LIB -DBOOST_FILESYSTEM_NO_LIB -DBOOST_IOSTREAMS_NO_LIB -DBOOST_LOCALE_NO_LIB -DBOOST_LOG_NO_LIB -DBOOST_REGEX_NO_LIB -DBOOST_SYSTEM_NO_LIB -DBOOST_THREAD_NO_LIB -DCURL_STATICLIB -DGLEW_STATIC -DLIBNEST2D_GEOMETRIES_libslic3r -DLIBNEST2D_OPTIMIZER_nlopt -DLIBNEST2D_STATIC -DLIBNEST2D_THREADING_tbb -DOPENSSL_CERT_OVERRIDE -DOPENVDB_OPENEXR_STATICLIB -DOPENVDB_STATICLIB -DSLIC3R_CURRENTLY_COMPILING_GUI_MODULE -DSLIC3R_GUI -DTBB_USE_CAPTURED_EXCEPTION=0 -DUNICODE -DUSE_TBB -DWXINTL_NO_GETTEXT_MACRO -D_UNICODE -D__WXGTK3__ -D__WXGTK__ -DwxDEBUG_LEVEL=0 -DwxNO_UNSAFE_WXSTRING_CONV -DwxUSE_UNICODE -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/run/build/BambuStudio/src -I/run/build/BambuStudio/build/src/platform -I/run/build/BambuStudio/src/hidapi/include -I/run/build/BambuStudio/src/slic3r/Utils -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/webp -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/atk-1.0 -I/usr/include/fribidi -I/usr/include/pixman-1 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gio-unix-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/sysprof-6 -I/usr/include/gstreamer-1.0 -I/run/build/BambuStudio/build/src/libslic3r -I/run/build/BambuStudio/deps/build/destdir/usr/local/include/opencascade -I/run/build/BambuStudio/src/libnest2d/include -I/run/build/BambuStudio/src/miniz -I/run/build/BambuStudio/src/glu-libtess/include -I/run/build/BambuStudio/src/clipper2/Clipper2Lib/include -I/run/build/BambuStudio/src/minilzo -isystem /run/build/BambuStudio/src/eigen -isystem /run/build/BambuStudio/src/libigl -isystem /app/lib/wx/include/gtk3-unicode-static-3.1 -isystem /app/include/wx-3.1 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/opencv4 -isystem /run/build/BambuStudio/deps/build/destdir/usr/local/include/OpenEXR -std=gnu++20 -fext-numeric-literals -Wall -Wno-reorder -pthread -O3 -DNDEBUG -std=gnu++17 -fPIC -fsigned-char -Werror=return-type -Wno-ignored-attributes -Wno-unknown-pragmas -DOPENVDB_ABI_VERSION_NUMBER=8 -MD -MT src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o -MF src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o.d -o src/slic3r/CMakeFiles/libslic3r_gui.dir/GUI/TaskManager.cpp.o -c /run/build/BambuStudio/src/slic3r/GUI/TaskManager.cpp
In file included from /run/build/BambuStudio/src/slic3r/GUI/TaskManager.cpp:1:
/run/build/BambuStudio/src/slic3r/GUI/TaskManager.hpp: In member function ‘void Slic3r::TaskStateInfo::set_state(Slic3r::TaskState)’:
/run/build/BambuStudio/src/slic3r/GUI/TaskManager.hpp:40:9: error: ‘BOOST_LOG_TRIVIAL’ was not declared in this scope
   40 |         BOOST_LOG_TRIVIAL(trace) << "TaskStateInfo set state = " << get_task_state_enum_str(ts);
      |         ^~~~~~~~~~~~~~~~~

* fix OpenCV

* wip - build break

* fix build error wip

* ENH: support preset description(tooltip)

Change-Id: Iff005baac4974c538d1109fb0ba1df20b04a8f69
Jira: STUDIO-5754

* fix more build errors

* Revert "ENH: load more fonts"

This reverts commit 32b6fd199a.

* change colors

* misc fixes

* restore export gcode btn

---------

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Signed-off-by: Stone Li <stone.li@bambulab.com>
Signed-off-by: Kunlong Ma <kunlong.ma@bambulab.com>
Signed-off-by: XunZhangBambu <xun.zhang@bambulab.com>
Co-authored-by: lane.wei <lane.wei@bambulab.com>
Co-authored-by: Arthur <arthur.tang@bambulab.com>
Co-authored-by: xun.zhang <xun.zhang@bambulab.com>
Co-authored-by: zhimin.zeng <zhimin.zeng@bambulab.com>
Co-authored-by: Kunlong Ma <kunlong.ma@bambulab.com>
Co-authored-by: jianjia.ma <jianjia.ma@bambulab.com>
Co-authored-by: liz.li <liz.li@bambulab.com>
Co-authored-by: tao wang <tao.wang@bambulab.com>
Co-authored-by: Stone Li <stone.li@bambulab.com>
Co-authored-by: zhou.xu <zhou.xu@bambulab.com>
Co-authored-by: Bastien Nocera <hadess@hadess.net>
Co-authored-by: chunmao.guo <chunmao.guo@bambulab.com>
This commit is contained in:
SoftFever
2024-04-28 22:58:47 +08:00
committed by GitHub
co-authored by lane.wei Arthur xun.zhang zhimin.zeng Kunlong Ma jianjia.ma liz.li tao wang Stone Li zhou.xu Bastien Nocera chunmao.guo
parent 78af750ed9
commit 226450ea6a
177 changed files with 24423 additions and 4255 deletions
+42
View File
@@ -186,6 +186,8 @@ void AppConfig::set_defaults()
if (get("show_hints").empty())
set_bool("show_hints", true);
//#endif
if (get("enable_multi_machine").empty())
set_bool("enable_multi_machine", false);
if (get("show_gcode_window").empty())
set_bool("show_gcode_window", true);
@@ -359,6 +361,14 @@ void AppConfig::set_defaults()
set("curr_bed_type", "1");
}
if (get("sending_interval").empty()) {
set("sending_interval", "5");
}
if (get("max_send").empty()) {
set("max_send", "3");
}
// #if BBL_RELEASE_TO_PUBLIC
if (get("iot_environment").empty()) {
set("iot_environment", "3");
@@ -1246,6 +1256,38 @@ bool AppConfig::is_engineering_region(){
return false;
}
void AppConfig::save_custom_color_to_config(const std::vector<std::string> &colors)
{
auto set_colors = [](std::map<std::string, std::string> &data, const std::vector<std::string> &colors) {
for (size_t i = 0; i < colors.size(); i++) {
data[std::to_string(10 + i)] = colors[i]; // for map sort:10 begin
}
};
if (colors.size() > 0) {
if (!has_section("custom_color_list")) {
std::map<std::string, std::string> data;
set_colors(data, colors);
set_section("custom_color_list", data);
} else {
auto data = get_section("custom_color_list");
auto data_modify = const_cast<std::map<std::string, std::string> *>(&data);
set_colors(*data_modify, colors);
set_section("custom_color_list", *data_modify);
}
}
}
std::vector<std::string> AppConfig::get_custom_color_from_config()
{
std::vector<std::string> colors;
if (has_section("custom_color_list")) {
auto data = get_section("custom_color_list");
for (auto iter : data) {
colors.push_back(iter.second);
}
}
return colors;
}
void AppConfig::reset_selections()
{
+3 -1
View File
@@ -233,7 +233,9 @@ public:
std::string get_country_code();
bool is_engineering_region();
// reset the current print / filament / printer selections, so that
void save_custom_color_to_config(const std::vector<std::string> &colors);
std::vector<std::string> get_custom_color_from_config();
// reset the current print / filament / printer selections, so that
// the PresetBundle::load_selections(const AppConfig &config) call will select
// the first non-default preset when called.
void reset_selections();
+1 -1
View File
@@ -987,7 +987,7 @@ void _arrange(
// polygon nesting, a convex hull needs to be calculated.
if (params.allow_rotations) {
for (auto &itm : shapes) {
itm.rotation(min_area_boundingbox_rotation(itm.rawShape()));
itm.rotation(min_area_boundingbox_rotation(itm.transformedShape()));
// If the item is too big, try to find a rotation that makes it fit
if constexpr (std::is_same_v<BinT, Box>) {
+5
View File
@@ -100,6 +100,8 @@ set(lisbslic3r_sources
Fill/FillConcentric.hpp
Fill/FillConcentricInternal.cpp
Fill/FillConcentricInternal.hpp
Fill/FillCrossHatch.cpp
Fill/FillCrossHatch.hpp
Fill/FillHoneycomb.cpp
Fill/FillHoneycomb.hpp
Fill/FillGyroid.cpp
@@ -232,6 +234,7 @@ set(lisbslic3r_sources
Arrange.cpp
NormalUtils.cpp
NormalUtils.hpp
ObjColorUtils.hpp
Orient.hpp
Orient.cpp
MultiPoint.cpp
@@ -473,6 +476,7 @@ set(CGAL_DO_NOT_WARN_ABOUT_CMAKE_BUILD_TYPE ON CACHE BOOL "" FORCE)
cmake_policy(PUSH)
cmake_policy(SET CMP0011 NEW)
find_package(CGAL REQUIRED)
find_package(OpenCV REQUIRED core)
cmake_policy(POP)
add_library(libslic3r_cgal STATIC
@@ -573,6 +577,7 @@ target_link_libraries(libslic3r
mcut
JPEG::JPEG
qoi
opencv_world
)
if(NOT WIN32)
+9 -1
View File
@@ -6,7 +6,15 @@
static const float INV_255 = 1.0f / 255.0f;
namespace Slic3r {
bool color_is_equal(const RGBA a, const RGBA& b)
{
for (size_t i = 0; i < 4; i++) {
if (abs(a[i] - b[i]) > 0.01) {
return false;
}
}
return true;
}
// Conversion from RGB to HSV color space
// The input RGB values are in the range [0, 1]
// The output HSV values are in the ranges h = [0, 360], and s, v = [0, 1]
+7 -2
View File
@@ -7,7 +7,10 @@
#include <algorithm>
namespace Slic3r {
using RGB = std::array<float, 3>;
using RGBA = std::array<float, 4>;
const RGBA UNDEFINE_COLOR = {0,0,0,0};
bool color_is_equal(const RGBA a, const RGBA &b);
class ColorRGB
{
std::array<float, 3> m_data{1.0f, 1.0f, 1.0f};
@@ -82,7 +85,9 @@ public:
ColorRGBA& operator = (const ColorRGBA& other) { m_data = other.m_data; return *this; }
bool operator == (const ColorRGBA& other) const { return m_data == other.m_data; }
bool operator==(const ColorRGBA &other) const{
return color_is_equal(m_data, other.m_data);
}
bool operator != (const ColorRGBA& other) const { return !operator==(other); }
bool operator < (const ColorRGBA& other) const;
bool operator > (const ColorRGBA& other) const;
+3
View File
@@ -831,6 +831,9 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
else if (boost::iequals(it.key(), BBL_JSON_KEY_FROM)) {
key_values.emplace(BBL_JSON_KEY_FROM, it.value());
}
else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) {
key_values.emplace(BBL_JSON_KEY_DESCRIPTION, it.value());
}
else if (boost::iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) {
key_values.emplace(BBL_JSON_KEY_INSTANTIATION, it.value());
}
+2
View File
@@ -32,6 +32,7 @@
#include "FillLightning.hpp"
// BBS: new infill pattern header
#include "FillConcentricInternal.hpp"
#include "FillCrossHatch.hpp"
// #define INFILL_DEBUG_OUTPUT
@@ -51,6 +52,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
case ipGyroid: return new FillGyroid();
case ipRectilinear: return new FillRectilinear();
case ipAlignedRectilinear: return new FillAlignedRectilinear();
case ipCrossHatch: return new FillCrossHatch();
case ipMonotonic: return new FillMonotonic();
case ipLine: return new FillLine();
case ipGrid: return new FillGrid();
+227
View File
@@ -0,0 +1,227 @@
#include "../ClipperUtils.hpp"
#include "../ShortestPath.hpp"
#include "../Surface.hpp"
#include "FillCrossHatch.hpp"
namespace Slic3r {
// CrossHatch Infill: Enhances 3D Printing Speed & Reduces Noise
// CrossHatch, as its name hints, alternates line direction by 90 degrees every few layers to improve adhesion.
// It introduces transform layers between direction shifts for better line cohesion, which fixes the weakness of line infill.
// The transform technique is inspired by David Eccles, improved 3D honeycomb but we made a more flexible implementation.
// This method notably increases printing speed, meeting the demands of modern high-speed 3D printers, and reduces noise for most layers.
// By Bambu Lab
// graph credits: David Eccles (gringer).
// But we made a different definition for points.
/* o---o
* / \
* / \
* \ /
* \ /
* o---o
* p1 p2 p3 p4
*/
static Pointfs generate_one_cycle(double progress, coordf_t period)
{
Pointfs out;
double offset = progress * 1. / 8. * period;
out.reserve(4);
out.push_back(Vec2d(0.25 * period - offset, offset));
out.push_back(Vec2d(0.25 * period + offset, offset));
out.push_back(Vec2d(0.75 * period - offset, -offset));
out.push_back(Vec2d(0.75 * period + offset, -offset));
return out;
}
static Polylines generate_transform_pattern(double inprogress, int direction, coordf_t ingrid_size, coordf_t inwidth, coordf_t inheight)
{
coordf_t width = inwidth;
coordf_t height = inheight;
coordf_t grid_size = ingrid_size * 2; // we due with odd and even saparately.
double progress = inprogress;
Polylines out_polylines;
// generate template patterns;
Pointfs one_cycle_points = generate_one_cycle(progress, grid_size);
Polyline one_cycle;
one_cycle.points.reserve(one_cycle_points.size());
for (size_t i = 0; i < one_cycle_points.size(); i++) one_cycle.points.push_back(Point(one_cycle_points[i]));
// swap if vertical
if (direction < 0) {
width = height;
height = inwidth;
}
// replicate polylines;
Polylines odd_polylines;
Polyline odd_poly;
int num_of_cycle = width / grid_size + 2;
odd_poly.points.reserve(num_of_cycle * one_cycle.size());
// replicate to odd line
Point translate = Point(0, 0);
for (size_t i = 0; i < num_of_cycle; i++) {
Polyline odd_points;
odd_points = Polyline(one_cycle);
odd_points.translate(Point(i * grid_size, 0.0));
odd_poly.points.insert(odd_poly.points.end(), odd_points.begin(), odd_points.end());
}
// fill the height
int num_of_lines = height / grid_size + 2;
odd_polylines.reserve(num_of_lines * odd_poly.size());
for (size_t i = 0; i < num_of_lines; i++) {
Polyline poly = odd_poly;
poly.translate(Point(0.0, grid_size * i));
odd_polylines.push_back(poly);
}
// save to output
out_polylines.insert(out_polylines.end(), odd_polylines.begin(), odd_polylines.end());
// replicate to even lines
Polylines even_polylines;
even_polylines.reserve(odd_polylines.size());
for (size_t i = 0; i < odd_polylines.size(); i++) {
Polyline even = odd_poly;
even.translate(Point(-0.5 * grid_size, (i + 0.5) * grid_size));
even_polylines.push_back(even);
}
// save for output
out_polylines.insert(out_polylines.end(), even_polylines.begin(), even_polylines.end());
// change to vertical if need
if (direction < 0) {
// swap xy, see if we need better performance method
for (Polyline &poly : out_polylines) {
for (Point &p : poly) { std::swap(p.x(), p.y()); }
}
}
return out_polylines;
}
static Polylines generate_repeat_pattern(int direction, coordf_t grid_size, coordf_t inwidth, coordf_t inheight)
{
coordf_t width = inwidth;
coordf_t height = inheight;
Polylines out_polylines;
// swap if vertical
if (direction < 0) {
width = height;
height = inwidth;
}
int num_of_lines = height / grid_size + 1;
out_polylines.reserve(num_of_lines);
for (int i = 0; i < num_of_lines; i++) {
Polyline poly;
poly.points.reserve(2);
poly.append(Point(coordf_t(0), coordf_t(grid_size * i)));
poly.append(Point(width, coordf_t(grid_size * i)));
out_polylines.push_back(poly);
}
// change to vertical if needed
if (direction < 0) {
// swap xy
for (Polyline &poly : out_polylines) {
for (Point &p : poly) { std::swap(p.x(), p.y()); }
}
}
return out_polylines;
}
// it makes the real patterns that overlap the bounding box
// repeat_ratio define the ratio between the height of repeat pattern and grid
static Polylines generate_infill_layers(coordf_t z_height, double repeat_ratio, coordf_t grid_size, coordf_t width, coordf_t height)
{
Polylines result;
coordf_t trans_layer_size = grid_size * 0.4; // upper.
coordf_t repeat_layer_size = grid_size * repeat_ratio; // lower.
z_height += repeat_layer_size / 2; // offset to improve first few layer strength
coordf_t period = trans_layer_size + repeat_layer_size;
coordf_t remains = z_height - std::floor(z_height / period) * period;
coordf_t trans_z = remains - repeat_layer_size; // put repeat layer first.
coordf_t repeat_z = remains;
int phase = fmod(z_height, period * 2) - (period - 1); // add epsilon
int direction = phase <= 0 ? -1 : 1;
// this is a repeat layer
if (trans_z < 0) {
result = generate_repeat_pattern(direction, grid_size, width, height);
}
// this is a transform layer
else {
double progress = fmod(trans_z, trans_layer_size) / trans_layer_size;
// split the progress to forward and backward, with a opposite direction.
if (progress < 0.5)
result = generate_transform_pattern((progress + 0.1) * 2, direction, grid_size, width, height); // increase overlapping.
else
result = generate_transform_pattern((1.1 - progress) * 2, -1 * direction, grid_size, width, height);
}
return result;
}
void FillCrossHatch ::_fill_surface_single(
const FillParams &params, unsigned int thickness_layers, const std::pair<float, Point> &direction, ExPolygon expolygon, Polylines &polylines_out)
{
// rotate angle
auto infill_angle = float(this->angle);
if (std::abs(infill_angle) >= EPSILON) expolygon.rotate(-infill_angle);
// get the rotated bounding box
BoundingBox bb = expolygon.contour.bounding_box();
// linespace modifier
coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
// reduce density
if (params.density < 0.999) line_spacing *= 1.08;
bb.merge(align_to_grid(bb.min, Point(line_spacing * 4, line_spacing * 4)));
// generate pattern
Polylines polylines = generate_infill_layers(scale_(this->z), 1, line_spacing, bb.size()(0), bb.size()(1));
// shift the pattern to the actual space
for (Polyline &pl : polylines) { pl.translate(bb.min); }
polylines = intersection_pl(polylines, to_polygons(expolygon));
// --- remove small remains from gyroid infill
if (!polylines.empty()) {
// Remove very small bits, but be careful to not remove infill lines connecting thin walls!
// The infill perimeter lines should be separated by around a single infill line width.
const double minlength = scale_(0.8 * this->spacing);
polylines.erase(std::remove_if(polylines.begin(), polylines.end(), [minlength](const Polyline &pl)
{ return pl.length() < minlength; }), polylines.end());
}
if (!polylines.empty()) {
int infill_start_idx = polylines_out.size(); // only rotate what belongs to us.
// connect lines
if (params.dont_connect() || polylines.size() <= 1)
append(polylines_out, chain_polylines(std::move(polylines)));
else
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
// rotate back
if (std::abs(infill_angle) >= EPSILON) {
for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) it->rotate(infill_angle);
}
}
}
} // namespace Slic3r
+29
View File
@@ -0,0 +1,29 @@
#ifndef slic3r_FillCrossHatch_hpp_
#define slic3r_FillCrossHatch_hpp_
#include <map>
#include "../libslic3r.h"
#include "FillBase.hpp"
namespace Slic3r {
class FillCrossHatch : public Fill
{
public:
Fill *clone() const override { return new FillCrossHatch(*this); };
~FillCrossHatch() override {}
protected:
void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon expolygon,
Polylines &polylines_out) override;
};
} // namespace Slic3r
#endif // slic3r_FillCrossHatch_hpp_
+106 -18
View File
@@ -21,19 +21,39 @@
namespace Slic3r {
bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::string &message)
{
if (meshptr == nullptr)
return false;
// Parse the OBJ file.
ObjParser::ObjData data;
ObjParser::MtlData mtl_data;
if (! ObjParser::objparse(path, data)) {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path;
message = _L("load_obj: failed to parse");
return false;
}
bool exist_mtl = false;
if (data.mtllibs.size() > 0) { // read mtl
for (auto mtl_name : data.mtllibs) {
boost::filesystem::path full_path(path);
std::string dir = full_path.parent_path().string();
auto mtl_file = dir + "/" + mtl_name;
boost::filesystem::path mtl_path(mtl_file);
auto _mtl_path = mtl_path.string().c_str();
if (boost::filesystem::exists(mtl_path)) {
if (!ObjParser::mtlparse(_mtl_path, mtl_data)) {
BOOST_LOG_TRIVIAL(error) << "load_obj:load_mtl: failed to parse " << _mtl_path;
message = _L("load mtl in obj: failed to parse");
return false;
}
}
else {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to load mtl_path:" << _mtl_path;
}
}
exist_mtl = true;
}
// Count the faces and verify, that all faces are triangular.
size_t num_faces = 0;
size_t num_quads = 0;
@@ -59,17 +79,27 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
i = j;
}
}
// Convert ObjData into indexed triangle set.
indexed_triangle_set its;
size_t num_vertices = data.coordinates.size() / 4;
size_t num_vertices = data.coordinates.size() / OBJ_VERTEX_LENGTH;
its.vertices.reserve(num_vertices);
its.indices.reserve(num_faces + num_quads);
for (size_t i = 0; i < num_vertices; ++ i) {
size_t j = i << 2;
its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
if (exist_mtl) {
obj_info.is_single_mtl = data.usemtls.size() == 1 && mtl_data.new_mtl_unmap.size() == 1;
obj_info.face_colors.reserve(num_faces + num_quads);
}
int indices[4];
bool has_color = data.has_vertex_color;
for (size_t i = 0; i < num_vertices; ++ i) {
size_t j = i * OBJ_VERTEX_LENGTH;
its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
if (data.has_vertex_color) {
RGBA color{std::clamp(data.coordinates[j + 3], 0.f, 1.f), std::clamp(data.coordinates[j + 4], 0.f, 1.f), std::clamp(data.coordinates[j + 5], 0.f, 1.f),
std::clamp(data.coordinates[j + 6], 0.f, 1.f)};
obj_info.vertex_colors.emplace_back(color);
}
}
int indices[ONE_FACE_SIZE];
int uvs[ONE_FACE_SIZE];
for (size_t i = 0; i < data.vertices.size();)
if (data.vertices[i].coordIdx == -1)
++ i;
@@ -79,20 +109,79 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
if (const ObjParser::ObjVertex &vertex = data.vertices[i ++]; vertex.coordIdx == -1) {
break;
} else {
assert(cnt < 4);
assert(cnt < OBJ_VERTEX_LENGTH);
if (vertex.coordIdx < 0 || vertex.coordIdx >= int(its.vertices.size())) {
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index.";
message = _L("The file contains invalid vertex index.");
return false;
}
indices[cnt ++] = vertex.coordIdx;
indices[cnt] = vertex.coordIdx;
uvs[cnt] = vertex.textureCoordIdx;
cnt++;
}
if (cnt) {
assert(cnt == 3 || cnt == 4);
// Insert one or two faces (triangulate a quad).
its.indices.emplace_back(indices[0], indices[1], indices[2]);
if (cnt == 4)
int face_index =its.indices.size() - 1;
RGBA face_color;
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name) {
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
bool is_merge_ka_kd = true;
for (size_t n = 0; n < 3; n++) {
if (float(mtl_data.new_mtl_unmap[mtl_name]->Ka[n] + mtl_data.new_mtl_unmap[mtl_name]->Kd[n]) > 1.0) {
is_merge_ka_kd=false;
break;
}
}
for (size_t n = 0; n < 3; n++) {
if (is_merge_ka_kd) {
face_color[n] = std::clamp(float(mtl_data.new_mtl_unmap[mtl_name]->Ka[n] + mtl_data.new_mtl_unmap[mtl_name]->Kd[n]), 0.f, 1.f);
}
else {
face_color[n] = std::clamp(float(mtl_data.new_mtl_unmap[mtl_name]->Kd[n]), 0.f, 1.f);
}
}
face_color[3] = mtl_data.new_mtl_unmap[mtl_name]->Tr; // alpha
if (mtl_data.new_mtl_unmap[mtl_name]->map_Kd.size() > 0) {
auto png_name = mtl_data.new_mtl_unmap[mtl_name]->map_Kd;
obj_info.has_uv_png = true;
if (obj_info.pngs.find(png_name) == obj_info.pngs.end()) { obj_info.pngs[png_name] = false; }
obj_info.uv_map_pngs[face_index] = png_name;
}
if (data.textureCoordinates.size() > 0) {
Vec2f uv0(data.textureCoordinates[uvs[0] * 2], data.textureCoordinates[uvs[0] * 2 + 1]);
Vec2f uv1(data.textureCoordinates[uvs[1] * 2], data.textureCoordinates[uvs[1] * 2 + 1]);
Vec2f uv2(data.textureCoordinates[uvs[2] * 2], data.textureCoordinates[uvs[2] * 2 + 1]);
std::array<Vec2f, 3> uv_array{uv0, uv1, uv2};
obj_info.uvs.emplace_back(uv_array);
}
obj_info.face_colors.emplace_back(face_color);
}
};
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index) {
if (data.usemtls.size() == 1) {
set_face_color(face_index, data.usemtls[0].name);
} else {
for (size_t k = 0; k < data.usemtls.size(); k++) {
auto mtl = data.usemtls[k];
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
set_face_color(face_index, data.usemtls[k].name);
break;
}
}
}
};
if (exist_mtl) {
set_face_color_by_mtl(face_index);
}
if (cnt == 4) {
its.indices.emplace_back(indices[0], indices[2], indices[3]);
int face_index = its.indices.size() - 1;
if (exist_mtl) {
set_face_color_by_mtl(face_index);
}
}
}
}
@@ -107,12 +196,12 @@ bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
return true;
}
bool load_obj(const char *path, Model *model, std::string &message, const char *object_name_in)
bool load_obj(const char *path, Model *model, ObjInfo& obj_info, std::string &message, const char *object_name_in)
{
TriangleMesh mesh;
bool ret = load_obj(path, &mesh, message);
bool ret = load_obj(path, &mesh, obj_info, message);
if (ret) {
std::string object_name;
if (object_name_in == nullptr) {
@@ -120,10 +209,9 @@ bool load_obj(const char *path, Model *model, std::string &message, const char *
object_name.assign((last_slash == nullptr) ? path : last_slash + 1);
} else
object_name.assign(object_name_in);
model->add_object(object_name.c_str(), path, std::move(mesh));
}
return ret;
}
+16 -4
View File
@@ -1,15 +1,27 @@
#ifndef slic3r_Format_OBJ_hpp_
#define slic3r_Format_OBJ_hpp_
#include "libslic3r/Color.hpp"
#include <unordered_map>
namespace Slic3r {
class TriangleMesh;
class Model;
class ModelObject;
typedef std::function<void(std::vector<RGBA> &input_colors, bool is_single_color, std::vector<unsigned char> &filament_ids, unsigned char &first_extruder_id)> ObjImportColorFn;
// Load an OBJ file into a provided model.
extern bool load_obj(const char *path, TriangleMesh *mesh, std::string &message);
extern bool load_obj(const char *path, Model *model, std::string &message, const char *object_name = nullptr);
struct ObjInfo {
std::vector<RGBA> vertex_colors;
std::vector<RGBA> face_colors;
bool is_single_mtl{false};
std::vector<std::array<Vec2f,3>> uvs;
std::string obj_dircetory;
std::map<std::string,bool> pngs;
std::unordered_map<int, std::string> uv_map_pngs;
bool has_uv_png{false};
};
extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message);
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr);
extern bool store_obj(const char *path, TriangleMesh *mesh);
extern bool store_obj(const char *path, ModelObject *model);
+7 -11
View File
@@ -213,6 +213,7 @@ static constexpr const char* FILAMENT_TYPE_TAG = "type";
static constexpr const char *FILAMENT_COLOR_TAG = "color";
static constexpr const char *FILAMENT_USED_M_TAG = "used_m";
static constexpr const char *FILAMENT_USED_G_TAG = "used_g";
static constexpr const char *FILAMENT_TRAY_INFO_ID_TAG = "tray_info_idx";
static constexpr const char* CONFIG_TAG = "config";
@@ -586,21 +587,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return ret;
};
for (auto it = ps.volumes_per_extruder.begin(); it != ps.volumes_per_extruder.end(); it++) {
for (auto it = ps.total_volumes_per_extruder.begin(); it != ps.total_volumes_per_extruder.end(); it++) {
double volume = it->second;
auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, it->first);
FilamentInfo info;
info.id = it->first;
if (ps.flush_per_filament.find(it->first) != ps.flush_per_filament.end()) {
volume = ps.flush_per_filament.at(it->first);
auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, it->first);
info.used_m = used_filament_m + flushed_filament_m;
info.used_g = used_filament_g + flushed_filament_g;
} else {
info.used_m = used_filament_m;
info.used_g = used_filament_g;
}
info.used_g = used_filament_g;
info.used_m = used_filament_m;
slice_filaments_info.push_back(info);
}
@@ -4231,13 +4225,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string color = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_COLOR_TAG);
std::string used_m = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_M_TAG);
std::string used_g = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_USED_G_TAG);
std::string filament_id = bbs_get_attribute_value_string(attributes, num_attributes, FILAMENT_TRAY_INFO_ID_TAG);
FilamentInfo filament_info;
filament_info.id = atoi(id.c_str()) - 1;
filament_info.type = type;
filament_info.color = color;
filament_info.used_m = atof(used_m.c_str());
filament_info.used_g = atof(used_g.c_str());
filament_info.filament_id = filament_id;
m_curr_plater->slice_filaments_info.push_back(filament_info);
}
return true;
@@ -7659,6 +7654,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++)
{
stream << " <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" "
<< FILAMENT_TRAY_INFO_ID_TAG <<"=\""<< it->filament_id <<"\" "
<< FILAMENT_TYPE_TAG << "=\"" << it->type << "\" "
<< FILAMENT_COLOR_TAG << "=\"" << it->color << "\" "
<< FILAMENT_USED_M_TAG << "=\"" << it->used_m << "\" "
+301 -18
View File
@@ -9,16 +9,12 @@
#include "libslic3r/LocalesUtils.hpp"
namespace ObjParser {
#define EATWS() while (*line == ' ' || *line == '\t') ++line
static bool obj_parseline(const char *line, ObjData &data)
{
#define EATWS() while (*line == ' ' || *line == '\t') ++ line
if (*line == 0)
return true;
assert(Slic3r::is_decimal_separator_point());
// Ignore whitespaces at the beginning of the line.
//FIXME is this a good idea?
EATWS();
@@ -55,19 +51,19 @@ static bool obj_parseline(const char *line, ObjData &data)
line = endptr;
EATWS();
}
double w = 0;
/*double w = 0;
if (*line != 0) {
w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
}
}*/
if (*line != 0)
return false;
data.textureCoordinates.push_back((float)u);
data.textureCoordinates.push_back((float)v);
data.textureCoordinates.push_back((float)w);
//data.textureCoordinates.push_back((float)w);
break;
}
case 'n':
@@ -156,23 +152,46 @@ static bool obj_parseline(const char *line, ObjData &data)
return false;
line = endptr;
EATWS();
double w = 1.0;
if (*line != 0) {
w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
double color_x = 0.0, color_y = 0.0, color_z = 0.0, color_w = 0.0;//undefine color
if (*line != 0) {
if (!data.has_vertex_color) {
data.has_vertex_color = true;
}
color_x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
color_w = 1.0;//default define alpha = 1.0
if (*line != 0) {
color_w = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
}
}
// the following check is commented out because there may be obj files containing extra data, as those generated by Meshlab,
// see https://dev.prusa3d.com/browse/SPE-1019 for an example,
// and this would lead to a crash because no vertex would be stored
// and this would lead to a crash because no vertex would be stored
// if (*line != 0)
// return false;
data.coordinates.push_back((float)x);
data.coordinates.push_back((float)y);
data.coordinates.push_back((float)z);
data.coordinates.push_back((float)w);
data.coordinates.push_back((float) color_x);
data.coordinates.push_back((float) color_y);
data.coordinates.push_back((float) color_z);
data.coordinates.push_back((float) color_w);
break;
}
}
@@ -232,6 +251,24 @@ static bool obj_parseline(const char *line, ObjData &data)
data.vertices.push_back(vertex);
EATWS();
}
if (data.usemtls.size() > 0) {
data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
}
if (data.usemtls.size() > 0) {
int face_index_count = 0;
for (int i = data.vertices.size() - 1; i >= 0; i--) {
if (data.vertices[i].coordIdx == -1) {
break;
}
face_index_count++;
}
if (face_index_count == 3) {//tri
data.usemtls.back().face_end++;
} else if (face_index_count == 4) {//quad
data.usemtls.back().face_end++;
data.usemtls.back().face_end++;
}
}
vertex.coordIdx = -1;
vertex.normalIdx = -1;
vertex.textureCoordIdx = -1;
@@ -263,10 +300,23 @@ static bool obj_parseline(const char *line, ObjData &data)
// usemtl [material name]
// printf("usemtl %s\r\n", line);
EATWS();
if (data.usemtls.size()>0) {
data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
}
ObjUseMtl usemtl;
usemtl.vertexIdxFirst = (int)data.vertices.size();
usemtl.name = line;
data.usemtls.push_back(usemtl);
if (data.usemtls.size() == 1) {
data.usemtls.back().face_start = 0;
}
else {//>=2
auto count = data.usemtls.size();
auto& last_usemtl = data.usemtls[count-1];
auto& last_last_usemtl = data.usemtls[count - 2];
last_usemtl.face_start = last_last_usemtl.face_end + 1;
}
data.usemtls.back().face_end = data.usemtls.back().face_start - 1;
break;
}
case 'o':
@@ -323,6 +373,197 @@ static bool obj_parseline(const char *line, ObjData &data)
return true;
}
static std::string cur_mtl_name = "";
static bool mtl_parseline(const char *line, MtlData &data)
{
if (*line == 0) return true;
assert(Slic3r::is_decimal_separator_point());
// Ignore whitespaces at the beginning of the line.
// FIXME is this a good idea?
EATWS();
char c1 = *line++;
switch (c1) {
case '#': {// Comment, ignore the rest of the line.
break;
}
case 'n': {
if (*(line++) != 'e' || *(line++) != 'w' || *(line++) != 'm' || *(line++) != 't' || *(line++) != 'l')
return false;
EATWS();
ObjNewMtl new_mtl;
cur_mtl_name = line;
data.new_mtl_unmap[cur_mtl_name] = std::make_shared<ObjNewMtl>();
break;
}
case 'm': {
if (*(line++) != 'a' || *(line++) != 'p' || *(line++) != '_' || *(line++) != 'K' || *(line++) != 'd') return false;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->map_Kd = line;
}
break;
}
case 'N': {
char cur_char = *(line++);
if (cur_char == 's') {
EATWS();
char * endptr = 0;
double ns = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ns = (float) ns;
}
} else if (cur_char == 'i') {
EATWS();
char * endptr = 0;
double ni = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ni = (float) ni;
}
}
break;
}
case 'K': {
char cur_char = *(line++);
if (cur_char == 'a') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ka[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ka[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ka[2] = z;
}
} else if (cur_char == 'd') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Kd[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Kd[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Kd[2] = z;
}
} else if (cur_char == 's') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ks[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ks[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ks[2] = z;
}
} else if (cur_char == 'e') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Ke[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Ke[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Ke[2] = z;
}
}
break;
}
case 'i': {
if (*(line++) != 'l' || *(line++) != 'l' || *(line++) != 'u' || *(line++) != 'm')
return false;
EATWS();
char * endptr = 0;
double illum = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->illum = (float) illum;
}
break;
}
case 'd': {
EATWS();
char * endptr = 0;
double d = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->d = (float) d;
}
break;
}
case 'T': {
char cur_char = *(line++);
if (cur_char == 'r') {
EATWS();
char * endptr = 0;
double tr = strtod(line, &endptr);
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Tr = (float) tr;
}
break;
} else if (cur_char == 'f') {
EATWS();
char * endptr = 0;
double x = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
line = endptr;
EATWS();
if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
data.new_mtl_unmap[cur_mtl_name]->Tf[0] = x;
data.new_mtl_unmap[cur_mtl_name]->Tf[1] = y;
data.new_mtl_unmap[cur_mtl_name]->Tf[2] = z;
}
break;
}
}
}
return true;
}
bool objparse(const char *path, ObjData &data)
{
@@ -369,10 +610,52 @@ bool objparse(const char *path, ObjData &data)
return true;
}
bool mtlparse(const char *path, MtlData &data)
{
Slic3r::CNumericLocalesSetter locales_setter;
FILE *pFile = boost::nowide::fopen(path, "rt");
if (pFile == 0) return false;
cur_mtl_name = "";
try {
char buf[65536 * 2];
size_t len = 0;
size_t lenPrev = 0;
while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
len += lenPrev;
size_t lastLine = 0;
for (size_t i = 0; i < len; ++i)
if (buf[i] == '\r' || buf[i] == '\n') {
buf[i] = 0;
char *c = buf + lastLine;
while (*c == ' ' || *c == '\t') ++c;
// FIXME check the return value and exit on error?
// Will it break parsing of some obj files?
mtl_parseline(c, data);
lastLine = i + 1;
}
lenPrev = len - lastLine;
if (lenPrev > 65536) {
BOOST_LOG_TRIVIAL(error) << "MtlParser: Excessive line length";
::fclose(pFile);
return false;
}
memmove(buf, buf + lastLine, lenPrev);
}
} catch (std::bad_alloc &) {
BOOST_LOG_TRIVIAL(error) << "MtlParser: Out of memory";
}
::fclose(pFile);
// printf("vertices: %d\r\n", data.vertices.size() / 4);
// printf("coords: %d\r\n", data.coordinates.size());
return true;
}
bool objparse(std::istream &stream, ObjData &data)
{
Slic3r::CNumericLocalesSetter locales_setter;
try {
char buf[65536 * 2];
size_t len = 0;
+38 -11
View File
@@ -3,6 +3,8 @@
#include <string>
#include <vector>
#include <array>
#include <unordered_map>
#include <istream>
namespace ObjParser {
@@ -16,22 +18,39 @@ struct ObjVertex
inline bool operator==(const ObjVertex &v1, const ObjVertex &v2)
{
return
v1.coordIdx == v2.coordIdx &&
v1.textureCoordIdx == v2.textureCoordIdx &&
return v1.coordIdx == v2.coordIdx &&
v1.textureCoordIdx == v2.textureCoordIdx &&
v1.normalIdx == v2.normalIdx;
}
struct ObjUseMtl
{
int vertexIdxFirst;
int vertexIdxEnd{-1};
int face_start;
int face_end{-1};
std::string name;
};
struct ObjNewMtl
{
std::string name;
float Ns;
float Ni;
float d;
float illum;
float Tr{1.0f}; // Transmission
std::array<float, 3> Tf;
std::array<float, 3> Ka;
std::array<float, 3> Kd;
std::array<float, 3> Ks;
std::array<float, 3> Ke;
std::string map_Kd;//defalut png
};
inline bool operator==(const ObjUseMtl &v1, const ObjUseMtl &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.name.compare(v2.name) == 0;
}
@@ -56,8 +75,7 @@ struct ObjGroup
inline bool operator==(const ObjGroup &v1, const ObjGroup &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.name.compare(v2.name) == 0;
}
@@ -69,17 +87,19 @@ struct ObjSmoothingGroup
inline bool operator==(const ObjSmoothingGroup &v1, const ObjSmoothingGroup &v2)
{
return
v1.vertexIdxFirst == v2.vertexIdxFirst &&
return v1.vertexIdxFirst == v2.vertexIdxFirst &&
v1.smoothingGroupID == v2.smoothingGroupID;
}
#define OBJ_VERTEX_COLOR_ALPHA 6
#define OBJ_VERTEX_LENGTH 7 // x, y, z, color_x,color_y,color_z,color_w
#define ONE_FACE_SIZE 4//ONE_FACE format: f 8/4/6 7/3/6 6/2/6 -1/-1/-1
struct ObjData {
// Version of the data structure for load / store in the private binary format.
int version;
// x, y, z, w
// x, y, z, color_x,color_y,color_z,color_w
std::vector<float> coordinates;
bool has_vertex_color{false};
// u, v, w
std::vector<float> textureCoordinates;
// x, y, z
@@ -97,7 +117,14 @@ struct ObjData {
std::vector<ObjVertex> vertices;
};
struct MtlData
{
// Version of the data structure for load / store in the private binary format.
int version;
std::unordered_map<std::string, std::shared_ptr<ObjNewMtl>> new_mtl_unmap;
};
extern bool objparse(const char *path, ObjData &data);
extern bool mtlparse(const char *path, MtlData &data);
extern bool objparse(std::istream &stream, ObjData &data);
extern bool objbinsave(const char *path, const ObjData &data);
+2 -46
View File
@@ -1382,52 +1382,8 @@ namespace DoExport {
double total_used_filament = 0.0;
double total_weight = 0.0;
double total_cost = 0.0;
for (auto volume : result.print_statistics.volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) { return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
//BBS: add flush volume
for (auto volume : result.print_statistics.flush_per_filament) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) { return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
for (auto volume : result.print_statistics.wipe_tower_volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
auto extruder = std::find_if(extruders.begin(), extruders.end(), [extruder_id](const Extruder& extr) {return extr.id() == extruder_id; });
if (extruder == extruders.end())
continue;
double s = PI * sqr(0.5* extruder->filament_diameter());
double weight = volume.second * extruder->filament_density() * 0.001;
total_used_filament += volume.second/s;
total_weight += weight;
total_cost += weight * extruder->filament_cost() * 0.001;
}
for (auto volume : result.print_statistics.support_volumes_per_extruder) {
for (auto volume : result.print_statistics.total_volumes_per_extruder) {
total_extruded_volume += volume.second;
size_t extruder_id = volume.first;
@@ -1447,7 +1403,7 @@ namespace DoExport {
print_statistics.total_weight = total_weight;
print_statistics.total_cost = total_cost;
print_statistics.filament_stats = result.print_statistics.volumes_per_extruder;
print_statistics.filament_stats = result.print_statistics.model_volumes_per_extruder;
}
// if any reserved keyword is found, returns a std::vector containing the first MAX_COUNT keywords found
+50 -21
View File
@@ -753,7 +753,7 @@ void GCodeProcessor::UsedFilaments::reset()
volumes_per_color_change = std::vector<double>();
model_extrude_cache = 0.0f;
volumes_per_extruder.clear();
model_volumes_per_extruder.clear();
flush_per_filament.clear();
@@ -761,16 +761,20 @@ void GCodeProcessor::UsedFilaments::reset()
filaments_per_role.clear();
wipe_tower_cache = 0.0f;
wipe_tower_volume_per_extruder.clear();
wipe_tower_volumes_per_extruder.clear();
support_volume_cache = 0.0f;
support_volume_per_extruder.clear();
support_volumes_per_extruder.clear();
total_volume_cache = 0.0f;
total_volumes_per_extruder.clear();
}
void GCodeProcessor::UsedFilaments::increase_support_caches(double extruded_volume)
{
support_volume_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume)
@@ -778,12 +782,14 @@ void GCodeProcessor::UsedFilaments::increase_model_caches(double extruded_volume
color_change_cache += extruded_volume;
model_extrude_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::increase_wipe_tower_caches(double extruded_volume)
{
wipe_tower_cache += extruded_volume;
role_cache += extruded_volume;
total_volume_cache += extruded_volume;
}
void GCodeProcessor::UsedFilaments::process_color_change_cache()
@@ -794,14 +800,27 @@ void GCodeProcessor::UsedFilaments::process_color_change_cache()
}
}
void GCodeProcessor::UsedFilaments::process_total_volume_cache(GCodeProcessor* processor)
{
size_t active_extruder_id = processor->m_extruder_id;
if (total_volume_cache!= 0.0f) {
if (total_volumes_per_extruder.find(active_extruder_id) != total_volumes_per_extruder.end())
total_volumes_per_extruder[active_extruder_id] += total_volume_cache;
else
total_volumes_per_extruder[active_extruder_id] = total_volume_cache;
total_volume_cache = 0.0f;
}
}
void GCodeProcessor::UsedFilaments::process_model_cache(GCodeProcessor* processor)
{
size_t active_extruder_id = processor->m_extruder_id;
if (model_extrude_cache != 0.0f) {
if (volumes_per_extruder.find(active_extruder_id) != volumes_per_extruder.end())
volumes_per_extruder[active_extruder_id] += model_extrude_cache;
if (model_volumes_per_extruder.find(active_extruder_id) != model_volumes_per_extruder.end())
model_volumes_per_extruder[active_extruder_id] += model_extrude_cache;
else
volumes_per_extruder[active_extruder_id] = model_extrude_cache;
model_volumes_per_extruder[active_extruder_id] = model_extrude_cache;
model_extrude_cache = 0.0f;
}
}
@@ -810,10 +829,10 @@ void GCodeProcessor::UsedFilaments::process_wipe_tower_cache(GCodeProcessor* pro
{
size_t active_extruder_id = processor->m_extruder_id;
if (wipe_tower_cache != 0.0f) {
if (wipe_tower_volume_per_extruder.find(active_extruder_id) != wipe_tower_volume_per_extruder.end())
wipe_tower_volume_per_extruder[active_extruder_id] += wipe_tower_cache;
if (wipe_tower_volumes_per_extruder.find(active_extruder_id) != wipe_tower_volumes_per_extruder.end())
wipe_tower_volumes_per_extruder[active_extruder_id] += wipe_tower_cache;
else
wipe_tower_volume_per_extruder[active_extruder_id] = wipe_tower_cache;
wipe_tower_volumes_per_extruder[active_extruder_id] = wipe_tower_cache;
wipe_tower_cache = 0.0f;
}
}
@@ -822,20 +841,27 @@ void GCodeProcessor::UsedFilaments::process_support_cache(GCodeProcessor* proces
{
size_t active_extruder_id = processor->m_extruder_id;
if (support_volume_cache != 0.0f){
if (support_volume_per_extruder.find(active_extruder_id) != support_volume_per_extruder.end())
support_volume_per_extruder[active_extruder_id] += support_volume_cache;
if (support_volumes_per_extruder.find(active_extruder_id) != support_volumes_per_extruder.end())
support_volumes_per_extruder[active_extruder_id] += support_volume_cache;
else
support_volume_per_extruder[active_extruder_id] = support_volume_cache;
support_volumes_per_extruder[active_extruder_id] = support_volume_cache;
support_volume_cache = 0.0f;
}
}
void GCodeProcessor::UsedFilaments::update_flush_per_filament(size_t extrude_id, float flush_volume)
{
if (flush_per_filament.find(extrude_id) != flush_per_filament.end())
flush_per_filament[extrude_id] += flush_volume;
else
flush_per_filament[extrude_id] = flush_volume;
if (flush_volume != 0.f) {
if (flush_per_filament.find(extrude_id) != flush_per_filament.end())
flush_per_filament[extrude_id] += flush_volume;
else
flush_per_filament[extrude_id] = flush_volume;
if (total_volumes_per_extruder.find(extrude_id) != total_volumes_per_extruder.end())
total_volumes_per_extruder[extrude_id] += flush_volume;
else
total_volumes_per_extruder[extrude_id] = flush_volume;
}
}
void GCodeProcessor::UsedFilaments::process_role_cache(GCodeProcessor* processor)
@@ -865,6 +891,7 @@ void GCodeProcessor::UsedFilaments::process_caches(GCodeProcessor* processor)
process_role_cache(processor);
process_wipe_tower_cache(processor);
process_support_cache(processor);
process_total_volume_cache(processor);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
@@ -4542,6 +4569,7 @@ void GCodeProcessor::process_filaments(CustomGCode::Type code)
if (code == CustomGCode::ToolChange) {
m_used_filaments.process_model_cache(this);
m_used_filaments.process_support_cache(this);
m_used_filaments.process_total_volume_cache(this);
//BBS: reset remaining filament
m_remaining_volume = m_nozzle_volume;
}
@@ -4573,11 +4601,12 @@ void GCodeProcessor::update_estimated_times_stats()
m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].reset();
m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change;
m_result.print_statistics.volumes_per_extruder = m_used_filaments.volumes_per_extruder;
m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volume_per_extruder;
m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volume_per_extruder;
m_result.print_statistics.model_volumes_per_extruder = m_used_filaments.model_volumes_per_extruder;
m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volumes_per_extruder;
m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volumes_per_extruder;
m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament;
m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role;
m_result.print_statistics.total_volumes_per_extruder = m_used_filaments.total_volumes_per_extruder;
}
//BBS: ugly code...
@@ -4587,8 +4616,8 @@ void GCodeProcessor::update_slice_warnings()
auto get_used_extruders = [this]() {
std::vector<size_t> used_extruders;
used_extruders.reserve(m_used_filaments.volumes_per_extruder.size());
for (auto item : m_used_filaments.volumes_per_extruder) {
used_extruders.reserve(m_used_filaments.total_volumes_per_extruder.size());
for (auto item : m_used_filaments.total_volumes_per_extruder) {
used_extruders.push_back(item.first);
}
return used_extruders;
+12 -5
View File
@@ -73,9 +73,10 @@ namespace Slic3r {
};
std::vector<double> volumes_per_color_change;
std::map<size_t, double> volumes_per_extruder;
std::map<size_t, double> model_volumes_per_extruder;
std::map<size_t, double> wipe_tower_volumes_per_extruder;
std::map<size_t, double> support_volumes_per_extruder;
std::map<size_t, double> total_volumes_per_extruder;
//BBS: the flush amount of every filament
std::map<size_t, double> flush_per_filament;
std::map<ExtrusionRole, std::pair<double, double>> used_filaments_per_role;
@@ -92,7 +93,9 @@ namespace Slic3r {
volumes_per_color_change.clear();
volumes_per_color_change.shrink_to_fit();
wipe_tower_volumes_per_extruder.clear();
volumes_per_extruder.clear();
model_volumes_per_extruder.clear();
support_volumes_per_extruder.clear();
total_volumes_per_extruder.clear();
flush_per_filament.clear();
used_filaments_per_role.clear();
total_filamentchanges = 0;
@@ -500,17 +503,20 @@ namespace Slic3r {
std::vector<double> volumes_per_color_change;
double model_extrude_cache;
std::map<size_t, double> volumes_per_extruder;
std::map<size_t, double> model_volumes_per_extruder;
double wipe_tower_cache;
std::map<size_t, double>wipe_tower_volume_per_extruder;
std::map<size_t, double>wipe_tower_volumes_per_extruder;
double support_volume_cache;
std::map<size_t, double>support_volume_per_extruder;
std::map<size_t, double>support_volumes_per_extruder;
//BBS: the flush amount of every filament
std::map<size_t, double> flush_per_filament;
double total_volume_cache;
std::map<size_t, double>total_volumes_per_extruder;
double role_cache;
std::map<ExtrusionRole, std::pair<double, double>> filaments_per_role;
@@ -524,6 +530,7 @@ namespace Slic3r {
void process_model_cache(GCodeProcessor* processor);
void process_wipe_tower_cache(GCodeProcessor* processor);
void process_support_cache(GCodeProcessor* processor);
void process_total_volume_cache(GCodeProcessor* processor);
void update_flush_per_filament(size_t extrude_id, float flush_length);
void process_role_cache(GCodeProcessor* processor);
+5 -3
View File
@@ -160,10 +160,12 @@ VoronoiDiagram::detect_known_issues(const VoronoiDiagram &voronoi_diagram, Segme
return IssueType::FINITE_EDGE_WITH_NON_FINITE_VERTEX;
} else if (const IssueType cell_issue_type = detect_known_voronoi_cell_issues(voronoi_diagram, segment_begin, segment_end); cell_issue_type != IssueType::NO_ISSUE_DETECTED) {
return cell_issue_type;
} else if (!VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segment_begin, segment_end)) {
// Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
return IssueType::NON_PLANAR_VORONOI_DIAGRAM;
}
// BBS: test no problem in BBS
//} else if (!VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segment_begin, segment_end)) {
// // Detection of non-planar Voronoi diagram detects at least GH issues #8474, #8514 and #8446.
// return IssueType::NON_PLANAR_VORONOI_DIAGRAM;
//}
return IssueType::NO_ISSUE_DETECTED;
}
+206 -6
View File
@@ -24,9 +24,6 @@
#include "TriangleSelector.hpp"
#include "Format/AMF.hpp"
#include "Format/OBJ.hpp"
#include "Format/STL.hpp"
#include "Format/STEP.hpp"
#include "Format/svg.hpp"
// BBS
#include "FaceDetector.hpp"
@@ -60,6 +57,9 @@
#define _L(s) Slic3r::I18N::translate(s)
namespace Slic3r {
const std::vector<std::string> CONST_FILAMENTS = {
"", "4", "8", "0C", "1C", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "AC", "BC", "CC", "DC",
}; // 5 10 15 16
// BBS initialization of static variables
std::map<size_t, ExtruderParams> Model::extruderParamsMap = { {0,{"",0,0}}};
GlobalSpeedMap Model::printSpeedMap{};
@@ -190,7 +190,12 @@ Model::~Model()
// Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well.
Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions,
LoadStrategy options, PlateDataPtrs* plate_data, std::vector<Preset*>* project_presets, bool *is_xxx, Semver* file_version, Import3mfProgressFn proFn,
ImportstlProgressFn stlFn, ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project, int plate_id)
ImportstlProgressFn stlFn,
ImportStepProgressFn stepFn,
StepIsUtf8Fn stepIsUtf8Fn,
BBLProject * project,
int plate_id,
ObjImportColorFn objFn)
{
Model model;
@@ -221,8 +226,46 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
result = load_stl(input_file.c_str(), &model, nullptr, stlFn);
else if (boost::algorithm::iends_with(input_file, ".oltp"))
result = load_stl(input_file.c_str(), &model, nullptr, stlFn,256);
else if (boost::algorithm::iends_with(input_file, ".obj"))
result = load_obj(input_file.c_str(), &model, message);
else if (boost::algorithm::iends_with(input_file, ".obj")) {
ObjInfo obj_info;
result = load_obj(input_file.c_str(), &model, obj_info, message);
if (result){
unsigned char first_extruder_id;
if (obj_info.vertex_colors.size() > 0) {
std::vector<unsigned char> vertex_filament_ids;
if (objFn) { // 1.result is ok and pop up a dialog
objFn(obj_info.vertex_colors, false, vertex_filament_ids, first_extruder_id);
if (vertex_filament_ids.size() > 0) {
result = obj_import_vertex_color_deal(vertex_filament_ids, first_extruder_id, & model);
}
} else { // test //todo delete
vertex_filament_ids.push_back(2);
vertex_filament_ids.push_back(3);
vertex_filament_ids.push_back(4);
vertex_filament_ids.push_back(1); // 4
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1);
vertex_filament_ids.push_back(1); // 8
result = obj_import_vertex_color_deal(vertex_filament_ids, first_extruder_id, &model);
}
} else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) { // mtl file
std::vector<unsigned char> face_filament_ids;
if (objFn) { // 1.result is ok and pop up a dialog
objFn(obj_info.face_colors, obj_info.is_single_mtl, face_filament_ids, first_extruder_id);
if (face_filament_ids.size() > 0) {
result = obj_import_face_color_deal(face_filament_ids, first_extruder_id, &model);
}
}
} /*else if (obj_info.has_uv_png && obj_info.uvs.size() > 0) {
boost::filesystem::path full_path(input_file);
std::string obj_directory = full_path.parent_path().string();
obj_info.obj_dircetory = obj_directory;
result = false;
message = _L("Importing obj with png function is developing.");
}*/
}
}
else if (boost::algorithm::iends_with(input_file, ".svg"))
result = load_svg(input_file.c_str(), &model, message);
//BBS: remove the old .amf.xml files
@@ -2866,6 +2909,163 @@ void Model::setExtruderParams(const DynamicPrintConfig& config, int extruders_co
}
}
static void get_real_filament_id(const unsigned char &id, std::string &result) {
if (id < CONST_FILAMENTS.size()) {
result = CONST_FILAMENTS[id];
} else {
result = "";//error
}
};
bool Model::obj_import_vertex_color_deal(const std::vector<unsigned char> &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model)
{
if (vertex_filament_ids.size() == 0) {
return false;
}
// 2.generate mmu_segmentation_facets
if (model->objects.size() == 1 ) {
auto obj = model->objects[0];
obj->config.set("extruder", first_extruder_id);
if (obj->volumes.size() == 1) {
enum VertexColorCase {
_3_SAME_COLOR,
_3_DIFF_COLOR,
_2_SAME_1_DIFF_COLOR,
};
auto calc_vertex_color_case = [](const unsigned char &c0, const unsigned char &c1, const unsigned char &c2, VertexColorCase &vertex_color_case,
unsigned char &iso_index) {
if (c0 == c1 && c1 == c2) {
vertex_color_case = VertexColorCase::_3_SAME_COLOR;
} else if (c0 != c1 && c1 != c2 && c0 != c2) {
vertex_color_case = VertexColorCase::_3_DIFF_COLOR;
} else if (c0 == c1) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 2;
} else if (c1 == c2) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 0;
} else if (c0 == c2) {
vertex_color_case = _2_SAME_1_DIFF_COLOR;
iso_index = 1;
} else {
std::cout << "error";
}
};
auto calc_tri_area = [](const Vec3f &v0, const Vec3f &v1, const Vec3f &v2) {
return std::abs((v0 - v1).cross(v0 - v2).norm()) / 2;
};
auto volume = obj->volumes[0];
volume->config.set("extruder", first_extruder_id);
auto face_count = volume->mesh().its.indices.size();
volume->mmu_segmentation_facets.reserve(face_count);
if (volume->mesh().its.vertices.size() != vertex_filament_ids.size()) {
return false;
}
for (size_t i = 0; i < volume->mesh().its.indices.size(); i++) {
auto face = volume->mesh().its.indices[i];
auto filament_id0 = vertex_filament_ids[face[0]];
auto filament_id1 = vertex_filament_ids[face[1]];
auto filament_id2 = vertex_filament_ids[face[2]];
if (filament_id0 <= 1 && filament_id1 <= 1 && filament_id2 <= 2) {
continue;
}
if (i == 0) {
std::cout << "";
}
VertexColorCase vertex_color_case;
unsigned char iso_index;
calc_vertex_color_case(filament_id0, filament_id1, filament_id2, vertex_color_case, iso_index);
switch (vertex_color_case) {
case _3_SAME_COLOR: {
std::string result;
get_real_filament_id(filament_id0, result);
volume->mmu_segmentation_facets.set_triangle_from_string(i, result);
break;
}
case _3_DIFF_COLOR: {
std::string result0, result1, result2;
get_real_filament_id(filament_id0, result0);
get_real_filament_id(filament_id1, result1);
get_real_filament_id(filament_id2, result2);
auto v0 = volume->mesh().its.vertices[face[0]];
auto v1 = volume->mesh().its.vertices[face[1]];
auto v2 = volume->mesh().its.vertices[face[2]];
auto dir_0_1 = (v1 - v0).normalized();
auto dir_0_2 = (v2 - v0).normalized();
float sita0 = acos(dir_0_1.dot(dir_0_2));
auto dir_1_0 = -dir_0_1;
auto dir_1_2 = (v2 - v1).normalized();
float sita1 = acos(dir_1_0.dot(dir_1_2));
float sita2 = PI - sita0 - sita1;
std::array<float, 3> sitas = {sita0, sita1, sita2};
float max_sita = sitas[0];
int max_sita_vertex_index = 0;
for (size_t j = 1; j < sitas.size(); j++) {
if (sitas[j] > max_sita) {
max_sita_vertex_index = j;
max_sita = sitas[j];
}
}
if (max_sita_vertex_index == 0) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result1 + result2 + "5" )+ "3"); //"1C0C2C0C1C13"
} else if (max_sita_vertex_index == 1) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result0 + result2 + "9") + "3");
} else{// if (max_sita_vertex_index == 2)
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result2 + (result1 + result0 + "1") + "3");
}
break;
}
case _2_SAME_1_DIFF_COLOR: {
std::string result0, result1, result2;
get_real_filament_id(filament_id0, result0);
get_real_filament_id(filament_id1, result1);
get_real_filament_id(filament_id2, result2);
if (iso_index == 0) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result0 + result1 + result1 + "2");
} else if (iso_index == 1) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result1 + result0 + result0 + "6");
} else if (iso_index == 2) {
volume->mmu_segmentation_facets.set_triangle_from_string(i, result2 + result0 + result0 + "A");
}
break;
}
default: break;
}
}
return true;
}
}
return false;
}
bool Model::obj_import_face_color_deal(const std::vector<unsigned char> &face_filament_ids, const unsigned char &first_extruder_id, Model *model)
{
if (face_filament_ids.size() == 0) { return false; }
// 2.generate mmu_segmentation_facets
if (model->objects.size() == 1) {
auto obj = model->objects[0];
obj->config.set("extruder", first_extruder_id);
if (obj->volumes.size() == 1) {
auto volume = obj->volumes[0];
volume->config.set("extruder", first_extruder_id);
auto face_count = volume->mesh().its.indices.size();
volume->mmu_segmentation_facets.reserve(face_count);
if (volume->mesh().its.indices.size() != face_filament_ids.size()) { return false; }
for (size_t i = 0; i < volume->mesh().its.indices.size(); i++) {
auto face = volume->mesh().its.indices[i];
auto filament_id = face_filament_ids[i];
if (filament_id <= 1) { continue; }
std::string result;
get_real_filament_id(filament_id, result);
volume->mmu_segmentation_facets.set_triangle_from_string(i, result);
}
return true;
}
}
return false;
}
// update the maxSpeed of an object if it is different from the global configuration
double Model::findMaxSpeed(const ModelObject* object) {
auto objectKeys = object->config.keys();
+10 -1
View File
@@ -35,6 +35,7 @@
#include "Format/STEP.hpp"
//BBS: add stl
#include "Format/STL.hpp"
#include "Format/OBJ.hpp"
#include <map>
#include <memory>
@@ -1564,8 +1565,16 @@ public:
DynamicPrintConfig* config = nullptr, ConfigSubstitutionContext* config_substitutions = nullptr,
LoadStrategy options = LoadStrategy::AddDefaultInstances, PlateDataPtrs* plate_data = nullptr,
std::vector<Preset*>* project_presets = nullptr, bool* is_xxx = nullptr, Semver* file_version = nullptr, Import3mfProgressFn proFn = nullptr,
ImportstlProgressFn stlFn = nullptr, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr, int plate_id = 0);
ImportstlProgressFn stlFn = nullptr,
ImportStepProgressFn stepFn = nullptr,
StepIsUtf8Fn stepIsUtf8Fn = nullptr,
BBLProject * project = nullptr,
int plate_id = 0,
ObjImportColorFn objFn = nullptr
);
// BBS
static bool obj_import_vertex_color_deal(const std::vector<unsigned char> &vertex_filament_ids, const unsigned char &first_extruder_id, Model *model);
static bool obj_import_face_color_deal(const std::vector<unsigned char> &face_filament_ids, const unsigned char &first_extruder_id, Model *model);
static double findMaxSpeed(const ModelObject* object);
static double getThermalLength(const ModelVolume* modelVolumePtr);
static double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs);
+191
View File
@@ -0,0 +1,191 @@
#pragma once
#include <iostream>
#include <ctime>
#include "opencv2/opencv.hpp"
class QuantKMeans
{
public:
int m_alpha_thres;
cv::Mat m_flatten_labels;
cv::Mat m_centers8UC3;
QuantKMeans(int alpha_thres = 10) : m_alpha_thres(alpha_thres) {}
void apply(cv::Mat &ori_image, cv::Mat &new_image, int num_cluster, int color_space)
{
cv::Mat image;
convert_color_space(ori_image, image, color_space);
cv::Mat flatten_image = flatten(image);
apply(flatten_image, num_cluster, color_space);
replace_centers(ori_image, new_image);
}
void apply_aplha(cv::Mat &ori_image, cv::Mat &new_image, int num_cluster, int color_space)
{
// cout << " *** DoAlpha *** " << endl;
cv::Mat flatten_image8UC3 = flatten_alpha(ori_image);
cv::Mat image8UC3;
convert_color_space(flatten_image8UC3, image8UC3, color_space);
cv::Mat image32FC3(image8UC3.rows, 1, CV_32FC3);
for (int i = 0; i < image8UC3.rows; i++) image32FC3.at<cv::Vec3f>(i, 0) = image8UC3.at<cv::Vec3b>(i, 0);
apply(image32FC3, num_cluster, color_space);
repalce_centers_aplha(ori_image, new_image);
}
void apply(cv::Mat &flatten_image, int num_cluster, int color_space)
{
cv::Mat centers32FC3;
num_cluster = fmin(flatten_image.rows, num_cluster);
kmeans(flatten_image, num_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS,
centers32FC3);
this->m_centers8UC3 = cv::Mat(num_cluster, 1, CV_8UC3);
for (int i = 0; i < num_cluster; i++) this->m_centers8UC3.at<cv::Vec3b>(i) = centers32FC3.at<cv::Vec3f>(i);
convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true);
}
void apply(const std::vector<std::array<float, 4>> &ori_colors,
std::vector<std::array<float, 4>> & cluster_results,
std::vector<int> & labels,
int num_cluster = -1,
int color_space = 2)
{
// 0~255
cv::Mat flatten_image8UC3 = flatten_vector(ori_colors);
cv::Mat image8UC3;
convert_color_space(flatten_image8UC3, image8UC3, color_space);
cv::Mat image32FC3(image8UC3.rows, 1, CV_32FC3);
for (int i = 0; i < image8UC3.rows; i++)
image32FC3.at<cv::Vec3f>(i, 0) = image8UC3.at<cv::Vec3b>(i, 0);
int best_cluster = 1;
double cur_score, best_score = 100;
int max_cluster = ori_colors.size();
num_cluster = fmin(num_cluster, max_cluster);
if (num_cluster < 1) {
cur_score = kmeans(image32FC3, 1, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS);
best_score = cur_score;
for (int cur_cluster = 2; cur_cluster < 16; cur_cluster++) {
if (cur_cluster > max_cluster)
break;
cur_score = kmeans(image32FC3, cur_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3,
cv::KMEANS_PP_CENTERS);
best_cluster = cur_score < best_score ? cur_cluster : best_cluster;
best_score = cur_score < best_score ? cur_score : best_score;
}
} else
best_cluster = num_cluster;
cv::Mat centers32FC3;
kmeans(image32FC3, best_cluster, this->m_flatten_labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 300, 0.5), 3, cv::KMEANS_PP_CENTERS,
centers32FC3);
this->m_centers8UC3 = cv::Mat(best_cluster, 1, CV_8UC3);
for (int i = 0; i < best_cluster; i++)
this->m_centers8UC3.at<cv::Vec3b>(i) = centers32FC3.at<cv::Vec3f>(i);
convert_color_space(this->m_centers8UC3, this->m_centers8UC3, color_space, true);
cluster_results.clear();
labels.clear();
for (int i = 0; i < ori_colors.size(); i++)
labels.emplace_back(this->m_flatten_labels.at<int>(i, 0));
for (int i = 0; i < best_cluster; i++) {
cv::Vec3f center = this->m_centers8UC3.at<cv::Vec3b>(i, 0);
cluster_results.emplace_back(std::array<float, 4>{center[0] / 255.f, center[1] / 255.f, center[2] / 255.f, 1.f});
}
}
void replace_centers(cv::Mat &ori_image, cv::Mat &new_image)
{
for (int i = 0; i < ori_image.rows; i++) {
for (int j = 0; j < ori_image.cols; j++) {
int idx = this->m_flatten_labels.at<int>(i * ori_image.cols + j, 0);
cv::Vec3b pixel = this->m_centers8UC3.at<cv::Vec3b>(idx);
new_image.at<cv::Vec3b>(i, j) = pixel;
}
}
}
void repalce_centers_aplha(cv::Mat &ori_image, cv::Mat &new_image)
{
int cnt = 0;
int idx;
cv::Vec3b center;
for (int i = 0; i < ori_image.rows; i++) {
for (int j = 0; j < ori_image.cols; j++) {
cv::Vec4b pixel = ori_image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] < this->m_alpha_thres)
new_image.at<cv::Vec4b>(i, j) = pixel;
else {
idx = this->m_flatten_labels.at<int>(cnt++, 0);
center = this->m_centers8UC3.at<cv::Vec3b>(idx);
new_image.at<cv::Vec4b>(i, j) = cv::Vec4b(center[0], center[1], center[2], pixel[3]);
}
}
}
}
void convert_color_space(cv::Mat &ori_image, cv::Mat &image, int color_space, bool reverse = false)
{
switch (color_space) {
case 0: image = ori_image; break;
case 1:
if (reverse)
cvtColor(ori_image, image, cv::COLOR_HSV2BGR);
else
cvtColor(ori_image, image, cv::COLOR_BGR2HSV);
break;
case 2:
if (reverse)
cvtColor(ori_image, image, cv::COLOR_Lab2BGR);
else
cvtColor(ori_image, image, cv::COLOR_BGR2Lab);
break;
default: break;
}
}
cv::Mat flatten(cv::Mat &image)
{
int num_pixels = image.rows * image.cols;
cv::Mat img(num_pixels, 1, CV_32FC3);
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cv::Vec3f pixel = image.at<cv::Vec3b>(i, j);
img.at<cv::Vec3f>(i * image.cols + j, 0) = pixel;
}
}
return img;
}
cv::Mat flatten_alpha(cv::Mat &image)
{
int num_pixels = image.rows * image.cols;
for (int i = 0; i < image.rows; i++)
for (int j = 0; j < image.cols; j++) {
cv::Vec4b pixel = image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] < this->m_alpha_thres) num_pixels--;
}
cv::Mat img(num_pixels, 1, CV_8UC3);
int cnt = 0;
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
cv::Vec4b pixel = image.at<cv::Vec4b>(i, j);
if ((int) pixel[3] >= this->m_alpha_thres) img.at<cv::Vec3b>(cnt++, 0) = cv::Vec3b(pixel[0], pixel[1], pixel[2]);
}
}
return img;
}
cv::Mat flatten_vector(const std::vector<std::array<float, 4>> &ori_colors)
{
int num_pixels = ori_colors.size();
cv::Mat image8UC3(num_pixels, 1, CV_8UC3);
for (int i = 0; i < num_pixels; i++) {
std::array<float, 4> pixel = ori_colors[i];
image8UC3.at<cv::Vec3b>(i, 0) = cv::Vec3b((int) (pixel[0] * 255.f), (int) (pixel[1] * 255.f), (int) (pixel[2] * 255.f));
}
return image8UC3;
}
};
+2
View File
@@ -1138,6 +1138,8 @@ void PresetCollection::load_presets(
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end())
preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM];
if (key_values.find(BBL_JSON_KEY_DESCRIPTION) != key_values.end())
preset.description = key_values[BBL_JSON_KEY_DESCRIPTION];
if (key_values.find("instantiation") != key_values.end())
preset.is_visible = key_values["instantiation"] != "false";
+1
View File
@@ -241,6 +241,7 @@ public:
std::string base_id; // base id of preset
std::string sync_info; // enum: "delete", "create", "update", ""
std::string custom_defined; // enum: "1", "0", ""
std::string description; //
long long updated_time{0}; //last updated time
std::map<std::string, std::string> key_values;
+6 -3
View File
@@ -1964,7 +1964,8 @@ std::set<std::string> PresetBundle::get_printer_names_by_printer_type_and_nozzle
if (printer_it->name.find(nozzle_diameter_str) != std::string::npos) printer_names.insert(printer_it->name);
}
assert(printer_names.size() == 1);
//assert(printer_names.size() == 1);
for (auto& printer_name : printer_names) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " printer name: " << printer_name;
@@ -3463,7 +3464,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
// Load the print, filament or printer preset.
std::string preset_name;
DynamicPrintConfig config;
std::string alias_name, inherits, instantiation, setting_id, filament_id;
std::string alias_name, inherits, description, instantiation, setting_id, filament_id;
std::vector<std::string> renamed_from;
const DynamicPrintConfig* default_config = nullptr;
std::string reason;
@@ -3480,7 +3481,8 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
return reason;
}
preset_name = key_values[BBL_JSON_KEY_NAME];
instantiation = key_values[BBL_JSON_KEY_INSTANTIATION];
description = key_values[BBL_JSON_KEY_DESCRIPTION];
instantiation = key_values[BBL_JSON_KEY_INSTANTIATION];
auto setting_it = key_values.find(BBL_JSON_KEY_SETTING_ID);
if (setting_it != key_values.end())
setting_id = setting_it->second;
@@ -3603,6 +3605,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_
loaded.is_system = true;
loaded.vendor = current_vendor_profile;
loaded.version = current_vendor_profile->config_version;
loaded.description = description;
loaded.setting_id = setting_id;
loaded.filament_id = filament_id;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << loaded.name << " load filament_id: " << filament_id;
+4 -1
View File
@@ -160,7 +160,8 @@ static t_config_enum_values s_keys_map_InfillPattern {
{ "archimedeanchords", ipArchimedeanChords },
{ "octagramspiral", ipOctagramSpiral },
{ "supportcubic", ipSupportCubic },
{ "lightning", ipLightning }
{ "lightning", ipLightning },
{ "crosshatch", ipCrossHatch}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern)
@@ -2049,6 +2050,7 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_values.push_back("octagramspiral");
def->enum_values.push_back("supportcubic");
def->enum_values.push_back("lightning");
def->enum_values.push_back("crosshatch");
def->enum_labels.push_back(L("Concentric"));
def->enum_labels.push_back(L("Rectilinear"));
def->enum_labels.push_back(L("Grid"));
@@ -2066,6 +2068,7 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_labels.push_back(L("Octagram Spiral"));
def->enum_labels.push_back(L("Support Cubic"));
def->enum_labels.push_back(L("Lightning"));
def->enum_labels.push_back(L("Cross Hatch"));
def->set_default_value(new ConfigOptionEnum<InfillPattern>(ipCubic));
auto def_infill_anchor_min = def = this->add("infill_anchor", coFloatOrPercent);
+1 -1
View File
@@ -69,7 +69,7 @@ enum AuthorizationType {
enum InfillPattern : int {
ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb,
ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal,
ipLightning,
ipLightning, ipCrossHatch,
ipCount,
};
+12 -3
View File
@@ -2333,9 +2333,17 @@ void PrintObject::bridge_over_infill()
};
// LAMBDA do determine optimal bridging angle
auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern) {
auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern, double infill_direction) {
AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
// Check it the infill that require a fixed infill angle.
switch (dominant_pattern) {
case ip3DHoneycomb:
case ipCrossHatch:
return (infill_direction + 45.0) * 2.0 * M_PI / 360.;
default: break;
}
std::map<double, int> counted_directions;
for (const Polygon &p : bridged_area) {
double acc_distance = 0;
@@ -2715,11 +2723,12 @@ void PrintObject::bridge_over_infill()
double bridging_angle = 0;
if (!anchors.empty()) {
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors),
candidate.region->region().config().sparse_infill_pattern.value);
candidate.region->region().config().sparse_infill_pattern.value,
candidate.region->region().config().infill_direction.value);
} else {
// use expansion boundaries as anchors.
// Also, use Infill pattern that is neutral for angle determination, since there are no infill lines.
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine);
bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(boundary_plines), InfillPattern::ipLine, 0);
}
boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());