Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9400ddda | ||
|
|
d6408bf239 | ||
|
|
d2012d4d9b | ||
|
|
2b80442677 | ||
|
|
494970573e | ||
|
|
4ee031407d | ||
|
|
f713cb579a | ||
|
|
7f19806dd9 | ||
|
|
f4f63b9a54 | ||
|
|
07b20e3c40 | ||
|
|
535ce1e4d5 | ||
|
|
478a3cabc4 | ||
|
|
40e1a5534e | ||
|
|
019c6dbb10 | ||
|
|
3e70923483 | ||
|
|
d1902fa3d5 | ||
|
|
424a37a68c | ||
|
|
1b2437fa02 | ||
|
|
1687c5d624 | ||
|
|
b1ff57de34 | ||
|
|
bccab56220 | ||
|
|
8ecf30a51d | ||
|
|
cf13b6b6ab | ||
|
|
1c85f23870 | ||
|
|
35c97ae363 | ||
|
|
963e22db99 | ||
|
|
1338e60f8b | ||
|
|
a6c966ffd8 | ||
|
|
2c2e8aaab2 | ||
|
|
65a245af41 | ||
|
|
f2ea046ab5 | ||
|
|
313d89a44f | ||
|
|
5dc99e0fdd | ||
|
|
f2a36c90c1 | ||
|
|
1d73b29a00 | ||
|
|
39bb8169a0 | ||
|
|
205d475acb | ||
|
|
a8371bbded | ||
|
|
261cd7d6e9 | ||
|
|
c4f8a7808a | ||
|
|
a2b2cf743e | ||
|
|
07e2346d8d | ||
|
|
0a6a5f8690 | ||
|
|
51c4567a09 | ||
|
|
0b9b50fa22 | ||
|
|
1cceb727d7 | ||
|
|
49f599efbf | ||
|
|
140ee733ca | ||
|
|
3d89653ad6 | ||
|
|
59aa772875 | ||
|
|
a7ad626cdd | ||
|
|
0886a00cae | ||
|
|
e452f65575 | ||
|
|
a867b747e6 | ||
|
|
8c0ec030e1 | ||
|
|
f39d64153a |
@@ -26,7 +26,6 @@ endif()
|
|||||||
option(SLIC3R_STATIC "Compile QIDISlicer with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL})
|
option(SLIC3R_STATIC "Compile QIDISlicer with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL})
|
||||||
option(SLIC3R_GUI "Compile QIDISlicer with GUI components (OpenGL, wxWidgets)" 1)
|
option(SLIC3R_GUI "Compile QIDISlicer with GUI components (OpenGL, wxWidgets)" 1)
|
||||||
option(SLIC3R_FHS "Assume QIDISlicer is to be installed in a FHS directory structure" 0)
|
option(SLIC3R_FHS "Assume QIDISlicer is to be installed in a FHS directory structure" 0)
|
||||||
option(SLIC3R_WX_STABLE "Build against wxWidgets stable (3.0) as oppsed to dev (3.1) on Linux" 0)
|
|
||||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||||
@@ -60,7 +59,6 @@ if (APPLE)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Proposal for C++ unit tests and sandboxes
|
|
||||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||||
option(SLIC3R_BUILD_TESTS "Build unit tests" ON)
|
option(SLIC3R_BUILD_TESTS "Build unit tests" ON)
|
||||||
|
|
||||||
@@ -172,8 +170,8 @@ if(WIN32)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(DEFINED WIN10SDK_PATH)
|
if(DEFINED WIN10SDK_PATH)
|
||||||
if (EXISTS "${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h")
|
if (EXISTS "${WIN10SDK_PATH}/winrt/windows.graphics.printing3d.h")
|
||||||
set(WIN10SDK_INCLUDE_PATH "${WIN10SDK_PATH}/Include")
|
set(WIN10SDK_INCLUDE_PATH "${WIN10SDK_PATH}")
|
||||||
else()
|
else()
|
||||||
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
message("WIN10SDK_PATH is invalid: ${WIN10SDK_PATH}")
|
||||||
message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
|
message("${WIN10SDK_PATH}/include/winrt/windows.graphics.printing3d.h was not found")
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
1.0.2
|
1.0.5
|
||||||
alpha=1.0.2-alpha1
|
alpha=1.0.5-alpha1
|
||||||
beta=1.0.2-beta1
|
beta=1.0.5-beta1
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
release = 1.0.2
|
release = 1.0.5
|
||||||
alpha = 1.0.2-alpha1
|
alpha = 1.0.5-alpha1
|
||||||
beta = 1.0.2-beta1
|
beta = 1.0.5-beta1
|
||||||
rc = 1.0.2-rc2
|
rc = 1.0.5-rc2
|
||||||
|
|
||||||
[release:win64]
|
[release:win64]
|
||||||
url = https://github.com/QIDITECH/QIDISlicer/releases/download/V1.0.2/QIDISlicer_Setup_1.0.2.exe
|
url = https://github.com/QIDITECH/QIDISlicer/releases/download/V1.0.5/QIDISlicer_Setup_1.0.5_Win64.exe
|
||||||
size = 71118761
|
size = 71118761
|
||||||
|
|
||||||
[release:linux]
|
[release:linux]
|
||||||
url = https://qidi3d.com
|
url = https://github.com/QIDITECH/QIDISlicer/releases/download/V1.0.4/QIDISlicer-1.0.4.AppImage
|
||||||
size = 69915840
|
size = 69915840
|
||||||
|
|
||||||
[release:osx]
|
[release:osx]
|
||||||
url = https://qidi3d.com/
|
url = https://github.com/QIDITECH/QIDISlicer/releases/download/V1.0.5/QIDISlicer_Setup_1.0.5_Win64.exe
|
||||||
size = 90237989
|
size = 90237989
|
||||||
@@ -7,7 +7,7 @@ QIDISlicer is a professional 3D printer slicing software,which is perfectly co
|
|||||||
**Notice:QIDISlicer as a new software dedicated to QIDI's new high speed printers, please make sure your firmware version is V 4.0.0 or above.**
|
**Notice:QIDISlicer as a new software dedicated to QIDI's new high speed printers, please make sure your firmware version is V 4.0.0 or above.**
|
||||||
|
|
||||||
QIDISlicer is based on [PrusaSlicer](https://github.com/prusa3d/PrusaSlicer) by Prusa Research, which is from [Slic3r](https://github.com/Slic3r/Slic3r) by Alessandro Ranellucci and the RepRap community.
|
QIDISlicer is based on [PrusaSlicer](https://github.com/prusa3d/PrusaSlicer) by Prusa Research, which is from [Slic3r](https://github.com/Slic3r/Slic3r) by Alessandro Ranellucci and the RepRap community.
|
||||||
Thanks to PrusaSlicer and Bambulab for their contributions to the 3D printing community.
|
Thanks to PrusaSlicer, Bambulab and OrcaSlicer for their contributions to the 3D printing community.
|
||||||
|
|
||||||
See the [QIDI's homepage](https://qidi3d.com) for more information.
|
See the [QIDI's homepage](https://qidi3d.com) for more information.
|
||||||
|
|
||||||
|
|||||||
1214
cmake/modules/FindwxWidgets.cmake
Normal file
BIN
resources/calib/FlowRate/flowrate_coarse.3mf
Normal file
BIN
resources/calib/FlowRate/flowrate_fine.3mf
Normal file
BIN
resources/calib/PressureAdvance/pa_line.stl
Normal file
BIN
resources/calib/PressureAdvance/pa_pattern.stl
Normal file
3026
resources/calib/PressureAdvance/pa_tower.stl
Normal file
36075
resources/calib/VolumetricSpeed/volumetric_speed.step
Normal file
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
4
resources/icons/check_half.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#009688"/>
|
||||||
|
<path d="M4 9L14 9" stroke="white" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 228 B |
4
resources/icons/check_half_disabled.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#CECECE"/>
|
||||||
|
<line x1="4.37881" y1="8.93516" x2="13.6213" y2="8.93515" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 285 B |
4
resources/icons/check_half_focused.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#4db6ac"/>
|
||||||
|
<path d="M4 9L14 9" stroke="white" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 232 B |
3
resources/icons/check_off.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" stroke="#ACACAC"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 176 B |
3
resources/icons/check_off_disabled.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" fill="#CECECE" stroke="#ACACAC"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 191 B |
3
resources/icons/check_off_focused.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" stroke="#009688"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 176 B |
4
resources/icons/check_on.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#009688"/>
|
||||||
|
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/check_on_disabled.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#CECECE"/>
|
||||||
|
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/check_on_focused.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="1" y="1" width="16" height="16" rx="1" fill="#4db6ac"/>
|
||||||
|
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/checked.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3 8.9375L6.45062 11.6772C6.67263 11.8535 6.99663 11.8101 7.16447 11.5817L12 5" stroke="white" stroke-linecap="round"/>
|
||||||
|
<path d="M3 8.9375L6.45062 11.6772C6.67263 11.8535 6.99663 11.8101 7.16447 11.5817L12 5" stroke="white" stroke-opacity="0.2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 382 B |
7
resources/icons/snap.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
|
<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="m1.5,11.5V3.5c0-1.104569435119629.895430564880371-2,2-2h9c1.104569435119629,0,2,.895430564880371,2,2v8" />
|
||||||
|
<line x1="1.5" y1="14.5" x2="14.5" y2="14.5" style="fill:none; stroke:#ed6b21; stroke-linecap:round; stroke-miterlimit:10;"/>
|
||||||
|
<path d="m7,15h-3V5.237499999999272c0-.683452377914364.447715250171314-1.237499999999272,1-1.237499999999272h2v11Z" style="fill:#ed6b21; stroke-width:0px;"/>
|
||||||
|
<path d="m9,15h3V5.237499999999272c0-.683452377914364-.447715250171314-1.237499999999272-1-1.237499999999272h-2v11Z" style="fill:#ed6b21; stroke-width:0px;"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 755 B |
@@ -1,3 +1,5 @@
|
|||||||
|
min_slic3r_version = 1.0.5
|
||||||
|
1.0.5 Optimize parameters
|
||||||
min_slic3r_version = 1.0.4
|
min_slic3r_version = 1.0.4
|
||||||
1.0.4 Modify start code
|
1.0.4 Modify start code
|
||||||
min_slic3r_version = 1.0.3
|
min_slic3r_version = 1.0.3
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
# Vendor name will be shown by the Config Wizard.
|
# Vendor name will be shown by the Config Wizard.
|
||||||
name = QIDI Technology
|
name = QIDI Technology
|
||||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
# This means, the server may force the QIDISlicer configuration to be downgraded.
|
||||||
config_version = 1.0.4
|
config_version = 1.0.6
|
||||||
# Where to get the updates from?
|
# Where to get the updates from?
|
||||||
config_update_url = https://github.com/QIDITECH/QIDISlicer/releases/download/QIDITechnology/
|
config_update_url = https://github.com/QIDITECH/QIDISlicer/releases/download/QIDITechnology/
|
||||||
changelog_url = https://qidi3d.com/pages/software-firmware
|
changelog_url = https://qidi3d.com/pages/software-firmware
|
||||||
@@ -21,7 +21,7 @@ technology = FFF
|
|||||||
family = X
|
family = X
|
||||||
bed_model = X-MAX 3_bed.stl
|
bed_model = X-MAX 3_bed.stl
|
||||||
bed_texture = X-MAX 3.svg
|
bed_texture = X-MAX 3.svg
|
||||||
default_materials = QIDI ABS Rapido @X-MAX 3; QIDI PLA Rapido @X-MAX 3; QIDI PLA Rapido Matte @X-MAX 3; QIDI ToughPETG @X-MAX 3; Generic ABS @X-MAX 3; Generic PETG @X-MAX 3; Generic PLA @X-MAX 3
|
default_materials = QIDI ABS Odorless @X-MAX 3; QIDI ABS Rapido @X-MAX 3; QIDI ASA @X-MAX 3; QIDI PLA Rapido @X-MAX 3; QIDI PLA Rapido Matte @X-MAX 3; QIDI ToughPETG @X-MAX 3; Generic ABS @X-MAX 3; Generic PETG @X-MAX 3; Generic PLA @X-MAX 3
|
||||||
|
|
||||||
[printer_model:X-Plus 3]
|
[printer_model:X-Plus 3]
|
||||||
name = X-Plus 3
|
name = X-Plus 3
|
||||||
@@ -30,7 +30,7 @@ technology = FFF
|
|||||||
family = X
|
family = X
|
||||||
bed_model = X-Plus 3_bed.stl
|
bed_model = X-Plus 3_bed.stl
|
||||||
bed_texture = X-Plus 3.svg
|
bed_texture = X-Plus 3.svg
|
||||||
default_materials = QIDI ABS Rapido @X-Plus 3; QIDI PLA Rapido @X-Plus 3; QIDI PLA Rapido Matte @X-Plus 3; QIDI ToughPETG @X-Plus 3; Generic ABS @X-Plus 3; Generic PETG @X-Plus 3; Generic PLA @X-Plus 3
|
default_materials = QIDI ABS Odorless @X-Plus 3; QIDI ABS Rapido @X-Plus 3; QIDI ASA @X-Plus 3; QIDI PLA Rapido @X-Plus 3; QIDI PLA Rapido Matte @X-Plus 3; QIDI ToughPETG @X-Plus 3; Generic ABS @X-Plus 3; Generic PETG @X-Plus 3; Generic PLA @X-Plus 3
|
||||||
|
|
||||||
[printer_model:X-smart 3]
|
[printer_model:X-smart 3]
|
||||||
name = X-smart 3
|
name = X-smart 3
|
||||||
@@ -39,7 +39,7 @@ technology = FFF
|
|||||||
family = X
|
family = X
|
||||||
bed_model = X-smart 3_bed.stl
|
bed_model = X-smart 3_bed.stl
|
||||||
bed_texture = X-smart 3.svg
|
bed_texture = X-smart 3.svg
|
||||||
default_materials = QIDI ABS Rapido @X-smart 3; QIDI PLA Rapido @X-smart 3; QIDI PLA Rapido Matte @X-smart 3; QIDI ToughPETG @X-smart 3; Generic ABS @X-smart 3; Generic PETG @X-smart 3; Generic PLA @X-smart 3
|
default_materials = QIDI ABS Odorless @X-smart 3;QIDI ABS Rapido @X-smart 3; QIDI ASA @X-smart 3; QIDI PLA Rapido @X-smart 3; QIDI PLA Rapido Matte @X-smart 3; QIDI ToughPETG @X-smart 3; Generic ABS @X-smart 3; Generic PETG @X-smart 3; Generic PLA @X-smart 3
|
||||||
|
|
||||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||||
# not make it into the user interface.
|
# not make it into the user interface.
|
||||||
@@ -83,15 +83,17 @@ first_layer_acceleration = 500
|
|||||||
first_layer_acceleration_over_raft = 500
|
first_layer_acceleration_over_raft = 500
|
||||||
first_layer_extrusion_width = 0.5
|
first_layer_extrusion_width = 0.5
|
||||||
first_layer_height = 0.2
|
first_layer_height = 0.2
|
||||||
first_layer_speed = 55
|
first_layer_infill_speed = 100
|
||||||
|
first_layer_speed = 50
|
||||||
first_layer_speed_over_raft = 30
|
first_layer_speed_over_raft = 30
|
||||||
|
first_layer_travel_speed = 300
|
||||||
fuzzy_skin = none
|
fuzzy_skin = none
|
||||||
fuzzy_skin_point_dist = 0.8
|
fuzzy_skin_point_dist = 0.8
|
||||||
fuzzy_skin_thickness = 0.3
|
fuzzy_skin_thickness = 0.3
|
||||||
gap_fill_enabled = 0
|
gap_fill_enabled = 0
|
||||||
gap_fill_speed = 250
|
gap_fill_speed = 250
|
||||||
gcode_comments = 0
|
gcode_comments = 0
|
||||||
gcode_label_objects = 0
|
gcode_label_objects = 1
|
||||||
gcode_resolution = 0.0125
|
gcode_resolution = 0.0125
|
||||||
gcode_substitutions =
|
gcode_substitutions =
|
||||||
infill_acceleration = 0
|
infill_acceleration = 0
|
||||||
@@ -192,8 +194,8 @@ support_tree_branch_diameter_double_wall = 3
|
|||||||
support_tree_branch_distance = 1
|
support_tree_branch_distance = 1
|
||||||
support_tree_tip_diameter = 0.8
|
support_tree_tip_diameter = 0.8
|
||||||
support_tree_top_rate = 15%
|
support_tree_top_rate = 15%
|
||||||
thick_bridges = 1
|
thick_bridges = 0
|
||||||
thin_walls = 1
|
thin_walls = 0
|
||||||
threads = 12
|
threads = 12
|
||||||
top_fill_pattern = monotoniclines
|
top_fill_pattern = monotoniclines
|
||||||
top_infill_extrusion_width = 0
|
top_infill_extrusion_width = 0
|
||||||
@@ -263,7 +265,7 @@ solid_infill_speed = 230
|
|||||||
# Common filament preset
|
# Common filament preset
|
||||||
[filament:*common*]
|
[filament:*common*]
|
||||||
advance_pressure = 0.031
|
advance_pressure = 0.031
|
||||||
bed_temperature = 60
|
bed_temperature = 55
|
||||||
bridge_fan_speed = 100
|
bridge_fan_speed = 100
|
||||||
compatible_printers =
|
compatible_printers =
|
||||||
compatible_printers_condition =
|
compatible_printers_condition =
|
||||||
@@ -271,6 +273,7 @@ compatible_prints =
|
|||||||
compatible_prints_condition =
|
compatible_prints_condition =
|
||||||
cooling = 1
|
cooling = 1
|
||||||
disable_fan_first_layers = 1
|
disable_fan_first_layers = 1
|
||||||
|
disable_rapid_cooling_fan_first_layers = 3
|
||||||
enable_advance_pressure = 1
|
enable_advance_pressure = 1
|
||||||
enable_auxiliary_fan = 100
|
enable_auxiliary_fan = 100
|
||||||
enable_dynamic_fan_speeds = 0
|
enable_dynamic_fan_speeds = 0
|
||||||
@@ -303,7 +306,7 @@ filament_retract_lift_above = nil
|
|||||||
filament_retract_lift_below = nil
|
filament_retract_lift_below = nil
|
||||||
filament_retract_restart_extra = nil
|
filament_retract_restart_extra = nil
|
||||||
filament_retract_speed = nil
|
filament_retract_speed = nil
|
||||||
filament_settings_id = PrusaSlicer_cf_pro.ini
|
filament_settings_id =
|
||||||
filament_soluble = 0
|
filament_soluble = 0
|
||||||
filament_spool_weight = 0
|
filament_spool_weight = 0
|
||||||
filament_toolchange_delay = 0
|
filament_toolchange_delay = 0
|
||||||
@@ -313,7 +316,7 @@ filament_unloading_speed = 90
|
|||||||
filament_unloading_speed_start = 100
|
filament_unloading_speed_start = 100
|
||||||
filament_vendor = QIDI
|
filament_vendor = QIDI
|
||||||
filament_wipe = nil
|
filament_wipe = nil
|
||||||
first_layer_bed_temperature = 60
|
first_layer_bed_temperature = 55
|
||||||
first_layer_temperature = 210
|
first_layer_temperature = 210
|
||||||
first_layer_volume_temperature = 0
|
first_layer_volume_temperature = 0
|
||||||
full_fan_speed_layer = 0
|
full_fan_speed_layer = 0
|
||||||
@@ -328,26 +331,60 @@ overhang_fan_speed_2 = 0
|
|||||||
overhang_fan_speed_3 = 0
|
overhang_fan_speed_3 = 0
|
||||||
slowdown_below_layer_time = 5
|
slowdown_below_layer_time = 5
|
||||||
smooth_time = 0.03
|
smooth_time = 0.03
|
||||||
start_filament_gcode = "; Filament gcode\n"
|
start_filament_gcode = "; Filament gcode\n{if (enable_advance_pressure[0] == true)}M900{else};M900{endif} K[advance_pressure] T[smooth_time]\n"
|
||||||
temperature = 220
|
temperature = 220
|
||||||
volume_temperature = 0
|
volume_temperature = 0
|
||||||
|
|
||||||
# QIDI filament preset
|
# QIDI filament preset
|
||||||
|
[filament:*QIDI ABS Odorless*]
|
||||||
|
inherits = *common*
|
||||||
|
advance_pressure = 0.021
|
||||||
|
bed_temperature = 90
|
||||||
|
disable_fan_first_layers = 3
|
||||||
|
enable_auxiliary_fan = 0
|
||||||
|
enable_dynamic_fan_speeds = 1
|
||||||
|
enable_volume_fan = 40
|
||||||
|
extrusion_multiplier = 0.92
|
||||||
|
fan_below_layer_time = 30
|
||||||
|
filament_colour = #FFFACD
|
||||||
|
filament_density = 1.02
|
||||||
|
filament_max_volumetric_speed = 22
|
||||||
|
filament_type = ABS
|
||||||
|
first_layer_bed_temperature = 90
|
||||||
|
first_layer_temperature = 250
|
||||||
|
max_fan_speed = 50
|
||||||
|
min_fan_speed = 10
|
||||||
|
overhang_fan_speed_0 = 100
|
||||||
|
overhang_fan_speed_1 = 90
|
||||||
|
overhang_fan_speed_2 = 80
|
||||||
|
overhang_fan_speed_3 = 80
|
||||||
|
slowdown_below_layer_time = 4
|
||||||
|
temperature = 270
|
||||||
|
volume_temperature = 55
|
||||||
|
|
||||||
[filament:*QIDI ABS Rapido*]
|
[filament:*QIDI ABS Rapido*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.021
|
advance_pressure = 0.021
|
||||||
bed_temperature = 100
|
bed_temperature = 90
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
|
enable_dynamic_fan_speeds = 1
|
||||||
enable_volume_fan = 40
|
enable_volume_fan = 40
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
|
fan_below_layer_time = 30
|
||||||
filament_colour = #FFC800
|
filament_colour = #FFC800
|
||||||
filament_density = 1.02
|
filament_density = 1.02
|
||||||
filament_max_volumetric_speed = 22
|
filament_max_volumetric_speed = 22
|
||||||
filament_type = ABS
|
filament_type = ABS
|
||||||
first_layer_bed_temperature = 100
|
first_layer_bed_temperature = 90
|
||||||
first_layer_temperature = 240
|
first_layer_temperature = 250
|
||||||
max_fan_speed = 60
|
max_fan_speed = 80
|
||||||
min_fan_speed = 60
|
min_fan_speed = 10
|
||||||
|
overhang_fan_speed_0 = 100
|
||||||
|
overhang_fan_speed_1 = 90
|
||||||
|
overhang_fan_speed_2 = 80
|
||||||
|
overhang_fan_speed_3 = 80
|
||||||
|
slowdown_below_layer_time = 4
|
||||||
temperature = 270
|
temperature = 270
|
||||||
volume_temperature = 55
|
volume_temperature = 55
|
||||||
|
|
||||||
@@ -356,6 +393,7 @@ inherits = *common*
|
|||||||
advance_pressure = 0.01
|
advance_pressure = 0.01
|
||||||
bed_temperature = 100
|
bed_temperature = 100
|
||||||
bridge_fan_speed = 0
|
bridge_fan_speed = 0
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
enable_volume_fan = 0
|
enable_volume_fan = 0
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
@@ -370,72 +408,117 @@ min_fan_speed = 20
|
|||||||
temperature = 270
|
temperature = 270
|
||||||
volume_temperature = 55
|
volume_temperature = 55
|
||||||
|
|
||||||
|
# QIDI filament preset
|
||||||
|
[filament:*QIDI ASA*]
|
||||||
|
inherits = *common*
|
||||||
|
advance_pressure = 0.021
|
||||||
|
bed_temperature = 90
|
||||||
|
disable_fan_first_layers = 3
|
||||||
|
enable_auxiliary_fan = 0
|
||||||
|
enable_dynamic_fan_speeds = 1
|
||||||
|
enable_volume_fan = 40
|
||||||
|
extrusion_multiplier = 0.92
|
||||||
|
fan_below_layer_time = 35
|
||||||
|
filament_colour = #F0E68C
|
||||||
|
filament_density = 1.02
|
||||||
|
filament_max_volumetric_speed = 16
|
||||||
|
filament_type = ABS
|
||||||
|
first_layer_bed_temperature = 90
|
||||||
|
first_layer_temperature = 250
|
||||||
|
max_fan_speed = 50
|
||||||
|
min_fan_speed = 10
|
||||||
|
overhang_fan_speed_0 = 100
|
||||||
|
overhang_fan_speed_1 = 80
|
||||||
|
overhang_fan_speed_2 = 60
|
||||||
|
overhang_fan_speed_3 = 40
|
||||||
|
slowdown_below_layer_time = 4
|
||||||
|
temperature = 270
|
||||||
|
volume_temperature = 55
|
||||||
|
|
||||||
[filament:*QIDI PA12-CF*]
|
[filament:*QIDI PA12-CF*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.01
|
advance_pressure = 0.01
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
bridge_fan_speed = 0
|
bridge_fan_speed = 40
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 0.96
|
extrusion_multiplier = 0.96
|
||||||
|
fan_below_layer_time = 5
|
||||||
filament_colour = #696969
|
filament_colour = #696969
|
||||||
filament_density = 1.09
|
filament_density = 1.09
|
||||||
filament_max_volumetric_speed = 14
|
filament_max_volumetric_speed = 14
|
||||||
filament_type = PA12-CF
|
filament_type = PA12-CF
|
||||||
first_layer_bed_temperature = 80
|
first_layer_bed_temperature = 80
|
||||||
first_layer_temperature = 290
|
first_layer_temperature = 290
|
||||||
max_fan_speed = 15
|
max_fan_speed = 30
|
||||||
min_fan_speed = 15
|
min_fan_speed = 10
|
||||||
|
slowdown_below_layer_time = 2
|
||||||
temperature = 290
|
temperature = 290
|
||||||
|
|
||||||
[filament:*QIDI PAHT-CF*]
|
[filament:*QIDI PAHT-CF*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.01
|
advance_pressure = 0.01
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
bridge_fan_speed = 0
|
bridge_fan_speed = 40
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 0.96
|
extrusion_multiplier = 0.96
|
||||||
|
fan_below_layer_time = 5
|
||||||
filament_colour = #4F4F4F
|
filament_colour = #4F4F4F
|
||||||
filament_density = 1.20
|
filament_density = 1.20
|
||||||
filament_max_volumetric_speed = 15
|
filament_max_volumetric_speed = 15
|
||||||
filament_type = PAHT-CF
|
filament_type = PAHT-CF
|
||||||
first_layer_bed_temperature = 80
|
first_layer_bed_temperature = 80
|
||||||
first_layer_temperature = 310
|
first_layer_temperature = 310
|
||||||
max_fan_speed = 15
|
max_fan_speed = 30
|
||||||
min_fan_speed = 15
|
min_fan_speed = 10
|
||||||
|
slowdown_below_layer_time = 2
|
||||||
temperature = 310
|
temperature = 310
|
||||||
|
|
||||||
[filament:*QIDI PET-CF*]
|
[filament:*QIDI PET-CF*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.01
|
advance_pressure = 0.01
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
bridge_fan_speed = 5
|
bridge_fan_speed = 40
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 1
|
extrusion_multiplier = 1
|
||||||
|
fan_below_layer_time = 5
|
||||||
filament_colour = #323232
|
filament_colour = #323232
|
||||||
filament_density = 1.30
|
filament_density = 1.30
|
||||||
filament_max_volumetric_speed = 14
|
filament_max_volumetric_speed = 14
|
||||||
filament_type = PET-CF
|
filament_type = PET-CF
|
||||||
first_layer_bed_temperature = 80
|
first_layer_bed_temperature = 80
|
||||||
first_layer_temperature = 320
|
first_layer_temperature = 320
|
||||||
max_fan_speed = 10
|
max_fan_speed = 30
|
||||||
min_fan_speed = 10
|
min_fan_speed = 10
|
||||||
|
slowdown_below_layer_time = 2
|
||||||
temperature = 320
|
temperature = 320
|
||||||
|
|
||||||
[filament:*QIDI PETG-Tough*]
|
[filament:*QIDI PETG-Tough*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.07
|
advance_pressure = 0.07
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
bridge_fan_speed = 60
|
bridge_fan_speed = 90
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
|
enable_dynamic_fan_speeds = 1
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
|
fan_below_layer_time = 30
|
||||||
filament_colour = #00FF40
|
filament_colour = #00FF40
|
||||||
filament_density = 1.24
|
filament_density = 1.24
|
||||||
filament_max_volumetric_speed = 16
|
filament_max_volumetric_speed = 16
|
||||||
filament_type = PETG
|
filament_type = PETG
|
||||||
first_layer_bed_temperature = 80
|
first_layer_bed_temperature = 80
|
||||||
first_layer_temperature = 240
|
first_layer_temperature = 240
|
||||||
max_fan_speed = 60
|
max_fan_speed = 40
|
||||||
min_fan_speed = 60
|
min_fan_speed = 10
|
||||||
|
min_print_speed = 10
|
||||||
|
overhang_fan_speed_0 = 90
|
||||||
|
overhang_fan_speed_1 = 70
|
||||||
|
overhang_fan_speed_2 = 50
|
||||||
|
overhang_fan_speed_3 = 40
|
||||||
|
slowdown_below_layer_time = 8
|
||||||
temperature = 250
|
temperature = 250
|
||||||
|
|
||||||
[filament:*QIDI PLA Rapido*]
|
[filament:*QIDI PLA Rapido*]
|
||||||
@@ -451,7 +534,7 @@ filament_max_volumetric_speed = 22
|
|||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.03
|
advance_pressure = 0.03
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
bridge_fan_speed = 0
|
bridge_fan_speed = 20
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 0.96
|
extrusion_multiplier = 0.96
|
||||||
filament_colour = #FFEBCD
|
filament_colour = #FFEBCD
|
||||||
@@ -468,27 +551,37 @@ temperature = 300
|
|||||||
[filament:*Generic ABS*]
|
[filament:*Generic ABS*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.021
|
advance_pressure = 0.021
|
||||||
bed_temperature = 100
|
bed_temperature = 90
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
|
enable_dynamic_fan_speeds = 1
|
||||||
enable_volume_fan = 40
|
enable_volume_fan = 40
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
|
fan_below_layer_time = 30
|
||||||
filament_colour = #FFFF00
|
filament_colour = #FFFF00
|
||||||
filament_density = 1.04
|
filament_density = 1.04
|
||||||
filament_max_volumetric_speed = 17.5
|
filament_max_volumetric_speed = 17
|
||||||
filament_type = ABS
|
filament_type = ABS
|
||||||
filament_vendor = Generic
|
filament_vendor = Generic
|
||||||
first_layer_bed_temperature = 100
|
first_layer_bed_temperature = 90
|
||||||
first_layer_temperature = 240
|
first_layer_temperature = 250
|
||||||
max_fan_speed = 60
|
max_fan_speed = 80
|
||||||
min_fan_speed = 60
|
min_fan_speed = 10
|
||||||
|
overhang_fan_speed_0 = 100
|
||||||
|
overhang_fan_speed_1 = 90
|
||||||
|
overhang_fan_speed_2 = 80
|
||||||
|
overhang_fan_speed_3 = 80
|
||||||
|
slowdown_below_layer_time = 4
|
||||||
temperature = 260
|
temperature = 260
|
||||||
|
|
||||||
[filament:*Generic PETG*]
|
[filament:*Generic PETG*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.07
|
advance_pressure = 0.07
|
||||||
bed_temperature = 80
|
bed_temperature = 80
|
||||||
|
disable_fan_first_layers = 3
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
|
fan_below_layer_time = 30
|
||||||
filament_colour = #00FF00
|
filament_colour = #00FF00
|
||||||
filament_density = 1.27
|
filament_density = 1.27
|
||||||
filament_max_volumetric_speed = 9
|
filament_max_volumetric_speed = 9
|
||||||
@@ -496,20 +589,23 @@ filament_type = PETG
|
|||||||
filament_vendor = Generic
|
filament_vendor = Generic
|
||||||
first_layer_bed_temperature = 80
|
first_layer_bed_temperature = 80
|
||||||
first_layer_temperature = 240
|
first_layer_temperature = 240
|
||||||
max_fan_speed = 60
|
max_fan_speed = 90
|
||||||
min_fan_speed = 60
|
min_fan_speed = 40
|
||||||
|
min_print_speed = 10
|
||||||
|
slowdown_below_layer_time = 4
|
||||||
temperature = 250
|
temperature = 250
|
||||||
|
|
||||||
[filament:*Generic PLA*]
|
[filament:*Generic PLA*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
filament_colour = #0000FF
|
filament_colour = #0000FF
|
||||||
filament_density = 1.20
|
filament_density = 1.20
|
||||||
filament_max_volumetric_speed = 17
|
filament_max_volumetric_speed = 14
|
||||||
filament_vendor = Generic
|
filament_vendor = Generic
|
||||||
|
|
||||||
[filament:*Generic TPU 95A*]
|
[filament:*Generic TPU 95A*]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
advance_pressure = 0.1
|
advance_pressure = 0.1
|
||||||
|
enable_auxiliary_fan = 0
|
||||||
extrusion_multiplier = 1
|
extrusion_multiplier = 1
|
||||||
filament_colour = #8000FF
|
filament_colour = #8000FF
|
||||||
filament_density = 1.21
|
filament_density = 1.21
|
||||||
@@ -517,9 +613,15 @@ filament_max_volumetric_speed = 6
|
|||||||
filament_type = TPU
|
filament_type = TPU
|
||||||
filament_vendor = Generic
|
filament_vendor = Generic
|
||||||
first_layer_temperature = 230
|
first_layer_temperature = 230
|
||||||
|
min_print_speed = 10
|
||||||
|
slowdown_below_layer_time = 8
|
||||||
temperature = 230
|
temperature = 230
|
||||||
|
|
||||||
# X-MAX 3 QIDI filament preset
|
# X-MAX 3 QIDI filament preset
|
||||||
|
[filament:QIDI ABS Odorless @X-MAX 3]
|
||||||
|
inherits = *QIDI ABS Odorless*
|
||||||
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
[filament:QIDI ABS Rapido @X-MAX 3]
|
[filament:QIDI ABS Rapido @X-MAX 3]
|
||||||
inherits = *QIDI ABS Rapido*
|
inherits = *QIDI ABS Rapido*
|
||||||
compatible_printers_condition = printer_model=="X-MAX 3"
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
@@ -528,11 +630,15 @@ compatible_printers_condition = printer_model=="X-MAX 3"
|
|||||||
inherits = *QIDI ABS-GF*
|
inherits = *QIDI ABS-GF*
|
||||||
compatible_printers_condition = printer_model=="X-MAX 3"
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
|
[filament:QIDI ASA @X-MAX 3]
|
||||||
|
inherits = *QIDI ASA*
|
||||||
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
[filament:QIDI PA12-CF @X-MAX 3]
|
[filament:QIDI PA12-CF @X-MAX 3]
|
||||||
inherits = *QIDI PA12-CF*
|
inherits = *QIDI PA12-CF*
|
||||||
compatible_printers_condition = printer_model=="X-MAX 3"
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
[filament:QIDI PAHT-CF @X-Plus3]
|
[filament:QIDI PAHT-CF @X-MAX 3]
|
||||||
inherits = *QIDI PAHT-CF*
|
inherits = *QIDI PAHT-CF*
|
||||||
compatible_printers_condition = printer_model=="X-MAX 3"
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
@@ -574,6 +680,10 @@ inherits = *Generic TPU 95A*
|
|||||||
compatible_printers_condition = printer_model=="X-MAX 3"
|
compatible_printers_condition = printer_model=="X-MAX 3"
|
||||||
|
|
||||||
# X-Plus 3 QIDI filament preset
|
# X-Plus 3 QIDI filament preset
|
||||||
|
[filament:QIDI ABS Odorless @X-Plus 3]
|
||||||
|
inherits = *QIDI ABS Odorless*
|
||||||
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
|
|
||||||
[filament:QIDI ABS Rapido @X-Plus 3]
|
[filament:QIDI ABS Rapido @X-Plus 3]
|
||||||
inherits = *QIDI ABS Rapido*
|
inherits = *QIDI ABS Rapido*
|
||||||
compatible_printers_condition = printer_model=="X-Plus 3"
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
@@ -582,6 +692,10 @@ compatible_printers_condition = printer_model=="X-Plus 3"
|
|||||||
inherits = *QIDI ABS-GF*
|
inherits = *QIDI ABS-GF*
|
||||||
compatible_printers_condition = printer_model=="X-Plus 3"
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
|
|
||||||
|
[filament:QIDI ASA @X-Plus 3]
|
||||||
|
inherits = *QIDI ASA*
|
||||||
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
|
|
||||||
[filament:QIDI PA12-CF @X-Plus 3]
|
[filament:QIDI PA12-CF @X-Plus 3]
|
||||||
inherits = *QIDI PA12-CF*
|
inherits = *QIDI PA12-CF*
|
||||||
compatible_printers_condition = printer_model=="X-Plus 3"
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
@@ -628,6 +742,13 @@ inherits = *Generic TPU 95A*
|
|||||||
compatible_printers_condition = printer_model=="X-Plus 3"
|
compatible_printers_condition = printer_model=="X-Plus 3"
|
||||||
|
|
||||||
# X-smart 3 QIDI filament preset
|
# X-smart 3 QIDI filament preset
|
||||||
|
[filament:QIDI ABS Odorless @X-smart 3]
|
||||||
|
inherits = *QIDI ABS Odorless*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
advance_pressure = 0.024
|
||||||
|
filament_max_volumetric_speed = 20
|
||||||
|
volume_temperature = 0
|
||||||
|
|
||||||
[filament:QIDI ABS Rapido @X-smart 3]
|
[filament:QIDI ABS Rapido @X-smart 3]
|
||||||
inherits = *QIDI ABS Rapido*
|
inherits = *QIDI ABS Rapido*
|
||||||
compatible_printers_condition = printer_model=="X-smart 3"
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
@@ -635,6 +756,30 @@ advance_pressure = 0.024
|
|||||||
filament_max_volumetric_speed = 20
|
filament_max_volumetric_speed = 20
|
||||||
volume_temperature = 0
|
volume_temperature = 0
|
||||||
|
|
||||||
|
[filament:QIDI ABS-GF @X-smart 3]
|
||||||
|
inherits = *QIDI ABS-GF*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
volume_temperature = 0
|
||||||
|
|
||||||
|
[filament:QIDI ASA @X-smart 3]
|
||||||
|
inherits = *QIDI ASA*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
advance_pressure = 0.024
|
||||||
|
filament_max_volumetric_speed = 20
|
||||||
|
volume_temperature = 0
|
||||||
|
|
||||||
|
[filament:QIDI PA12-CF @X-smart 3]
|
||||||
|
inherits = *QIDI PA12-CF*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
|
||||||
|
[filament:QIDI PAHT-CF @X-smart 3]
|
||||||
|
inherits = *QIDI PAHT-CF*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
|
||||||
|
[filament:QIDI PET-CF @X-smart 3]
|
||||||
|
inherits = *QIDI PET-CF*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
|
||||||
[filament:QIDI PETG-Tough @X-smart 3]
|
[filament:QIDI PETG-Tough @X-smart 3]
|
||||||
inherits = *QIDI PETG-Tough*
|
inherits = *QIDI PETG-Tough*
|
||||||
compatible_printers_condition = printer_model=="X-smart 3"
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
@@ -653,6 +798,10 @@ compatible_printers_condition = printer_model=="X-smart 3"
|
|||||||
filament_max_volumetric_speed = 20
|
filament_max_volumetric_speed = 20
|
||||||
slowdown_below_layer_time = 8
|
slowdown_below_layer_time = 8
|
||||||
|
|
||||||
|
[filament:QIDI UltraPA @X-smart 3]
|
||||||
|
inherits = *QIDI UltraPA*
|
||||||
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
|
|
||||||
# X-smart 3 Generic filament preset
|
# X-smart 3 Generic filament preset
|
||||||
[filament:Generic ABS @X-smart 3]
|
[filament:Generic ABS @X-smart 3]
|
||||||
inherits = *Generic ABS*
|
inherits = *Generic ABS*
|
||||||
@@ -669,13 +818,11 @@ filament_max_volumetric_speed = 8
|
|||||||
[filament:Generic PLA @X-smart 3]
|
[filament:Generic PLA @X-smart 3]
|
||||||
inherits = *Generic PLA*
|
inherits = *Generic PLA*
|
||||||
compatible_printers_condition = printer_model=="X-smart 3"
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
filament_max_volumetric_speed = 15
|
|
||||||
slowdown_below_layer_time = 8
|
slowdown_below_layer_time = 8
|
||||||
|
|
||||||
[filament:Generic TPU 95A @X-smart 3]
|
[filament:Generic TPU 95A @X-smart 3]
|
||||||
inherits = *Generic TPU 95A*
|
inherits = *Generic TPU 95A*
|
||||||
compatible_printers_condition = printer_model=="X-smart 3"
|
compatible_printers_condition = printer_model=="X-smart 3"
|
||||||
slowdown_below_layer_time = 8
|
|
||||||
|
|
||||||
# Common printer preset
|
# Common printer preset
|
||||||
[printer:*common*]
|
[printer:*common*]
|
||||||
@@ -747,7 +894,7 @@ retract_restart_extra_toolchange = 0
|
|||||||
retract_speed = 30
|
retract_speed = 30
|
||||||
silent_mode = 0
|
silent_mode = 0
|
||||||
single_extruder_multi_material = 0
|
single_extruder_multi_material = 0
|
||||||
start_gcode = PRINT_START\nG28\nM141 S0\nG0 Z50 F600\nM190 S[first_layer_bed_temperature]\nG28 Z\nG29 ; mesh bed leveling ,comment this code to close it\nG0 X0 Y0 Z50 F6000\nM109 S[first_layer_temperature]\nM106 P3 S255\nM83\nG0 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0)} Z5 F6000\nG0 Z0.2 F600\nG1 E3 F1800\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 80))} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 85} E{83 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 3} E{82 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 12} E{-10 * 0.04} F3000\nG1 E{10 * 0.04} F3000
|
start_gcode = PRINT_START\nG28\nM141 S0\nG0 Z50 F600\nM190 S[first_layer_bed_temperature]\nG28 Z\nG29 ; mesh bed leveling ,comment this code to close it\nG0 X0 Y0 Z50 F6000\nM109 S[first_layer_temperature]\nM106 P3 S255\nM83\nG4 P3000\nG0 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0)} Z5 F6000\nG0 Z0.2 F600\nG1 E3 F1800\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 80))} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 85} E{83 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 3} E{82 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 12} E{-10 * 0.04} F3000\nG1 E{10 * 0.04} F3000
|
||||||
template_custom_gcode =
|
template_custom_gcode =
|
||||||
thumbnails =
|
thumbnails =
|
||||||
thumbnails_format = QIDI
|
thumbnails_format = QIDI
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,264 +1,363 @@
|
|||||||
var LangText={
|
var LangText={
|
||||||
"en": {
|
"en": {
|
||||||
"t0": "Welcome to QIDISlicer",
|
|
||||||
"t1": "User Guide",
|
"t1": "User Guide",
|
||||||
"t2": "First Print",
|
"t2": "First Print",
|
||||||
"t3": "Add Support",
|
"t3": "Add Support",
|
||||||
"t4": "Connect Device",
|
"t4": "Connect Device",
|
||||||
"t5": "Wifi Send",
|
"t5": "Wifi Send",
|
||||||
"t6": "Issue Report",
|
"t6": "Issue Report",
|
||||||
"t7": "Demonstration",
|
"t7": "Introduce",
|
||||||
"t8": "Product Info",
|
"t8": "3D Printers",
|
||||||
"t9": "Contact with us",
|
"t9": "Contact with us",
|
||||||
"t10": "Filament",
|
"t10": "Filaments",
|
||||||
"t11": "Add Text",
|
"t11": "Add Text",
|
||||||
"t12": "Cut Model",
|
"t12": "Cut Model",
|
||||||
"t13": "Download Model",
|
"t13": "Download Model",
|
||||||
"t14": "Adaptive Meshing",
|
"t14": "Adaptive Meshing",
|
||||||
"ls0": "Learn more:",
|
"t15": "Flow Rate Calibration",
|
||||||
"ls1": "You can download 3D models from the following websites.",
|
"t16": "Calibration",
|
||||||
"ls2": "If you have any questions about the Printer or QIDISlicer, please contact us via the appropriate E-mail address or Skype.",
|
"t17": "Pressure Advance",
|
||||||
"ls3": "Note: please try to tell us your requirements in the form of video or pictures, and provide 3MF file, G-code file, machine number and other necessary information.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "Learn more:",
|
||||||
"ls5": "Why do you need Adaptive Meshing:",
|
"l1": "You can download the 3D model from the following link.",
|
||||||
"ls6": "How to disable this feature:",
|
"l2": "If you have any questions about the Printer or QIDISlicer, please contact us via the appropriate E-mail address or Skype.",
|
||||||
"ls7": "1.No wasted probe information, Adaptive Meshing will generate a mesh only in the area you actually need it: This means that leveling before each print takes significantly less time!",
|
"l3": "Note: please try to tell us your requirements in the form of video or pictures, and provide 3MF file, G-code file, machine number and other necessary information.",
|
||||||
"ls8": "2.Since the mesh area will be smaller, the mesh can be much more dense. Imagine making a 3x3 mesh, but the size of a 3DBenchy! Which brings you a higher precision printing experience.",
|
"l5": "Why do you need Adaptive Meshing:",
|
||||||
"ls9": "Add ';' before 'G29' in the Start G-code.",
|
"l6": "How to close:",
|
||||||
"ls10": "Red Area: General mesh leveling.",
|
"l7": "1.No wasted probe information, Adaptive Meshing will generate a mesh only in the area you actually need it: This means that leveling before each print takes significantly less time!",
|
||||||
"ls11": "Green Area: Adaptive mesh leveling.",
|
"l8": "2.Since the mesh area will be smaller, the mesh can be much more dense. Imagine making a 3x3 mesh, but the size of a 3DBenchy! Which brings you a higher precision printing experience.",
|
||||||
|
"l9": "Add ';' before 'G29' in the Start G-code.",
|
||||||
|
"l10": "Red Area: General mesh leveling.",
|
||||||
|
"l11": "Green Area: Adaptive mesh leveling.",
|
||||||
|
"l12": "Why you need Flowrate Calibration",
|
||||||
|
"l13": "Different filaments have different shrinkage rates, and in order to obtain perfect surface quality, the print flow rate needs to be carefully adjusted.",
|
||||||
|
"l14": "Flowrate can be changed by modifying the 'Extrusion multiplier'.",
|
||||||
|
"l15": "1.Overextrusion: There is too much material on the model, causing bumps to form or layers to appear thicker and uneven than expected.",
|
||||||
|
"l16": "2.Underextrusion extrusion: the printing layer is too thin, the filling strength is insufficient, the surface has dents, and the model is easy to break.",
|
||||||
|
"l17": "Coarse calibration",
|
||||||
|
"l18": "Print calibration blocks in the 'Extrusion multiplier' ±0.2 range, with each block having a step size of 0.05.",
|
||||||
|
"l19": "When you are unsure of the consumable flow rate, you can use coarse calibration first to get a better range, then fine calibration to get a more accurate value.",
|
||||||
|
"l20": "After printing, determine the best value based on the model surface, enter the 'Extrusion multiplier', and save.",
|
||||||
|
"l21": "In the figure below, -5 has the best surface quality, so the optimal 'Extrusion multiplier' is 0.95 (1-5%).",
|
||||||
|
"l22": "Fine calibration",
|
||||||
|
"l23": "Print calibration blocks in the ±0.04 range based on the 'Extrusion multiplier' you entered, each with a step size of 0.01.",
|
||||||
|
"l24": "The 'Extrusion multiplier' entered in the figure below is 0.95, and 1 has the best surface quality, so the best 'Extrusion multiplier' is 0.96 (0.95+1%).",
|
||||||
|
"l25": "Pressure advance can reduce bleed during non-extrude moves and reduce blobbing during cornering.",
|
||||||
|
"l26": "When to Calibrate Pressure in Advance",
|
||||||
|
"l27": "1.Use different brands of filaments, or the filaments are damp;",
|
||||||
|
"l28": "2.The nozzle is worn or replaced with a different size nozzle;",
|
||||||
|
"l29": "3.Use different printing parameters such as temperature and line width.",
|
||||||
|
"l30": "How to calibrate",
|
||||||
|
"l31": "We provide three common calibration methods, you can choose the method you like for calibration.",
|
||||||
|
"l32": "There is a 10% error in the test results, but it is almost indistinguishable to the naked eye. Choose a suitable value and save it, then start your printing.",
|
||||||
|
"l33": "If you need to modify the printing parameters, please modify and save the parameters first, and then perform the calibration procedure.",
|
||||||
|
"l34": "After printing is completed, please enter the best value into the software and save it.",
|
||||||
|
"l35": "PA Line",
|
||||||
|
"l36": "After printing is completed, select the smoothest line, enter its corresponding value into the software and save it.",
|
||||||
|
"l37": "PA Pattern",
|
||||||
|
"l38": "After printing is completed, select the flattest set of lines, enter its corresponding values into the software and save it.",
|
||||||
|
"l39": "PA Tower",
|
||||||
|
"l40": "The pressure advance value will be changed every 5mm the PA tower rises. Please measure the height of the best area of the model, and then calculate the corresponding pressure advance value based on the set step value, then input it into the software and save it.",
|
||||||
},
|
},
|
||||||
"zh_CN": {
|
"zh_CN": {
|
||||||
"t0": "欢迎使用QIDISlicer",
|
|
||||||
"t1": "用户指南",
|
"t1": "用户指南",
|
||||||
"t2": "首次打印",
|
"t2": "首次打印",
|
||||||
"t3": "添加支撑",
|
"t3": "添加支撑",
|
||||||
"t4": "连接设备",
|
"t4": "连接设备",
|
||||||
"t5": "无线发送",
|
"t5": "无线发送",
|
||||||
"t6": "问题报告",
|
"t6": "问题报告",
|
||||||
"t7": "演示",
|
"t8": "3D打印机",
|
||||||
"t8": "产品信息",
|
"t7": "介绍",
|
||||||
"t9": "与我们联系",
|
"t9": "与我们联系",
|
||||||
"t10": "耗材",
|
"t10": "耗材",
|
||||||
"t11": "添加文本",
|
"t11": "添加文本",
|
||||||
"t12": "切割模型",
|
"t12": "切割模型",
|
||||||
"t13": "下载模型",
|
"t13": "下载模型",
|
||||||
"t14": "自适应网格划分",
|
"t14": "自适应网格划分",
|
||||||
"ls0": "了解更多:",
|
"t15": "流量校准",
|
||||||
"ls1": "您可以从以下网站下载 3D 模型。",
|
"t16": "校准",
|
||||||
"ls2": "如果您对打印机或 QIDISlicer 有任何疑问,请通过相应的电子邮件地址或 Skype 与我们联系。",
|
"t17": "压力提前",
|
||||||
"ls3": "注:请尽量以视频或图片的形式告诉我们您的需求,并提供3MF文件、G-Code文件、机器编号等必要信息。",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "了解更多:",
|
||||||
"ls5": "为什么需要自适应网格划分:",
|
"l1": "您可以从以下链接下载3D模型。",
|
||||||
"ls6": "如何禁用此功能:",
|
"l2": "如果您对打印机或 QIDISlicer 有任何疑问,请通过相应的电子邮件地址或Skype与我们联系。",
|
||||||
"ls7": "1.不浪费探头信息,自适应网格划分将仅在您实际需要的区域生成网格:这意味着每次打印之前的调平所需的时间显着减少!",
|
"l3": "注:请尽量以视频或图片的形式告诉我们您的需求,并提供3MF文件、G-Code文件、机器编号等必要信息。",
|
||||||
"ls8": "2.由于网格面积会更小,所以网格可以更密。想象一下制作一个 3x3 网格,但大小与 3DBenchy 一样!为您带来更高精度的打印体验。",
|
"l5": "为什么需要自适应网格划分:",
|
||||||
"ls9": "在起始G-code中的'G29'前添加';'。",
|
"l6": "如何禁用此功能:",
|
||||||
"ls10": "红色区域:一般网格调平。",
|
"l7": "1.不浪费探头信息,自适应网格划分将仅在您实际需要的区域生成网格:这意味着每次打印之前的调平所需的时间显着减少!",
|
||||||
"ls11": "绿色区域:自适应网格平整。",
|
"l8": "2.由于网格面积会更小,所以网格可以更密。想象一下制作一个 3x3 网格,但大小与3DBenchy一样!为您带来更高精度的打印体验。",
|
||||||
|
"l9": "在起始G-code中的'G29'前添加';'。",
|
||||||
|
"l10": "红色区域:一般网格调平。",
|
||||||
|
"l11": "绿色区域:自适应网格调平。",
|
||||||
|
"l12": "为什么需要流量校准",
|
||||||
|
"l13": "不同的耗材拥有不同的收缩率,为了获得完美的表面质量,需要对打印流量进行细致的调整。",
|
||||||
|
"l14": "通过修改‘挤出乘数’可以更改打印流量。",
|
||||||
|
"l15": "1.挤出过度:模型上的材料过多,导致形成凸起或层显得比预期更厚且不均匀。",
|
||||||
|
"l16": "2.挤出不足:打印层太薄,填充强度不足,表面有凹痕,模型易断裂。",
|
||||||
|
"l17": "粗校准",
|
||||||
|
"l18": "打印‘挤出乘数’±0.2范围内的校准块,每个校准块步长为0.05。",
|
||||||
|
"l19": "当您不确定耗材流量时,可以先使用粗校准以获得更好的范围,然后使用精校准以获得更准确的值。",
|
||||||
|
"l20": "打印完成后,根据模型表面确定最佳值,输入‘挤出乘数’,并保存。",
|
||||||
|
"l21": "下图中-5的表面质量最佳,因此最佳‘挤出乘数’为0.95(1-5%)。",
|
||||||
|
"l22": "精校准",
|
||||||
|
"l23": "根据您输入的‘挤出乘数‘打印±0.04范围内的校准块,每个校准块步长为0.01。",
|
||||||
|
"l24": "下图中输入的‘挤出乘数’为0.95,1的表面质量最佳,因此最佳‘挤出乘数’为0.96(0.95+1%)。",
|
||||||
|
"l25": "压力提前可以减少非挤压移动期间的渗出,并减少转弯期间的滴落。",
|
||||||
|
"l26": "什么时候需要校准压力提前",
|
||||||
|
"l27": "1.使用不同品牌的耗材,或耗材受潮;",
|
||||||
|
"l28": "2.喷嘴磨损或更换不同尺寸的喷嘴;",
|
||||||
|
"l29": "3.使用不同的温度、线宽等打印参数。",
|
||||||
|
"l30": "如何校准",
|
||||||
|
"l31": "我们提供了三种常见的校准方式,你可以选择自己喜欢的方式进行校准。",
|
||||||
|
"l32": "测试结果存在10%的误差,但肉眼几乎无法区别,选择一个合适的值并将其保存,然后开始你的打印吧。",
|
||||||
|
"l33": "如果你需要修改打印参数,请先修改并保存参数,然后再进行校准程序。",
|
||||||
|
"l34": "打印完成后,请将最佳值输入到软件中并保存。",
|
||||||
|
"l35": "PA 划线",
|
||||||
|
"l36": "打印完成后,选择最平滑的一条线,请将其对应的值输入到软件中并保存。",
|
||||||
|
"l37": "PA 图形",
|
||||||
|
"l38": "打印完成后,选择最平整的一组线,请将其对应的值输入到软件中并保存。",
|
||||||
|
"l39": "PA 塔",
|
||||||
|
"l40": "PA 塔每升高5mm会更改一次压力提前值,请测量出模型最佳区域的高度,再根据设定的步进值计算出其对应的压力提前值,然后输入到软件中并保存。",
|
||||||
},
|
},
|
||||||
"ja": {
|
"ja": {
|
||||||
"t0": "QIDISlicerへようこそ",
|
|
||||||
"t1": "ユーザーガイド",
|
"t1": "ユーザーガイド",
|
||||||
"t2": "最初の印刷物",
|
"t2": "最初の印刷物",
|
||||||
"t3": "サポートを追加する",
|
"t3": "サポートを追加する",
|
||||||
"t4": "デバイスを接続する",
|
"t4": "デバイスを接続する",
|
||||||
"t5": "Wi-Fi送信",
|
"t5": "Wi-Fi送信",
|
||||||
"t6": "問題レポート",
|
"t6": "問題レポート",
|
||||||
"t7": "デモンストレーション",
|
"t7": "紹介します",
|
||||||
"t8": "製品情報",
|
"t8": "3Dプリンター",
|
||||||
"t9": "お問い合わせください",
|
"t9": "お問い合わせください",
|
||||||
"t10": "フィラメント",
|
"t10": "フィラメント",
|
||||||
"t11": "テキストを追加",
|
"t11": "テキストを追加",
|
||||||
"t12": "カットモデル",
|
"t12": "カットモデル",
|
||||||
"t13": "モデルをダウンロード",
|
"t13": "モデルをダウンロード",
|
||||||
"t14": "適応性メッシュ",
|
"t14": "適応性メッシュ",
|
||||||
"ls0": "もっと詳しく知る:",
|
"t15": "流量校正",
|
||||||
"ls1": "3Dモデルは以下のWebサイトからダウンロードできます。",
|
"t16": "較正",
|
||||||
"ls2": "如果您对打印机或 QIDISlicer 有任何疑问,请通过相应的电子邮件地址或 Skype 与我们联系。",
|
"t17": "圧力前進",
|
||||||
"ls3": "注:请尽量以视频或图片的形式告诉我们您的需求,并提供3MF文件、G-Code文件、机器编号等必要信息。",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "もっと詳しく知る:",
|
||||||
"ls5": "アダプティブ メッシュが必要な理由:",
|
"l1": "3Dモデルは以下のWebサイトからダウンロードできます。",
|
||||||
"ls6": "この機能を無効にする方法:",
|
"l2": "如果您对打印机或 QIDISlicer 有任何疑问,请通过相应的电子邮件地址或 Skype 与我们联系。",
|
||||||
"ls7": "1. 無駄なプローブ情報がなく、アダプティブメッシュは実際に必要な領域のメッシュのみを生成します。これは、各印刷前のレベリングにかかる時間が大幅に短縮されることを意味します。",
|
"l3": "注:请尽量以视频或图片的形式告诉我们您的需求,并提供3MF文件、G-Code文件、机器编号等必要信息。",
|
||||||
"ls8": "2.メッシュ領域が小さくなるため、メッシュをより高密度にすることができます。 3x3 メッシュを 3DBenchy のサイズで作成することを想像してみてください。これにより、より高精度の印刷体験が得られます。",
|
"l5": "アダプティブ メッシュが必要な理由:",
|
||||||
"ls9": "追加 ';' 「最初のGコード」の'G29'の前。",
|
"l6": "この機能を無効にする方法:",
|
||||||
"ls10": "赤い領域: 一般的なメッシュ レベリング。",
|
"l7": "1. 無駄なプローブ情報がなく、アダプティブメッシュは実際に必要な領域のメッシュのみを生成します。これは、各印刷前のレベリングにかかる時間が大幅に短縮されることを意味します。",
|
||||||
"ls11": "緑色の領域: 適応性メッシュ レベリング。",
|
"l8": "2.メッシュ領域が小さくなるため、メッシュをより高密度にすることができます。 3x3 メッシュを 3DBenchy のサイズで作成することを想像してみてください。これにより、より高精度の印刷体験が得られます。",
|
||||||
|
"l9": "追加 ';' 「最初のGコード」の'G29'の前。",
|
||||||
|
"l10": "赤い領域: 一般的なメッシュ レベリング。",
|
||||||
|
"l11": "緑色の領域: 適応性メッシュ レベリング。",
|
||||||
|
"l12": "フローのキャリブレーションはなぜ必要なのでしょうか",
|
||||||
|
"l13": "消耗品によっても収縮率は異なりますし、完璧な表面品質を得るためには印刷フローの調整が必要です。",
|
||||||
|
"l14": "『押し出し乗数』を修正することでプリントフローを変更できます。",
|
||||||
|
"l15": "1.押し出しすぎ:型の上の材料が多すぎて、突起や層が予想より厚くなってムラができてしまいます。",
|
||||||
|
"l16": "2.押し出し不足:印刷層が薄すぎて、充填強度が足りなくて、表面に凹痕があって、型が切れやすいです。",
|
||||||
|
"l17": "粗いキャリブレーション",
|
||||||
|
"l18": "「押し出し乗数」±0.2の範囲のキャリブレーションブロックを印刷し、各キャリブレーションブロックのステップを0.05とします。",
|
||||||
|
"l19": "消耗品の流れがわからないときは、粗いキャリブレーションを使って範囲を広くしてから、精緻なキャリブレーションを使ってより正確な値を出すことができます。",
|
||||||
|
"l20": "印刷が終わったら、モデルの表面から最適値を決めて、「押し出し乗数」を入力し、保存します。",
|
||||||
|
"l21": "次の図では、-5が最適なので、最適な「押し出し乗数」は0.95(1-5%)となります。",
|
||||||
|
"l22": "キャリブレーションを行います",
|
||||||
|
"l23": "入力された「押し出し乗数」に応じて±0.04の範囲のキャリブレーションブロックを印刷します。キャリブレーションブロック毎のステップサイズは0.01です。",
|
||||||
|
"l24": "図では、「押し出し乗数」を0.95と入力していますが、1の表面品質が最適なので、最適な「押し出し乗数」は0.96(0.95+1%)となります。",
|
||||||
|
"l25": "圧力前進により、非絞り動作時のブリードが減少し、旋回時の液だれが減少します。",
|
||||||
|
"l26": "圧力前進を校正する場合",
|
||||||
|
"l27": "1.異なるブランドの消耗品を使用すると、消耗品が湿気を帯びます。",
|
||||||
|
"l28": "2.ノズルが磨耗しているか、異なるサイズのノズルに交換されている。",
|
||||||
|
"l29": "3.温度や線幅などのさまざまな印刷パラメータを使用します。",
|
||||||
|
"l30": "校正方法",
|
||||||
|
"l31": "一般的な3つの校正方法が用意されており、お好みの校正方法を選択できます。",
|
||||||
|
"l32": "テスト結果には10%程度の誤差がありますが、肉眼ではほとんど区別できない程度ですので、適切な値を選択して保存し、印刷を開始してください。",
|
||||||
|
"l33": "印刷パラメータを変更する必要がある場合は、まずパラメータを変更して保存してから、キャリブレーション手順を実行してください。",
|
||||||
|
"l34": "印刷が完了したら、ソフトウェアに最適な値を入力して保存します。",
|
||||||
|
"l35": "PA 線",
|
||||||
|
"l36": "印刷が完了したら、最も滑らかな線を選択し、対応する値をソフトウェアに入力して保存します。",
|
||||||
|
"l37": "PAグラフィックス",
|
||||||
|
"l38": "印刷が完了したら、最も平坦な線のセットを選択し、対応する値をソフトウェアに入力して保存します。",
|
||||||
|
"l39": "PAタワー",
|
||||||
|
"l40": "PAタワーが上昇する5mmごとに圧力アドバンス値が変更されますので、モデルの最適領域の高さを測定し、設定されたステップ値に基づいて対応する圧力アドバンス値を計算し、それをソフトウェアに入力して、それを保存。",
|
||||||
},
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
"t0": "Bienvenue dans QIDISlicer",
|
|
||||||
"t1": "Guide de l'utilisateur",
|
"t1": "Guide de l'utilisateur",
|
||||||
"t2": "Première d'impression",
|
"t2": "Première d'impression",
|
||||||
"t3": "Ajouter une prise en charge",
|
"t3": "Ajouter une prise en charge",
|
||||||
"t4": "Connecter l'appareil",
|
"t4": "Connecter l'appareil",
|
||||||
"t5": "Envoi Wi-Fi",
|
"t5": "Envoi Wi-Fi",
|
||||||
"t6": "Rapport de problème",
|
"t6": "Rapport de problème",
|
||||||
"t7": "Démonstration",
|
"t7": "Présentez",
|
||||||
"t8": "Informations sur le produit",
|
"t8": "Imprimantes 3D",
|
||||||
"t9": "Contactez-nous",
|
"t9": "Contactez-nous",
|
||||||
"t10": "Filament",
|
"t10": "Filaments",
|
||||||
"t11": "Ajouter du texte",
|
"t11": "Ajouter du texte",
|
||||||
"t12": "Couper le modèle",
|
"t12": "Couper le modèle",
|
||||||
"t13": "Télécharger le modèle",
|
"t13": "Télécharger le modèle",
|
||||||
"t14": "Maillage adaptatif",
|
"t14": "Maillage adaptatif",
|
||||||
"ls0": "Apprendre encore plus:",
|
"t15": "Étalonnage du débit",
|
||||||
"ls1": "Vous pouvez télécharger des modèles 3D à partir des sites Web suivants.",
|
"t16": "Étalonnage",
|
||||||
"ls2": "Si vous avez des questions sur l'imprimante ou le QIDISlicer, veuillez nous contacter via l'adresse e-mail appropriée ou via Skype.",
|
"t17": "Avance de pression",
|
||||||
"ls3": "Remarque : veuillez essayer de nous indiquer vos besoins sous forme de vidéo ou d'images, et fournir un fichier 3MF, un fichier G-code, un numéro de machine et d'autres informations nécessaires.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "Apprendre encore plus:",
|
||||||
"ls5": "Pourquoi avez-vous besoin d'un maillage adaptatif :",
|
"l1": "Vous pouvez télécharger des modèles 3D à partir des sites Web suivants.",
|
||||||
"ls6": "Comment désactiver cette fonctionnalité :",
|
"l2": "Si vous avez des questions sur l'imprimante ou le QIDISlicer, veuillez nous contacter via l'adresse e-mail appropriée ou via Skype.",
|
||||||
"ls7": "1. Aucune information de sonde gaspillée, le maillage adaptatif générera un maillage uniquement dans la zone où vous en avez réellement besoin : cela signifie que le nivellement avant chaque impression prend beaucoup moins de temps !",
|
"l3": "Remarque: veuillez essayer de nous indiquer vos besoins sous forme de vidéo ou d'images, et fournir un fichier 3MF, un fichier G-code, un numéro de machine et d'autres informations nécessaires.",
|
||||||
"ls8": "2. Étant donné que la zone de maillage sera plus petite, le maillage peut être beaucoup plus dense. Imaginez faire un maillage 3x3, mais de la taille d'un 3DBenchy ! Ce qui vous apporte une expérience d'impression de plus grande précision.",
|
"l5": "Pourquoi avez-vous besoin d'un maillage adaptatif:",
|
||||||
"ls9": "Ajouter ';' avant 'G29' dans le G-code de début",
|
"l6": "Comment désactiver cette fonctionnalité:",
|
||||||
"ls10": "Zone rouge : Nivellement général du maillage.",
|
"l7": "1.Aucune information de sonde gaspillée, le maillage adaptatif générera un maillage uniquement dans la zone où vous en avez réellement besoin: cela signifie que le nivellement avant chaque impression prend beaucoup moins de temps !",
|
||||||
"ls11": "Zone verte : Nivellement de maillage adaptatif.",
|
"l8": "2.Étant donné que la zone de maillage sera plus petite, le maillage peut être beaucoup plus dense. Imaginez faire un maillage 3x3, mais de la taille d'un 3DBenchy ! Ce qui vous apporte une expérience d'impression de plus grande précision.",
|
||||||
|
"l9": "Ajouter ';' avant 'G29' dans le G-code de début",
|
||||||
|
"l10": "Zone rouge: Nivellement général du maillage.",
|
||||||
|
"l11": "Zone verte: Nivellement de maillage adaptatif.",
|
||||||
|
"l12": "Pourquoi vous avez besoin de la Calibration du débit",
|
||||||
|
"l13": "Les différents filaments ont des taux de retrait différents, et afin d’obtenir une qualité de surface parfaite, le débit d’impression doit être ajusté avec soin.",
|
||||||
|
"l14": "Le débit peut être modifié en modifiant le «multiplicateur d’extrusion».",
|
||||||
|
"l15": "1.Surextrusion: il y a trop de matériau sur le modèle, provoquant la formation de bosses ou l’apparition de couches plus épaisses et inégales que prévu.",
|
||||||
|
"l16": "2.Extrusion d’underextrusion: la couche d’impression est trop mince, la force remplissante est insuffisante, la surface a des bosses, et le modèle est facile à casser.",
|
||||||
|
"l17": "Calibrage grossier",
|
||||||
|
"l18": "Imprimer des blocs d’étalonnage dans la gamme «multiplicateur d’extrusion» de ± 0.2, chaque bloc ayant une taille de pas de 0.05.",
|
||||||
|
"l19": "Lorsque vous n’êtes pas sûr du débit des consommables, vous pouvez utiliser l’étalonnage grossier d’abord pour obtenir une meilleure plage, puis l’étalonnage fin pour obtenir une valeur plus précise.",
|
||||||
|
"l20": "Après l’impression, déterminez la meilleure valeur en fonction de la surface du modèle, saisissez le «multiplicateur d’extrusion» et sauvegardez.",
|
||||||
|
"l21": "Dans la figure ci-dessous, -5 a la meilleure qualité de surface, de sorte que le multiplicateur d’extrusion optimal ’ est 0.95 (1-5%).",
|
||||||
|
"l22": "Calibrage fin",
|
||||||
|
"l23": "Imprimez des blocs d’étalonnage de ± 0.04 en fonction du «multiplicateur d’extrusion» que vous avez entré, chacun avec une taille de pas de 0.01.",
|
||||||
|
"l24": "Le «multiplicateur d’extrusion» indiqué dans la figure ci-dessous est de 0.95, et 1 a la meilleure qualité de surface, donc le meilleur «multiplicateur d’extrusion» est de 0.96 (0.95+1%).",
|
||||||
|
"l25": "L'avance de pression peut réduire le saignement lors des mouvements sans extrusion et réduire les gouttes dans les virages.",
|
||||||
|
"l26": "Quand calibrer la pression à l’avance",
|
||||||
|
"l27": "1.Utilisez différentes marques de filaments, sinon les filaments sont humides ;",
|
||||||
|
"l28": "2.La buse est usée ou remplacée par une buse de taille différente ;",
|
||||||
|
"l29": "3.Utilisez différents paramètres d'impression tels que la température et la largeur des lignes.",
|
||||||
|
"l30": "Comment calibrer",
|
||||||
|
"l31": "Nous proposons trois méthodes d'étalonnage courantes, vous pouvez choisir la méthode que vous souhaitez pour l'étalonnage.",
|
||||||
|
"l32": "Il y a une erreur de 10 % dans les résultats du test, mais elle est presque impossible à distinguer à l'œil nu. Choisissez une valeur appropriée et enregistrez-la, puis démarrez votre impression.",
|
||||||
|
"l33": "Si vous devez modifier les paramètres d'impression, veuillez d'abord modifier et enregistrer les paramètres, puis effectuer la procédure d'étalonnage.",
|
||||||
|
"l34": "Une fois l'impression terminée, veuillez saisir la meilleure valeur dans le logiciel et l'enregistrer.",
|
||||||
|
"l35": "Ligne PA",
|
||||||
|
"l36": "Une fois l'impression terminée, sélectionnez la ligne la plus lisse, entrez la valeur correspondante dans le logiciel et enregistrez-la.",
|
||||||
|
"l37": "Modèle PA",
|
||||||
|
"l38": "Une fois l'impression terminée, sélectionnez l'ensemble de lignes le plus plat, entrez ses valeurs correspondantes dans le logiciel et enregistrez-le.",
|
||||||
|
"l39": "La tour PA",
|
||||||
|
"l40": "La valeur d'avance de pression sera modifiée tous les 5 mm d'élévation de la tour PA. Veuillez mesurer la hauteur de la meilleure zone du modèle, puis calculer la valeur d'avance de pression correspondante en fonction de la valeur de pas définie, puis la saisir dans le logiciel et l'enregistrer.",
|
||||||
},
|
},
|
||||||
"de": {
|
"de": {
|
||||||
"t0": "Willkommen bei QIDISlicer",
|
|
||||||
"t1": "Benutzerhandbuch",
|
"t1": "Benutzerhandbuch",
|
||||||
"t2": "Erster Druck",
|
"t2": "Erster Druck",
|
||||||
"t3": "Unterstützung hinzufügen",
|
"t3": "Unterstützung hinzufügen",
|
||||||
"t4": "Gerät verbinden",
|
"t4": "Gerät verbinden",
|
||||||
"t5": "Wi-Fi senden",
|
"t5": "Wi-Fi senden",
|
||||||
"t6": "Problembericht",
|
"t6": "Problembericht",
|
||||||
"t7": "Demonstration",
|
"t7": "Vorstellung",
|
||||||
"t8": "Produktinformationen",
|
"t8": "3D-Drucker",
|
||||||
"t9": "Kontaktieren Sie uns",
|
"t9": "Kontaktieren Sie uns",
|
||||||
"t10": "Filament",
|
"t10": "Filaments",
|
||||||
"t11": "Text hinzufügen",
|
"t11": "Text hinzufügen",
|
||||||
"t12": "Modell schneiden",
|
"t12": "Modell schneiden",
|
||||||
"t13": "Modell herunterladen",
|
"t13": "Modell herunterladen",
|
||||||
"t14": "Adaptive Gitternetz",
|
"t14": "Adaptive Gitternetz",
|
||||||
"ls0": "Erfahren Sie mehr:",
|
"t15": "Kalibrierung der Durchflussrate",
|
||||||
"ls1": "Sie können 3D-Modelle von den folgenden Websites herunterladen.",
|
"t16": "Kalibrierung",
|
||||||
"ls2": "Wenn Sie Fragen zum Drucker oder QIDISlicer haben, kontaktieren Sie uns bitte über die entsprechende E-Mail-Adresse oder Skype.",
|
"t17": "Druckvorschub",
|
||||||
"ls3": "Hinweis: Bitte versuchen Sie, uns Ihre Anforderungen in Form von Videos oder Bildern mitzuteilen und geben Sie die 3MF-Datei, die G-Code-Datei, die Maschinennummer und andere notwendige Informationen an.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "Erfahren Sie mehr:",
|
||||||
"ls5": "Warum brauchen Sie Adaptive Meshing:",
|
"l1": "Sie können 3D-Modelle von den folgenden Websites herunterladen.",
|
||||||
"ls6": "So deaktivieren Sie diese Funktion:",
|
"l2": "Wenn Sie Fragen zum Drucker oder QIDISlicer haben, kontaktieren Sie uns bitte über die entsprechende E-Mail-Adresse oder Skype.",
|
||||||
"ls7": "1. Keine Verschwendung von Sondeninformationen, Adaptive Meshing erstellt ein Netz nur in dem Bereich, in dem Sie es tatsächlich benötigen: Das bedeutet, dass die Nivellierung vor jedem Druck deutlich weniger Zeit in Anspruch nimmt!",
|
"l3": "Hinweis: Bitte versuchen Sie, uns Ihre Anforderungen in Form von Videos oder Bildern mitzuteilen und geben Sie die 3MF-Datei, die G-Code-Datei, die Maschinennummer und andere notwendige Informationen an.",
|
||||||
"ls8": "2.Da die Maschenfläche kleiner wird, kann das Netz viel dichter sein. Stellen Sie sich vor, Sie erstellen ein 3x3-Netz, aber in der Größe eines 3DBenchy! Das bringt Ihnen ein präziseres Druckerlebnis.",
|
"l5": "Warum brauchen Sie Adaptive Meshing:",
|
||||||
"ls9": "Füge hinzu ein „;“ vor „G29“ im Start-G-Code.",
|
"l6": "So deaktivieren Sie diese Funktion:",
|
||||||
"ls10": "Roter Bereich: Allgemeine Netznivellierung.",
|
"l7": "1.Keine Verschwendung von Sondeninformationen, Adaptive Meshing erstellt ein Netz nur in dem Bereich, in dem Sie es tatsächlich benötigen: Das bedeutet, dass die Nivellierung vor jedem Druck deutlich weniger Zeit in Anspruch nimmt!",
|
||||||
"ls11": "Grüner Bereich: Adaptive Netznivellierung.",
|
"l8": "2.Da die Maschenfläche kleiner wird, kann das Netz viel dichter sein. Stellen Sie sich vor, Sie erstellen ein 3x3-Netz, aber in der Größe eines 3DBenchy! Das bringt Ihnen ein präziseres Druckerlebnis.",
|
||||||
|
"l9": "Füge hinzu ein „;“ vor „G29“ im Start-G-Code.",
|
||||||
|
"l10": "Roter Bereich: Allgemeine Netznivellierung.",
|
||||||
|
"l11": "Grüner Bereich: Adaptive Netznivellierung.",
|
||||||
|
"l12": "Was ist eine icd",
|
||||||
|
"l13": "Es gibt unterschiedliche skalenquoten und man muss den fluss der blüten genau einstellen, um eine optimale oberflächenqualität zu erreichen.",
|
||||||
|
"l14": "Die durchflussrate kann durch änderung des expeit geändert werden.",
|
||||||
|
"l15": "1.Überdruck: das modell enthält zu viel material, was dazu führt, dass die form dicker und ungleichmäßiger aussieht als erwartet.",
|
||||||
|
"l16": "2.Auspressen: der druck ist zu dünn, lässt das material zu wenig laden, hat löcher an der oberfläche, die die modelle beschädigen.",
|
||||||
|
"l17": "Grobkalibrierung.",
|
||||||
|
"l18": "Das überprüfen der kalibrierungsblock im rahmen des cop-fensters mit einer wand Von 0.05 stufen.",
|
||||||
|
"l19": "Bei problemen mit problemen können sie zunächst die raummanadung verwenden, um die richtige übereinstimmung zu erreichen, dann die feinkalibrierung einsetzen.",
|
||||||
|
"l20": "Wenn der ausdruck fertig ist, beschriftet man die besten werte anhand der oberfläche des modells, geht in den specker-bereich und speichern.",
|
||||||
|
"l21": "In der grafik, -5 mit der besten oberflächenqualität, kriegst du damit eine optimale ersparnis Von 0.95 (1-5%).",
|
||||||
|
"l22": "Härtstrich.",
|
||||||
|
"l23": "Das druckmodul für die wand im bereich Von 0.04 überprüfen, und jeder schritt ist eine 0.01",
|
||||||
|
"l24": "In dem unteren bild wurde ein -queprol Von 0.95 angezeigt, wobei 1 die beste oberflächenqualität hat. Damit liegt die beste -weshalb bei 0.96 (0.95+1).",
|
||||||
|
"l25": "Der Druckvorschub kann das Ausbluten bei nicht extrudierten Bewegungen und das Klopfen bei Kurvenfahrten reduzieren.",
|
||||||
|
"l26": "Wann sollte der Druck im Voraus kalibriert werden",
|
||||||
|
"l27": "1.Verwenden Sie Filamente verschiedener Marken, oder die Filamente sind feucht;",
|
||||||
|
"l28": "2.Die Düse ist abgenutzt oder durch eine Düse anderer Größe ersetzt;",
|
||||||
|
"l29": "3.Verwenden Sie verschiedene Druckparameter wie Temperatur und Linienbreite.",
|
||||||
|
"l30": "So kalibrieren Sie",
|
||||||
|
"l31": "Wir bieten drei gängige Kalibrierungsmethoden an. Sie können die Methode auswählen, die Ihnen für die Kalibrierung am besten gefällt.",
|
||||||
|
"l32": "Die Testergebnisse weisen einen Fehler von 10 % auf, der jedoch mit bloßem Auge kaum zu erkennen ist. Wählen Sie einen geeigneten Wert, speichern Sie ihn und starten Sie dann den Druckvorgang.",
|
||||||
|
"l33": "Wenn Sie die Druckparameter ändern müssen, ändern und speichern Sie bitte zuerst die Parameter und führen Sie dann den Kalibrierungsvorgang durch.",
|
||||||
|
"l34": "Nachdem der Druckvorgang abgeschlossen ist, geben Sie bitte den besten Wert in die Software ein und speichern Sie ihn.",
|
||||||
|
"l35": "PA-Leitung",
|
||||||
|
"l36": "Wählen Sie nach Abschluss des Druckvorgangs die glatteste Linie aus, geben Sie den entsprechenden Wert in die Software ein und speichern Sie ihn.",
|
||||||
|
"l37": "PA-Muster",
|
||||||
|
"l38": "Wählen Sie nach Abschluss des Druckvorgangs den flachsten Liniensatz aus, geben Sie die entsprechenden Werte in die Software ein und speichern Sie sie.",
|
||||||
|
"l39": "PA-Turm",
|
||||||
|
"l40": "Der Druckvorschubwert wird alle 5 mm geändert, wenn der PA-Turm ansteigt. Bitte messen Sie die Höhe des besten Bereichs des Modells und berechnen Sie dann den entsprechenden Druckvorschubwert basierend auf dem eingestellten Schrittwert, geben Sie ihn dann in die Software ein und speichern Sie ihn.",
|
||||||
},
|
},
|
||||||
"be": {
|
"be": {
|
||||||
"t0": "Вітаем у QIDISlicer",
|
|
||||||
"t1": "Кіраўніцтва карыстальніка",
|
"t1": "Кіраўніцтва карыстальніка",
|
||||||
"t2": "Першы адбітак",
|
"t2": "Першы адбітак",
|
||||||
"t3": "Дадаць падтрымку",
|
"t3": "Дадаць падтрымку",
|
||||||
"t4": "Падключыць прыладу",
|
"t4": "Падключыць прыладу",
|
||||||
"t5": "Адправіць па Wi-Fi",
|
"t5": "Адправіць па Wi-Fi",
|
||||||
"t6": "Паведамленне аб праблеме",
|
"t6": "Паведамленне аб праблеме",
|
||||||
"t7": "Дэманстрацыя",
|
"t7": "Познакомьтесь с нами",
|
||||||
"t8": "Інфармацыя аб прадукце",
|
"t8": "3D принтеры",
|
||||||
"t9": "Звязацца з намі",
|
"t9": "Звязацца з намі",
|
||||||
"t10": "Філамент",
|
"t10": "Філамент",
|
||||||
"t11": "Дадаць тэкст",
|
"t11": "Дадаць тэкст",
|
||||||
"t12": "Разрэзаная мадэль",
|
"t12": "Разрэзаная мадэль",
|
||||||
"t13": "Спампаваць мадэль",
|
"t13": "Спампаваць мадэль",
|
||||||
"t14": "Адаптыўная сетка",
|
"t14": "Адаптыўная сетка",
|
||||||
"ls0": "даведацца больш:",
|
"t15": "Каліброўка хуткасці патоку",
|
||||||
"ls1": "Вы можаце загрузіць 3D-мадэлі з наступных сайтаў.",
|
"t16": "Каліброўка",
|
||||||
"ls2": "Калі ў вас ёсць якія-небудзь пытанні аб прынтары або QIDISlicer, калі ласка, звяжыцеся з намі праз адпаведны адрас электроннай пошты або Skype.",
|
"t17": "Увеличение давления",
|
||||||
"ls3": "Заўвага: калі ласка, паспрабуйце паведаміць нам свае патрабаванні ў выглядзе відэа ці малюнкаў, а таксама прадаставіць файл 3MF, файл G-кода, нумар машыны і іншую неабходную інфармацыю.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l0": "даведацца больш:",
|
||||||
"ls5": "Навошта вам патрэбна адаптыўная сетка:",
|
"l1": "Вы можаце загрузіць 3D-мадэлі з наступных сайтаў.",
|
||||||
"ls6": "Як адключыць гэтую функцыю:",
|
"l2": "Калі ў вас ёсць якія-небудзь пытанні аб прынтары або QIDISlicer, калі ласка, звяжыцеся з намі праз адпаведны адрас электроннай пошты або Skype.",
|
||||||
"ls7": "1.Няма марнай інфармацыі пра зонд, Adaptive Meshing будзе ствараць сетку толькі ў той вобласці, якая вам сапраўды патрэбна: гэта азначае, што выраўноўванне перад кожнай друкам займае значна менш часу!",
|
"l3": "Заўвага: калі ласка, паспрабуйце паведаміць нам свае патрабаванні ў выглядзе відэа ці малюнкаў, а таксама прадаставіць файл 3MF, файл G-кода, нумар машыны і іншую неабходную інфармацыю.",
|
||||||
"ls8": "2.Паколькі плошча сеткі будзе меншай, сетка можа быць значна больш шчыльнай. Уявіце, што вы робіце сетку 3x3, але памерам з 3DBenchy! Што дае вам вопыт больш высокай дакладнасці друку.",
|
"l5": "Навошта вам патрэбна адаптыўная сетка:",
|
||||||
"ls9": "Дадайце ';' перад 'G29' у Пачатковым G-кодзе.",
|
"l6": "Як адключыць гэтую функцыю:",
|
||||||
"ls10": "Чырвоная зона: агульнае выраўноўванне сеткі.",
|
"l7": "1.Няма марнай інфармацыі пра зонд, Adaptive Meshing будзе ствараць сетку толькі ў той вобласці, якая вам сапраўды патрэбна: гэта азначае, што выраўноўванне перад кожнай друкам займае значна менш часу!",
|
||||||
"ls11": "Зялёная зона: адаптыўнае выраўноўванне сеткі.",
|
"l8": "2.Паколькі плошча сеткі будзе меншай, сетка можа быць значна больш шчыльнай. Уявіце, што вы робіце сетку 3x3, але памерам з 3DBenchy! Што дае вам вопыт больш высокай дакладнасці друку.",
|
||||||
},
|
"l9": "Дадайце ';' перад 'G29' у Пачатковым G-кодзе.",
|
||||||
"ca": {
|
"l10": "Чырвоная зона: агульнае выраўноўванне сеткі.",
|
||||||
"t0": "Benvingut a QIDISlicer",
|
"l11": "Зялёная зона: адаптыўнае выраўноўванне сеткі.",
|
||||||
"t1": "Guia de l'usuari",
|
"l12": "Зачем вам калибровка расхода",
|
||||||
"t2": "Primera d'impressió",
|
"l13": "Различные нити накала имеют разную скорость усадки, и для того, чтобы получить идеальное качество поверхности, скорость печати должна быть тщательно скорректирована.",
|
||||||
"t3": "Afegeix suport",
|
"l14": "Расход может быть изменен путем изменения 'экструзионный множитель'.",
|
||||||
"t4": "Connecta el dispositiu",
|
"l15": "1.Чрезмерная трузия: на модели слишком много материала, что приводит к образованию шишек или слоев, которые кажутся толще и неравномерно, чем ожидалось.",
|
||||||
"t5": "Enviament sense fil",
|
"l16": "2.Экструзия: слой печати слишком тонкий, прочность наполнения недостаточна, поверхность имеет вмятины, а модель легко сломать.",
|
||||||
"t6": "Informe de problemes",
|
"l17": "Калибровка по грубой поверхности",
|
||||||
"t7": "Demostració",
|
"l18": "Печать калибровочных блоков в диапазоне 'экструзионный множитель' ±0.2, причем каждый блок имеет размер шага 0.05.",
|
||||||
"t8": "Informació del producte",
|
"l19": "Если вы не уверены в скорости потока расходуемых материалов, вы можете сначала использовать крупногабаритную калибровку, чтобы получить лучший диапазон, а затем тонкую калибровку, чтобы получить более точное значение.",
|
||||||
"t9": "Contacteu amb nosaltres",
|
"l20": "После печати определите наилучшее значение на основе поверхности модели, введите 'экструзионный множитель' и сохраните.",
|
||||||
"t10": "Filament",
|
"l21": "На рисунке ниже -5 имеет наилучшее качество поверхности, поэтому оптимальный 'экструзионный множитель' составляет 0,95 (1-5%).",
|
||||||
"t11": "Afegeix text",
|
"l22": "- точная калибровка",
|
||||||
"t12": "Tallar el model",
|
"l23": "Печать калибровочных блоков в диапазоне ±0.04 на основе 'экструзионный множитель'вы ввели, каждый размер шага 0.01.",
|
||||||
"t13": "Baixa el model",
|
"l24": "Приведенный ниже 'экструзионный множитель' равен 0,95, а 1 имеет наилучшее качество поверхности, поэтому лучший 'экструзионный множитель' равен 0.96 (0.95+1%).",
|
||||||
"t14": "Malla adaptativa",
|
"l25": "Увеличение давления может уменьшить кровотечение при движениях без выдавливания и уменьшить образование пятен при прохождении поворотов.",
|
||||||
"ls0": "Aprèn més:",
|
"l26": "Когда следует калибровать давление заранее",
|
||||||
"ls1": "Podeu descarregar models 3D dels següents llocs web.",
|
"l27": "1.Используйте нити разных марок, иначе нити влажные;",
|
||||||
"ls2": "Si teniu cap pregunta sobre la impressora o QIDISlicer, poseu-vos en contacte amb nosaltres mitjançant l'adreça de correu electrònic corresponent o Skype.",
|
"l28": "2.Насадка изношена или заменена насадкой другого размера;",
|
||||||
"ls3": "Nota: proveu d'indicar-nos els vostres requisits en forma de vídeo o imatges i proporcioneu un fitxer 3MF, un fitxer de codi G, un número de màquina i altra informació necessària.",
|
"l29": "3.Используйте различные параметры печати, такие как температура и ширина линии.",
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
"l30": "Как калибровать",
|
||||||
"ls5": "Per què necessiteu el mallat adaptatiu:",
|
"l31": "Мы предоставляем три распространенных метода калибровки. Вы можете выбрать тот метод калибровки, который вам нравится.",
|
||||||
"ls6": "Com desactivar aquesta funció:",
|
"l32": "В результатах теста есть погрешность в 10%, но она практически неразличима невооруженным глазом. Выберите подходящее значение и сохраните его, а затем начните печать.",
|
||||||
"ls7": "1. Sense informació de la sonda malgastada, l'Adaptive Meshing generarà una malla només a l'àrea que realment la necessiteu: això significa que l'anivellament abans de cada impressió triga molt menys temps!",
|
"l33": "Если вам необходимо изменить параметры печати, сначала измените и сохраните параметры, а затем выполните процедуру калибровки.",
|
||||||
"ls8": "2.Com que l'àrea de la malla serà més petita, la malla pot ser molt més densa. Imagineu-vos fent una malla de 3x3, però de la mida d'un 3DBenchy! El que us ofereix una experiència d'impressió de major precisió.",
|
"l34": "После завершения печати введите наилучшее значение в программу и сохраните его.",
|
||||||
"ls9": "Afegeix ';' abans de 'G29' al codi G inicial.",
|
"l35": "Линия PA",
|
||||||
"ls10": "Zona vermella: Anivellament general de malla.",
|
"l36": "После завершения печати выберите самую плавную линию, введите соответствующее ей значение в программу и сохраните.",
|
||||||
"ls11": "Zona verda: Anivellació adaptativa de malla.",
|
"l37": "Шаблон PA",
|
||||||
},
|
"l38": "После завершения печати выберите самый плоский набор линий, введите соответствующие значения в программу и сохраните.",
|
||||||
"cs": {
|
"l39": "ПА Тауэр",
|
||||||
"t0": "Vítejte v QIDISlicer",
|
"l40": "Значение опережения давления будет меняться каждые 5 мм подъема башни PA. Измерьте высоту лучшей области модели, а затем рассчитайте соответствующее значение опережения давления на основе установленного значения шага, затем введите его в программное обеспечение и сохраните.",
|
||||||
"t1": "Uživatelská příručka",
|
|
||||||
"t2": "První výtisk",
|
|
||||||
"t3": "Přidat podporu",
|
|
||||||
"t4": "Připojit zařízení",
|
|
||||||
"t5": "Bezdrátové odesílání",
|
|
||||||
"t6": "Hlášení o problému",
|
|
||||||
"t7": "Demonstrace",
|
|
||||||
"t8": "Informace o produktu",
|
|
||||||
"t9": "Kontaktujte nás",
|
|
||||||
"t10": "Filament",
|
|
||||||
"t11": "Přidat text",
|
|
||||||
"t12": "Vyříznutý model",
|
|
||||||
"t13": "Stáhnout model",
|
|
||||||
"t14": "Adaptivní mřížka",
|
|
||||||
"ls0": "Další informace:",
|
|
||||||
"ls1": "3D modely si můžete stáhnout z následujících webových stránek.",
|
|
||||||
"ls2": "Máte-li jakékoli dotazy týkající se tiskárny nebo QIDISlicer, kontaktujte nás prosím prostřednictvím příslušné e-mailové adresy nebo Skype.",
|
|
||||||
"ls3": "Poznámka: Zkuste nám prosím sdělit své požadavky ve formě videa nebo obrázků a poskytněte soubor 3MF, soubor G-kódu, číslo stroje a další potřebné informace.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
|
||||||
"ls5": "Proč potřebujete adaptivní síťování:",
|
|
||||||
"ls6": "Jak tuto funkci zakázat:",
|
|
||||||
"ls7": "1. Žádné plýtvání informacemi ze sondy, adaptivní síťování vygeneruje síť pouze v oblasti, kde ji skutečně potřebujete: To znamená, že vyrovnání před každým tiskem zabere podstatně méně času!",
|
|
||||||
"ls8": "2. Vzhledem k tomu, že plocha sítě bude menší, může být síť mnohem hustší. Představte si, že vytvoříte síť 3x3, ale velikost 3DBenchy! Což vám přináší vyšší přesnost tisku.",
|
|
||||||
"ls9": "Přidat ';' před 'G29' v začátek G-code.",
|
|
||||||
"ls10": "Červená oblast: Obecné vyrovnání sítě.",
|
|
||||||
"ls11": "Zelená plocha: Adaptivní vyrovnání sítě.",
|
|
||||||
},
|
|
||||||
"es": {
|
|
||||||
"t0": "Bienvenido a QIDISlicer",
|
|
||||||
"t1": "Guía del usuario",
|
|
||||||
"t2": "Primera de impresión",
|
|
||||||
"t3": "Agregar soporte",
|
|
||||||
"t4": "Conectar dispositivo",
|
|
||||||
"t5": "Envío inalámbrico",
|
|
||||||
"t6": "Informe de problema",
|
|
||||||
"t7": "Demostración",
|
|
||||||
"t8": "Información del producto",
|
|
||||||
"t9": "Contacta con nosotros",
|
|
||||||
"t10": "Filamento",
|
|
||||||
"t11": "Agregar texto",
|
|
||||||
"t12": "Modelo cortado",
|
|
||||||
"t13": "Descargar Modelo",
|
|
||||||
"t14": "Malla adaptativa",
|
|
||||||
"ls0": "Aprende más:",
|
|
||||||
"ls1": "Puede descargar modelos 3D de los siguientes sitios web.",
|
|
||||||
"ls2": "Si tiene alguna pregunta sobre la impresora o QIDISlicer, comuníquese con nosotros a través de la dirección de correo electrónico correspondiente o Skype.",
|
|
||||||
"ls3": "Nota: intente decirnos sus requisitos en forma de video o imágenes, y proporcione el archivo 3MF, el archivo de código G, el número de máquina y otra información necesaria.",
|
|
||||||
"ls4": "A unique leveling solution for Klipper-enabled 3D printers!",
|
|
||||||
"ls5": "Por qué necesita Mallado adaptativo:",
|
|
||||||
"ls6": "Cómo deshabilitar esta función:",
|
|
||||||
"ls7": "1. Sin desperdiciar información de la sonda, Adaptive Meshing generará una malla solo en el área que realmente la necesita: ¡esto significa que nivelar antes de cada impresión lleva mucho menos tiempo!",
|
|
||||||
"ls8": "2. Dado que el área de la malla será más pequeña, la malla puede ser mucho más densa. ¡Imagina hacer una malla de 3x3, pero del tamaño de un 3DBenchy! Lo que le brinda una experiencia de impresión de mayor precisión.",
|
|
||||||
"ls9": "Agregar ';' antes de 'G29' en el Código G inicial.",
|
|
||||||
"ls10": "Zona roja: Nivelación general de mallas.",
|
|
||||||
"ls11": "Zona verde: Nivelación de malla adaptativa.",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,91 +16,80 @@ html, body {
|
|||||||
background-color: #F4F7FE;
|
background-color: #F4F7FE;
|
||||||
}
|
}
|
||||||
|
|
||||||
.LinkBtn {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #1200FF;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.LinkBtn:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------*/
|
|
||||||
* {
|
|
||||||
/* 页面初始化 清除元素原有的内外边距 */
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
/* 盒子模型 */
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/* 让页面占浏览器可视区域的高度 */
|
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#LeftBoard {
|
.LeftBoard {
|
||||||
/*border-right-width: 1px;
|
|
||||||
border-right-style: solid;*/
|
|
||||||
background: #414345;
|
background: #414345;
|
||||||
width:360px;
|
width:360px;
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.GuideBtn {
|
||||||
|
height: 100px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: line;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #4479FB;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.GuideBtn:hover {
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Logo {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*导航栏属性*/
|
||||||
li {
|
li {
|
||||||
/* 清除li元素前面的项目符号 */
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion {
|
.accordion {
|
||||||
/* 溢出隐藏 */
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* 圆角属性 */
|
|
||||||
border-radius: 0 8px 8px 0;
|
border-radius: 0 8px 8px 0;
|
||||||
/* 盒子阴影 */
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.6);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
.accordion > li {
|
.accordion > li {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.accordion > li input {
|
.accordion > li input {
|
||||||
/* 将单选按钮隐藏起来 */
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.accordion > li label {
|
.accordion > li label {
|
||||||
/* 相对定位 */
|
|
||||||
position: relative;
|
position: relative;
|
||||||
/* label元素是行内元素 需要将其转为块级元素 才能设置宽度和高度 */
|
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px 50px;
|
padding: 20px 50px;
|
||||||
color: #fff;
|
color: #FFFFFF;
|
||||||
background-color: #4479FB;
|
background-color: #4479FB;
|
||||||
/* 鼠标移入变小手 */
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.accordion > li label i {
|
.accordion > li label i {
|
||||||
/* 绝对定位 */
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
/* calc方法自动计算数值 让字体图标垂直居中 */
|
|
||||||
top: calc(50% - 12px);
|
top: calc(50% - 12px);
|
||||||
left: 20px;
|
left: 20px;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
/* 加过渡 */
|
|
||||||
transition: all 0.5s;
|
transition: all 0.5s;
|
||||||
}
|
}
|
||||||
.accordion > li label:hover {
|
.accordion > li label:hover {
|
||||||
border-left-color: #F1F1FF;
|
border-left-color: #FFFFFF;
|
||||||
border-left-width: 4px;
|
border-left-width: 4px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
/* :not()选择器选取的是除括号里的元素以外的其它元素 :first-child选择器是第一个元素 */
|
|
||||||
.accordion > li:not(:first-child) label {
|
.accordion > li:not(:first-child) label {
|
||||||
border-top: 1px solid #38814d;
|
border-top: 1px solid #38814D;
|
||||||
}
|
}
|
||||||
.accordion > li ol {
|
.accordion > li ol {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -135,307 +124,168 @@ li {
|
|||||||
.accordion > li input:checked ~ ol li {
|
.accordion > li input:checked ~ ol li {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
|
/*导航栏属性*/
|
||||||
|
|
||||||
#GuideArea {
|
.MenuBtn {
|
||||||
/*border-bottom-width:1px;
|
height: 50px;
|
||||||
border-bottom-style:inset;*/
|
|
||||||
height: 100px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: line;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#Guide1 {
|
|
||||||
height: 36px;
|
|
||||||
line-height: 36px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#GuideBtn {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
color: #FFFFFF;
|
||||||
|
transition: all 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuBtn:hover {
|
||||||
color: #4479FB;
|
color: #4479FB;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TbItem {
|
.MenuBtnSelected {
|
||||||
font-size: 24px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #4479FB
|
|
||||||
}
|
|
||||||
|
|
||||||
.TbItem:hover {
|
|
||||||
font-size: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.TbItemSelected {
|
|
||||||
}
|
|
||||||
|
|
||||||
#Icon1 {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#QDIcon {
|
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*------------------*/
|
|
||||||
#BtnArea {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.BtnItem {
|
|
||||||
padding-left: 30px;
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
text-indent: 10px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
|
||||||
transition: all 0.5s;
|
|
||||||
}
|
|
||||||
.BtnItem:hover {
|
|
||||||
color: #4479FB
|
|
||||||
}
|
|
||||||
|
|
||||||
.BtnItemSelected {
|
|
||||||
background-color: #CED1D9;
|
background-color: #CED1D9;
|
||||||
color: #4479FB
|
color: #4479FB;
|
||||||
}
|
}
|
||||||
|
|
||||||
.BtnIcon {
|
.MenuBtnIcon {
|
||||||
margin-left: 15px;
|
margin: auto 15px;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.BookIcon {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MainIcon {
|
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.LeftIcon {
|
.RightBoard {
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------*/
|
|
||||||
#RightBoard {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 835px;
|
min-width: 700px;
|
||||||
|
padding: 0px 50px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ThumbBoard
|
.GuideBoard {
|
||||||
{
|
margin-top: 20px;
|
||||||
overflow-y:auto;
|
|
||||||
padding: 0px 40px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-content: flex-start;
|
|
||||||
margin: 30px 40px;
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1100px) {
|
.Thumbnail {
|
||||||
.GuideBlock {
|
min-width: 300px;
|
||||||
width: calc(50% - 20px);
|
max-width: 600px;
|
||||||
margin: 0px 10px 40px 10px;
|
width: 23%;
|
||||||
cursor: pointer;
|
margin: 10px auto;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:1101px) and ( max-width:1680px ) {
|
|
||||||
.GuideBlock {
|
|
||||||
width: calc(33% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:1681px) and (max-width:2120px ) {
|
|
||||||
.GuideBlock {
|
|
||||||
width: calc(25% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:2121px) and (max-width:2620px ) {
|
|
||||||
.GuideBlock {
|
|
||||||
width: calc(20% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width:2621px ) and (max-width:3120px ) {
|
|
||||||
.GuideBlock {
|
|
||||||
width: calc(16.6% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width:3121px ) {
|
|
||||||
.GuideBlock {
|
|
||||||
width: calc(14.2% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#IssueBoard {
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 0px 40px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: column;
|
||||||
justify-content: center;
|
cursor: pointer;
|
||||||
align-items: center;
|
|
||||||
margin: 30px 40px;
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen{
|
.ThumbnailTitle {
|
||||||
.halfBlock {
|
text-align: center;
|
||||||
text-align: center;
|
font-size: 18px;
|
||||||
justify-content: center;
|
font-weight: 700;
|
||||||
width: calc(50% - 20px);
|
width: 100%;
|
||||||
margin: 0px 10px;
|
color: #4479FB;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1100px) {
|
.ImageBoard {
|
||||||
.PrintBlock {
|
margin: 50px auto;
|
||||||
text-align:center;
|
|
||||||
width: calc(50% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:1101px) and ( max-width:1680px ) {
|
|
||||||
.PrintBlock {
|
|
||||||
width: calc(33% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:1681px) and (max-width:2120px ) {
|
|
||||||
.PrintBlock {
|
|
||||||
width: calc(25% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and ( min-width:2121px) and (max-width:2620px ) {
|
|
||||||
.PrintBlock {
|
|
||||||
width: calc(20% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width:2621px ) and (max-width:3120px ) {
|
|
||||||
.PrintBlock {
|
|
||||||
width: calc(16.6% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width:3121px ) {
|
|
||||||
.PrintBlock {
|
|
||||||
width: calc(14.2% - 20px);
|
|
||||||
margin: 0px 10px 40px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#FilaBigBoard {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#FilaBoard {
|
.AutozoomImage img {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #4479FB;
|
||||||
|
margin: 20px auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
left: 0px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.IntroduceBoard {
|
||||||
margin: 50px 50px;
|
margin: 50px auto;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IntroduceTitle {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 30px 0;
|
||||||
|
color: #4479FB;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IntroduceText {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IntroduceTextBold {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CenterImage img{
|
||||||
|
margin: 20px auto;
|
||||||
|
max-width: 1200px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #4479FB;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IntroduceTextRed {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #ED1C24;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IntroduceTextGreen {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #24AB4D;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FilamentsTable {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*表格属性*/
|
||||||
td, th {
|
td, th {
|
||||||
/* 设置td,th宽度高度 */
|
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
background-color: #4F6EBC;
|
background-color: #4F6EBC;
|
||||||
color: #fff;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: 200px; /* 固定宽度 */
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td:first-child, th:first-child {
|
td:first-child, th:first-child {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
left: 0; /* 首行永远固定在左侧 */
|
left: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: #CDDBFB;
|
background: #CDDBFB;
|
||||||
}
|
}
|
||||||
|
|
||||||
th:nth-child(odd) { /*奇表头*/
|
th:nth-child(odd) {
|
||||||
background-color: #6993FB;
|
background-color: #6993FB;
|
||||||
}
|
}
|
||||||
|
|
||||||
thead tr th {
|
thead tr th {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0; /* 列首永远固定在头部 */
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody tr:nth-child(odd) {
|
tbody tr:nth-child(odd) {
|
||||||
@@ -445,121 +295,22 @@ tbody tr:nth-child(odd) {
|
|||||||
th:first-child {
|
th:first-child {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
/*表格属性*/
|
||||||
|
|
||||||
/*------Gif------*/
|
.IssueBoard {
|
||||||
#GifBigBoard {
|
margin-top: 20px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#GifBoard {
|
.EmailBlock {
|
||||||
|
margin: 10px auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
|
||||||
align-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow-y: auto;
|
flex-wrap: wrap;
|
||||||
margin: 30px 40px;
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen {
|
.PrinterBlock {
|
||||||
.GifBlock {
|
margin: 0 10px;
|
||||||
margin: 0px 0px 0px 0px;
|
display: flex;
|
||||||
cursor: pointer;
|
flex-direction: column;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.UG_PRINTER {
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_PRINTER img {
|
|
||||||
width: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_IMG {
|
|
||||||
justify-content:center;
|
|
||||||
text-align:center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_IMG img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 5px 5px 5px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_TITLE {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 25px;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
color: #4479FB;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_DESC {
|
|
||||||
font-size: 14px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_DESC_RED {
|
|
||||||
font-size: 14px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #ED1C24;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_DESC_GREEN {
|
|
||||||
font-size: 14px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #24AB4D;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_CDESC {
|
|
||||||
margin-top:35px;
|
|
||||||
margin-bottom:5px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 24px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_B_TITLE {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 36px;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 25px;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
color: #4479FB;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_B_DESC {
|
|
||||||
font-size: 16px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_AMB_DESC {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 700;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.UG_AM_DESC {
|
|
||||||
font-size: 16px;
|
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
BIN
resources/web/guide/img/FlowrateCoarse.gif
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
resources/web/guide/img/FlowrateCoarse.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
resources/web/guide/img/FlowrateCompare.png
Normal file
|
After Width: | Height: | Size: 624 KiB |
BIN
resources/web/guide/img/FlowrateFine.gif
Normal file
|
After Width: | Height: | Size: 4.1 MiB |
BIN
resources/web/guide/img/FlowrateFine.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
resources/web/guide/img/FlowrateValue.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
resources/web/guide/img/MakerWorld.png
Normal file
|
After Width: | Height: | Size: 1020 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
resources/web/guide/img/PressureAdvance.gif
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
resources/web/guide/img/PressureAdvanceCompare.png
Normal file
|
After Width: | Height: | Size: 480 KiB |
BIN
resources/web/guide/img/PressureAdvanceLine.png
Normal file
|
After Width: | Height: | Size: 813 KiB |
BIN
resources/web/guide/img/PressureAdvancePattern.png
Normal file
|
After Width: | Height: | Size: 758 KiB |
BIN
resources/web/guide/img/PressureAdvanceTower.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
resources/web/guide/img/PressureAdvanceValue.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
resources/web/guide/img/X-MAX 3.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 721 KiB After Width: | Height: | Size: 721 KiB |
BIN
resources/web/guide/img/X-Plus 3.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 460 KiB After Width: | Height: | Size: 460 KiB |
|
Before Width: | Height: | Size: 131 KiB |
BIN
resources/web/guide/img/X-smart 3.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 502 KiB After Width: | Height: | Size: 502 KiB |
@@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1687913925905" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8764" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M264.153704 952.655092 64.311213 952.655092 64.311213 224.110197l199.843514 0L264.154727 952.655092 264.153704 952.655092zM229.954811 261.241886 98.815051 261.241886l0 67.14219 131.139759 0L229.954811 261.241886 229.954811 261.241886zM326.469981 64.541969l198.266599 0 0 888.044562L326.469981 952.58653 326.469981 64.541969 326.469981 64.541969zM495.458767 98.756211 360.142895 98.756211l0 69.234851 135.314849 0L495.457744 98.756211 495.458767 98.756211zM954.857758 892.768143l-190.012611 61.911048-225.718835-692.706665 190.010565-61.911048L954.857758 892.768143 954.857758 892.768143zM708.125331 245.963924 583.437517 286.590204l20.798698 63.833841 124.685767-40.627303L708.125331 245.963924 708.125331 245.963924zM708.125331 245.963924" fill="#4479FB" p-id="8765"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -2,496 +2,492 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="Cache-Control" content="max-age=7200" />
|
<meta http-equiv="Cache-Control" content="max-age=7200"/>
|
||||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
|
||||||
<title>homepage</title>
|
<title>homepage</title>
|
||||||
<link rel="stylesheet" type="text/css" href="css/font-awesome.min.css" />
|
<link rel="stylesheet" type="text/css" href="css/font-awesome.min.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="css/home.css" />
|
<link rel="stylesheet" type="text/css" href="css/home.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="css/dark.css" />
|
<link rel="stylesheet" type="text/css" href="css/dark.css"/>
|
||||||
<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
|
<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
|
||||||
<script type="text/javascript" src="../data/text.js"></script>
|
<script type="text/javascript" src="../data/text.js"></script>
|
||||||
<script type="text/javascript" src="js/json2.js"></script>
|
<script type="text/javascript" src="js/json2.js"></script>
|
||||||
<script type="text/javascript" src="js/globalapi.js"></script>
|
<script type="text/javascript" src="js/globalapi.js"></script>
|
||||||
<script type="text/javascript" src="js/home.js"></script>
|
<script type="text/javascript" src="js/home.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="ZScrol" onLoad="OnInit()">
|
|
||||||
<div id="LeftBoard">
|
<body onLoad="OnInit()">
|
||||||
<div id="GuideArea">
|
<div class="LeftBoard">
|
||||||
<div id="Guide1">
|
<div menu="UserGuide" class="GuideBtn" onClick="GotoMenu('UserGuide')">
|
||||||
<div id="Icon1"><img id="QDIcon" src="img/logo.png" /></div>
|
<div class="Logo"><img src="img/logo.png"/></div>
|
||||||
<div menu="userguide" class="TbItem" onClick="GotoMain('userguide');">
|
<div class="trans" tid="t1"></div>
|
||||||
<div class="trans" tid="t1">UserGuide</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<ul class="accordion">
|
<ul class="accordion">
|
||||||
<li>
|
<li>
|
||||||
<input type="radio" name="item" id="item1" />
|
<input type="radio" name="GuideMenu" id="GuideMenu1"/>
|
||||||
<label for="item1">
|
<label for="GuideMenu1">
|
||||||
<a class="trans" tid="t7"></a>
|
<a class="trans" tid="t7"></a>
|
||||||
<i class="fa fa-caret-right"></i>
|
<i class="fa fa-caret-right"></i>
|
||||||
</label>
|
</label>
|
||||||
<ol>
|
<ol>
|
||||||
<li menu="firstprint" class="BtnItem" onClick="GotoMenu('firstprint')">
|
<li menu="FirstPrint" class="MenuBtn" onClick="GotoMenu('FirstPrint')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t2">UserGuide</div>
|
<div class="trans" tid="t2"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="addsupport" class="BtnItem" onClick="GotoMenu('addsupport')">
|
<li menu="AddSupport" class="MenuBtn" onClick="GotoMenu('AddSupport')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t3">UserGuide</div>
|
<div class="trans" tid="t3"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="wifisend" class="BtnItem" onClick="GotoMenu('wifisend')">
|
<li menu="WifiSend" class="MenuBtn" onClick="GotoMenu('WifiSend')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t5">UserGuide</div>
|
<div class="trans" tid="t5"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="connectdevice" class="BtnItem" onClick="GotoMenu('connectdevice')">
|
<li menu="ConnectDevice" class="MenuBtn" onClick="GotoMenu('ConnectDevice')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t4">UserGuide</div>
|
<div class="trans" tid="t4"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="addtext" class="BtnItem" onClick="GotoMenu('addtext')">
|
<li menu="AddText" class="MenuBtn" onClick="GotoMenu('AddText')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t11">UserGuide</div>
|
<div class="trans" tid="t11"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="cutmodel" class="BtnItem" onClick="GotoMenu('cutmodel')">
|
<li menu="CutModel" class="MenuBtn" onClick="GotoMenu('CutModel')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t12">UserGuide</div>
|
<div class="trans" tid="t12"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="admeshing" class="BtnItem" onClick="GotoMenu('admeshing')">
|
<li menu="AdaptiveMeshing" class="MenuBtn" onClick="GotoMenu('AdaptiveMeshing')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t14">UserGuide</div>
|
<div class="trans" tid="t14"></div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="downloadm" class="BtnItem" onClick="GotoMenu('downloadm')">
|
<li menu="ModelDownload" class="MenuBtn" onClick="GotoMenu('ModelDownload')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t13">UserGuide</div>
|
<div class="trans" tid="t13"></div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<input type="radio" name="item" id="item2" />
|
<input type="radio" name="GuideMenu" id="GuideMenu2"/>
|
||||||
<label for="item2">
|
<label for="GuideMenu2">
|
||||||
|
<a class="trans" tid="t16"></a>
|
||||||
|
<i class="fa fa-caret-right"></i>
|
||||||
|
</label>
|
||||||
|
<ol>
|
||||||
|
<li menu="Flowrate" class="MenuBtn" onClick="GotoMenu('Flowrate')">
|
||||||
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
|
<div class="trans" tid="t15"></div>
|
||||||
|
</li>
|
||||||
|
<li menu="PressureAdvance" class="MenuBtn" onClick="GotoMenu('PressureAdvance')">
|
||||||
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
|
<div class="trans" tid="t17"></div>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<input type="radio" name="GuideMenu" id="GuideMenu3"/>
|
||||||
|
<label for="GuideMenu3">
|
||||||
<a class="trans" tid="t8"></a>
|
<a class="trans" tid="t8"></a>
|
||||||
<i class="fa fa-caret-right"></i>
|
<i class="fa fa-caret-right"></i>
|
||||||
</label>
|
</label>
|
||||||
<ol>
|
<ol>
|
||||||
<li menu="infomax3" class="BtnItem" onClick="GotoMenu('infomax3')">
|
<li menu="X-MAX 3" class="MenuBtn" onClick="GotoMenu('X-MAX 3')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="TextS1">X-MAX 3</div>
|
<div>X-MAX 3</div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="infoplus3" class="BtnItem" onClick="GotoMenu('infoplus3')">
|
<li menu="X-Plus 3" class="MenuBtn" onClick="GotoMenu('X-Plus 3')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="TextS1">X-Plus 3</div>
|
<div>X-Plus 3</div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="infosmart3" class="BtnItem" onClick="GotoMenu('infosmart3')">
|
<li menu="X-smart 3" class="MenuBtn" onClick="GotoMenu('X-smart 3')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="TextS1">X-Smart 3</div>
|
<div>X-Smart 3</div>
|
||||||
</li>
|
</li>
|
||||||
<li menu="infof1" class="BtnItem" onClick="GotoMenu('infof1')">
|
<li menu="Filaments" class="MenuBtn" onClick="GotoMenu('Filaments')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t10">FInfo</div>
|
<div class="trans" tid="t10"></div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<input type="radio" name="item" id="item3" />
|
<input type="radio" name="GuideMenu" id="GuideMenu4"/>
|
||||||
<label for="item3">
|
<label for="GuideMenu4">
|
||||||
<a class="trans" tid="t9"></a>
|
<a class="trans" tid="t9"></a>
|
||||||
<i class="fa fa-caret-right"></i>
|
<i class="fa fa-caret-right"></i>
|
||||||
</label>
|
</label>
|
||||||
<ol>
|
<ol>
|
||||||
<li menu="issuereport" class="BtnItem" onClick="GotoMenu('issuereport')">
|
<li menu="IssueReport" class="MenuBtn" onClick="GotoMenu('IssueReport')">
|
||||||
<div class="BtnIcon "><img class="LeftIcon" src="img/i1.svg" /></div>
|
<div class="MenuBtnIcon"><img src="img/MenuBtnIcon.svg"/></div>
|
||||||
<div class="trans" tid="t6">UserGuide</div>
|
<div class="trans" tid="t6"></div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="RightBoard">
|
|
||||||
<div id="ThumbBoard" class="ZScrol" board="userguide">
|
<div class="RightBoard">
|
||||||
<div class="GuideBlock" onClick="GotoMenu('firstprint');">
|
<div class="GuideBoard" board="UserGuide">
|
||||||
<div class="UG_IMG"><img src="img/FirstPrint.gif" /></div>
|
<div class="Thumbnail" onClick="GotoMenu('FirstPrint')">
|
||||||
<div class="UG_TITLE trans TextS1" tid="t2">FirstPrint</div>
|
<div class="AutozoomImage"><img src="img/FirstPrint.gif"/></div>
|
||||||
|
<div class="ThumbnailTitle trans" tid="t2"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('addsupport');">
|
<div class="Thumbnail" onClick="GotoMenu('AddSupport')">
|
||||||
<div class="UG_IMG"><img src="img/AddSupport.gif" /></div>
|
<div class="AutozoomImage"><img src="img/AddSupport.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t3">AddSupport</div>
|
<div class="ThumbnailTitle trans" tid="t3"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('wifisend');">
|
<div class="Thumbnail" onClick="GotoMenu('WifiSend')">
|
||||||
<div class="UG_IMG"><img src="img/WifiSend.gif" /></div>
|
<div class="AutozoomImage"><img src="img/WifiSend.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t5">WifiSend</div>
|
<div class="ThumbnailTitle trans" tid="t5"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('connectdevice');">
|
<div class="Thumbnail" onClick="GotoMenu('ConnectDevice')">
|
||||||
<div class="UG_IMG"><img src="img/ConnectDevice.gif" /></div>
|
<div class="AutozoomImage"><img src="img/ConnectDevice.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t4">ConnectDevice</div>
|
<div class="ThumbnailTitle trans" tid="t4"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('addtext');">
|
<div class="Thumbnail" onClick="GotoMenu('AddText')">
|
||||||
<div class="UG_IMG"><img src="img/AddText.gif" /></div>
|
<div class="AutozoomImage"><img src="img/AddText.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t11">AddText</div>
|
<div class="ThumbnailTitle trans" tid="t11"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('cutmodel');">
|
<div class="Thumbnail" onClick="GotoMenu('CutModel')">
|
||||||
<div class="UG_IMG"><img src="img/CutModel.gif" /></div>
|
<div class="AutozoomImage"><img src="img/CutModel.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t12">CutModel</div>
|
<div class="ThumbnailTitle trans" tid="t12"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('admeshing');">
|
<div class="Thumbnail" onClick="GotoMenu('AdaptiveMeshing')">
|
||||||
<div class="UG_IMG"><img src="img/AMPNG.png" /></div>
|
<div class="AutozoomImage"><img src="img/AdaptiveMeshingThumbnail.png"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t14">AddText</div>
|
<div class="ThumbnailTitle trans" tid="t14"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('downloadm');">
|
<div class="Thumbnail" onClick="GotoMenu('ModelDownload')">
|
||||||
<div class="UG_IMG"><img src="img/DownloadModel.png" /></div>
|
<div class="AutozoomImage"><img src="img/DownloadModel.png"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t13">AddText</div>
|
<div class="ThumbnailTitle trans" tid="t13"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="GuideBlock" onClick="GotoMenu('issuereport');">
|
<div class="Thumbnail" onClick="GotoMenu('Flowrate')">
|
||||||
<div class="UG_IMG"><img src="img/IssueReport.png" /></div>
|
<div class="AutozoomImage"><img src="img/FlowrateCoarse.gif"/></div>
|
||||||
<div class="UG_TITLE trans TextS1" tid="t6">IssueReport</div>
|
<div class="ThumbnailTitle trans" tid="t15"></div>
|
||||||
|
</div>
|
||||||
|
<div class="Thumbnail" onClick="GotoMenu('PressureAdvance')">
|
||||||
|
<div class="AutozoomImage"><img src="img/PressureAdvance.gif"/></div>
|
||||||
|
<div class="ThumbnailTitle trans" tid="t17"></div>
|
||||||
|
</div>
|
||||||
|
<div class="Thumbnail" onClick="GotoMenu('IssueReport')">
|
||||||
|
<div class="AutozoomImage"><img src="img/IssueReport.png"/></div>
|
||||||
|
<div class="ThumbnailTitle trans" tid="t6"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="GifBigBoard" board="firstprint">
|
<div class="ImageBoard" board="FirstPrint">
|
||||||
<div id="GifBoard">
|
<div class="IntroduceTitle trans" tid="t2"></div>
|
||||||
<div class="GifBlock">
|
<div class="AutozoomImage"><img src="img/FirstPrint.gif"/></div>
|
||||||
<div class="UG_IMG"><img src="img/FirstPrint.gif" /></div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="ImageBoard" board="AddSupport">
|
||||||
|
<div class="IntroduceTitle trans" tid="t3"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/AddSupport.gif"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ImageBoard" board="ConnectDevice">
|
||||||
|
<div class="IntroduceTitle trans" tid="t5"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/ConnectDevice.gif"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ImageBoard" board="WifiSend">
|
||||||
|
<div class="IntroduceTitle trans" tid="t4"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/WifiSend.gif"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ImageBoard" board="AddText">
|
||||||
|
<div class="IntroduceTitle trans" tid="t11"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/AddText.gif"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ImageBoard" board="CutModel">
|
||||||
|
<div class="IntroduceTitle trans" tid="t12"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/CutModel.gif"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="AdaptiveMeshing">
|
||||||
|
<div class="IntroduceTitle trans" tid="t14"></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l5"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l7"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l8"></div>
|
||||||
|
<div class="CenterImage"><img src="img/AdaptiveMeshing.png"/></div>
|
||||||
|
<div class="IntroduceTextRed trans" tid="l10"></div>
|
||||||
|
<div class="IntroduceTextGreen trans" tid="l11"></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l6"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l9"></div>
|
||||||
|
<div class="CenterImage"><img src="img/DisableAM.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l0"></div>
|
||||||
|
<div class="IntroduceText">https://github.com/kyleisah/Klipper-Adaptive-Meshing-Purging#key-features</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="ModelDownload">
|
||||||
|
<div class="IntroduceTitle trans" tid="t13"></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l1"></div>
|
||||||
|
<div class="IntroduceText">https://makerworld.com</div>
|
||||||
|
<div class="AutozoomImage"><img src="img/MakerWorld.png"/></div>
|
||||||
|
<div class="IntroduceText">https://www.thingiverse.com</div>
|
||||||
|
<div class="AutozoomImage"><img src="img/thingiverse.png"/></div>
|
||||||
|
<div class="IntroduceText">https://www.printables.com/model</div>
|
||||||
|
<div class="AutozoomImage"><img src="img/printables.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="Flowrate">
|
||||||
|
<div class="IntroduceTitle trans" tid="t15"></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l12"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l13"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l14"></div>
|
||||||
|
<div class="CenterImage"><img src="img/FlowrateValue.png"/></div>
|
||||||
|
<div class="IntroduceText trans" tid="l15"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l16"></div>
|
||||||
|
<div class="CenterImage"><img src="img/FlowrateCompare.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l17"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l18"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l19"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l20"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/FlowrateCoarse.gif"/></div>
|
||||||
|
<div class="IntroduceText trans" tid="l21"></div>
|
||||||
|
<div class="CenterImage"><img src="img/FlowrateCoarse.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l22"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l23"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l20"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/FlowrateFine.gif"/></div>
|
||||||
|
<div class="IntroduceText trans" tid="l24"></div>
|
||||||
|
<div class="CenterImage"><img src="img/FlowrateFine.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="PressureAdvance">
|
||||||
|
<div class="IntroduceTitle trans" tid="t17"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l25"></div>
|
||||||
|
<div class="CenterImage"><img src="img/PressureAdvanceCompare.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l26"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l27"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l28"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l29"></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l30"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l31"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l32"></div>
|
||||||
|
<div class="AutozoomImage"><img src="img/PressureAdvance.gif"/></div>
|
||||||
|
<div class="IntroduceText trans" tid="l33"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l34"></div>
|
||||||
|
<div class="CenterImage"><img src="img/PressureAdvanceValue.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l35"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l36"></div>
|
||||||
|
<div class="CenterImage"><img src="img/PressureAdvanceLine.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l37"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l38"></div>
|
||||||
|
<div class="CenterImage"><img src="img/PressureAdvancePattern.png"/></div>
|
||||||
|
<div class="IntroduceTextBold trans" tid="l39"></div>
|
||||||
|
<div class="IntroduceText trans" tid="l40"></div>
|
||||||
|
<div class="CenterImage"><img src="img/PressureAdvanceTower.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="X-MAX 3">
|
||||||
|
<div class="AutozoomImage"><img src="img/X-MAX3Poster.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="X-Plus 3">
|
||||||
|
<div class="AutozoomImage"><img src="img/X-Plus3Poster.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="X-smart 3">
|
||||||
|
<div class="AutozoomImage"><img src="img/X-smart3Poster.png"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="IntroduceBoard" board="Filaments">
|
||||||
|
<div class="FilamentsTable">
|
||||||
|
<table cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Filament</th>
|
||||||
|
<th>Drying box</th>
|
||||||
|
<th>Anneal</th>
|
||||||
|
<th>Water resistance</th>
|
||||||
|
<th>Corrosion resistance</th>
|
||||||
|
<th>Creep resistance</th>
|
||||||
|
<th>HDT 0.45</th>
|
||||||
|
<th>HDT 1.80</th>
|
||||||
|
<th>Tensile strength(MPa)</th>
|
||||||
|
<th>Tensile modulus(MPa)</th>
|
||||||
|
<th>Elongation at break(%)</th>
|
||||||
|
<th>Flexural strength(MPa)</th>
|
||||||
|
<th>Flexural modulus(MPa)</th>
|
||||||
|
<th>Notch impact strength(KJ/㎡)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>ToughPETG</td>
|
||||||
|
<td>≤20%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>78℃</td>
|
||||||
|
<td>73℃</td>
|
||||||
|
<td>40.3±0.6</td>
|
||||||
|
<td>1780±80</td>
|
||||||
|
<td>4.0±0.2</td>
|
||||||
|
<td>62.8±0.4</td>
|
||||||
|
<td>1919±54</td>
|
||||||
|
<td>13.9±2.3</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>UltraABS-GF25</td>
|
||||||
|
<td>≤30%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>97℃</td>
|
||||||
|
<td>93℃</td>
|
||||||
|
<td>48.48 ± 0.61</td>
|
||||||
|
<td>3752.13 ± 68.39</td>
|
||||||
|
<td>2.10 ± 0.10</td>
|
||||||
|
<td>78.80 ± 1.26</td>
|
||||||
|
<td>3531.71 ± 75.79</td>
|
||||||
|
<td>8.91 ± 0.63</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>ABS Rapido</td>
|
||||||
|
<td>≤30%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>85℃</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>41 ± 1</td>
|
||||||
|
<td>3850 ± 150</td>
|
||||||
|
<td>11 ± 1</td>
|
||||||
|
<td>77.5 ± 2.5</td>
|
||||||
|
<td>77.5 ± 2.5</td>
|
||||||
|
<td>20 ± 2</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>PA12-CF</td>
|
||||||
|
<td>≤15%</td>
|
||||||
|
<td>80-100℃</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>149.6℃</td>
|
||||||
|
<td>112.4℃</td>
|
||||||
|
<td>87.49 ± 2.81</td>
|
||||||
|
<td>5438.40 ± 282.82</td>
|
||||||
|
<td>2.59 ± 0.19</td>
|
||||||
|
<td>133.17 ± 4.66</td>
|
||||||
|
<td>4667.43 ± 339.80</td>
|
||||||
|
<td>6.11 ± 1.45</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>PATH-CF</td>
|
||||||
|
<td>≤15%</td>
|
||||||
|
<td>80-100℃</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>192.3℃</td>
|
||||||
|
<td>121.7℃</td>
|
||||||
|
<td>104.90 ± 1.99</td>
|
||||||
|
<td>8383.26 ± 419.53</td>
|
||||||
|
<td>1.60 ± 0.07</td>
|
||||||
|
<td>147.70 ± 4.09</td>
|
||||||
|
<td>5969.35 ± 145.28</td>
|
||||||
|
<td>6.17 ± 0.2</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>PET-CF</td>
|
||||||
|
<td>≤15%</td>
|
||||||
|
<td>80-100℃</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>+++</td>
|
||||||
|
<td>148.8℃</td>
|
||||||
|
<td>112.1℃</td>
|
||||||
|
<td>87.41 ± 3.57</td>
|
||||||
|
<td>6025.53 ± 355.46</td>
|
||||||
|
<td>1.99 ±0.18</td>
|
||||||
|
<td>122.69 ± 5.19</td>
|
||||||
|
<td>5313.21 ± 197.89</td>
|
||||||
|
<td>5.57 ± 0.58</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>PLA Rapido</td>
|
||||||
|
<td>≤30%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>57℃</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>39 ± 3</td>
|
||||||
|
<td>4650 ± 150</td>
|
||||||
|
<td>12.5 ± 2.5</td>
|
||||||
|
<td>72.5 ± 2.5</td>
|
||||||
|
<td>2850 ± 150</td>
|
||||||
|
<td>6 ± 2</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>PLA Rapido Matte</td>
|
||||||
|
<td>≤30%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>+</td>
|
||||||
|
<td>58℃</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>39 ± 3</td>
|
||||||
|
<td>2400 ± 200</td>
|
||||||
|
<td>3 ± 1</td>
|
||||||
|
<td>77.5 ± 2.5</td>
|
||||||
|
<td>2200 ± 200</td>
|
||||||
|
<td>7.5 ± 1.5</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="(item, index) in 1" :key="index">
|
||||||
|
<td>UltraPA</td>
|
||||||
|
<td>≤15%</td>
|
||||||
|
<td>/</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>++</td>
|
||||||
|
<td>77.8℃</td>
|
||||||
|
<td>73.1℃</td>
|
||||||
|
<td>86.15 ± 0.56</td>
|
||||||
|
<td>3609.22 ± 153.31</td>
|
||||||
|
<td>11.68 ± 3.36</td>
|
||||||
|
<td>121.47 ± 3.14</td>
|
||||||
|
<td>3314.03 ±181.88</td>
|
||||||
|
<td>5.78 ± 0.30</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="GifBigBoard" board="addsupport">
|
<div class="IssueBoard" board="IssueReport">
|
||||||
<div id="GifBoard">
|
<div class="IntroduceTitle trans" tid="t6"></div>
|
||||||
<div class="GifBlock">
|
<div class="IntroduceText trans" tid="l2"></div>
|
||||||
<div class="UG_IMG"><img src="img/AddSupport.gif" /></div>
|
<div class="IntroduceText trans" tid="l3"></div>
|
||||||
</div>
|
<div class="EmailBlock">
|
||||||
</div>
|
<div class="PrinterBlock">
|
||||||
</div>
|
<div class="CenterImage"><img src="img/X-MAX 3.png"/></div>
|
||||||
|
<div class="ThumbnailTitle">X-MAX 3</div>
|
||||||
<div id="GifBigBoard" board="connectdevice">
|
<div class="IntroduceText">
|
||||||
<div id="GifBoard">
|
<b>E-mail:</b><br/>MAX3support@qd3dprinter.com<br>MAX3AMS@qd3dprinter.com<br/><br>
|
||||||
<div class="GifBlock">
|
<b>Skype:</b><br/>MAX3support@qd3dprinter.com
|
||||||
<div class="UG_IMG"><img src="img/ConnectDevice.gif" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="wifisend">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/WifiSend.gif" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="addtext">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/AddText.gif" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="cutmodel">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/CutModel.gif" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="admeshing">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_B_TITLE trans TextS1" tid="t14">AdaptiveMeshing</div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>
|
|
||||||
<div class="UG_AMB_DESC trans" tid="ls5"></div>
|
|
||||||
<div class="UG_AM_DESC trans" tid="ls7"></div>
|
|
||||||
<div class="UG_AM_DESC trans" tid="ls8"></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/AdaptiveMeshing.png" /></div>
|
|
||||||
<a class="UG_DESC_RED trans" tid="ls10"></a>
|
|
||||||
<a class="UG_DESC_GREEN trans" tid="ls11"></a>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>
|
|
||||||
<div class="UG_AMB_DESC trans" tid="ls6"></div>
|
|
||||||
<div class="UG_AM_DESC trans" tid="ls9"></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/DisableAM.png" /></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>
|
|
||||||
<div class="UG_AMB_DESC trans" tid="ls0"></div>
|
|
||||||
<div class="UG_AM_DESC">URL:https://github.com/kyleisah/Klipper-Adaptive-Meshing-Purging#key-features</div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
<!--<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/AdaptiveMeshing.png" /></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_AMB_DESC trans" tid="ls7"></div>
|
|
||||||
<div class="UG_AM_DESC trans" tid="ls10"></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/DisableAM.png" /></div>
|
|
||||||
<div class="UG_CDESC"> </div>
|
|
||||||
</div>-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="downloadm">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_B_TITLE trans TextS1" tid="t13">download</div>
|
|
||||||
<div class="UG_CDESC trans" tid="ls1"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="IssueBoard">
|
|
||||||
<div class="halfBlock">
|
|
||||||
<div class="UG_DESC">URL:https://www.thingiverse.com/</div>
|
|
||||||
<div class="UG_IMG"><img src="img/thingiverse.png" /></div>
|
|
||||||
</div>
|
|
||||||
<div class="halfBlock">
|
|
||||||
<div class="UG_DESC">URL:https://www.printables.com/model</div>
|
|
||||||
<div class="UG_IMG"><img src="img/printables.png" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--<div id="GifBigBoard" board="downloadm">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_B_TITLE trans" tid="t13">downloadm</div>
|
|
||||||
</div>
|
|
||||||
<div id="IssueBoard">
|
|
||||||
<div class="halfBlock">
|
|
||||||
<div class="UG_CDESC">URL:https://www.thingiverse.com/</div>
|
|
||||||
<div class="UG_IMG"><img src="img/thingiverse.png" /></div>
|
|
||||||
<div class="UG_CDESC">URL:https://www.printables.com/model</div>
|
|
||||||
<div class="UG_IMG"><img src="img/printables.png" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="infomax3">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="UG_IMG"><img src="img/info1.png" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="infoplus3">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="UG_IMG"><img src="img/info2.png" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="infosmart3">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="UG_IMG"><img src="img/info3.png" /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="FilaBigBoard" board="infof1">
|
|
||||||
<div id="FilaBoard">
|
|
||||||
<div class="main">
|
|
||||||
<table cellspacing="0">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Filament</th>
|
|
||||||
<th>Drying box</th>
|
|
||||||
<th>Anneal</th>
|
|
||||||
<th>Water resistance</th>
|
|
||||||
<th>Corrosion resistance</th>
|
|
||||||
<th>Creep resistance</th>
|
|
||||||
<th>HDT 0.45</th>
|
|
||||||
<th>HDT 1.80</th>
|
|
||||||
<th>Tensile strength(MPa)</th>
|
|
||||||
<th>Tensile modulus(MPa)</th>
|
|
||||||
<th>Elongation at break(%)</th>
|
|
||||||
<th>Flexural strength(MPa)</th>
|
|
||||||
<th>Flexural modulus(MPa)</th>
|
|
||||||
<th>Notch impact strength(KJ/㎡)</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>ToughPETG</td>
|
|
||||||
<td>≤20%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>78℃</td>
|
|
||||||
<td>73℃</td>
|
|
||||||
<td>40.3±0.6</td>
|
|
||||||
<td>1780±80</td>
|
|
||||||
<td>4.0±0.2</td>
|
|
||||||
<td>62.8±0.4</td>
|
|
||||||
<td>1919±54</td>
|
|
||||||
<td>13.9±2.3</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>UltraABS-GF25</td>
|
|
||||||
<td>≤30%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>97℃</td>
|
|
||||||
<td>93℃</td>
|
|
||||||
<td>48.48 ± 0.61</td>
|
|
||||||
<td>3752.13 ± 68.39</td>
|
|
||||||
<td>2.10 ± 0.10</td>
|
|
||||||
<td>78.80 ± 1.26</td>
|
|
||||||
<td>3531.71 ± 75.79</td>
|
|
||||||
<td>8.91 ± 0.63</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>ABS Rapido</td>
|
|
||||||
<td>≤30%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>85℃</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>41 ± 1</td>
|
|
||||||
<td>3850 ± 150</td>
|
|
||||||
<td>11 ± 1</td>
|
|
||||||
<td>77.5 ± 2.5</td>
|
|
||||||
<td>77.5 ± 2.5</td>
|
|
||||||
<td>20 ± 2</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>PA12-CF</td>
|
|
||||||
<td>≤15%</td>
|
|
||||||
<td>80-100℃</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>149.6℃</td>
|
|
||||||
<td>112.4℃</td>
|
|
||||||
<td>87.49 ± 2.81</td>
|
|
||||||
<td>5438.40 ± 282.82</td>
|
|
||||||
<td>2.59 ± 0.19</td>
|
|
||||||
<td>133.17 ± 4.66</td>
|
|
||||||
<td>4667.43 ± 339.80</td>
|
|
||||||
<td>6.11 ± 1.45</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>PATH-CF</td>
|
|
||||||
<td>≤15%</td>
|
|
||||||
<td>80-100℃</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>192.3℃</td>
|
|
||||||
<td>121.7℃</td>
|
|
||||||
<td>104.90 ± 1.99</td>
|
|
||||||
<td>8383.26 ± 419.53</td>
|
|
||||||
<td>1.60 ± 0.07</td>
|
|
||||||
<td>147.70 ± 4.09</td>
|
|
||||||
<td>5969.35 ± 145.28</td>
|
|
||||||
<td>6.17 ± 0.2</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>PET-CF</td>
|
|
||||||
<td>≤15%</td>
|
|
||||||
<td>80-100℃</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>+++</td>
|
|
||||||
<td>148.8℃</td>
|
|
||||||
<td>112.1℃</td>
|
|
||||||
<td>87.41 ± 3.57</td>
|
|
||||||
<td>6025.53 ± 355.46</td>
|
|
||||||
<td>1.99 ±0.18</td>
|
|
||||||
<td>122.69 ± 5.19</td>
|
|
||||||
<td>5313.21 ± 197.89</td>
|
|
||||||
<td>5.57 ± 0.58</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>PLA Rapido</td>
|
|
||||||
<td>≤30%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>57℃</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>39 ± 3</td>
|
|
||||||
<td>4650 ± 150</td>
|
|
||||||
<td>12.5 ± 2.5</td>
|
|
||||||
<td>72.5 ± 2.5</td>
|
|
||||||
<td>2850 ± 150</td>
|
|
||||||
<td>6 ± 2</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>PLA Rapido Matte</td>
|
|
||||||
<td>≤30%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>+</td>
|
|
||||||
<td>58℃</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>39 ± 3</td>
|
|
||||||
<td>2400 ± 200</td>
|
|
||||||
<td>3 ± 1</td>
|
|
||||||
<td>77.5 ± 2.5</td>
|
|
||||||
<td>2200 ± 200</td>
|
|
||||||
<td>7.5 ± 1.5</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-for="(item, index) in 1" :key="index">
|
|
||||||
<td>UltraPA</td>
|
|
||||||
<td>≤15%</td>
|
|
||||||
<td>/</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>++</td>
|
|
||||||
<td>77.8℃</td>
|
|
||||||
<td>73.1℃</td>
|
|
||||||
<td>86.15 ± 0.56</td>
|
|
||||||
<td>3609.22 ± 153.31</td>
|
|
||||||
<td>11.68 ± 3.36</td>
|
|
||||||
<td>121.47 ± 3.14</td>
|
|
||||||
<td>3314.03 ±181.88</td>
|
|
||||||
<td>5.78 ± 0.30</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="GifBigBoard" board="issuereport">
|
|
||||||
<div id="GifBoard">
|
|
||||||
<div class="GifBlock">
|
|
||||||
<div class="UG_B_TITLE trans TextS1" tid="t6"></div>
|
|
||||||
<div class="trans" tid="ls2"></div>
|
|
||||||
<div class="UG_B_DESC trans" tid="ls3"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="IssueBoard">
|
|
||||||
<div class="PrintBlock">
|
|
||||||
<div class="UG_IMG"><img src="img/X-MAX3.png" /></div>
|
|
||||||
<div class="UG_TITLE">X-MAX 3</div>
|
|
||||||
<div class="UG_DESC">
|
|
||||||
E-mail:<br />MAX3support@qd3dprinter.com<br>MAX3AMS@qd3dprinter.com<br /><br>
|
|
||||||
Skype:<br />MAX3support@qd3dprinter.com
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="PrintBlock">
|
<div class="PrinterBlock">
|
||||||
<div class="UG_IMG"><img src="img/X-Plus3.png" /></div>
|
<div class="CenterImage"><img src="img/X-Plus 3.png"/></div>
|
||||||
<div class="UG_TITLE">X-Plus 3</div>
|
<div class="ThumbnailTitle">X-Plus 3</div>
|
||||||
<div class="UG_DESC">
|
<div class="IntroduceText">
|
||||||
E-mail:<br />Plus3support01@qd3dprinter.com<br>Plus3support02@qd3dprinter.com<br /><br>
|
<b>E-mail:</b><br/>Plus3support01@qd3dprinter.com<br>Plus3support02@qd3dprinter.com<br/><br>
|
||||||
Skype:<br />Plus3support@qd3dprinter.com
|
<b>Skype:</b><br/>Plus3support@qd3dprinter.com
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="PrintBlock">
|
<div class="PrinterBlock">
|
||||||
<div class="UG_IMG"><img src="img/X-Smart3.png" /></div>
|
<div class="CenterImage"><img src="img/X-smart 3.png"/></div>
|
||||||
<div class="UG_TITLE">X-Smart 3</div>
|
<div class="ThumbnailTitle">X-smart 3</div>
|
||||||
<div class="UG_DESC">
|
<div class="IntroduceText">
|
||||||
E-mail:<br />Smart3support@qd3dprinter.com<br>Smart3AMS@qd3dprinter.com<br /><br>
|
<b>E-mail:</b><br/>Smart3support@qd3dprinter.com<br>Smart3AMS@qd3dprinter.com<br/><br>
|
||||||
Skype:<br />Smart3support@qd3dprinter.com
|
<b>Skype:</b><br/>Smart3support@qd3dprinter.com
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
function OnInit()
|
function OnInit()
|
||||||
{
|
{
|
||||||
//-----Test-----
|
TranslatePage();
|
||||||
//Set_RecentFile_MouseRightBtn_Event();
|
|
||||||
|
|
||||||
|
|
||||||
//-----Official-----
|
|
||||||
TranslatePage();
|
|
||||||
|
|
||||||
SendMsg_GetLoginInfo();
|
SendMsg_GetLoginInfo();
|
||||||
SendMsg_GetRecentFile();
|
SendMsg_GetRecentFile();
|
||||||
@@ -13,40 +8,27 @@ function OnInit()
|
|||||||
|
|
||||||
function GotoMenu( strMenu )
|
function GotoMenu( strMenu )
|
||||||
{
|
{
|
||||||
let MenuList = $(".BtnItem");
|
if (strMenu == "UserGuide")
|
||||||
let nAll=MenuList.length;
|
|
||||||
|
|
||||||
for(let n=0;n<nAll;n++)
|
|
||||||
{
|
{
|
||||||
let OneBtn=MenuList[n];
|
$(".MenuBtnSelected").removeClass("MenuBtnSelected");
|
||||||
|
$("div[board]").hide();
|
||||||
if( $(OneBtn).attr("menu")==strMenu )
|
$("div[board=\'" + strMenu + "\']").show();
|
||||||
{
|
|
||||||
$(".BtnItem").removeClass("BtnItemSelected");
|
|
||||||
|
|
||||||
$(OneBtn).addClass("BtnItemSelected");
|
|
||||||
|
|
||||||
$("div[board]").hide();
|
|
||||||
$("div[board=\'"+strMenu+"\']").show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
let MenuList = $(".MenuBtn");
|
||||||
|
let nAll=MenuList.length;
|
||||||
|
|
||||||
function GotoMain(strMenu) {
|
for(let n=0;n<nAll;n++)
|
||||||
let MenuList = $(".TbItem")
|
{
|
||||||
let nAll = MenuList.length;
|
let OneBtn=MenuList[n];
|
||||||
|
if ($(OneBtn).attr("menu")==strMenu)
|
||||||
for (let n = 0; n < nAll; n++) {
|
{
|
||||||
let OneBtn = MenuList[n];
|
$(".MenuBtnSelected").removeClass("MenuBtnSelected");
|
||||||
|
$(OneBtn).addClass("MenuBtnSelected");
|
||||||
if ($(OneBtn).attr("menu") == strMenu) {
|
$("div[board]").hide();
|
||||||
$(".TbItem").removeClass("TbItemSelected");
|
$("div[board=\'"+strMenu+"\']").show();
|
||||||
|
}
|
||||||
$(OneBtn).addClass("TbItemSelected");
|
|
||||||
$(".BtnItem").removeClass("BtnItemSelected");
|
|
||||||
|
|
||||||
$("div[board]").hide();
|
|
||||||
$("div[board=\'" + strMenu + "\']").show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#add_subdirectory(slasupporttree)
|
#add_subdirectory(slasupporttree)
|
||||||
#add_subdirectory(openvdb)
|
#add_subdirectory(openvdb)
|
||||||
# add_subdirectory(meshboolean)
|
# add_subdirectory(meshboolean)
|
||||||
add_subdirectory(its_neighbor_index)
|
#add_subdirectory(its_neighbor_index)
|
||||||
# add_subdirectory(opencsg)
|
# add_subdirectory(opencsg)
|
||||||
#add_subdirectory(aabb-evaluation)
|
#add_subdirectory(aabb-evaluation)
|
||||||
add_subdirectory(wx_gl_test)
|
#add_subdirectory(wx_gl_test)
|
||||||
|
add_subdirectory(print_arrange_polys)
|
||||||
|
|||||||
7
sandboxes/print_arrange_polys/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
add_executable(print_arrange_polys main.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(print_arrange_polys libslic3r admesh)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
qidislicer_copy_dlls(print_arrange_polys)
|
||||||
|
endif()
|
||||||
103
sandboxes/print_arrange_polys/main.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include <libslic3r/TriangleMesh.hpp>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
void print_arrange_polygons(const std::string &dirpath, std::ostream &out)
|
||||||
|
{
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
boost::filesystem::path p = dirpath;
|
||||||
|
|
||||||
|
if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& entry : boost::filesystem::directory_iterator(p)) {
|
||||||
|
if (!boost::filesystem::is_regular_file(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh mesh;
|
||||||
|
mesh.ReadSTLFile(entry.path().c_str());
|
||||||
|
ExPolygons outline = mesh.horizontal_projection();
|
||||||
|
|
||||||
|
out << "// " << entry.path().filename() << ": " << std::endl;
|
||||||
|
for (const ExPolygon &expoly : outline) {
|
||||||
|
out << "MyPoly{\n"; // Start of polygon
|
||||||
|
|
||||||
|
out << "\t{\n"; // Start of contour
|
||||||
|
for (const auto& point : expoly.contour.points) {
|
||||||
|
out << " {" << point.x() << ", " << point.y() << "},\n"; // Print point coordinates
|
||||||
|
}
|
||||||
|
out << " },\n"; // End of contour
|
||||||
|
|
||||||
|
out << " {\n"; // start of holes
|
||||||
|
for (const auto& hole : expoly.holes) {
|
||||||
|
out << " {\n"; // Start of hole
|
||||||
|
for (const auto& point : hole.points) {
|
||||||
|
out << " {" << point.x() << ", " << point.y() << "},\n"; // Print point coordinates
|
||||||
|
}
|
||||||
|
out << " },\n"; // End of hole Polygon
|
||||||
|
}
|
||||||
|
out << " }\n"; // end of holes Polygons
|
||||||
|
out << "},\n"; // End of ExPolygon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_arrange_items(const std::string &dirpath, std::ostream &out)
|
||||||
|
{
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
boost::filesystem::path p = dirpath;
|
||||||
|
|
||||||
|
if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& entry : boost::filesystem::directory_iterator(p)) {
|
||||||
|
if (!boost::filesystem::is_regular_file(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh mesh;
|
||||||
|
mesh.ReadSTLFile(entry.path().c_str());
|
||||||
|
ExPolygons outline = mesh.horizontal_projection();
|
||||||
|
|
||||||
|
out << "ExPolygons{ " << "// " << entry.path().filename() << ":\n";
|
||||||
|
for (const ExPolygon &expoly : outline) {
|
||||||
|
out << " MyPoly{\n"; // Start of polygon
|
||||||
|
|
||||||
|
out << " {\n"; // Start of contour
|
||||||
|
for (const auto& point : expoly.contour.points) {
|
||||||
|
out << " {" << point.x() << ", " << point.y() << "},\n"; // Print point coordinates
|
||||||
|
}
|
||||||
|
out << " },\n"; // End of contour
|
||||||
|
|
||||||
|
out << " {\n"; // start of holes
|
||||||
|
for (const auto& hole : expoly.holes) {
|
||||||
|
out << " {\n"; // Start of hole
|
||||||
|
for (const auto& point : hole.points) {
|
||||||
|
out << " {" << point.x() << ", " << point.y() << "},\n"; // Print point coordinates
|
||||||
|
}
|
||||||
|
out << " },\n"; // End of hole Polygon
|
||||||
|
}
|
||||||
|
out << " }\n"; // end of holes Polygons
|
||||||
|
out << " },\n"; // End of ExPolygon
|
||||||
|
}
|
||||||
|
out << "},\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
if (argc <= 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
std::string dirpath = argv[1];
|
||||||
|
|
||||||
|
print_arrange_items(dirpath, std::cout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -49,21 +49,12 @@ if (SLIC3R_GUI)
|
|||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||||
if (SLIC3R_WX_STABLE)
|
|
||||||
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
|
|
||||||
else ()
|
|
||||||
find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl)
|
|
||||||
|
|
||||||
if (NOT wxWidgets_FOUND)
|
|
||||||
message(FATAL_ERROR "\nCould not find wxWidgets 3.1.\n"
|
|
||||||
"Hint: On Linux you can set -DSLIC3R_WX_STABLE=1 to use wxWidgets 3.0\n")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(${wxWidgets_USE_FILE})
|
|
||||||
else ()
|
|
||||||
find_package(wxWidgets 3.2 REQUIRED COMPONENTS html adv gl core base webview aui net media)
|
|
||||||
endif ()
|
endif ()
|
||||||
|
find_package(wxWidgets 3.2 MODULE REQUIRED COMPONENTS base core adv html gl aui net webview)
|
||||||
|
|
||||||
|
include(${wxWidgets_USE_FILE})
|
||||||
|
|
||||||
|
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#include "libslic3r/CutUtils.hpp"
|
||||||
#include "libslic3r/ModelArrange.hpp"
|
#include "libslic3r/ModelArrange.hpp"
|
||||||
#include "libslic3r/Platform.hpp"
|
#include "libslic3r/Platform.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
@@ -313,10 +314,10 @@ int CLI::run(int argc, char **argv)
|
|||||||
|
|
||||||
// Loop through transform options.
|
// Loop through transform options.
|
||||||
bool user_center_specified = false;
|
bool user_center_specified = false;
|
||||||
Points bed = get_bed_shape(m_print_config);
|
arr2::ArrangeBed bed = arr2::to_arrange_bed(get_bed_shape(m_print_config));
|
||||||
ArrangeParams arrange_cfg;
|
arr2::ArrangeSettings arrange_cfg;
|
||||||
arrange_cfg.min_obj_distance = scaled(min_object_distance(m_print_config));
|
arrange_cfg.set_distance_from_objects(min_object_distance(m_print_config));
|
||||||
|
|
||||||
for (auto const &opt_key : m_transforms) {
|
for (auto const &opt_key : m_transforms) {
|
||||||
if (opt_key == "merge") {
|
if (opt_key == "merge") {
|
||||||
Model m;
|
Model m;
|
||||||
@@ -329,7 +330,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
if (this->has_print_action())
|
if (this->has_print_action())
|
||||||
arrange_objects(m, bed, arrange_cfg);
|
arrange_objects(m, bed, arrange_cfg);
|
||||||
else
|
else
|
||||||
arrange_objects(m, InfiniteBed{}, arrange_cfg);
|
arrange_objects(m, arr2::InfiniteBed{}, arrange_cfg);
|
||||||
}
|
}
|
||||||
m_models.clear();
|
m_models.clear();
|
||||||
m_models.emplace_back(std::move(m));
|
m_models.emplace_back(std::move(m));
|
||||||
@@ -437,8 +438,11 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower);
|
// model.objects.front()->cut(0, m_config.opt_float("cut"), ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::FlipLower);
|
||||||
model.objects.front()->cut(0, Geometry::translation_transform(m_config.opt_float("cut") * Vec3d::UnitZ()),
|
Cut cut(model.objects.front(), 0, Geometry::translation_transform(m_config.opt_float("cut") * Vec3d::UnitZ()),
|
||||||
ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper);
|
ModelObjectCutAttribute::KeepLower | ModelObjectCutAttribute::KeepUpper | ModelObjectCutAttribute::PlaceOnCutUpper);
|
||||||
|
auto cut_objects = cut.perform_with_plane();
|
||||||
|
for (ModelObject* obj : cut_objects)
|
||||||
|
model.add_object(*obj);
|
||||||
#endif
|
#endif
|
||||||
model.delete_object(size_t(0));
|
model.delete_object(size_t(0));
|
||||||
}
|
}
|
||||||
@@ -572,7 +576,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
if (! m_config.opt_bool("dont_arrange")) {
|
if (! m_config.opt_bool("dont_arrange")) {
|
||||||
if (user_center_specified) {
|
if (user_center_specified) {
|
||||||
Vec2d c = m_config.option<ConfigOptionPoint>("center")->value;
|
Vec2d c = m_config.option<ConfigOptionPoint>("center")->value;
|
||||||
arrange_objects(model, InfiniteBed{scaled(c)}, arrange_cfg);
|
arrange_objects(model, arr2::InfiniteBed{scaled(c)}, arrange_cfg);
|
||||||
} else
|
} else
|
||||||
arrange_objects(model, bed, arrange_cfg);
|
arrange_objects(model, bed, arrange_cfg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ struct indexed_triangle_set
|
|||||||
std::vector<stl_vertex> vertices;
|
std::vector<stl_vertex> vertices;
|
||||||
|
|
||||||
bool empty() const { return indices.empty() || vertices.empty(); }
|
bool empty() const { return indices.empty() || vertices.empty(); }
|
||||||
|
bool operator==(const indexed_triangle_set& other) const { return this->indices == other.indices && this->vertices == other.vertices; }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool stl_open(stl_file *stl, const char *file);
|
extern bool stl_open(stl_file *stl, const char *file);
|
||||||
|
|||||||
@@ -86,7 +86,13 @@ inline IntPoint IntPoint2d(cInt x, cInt y)
|
|||||||
|
|
||||||
inline cInt Round(double val)
|
inline cInt Round(double val)
|
||||||
{
|
{
|
||||||
return static_cast<cInt>((val < 0) ? (val - 0.5) : (val + 0.5));
|
double v = val < 0 ? val - 0.5 : val + 0.5;
|
||||||
|
#if defined(CLIPPERLIB_INT32) && ! defined(NDEBUG)
|
||||||
|
static constexpr const double hi = 65536 * 16383;
|
||||||
|
if (v > hi || -v > hi)
|
||||||
|
throw clipperException("Coordinate outside allowed range");
|
||||||
|
#endif
|
||||||
|
return static_cast<cInt>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overriding the Eigen operators because we don't want to compare Z coordinate if IntPoint is 3 dimensional.
|
// Overriding the Eigen operators because we don't want to compare Z coordinate if IntPoint is 3 dimensional.
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ namespace ImGui
|
|||||||
// const wchar_t MmuSegmentationMarker = 0x1F;
|
// const wchar_t MmuSegmentationMarker = 0x1F;
|
||||||
const wchar_t PlugMarker = 0x1C;
|
const wchar_t PlugMarker = 0x1C;
|
||||||
const wchar_t DowelMarker = 0x1D;
|
const wchar_t DowelMarker = 0x1D;
|
||||||
|
const wchar_t SnapMarker = 0x1E;
|
||||||
// Do not forget use following letters only in wstring
|
// Do not forget use following letters only in wstring
|
||||||
const wchar_t DocumentationButton = 0x2600;
|
const wchar_t DocumentationButton = 0x2600;
|
||||||
const wchar_t DocumentationHoverButton = 0x2601;
|
const wchar_t DocumentationHoverButton = 0x2601;
|
||||||
|
|||||||
@@ -18,11 +18,10 @@ set(LIBNEST2D_SRCFILES
|
|||||||
include/libnest2d/optimizers/nlopt/simplex.hpp
|
include/libnest2d/optimizers/nlopt/simplex.hpp
|
||||||
include/libnest2d/optimizers/nlopt/subplex.hpp
|
include/libnest2d/optimizers/nlopt/subplex.hpp
|
||||||
include/libnest2d/optimizers/nlopt/genetic.hpp
|
include/libnest2d/optimizers/nlopt/genetic.hpp
|
||||||
src/libnest2d.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES})
|
add_library(libnest2d INTERFACE)
|
||||||
|
|
||||||
target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
target_include_directories(libnest2d INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
target_link_libraries(libnest2d PUBLIC NLopt::nlopt TBB::tbb TBB::tbbmalloc Boost::boost libslic3r)
|
target_link_libraries(libnest2d INTERFACE NLopt::nlopt TBB::tbb TBB::tbbmalloc Boost::boost libslic3r)
|
||||||
target_compile_definitions(libnest2d PUBLIC LIBNEST2D_THREADING_tbb LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_libslic3r)
|
target_compile_definitions(libnest2d INTERFACE LIBNEST2D_THREADING_tbb LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_libslic3r)
|
||||||
|
|||||||
@@ -243,6 +243,12 @@ inline void translate(Slic3r::ExPolygon& sh, const Slic3r::Point& offs)
|
|||||||
sh.translate(offs);
|
sh.translate(offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void translate(Slic3r::Polygon& sh, const Slic3r::Point& offs)
|
||||||
|
{
|
||||||
|
sh.translate(offs);
|
||||||
|
}
|
||||||
|
|
||||||
#define DISABLE_BOOST_ROTATE
|
#define DISABLE_BOOST_ROTATE
|
||||||
template<>
|
template<>
|
||||||
inline void rotate(Slic3r::ExPolygon& sh, const Radians& rads)
|
inline void rotate(Slic3r::ExPolygon& sh, const Radians& rads)
|
||||||
@@ -250,6 +256,12 @@ inline void rotate(Slic3r::ExPolygon& sh, const Radians& rads)
|
|||||||
sh.rotate(rads);
|
sh.rotate(rads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void rotate(Slic3r::Polygon& sh, const Radians& rads)
|
||||||
|
{
|
||||||
|
sh.rotate(rads);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shapelike
|
} // namespace shapelike
|
||||||
|
|
||||||
namespace nfp {
|
namespace nfp {
|
||||||
|
|||||||
@@ -15,12 +15,19 @@ namespace Slic3r {
|
|||||||
// The stored pointer is not checked for being null when dereferenced.
|
// The stored pointer is not checked for being null when dereferenced.
|
||||||
//
|
//
|
||||||
// This is a movable only object due to the fact that it can possibly hold
|
// This is a movable only object due to the fact that it can possibly hold
|
||||||
// a unique_ptr which a non-copy.
|
// a unique_ptr which can only be moved.
|
||||||
|
//
|
||||||
|
// Drawbacks:
|
||||||
|
// No custom deleters are supported when storing a unique_ptr, but overloading
|
||||||
|
// std::default_delete for a particular type could be a workaround
|
||||||
|
//
|
||||||
|
// raw array types are problematic, since std::default_delete also does not
|
||||||
|
// support them well.
|
||||||
template<class T>
|
template<class T>
|
||||||
class AnyPtr {
|
class AnyPtr {
|
||||||
enum { RawPtr, UPtr, ShPtr, WkPtr };
|
enum { RawPtr, UPtr, ShPtr };
|
||||||
|
|
||||||
boost::variant<T*, std::unique_ptr<T>, std::shared_ptr<T>, std::weak_ptr<T>> ptr;
|
boost::variant<T*, std::unique_ptr<T>, std::shared_ptr<T>> ptr;
|
||||||
|
|
||||||
template<class Self> static T *get_ptr(Self &&s)
|
template<class Self> static T *get_ptr(Self &&s)
|
||||||
{
|
{
|
||||||
@@ -28,91 +35,119 @@ class AnyPtr {
|
|||||||
case RawPtr: return boost::get<T *>(s.ptr);
|
case RawPtr: return boost::get<T *>(s.ptr);
|
||||||
case UPtr: return boost::get<std::unique_ptr<T>>(s.ptr).get();
|
case UPtr: return boost::get<std::unique_ptr<T>>(s.ptr).get();
|
||||||
case ShPtr: return boost::get<std::shared_ptr<T>>(s.ptr).get();
|
case ShPtr: return boost::get<std::shared_ptr<T>>(s.ptr).get();
|
||||||
case WkPtr: {
|
|
||||||
auto shptr = boost::get<std::weak_ptr<T>>(s.ptr).lock();
|
|
||||||
return shptr.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
template<class TT> friend class AnyPtr;
|
||||||
template<class TT = T, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
|
||||||
AnyPtr(TT *p = nullptr) : ptr{p}
|
|
||||||
{}
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
|
||||||
AnyPtr(std::unique_ptr<TT> p) : ptr{std::unique_ptr<T>(std::move(p))}
|
|
||||||
{}
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
|
||||||
AnyPtr(std::shared_ptr<TT> p) : ptr{std::shared_ptr<T>(std::move(p))}
|
|
||||||
{}
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
|
||||||
AnyPtr(std::weak_ptr<TT> p) : ptr{std::weak_ptr<T>(std::move(p))}
|
|
||||||
{}
|
|
||||||
|
|
||||||
~AnyPtr() = default;
|
template<class TT>
|
||||||
|
using SimilarPtrOnly = std::enable_if_t<std::is_convertible_v<TT*, T*>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AnyPtr() noexcept = default;
|
||||||
|
|
||||||
|
AnyPtr(T *p) noexcept: ptr{p} {}
|
||||||
|
|
||||||
|
AnyPtr(std::nullptr_t) noexcept {};
|
||||||
|
|
||||||
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
|
AnyPtr(TT *p) noexcept : ptr{p}
|
||||||
|
{}
|
||||||
|
template<class TT = T, class = SimilarPtrOnly<TT>>
|
||||||
|
AnyPtr(std::unique_ptr<TT> p) noexcept : ptr{std::unique_ptr<T>(std::move(p))}
|
||||||
|
{}
|
||||||
|
template<class TT = T, class = SimilarPtrOnly<TT>>
|
||||||
|
AnyPtr(std::shared_ptr<TT> p) noexcept : ptr{std::shared_ptr<T>(std::move(p))}
|
||||||
|
{}
|
||||||
|
|
||||||
AnyPtr(AnyPtr &&other) noexcept : ptr{std::move(other.ptr)} {}
|
AnyPtr(AnyPtr &&other) noexcept : ptr{std::move(other.ptr)} {}
|
||||||
|
|
||||||
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
|
AnyPtr(AnyPtr<TT> &&other) noexcept
|
||||||
|
{
|
||||||
|
this->operator=(std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
AnyPtr(const AnyPtr &other) = delete;
|
AnyPtr(const AnyPtr &other) = delete;
|
||||||
|
|
||||||
AnyPtr &operator=(AnyPtr &&other) noexcept { ptr = std::move(other.ptr); return *this; }
|
AnyPtr &operator=(AnyPtr &&other) noexcept
|
||||||
|
{
|
||||||
|
ptr = std::move(other.ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
AnyPtr &operator=(const AnyPtr &other) = delete;
|
AnyPtr &operator=(const AnyPtr &other) = delete;
|
||||||
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
AnyPtr &operator=(TT *p) { ptr = p; return *this; }
|
AnyPtr& operator=(AnyPtr<TT> &&other) noexcept
|
||||||
|
{
|
||||||
|
switch (other.ptr.which()) {
|
||||||
|
case RawPtr: *this = boost::get<TT *>(other.ptr); break;
|
||||||
|
case UPtr: *this = std::move(boost::get<std::unique_ptr<TT>>(other.ptr)); break;
|
||||||
|
case ShPtr: *this = std::move(boost::get<std::shared_ptr<TT>>(other.ptr)); break;
|
||||||
|
}
|
||||||
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
return *this;
|
||||||
AnyPtr &operator=(std::unique_ptr<TT> p) { ptr = std::move(p); return *this; }
|
}
|
||||||
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
AnyPtr &operator=(std::shared_ptr<TT> p) { ptr = p; return *this; }
|
AnyPtr &operator=(TT *p) noexcept
|
||||||
|
{
|
||||||
|
ptr = static_cast<T *>(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<class TT, class = std::enable_if_t<std::is_convertible_v<TT*, T*>>>
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
AnyPtr &operator=(std::weak_ptr<TT> p) { ptr = std::move(p); return *this; }
|
AnyPtr &operator=(std::unique_ptr<TT> p) noexcept
|
||||||
|
{
|
||||||
|
ptr = std::unique_ptr<T>(std::move(p));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const T &operator*() const { return *get_ptr(*this); }
|
template<class TT, class = SimilarPtrOnly<TT>>
|
||||||
T &operator*() { return *get_ptr(*this); }
|
AnyPtr &operator=(std::shared_ptr<TT> p) noexcept
|
||||||
|
{
|
||||||
|
ptr = std::shared_ptr<T>(std::move(p));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
T *operator->() { return get_ptr(*this); }
|
const T &operator*() const noexcept { return *get_ptr(*this); }
|
||||||
const T *operator->() const { return get_ptr(*this); }
|
T &operator*() noexcept { return *get_ptr(*this); }
|
||||||
|
|
||||||
T *get() { return get_ptr(*this); }
|
T *operator->() noexcept { return get_ptr(*this); }
|
||||||
const T *get() const { return get_ptr(*this); }
|
const T *operator->() const noexcept { return get_ptr(*this); }
|
||||||
|
|
||||||
operator bool() const
|
T *get() noexcept { return get_ptr(*this); }
|
||||||
|
const T *get() const noexcept { return get_ptr(*this); }
|
||||||
|
|
||||||
|
operator bool() const noexcept
|
||||||
{
|
{
|
||||||
switch (ptr.which()) {
|
switch (ptr.which()) {
|
||||||
case RawPtr: return bool(boost::get<T *>(ptr));
|
case RawPtr: return bool(boost::get<T *>(ptr));
|
||||||
case UPtr: return bool(boost::get<std::unique_ptr<T>>(ptr));
|
case UPtr: return bool(boost::get<std::unique_ptr<T>>(ptr));
|
||||||
case ShPtr: return bool(boost::get<std::shared_ptr<T>>(ptr));
|
case ShPtr: return bool(boost::get<std::shared_ptr<T>>(ptr));
|
||||||
case WkPtr: {
|
|
||||||
auto shptr = boost::get<std::weak_ptr<T>>(ptr).lock();
|
|
||||||
return bool(shptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the stored pointer is a shared or weak pointer, returns a reference
|
// If the stored pointer is a shared pointer, returns a reference
|
||||||
// counted copy. Empty shared pointer is returned otherwise.
|
// counted copy. Empty shared pointer is returned otherwise.
|
||||||
std::shared_ptr<T> get_shared_cpy() const
|
std::shared_ptr<T> get_shared_cpy() const noexcept
|
||||||
{
|
{
|
||||||
std::shared_ptr<T> ret;
|
std::shared_ptr<T> ret;
|
||||||
|
|
||||||
switch (ptr.which()) {
|
if (ptr.which() == ShPtr)
|
||||||
case ShPtr: ret = boost::get<std::shared_ptr<T>>(ptr); break;
|
ret = boost::get<std::shared_ptr<T>>(ptr);
|
||||||
case WkPtr: ret = boost::get<std::weak_ptr<T>>(ptr).lock(); break;
|
|
||||||
default:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the underlying pointer is unique, convert to shared pointer
|
// If the underlying pointer is unique, convert to shared pointer
|
||||||
void convert_unique_to_shared()
|
void convert_unique_to_shared() noexcept
|
||||||
{
|
{
|
||||||
if (ptr.which() == UPtr)
|
if (ptr.which() == UPtr)
|
||||||
ptr = std::shared_ptr<T>{std::move(boost::get<std::unique_ptr<T>>(ptr))};
|
ptr = std::shared_ptr<T>{std::move(boost::get<std::unique_ptr<T>>(ptr))};
|
||||||
@@ -125,6 +160,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif // ANYPTR_HPP
|
#endif // ANYPTR_HPP
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <ClipperUtils.hpp>
|
#include <ClipperUtils.hpp>
|
||||||
|
|
||||||
#include <boost/geometry/index/rtree.hpp>
|
#include <boost/geometry/index/rtree.hpp>
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(__clang__)
|
#if defined(_MSC_VER) && defined(__clang__)
|
||||||
#define BOOST_NO_CXX17_HDR_STRING_VIEW
|
#define BOOST_NO_CXX17_HDR_STRING_VIEW
|
||||||
@@ -258,7 +259,7 @@ protected:
|
|||||||
auto& index = isBig(item.area()) ? spatindex : smalls_spatindex;
|
auto& index = isBig(item.area()) ? spatindex : smalls_spatindex;
|
||||||
|
|
||||||
// Query the spatial index for the neighbors
|
// Query the spatial index for the neighbors
|
||||||
std::vector<SpatElement> result;
|
boost::container::small_vector<SpatElement, 100> result;
|
||||||
result.reserve(index.size());
|
result.reserve(index.size());
|
||||||
|
|
||||||
index.query(query, std::back_inserter(result));
|
index.query(query, std::back_inserter(result));
|
||||||
|
|||||||
269
src/libslic3r/Arrange/Arrange.hpp
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGE2_HPP
|
||||||
|
#define ARRANGE2_HPP
|
||||||
|
|
||||||
|
#include "Scene.hpp"
|
||||||
|
#include "Items/MutableItemTraits.hpp"
|
||||||
|
#include "Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/MinAreaBoundingBox.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
template<class ArrItem> class Arranger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Ctl : public ArrangeTaskCtl {
|
||||||
|
public:
|
||||||
|
virtual void on_packed(ArrItem &item) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Arranger() = default;
|
||||||
|
|
||||||
|
virtual void arrange(std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
Ctl &ctl) = 0;
|
||||||
|
|
||||||
|
void arrange(std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
ArrangeTaskCtl &ctl);
|
||||||
|
|
||||||
|
void arrange(std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
Ctl &&ctl)
|
||||||
|
{
|
||||||
|
arrange(items, fixed, bed, ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arrange(std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
ArrangeTaskCtl &&ctl)
|
||||||
|
{
|
||||||
|
arrange(items, fixed, bed, ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Arranger> create(const ArrangeSettingsView &settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem> using ArrangerCtl = typename Arranger<ArrItem>::Ctl;
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
class DefaultArrangerCtl : public Arranger<ArrItem>::Ctl {
|
||||||
|
ArrangeTaskCtl *taskctl = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DefaultArrangerCtl() = default;
|
||||||
|
|
||||||
|
explicit DefaultArrangerCtl(ArrangeTaskBase::Ctl &ctl) : taskctl{&ctl} {}
|
||||||
|
|
||||||
|
void update_status(int st) override
|
||||||
|
{
|
||||||
|
if (taskctl)
|
||||||
|
taskctl->update_status(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool was_canceled() const override
|
||||||
|
{
|
||||||
|
if (taskctl)
|
||||||
|
return taskctl->was_canceled();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
void Arranger<ArrItem>::arrange(std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
ArrangeTaskCtl &ctl)
|
||||||
|
{
|
||||||
|
arrange(items, fixed, bed, DefaultArrangerCtl<ArrItem>{ctl});
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyItemOutlineError: public std::exception {
|
||||||
|
static constexpr const char *Msg = "No outline can be derived for object";
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char* what() const noexcept override { return Msg; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem> class ArrangeableToItemConverter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ArrangeableToItemConverter() = default;
|
||||||
|
|
||||||
|
// May throw EmptyItemOutlineError
|
||||||
|
virtual ArrItem convert(const Arrangeable &arrbl, coord_t offs = 0) const = 0;
|
||||||
|
|
||||||
|
// Returns the extent of simplification that the converter utilizes when
|
||||||
|
// creating arrange items. Zero shall mean no simplification at all.
|
||||||
|
virtual coord_t simplification_tolerance() const { return 0; }
|
||||||
|
|
||||||
|
static std::unique_ptr<ArrangeableToItemConverter> create(
|
||||||
|
ArrangeSettingsView::GeometryHandling geometry_handling,
|
||||||
|
coord_t safety_d);
|
||||||
|
|
||||||
|
static std::unique_ptr<ArrangeableToItemConverter> create(
|
||||||
|
const Scene &sc)
|
||||||
|
{
|
||||||
|
return create(sc.settings().get_geometry_handling(),
|
||||||
|
scaled(sc.settings().get_distance_from_objects()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class DStore, class = WritableDataStoreOnly<DStore>>
|
||||||
|
class AnyWritableDataStore: public AnyWritable
|
||||||
|
{
|
||||||
|
DStore &dstore;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AnyWritableDataStore(DStore &store): dstore{store} {}
|
||||||
|
|
||||||
|
void write(std::string_view key, std::any d) override
|
||||||
|
{
|
||||||
|
set_data(dstore, std::string{key}, std::move(d));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
class BasicItemConverter : public ArrangeableToItemConverter<ArrItem>
|
||||||
|
{
|
||||||
|
coord_t m_safety_d;
|
||||||
|
coord_t m_simplify_tol;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BasicItemConverter(coord_t safety_d = 0, coord_t simpl_tol = 0)
|
||||||
|
: m_safety_d{safety_d}, m_simplify_tol{simpl_tol}
|
||||||
|
{}
|
||||||
|
|
||||||
|
coord_t safety_dist() const noexcept { return m_safety_d; }
|
||||||
|
|
||||||
|
coord_t simplification_tolerance() const override
|
||||||
|
{
|
||||||
|
return m_simplify_tol;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
class ConvexItemConverter : public BasicItemConverter<ArrItem>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using BasicItemConverter<ArrItem>::BasicItemConverter;
|
||||||
|
|
||||||
|
ArrItem convert(const Arrangeable &arrbl, coord_t offs) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
class AdvancedItemConverter : public BasicItemConverter<ArrItem>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual ArrItem get_arritem(const Arrangeable &arrbl, coord_t eps) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using BasicItemConverter<ArrItem>::BasicItemConverter;
|
||||||
|
|
||||||
|
ArrItem convert(const Arrangeable &arrbl, coord_t offs) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
class BalancedItemConverter : public AdvancedItemConverter<ArrItem>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
ArrItem get_arritem(const Arrangeable &arrbl, coord_t offs) const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using AdvancedItemConverter<ArrItem>::AdvancedItemConverter;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem, class En = void> struct ImbueableItemTraits_
|
||||||
|
{
|
||||||
|
static constexpr const char *Key = "object_id";
|
||||||
|
|
||||||
|
static void imbue_id(ArrItem &itm, const ObjectID &id)
|
||||||
|
{
|
||||||
|
set_arbitrary_data(itm, Key, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<ObjectID> retrieve_id(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
std::optional<ObjectID> ret;
|
||||||
|
auto idptr = get_data<const ObjectID>(itm, Key);
|
||||||
|
if (idptr)
|
||||||
|
ret = *idptr;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
using ImbueableItemTraits = ImbueableItemTraits_<StripCVRef<ArrItem>>;
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
void imbue_id(ArrItem &itm, const ObjectID &id)
|
||||||
|
{
|
||||||
|
ImbueableItemTraits<ArrItem>::imbue_id(itm, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
std::optional<ObjectID> retrieve_id(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return ImbueableItemTraits<ArrItem>::retrieve_id(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool apply_arrangeitem(const ArrItem &itm, ArrangeableModel &mdl)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (auto id = retrieve_id(itm)) {
|
||||||
|
mdl.visit_arrangeable(*id, [&itm, &ret](Arrangeable &arrbl) {
|
||||||
|
if ((ret = arrbl.assign_bed(get_bed_index(itm))))
|
||||||
|
arrbl.transform(unscaled(get_translation(itm)), get_rotation(itm));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double get_min_area_bounding_box_rotation(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return MinAreaBoundigBox{envelope_convex_hull(itm),
|
||||||
|
MinAreaBoundigBox::pcConvex}
|
||||||
|
.angle_to_X();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double get_fit_into_bed_rotation(const ArrItem &itm, const RectangleBed &bed)
|
||||||
|
{
|
||||||
|
double ret = 0.;
|
||||||
|
|
||||||
|
auto bbsz = envelope_bounding_box(itm).size();
|
||||||
|
auto binbb = bounding_box(bed);
|
||||||
|
auto binbbsz = binbb.size();
|
||||||
|
|
||||||
|
if (bbsz.x() >= binbbsz.x() || bbsz.y() >= binbbsz.y())
|
||||||
|
ret = fit_into_box_rotation(envelope_convex_hull(itm), binbb);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
auto get_corrected_bed(const ExtendedBed &bed,
|
||||||
|
const ArrangeableToItemConverter<ArrItem> &converter)
|
||||||
|
{
|
||||||
|
auto bedcpy = bed;
|
||||||
|
visit_bed([tol = -converter.simplification_tolerance()](auto &rawbed) {
|
||||||
|
rawbed = offset(rawbed, tol);
|
||||||
|
}, bedcpy);
|
||||||
|
|
||||||
|
return bedcpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGE2_HPP
|
||||||
498
src/libslic3r/Arrange/ArrangeImpl.hpp
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGEIMPL_HPP
|
||||||
|
#define ARRANGEIMPL_HPP
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Arrange.hpp"
|
||||||
|
|
||||||
|
#include "Core/ArrangeBase.hpp"
|
||||||
|
#include "Core/ArrangeFirstFit.hpp"
|
||||||
|
#include "Core/NFP/PackStrategyNFP.hpp"
|
||||||
|
#include "Core/NFP/Kernels/TMArrangeKernel.hpp"
|
||||||
|
#include "Core/NFP/Kernels/GravityKernel.hpp"
|
||||||
|
#include "Core/NFP/RectangleOverfitPackingStrategy.hpp"
|
||||||
|
#include "Core/Beds.hpp"
|
||||||
|
|
||||||
|
#include "Items/MutableItemTraits.hpp"
|
||||||
|
|
||||||
|
#include "SegmentedRectangleBed.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||||
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include "Core/NFP/Kernels/SVGDebugOutputKernelWrapper.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// arrange overload for SegmentedRectangleBed which is exactly what is used
|
||||||
|
// by XL printers.
|
||||||
|
template<class It,
|
||||||
|
class ConstIt,
|
||||||
|
class SelectionStrategy,
|
||||||
|
class PackStrategy, class...SBedArgs>
|
||||||
|
void arrange(SelectionStrategy &&selstrategy,
|
||||||
|
PackStrategy &&packingstrategy,
|
||||||
|
const Range<It> &items,
|
||||||
|
const Range<ConstIt> &fixed,
|
||||||
|
const SegmentedRectangleBed<SBedArgs...> &bed)
|
||||||
|
{
|
||||||
|
// Dispatch:
|
||||||
|
arrange(std::forward<SelectionStrategy>(selstrategy),
|
||||||
|
std::forward<PackStrategy>(packingstrategy), items, fixed,
|
||||||
|
RectangleBed{bed.bb}, SelStrategyTag<SelectionStrategy>{});
|
||||||
|
|
||||||
|
std::vector<int> bed_indices = get_bed_indices(items, fixed);
|
||||||
|
std::map<int, BoundingBox> pilebb;
|
||||||
|
std::map<int, bool> bed_occupied;
|
||||||
|
|
||||||
|
for (auto &itm : items) {
|
||||||
|
auto bedidx = get_bed_index(itm);
|
||||||
|
if (bedidx >= 0) {
|
||||||
|
pilebb[bedidx].merge(fixed_bounding_box(itm));
|
||||||
|
if (is_wipe_tower(itm))
|
||||||
|
bed_occupied[bedidx] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &fxitm : fixed) {
|
||||||
|
auto bedidx = get_bed_index(fxitm);
|
||||||
|
if (bedidx >= 0)
|
||||||
|
bed_occupied[bedidx] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bedbb = bounding_box(bed);
|
||||||
|
auto piecesz = unscaled(bedbb).size();
|
||||||
|
piecesz.x() /= bed.segments_x();
|
||||||
|
piecesz.y() /= bed.segments_y();
|
||||||
|
|
||||||
|
using Pivots = RectPivots;
|
||||||
|
|
||||||
|
Pivots pivot = bed.alignment();
|
||||||
|
|
||||||
|
for (int bedidx : bed_indices) {
|
||||||
|
if (auto occup_it = bed_occupied.find(bedidx);
|
||||||
|
occup_it != bed_occupied.end() && occup_it->second)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BoundingBox bb;
|
||||||
|
auto pilesz = unscaled(pilebb[bedidx]).size();
|
||||||
|
bb.max.x() = scaled(std::ceil(pilesz.x() / piecesz.x()) * piecesz.x());
|
||||||
|
bb.max.y() = scaled(std::ceil(pilesz.y() / piecesz.y()) * piecesz.y());
|
||||||
|
|
||||||
|
switch (pivot) {
|
||||||
|
case Pivots::BottomLeft:
|
||||||
|
bb.translate(bedbb.min - bb.min);
|
||||||
|
break;
|
||||||
|
case Pivots::TopRight:
|
||||||
|
bb.translate(bedbb.max - bb.max);
|
||||||
|
break;
|
||||||
|
case Pivots::BottomRight: {
|
||||||
|
Point bedref{bedbb.max.x(), bedbb.min.y()};
|
||||||
|
Point bbref {bb.max.x(), bb.min.y()};
|
||||||
|
bb.translate(bedref - bbref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Pivots::TopLeft: {
|
||||||
|
Point bedref{bedbb.min.x(), bedbb.max.y()};
|
||||||
|
Point bbref {bb.min.x(), bb.max.y()};
|
||||||
|
bb.translate(bedref - bbref);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Pivots::Center: {
|
||||||
|
bb.translate(bedbb.center() - bb.center());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd d = bb.center() - pilebb[bedidx].center();
|
||||||
|
|
||||||
|
auto pilebbx = pilebb[bedidx];
|
||||||
|
pilebbx.translate(d);
|
||||||
|
|
||||||
|
Point corr{0, 0};
|
||||||
|
corr.x() = -std::min(0, pilebbx.min.x() - bedbb.min.x())
|
||||||
|
-std::max(0, pilebbx.max.x() - bedbb.max.x());
|
||||||
|
corr.y() = -std::min(0, pilebbx.min.y() - bedbb.min.y())
|
||||||
|
-std::max(0, pilebbx.max.y() - bedbb.max.y());
|
||||||
|
|
||||||
|
d += corr;
|
||||||
|
|
||||||
|
for (auto &itm : items)
|
||||||
|
if (get_bed_index(itm) == static_cast<int>(bedidx) && !is_wipe_tower(itm))
|
||||||
|
translate(itm, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using VariantKernel =
|
||||||
|
boost::variant<TMArrangeKernel, GravityKernel>;
|
||||||
|
|
||||||
|
template<> struct KernelTraits_<VariantKernel> {
|
||||||
|
template<class ArrItem>
|
||||||
|
static double placement_fitness(const VariantKernel &kernel,
|
||||||
|
const ArrItem &itm,
|
||||||
|
const Vec2crd &transl)
|
||||||
|
{
|
||||||
|
double ret = NaNd;
|
||||||
|
boost::apply_visitor(
|
||||||
|
[&](auto &k) { ret = k.placement_fitness(itm, transl); }, kernel);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Ctx, class RemIt>
|
||||||
|
static bool on_start_packing(VariantKernel &kernel,
|
||||||
|
ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Ctx &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
boost::apply_visitor([&](auto &k) {
|
||||||
|
ret = k.on_start_packing(itm, bed, packing_context, remaining_items);
|
||||||
|
}, kernel);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
static bool on_item_packed(VariantKernel &kernel, ArrItem &itm)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
boost::apply_visitor([&](auto &k) { ret = k.on_item_packed(itm); },
|
||||||
|
kernel);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
struct firstfit::ItemArrangedVisitor<ArrItem, DataStoreOnly<ArrItem>> {
|
||||||
|
template<class Bed, class PIt, class RIt>
|
||||||
|
static void on_arranged(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Range<PIt> &packed,
|
||||||
|
const Range<RIt> &remaining)
|
||||||
|
{
|
||||||
|
using OnArrangeCb = std::function<void(StripCVRef<ArrItem> &)>;
|
||||||
|
|
||||||
|
auto cb = get_data<OnArrangeCb>(itm, "on_arranged");
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
(*cb)(itm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline RectPivots xlpivots_to_rect_pivots(ArrangeSettingsView::XLPivots xlpivot)
|
||||||
|
{
|
||||||
|
if (xlpivot == arr2::ArrangeSettingsView::xlpRandom) {
|
||||||
|
// means it should be random
|
||||||
|
std::random_device rd{};
|
||||||
|
std::mt19937 rng(rd());
|
||||||
|
std::uniform_int_distribution<std::mt19937::result_type>
|
||||||
|
dist(0, arr2::ArrangeSettingsView::xlpRandom - 1);
|
||||||
|
xlpivot = static_cast<ArrangeSettingsView::XLPivots>(dist(rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
RectPivots rectpivot = RectPivots::Center;
|
||||||
|
|
||||||
|
switch(xlpivot) {
|
||||||
|
case arr2::ArrangeSettingsView::xlpCenter: rectpivot = RectPivots::Center; break;
|
||||||
|
case arr2::ArrangeSettingsView::xlpFrontLeft: rectpivot = RectPivots::BottomLeft; break;
|
||||||
|
case arr2::ArrangeSettingsView::xlpFrontRight: rectpivot = RectPivots::BottomRight; break;
|
||||||
|
case arr2::ArrangeSettingsView::xlpRearLeft: rectpivot = RectPivots::TopLeft; break;
|
||||||
|
case arr2::ArrangeSettingsView::xlpRearRight: rectpivot = RectPivots::TopRight; break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rectpivot;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It, class Bed>
|
||||||
|
void fill_rotations(const Range<It> &items,
|
||||||
|
const Bed &bed,
|
||||||
|
const ArrangeSettingsView &settings)
|
||||||
|
{
|
||||||
|
if (!settings.is_rotation_enabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto &itm : items) {
|
||||||
|
if (is_wipe_tower(itm)) // Rotating the wipe tower is currently problematic
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Use the minimum bounding box rotation as a starting point.
|
||||||
|
auto minbbr = get_min_area_bounding_box_rotation(itm);
|
||||||
|
std::vector<double> rotations =
|
||||||
|
{minbbr,
|
||||||
|
minbbr + PI / 4., minbbr + PI / 2.,
|
||||||
|
minbbr + PI, minbbr + 3 * PI / 4.};
|
||||||
|
|
||||||
|
// Add the original rotation of the item if minbbr
|
||||||
|
// is not already the original rotation (zero)
|
||||||
|
if (std::abs(minbbr) > 0.)
|
||||||
|
rotations.emplace_back(0.);
|
||||||
|
|
||||||
|
// Also try to find the rotation that fits the item
|
||||||
|
// into a rectangular bed, given that it cannot fit,
|
||||||
|
// and there exists a rotation which can fit.
|
||||||
|
if constexpr (std::is_convertible_v<Bed, RectangleBed>) {
|
||||||
|
double fitbrot = get_fit_into_bed_rotation(itm, bed);
|
||||||
|
if (std::abs(fitbrot) > 0.)
|
||||||
|
rotations.emplace_back(fitbrot);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_allowed_rotations(itm, rotations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An arranger put together to fulfill all the requirements based
|
||||||
|
// on the supplied ArrangeSettings
|
||||||
|
template<class ArrItem>
|
||||||
|
class DefaultArranger: public Arranger<ArrItem> {
|
||||||
|
ArrangeSettings m_settings;
|
||||||
|
|
||||||
|
static constexpr auto Accuracy = 1.;
|
||||||
|
|
||||||
|
template<class It, class FixIt, class Bed>
|
||||||
|
void arrange_(
|
||||||
|
const Range<It> &items,
|
||||||
|
const Range<FixIt> &fixed,
|
||||||
|
const Bed &bed,
|
||||||
|
ArrangerCtl<ArrItem> &ctl)
|
||||||
|
{
|
||||||
|
auto cmpfn = [](const auto &itm1, const auto &itm2) {
|
||||||
|
int pa = get_priority(itm1);
|
||||||
|
int pb = get_priority(itm2);
|
||||||
|
|
||||||
|
return pa == pb ? area(envelope_convex_hull(itm1)) > area(envelope_convex_hull(itm2)) :
|
||||||
|
pa > pb;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto on_arranged = [&ctl](auto &itm, auto &bed, auto &ctx, auto &rem) {
|
||||||
|
ctl.update_status(rem.size());
|
||||||
|
|
||||||
|
ctl.on_packed(itm);
|
||||||
|
|
||||||
|
firstfit::DefaultOnArrangedFn{}(itm, bed, ctx, rem);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto stop_cond = [&ctl] { return ctl.was_canceled(); };
|
||||||
|
|
||||||
|
firstfit::SelectionStrategy sel{cmpfn, on_arranged, stop_cond};
|
||||||
|
|
||||||
|
constexpr auto ep = ex_tbb;
|
||||||
|
|
||||||
|
VariantKernel basekernel;
|
||||||
|
switch (m_settings.get_arrange_strategy()) {
|
||||||
|
default:
|
||||||
|
[[fallthrough]];
|
||||||
|
case ArrangeSettingsView::asAuto:
|
||||||
|
if constexpr (std::is_convertible_v<Bed, CircleBed>){
|
||||||
|
basekernel = GravityKernel{};
|
||||||
|
} else {
|
||||||
|
basekernel = TMArrangeKernel{items.size(), area(bed)};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ArrangeSettingsView::asPullToCenter:
|
||||||
|
basekernel = GravityKernel{};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
SVGDebugOutputKernelWrapper<VariantKernel> kernel{bounding_box(bed), basekernel};
|
||||||
|
#else
|
||||||
|
auto & kernel = basekernel;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fill_rotations(items, bed, m_settings);
|
||||||
|
|
||||||
|
bool with_wipe_tower = std::any_of(items.begin(), items.end(),
|
||||||
|
[](auto &itm) {
|
||||||
|
return is_wipe_tower(itm);
|
||||||
|
});
|
||||||
|
|
||||||
|
// With rectange bed, and no fixed items, let's use an infinite bed
|
||||||
|
// with RectangleOverfitKernelWrapper. It produces better results than
|
||||||
|
// a pure RectangleBed with inner-fit polygon calculation.
|
||||||
|
if (!with_wipe_tower &&
|
||||||
|
m_settings.get_arrange_strategy() == ArrangeSettingsView::asAuto &&
|
||||||
|
std::is_convertible_v<Bed, RectangleBed>) {
|
||||||
|
PackStrategyNFP base_strategy{std::move(kernel), ep, Accuracy, stop_cond};
|
||||||
|
|
||||||
|
RectangleOverfitPackingStrategy final_strategy{std::move(base_strategy)};
|
||||||
|
|
||||||
|
arr2::arrange(sel, final_strategy, items, fixed, bed);
|
||||||
|
} else {
|
||||||
|
PackStrategyNFP ps{std::move(kernel), ep, Accuracy, stop_cond};
|
||||||
|
|
||||||
|
arr2::arrange(sel, ps, items, fixed, bed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DefaultArranger(const ArrangeSettingsView &settings)
|
||||||
|
{
|
||||||
|
m_settings.set_from(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arrange(
|
||||||
|
std::vector<ArrItem> &items,
|
||||||
|
const std::vector<ArrItem> &fixed,
|
||||||
|
const ExtendedBed &bed,
|
||||||
|
ArrangerCtl<ArrItem> &ctl) override
|
||||||
|
{
|
||||||
|
visit_bed([this, &items, &fixed, &ctl](auto rawbed) {
|
||||||
|
|
||||||
|
if constexpr (IsSegmentedBed<decltype(rawbed)>)
|
||||||
|
rawbed.pivot = xlpivots_to_rect_pivots(
|
||||||
|
m_settings.get_xl_alignment());
|
||||||
|
|
||||||
|
arrange_(range(items), crange(fixed), rawbed, ctl);
|
||||||
|
}, bed);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
std::unique_ptr<Arranger<ArrItem>> Arranger<ArrItem>::create(
|
||||||
|
const ArrangeSettingsView &settings)
|
||||||
|
{
|
||||||
|
// Currently all that is needed is handled by DefaultArranger
|
||||||
|
return std::make_unique<DefaultArranger<ArrItem>>(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
ArrItem ConvexItemConverter<ArrItem>::convert(const Arrangeable &arrbl,
|
||||||
|
coord_t offs) const
|
||||||
|
{
|
||||||
|
auto bed_index = arrbl.get_bed_index();
|
||||||
|
Polygon outline = arrbl.convex_outline();
|
||||||
|
|
||||||
|
if (outline.empty())
|
||||||
|
throw EmptyItemOutlineError{};
|
||||||
|
|
||||||
|
Polygon envelope = arrbl.convex_envelope();
|
||||||
|
|
||||||
|
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
||||||
|
|
||||||
|
if (infl != 0) {
|
||||||
|
outline = Geometry::convex_hull(offset(outline, infl));
|
||||||
|
if (! envelope.empty())
|
||||||
|
envelope = Geometry::convex_hull(offset(envelope, infl));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrItem ret;
|
||||||
|
set_convex_shape(ret, outline);
|
||||||
|
if (! envelope.empty())
|
||||||
|
set_convex_envelope(ret, envelope);
|
||||||
|
|
||||||
|
set_bed_index(ret, bed_index);
|
||||||
|
set_priority(ret, arrbl.priority());
|
||||||
|
|
||||||
|
imbue_id(ret, arrbl.id());
|
||||||
|
if constexpr (IsWritableDataStore<ArrItem>)
|
||||||
|
arrbl.imbue_data(AnyWritableDataStore{ret});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
ArrItem AdvancedItemConverter<ArrItem>::convert(const Arrangeable &arrbl,
|
||||||
|
coord_t offs) const
|
||||||
|
{
|
||||||
|
auto bed_index = arrbl.get_bed_index();
|
||||||
|
ArrItem ret = get_arritem(arrbl, offs);
|
||||||
|
|
||||||
|
set_bed_index(ret, bed_index);
|
||||||
|
set_priority(ret, arrbl.priority());
|
||||||
|
imbue_id(ret, arrbl.id());
|
||||||
|
if constexpr (IsWritableDataStore<ArrItem>)
|
||||||
|
arrbl.imbue_data(AnyWritableDataStore{ret});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
ArrItem AdvancedItemConverter<ArrItem>::get_arritem(const Arrangeable &arrbl,
|
||||||
|
coord_t offs) const
|
||||||
|
{
|
||||||
|
coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.));
|
||||||
|
|
||||||
|
auto outline = arrbl.full_outline();
|
||||||
|
|
||||||
|
if (outline.empty())
|
||||||
|
throw EmptyItemOutlineError{};
|
||||||
|
|
||||||
|
auto envelope = arrbl.full_envelope();
|
||||||
|
|
||||||
|
if (infl != 0) {
|
||||||
|
outline = offset_ex(outline, infl);
|
||||||
|
if (! envelope.empty())
|
||||||
|
envelope = offset_ex(envelope, infl);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto simpl_tol = static_cast<double>(this->simplification_tolerance());
|
||||||
|
|
||||||
|
if (simpl_tol > 0)
|
||||||
|
{
|
||||||
|
outline = expolygons_simplify(outline, simpl_tol);
|
||||||
|
if (!envelope.empty())
|
||||||
|
envelope = expolygons_simplify(envelope, simpl_tol);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrItem ret;
|
||||||
|
set_shape(ret, outline);
|
||||||
|
if (! envelope.empty())
|
||||||
|
set_envelope(ret, envelope);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
ArrItem BalancedItemConverter<ArrItem>::get_arritem(const Arrangeable &arrbl,
|
||||||
|
coord_t offs) const
|
||||||
|
{
|
||||||
|
ArrItem ret = AdvancedItemConverter<ArrItem>::get_arritem(arrbl, offs);
|
||||||
|
set_convex_envelope(ret, envelope_convex_hull(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
std::unique_ptr<ArrangeableToItemConverter<ArrItem>>
|
||||||
|
ArrangeableToItemConverter<ArrItem>::create(
|
||||||
|
ArrangeSettingsView::GeometryHandling gh,
|
||||||
|
coord_t safety_d)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ArrangeableToItemConverter<ArrItem>> ret;
|
||||||
|
|
||||||
|
constexpr coord_t SimplifyTol = scaled(.2);
|
||||||
|
|
||||||
|
switch(gh) {
|
||||||
|
case arr2::ArrangeSettingsView::ghConvex:
|
||||||
|
ret = std::make_unique<ConvexItemConverter<ArrItem>>(safety_d);
|
||||||
|
break;
|
||||||
|
case arr2::ArrangeSettingsView::ghBalanced:
|
||||||
|
ret = std::make_unique<BalancedItemConverter<ArrItem>>(safety_d, SimplifyTol);
|
||||||
|
break;
|
||||||
|
case arr2::ArrangeSettingsView::ghAdvanced:
|
||||||
|
ret = std::make_unique<AdvancedItemConverter<ArrItem>>(safety_d, SimplifyTol);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGEIMPL_HPP
|
||||||
198
src/libslic3r/Arrange/ArrangeSettingsDb_AppCfg.cpp
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
|
||||||
|
#include "ArrangeSettingsDb_AppCfg.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
ArrangeSettingsDb_AppCfg::ArrangeSettingsDb_AppCfg(AppConfig *appcfg) : m_appcfg{appcfg}
|
||||||
|
{
|
||||||
|
m_settings_fff.postfix = "_fff";
|
||||||
|
m_settings_fff_seq.postfix = "_fff_seq_print";
|
||||||
|
m_settings_sla.postfix = "_sla";
|
||||||
|
|
||||||
|
std::string dist_fff_str =
|
||||||
|
m_appcfg->get("arrange", "min_object_distance_fff");
|
||||||
|
|
||||||
|
std::string dist_bed_fff_str =
|
||||||
|
m_appcfg->get("arrange", "min_bed_distance_fff");
|
||||||
|
|
||||||
|
std::string dist_fff_seq_print_str =
|
||||||
|
m_appcfg->get("arrange", "min_object_distance_fff_seq_print");
|
||||||
|
|
||||||
|
std::string dist_bed_fff_seq_print_str =
|
||||||
|
m_appcfg->get("arrange", "min_bed_distance_fff_seq_print");
|
||||||
|
|
||||||
|
std::string dist_sla_str =
|
||||||
|
m_appcfg->get("arrange", "min_object_distance_sla");
|
||||||
|
|
||||||
|
std::string dist_bed_sla_str =
|
||||||
|
m_appcfg->get("arrange", "min_bed_distance_sla");
|
||||||
|
|
||||||
|
std::string en_rot_fff_str =
|
||||||
|
m_appcfg->get("arrange", "enable_rotation_fff");
|
||||||
|
|
||||||
|
std::string en_rot_fff_seqp_str =
|
||||||
|
m_appcfg->get("arrange", "enable_rotation_fff_seq_print");
|
||||||
|
|
||||||
|
std::string en_rot_sla_str =
|
||||||
|
m_appcfg->get("arrange", "enable_rotation_sla");
|
||||||
|
|
||||||
|
// std::string alignment_fff_str =
|
||||||
|
// m_appcfg->get("arrange", "alignment_fff");
|
||||||
|
|
||||||
|
// std::string alignment_fff_seqp_str =
|
||||||
|
// m_appcfg->get("arrange", "alignment_fff_seq_pring");
|
||||||
|
|
||||||
|
// std::string alignment_sla_str =
|
||||||
|
// m_appcfg->get("arrange", "alignment_sla");
|
||||||
|
|
||||||
|
// Override default alignment and save save/load it to a temporary slot "alignment_xl"
|
||||||
|
std::string alignment_xl_str =
|
||||||
|
m_appcfg->get("arrange", "alignment_xl");
|
||||||
|
|
||||||
|
std::string geom_handling_str =
|
||||||
|
m_appcfg->get("arrange", "geometry_handling");
|
||||||
|
|
||||||
|
std::string strategy_str =
|
||||||
|
m_appcfg->get("arrange", "arrange_strategy");
|
||||||
|
|
||||||
|
if (!dist_fff_str.empty())
|
||||||
|
m_settings_fff.vals.d_obj = string_to_float_decimal_point(dist_fff_str);
|
||||||
|
|
||||||
|
if (!dist_bed_fff_str.empty())
|
||||||
|
m_settings_fff.vals.d_bed = string_to_float_decimal_point(dist_bed_fff_str);
|
||||||
|
|
||||||
|
if (!dist_fff_seq_print_str.empty())
|
||||||
|
m_settings_fff_seq.vals.d_obj = string_to_float_decimal_point(dist_fff_seq_print_str);
|
||||||
|
|
||||||
|
if (!dist_bed_fff_seq_print_str.empty())
|
||||||
|
m_settings_fff_seq.vals.d_bed = string_to_float_decimal_point(dist_bed_fff_seq_print_str);
|
||||||
|
|
||||||
|
if (!dist_sla_str.empty())
|
||||||
|
m_settings_sla.vals.d_obj = string_to_float_decimal_point(dist_sla_str);
|
||||||
|
|
||||||
|
if (!dist_bed_sla_str.empty())
|
||||||
|
m_settings_sla.vals.d_bed = string_to_float_decimal_point(dist_bed_sla_str);
|
||||||
|
|
||||||
|
if (!en_rot_fff_str.empty())
|
||||||
|
m_settings_fff.vals.rotations = (en_rot_fff_str == "1" || en_rot_fff_str == "yes");
|
||||||
|
|
||||||
|
if (!en_rot_fff_seqp_str.empty())
|
||||||
|
m_settings_fff_seq.vals.rotations = (en_rot_fff_seqp_str == "1" || en_rot_fff_seqp_str == "yes");
|
||||||
|
|
||||||
|
if (!en_rot_sla_str.empty())
|
||||||
|
m_settings_sla.vals.rotations = (en_rot_sla_str == "1" || en_rot_sla_str == "yes");
|
||||||
|
|
||||||
|
// if (!alignment_sla_str.empty())
|
||||||
|
// m_arrange_settings_sla.alignment = std::stoi(alignment_sla_str);
|
||||||
|
|
||||||
|
// if (!alignment_fff_str.empty())
|
||||||
|
// m_arrange_settings_fff.alignment = std::stoi(alignment_fff_str);
|
||||||
|
|
||||||
|
// if (!alignment_fff_seqp_str.empty())
|
||||||
|
// m_arrange_settings_fff_seq_print.alignment = std::stoi(alignment_fff_seqp_str);
|
||||||
|
|
||||||
|
// Override default alignment and save save/load it to a temporary slot "alignment_xl"
|
||||||
|
ArrangeSettingsView::XLPivots arr_alignment = ArrangeSettingsView::xlpFrontLeft;
|
||||||
|
if (!alignment_xl_str.empty()) {
|
||||||
|
int align_val = std::stoi(alignment_xl_str);
|
||||||
|
|
||||||
|
if (align_val >= 0 && align_val < ArrangeSettingsView::xlpCount)
|
||||||
|
arr_alignment =
|
||||||
|
static_cast<ArrangeSettingsView::XLPivots>(align_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings_sla.vals.xl_align = arr_alignment ;
|
||||||
|
m_settings_fff.vals.xl_align = arr_alignment ;
|
||||||
|
m_settings_fff_seq.vals.xl_align = arr_alignment ;
|
||||||
|
|
||||||
|
ArrangeSettingsView::GeometryHandling geom_handl = arr2::ArrangeSettingsView::ghConvex;
|
||||||
|
if (!geom_handling_str.empty()) {
|
||||||
|
int gh = std::stoi(geom_handling_str);
|
||||||
|
if(gh >= 0 && gh < ArrangeSettingsView::GeometryHandling::ghCount)
|
||||||
|
geom_handl = static_cast<ArrangeSettingsView::GeometryHandling>(gh);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings_sla.vals.geom_handling = geom_handl;
|
||||||
|
m_settings_fff.vals.geom_handling = geom_handl;
|
||||||
|
m_settings_fff_seq.vals.geom_handling = geom_handl;
|
||||||
|
|
||||||
|
ArrangeSettingsView::ArrangeStrategy arr_strategy = arr2::ArrangeSettingsView::asAuto;
|
||||||
|
if (!strategy_str.empty()) {
|
||||||
|
int strateg = std::stoi(strategy_str);
|
||||||
|
if(strateg >= 0 && strateg < ArrangeSettingsView::ArrangeStrategy::asCount)
|
||||||
|
arr_strategy = static_cast<ArrangeSettingsView::ArrangeStrategy>(strateg);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings_sla.vals.arr_strategy = arr_strategy;
|
||||||
|
m_settings_fff.vals.arr_strategy = arr_strategy;
|
||||||
|
m_settings_fff_seq.vals.arr_strategy = arr_strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArrangeSettingsDb_AppCfg::distance_from_obj_range(float &min,
|
||||||
|
float &max) const
|
||||||
|
{
|
||||||
|
min = get_slot(this).dobj_range.minval;
|
||||||
|
max = get_slot(this).dobj_range.maxval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArrangeSettingsDb_AppCfg::distance_from_bed_range(float &min,
|
||||||
|
float &max) const
|
||||||
|
{
|
||||||
|
min = get_slot(this).dbed_range.minval;
|
||||||
|
max = get_slot(this).dbed_range.maxval;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_distance_from_objects(float v)
|
||||||
|
{
|
||||||
|
Slot &slot = get_slot(this);
|
||||||
|
slot.vals.d_obj = v;
|
||||||
|
m_appcfg->set("arrange", "min_object_distance" + slot.postfix,
|
||||||
|
float_to_string_decimal_point(v));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_distance_from_bed(float v)
|
||||||
|
{
|
||||||
|
Slot &slot = get_slot(this);
|
||||||
|
slot.vals.d_bed = v;
|
||||||
|
m_appcfg->set("arrange", "min_bed_distance" + slot.postfix,
|
||||||
|
float_to_string_decimal_point(v));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_rotation_enabled(bool v)
|
||||||
|
{
|
||||||
|
Slot &slot = get_slot(this);
|
||||||
|
slot.vals.rotations = v;
|
||||||
|
m_appcfg->set("arrange", "enable_rotation" + slot.postfix, v ? "1" : "0");
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_xl_alignment(XLPivots v)
|
||||||
|
{
|
||||||
|
m_settings_fff.vals.xl_align = v;
|
||||||
|
m_appcfg->set("arrange", "alignment_xl", std::to_string(v));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_geometry_handling(GeometryHandling v)
|
||||||
|
{
|
||||||
|
m_settings_fff.vals.geom_handling = v;
|
||||||
|
m_appcfg->set("arrange", "geometry_handling", std::to_string(v));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr2::ArrangeSettingsDb& ArrangeSettingsDb_AppCfg::set_arrange_strategy(ArrangeStrategy v)
|
||||||
|
{
|
||||||
|
m_settings_fff.vals.arr_strategy = v;
|
||||||
|
m_appcfg->set("arrange", "arrange_strategy", std::to_string(v));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
92
src/libslic3r/Arrange/ArrangeSettingsDb_AppCfg.hpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGESETTINGSDB_APPCFG_HPP
|
||||||
|
#define ARRANGESETTINGSDB_APPCFG_HPP
|
||||||
|
|
||||||
|
#include "ArrangeSettingsView.hpp"
|
||||||
|
#include "libslic3r/AppConfig.hpp"
|
||||||
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class ArrangeSettingsDb_AppCfg: public arr2::ArrangeSettingsDb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Slots { slotFFF, slotFFFSeqPrint, slotSLA };
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppConfig *m_appcfg;
|
||||||
|
Slots m_current_slot = slotFFF;
|
||||||
|
|
||||||
|
struct FloatRange { float minval = 0.f, maxval = 100.f; };
|
||||||
|
struct Slot
|
||||||
|
{
|
||||||
|
Values vals;
|
||||||
|
Values defaults;
|
||||||
|
FloatRange dobj_range, dbed_range;
|
||||||
|
std::string postfix;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Settings and their defaults are stored separately for fff,
|
||||||
|
// sla and fff sequential mode
|
||||||
|
Slot m_settings_fff, m_settings_fff_seq, m_settings_sla;
|
||||||
|
|
||||||
|
template<class Self>
|
||||||
|
static auto & get_slot(Self *self, Slots slot) {
|
||||||
|
switch(slot) {
|
||||||
|
case slotFFF: return self->m_settings_fff;
|
||||||
|
case slotFFFSeqPrint: return self->m_settings_fff_seq;
|
||||||
|
case slotSLA: return self->m_settings_sla;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self->m_settings_fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Self> static auto &get_slot(Self *self)
|
||||||
|
{
|
||||||
|
return get_slot(self, self->m_current_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Self>
|
||||||
|
static auto& get_ref(Self *self) { return get_slot(self).vals; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ArrangeSettingsDb_AppCfg(AppConfig *appcfg);
|
||||||
|
|
||||||
|
float get_distance_from_objects() const override { return get_ref(this).d_obj; }
|
||||||
|
float get_distance_from_bed() const override { return get_ref(this).d_bed; }
|
||||||
|
bool is_rotation_enabled() const override { return get_ref(this).rotations; }
|
||||||
|
|
||||||
|
XLPivots get_xl_alignment() const override { return m_settings_fff.vals.xl_align; }
|
||||||
|
GeometryHandling get_geometry_handling() const override { return m_settings_fff.vals.geom_handling; }
|
||||||
|
ArrangeStrategy get_arrange_strategy() const override { return m_settings_fff.vals.arr_strategy; }
|
||||||
|
|
||||||
|
void distance_from_obj_range(float &min, float &max) const override;
|
||||||
|
void distance_from_bed_range(float &min, float &max) const override;
|
||||||
|
|
||||||
|
ArrangeSettingsDb& set_distance_from_objects(float v) override;
|
||||||
|
ArrangeSettingsDb& set_distance_from_bed(float v) override;
|
||||||
|
ArrangeSettingsDb& set_rotation_enabled(bool v) override;
|
||||||
|
|
||||||
|
ArrangeSettingsDb& set_xl_alignment(XLPivots v) override;
|
||||||
|
ArrangeSettingsDb& set_geometry_handling(GeometryHandling v) override;
|
||||||
|
ArrangeSettingsDb& set_arrange_strategy(ArrangeStrategy v) override;
|
||||||
|
|
||||||
|
Values get_defaults() const override { return get_slot(this).defaults; }
|
||||||
|
|
||||||
|
void set_active_slot(Slots slot) noexcept { m_current_slot = slot; }
|
||||||
|
void set_distance_from_obj_range(Slots slot, float min, float max)
|
||||||
|
{
|
||||||
|
get_slot(this, slot).dobj_range = FloatRange{min, max};
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_distance_from_bed_range(Slots slot, float min, float max)
|
||||||
|
{
|
||||||
|
get_slot(this, slot).dbed_range = FloatRange{min, max};
|
||||||
|
}
|
||||||
|
|
||||||
|
Values &get_defaults(Slots slot) { return get_slot(this, slot).defaults; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // ARRANGESETTINGSDB_APPCFG_HPP
|
||||||
119
src/libslic3r/Arrange/ArrangeSettingsView.hpp
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGESETTINGSVIEW_HPP
|
||||||
|
#define ARRANGESETTINGSVIEW_HPP
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
class ArrangeSettingsView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum GeometryHandling { ghConvex, ghBalanced, ghAdvanced, ghCount };
|
||||||
|
enum ArrangeStrategy { asAuto, asPullToCenter, asCount };
|
||||||
|
enum XLPivots {
|
||||||
|
xlpCenter,
|
||||||
|
xlpRearLeft,
|
||||||
|
xlpFrontLeft,
|
||||||
|
xlpFrontRight,
|
||||||
|
xlpRearRight,
|
||||||
|
xlpRandom,
|
||||||
|
xlpCount
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~ArrangeSettingsView() = default;
|
||||||
|
|
||||||
|
virtual float get_distance_from_objects() const = 0;
|
||||||
|
virtual float get_distance_from_bed() const = 0;
|
||||||
|
virtual bool is_rotation_enabled() const = 0;
|
||||||
|
|
||||||
|
virtual XLPivots get_xl_alignment() const = 0;
|
||||||
|
virtual GeometryHandling get_geometry_handling() const = 0;
|
||||||
|
virtual ArrangeStrategy get_arrange_strategy() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrangeSettingsDb: public ArrangeSettingsView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void distance_from_obj_range(float &min, float &max) const = 0;
|
||||||
|
virtual void distance_from_bed_range(float &min, float &max) const = 0;
|
||||||
|
|
||||||
|
virtual ArrangeSettingsDb& set_distance_from_objects(float v) = 0;
|
||||||
|
virtual ArrangeSettingsDb& set_distance_from_bed(float v) = 0;
|
||||||
|
virtual ArrangeSettingsDb& set_rotation_enabled(bool v) = 0;
|
||||||
|
|
||||||
|
virtual ArrangeSettingsDb& set_xl_alignment(XLPivots v) = 0;
|
||||||
|
virtual ArrangeSettingsDb& set_geometry_handling(GeometryHandling v) = 0;
|
||||||
|
virtual ArrangeSettingsDb& set_arrange_strategy(ArrangeStrategy v) = 0;
|
||||||
|
|
||||||
|
struct Values {
|
||||||
|
float d_obj = 6.f, d_bed = 0.f;
|
||||||
|
bool rotations = false;
|
||||||
|
XLPivots xl_align = XLPivots::xlpFrontLeft;
|
||||||
|
GeometryHandling geom_handling = GeometryHandling::ghConvex;
|
||||||
|
ArrangeStrategy arr_strategy = ArrangeStrategy::asAuto;
|
||||||
|
|
||||||
|
Values() = default;
|
||||||
|
Values(const ArrangeSettingsView &sv)
|
||||||
|
{
|
||||||
|
d_bed = sv.get_distance_from_bed();
|
||||||
|
d_obj = sv.get_distance_from_objects();
|
||||||
|
arr_strategy = sv.get_arrange_strategy();
|
||||||
|
geom_handling = sv.get_geometry_handling();
|
||||||
|
rotations = sv.is_rotation_enabled();
|
||||||
|
xl_align = sv.get_xl_alignment();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual Values get_defaults() const { return {}; }
|
||||||
|
|
||||||
|
ArrangeSettingsDb& set_from(const ArrangeSettingsView &sv)
|
||||||
|
{
|
||||||
|
set_distance_from_bed(sv.get_distance_from_bed());
|
||||||
|
set_distance_from_objects(sv.get_distance_from_objects());
|
||||||
|
set_arrange_strategy(sv.get_arrange_strategy());
|
||||||
|
set_geometry_handling(sv.get_geometry_handling());
|
||||||
|
set_rotation_enabled(sv.is_rotation_enabled());
|
||||||
|
set_xl_alignment(sv.get_xl_alignment());
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrangeSettings: public Slic3r::arr2::ArrangeSettingsDb
|
||||||
|
{
|
||||||
|
ArrangeSettingsDb::Values m_v = {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ArrangeSettings(
|
||||||
|
const ArrangeSettingsDb::Values &v = {})
|
||||||
|
: m_v{v}
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit ArrangeSettings(const ArrangeSettingsView &v)
|
||||||
|
: m_v{v}
|
||||||
|
{}
|
||||||
|
|
||||||
|
float get_distance_from_objects() const override { return m_v.d_obj; }
|
||||||
|
float get_distance_from_bed() const override { return m_v.d_bed; }
|
||||||
|
bool is_rotation_enabled() const override { return m_v.rotations; }
|
||||||
|
XLPivots get_xl_alignment() const override { return m_v.xl_align; }
|
||||||
|
GeometryHandling get_geometry_handling() const override { return m_v.geom_handling; }
|
||||||
|
ArrangeStrategy get_arrange_strategy() const override { return m_v.arr_strategy; }
|
||||||
|
|
||||||
|
void distance_from_obj_range(float &min, float &max) const override { min = 0.f; max = 100.f; }
|
||||||
|
void distance_from_bed_range(float &min, float &max) const override { min = 0.f; max = 100.f; }
|
||||||
|
|
||||||
|
ArrangeSettings& set_distance_from_objects(float v) override { m_v.d_obj = v; return *this; }
|
||||||
|
ArrangeSettings& set_distance_from_bed(float v) override { m_v.d_bed = v; return *this; }
|
||||||
|
ArrangeSettings& set_rotation_enabled(bool v) override { m_v.rotations = v; return *this; }
|
||||||
|
ArrangeSettings& set_xl_alignment(XLPivots v) override { m_v.xl_align = v; return *this; }
|
||||||
|
ArrangeSettings& set_geometry_handling(GeometryHandling v) override { m_v.geom_handling = v; return *this; }
|
||||||
|
ArrangeSettings& set_arrange_strategy(ArrangeStrategy v) override { m_v.arr_strategy = v; return *this; }
|
||||||
|
|
||||||
|
auto & values() const { return m_v; }
|
||||||
|
auto & values() { return m_v; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGESETTINGSVIEW_HPP
|
||||||
295
src/libslic3r/Arrange/Core/ArrangeBase.hpp
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGEBASE_HPP
|
||||||
|
#define ARRANGEBASE_HPP
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "ArrangeItemTraits.hpp"
|
||||||
|
#include "PackingContext.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
namespace detail_is_const_it {
|
||||||
|
|
||||||
|
template<class It, class En = void>
|
||||||
|
struct IsConstIt_ { static constexpr bool value = false; };
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
using iterator_category_t = typename std::iterator_traits<It>::iterator_category;
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
using iterator_reference_t = typename std::iterator_traits<It>::reference;
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
struct IsConstIt_ <It, std::enable_if_t<std::is_class_v<iterator_category_t<It>>> >
|
||||||
|
{
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_const_v<std::remove_reference_t<iterator_reference_t<It>>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail_is_const_it
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
static constexpr bool IsConstIterator = detail_is_const_it::IsConstIt_<It>::value;
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
constexpr bool is_const_iterator(const It &it) noexcept { return IsConstIterator<It>; }
|
||||||
|
|
||||||
|
// The pack() function will use tag dispatching, based on the given strategy
|
||||||
|
// object that is used as its first argument.
|
||||||
|
|
||||||
|
// This tag is derived for a packing strategy as default, and will be used
|
||||||
|
// to cast a compile error.
|
||||||
|
struct UnimplementedPacking {};
|
||||||
|
|
||||||
|
// PackStrategyTag_ needs to be specialized for any valid packing strategy class
|
||||||
|
template<class PackStrategy> struct PackStrategyTag_ {
|
||||||
|
using Tag = UnimplementedPacking;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper metafunc to derive packing strategy tag from a strategy object.
|
||||||
|
template<class Strategy>
|
||||||
|
using PackStrategyTag =
|
||||||
|
typename PackStrategyTag_<remove_cvref_t<Strategy>>::Tag;
|
||||||
|
|
||||||
|
|
||||||
|
template<class PackStrategy, class En = void> struct PackStrategyTraits_ {
|
||||||
|
template<class ArrItem> using Context = DefaultPackingContext<ArrItem>;
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed>
|
||||||
|
static Context<ArrItem> create_context(PackStrategy &ps,
|
||||||
|
const Bed &bed,
|
||||||
|
int bed_index)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class PS> using PackStrategyTraits = PackStrategyTraits_<StripCVRef<PS>>;
|
||||||
|
|
||||||
|
template<class PS, class ArrItem>
|
||||||
|
using PackStrategyContext =
|
||||||
|
typename PackStrategyTraits<PS>::template Context<StripCVRef<ArrItem>>;
|
||||||
|
|
||||||
|
template<class ArrItem, class PackStrategy, class Bed>
|
||||||
|
PackStrategyContext<PackStrategy, ArrItem> create_context(PackStrategy &&ps,
|
||||||
|
const Bed &bed,
|
||||||
|
int bed_index)
|
||||||
|
{
|
||||||
|
return PackStrategyTraits<PackStrategy>::template create_context<
|
||||||
|
StripCVRef<ArrItem>>(ps, bed, bed_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to pack one item into a bed.
|
||||||
|
// strategy parameter holds clue to what packing strategy to use. This function
|
||||||
|
// needs to be overloaded for the strategy tag belonging to the given
|
||||||
|
// strategy.
|
||||||
|
// 'bed' parameter is the type of bed into which the new item should be packed.
|
||||||
|
// See beds.hpp for valid bed classes.
|
||||||
|
// 'item' parameter is the item to be packed. After succesful arrangement
|
||||||
|
// (see return value) the item will have it's translation and rotation
|
||||||
|
// set correctly. If the function returns false, the translation and
|
||||||
|
// rotation of the input item might be changed to arbitrary values.
|
||||||
|
// 'fixed_items' paramter holds a range of ArrItem type objects that are already
|
||||||
|
// on the bed and need to be avoided by the newly packed item.
|
||||||
|
// 'remaining_items' is a range of ArrItem type objects that are intended to be
|
||||||
|
// packed in the future. This information can be leveradged by
|
||||||
|
// the packing strategy to make more intelligent placement
|
||||||
|
// decisions for the input item.
|
||||||
|
template<class Strategy, class Bed, class ArrItem, class RemIt>
|
||||||
|
bool pack(Strategy &&strategy,
|
||||||
|
const Bed &bed,
|
||||||
|
ArrItem &item,
|
||||||
|
const PackStrategyContext<Strategy, ArrItem> &context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
static_assert(IsConstIterator<RemIt>, "Remaining item iterator is not const!");
|
||||||
|
|
||||||
|
// Dispatch:
|
||||||
|
return pack(std::forward<Strategy>(strategy), bed, item, context,
|
||||||
|
remaining_items, PackStrategyTag<Strategy>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload without fixed items:
|
||||||
|
template<class Strategy, class Bed, class ArrItem>
|
||||||
|
bool pack(Strategy &&strategy, const Bed &bed, ArrItem &item)
|
||||||
|
{
|
||||||
|
std::vector<ArrItem> dummy;
|
||||||
|
auto context = create_context<ArrItem>(strategy, bed, PhysicalBedId);
|
||||||
|
return pack(std::forward<Strategy>(strategy), bed, item, context,
|
||||||
|
crange(dummy));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload when strategy is unkown, yields compile error:
|
||||||
|
template<class Strategy, class Bed, class ArrItem, class RemIt>
|
||||||
|
bool pack(Strategy &&strategy,
|
||||||
|
const Bed &bed,
|
||||||
|
ArrItem &item,
|
||||||
|
const PackStrategyContext<Strategy, ArrItem> &context,
|
||||||
|
const Range<RemIt> &remaining_items,
|
||||||
|
const UnimplementedPacking &)
|
||||||
|
{
|
||||||
|
static_assert(always_false<Strategy>::value,
|
||||||
|
"Packing unimplemented for this placement strategy");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to remove unpackable items from the input container.
|
||||||
|
template<class PackStrategy, class Container, class Bed, class StopCond>
|
||||||
|
void remove_unpackable_items(PackStrategy &&ps,
|
||||||
|
Container &c,
|
||||||
|
const Bed &bed,
|
||||||
|
const StopCond &stopcond)
|
||||||
|
{
|
||||||
|
// Safety test: try to pack each item into an empty bed. If it fails
|
||||||
|
// then it should be removed from the list
|
||||||
|
auto it = c.begin();
|
||||||
|
while (it != c.end() && !stopcond()) {
|
||||||
|
StripCVRef<decltype(*it)> &itm = *it;
|
||||||
|
auto cpy{itm};
|
||||||
|
|
||||||
|
if (!pack(ps, bed, cpy)) {
|
||||||
|
set_bed_index(itm, Unarranged);
|
||||||
|
it = c.erase(it);
|
||||||
|
} else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// arrange() function will use tag dispatching based on the selection strategy
|
||||||
|
// given as its first argument.
|
||||||
|
|
||||||
|
// This tag is derived for a selection strategy as default, and will be used
|
||||||
|
// to cast a compile error.
|
||||||
|
struct UnimplementedSelection {};
|
||||||
|
|
||||||
|
// SelStrategyTag_ needs to be specialized for any valid selection strategy class
|
||||||
|
template<class SelStrategy> struct SelStrategyTag_ {
|
||||||
|
using Tag = UnimplementedSelection;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper metafunc to derive the selection strategy tag from a strategy object.
|
||||||
|
template<class Strategy>
|
||||||
|
using SelStrategyTag = typename SelStrategyTag_<remove_cvref_t<Strategy>>::Tag;
|
||||||
|
|
||||||
|
// Main function to start the arrangement. Takes a selection and a packing
|
||||||
|
// strategy object as the first two parameters. An implementation
|
||||||
|
// (function overload) must exist for this function that takes the coresponding
|
||||||
|
// selection strategy tag belonging to the given selstrategy argument.
|
||||||
|
//
|
||||||
|
// items parameter is a range of arrange items to arrange.
|
||||||
|
// fixed parameter is a range of arrange items that have fixed position and will
|
||||||
|
// not move during the arrangement but need to be avoided by the
|
||||||
|
// moving items.
|
||||||
|
// bed parameter is the type of bed into which the items need to fit.
|
||||||
|
template<class It,
|
||||||
|
class ConstIt,
|
||||||
|
class TBed,
|
||||||
|
class SelectionStrategy,
|
||||||
|
class PackStrategy>
|
||||||
|
void arrange(SelectionStrategy &&selstrategy,
|
||||||
|
PackStrategy &&packingstrategy,
|
||||||
|
const Range<It> &items,
|
||||||
|
const Range<ConstIt> &fixed,
|
||||||
|
const TBed &bed)
|
||||||
|
{
|
||||||
|
static_assert(IsConstIterator<ConstIt>, "Fixed item iterator is not const!");
|
||||||
|
|
||||||
|
// Dispatch:
|
||||||
|
arrange(std::forward<SelectionStrategy>(selstrategy),
|
||||||
|
std::forward<PackStrategy>(packingstrategy), items, fixed, bed,
|
||||||
|
SelStrategyTag<SelectionStrategy>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It, class TBed, class SelectionStrategy, class PackStrategy>
|
||||||
|
void arrange(SelectionStrategy &&selstrategy,
|
||||||
|
PackStrategy &&packingstrategy,
|
||||||
|
const Range<It> &items,
|
||||||
|
const TBed &bed)
|
||||||
|
{
|
||||||
|
std::vector<typename std::iterator_traits<It>::value_type> dummy;
|
||||||
|
arrange(std::forward<SelectionStrategy>(selstrategy),
|
||||||
|
std::forward<PackStrategy>(packingstrategy), items, crange(dummy),
|
||||||
|
bed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload for unimplemented selection strategy, yields compile error:
|
||||||
|
template<class It,
|
||||||
|
class ConstIt,
|
||||||
|
class TBed,
|
||||||
|
class SelectionStrategy,
|
||||||
|
class PackStrategy>
|
||||||
|
void arrange(SelectionStrategy &&selstrategy,
|
||||||
|
PackStrategy &&packingstrategy,
|
||||||
|
const Range<It> &items,
|
||||||
|
const Range<ConstIt> &fixed,
|
||||||
|
const TBed &bed,
|
||||||
|
const UnimplementedSelection &)
|
||||||
|
{
|
||||||
|
static_assert(always_false<SelectionStrategy>::value,
|
||||||
|
"Arrange unimplemented for this selection strategy");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
std::vector<int> get_bed_indices(const Range<It> &items)
|
||||||
|
{
|
||||||
|
auto bed_indices = reserve_vector<int>(items.size());
|
||||||
|
|
||||||
|
for (auto &itm : items)
|
||||||
|
bed_indices.emplace_back(get_bed_index(itm));
|
||||||
|
|
||||||
|
std::sort(bed_indices.begin(), bed_indices.end());
|
||||||
|
auto endit = std::unique(bed_indices.begin(), bed_indices.end());
|
||||||
|
|
||||||
|
bed_indices.erase(endit, bed_indices.end());
|
||||||
|
|
||||||
|
return bed_indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It, class CIt>
|
||||||
|
std::vector<int> get_bed_indices(const Range<It> &items, const Range<CIt> &fixed)
|
||||||
|
{
|
||||||
|
std::vector<int> ret;
|
||||||
|
|
||||||
|
auto iitems = get_bed_indices(items);
|
||||||
|
auto ifixed = get_bed_indices(fixed);
|
||||||
|
ret.reserve(std::max(iitems.size(), ifixed.size()));
|
||||||
|
std::set_union(iitems.begin(), iitems.end(),
|
||||||
|
ifixed.begin(), ifixed.end(),
|
||||||
|
std::back_inserter(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
size_t get_bed_count(const Range<It> &items)
|
||||||
|
{
|
||||||
|
return get_bed_indices(items).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It> int get_max_bed_index(const Range<It> &items)
|
||||||
|
{
|
||||||
|
auto it = std::max_element(items.begin(),
|
||||||
|
items.end(),
|
||||||
|
[](auto &i1, auto &i2) {
|
||||||
|
return get_bed_index(i1) < get_bed_index(i2);
|
||||||
|
});
|
||||||
|
|
||||||
|
int ret = Unarranged;
|
||||||
|
if (it != items.end())
|
||||||
|
ret = get_bed_index(*it);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DefaultStopCondition {
|
||||||
|
constexpr bool operator()() const noexcept { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGEBASE_HPP
|
||||||
166
src/libslic3r/Arrange/Core/ArrangeFirstFit.hpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGEFIRSTFIT_HPP
|
||||||
|
#define ARRANGEFIRSTFIT_HPP
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <libslic3r/Arrange/Core/ArrangeBase.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 { namespace firstfit {
|
||||||
|
|
||||||
|
struct SelectionTag {};
|
||||||
|
|
||||||
|
// Can be specialized by Items
|
||||||
|
template<class ArrItem, class En = void>
|
||||||
|
struct ItemArrangedVisitor {
|
||||||
|
template<class Bed, class PIt, class RIt>
|
||||||
|
static void on_arranged(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Range<PIt> &packed_items,
|
||||||
|
const Range<RIt> &remaining_items)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use the the visitor baked into the ArrItem type by default
|
||||||
|
struct DefaultOnArrangedFn {
|
||||||
|
template<class ArrItem, class Bed, class PIt, class RIt>
|
||||||
|
void operator()(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Range<PIt> &packed,
|
||||||
|
const Range<RIt> &remaining)
|
||||||
|
{
|
||||||
|
ItemArrangedVisitor<StripCVRef<ArrItem>>::on_arranged(itm, bed, packed,
|
||||||
|
remaining);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DefaultItemCompareFn {
|
||||||
|
template<class ArrItem>
|
||||||
|
bool operator() (const ArrItem &ia, const ArrItem &ib)
|
||||||
|
{
|
||||||
|
return get_priority(ia) > get_priority(ib);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class CompareFn = DefaultItemCompareFn,
|
||||||
|
class OnArrangedFn = DefaultOnArrangedFn,
|
||||||
|
class StopCondition = DefaultStopCondition>
|
||||||
|
struct SelectionStrategy
|
||||||
|
{
|
||||||
|
CompareFn cmpfn;
|
||||||
|
OnArrangedFn on_arranged_fn;
|
||||||
|
StopCondition cancel_fn;
|
||||||
|
|
||||||
|
SelectionStrategy(CompareFn cmp = {},
|
||||||
|
OnArrangedFn on_arranged = {},
|
||||||
|
StopCondition stopcond = {})
|
||||||
|
: cmpfn{cmp},
|
||||||
|
on_arranged_fn{std::move(on_arranged)},
|
||||||
|
cancel_fn{std::move(stopcond)}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace firstfit
|
||||||
|
|
||||||
|
template<class... Args> struct SelStrategyTag_<firstfit::SelectionStrategy<Args...>> {
|
||||||
|
using Tag = firstfit::SelectionTag;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class It,
|
||||||
|
class ConstIt,
|
||||||
|
class TBed,
|
||||||
|
class SelStrategy,
|
||||||
|
class PackStrategy>
|
||||||
|
void arrange(
|
||||||
|
SelStrategy &&sel,
|
||||||
|
PackStrategy &&ps,
|
||||||
|
const Range<It> &items,
|
||||||
|
const Range<ConstIt> &fixed,
|
||||||
|
const TBed &bed,
|
||||||
|
const firstfit::SelectionTag &)
|
||||||
|
{
|
||||||
|
using ArrItem = typename std::iterator_traits<It>::value_type;
|
||||||
|
using ArrItemRef = std::reference_wrapper<ArrItem>;
|
||||||
|
|
||||||
|
auto sorted_items = reserve_vector<ArrItemRef>(items.size());
|
||||||
|
|
||||||
|
for (auto &itm : items) {
|
||||||
|
set_bed_index(itm, Unarranged);
|
||||||
|
sorted_items.emplace_back(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
using Context = PackStrategyContext<PackStrategy, ArrItem>;
|
||||||
|
|
||||||
|
std::map<int, Context> bed_contexts;
|
||||||
|
auto get_or_init_context = [&ps, &bed, &bed_contexts](int bedidx) -> Context& {
|
||||||
|
auto ctx_it = bed_contexts.find(bedidx);
|
||||||
|
if (ctx_it == bed_contexts.end()) {
|
||||||
|
auto res = bed_contexts.emplace(
|
||||||
|
bedidx, create_context<ArrItem>(ps, bed, bedidx));
|
||||||
|
|
||||||
|
assert(res.second);
|
||||||
|
|
||||||
|
ctx_it = res.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx_it->second;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &itm : fixed) {
|
||||||
|
auto bedidx = get_bed_index(itm);
|
||||||
|
if (bedidx >= 0) {
|
||||||
|
Context &ctx = get_or_init_context(bedidx);
|
||||||
|
add_fixed_item(ctx, itm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (!std::is_null_pointer_v<decltype(sel.cmpfn)>) {
|
||||||
|
std::stable_sort(sorted_items.begin(), sorted_items.end(), sel.cmpfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto is_cancelled = [&sel]() {
|
||||||
|
return sel.cancel_fn();
|
||||||
|
};
|
||||||
|
|
||||||
|
remove_unpackable_items(ps, sorted_items, bed, [&is_cancelled]() {
|
||||||
|
return is_cancelled();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto it = sorted_items.begin();
|
||||||
|
|
||||||
|
using SConstIt = typename std::vector<ArrItemRef>::const_iterator;
|
||||||
|
|
||||||
|
while (it != sorted_items.end() && !is_cancelled()) {
|
||||||
|
bool was_packed = false;
|
||||||
|
int bedidx = 0;
|
||||||
|
while (!was_packed && !is_cancelled()) {
|
||||||
|
for (; !was_packed && !is_cancelled(); bedidx++) {
|
||||||
|
set_bed_index(*it, bedidx);
|
||||||
|
|
||||||
|
auto remaining = Range{std::next(static_cast<SConstIt>(it)),
|
||||||
|
sorted_items.cend()};
|
||||||
|
|
||||||
|
Context &ctx = get_or_init_context(bedidx);
|
||||||
|
|
||||||
|
was_packed = pack(ps, bed, *it, ctx, remaining);
|
||||||
|
|
||||||
|
if(was_packed) {
|
||||||
|
add_packed_item(ctx, *it);
|
||||||
|
|
||||||
|
auto packed_range = Range{sorted_items.cbegin(),
|
||||||
|
static_cast<SConstIt>(it)};
|
||||||
|
|
||||||
|
sel.on_arranged_fn(*it, bed, packed_range, remaining);
|
||||||
|
} else {
|
||||||
|
set_bed_index(*it, Unarranged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGEFIRSTFIT_HPP
|
||||||
114
src/libslic3r/Arrange/Core/ArrangeItemTraits.hpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGE_ITEM_TRAITS_HPP
|
||||||
|
#define ARRANGE_ITEM_TRAITS_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/Point.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// A logical bed representing an object not being arranged. Either the arrange
|
||||||
|
// has not yet successfully run on this ArrangePolygon or it could not fit the
|
||||||
|
// object due to overly large size or invalid geometry.
|
||||||
|
const constexpr int Unarranged = -1;
|
||||||
|
|
||||||
|
const constexpr int PhysicalBedId = 0;
|
||||||
|
|
||||||
|
// Basic interface of an arrange item. This struct can be specialized for any
|
||||||
|
// type that is arrangeable.
|
||||||
|
template<class ArrItem, class En = void> struct ArrangeItemTraits_ {
|
||||||
|
static Vec2crd get_translation(const ArrItem &ap)
|
||||||
|
{
|
||||||
|
return ap.get_translation();
|
||||||
|
}
|
||||||
|
|
||||||
|
static double get_rotation(const ArrItem &ap)
|
||||||
|
{
|
||||||
|
return ap.get_rotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_bed_index(const ArrItem &ap) { return ap.get_bed_index(); }
|
||||||
|
|
||||||
|
static int get_priority(const ArrItem &ap) { return ap.get_priority(); }
|
||||||
|
|
||||||
|
// Setters:
|
||||||
|
|
||||||
|
static void set_translation(ArrItem &ap, const Vec2crd &v)
|
||||||
|
{
|
||||||
|
ap.set_translation(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_rotation(ArrItem &ap, double v) { ap.set_rotation(v); }
|
||||||
|
|
||||||
|
static void set_bed_index(ArrItem &ap, int v) { ap.set_bed_index(v); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T> using ArrangeItemTraits = ArrangeItemTraits_<StripCVRef<T>>;
|
||||||
|
|
||||||
|
// Getters:
|
||||||
|
|
||||||
|
template<class T> Vec2crd get_translation(const T &itm)
|
||||||
|
{
|
||||||
|
return ArrangeItemTraits<T>::get_translation(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> double get_rotation(const T &itm)
|
||||||
|
{
|
||||||
|
return ArrangeItemTraits<T>::get_rotation(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> int get_bed_index(const T &itm)
|
||||||
|
{
|
||||||
|
return ArrangeItemTraits<T>::get_bed_index(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> int get_priority(const T &itm)
|
||||||
|
{
|
||||||
|
return ArrangeItemTraits<T>::get_priority(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setters:
|
||||||
|
|
||||||
|
template<class T> void set_translation(T &itm, const Vec2crd &v)
|
||||||
|
{
|
||||||
|
ArrangeItemTraits<T>::set_translation(itm, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void set_rotation(T &itm, double v)
|
||||||
|
{
|
||||||
|
ArrangeItemTraits<T>::set_rotation(itm, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void set_bed_index(T &itm, int v)
|
||||||
|
{
|
||||||
|
ArrangeItemTraits<T>::set_bed_index(itm, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions for arrange items
|
||||||
|
template<class ArrItem> bool is_arranged(const ArrItem &ap)
|
||||||
|
{
|
||||||
|
return get_bed_index(ap) > Unarranged;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> bool is_fixed(const ArrItem &ap)
|
||||||
|
{
|
||||||
|
return get_bed_index(ap) >= PhysicalBedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> bool is_on_physical_bed(const ArrItem &ap)
|
||||||
|
{
|
||||||
|
return get_bed_index(ap) == PhysicalBedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> void translate(ArrItem &ap, const Vec2crd &t)
|
||||||
|
{
|
||||||
|
set_translation(ap, get_translation(ap) + t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> void rotate(ArrItem &ap, double rads)
|
||||||
|
{
|
||||||
|
set_rotation(ap, get_rotation(ap) + rads);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGE_ITEM_HPP
|
||||||
130
src/libslic3r/Arrange/Core/Beds.cpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
#include "Beds.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
BoundingBox bounding_box(const InfiniteBed &bed)
|
||||||
|
{
|
||||||
|
BoundingBox ret;
|
||||||
|
using C = coord_t;
|
||||||
|
|
||||||
|
// It is important for Mx and My to be strictly less than half of the
|
||||||
|
// range of type C. width(), height() and area() will not overflow this way.
|
||||||
|
C Mx = C((std::numeric_limits<C>::lowest() + 2 * bed.center.x()) / 4.01);
|
||||||
|
C My = C((std::numeric_limits<C>::lowest() + 2 * bed.center.y()) / 4.01);
|
||||||
|
|
||||||
|
ret.max = bed.center - Point{Mx, My};
|
||||||
|
ret.min = bed.center + Point{Mx, My};
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon to_rectangle(const BoundingBox &bb)
|
||||||
|
{
|
||||||
|
Polygon ret;
|
||||||
|
ret.points = {
|
||||||
|
bb.min,
|
||||||
|
Point{bb.max.x(), bb.min.y()},
|
||||||
|
bb.max,
|
||||||
|
Point{bb.min.x(), bb.max.y()}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon approximate_circle_with_polygon(const arr2::CircleBed &bed, int nedges)
|
||||||
|
{
|
||||||
|
Polygon ret;
|
||||||
|
|
||||||
|
double angle_incr = (2 * M_PI) / nedges; // Angle increment for each edge
|
||||||
|
double angle = 0; // Starting angle
|
||||||
|
|
||||||
|
// Loop to generate vertices for each edge
|
||||||
|
for (int i = 0; i < nedges; i++) {
|
||||||
|
// Calculate coordinates of the vertices using trigonometry
|
||||||
|
auto x = bed.center().x() + static_cast<coord_t>(bed.radius() * std::cos(angle));
|
||||||
|
auto y = bed.center().y() + static_cast<coord_t>(bed.radius() * std::sin(angle));
|
||||||
|
|
||||||
|
// Add vertex to the vector
|
||||||
|
ret.points.emplace_back(x, y);
|
||||||
|
|
||||||
|
// Update the angle for the next iteration
|
||||||
|
angle += angle_incr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline coord_t width(const BoundingBox &box)
|
||||||
|
{
|
||||||
|
return box.max.x() - box.min.x();
|
||||||
|
}
|
||||||
|
inline coord_t height(const BoundingBox &box)
|
||||||
|
{
|
||||||
|
return box.max.y() - box.min.y();
|
||||||
|
}
|
||||||
|
inline double poly_area(const Points &pts)
|
||||||
|
{
|
||||||
|
return std::abs(Polygon::area(pts));
|
||||||
|
}
|
||||||
|
inline double distance_to(const Point &p1, const Point &p2)
|
||||||
|
{
|
||||||
|
double dx = p2.x() - p1.x();
|
||||||
|
double dy = p2.y() - p1.y();
|
||||||
|
return std::sqrt(dx * dx + dy * dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CircleBed to_circle(const Point ¢er, const Points &points)
|
||||||
|
{
|
||||||
|
std::vector<double> vertex_distances;
|
||||||
|
double avg_dist = 0;
|
||||||
|
|
||||||
|
for (const Point &pt : points) {
|
||||||
|
double distance = distance_to(center, pt);
|
||||||
|
vertex_distances.push_back(distance);
|
||||||
|
avg_dist += distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
avg_dist /= vertex_distances.size();
|
||||||
|
|
||||||
|
CircleBed ret(center, avg_dist);
|
||||||
|
for (auto el : vertex_distances) {
|
||||||
|
if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) {
|
||||||
|
ret = {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn)
|
||||||
|
{
|
||||||
|
if (bed.empty())
|
||||||
|
return fn(InfiniteBed{});
|
||||||
|
else if (bed.size() == 1)
|
||||||
|
return fn(InfiniteBed{bed.front()});
|
||||||
|
else {
|
||||||
|
auto bb = BoundingBox(bed);
|
||||||
|
CircleBed circ = to_circle(bb.center(), bed);
|
||||||
|
auto parea = poly_area(bed);
|
||||||
|
|
||||||
|
if ((1.0 - parea / area(bb)) < 1e-3) {
|
||||||
|
return fn(RectangleBed{bb});
|
||||||
|
} else if (!std::isnan(circ.radius()) && (1.0 - parea / area(circ)) < 1e-2)
|
||||||
|
return fn(circ);
|
||||||
|
else
|
||||||
|
return fn(IrregularBed{{ExPolygon(bed)}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrangeBed to_arrange_bed(const Points &bedpts)
|
||||||
|
{
|
||||||
|
ArrangeBed ret;
|
||||||
|
|
||||||
|
call_with_bed(bedpts, [&](const auto &bed) { ret = bed; });
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
192
src/libslic3r/Arrange/Core/Beds.hpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
|
||||||
|
#ifndef BEDS_HPP
|
||||||
|
#define BEDS_HPP
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include <libslic3r/Point.hpp>
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
#include <libslic3r/BoundingBox.hpp>
|
||||||
|
#include <libslic3r/ClipperUtils.hpp>
|
||||||
|
|
||||||
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// Bed types to be used with arrangement. Most generic bed is a simple polygon
|
||||||
|
// with holes, but other special bed types are also valid, like a bed without
|
||||||
|
// boundaries, or a special case of a rectangular or circular bed which leaves
|
||||||
|
// a lot of room for optimizations.
|
||||||
|
|
||||||
|
// Representing an unbounded bed.
|
||||||
|
struct InfiniteBed {
|
||||||
|
Point center;
|
||||||
|
explicit InfiniteBed(const Point &p = {0, 0}): center{p} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
BoundingBox bounding_box(const InfiniteBed &bed);
|
||||||
|
|
||||||
|
inline InfiniteBed offset(const InfiniteBed &bed, coord_t) { return bed; }
|
||||||
|
|
||||||
|
struct RectangleBed {
|
||||||
|
BoundingBox bb;
|
||||||
|
|
||||||
|
explicit RectangleBed(const BoundingBox &bedbb) : bb{bedbb} {}
|
||||||
|
explicit RectangleBed(coord_t w, coord_t h, Point c = {0, 0}):
|
||||||
|
bb{{c.x() - w / 2, c.y() - h / 2}, {c.x() + w / 2, c.y() + h / 2}}
|
||||||
|
{}
|
||||||
|
|
||||||
|
coord_t width() const { return bb.size().x(); }
|
||||||
|
coord_t height() const { return bb.size().y(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline BoundingBox bounding_box(const RectangleBed &bed) { return bed.bb; }
|
||||||
|
inline RectangleBed offset(RectangleBed bed, coord_t v)
|
||||||
|
{
|
||||||
|
bed.bb.offset(v);
|
||||||
|
return bed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon to_rectangle(const BoundingBox &bb);
|
||||||
|
|
||||||
|
inline Polygon to_rectangle(const RectangleBed &bed)
|
||||||
|
{
|
||||||
|
return to_rectangle(bed.bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CircleBed {
|
||||||
|
Point m_center;
|
||||||
|
double m_radius;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CircleBed(): m_center(0, 0), m_radius(NaNd) {}
|
||||||
|
explicit CircleBed(const Point& c, double r)
|
||||||
|
: m_center(c)
|
||||||
|
, m_radius(r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
double radius() const { return m_radius; }
|
||||||
|
const Point& center() const { return m_center; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to approximate a circle with a convex polygon
|
||||||
|
Polygon approximate_circle_with_polygon(const CircleBed &bed, int nedges = 24);
|
||||||
|
|
||||||
|
inline BoundingBox bounding_box(const CircleBed &bed)
|
||||||
|
{
|
||||||
|
auto r = static_cast<coord_t>(std::round(bed.radius()));
|
||||||
|
Point R{r, r};
|
||||||
|
|
||||||
|
return {bed.center() - R, bed.center() + R};
|
||||||
|
}
|
||||||
|
inline CircleBed offset(const CircleBed &bed, coord_t v)
|
||||||
|
{
|
||||||
|
return CircleBed{bed.center(), bed.radius() + v};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IrregularBed { ExPolygons poly; };
|
||||||
|
inline BoundingBox bounding_box(const IrregularBed &bed)
|
||||||
|
{
|
||||||
|
return get_extents(bed.poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IrregularBed offset(IrregularBed bed, coord_t v)
|
||||||
|
{
|
||||||
|
bed.poly = offset_ex(bed.poly, v);
|
||||||
|
return bed;
|
||||||
|
}
|
||||||
|
|
||||||
|
using ArrangeBed =
|
||||||
|
boost::variant<InfiniteBed, RectangleBed, CircleBed, IrregularBed>;
|
||||||
|
|
||||||
|
inline BoundingBox bounding_box(const ArrangeBed &bed)
|
||||||
|
{
|
||||||
|
BoundingBox ret;
|
||||||
|
auto visitor = [&ret](const auto &b) { ret = bounding_box(b); };
|
||||||
|
boost::apply_visitor(visitor, bed);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ArrangeBed offset(ArrangeBed bed, coord_t v)
|
||||||
|
{
|
||||||
|
auto visitor = [v](auto &b) { b = offset(b, v); };
|
||||||
|
boost::apply_visitor(visitor, bed);
|
||||||
|
|
||||||
|
return bed;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const BoundingBox &bb)
|
||||||
|
{
|
||||||
|
auto bbsz = bb.size();
|
||||||
|
return double(bbsz.x()) * bbsz.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const RectangleBed &bed)
|
||||||
|
{
|
||||||
|
auto bbsz = bed.bb.size();
|
||||||
|
return double(bbsz.x()) * bbsz.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const InfiniteBed &bed)
|
||||||
|
{
|
||||||
|
return std::numeric_limits<double>::infinity();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const IrregularBed &bed)
|
||||||
|
{
|
||||||
|
return std::accumulate(bed.poly.begin(), bed.poly.end(), 0.,
|
||||||
|
[](double s, auto &p) { return s + p.area(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const CircleBed &bed)
|
||||||
|
{
|
||||||
|
return bed.radius() * bed.radius() * PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double area(const ArrangeBed &bed)
|
||||||
|
{
|
||||||
|
double ret = 0.;
|
||||||
|
auto visitor = [&ret](auto &b) { ret = area(b); };
|
||||||
|
boost::apply_visitor(visitor, bed);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const InfiniteBed &bed)
|
||||||
|
{
|
||||||
|
return {ExPolygon{to_rectangle(RectangleBed{scaled(1000.), scaled(1000.)})}};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const RectangleBed &bed)
|
||||||
|
{
|
||||||
|
return {ExPolygon{to_rectangle(bed)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const CircleBed &bed)
|
||||||
|
{
|
||||||
|
return {ExPolygon{approximate_circle_with_polygon(bed)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const IrregularBed &bed) { return bed.poly; }
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const ArrangeBed &bed)
|
||||||
|
{
|
||||||
|
ExPolygons ret;
|
||||||
|
auto visitor = [&ret](const auto &b) { ret = to_expolygons(b); };
|
||||||
|
boost::apply_visitor(visitor, bed);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrangeBed to_arrange_bed(const Points &bedpts);
|
||||||
|
|
||||||
|
} // namespace arr2
|
||||||
|
|
||||||
|
inline BoundingBox &bounding_box(BoundingBox &bb) { return bb; }
|
||||||
|
inline const BoundingBox &bounding_box(const BoundingBox &bb) { return bb; }
|
||||||
|
inline BoundingBox bounding_box(const Polygon &p) { return get_extents(p); }
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // BEDS_HPP
|
||||||
79
src/libslic3r/Arrange/Core/DataStoreTraits.hpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
#ifndef DATASTORETRAITS_HPP
|
||||||
|
#define DATASTORETRAITS_HPP
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// Some items can be containers of arbitrary data stored under string keys.
|
||||||
|
template<class ArrItem, class En = void> struct DataStoreTraits_
|
||||||
|
{
|
||||||
|
static constexpr bool Implemented = false;
|
||||||
|
|
||||||
|
template<class T> static const T *get(const ArrItem &, const std::string &key)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above just not const.
|
||||||
|
template<class T> static T *get(ArrItem &, const std::string &key)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_key(const ArrItem &itm, const std::string &key)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem, class En = void> struct WritableDataStoreTraits_
|
||||||
|
{
|
||||||
|
static constexpr bool Implemented = false;
|
||||||
|
|
||||||
|
template<class T> static void set(ArrItem &, const std::string &key, T &&data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T> using DataStoreTraits = DataStoreTraits_<StripCVRef<T>>;
|
||||||
|
template<class T> constexpr bool IsDataStore = DataStoreTraits<StripCVRef<T>>::Implemented;
|
||||||
|
template<class T, class TT = T> using DataStoreOnly = std::enable_if_t<IsDataStore<T>, TT>;
|
||||||
|
|
||||||
|
template<class T, class ArrItem>
|
||||||
|
const T *get_data(const ArrItem &itm, const std::string &key)
|
||||||
|
{
|
||||||
|
return DataStoreTraits<ArrItem>::template get<T>(itm, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool has_key(const ArrItem &itm, const std::string &key)
|
||||||
|
{
|
||||||
|
return DataStoreTraits<ArrItem>::has_key(itm, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class ArrItem>
|
||||||
|
T *get_data(ArrItem &itm, const std::string &key)
|
||||||
|
{
|
||||||
|
return DataStoreTraits<ArrItem>::template get<T>(itm, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> using WritableDataStoreTraits = WritableDataStoreTraits_<StripCVRef<T>>;
|
||||||
|
template<class T> constexpr bool IsWritableDataStore = WritableDataStoreTraits<StripCVRef<T>>::Implemented;
|
||||||
|
template<class T, class TT = T> using WritableDataStoreOnly = std::enable_if_t<IsWritableDataStore<T>, TT>;
|
||||||
|
|
||||||
|
template<class T, class ArrItem>
|
||||||
|
void set_data(ArrItem &itm, const std::string &key, T &&data)
|
||||||
|
{
|
||||||
|
WritableDataStoreTraits<ArrItem>::template set(itm, key, std::forward<T>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> constexpr bool IsReadWritableDataStore = IsDataStore<T> && IsWritableDataStore<T>;
|
||||||
|
template<class T, class TT = T> using ReadWritableDataStoreOnly = std::enable_if_t<IsReadWritableDataStore<T>, TT>;
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // DATASTORETRAITS_HPP
|
||||||
111
src/libslic3r/Arrange/Core/NFP/CircularEdgeIterator.hpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
#ifndef CIRCULAR_EDGEITERATOR_HPP
|
||||||
|
#define CIRCULAR_EDGEITERATOR_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/Polygon.hpp>
|
||||||
|
#include <libslic3r/Line.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
// Circular iterator over a polygon yielding individual edges as Line objects
|
||||||
|
// if flip_lines is true, the orientation of each line is flipped (not the
|
||||||
|
// direction of traversal)
|
||||||
|
template<bool flip_lines = false>
|
||||||
|
class CircularEdgeIterator_ {
|
||||||
|
const Polygon *m_poly = nullptr;
|
||||||
|
size_t m_i = 0;
|
||||||
|
size_t m_c = 0; // counting how many times the iterator has circled over
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// i: vertex position of first line's starting vertex
|
||||||
|
// poly: target polygon
|
||||||
|
CircularEdgeIterator_(size_t i, const Polygon &poly)
|
||||||
|
: m_poly{&poly}
|
||||||
|
, m_i{!poly.empty() ? i % poly.size() : 0}
|
||||||
|
, m_c{!poly.empty() ? i / poly.size() : 0}
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit CircularEdgeIterator_ (const Polygon &poly)
|
||||||
|
: CircularEdgeIterator_(0, poly) {}
|
||||||
|
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = Line;
|
||||||
|
using pointer = Line*;
|
||||||
|
using reference = Line&;
|
||||||
|
|
||||||
|
CircularEdgeIterator_ & operator++()
|
||||||
|
{
|
||||||
|
assert (m_poly);
|
||||||
|
++m_i;
|
||||||
|
if (m_i == m_poly->size()) { // faster than modulo (?)
|
||||||
|
m_i = 0;
|
||||||
|
++m_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularEdgeIterator_ operator++(int)
|
||||||
|
{
|
||||||
|
auto cpy = *this; ++(*this); return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Line operator*() const
|
||||||
|
{
|
||||||
|
size_t nx = m_i == m_poly->size() - 1 ? 0 : m_i + 1;
|
||||||
|
Line ret;
|
||||||
|
if constexpr (flip_lines)
|
||||||
|
ret = Line((*m_poly)[nx], (*m_poly)[m_i]);
|
||||||
|
else
|
||||||
|
ret = Line((*m_poly)[m_i], (*m_poly)[nx]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Line operator->() const { return *(*this); }
|
||||||
|
|
||||||
|
bool operator==(const CircularEdgeIterator_& other) const
|
||||||
|
{
|
||||||
|
return m_i == other.m_i && m_c == other.m_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const CircularEdgeIterator_& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularEdgeIterator_& operator +=(size_t dist)
|
||||||
|
{
|
||||||
|
m_i = (m_i + dist) % m_poly->size();
|
||||||
|
m_c = (m_i + (m_c * m_poly->size()) + dist) / m_poly->size();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularEdgeIterator_ operator +(size_t dist)
|
||||||
|
{
|
||||||
|
auto cpy = *this;
|
||||||
|
cpy += dist;
|
||||||
|
|
||||||
|
return cpy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using CircularEdgeIterator = CircularEdgeIterator_<>;
|
||||||
|
using CircularReverseEdgeIterator = CircularEdgeIterator_<true>;
|
||||||
|
|
||||||
|
inline Range<CircularEdgeIterator> line_range(const Polygon &poly)
|
||||||
|
{
|
||||||
|
return Range{CircularEdgeIterator{0, poly}, CircularEdgeIterator{poly.size(), poly}};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Range<CircularReverseEdgeIterator> line_range_flp(const Polygon &poly)
|
||||||
|
{
|
||||||
|
return Range{CircularReverseEdgeIterator{0, poly}, CircularReverseEdgeIterator{poly.size(), poly}};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // CIRCULAR_EDGEITERATOR_HPP
|
||||||
100
src/libslic3r/Arrange/Core/NFP/EdgeCache.cpp
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
#include "EdgeCache.hpp"
|
||||||
|
#include "CircularEdgeIterator.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
void EdgeCache::create_cache(const ExPolygon &sh)
|
||||||
|
{
|
||||||
|
m_contour.distances.reserve(sh.contour.size());
|
||||||
|
m_holes.reserve(sh.holes.size());
|
||||||
|
|
||||||
|
m_contour.poly = &sh.contour;
|
||||||
|
|
||||||
|
fill_distances(sh.contour, m_contour.distances);
|
||||||
|
|
||||||
|
for (const Polygon &hole : sh.holes) {
|
||||||
|
auto &hc = m_holes.emplace_back();
|
||||||
|
hc.poly = &hole;
|
||||||
|
fill_distances(hole, hc.distances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd EdgeCache::coords(const ContourCache &cache, double distance) const
|
||||||
|
{
|
||||||
|
assert(cache.poly);
|
||||||
|
return arr2::coords(*cache.poly, cache.distances, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdgeCache::sample_contour(double accuracy, std::vector<ContourLocation> &samples)
|
||||||
|
{
|
||||||
|
const auto N = m_contour.distances.size();
|
||||||
|
const auto S = stride(N, accuracy);
|
||||||
|
|
||||||
|
if (N == 0 || S == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
samples.reserve(N / S + 1);
|
||||||
|
for(size_t i = 0; i < N; i += S) {
|
||||||
|
samples.emplace_back(
|
||||||
|
ContourLocation{0, m_contour.distances[i] / m_contour.distances.back()});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t hidx = 1; hidx <= m_holes.size(); ++hidx) {
|
||||||
|
auto& hc = m_holes[hidx - 1];
|
||||||
|
|
||||||
|
const auto NH = hc.distances.size();
|
||||||
|
const auto SH = stride(NH, accuracy);
|
||||||
|
|
||||||
|
if (NH == 0 || SH == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
samples.reserve(samples.size() + NH / SH + 1);
|
||||||
|
for (size_t i = 0; i < NH; i += SH) {
|
||||||
|
samples.emplace_back(
|
||||||
|
ContourLocation{hidx, hc.distances[i] / hc.distances.back()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd coords(const Polygon &poly, const std::vector<double> &distances, double distance)
|
||||||
|
{
|
||||||
|
assert(poly.size() > 1 && distance >= .0 && distance <= 1.0);
|
||||||
|
|
||||||
|
// distance is from 0.0 to 1.0, we scale it up to the full length of
|
||||||
|
// the circumference
|
||||||
|
double d = distance * distances.back();
|
||||||
|
|
||||||
|
// Magic: we find the right edge in log time
|
||||||
|
auto it = std::lower_bound(distances.begin(), distances.end(), d);
|
||||||
|
|
||||||
|
assert(it != distances.end());
|
||||||
|
|
||||||
|
auto idx = it - distances.begin(); // get the index of the edge
|
||||||
|
auto &pts = poly.points;
|
||||||
|
auto edge = idx == long(pts.size() - 1) ? Line(pts.back(), pts.front()) :
|
||||||
|
Line(pts[idx], pts[idx + 1]);
|
||||||
|
|
||||||
|
// Get the remaining distance on the target edge
|
||||||
|
auto ed = d - (idx > 0 ? *std::prev(it) : 0 );
|
||||||
|
|
||||||
|
double t = ed / edge.length();
|
||||||
|
Vec2d n {double(edge.b.x()) - edge.a.x(), double(edge.b.y()) - edge.a.y()};
|
||||||
|
Vec2crd ret = (edge.a.cast<double>() + t * n).cast<coord_t>();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_distances(const Polygon &poly, std::vector<double> &distances)
|
||||||
|
{
|
||||||
|
distances.reserve(poly.size());
|
||||||
|
|
||||||
|
double dist = 0.;
|
||||||
|
auto lrange = line_range(poly);
|
||||||
|
for (const Line &l : lrange) {
|
||||||
|
dist += l.length();
|
||||||
|
distances.emplace_back(dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
72
src/libslic3r/Arrange/Core/NFP/EdgeCache.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
#ifndef EDGECACHE_HPP
|
||||||
|
#define EDGECACHE_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// Position on the circumference of an ExPolygon.
|
||||||
|
// countour_id: 0th is contour, 1..N are holes
|
||||||
|
// dist: position given as a floating point number within <0., 1.>
|
||||||
|
struct ContourLocation { size_t contour_id; double dist; };
|
||||||
|
|
||||||
|
void fill_distances(const Polygon &poly, std::vector<double> &distances);
|
||||||
|
|
||||||
|
Vec2crd coords(const Polygon &poly, const std::vector<double>& distances, double distance);
|
||||||
|
|
||||||
|
// A class for getting a point on the circumference of the polygon (in log time)
|
||||||
|
//
|
||||||
|
// This is a transformation of the provided polygon to be able to pinpoint
|
||||||
|
// locations on the circumference. The optimizer will pass a floating point
|
||||||
|
// value e.g. within <0,1> and we have to transform this value quickly into a
|
||||||
|
// coordinate on the circumference. By definition 0 should yield the first
|
||||||
|
// vertex and 1.0 would be the last (which should coincide with first).
|
||||||
|
//
|
||||||
|
// We also have to make this work for the holes of the captured polygon.
|
||||||
|
class EdgeCache {
|
||||||
|
struct ContourCache {
|
||||||
|
const Polygon *poly;
|
||||||
|
std::vector<double> distances;
|
||||||
|
} m_contour;
|
||||||
|
|
||||||
|
std::vector<ContourCache> m_holes;
|
||||||
|
|
||||||
|
void create_cache(const ExPolygon& sh);
|
||||||
|
|
||||||
|
Vec2crd coords(const ContourCache& cache, double distance) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit EdgeCache(const ExPolygon *sh)
|
||||||
|
{
|
||||||
|
create_cache(*sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given coeff for accuracy <0., 1.>, return the number of vertices to skip
|
||||||
|
// when fetching corners.
|
||||||
|
static inline size_t stride(const size_t N, double accuracy)
|
||||||
|
{
|
||||||
|
size_t n = std::max(size_t{1}, N);
|
||||||
|
return static_cast<coord_t>(
|
||||||
|
std::round(N / std::pow(n, std::pow(accuracy, 1./3.)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sample_contour(double accuracy, std::vector<ContourLocation> &samples);
|
||||||
|
|
||||||
|
Vec2crd coords(const ContourLocation &loc) const
|
||||||
|
{
|
||||||
|
assert(loc.contour_id <= m_holes.size());
|
||||||
|
|
||||||
|
return loc.contour_id > 0 ?
|
||||||
|
coords(m_holes[loc.contour_id - 1], loc.dist) :
|
||||||
|
coords(m_contour, loc.dist);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // EDGECACHE_HPP
|
||||||
62
src/libslic3r/Arrange/Core/NFP/Kernels/CompactifyKernel.hpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
#ifndef COMPACTIFYKERNEL_HPP
|
||||||
|
#define COMPACTIFYKERNEL_HPP
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
#include <libslic3r/Geometry/ConvexHull.hpp>
|
||||||
|
#include <libslic3r/ClipperUtils.hpp>
|
||||||
|
|
||||||
|
#include "KernelUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
struct CompactifyKernel {
|
||||||
|
ExPolygons merged_pile;
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &itm, const Vec2crd &transl) const
|
||||||
|
{
|
||||||
|
auto pile = merged_pile;
|
||||||
|
|
||||||
|
ExPolygons itm_tr = to_expolygons(envelope_outline(itm));
|
||||||
|
for (auto &p : itm_tr)
|
||||||
|
p.translate(transl);
|
||||||
|
|
||||||
|
append(pile, std::move(itm_tr));
|
||||||
|
|
||||||
|
pile = union_ex(pile);
|
||||||
|
|
||||||
|
Polygon chull = Geometry::convex_hull(pile);
|
||||||
|
|
||||||
|
return -(chull.area());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Context, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Context &packing_context,
|
||||||
|
const Range<RemIt> & /*remaining_items*/)
|
||||||
|
{
|
||||||
|
bool ret = find_initial_position(itm, bounding_box(bed).center(), bed,
|
||||||
|
packing_context);
|
||||||
|
|
||||||
|
merged_pile.clear();
|
||||||
|
for (const auto &gitm : all_items_range(packing_context)) {
|
||||||
|
append(merged_pile, to_expolygons(fixed_outline(gitm)));
|
||||||
|
}
|
||||||
|
merged_pile = union_ex(merged_pile);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool on_item_packed(ArrItem &itm) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // COMPACTIFYKERNEL_HPP
|
||||||
59
src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
#ifndef GRAVITYKERNEL_HPP
|
||||||
|
#define GRAVITYKERNEL_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
#include "KernelUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
struct GravityKernel {
|
||||||
|
std::optional<Vec2crd> sink;
|
||||||
|
std::optional<Vec2crd> item_sink;
|
||||||
|
Vec2d active_sink;
|
||||||
|
|
||||||
|
GravityKernel(Vec2crd gravity_center) : sink{gravity_center} {}
|
||||||
|
GravityKernel() = default;
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &itm, const Vec2crd &transl) const
|
||||||
|
{
|
||||||
|
Vec2d center = unscaled(envelope_centroid(itm));
|
||||||
|
|
||||||
|
center += unscaled(transl);
|
||||||
|
|
||||||
|
return - (center - active_sink).squaredNorm();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Ctx, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Ctx &packing_context,
|
||||||
|
const Range<RemIt> & /*remaining_items*/)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
item_sink = get_gravity_sink(itm);
|
||||||
|
|
||||||
|
if (!sink) {
|
||||||
|
sink = bounding_box(bed).center();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item_sink)
|
||||||
|
active_sink = unscaled(*item_sink);
|
||||||
|
else
|
||||||
|
active_sink = unscaled(*sink);
|
||||||
|
|
||||||
|
ret = find_initial_position(itm, scaled(active_sink), bed, packing_context);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> bool on_item_packed(ArrItem &itm) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // GRAVITYKERNEL_HPP
|
||||||
58
src/libslic3r/Arrange/Core/NFP/Kernels/KernelTraits.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
#ifndef KERNELTRAITS_HPP
|
||||||
|
#define KERNELTRAITS_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/ArrangeItemTraits.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// An arrangement kernel that specifies the object function to the arrangement
|
||||||
|
// optimizer and additional callback functions to be able to track the state
|
||||||
|
// of the arranged pile during arrangement.
|
||||||
|
template<class Kernel, class En = void> struct KernelTraits_
|
||||||
|
{
|
||||||
|
// Has to return a score value marking the quality of the arrangement. The
|
||||||
|
// higher this value is, the better a particular placement of the item is.
|
||||||
|
// parameter transl is the translation needed for the item to be moved to
|
||||||
|
// the candidate position.
|
||||||
|
// To discard the item, return NaN as score for every translation.
|
||||||
|
template<class ArrItem>
|
||||||
|
static double placement_fitness(const Kernel &k,
|
||||||
|
const ArrItem &itm,
|
||||||
|
const Vec2crd &transl)
|
||||||
|
{
|
||||||
|
return k.placement_fitness(itm, transl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called whenever a new item is about to be processed by the optimizer.
|
||||||
|
// The current state of the arrangement can be saved by the kernel: the
|
||||||
|
// already placed items and the remaining items that need to fit into a
|
||||||
|
// particular bed.
|
||||||
|
// Returns true if the item is can be packed immediately, false if it
|
||||||
|
// should be processed further. This way, a kernel have the power to
|
||||||
|
// choose an initial position for the item that is not on the NFP.
|
||||||
|
template<class ArrItem, class Bed, class Ctx, class RemIt>
|
||||||
|
static bool on_start_packing(Kernel &k,
|
||||||
|
ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Ctx &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
return k.on_start_packing(itm, bed, packing_context, remaining_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when an item has been succesfully packed. itm should have the
|
||||||
|
// final translation and rotation already set.
|
||||||
|
// Can return false to discard the item after the optimization.
|
||||||
|
template<class ArrItem>
|
||||||
|
static bool on_item_packed(Kernel &k, ArrItem &itm)
|
||||||
|
{
|
||||||
|
return k.on_item_packed(itm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class K> using KernelTraits = KernelTraits_<StripCVRef<K>>;
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // KERNELTRAITS_HPP
|
||||||
76
src/libslic3r/Arrange/Core/NFP/Kernels/KernelUtils.hpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
#ifndef ARRANGEKERNELUTILS_HPP
|
||||||
|
#define ARRANGEKERNELUTILS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/DataStoreTraits.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
template<class Itm, class Bed, class Context>
|
||||||
|
bool find_initial_position(Itm &itm,
|
||||||
|
const Vec2crd &sink,
|
||||||
|
const Bed &bed,
|
||||||
|
const Context &packing_context)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if constexpr (std::is_convertible_v<Bed, RectangleBed> ||
|
||||||
|
std::is_convertible_v<Bed, InfiniteBed> ||
|
||||||
|
std::is_convertible_v<Bed, CircleBed>)
|
||||||
|
{
|
||||||
|
if (all_items_range(packing_context).empty()) {
|
||||||
|
auto rotations = allowed_rotations(itm);
|
||||||
|
auto chull = envelope_convex_hull(itm);
|
||||||
|
|
||||||
|
for (double rot : rotations) {
|
||||||
|
auto chullcpy = chull;
|
||||||
|
chullcpy.rotate(rot);
|
||||||
|
auto bbitm = bounding_box(chullcpy);
|
||||||
|
|
||||||
|
Vec2crd cb = sink;
|
||||||
|
Vec2crd ci = bbitm.center();
|
||||||
|
|
||||||
|
Vec2crd d = cb - ci;
|
||||||
|
bbitm.translate(d);
|
||||||
|
|
||||||
|
if (bounding_box(bed).contains(bbitm)) {
|
||||||
|
rotate(itm, rot);
|
||||||
|
translate(itm, d);
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> std::optional<Vec2crd> get_gravity_sink(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
constexpr const char * SinkKey = "sink";
|
||||||
|
|
||||||
|
std::optional<Vec2crd> ret;
|
||||||
|
|
||||||
|
auto ptr = get_data<Vec2crd>(itm, SinkKey);
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
ret = *ptr;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> bool is_wipe_tower(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
constexpr const char * Key = "is_wipe_tower";
|
||||||
|
|
||||||
|
return has_key(itm, Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGEKERNELUTILS_HPP
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
#ifndef RECTANGLEOVERFITKERNELWRAPPER_HPP
|
||||||
|
#define RECTANGLEOVERFITKERNELWRAPPER_HPP
|
||||||
|
|
||||||
|
#include "KernelTraits.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// This is a kernel wrapper that will apply a penality to the object function
|
||||||
|
// if the result cannot fit into the given rectangular bounds. This can be used
|
||||||
|
// to arrange into rectangular boundaries without calculating the IFP of the
|
||||||
|
// rectangle bed. Note that after the arrangement, what is garanteed is that
|
||||||
|
// the resulting pile will fit into the rectangular boundaries, but it will not
|
||||||
|
// be within the given rectangle. The items need to be moved afterwards manually.
|
||||||
|
// Use RectangeOverfitPackingStrategy to automate this post process step.
|
||||||
|
template<class Kernel>
|
||||||
|
struct RectangleOverfitKernelWrapper {
|
||||||
|
Kernel &k;
|
||||||
|
BoundingBox binbb;
|
||||||
|
BoundingBox pilebb;
|
||||||
|
|
||||||
|
RectangleOverfitKernelWrapper(Kernel &kern, const BoundingBox &limits)
|
||||||
|
: k{kern}
|
||||||
|
, binbb{limits}
|
||||||
|
{}
|
||||||
|
|
||||||
|
double overfit(const BoundingBox &itmbb) const
|
||||||
|
{
|
||||||
|
auto fullbb = pilebb;
|
||||||
|
fullbb.merge(itmbb);
|
||||||
|
auto fullbbsz = fullbb.size();
|
||||||
|
auto binbbsz = binbb.size();
|
||||||
|
|
||||||
|
auto wdiff = fullbbsz.x() - binbbsz.x() - SCALED_EPSILON;
|
||||||
|
auto hdiff = fullbbsz.y() - binbbsz.y() - SCALED_EPSILON;
|
||||||
|
double miss = .0;
|
||||||
|
if (wdiff > 0)
|
||||||
|
miss += double(wdiff);
|
||||||
|
if (hdiff > 0)
|
||||||
|
miss += double(hdiff);
|
||||||
|
|
||||||
|
miss = miss > 0? miss : 0;
|
||||||
|
|
||||||
|
return miss;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &item, const Vec2crd &transl) const
|
||||||
|
{
|
||||||
|
double score = KernelTraits<Kernel>::placement_fitness(k, item, transl);
|
||||||
|
|
||||||
|
auto itmbb = envelope_bounding_box(item);
|
||||||
|
itmbb.translate(transl);
|
||||||
|
double miss = overfit(itmbb);
|
||||||
|
score -= miss * miss;
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Ctx, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Ctx &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
pilebb = BoundingBox{};
|
||||||
|
|
||||||
|
for (auto &fitm : all_items_range(packing_context))
|
||||||
|
pilebb.merge(fixed_bounding_box(fitm));
|
||||||
|
|
||||||
|
return KernelTraits<Kernel>::on_start_packing(k, itm, RectangleBed{binbb},
|
||||||
|
packing_context,
|
||||||
|
remaining_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool on_item_packed(ArrItem &itm)
|
||||||
|
{
|
||||||
|
bool ret = KernelTraits<Kernel>::on_item_packed(k, itm);
|
||||||
|
|
||||||
|
double miss = overfit(envelope_bounding_box(itm));
|
||||||
|
|
||||||
|
if (miss > 0.)
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // RECTANGLEOVERFITKERNELWRAPPER_H
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
#ifndef SVGDEBUGOUTPUTKERNELWRAPPER_HPP
|
||||||
|
#define SVGDEBUGOUTPUTKERNELWRAPPER_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "KernelTraits.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/PackingContext.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
#include <libslic3r/SVG.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
template<class Kernel>
|
||||||
|
struct SVGDebugOutputKernelWrapper {
|
||||||
|
Kernel &k;
|
||||||
|
std::unique_ptr<Slic3r::SVG> svg;
|
||||||
|
BoundingBox drawbounds;
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
SVGDebugOutputKernelWrapper(const BoundingBox &bounds, Kernel &kern)
|
||||||
|
: k{kern}, drawbounds{bounds}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Context, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Context &packing_context,
|
||||||
|
const Range<RemIt> &rem)
|
||||||
|
{
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
bool ret = KernelTraits<Kernel>::on_start_packing(k, itm, bed,
|
||||||
|
packing_context,
|
||||||
|
rem);
|
||||||
|
|
||||||
|
if (arr2::get_bed_index(itm) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
svg.reset();
|
||||||
|
auto bounds = drawbounds;
|
||||||
|
auto fixed = all_items_range(packing_context);
|
||||||
|
svg = std::make_unique<SVG>(std::string("arrange_bed") +
|
||||||
|
std::to_string(
|
||||||
|
arr2::get_bed_index(itm)) +
|
||||||
|
"_" + std::to_string(fixed.size()) +
|
||||||
|
".svg",
|
||||||
|
bounds, 0, false);
|
||||||
|
|
||||||
|
svg->draw(ExPolygon{arr2::to_rectangle(drawbounds)}, "blue", .2f);
|
||||||
|
|
||||||
|
auto nfp = calculate_nfp(itm, packing_context, bed);
|
||||||
|
svg->draw_outline(nfp);
|
||||||
|
svg->draw(nfp, "green", 0.2f);
|
||||||
|
|
||||||
|
for (const auto &fixeditm : fixed) {
|
||||||
|
ExPolygons fixeditm_outline = to_expolygons(fixed_outline(fixeditm));
|
||||||
|
svg->draw_outline(fixeditm_outline);
|
||||||
|
svg->draw(fixeditm_outline, "yellow", 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &item, const Vec2crd &transl) const
|
||||||
|
{
|
||||||
|
return KernelTraits<Kernel>::placement_fitness(k, item, transl);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool on_item_packed(ArrItem &itm)
|
||||||
|
{
|
||||||
|
using namespace Slic3r;
|
||||||
|
using namespace Slic3r::arr2;
|
||||||
|
|
||||||
|
bool ret = KernelTraits<Kernel>::on_item_packed(k, itm);
|
||||||
|
|
||||||
|
if (svg) {
|
||||||
|
ExPolygons itm_outline = to_expolygons(fixed_outline(itm));
|
||||||
|
|
||||||
|
svg->draw_outline(itm_outline);
|
||||||
|
svg->draw(itm_outline, "grey");
|
||||||
|
|
||||||
|
svg->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // SVGDEBUGOUTPUTKERNELWRAPPER_HPP
|
||||||
271
src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
#ifndef TMARRANGEKERNEL_HPP
|
||||||
|
#define TMARRANGEKERNEL_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
#include "KernelUtils.hpp"
|
||||||
|
|
||||||
|
#include <boost/geometry/index/rtree.hpp>
|
||||||
|
#include <libslic3r/BoostAdapter.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// Summon the spatial indexing facilities from boost
|
||||||
|
namespace bgi = boost::geometry::index;
|
||||||
|
using SpatElement = std::pair<BoundingBox, unsigned>;
|
||||||
|
using SpatIndex = bgi::rtree<SpatElement, bgi::rstar<16, 4> >;
|
||||||
|
|
||||||
|
class TMArrangeKernel {
|
||||||
|
SpatIndex m_rtree; // spatial index for the normal (bigger) objects
|
||||||
|
SpatIndex m_smallsrtree; // spatial index for only the smaller items
|
||||||
|
BoundingBox m_pilebb;
|
||||||
|
double m_bin_area = NaNd;
|
||||||
|
double m_norm;
|
||||||
|
size_t m_rem_cnt = 0;
|
||||||
|
size_t m_item_cnt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
struct ItemStats { double area = 0.; BoundingBox bb; };
|
||||||
|
std::vector<ItemStats> m_itemstats;
|
||||||
|
|
||||||
|
// A coefficient used in separating bigger items and smaller items.
|
||||||
|
static constexpr double BigItemTreshold = 0.02;
|
||||||
|
|
||||||
|
template<class T> ArithmeticOnly<T, double> norm(T val) const
|
||||||
|
{
|
||||||
|
return double(val) / m_norm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat big items (compared to the print bed) differently
|
||||||
|
bool is_big(double a) const { return a / m_bin_area > BigItemTreshold; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::optional<Point> sink;
|
||||||
|
std::optional<Point> item_sink;
|
||||||
|
Point active_sink;
|
||||||
|
|
||||||
|
const BoundingBox & pilebb() const { return m_pilebb; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
TMArrangeKernel() = default;
|
||||||
|
TMArrangeKernel(Vec2crd gravity_center, size_t itm_cnt, double bedarea = NaNd)
|
||||||
|
: sink{gravity_center}
|
||||||
|
, m_bin_area(bedarea)
|
||||||
|
, m_item_cnt{itm_cnt}
|
||||||
|
{}
|
||||||
|
|
||||||
|
TMArrangeKernel(size_t itm_cnt, double bedarea = NaNd)
|
||||||
|
: m_bin_area(bedarea), m_item_cnt{itm_cnt}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &item, const Vec2crd &transl) const
|
||||||
|
{
|
||||||
|
// Candidate item bounding box
|
||||||
|
auto ibb = envelope_bounding_box(item);
|
||||||
|
ibb.translate(transl);
|
||||||
|
auto itmcntr = envelope_centroid(item);
|
||||||
|
itmcntr += transl;
|
||||||
|
|
||||||
|
// Calculate the full bounding box of the pile with the candidate item
|
||||||
|
auto fullbb = m_pilebb;
|
||||||
|
fullbb.merge(ibb);
|
||||||
|
|
||||||
|
// The bounding box of the big items (they will accumulate in the center
|
||||||
|
// of the pile
|
||||||
|
BoundingBox bigbb;
|
||||||
|
if(m_rtree.empty()) {
|
||||||
|
bigbb = fullbb;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto boostbb = m_rtree.bounds();
|
||||||
|
boost::geometry::convert(boostbb, bigbb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will hold the resulting score
|
||||||
|
double score = 0;
|
||||||
|
|
||||||
|
// Density is the pack density: how big is the arranged pile
|
||||||
|
double density = 0;
|
||||||
|
|
||||||
|
// Distinction of cases for the arrangement scene
|
||||||
|
enum e_cases {
|
||||||
|
// This branch is for big items in a mixed (big and small) scene
|
||||||
|
// OR for all items in a small-only scene.
|
||||||
|
BIG_ITEM,
|
||||||
|
|
||||||
|
// This branch is for the last big item in a mixed scene
|
||||||
|
LAST_BIG_ITEM,
|
||||||
|
|
||||||
|
// For small items in a mixed scene.
|
||||||
|
SMALL_ITEM,
|
||||||
|
|
||||||
|
WIPE_TOWER,
|
||||||
|
} compute_case;
|
||||||
|
|
||||||
|
bool is_wt = is_wipe_tower(item);
|
||||||
|
bool bigitems = is_big(envelope_area(item)) || m_rtree.empty();
|
||||||
|
if (is_wt)
|
||||||
|
compute_case = WIPE_TOWER;
|
||||||
|
else if (bigitems && m_rem_cnt > 0)
|
||||||
|
compute_case = BIG_ITEM;
|
||||||
|
else if (bigitems && m_rem_cnt == 0)
|
||||||
|
compute_case = LAST_BIG_ITEM;
|
||||||
|
else
|
||||||
|
compute_case = SMALL_ITEM;
|
||||||
|
|
||||||
|
switch (compute_case) {
|
||||||
|
case WIPE_TOWER: {
|
||||||
|
score = (unscaled(itmcntr) - unscaled(active_sink)).squaredNorm();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BIG_ITEM: {
|
||||||
|
const Point& minc = ibb.min; // bottom left corner
|
||||||
|
const Point& maxc = ibb.max; // top right corner
|
||||||
|
|
||||||
|
// top left and bottom right corners
|
||||||
|
Point top_left{minc.x(), maxc.y()};
|
||||||
|
Point bottom_right{maxc.x(), minc.y()};
|
||||||
|
|
||||||
|
// Now the distance of the gravity center will be calculated to the
|
||||||
|
// five anchor points and the smallest will be chosen.
|
||||||
|
std::array<double, 5> dists;
|
||||||
|
auto cc = fullbb.center(); // The gravity center
|
||||||
|
dists[0] = (minc - cc).cast<double>().norm();
|
||||||
|
dists[1] = (maxc - cc).cast<double>().norm();
|
||||||
|
dists[2] = (itmcntr - cc).template cast<double>().norm();
|
||||||
|
dists[3] = (top_left - cc).cast<double>().norm();
|
||||||
|
dists[4] = (bottom_right - cc).cast<double>().norm();
|
||||||
|
|
||||||
|
// The smalles distance from the arranged pile center:
|
||||||
|
double dist = norm(*(std::min_element(dists.begin(), dists.end())));
|
||||||
|
double bindist = norm((ibb.center() - active_sink).template cast<double>().norm());
|
||||||
|
dist = 0.8 * dist + 0.2 * bindist;
|
||||||
|
|
||||||
|
// Prepare a variable for the alignment score.
|
||||||
|
// This will indicate: how well is the candidate item
|
||||||
|
// aligned with its neighbors. We will check the alignment
|
||||||
|
// with all neighbors and return the score for the best
|
||||||
|
// alignment. So it is enough for the candidate to be
|
||||||
|
// aligned with only one item.
|
||||||
|
auto alignment_score = 1.0;
|
||||||
|
|
||||||
|
auto query = bgi::intersects(ibb);
|
||||||
|
auto& index = is_big(envelope_area(item)) ? m_rtree : m_smallsrtree;
|
||||||
|
|
||||||
|
// Query the spatial index for the neighbors
|
||||||
|
std::vector<SpatElement> result;
|
||||||
|
result.reserve(index.size());
|
||||||
|
|
||||||
|
index.query(query, std::back_inserter(result));
|
||||||
|
|
||||||
|
// now get the score for the best alignment
|
||||||
|
for(auto& e : result) {
|
||||||
|
auto idx = e.second;
|
||||||
|
const ItemStats& p = m_itemstats[idx];
|
||||||
|
auto parea = p.area;
|
||||||
|
if(std::abs(1.0 - parea / fixed_area(item)) < 1e-6) {
|
||||||
|
auto bb = p.bb;
|
||||||
|
bb.merge(ibb);
|
||||||
|
auto bbarea = area(bb);
|
||||||
|
auto ascore = 1.0 - (fixed_area(item) + parea) / bbarea;
|
||||||
|
|
||||||
|
if(ascore < alignment_score)
|
||||||
|
alignment_score = ascore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fullbbsz = fullbb.size();
|
||||||
|
density = std::sqrt(norm(fullbbsz.x()) * norm(fullbbsz.y()));
|
||||||
|
double R = double(m_rem_cnt) / (m_item_cnt);
|
||||||
|
|
||||||
|
// The final mix of the score is the balance between the
|
||||||
|
// distance from the full pile center, the pack density and
|
||||||
|
// the alignment with the neighbors
|
||||||
|
if (result.empty())
|
||||||
|
score = 0.50 * dist + 0.50 * density;
|
||||||
|
else
|
||||||
|
// Let the density matter more when fewer objects remain
|
||||||
|
score = 0.50 * dist + (1.0 - R) * 0.20 * density +
|
||||||
|
0.30 * alignment_score;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LAST_BIG_ITEM: {
|
||||||
|
score = norm((itmcntr - m_pilebb.center()).template cast<double>().norm());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SMALL_ITEM: {
|
||||||
|
// Here there are the small items that should be placed around the
|
||||||
|
// already processed bigger items.
|
||||||
|
// No need to play around with the anchor points, the center will be
|
||||||
|
// just fine for small items
|
||||||
|
score = norm((itmcntr - bigbb.center()).template cast<double>().norm());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -score;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Context, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Context &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
item_sink = get_gravity_sink(itm);
|
||||||
|
|
||||||
|
if (!sink) {
|
||||||
|
sink = bounding_box(bed).center();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item_sink)
|
||||||
|
active_sink = *item_sink;
|
||||||
|
else
|
||||||
|
active_sink = *sink;
|
||||||
|
|
||||||
|
auto fixed = all_items_range(packing_context);
|
||||||
|
|
||||||
|
bool ret = find_initial_position(itm, active_sink, bed, packing_context);
|
||||||
|
|
||||||
|
m_rem_cnt = remaining_items.size();
|
||||||
|
|
||||||
|
if (m_item_cnt == 0)
|
||||||
|
m_item_cnt = m_rem_cnt + fixed.size() + 1;
|
||||||
|
|
||||||
|
if (std::isnan(m_bin_area))
|
||||||
|
m_bin_area = area(bed);
|
||||||
|
|
||||||
|
m_norm = std::sqrt(m_bin_area);
|
||||||
|
|
||||||
|
m_itemstats.clear();
|
||||||
|
m_itemstats.reserve(fixed.size());
|
||||||
|
m_rtree.clear();
|
||||||
|
m_smallsrtree.clear();
|
||||||
|
m_pilebb = {};
|
||||||
|
unsigned idx = 0;
|
||||||
|
for (auto &fixitem : fixed) {
|
||||||
|
auto fixitmbb = fixed_bounding_box(fixitem);
|
||||||
|
m_itemstats.emplace_back(ItemStats{fixed_area(fixitem), fixitmbb});
|
||||||
|
m_pilebb.merge(fixitmbb);
|
||||||
|
|
||||||
|
if(is_big(fixed_area(fixitem)))
|
||||||
|
m_rtree.insert({fixitmbb, idx});
|
||||||
|
|
||||||
|
m_smallsrtree.insert({fixitmbb, idx});
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
bool on_item_packed(ArrItem &itm) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // TMARRANGEKERNEL_HPP
|
||||||
419
src/libslic3r/Arrange/Core/NFP/NFP.cpp
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
|
||||||
|
#ifndef NFP_CPP
|
||||||
|
#define NFP_CPP
|
||||||
|
|
||||||
|
#include "NFP.hpp"
|
||||||
|
#include "CircularEdgeIterator.hpp"
|
||||||
|
|
||||||
|
#include "NFPConcave_Tesselate.hpp"
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) && defined(__SIZEOF_INT128__) && !defined(__APPLE__)
|
||||||
|
namespace Slic3r { using LargeInt = __int128; }
|
||||||
|
#else
|
||||||
|
#include <boost/multiprecision/integer.hpp>
|
||||||
|
namespace Slic3r { using LargeInt = boost::multiprecision::int128_t; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/rational.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
static bool line_cmp(const Line& e1, const Line& e2)
|
||||||
|
{
|
||||||
|
using Ratio = boost::rational<LargeInt>;
|
||||||
|
|
||||||
|
const Vec<2, int64_t> ax(1, 0); // Unit vector for the X axis
|
||||||
|
|
||||||
|
Vec<2, int64_t> p1 = (e1.b - e1.a).cast<int64_t>();
|
||||||
|
Vec<2, int64_t> p2 = (e2.b - e2.a).cast<int64_t>();
|
||||||
|
|
||||||
|
// Quadrant mapping array. The quadrant of a vector can be determined
|
||||||
|
// from the dot product of the vector and its perpendicular pair
|
||||||
|
// with the unit vector X axis. The products will carry the values
|
||||||
|
// lcos = dot(p, ax) = l * cos(phi) and
|
||||||
|
// lsin = -dotperp(p, ax) = l * sin(phi) where
|
||||||
|
// l is the length of vector p. From the signs of these values we can
|
||||||
|
// construct an index which has the sign of lcos as MSB and the
|
||||||
|
// sign of lsin as LSB. This index can be used to retrieve the actual
|
||||||
|
// quadrant where vector p resides using the following map:
|
||||||
|
// (+ is 0, - is 1)
|
||||||
|
// cos | sin | decimal | quadrant
|
||||||
|
// + | + | 0 | 0
|
||||||
|
// + | - | 1 | 3
|
||||||
|
// - | + | 2 | 1
|
||||||
|
// - | - | 3 | 2
|
||||||
|
std::array<int, 4> quadrants {0, 3, 1, 2 };
|
||||||
|
|
||||||
|
std::array<int, 2> q {0, 0}; // Quadrant indices for p1 and p2
|
||||||
|
|
||||||
|
using TDots = std::array<int64_t, 2>;
|
||||||
|
TDots lcos { p1.dot(ax), p2.dot(ax) };
|
||||||
|
TDots lsin { -dotperp(p1, ax), -dotperp(p2, ax) };
|
||||||
|
|
||||||
|
// Construct the quadrant indices for p1 and p2
|
||||||
|
for(size_t i = 0; i < 2; ++i) {
|
||||||
|
if (lcos[i] == 0)
|
||||||
|
q[i] = lsin[i] > 0 ? 1 : 3;
|
||||||
|
else if (lsin[i] == 0)
|
||||||
|
q[i] = lcos[i] > 0 ? 0 : 2;
|
||||||
|
else
|
||||||
|
q[i] = quadrants[((lcos[i] < 0) << 1) + (lsin[i] < 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q[0] == q[1]) { // only bother if p1 and p2 are in the same quadrant
|
||||||
|
auto lsq1 = p1.squaredNorm(); // squared magnitudes, avoid sqrt
|
||||||
|
auto lsq2 = p2.squaredNorm(); // squared magnitudes, avoid sqrt
|
||||||
|
|
||||||
|
// We will actually compare l^2 * cos^2(phi) which saturates the
|
||||||
|
// cos function. But with the quadrant info we can get the sign back
|
||||||
|
int sign = q[0] == 1 || q[0] == 2 ? -1 : 1;
|
||||||
|
|
||||||
|
// If Ratio is an actual rational type, there is no precision loss
|
||||||
|
auto pcos1 = Ratio(lcos[0]) / lsq1 * sign * lcos[0];
|
||||||
|
auto pcos2 = Ratio(lcos[1]) / lsq2 * sign * lcos[1];
|
||||||
|
|
||||||
|
return q[0] < 2 ? pcos1 > pcos2 : pcos1 < pcos2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If in different quadrants, compare the quadrant indices only.
|
||||||
|
return q[0] < q[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool vsort(const Vec2crd& v1, const Vec2crd& v2)
|
||||||
|
{
|
||||||
|
return v1.y() == v2.y() ? v1.x() < v2.x() : v1.y() < v2.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons ifp_convex(const arr2::RectangleBed &obed, const Polygon &convexpoly)
|
||||||
|
{
|
||||||
|
ExPolygon ret;
|
||||||
|
|
||||||
|
auto sbox = bounding_box(convexpoly);
|
||||||
|
auto sboxsize = sbox.size();
|
||||||
|
coord_t sheight = sboxsize.y();
|
||||||
|
coord_t swidth = sboxsize.x();
|
||||||
|
Point sliding_top = reference_vertex(convexpoly);
|
||||||
|
auto leftOffset = sliding_top.x() - sbox.min.x();
|
||||||
|
auto rightOffset = sliding_top.x() - sbox.max.x();
|
||||||
|
coord_t topOffset = 0;
|
||||||
|
auto bottomOffset = sheight;
|
||||||
|
|
||||||
|
auto bedbb = obed.bb;
|
||||||
|
// bedbb.offset(1);
|
||||||
|
auto bedsz = bedbb.size();
|
||||||
|
auto boxWidth = bedsz.x();
|
||||||
|
auto boxHeight = bedsz.y();
|
||||||
|
|
||||||
|
auto bedMinx = bedbb.min.x();
|
||||||
|
auto bedMiny = bedbb.min.y();
|
||||||
|
auto bedMaxx = bedbb.max.x();
|
||||||
|
auto bedMaxy = bedbb.max.y();
|
||||||
|
|
||||||
|
Polygon innerNfp{ Point{bedMinx + leftOffset, bedMaxy + topOffset},
|
||||||
|
Point{bedMaxx + rightOffset, bedMaxy + topOffset},
|
||||||
|
Point{bedMaxx + rightOffset, bedMiny + bottomOffset},
|
||||||
|
Point{bedMinx + leftOffset, bedMiny + bottomOffset},
|
||||||
|
Point{bedMinx + leftOffset, bedMaxy + topOffset} };
|
||||||
|
|
||||||
|
if (sheight <= boxHeight && swidth <= boxWidth)
|
||||||
|
ret.contour = std::move(innerNfp);
|
||||||
|
|
||||||
|
return {ret};
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon ifp_convex_convex(const Polygon &fixed, const Polygon &movable)
|
||||||
|
{
|
||||||
|
auto subnfps = reserve_polygons(fixed.size());
|
||||||
|
|
||||||
|
// For each edge of the bed polygon, determine the nfp of convexpoly and
|
||||||
|
// the zero area polygon formed by the edge. The union of all these sub-nfps
|
||||||
|
// will contain a hole that is the actual ifp.
|
||||||
|
auto lrange = line_range(fixed);
|
||||||
|
for (const Line &l : lrange) { // Older mac compilers generate warnging if line_range is called in-place
|
||||||
|
Polygon fixed = {l.a, l.b};
|
||||||
|
subnfps.emplace_back(nfp_convex_convex_legacy(fixed, movable));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the union and then keep only the holes (should be only one or zero, if
|
||||||
|
// the convexpoly cannot fit into the bed)
|
||||||
|
Polygons ifp = union_(subnfps);
|
||||||
|
Polygon ret;
|
||||||
|
|
||||||
|
// find the first hole
|
||||||
|
auto it = std::find_if(ifp.begin(), ifp.end(), [](const Polygon &subifp){
|
||||||
|
return subifp.is_clockwise();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != ifp.end()) {
|
||||||
|
ret = std::move(*it);
|
||||||
|
std::reverse(ret.begin(), ret.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons ifp_convex(const arr2::CircleBed &bed, const Polygon &convexpoly)
|
||||||
|
{
|
||||||
|
Polygon circle = approximate_circle_with_polygon(bed);
|
||||||
|
|
||||||
|
return {ExPolygon{ifp_convex_convex(circle, convexpoly)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons ifp_convex(const arr2::IrregularBed &bed, const Polygon &convexpoly)
|
||||||
|
{
|
||||||
|
auto bb = get_extents(bed.poly);
|
||||||
|
bb.offset(scaled(1.));
|
||||||
|
|
||||||
|
Polygon rect = arr2::to_rectangle(bb);
|
||||||
|
|
||||||
|
ExPolygons blueprint = diff_ex(rect, bed.poly);
|
||||||
|
Polygons ifp;
|
||||||
|
for (const ExPolygon &part : blueprint) {
|
||||||
|
Polygons triangles = Slic3r::convex_decomposition_tess(part);
|
||||||
|
for (const Polygon &tr : triangles) {
|
||||||
|
Polygon subifp = nfp_convex_convex_legacy(tr, convexpoly);
|
||||||
|
ifp.emplace_back(std::move(subifp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ifp = union_(ifp);
|
||||||
|
|
||||||
|
Polygons ret;
|
||||||
|
|
||||||
|
std::copy_if(ifp.begin(), ifp.end(), std::back_inserter(ret),
|
||||||
|
[](const Polygon &p) { return p.is_clockwise(); });
|
||||||
|
|
||||||
|
for (Polygon &p : ret)
|
||||||
|
std::reverse(p.begin(), p.end());
|
||||||
|
|
||||||
|
return to_expolygons(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd reference_vertex(const Polygon &poly)
|
||||||
|
{
|
||||||
|
Vec2crd ret{std::numeric_limits<coord_t>::min(),
|
||||||
|
std::numeric_limits<coord_t>::min()};
|
||||||
|
|
||||||
|
auto it = std::max_element(poly.points.begin(), poly.points.end(), vsort);
|
||||||
|
if (it != poly.points.end())
|
||||||
|
ret = std::max(ret, static_cast<const Vec2crd &>(*it), vsort);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd reference_vertex(const ExPolygon &expoly)
|
||||||
|
{
|
||||||
|
return reference_vertex(expoly.contour);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd reference_vertex(const Polygons &outline)
|
||||||
|
{
|
||||||
|
Vec2crd ret{std::numeric_limits<coord_t>::min(),
|
||||||
|
std::numeric_limits<coord_t>::min()};
|
||||||
|
|
||||||
|
for (const Polygon &poly : outline)
|
||||||
|
ret = std::max(ret, reference_vertex(poly), vsort);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd reference_vertex(const ExPolygons &outline)
|
||||||
|
{
|
||||||
|
Vec2crd ret{std::numeric_limits<coord_t>::min(),
|
||||||
|
std::numeric_limits<coord_t>::min()};
|
||||||
|
|
||||||
|
for (const ExPolygon &expoly : outline)
|
||||||
|
ret = std::max(ret, reference_vertex(expoly), vsort);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd min_vertex(const Polygon &poly)
|
||||||
|
{
|
||||||
|
Vec2crd ret{std::numeric_limits<coord_t>::max(),
|
||||||
|
std::numeric_limits<coord_t>::max()};
|
||||||
|
|
||||||
|
auto it = std::min_element(poly.points.begin(), poly.points.end(), vsort);
|
||||||
|
if (it != poly.points.end())
|
||||||
|
ret = std::min(ret, static_cast<const Vec2crd&>(*it), vsort);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the vertex corresponding to the edge with minimum angle to X axis.
|
||||||
|
// Only usable with CircularEdgeIterator<> template.
|
||||||
|
template<class It> It find_min_anglex_edge(It from)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
auto it = from;
|
||||||
|
while (!found ) {
|
||||||
|
found = !line_cmp(*it, *std::next(it));
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only usable if both fixed and movable polygon is convex. In that case,
|
||||||
|
// their edges are already sorted by angle to X axis, only the starting
|
||||||
|
// (lowest X axis) edge needs to be found first.
|
||||||
|
void nfp_convex_convex(const Polygon &fixed, const Polygon &movable, Polygon &poly)
|
||||||
|
{
|
||||||
|
if (fixed.empty() || movable.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clear poly and adjust its capacity. Nothing happens if poly is
|
||||||
|
// already sufficiently large and and empty.
|
||||||
|
poly.clear();
|
||||||
|
poly.points.reserve(fixed.size() + movable.size());
|
||||||
|
|
||||||
|
// Find starting positions on the fixed and moving polygons
|
||||||
|
auto it_fx = find_min_anglex_edge(CircularEdgeIterator{fixed});
|
||||||
|
auto it_mv = find_min_anglex_edge(CircularReverseEdgeIterator{movable});
|
||||||
|
|
||||||
|
// End positions are at the same vertex after completing one full circle
|
||||||
|
auto end_fx = it_fx + fixed.size();
|
||||||
|
auto end_mv = it_mv + movable.size();
|
||||||
|
|
||||||
|
// Pos zero is just fine as starting point:
|
||||||
|
poly.points.emplace_back(0, 0);
|
||||||
|
|
||||||
|
// Output iterator adapter for std::merge
|
||||||
|
struct OutItAdaptor {
|
||||||
|
using value_type [[maybe_unused]] = Line;
|
||||||
|
using difference_type [[maybe_unused]] = std::ptrdiff_t;
|
||||||
|
using pointer [[maybe_unused]] = Line*;
|
||||||
|
using reference [[maybe_unused]] = Line& ;
|
||||||
|
using iterator_category [[maybe_unused]] = std::output_iterator_tag;
|
||||||
|
|
||||||
|
Polygon *outpoly;
|
||||||
|
OutItAdaptor(Polygon &out) : outpoly{&out} {}
|
||||||
|
|
||||||
|
OutItAdaptor &operator *() { return *this; }
|
||||||
|
void operator=(const Line &l)
|
||||||
|
{
|
||||||
|
// Yielding l.b, offsetted so that l.a touches the last vertex in
|
||||||
|
// in outpoly
|
||||||
|
outpoly->points.emplace_back(l.b + outpoly->back() - l.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutItAdaptor& operator++() { return *this; };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use std algo to merge the edges from the two polygons
|
||||||
|
std::merge(it_fx, end_fx, it_mv, end_mv, OutItAdaptor{poly}, line_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon nfp_convex_convex(const Polygon &fixed, const Polygon &movable)
|
||||||
|
{
|
||||||
|
Polygon ret;
|
||||||
|
nfp_convex_convex(fixed, movable, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buildPolygon(const std::vector<Line>& edgelist,
|
||||||
|
Polygon& rpoly,
|
||||||
|
Point& top_nfp)
|
||||||
|
{
|
||||||
|
auto& rsh = rpoly.points;
|
||||||
|
|
||||||
|
rsh.reserve(2 * edgelist.size());
|
||||||
|
|
||||||
|
// Add the two vertices from the first edge into the final polygon.
|
||||||
|
rsh.emplace_back(edgelist.front().a);
|
||||||
|
rsh.emplace_back(edgelist.front().b);
|
||||||
|
|
||||||
|
// Sorting function for the nfp reference vertex search
|
||||||
|
|
||||||
|
// the reference (rightmost top) vertex so far
|
||||||
|
top_nfp = *std::max_element(std::cbegin(rsh), std::cend(rsh), vsort);
|
||||||
|
|
||||||
|
auto tmp = std::next(std::begin(rsh));
|
||||||
|
|
||||||
|
// Construct final nfp by placing each edge to the end of the previous
|
||||||
|
for(auto eit = std::next(edgelist.begin()); eit != edgelist.end(); ++eit) {
|
||||||
|
auto d = *tmp - eit->a;
|
||||||
|
Vec2crd p = eit->b + d;
|
||||||
|
|
||||||
|
rsh.emplace_back(p);
|
||||||
|
|
||||||
|
// Set the new reference vertex
|
||||||
|
if (vsort(top_nfp, p))
|
||||||
|
top_nfp = p;
|
||||||
|
|
||||||
|
tmp = std::next(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon nfp_convex_convex_legacy(const Polygon &fixed, const Polygon &movable)
|
||||||
|
{
|
||||||
|
assert (!fixed.empty());
|
||||||
|
assert (!movable.empty());
|
||||||
|
|
||||||
|
Polygon rsh; // Final nfp placeholder
|
||||||
|
Point max_nfp;
|
||||||
|
std::vector<Line> edgelist;
|
||||||
|
|
||||||
|
auto cap = fixed.points.size() + movable.points.size();
|
||||||
|
|
||||||
|
// Reserve the needed memory
|
||||||
|
edgelist.reserve(cap);
|
||||||
|
rsh.points.reserve(cap);
|
||||||
|
|
||||||
|
auto add_edge = [&edgelist](const Point &v1, const Point &v2) {
|
||||||
|
Line e{v1, v2};
|
||||||
|
if ((e.b - e.a).cast<int64_t>().squaredNorm() > 0)
|
||||||
|
edgelist.emplace_back(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
Point max_fixed = fixed.points.front();
|
||||||
|
{ // place all edges from fixed into edgelist
|
||||||
|
auto first = std::cbegin(fixed);
|
||||||
|
auto next = std::next(first);
|
||||||
|
|
||||||
|
while(next != std::cend(fixed)) {
|
||||||
|
add_edge(*(first), *(next));
|
||||||
|
max_fixed = std::max(max_fixed, *first, vsort);
|
||||||
|
|
||||||
|
++first; ++next;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_edge(*std::crbegin(fixed), *std::cbegin(fixed));
|
||||||
|
max_fixed = std::max(max_fixed, *std::crbegin(fixed), vsort);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point max_movable = movable.points.front();
|
||||||
|
Point min_movable = movable.points.front();
|
||||||
|
{ // place all edges from movable into edgelist
|
||||||
|
auto first = std::cbegin(movable);
|
||||||
|
auto next = std::next(first);
|
||||||
|
|
||||||
|
while(next != std::cend(movable)) {
|
||||||
|
add_edge(*(next), *(first));
|
||||||
|
min_movable = std::min(min_movable, *first, vsort);
|
||||||
|
max_movable = std::max(max_movable, *first, vsort);
|
||||||
|
|
||||||
|
++first; ++next;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_edge(*std::cbegin(movable), *std::crbegin(movable));
|
||||||
|
min_movable = std::min(min_movable, *std::crbegin(movable), vsort);
|
||||||
|
max_movable = std::max(max_movable, *std::crbegin(movable), vsort);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(edgelist.begin(), edgelist.end(), line_cmp);
|
||||||
|
|
||||||
|
buildPolygon(edgelist, rsh, max_nfp);
|
||||||
|
|
||||||
|
auto dtouch = max_fixed - min_movable;
|
||||||
|
auto top_other = max_movable + dtouch;
|
||||||
|
auto dnfp = top_other - max_nfp;
|
||||||
|
rsh.translate(dnfp);
|
||||||
|
|
||||||
|
return rsh;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // NFP_CPP
|
||||||
51
src/libslic3r/Arrange/Core/NFP/NFP.hpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
#ifndef NFP_HPP
|
||||||
|
#define NFP_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
#include <libslic3r/Arrange/Core/Beds.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
template<class Unit = int64_t, class T>
|
||||||
|
Unit dotperp(const Vec<2, T> &a, const Vec<2, T> &b)
|
||||||
|
{
|
||||||
|
return Unit(a.x()) * Unit(b.y()) - Unit(a.y()) * Unit(b.x());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convex-Convex nfp in linear time (fixed.size() + movable.size()),
|
||||||
|
// no memory allocations (if out param is used).
|
||||||
|
// FIXME: Currently broken for very sharp triangles.
|
||||||
|
Polygon nfp_convex_convex(const Polygon &fixed, const Polygon &movable);
|
||||||
|
void nfp_convex_convex(const Polygon &fixed, const Polygon &movable, Polygon &out);
|
||||||
|
Polygon nfp_convex_convex_legacy(const Polygon &fixed, const Polygon &movable);
|
||||||
|
|
||||||
|
Polygon ifp_convex_convex(const Polygon &fixed, const Polygon &movable);
|
||||||
|
|
||||||
|
ExPolygons ifp_convex(const arr2::RectangleBed &bed, const Polygon &convexpoly);
|
||||||
|
ExPolygons ifp_convex(const arr2::CircleBed &bed, const Polygon &convexpoly);
|
||||||
|
ExPolygons ifp_convex(const arr2::IrregularBed &bed, const Polygon &convexpoly);
|
||||||
|
inline ExPolygons ifp_convex(const arr2::InfiniteBed &bed, const Polygon &convexpoly)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExPolygons ifp_convex(const arr2::ArrangeBed &bed, const Polygon &convexpoly)
|
||||||
|
{
|
||||||
|
ExPolygons ret;
|
||||||
|
auto visitor = [&ret, &convexpoly](const auto &b) { ret = ifp_convex(b, convexpoly); };
|
||||||
|
boost::apply_visitor(visitor, bed);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2crd reference_vertex(const Polygon &outline);
|
||||||
|
Vec2crd reference_vertex(const ExPolygon &outline);
|
||||||
|
Vec2crd reference_vertex(const Polygons &outline);
|
||||||
|
Vec2crd reference_vertex(const ExPolygons &outline);
|
||||||
|
|
||||||
|
Vec2crd min_vertex(const Polygon &outline);
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // NFP_HPP
|
||||||
197
src/libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
|
||||||
|
#ifndef NFPARRANGEITEMTRAITS_HPP
|
||||||
|
#define NFPARRANGEITEMTRAITS_HPP
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/ArrangeBase.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
// Additional methods that an ArrangeItem object has to implement in order
|
||||||
|
// to be usable with PackStrategyNFP.
|
||||||
|
template<class ArrItem, class En = void> struct NFPArrangeItemTraits_
|
||||||
|
{
|
||||||
|
template<class Context, class Bed, class StopCond = DefaultStopCondition>
|
||||||
|
static ExPolygons calculate_nfp(const ArrItem &item,
|
||||||
|
const Context &packing_context,
|
||||||
|
const Bed &bed,
|
||||||
|
StopCond stop_condition = {})
|
||||||
|
{
|
||||||
|
static_assert(always_false<ArrItem>::value,
|
||||||
|
"NFP unimplemented for this item type.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vec2crd reference_vertex(const ArrItem &item)
|
||||||
|
{
|
||||||
|
return item.reference_vertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoundingBox envelope_bounding_box(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.envelope_bounding_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoundingBox fixed_bounding_box(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.fixed_bounding_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Polygons & envelope_outline(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.envelope_outline();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Polygons & fixed_outline(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.fixed_outline();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Polygon & envelope_convex_hull(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.envelope_convex_hull();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Polygon & fixed_convex_hull(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.fixed_convex_hull();
|
||||||
|
}
|
||||||
|
|
||||||
|
static double envelope_area(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.envelope_area();
|
||||||
|
}
|
||||||
|
|
||||||
|
static double fixed_area(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return itm.fixed_area();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto allowed_rotations(const ArrItem &)
|
||||||
|
{
|
||||||
|
return std::array{0.};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vec2crd fixed_centroid(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return fixed_bounding_box(itm).center();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Vec2crd envelope_centroid(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return envelope_bounding_box(itm).center();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
using NFPArrangeItemTraits = NFPArrangeItemTraits_<StripCVRef<T>>;
|
||||||
|
|
||||||
|
template<class ArrItem,
|
||||||
|
class Context,
|
||||||
|
class Bed,
|
||||||
|
class StopCond = DefaultStopCondition>
|
||||||
|
ExPolygons calculate_nfp(const ArrItem &itm,
|
||||||
|
const Context &context,
|
||||||
|
const Bed &bed,
|
||||||
|
StopCond stopcond = {})
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::calculate_nfp(itm, context, bed,
|
||||||
|
std::move(stopcond));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> Vec2crd reference_vertex(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::reference_vertex(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> BoundingBox envelope_bounding_box(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::envelope_bounding_box(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> BoundingBox fixed_bounding_box(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::fixed_bounding_box(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> decltype(auto) envelope_convex_hull(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::envelope_convex_hull(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> decltype(auto) fixed_convex_hull(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::fixed_convex_hull(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> decltype(auto) envelope_outline(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::envelope_outline(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> decltype(auto) fixed_outline(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::fixed_outline(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> double envelope_area(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::envelope_area(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> double fixed_area(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::fixed_area(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> Vec2crd fixed_centroid(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::fixed_centroid(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> Vec2crd envelope_centroid(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::envelope_centroid(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
auto allowed_rotations(const ArrItem &itm)
|
||||||
|
{
|
||||||
|
return NFPArrangeItemTraits<ArrItem>::allowed_rotations(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
BoundingBox bounding_box(const Range<It> &itms) noexcept
|
||||||
|
{
|
||||||
|
auto pilebb =
|
||||||
|
std::accumulate(itms.begin(), itms.end(), BoundingBox{},
|
||||||
|
[](BoundingBox bb, const auto &itm) {
|
||||||
|
bb.merge(fixed_bounding_box(itm));
|
||||||
|
return bb;
|
||||||
|
});
|
||||||
|
|
||||||
|
return pilebb;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class It>
|
||||||
|
BoundingBox bounding_box_on_bedidx(const Range<It> &itms, int bed_index) noexcept
|
||||||
|
{
|
||||||
|
auto pilebb =
|
||||||
|
std::accumulate(itms.begin(), itms.end(), BoundingBox{},
|
||||||
|
[bed_index](BoundingBox bb, const auto &itm) {
|
||||||
|
if (bed_index == get_bed_index(itm))
|
||||||
|
bb.merge(fixed_bounding_box(itm));
|
||||||
|
|
||||||
|
return bb;
|
||||||
|
});
|
||||||
|
|
||||||
|
return pilebb;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // ARRANGEITEMTRAITSNFP_HPP
|
||||||
112
src/libslic3r/Arrange/Core/NFP/NFPConcave_CGAL.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
#include "NFP.hpp"
|
||||||
|
#include "NFPConcave_CGAL.hpp"
|
||||||
|
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/partition_2.h>
|
||||||
|
#include <CGAL/Partition_traits_2.h>
|
||||||
|
#include <CGAL/property_map.h>
|
||||||
|
#include <CGAL/Polygon_vertical_decomposition_2.h>
|
||||||
|
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
using K = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||||
|
using Partition_traits_2 = CGAL::Partition_traits_2<K, CGAL::Pointer_property_map<K::Point_2>::type >;
|
||||||
|
using Point_2 = Partition_traits_2::Point_2;
|
||||||
|
using Polygon_2 = Partition_traits_2::Polygon_2; // a polygon of indices
|
||||||
|
|
||||||
|
ExPolygons nfp_concave_concave_cgal(const ExPolygon &fixed, const ExPolygon &movable)
|
||||||
|
{
|
||||||
|
Polygons fixed_decomp = convex_decomposition_cgal(fixed);
|
||||||
|
Polygons movable_decomp = convex_decomposition_cgal(movable);
|
||||||
|
|
||||||
|
auto refs_mv = reserve_vector<Vec2crd>(movable_decomp.size());
|
||||||
|
|
||||||
|
for (const Polygon &p : movable_decomp)
|
||||||
|
refs_mv.emplace_back(reference_vertex(p));
|
||||||
|
|
||||||
|
auto nfps = reserve_polygons(fixed_decomp.size() *movable_decomp.size());
|
||||||
|
|
||||||
|
Vec2crd ref_whole = reference_vertex(movable);
|
||||||
|
for (const Polygon &fixed_part : fixed_decomp) {
|
||||||
|
size_t mvi = 0;
|
||||||
|
for (const Polygon &movable_part : movable_decomp) {
|
||||||
|
Polygon subnfp = nfp_convex_convex(fixed_part, movable_part);
|
||||||
|
const Vec2crd &ref_mp = refs_mv[mvi];
|
||||||
|
auto d = ref_whole - ref_mp;
|
||||||
|
subnfp.translate(d);
|
||||||
|
nfps.emplace_back(subnfp);
|
||||||
|
mvi++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return union_ex(nfps);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: holes
|
||||||
|
Polygons convex_decomposition_cgal(const ExPolygon &expoly)
|
||||||
|
{
|
||||||
|
CGAL::Polygon_vertical_decomposition_2<K> decomp;
|
||||||
|
|
||||||
|
CGAL::Polygon_2<K> contour;
|
||||||
|
for (auto &p : expoly.contour.points)
|
||||||
|
contour.push_back({unscaled(p.x()), unscaled(p.y())});
|
||||||
|
|
||||||
|
CGAL::Polygon_with_holes_2<K> cgalpoly{contour};
|
||||||
|
for (const Polygon &h : expoly.holes) {
|
||||||
|
CGAL::Polygon_2<K> hole;
|
||||||
|
for (auto &p : h.points)
|
||||||
|
hole.push_back({unscaled(p.x()), unscaled(p.y())});
|
||||||
|
|
||||||
|
cgalpoly.add_hole(hole);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CGAL::Polygon_2<K>> out;
|
||||||
|
decomp(cgalpoly, std::back_inserter(out));
|
||||||
|
|
||||||
|
Polygons ret;
|
||||||
|
for (auto &pwh : out) {
|
||||||
|
Polygon poly;
|
||||||
|
for (auto &p : pwh)
|
||||||
|
poly.points.emplace_back(scaled(p.x()), scaled(p.y()));
|
||||||
|
ret.emplace_back(std::move(poly));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret; //convex_decomposition_cgal(expoly.contour);
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygons convex_decomposition_cgal(const Polygon &poly)
|
||||||
|
{
|
||||||
|
auto pts = reserve_vector<K::Point_2>(poly.size());
|
||||||
|
|
||||||
|
for (const Point &p : poly.points)
|
||||||
|
pts.emplace_back(unscaled(p.x()), unscaled(p.y()));
|
||||||
|
|
||||||
|
Partition_traits_2 traits(CGAL::make_property_map(pts));
|
||||||
|
|
||||||
|
Polygon_2 polyidx;
|
||||||
|
for (size_t i = 0; i < pts.size(); ++i)
|
||||||
|
polyidx.push_back(i);
|
||||||
|
|
||||||
|
std::vector<Polygon_2> outp;
|
||||||
|
|
||||||
|
CGAL::optimal_convex_partition_2(polyidx.vertices_begin(),
|
||||||
|
polyidx.vertices_end(),
|
||||||
|
std::back_inserter(outp),
|
||||||
|
traits);
|
||||||
|
|
||||||
|
Polygons ret;
|
||||||
|
for (const Polygon_2& poly : outp){
|
||||||
|
Polygon r;
|
||||||
|
for(Point_2 p : poly.container())
|
||||||
|
r.points.emplace_back(scaled(pts[p].x()), scaled(pts[p].y()));
|
||||||
|
|
||||||
|
ret.emplace_back(std::move(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
15
src/libslic3r/Arrange/Core/NFP/NFPConcave_CGAL.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#ifndef NFPCONCAVE_CGAL_HPP
|
||||||
|
#define NFPCONCAVE_CGAL_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
Polygons convex_decomposition_cgal(const Polygon &expoly);
|
||||||
|
Polygons convex_decomposition_cgal(const ExPolygon &expoly);
|
||||||
|
ExPolygons nfp_concave_concave_cgal(const ExPolygon &fixed, const ExPolygon &movable);
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // NFPCONCAVE_CGAL_HPP
|
||||||
71
src/libslic3r/Arrange/Core/NFP/NFPConcave_Tesselate.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
#include "NFPConcave_Tesselate.hpp"
|
||||||
|
|
||||||
|
#include <libslic3r/ClipperUtils.hpp>
|
||||||
|
#include <libslic3r/Tesselate.hpp>
|
||||||
|
|
||||||
|
#include "NFP.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
Polygons convex_decomposition_tess(const Polygon &expoly)
|
||||||
|
{
|
||||||
|
return convex_decomposition_tess(ExPolygon{expoly});
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygons convex_decomposition_tess(const ExPolygon &expoly)
|
||||||
|
{
|
||||||
|
std::vector<Vec2d> tr = Slic3r::triangulate_expolygon_2d(expoly);
|
||||||
|
|
||||||
|
auto ret = Slic3r::reserve_polygons(tr.size() / 3);
|
||||||
|
for (size_t i = 0; i < tr.size(); i += 3) {
|
||||||
|
ret.emplace_back(
|
||||||
|
Polygon{scaled(tr[i]), scaled(tr[i + 1]), scaled(tr[i + 2])});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygons convex_decomposition_tess(const ExPolygons &expolys)
|
||||||
|
{
|
||||||
|
constexpr size_t AvgTriangleCountGuess = 50;
|
||||||
|
|
||||||
|
auto ret = reserve_polygons(AvgTriangleCountGuess * expolys.size());
|
||||||
|
for (const ExPolygon &expoly : expolys) {
|
||||||
|
Polygons convparts = convex_decomposition_tess(expoly);
|
||||||
|
std::move(convparts.begin(), convparts.end(), std::back_inserter(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons nfp_concave_concave_tess(const ExPolygon &fixed,
|
||||||
|
const ExPolygon &movable)
|
||||||
|
{
|
||||||
|
Polygons fixed_decomp = convex_decomposition_tess(fixed);
|
||||||
|
Polygons movable_decomp = convex_decomposition_tess(movable);
|
||||||
|
|
||||||
|
auto refs_mv = reserve_vector<Vec2crd>(movable_decomp.size());
|
||||||
|
|
||||||
|
for (const Polygon &p : movable_decomp)
|
||||||
|
refs_mv.emplace_back(reference_vertex(p));
|
||||||
|
|
||||||
|
auto nfps = reserve_polygons(fixed_decomp.size() * movable_decomp.size());
|
||||||
|
|
||||||
|
Vec2crd ref_whole = reference_vertex(movable);
|
||||||
|
for (const Polygon &fixed_part : fixed_decomp) {
|
||||||
|
size_t mvi = 0;
|
||||||
|
for (const Polygon &movable_part : movable_decomp) {
|
||||||
|
Polygon subnfp = nfp_convex_convex(fixed_part, movable_part);
|
||||||
|
const Vec2crd &ref_mp = refs_mv[mvi];
|
||||||
|
auto d = ref_whole - ref_mp;
|
||||||
|
subnfp.translate(d);
|
||||||
|
nfps.emplace_back(subnfp);
|
||||||
|
mvi++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return union_ex(nfps);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
16
src/libslic3r/Arrange/Core/NFP/NFPConcave_Tesselate.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef NFPCONCAVE_TESSELATE_HPP
|
||||||
|
#define NFPCONCAVE_TESSELATE_HPP
|
||||||
|
|
||||||
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
Polygons convex_decomposition_tess(const Polygon &expoly);
|
||||||
|
Polygons convex_decomposition_tess(const ExPolygon &expoly);
|
||||||
|
Polygons convex_decomposition_tess(const ExPolygons &expolys);
|
||||||
|
ExPolygons nfp_concave_concave_tess(const ExPolygon &fixed, const ExPolygon &movable);
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // NFPCONCAVE_TESSELATE_HPP
|
||||||
286
src/libslic3r/Arrange/Core/NFP/PackStrategyNFP.hpp
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
|
||||||
|
#ifndef PACKSTRATEGYNFP_HPP
|
||||||
|
#define PACKSTRATEGYNFP_HPP
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/ArrangeBase.hpp"
|
||||||
|
|
||||||
|
#include "EdgeCache.hpp"
|
||||||
|
#include "Kernels/KernelTraits.hpp"
|
||||||
|
|
||||||
|
#include "NFPArrangeItemTraits.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Optimize/NLoptOptimizer.hpp"
|
||||||
|
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
struct NFPPackingTag{};
|
||||||
|
|
||||||
|
struct DummyArrangeKernel
|
||||||
|
{
|
||||||
|
template<class ArrItem>
|
||||||
|
double placement_fitness(const ArrItem &itm, const Vec2crd &dest_pos) const
|
||||||
|
{
|
||||||
|
return NaNd;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class Context, class RemIt>
|
||||||
|
bool on_start_packing(ArrItem &itm,
|
||||||
|
const Bed &bed,
|
||||||
|
const Context &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ArrItem> bool on_item_packed(ArrItem &itm) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Strategy> using OptAlg = typename Strategy::OptAlg;
|
||||||
|
|
||||||
|
template<class ArrangeKernel = DummyArrangeKernel,
|
||||||
|
class ExecPolicy = ExecutionSeq,
|
||||||
|
class OptMethod = opt::AlgNLoptSubplex,
|
||||||
|
class StopCond = DefaultStopCondition>
|
||||||
|
struct PackStrategyNFP {
|
||||||
|
using OptAlg = OptMethod;
|
||||||
|
|
||||||
|
ArrangeKernel kernel;
|
||||||
|
ExecPolicy ep;
|
||||||
|
double accuracy = 1.;
|
||||||
|
opt::Optimizer<OptMethod> solver;
|
||||||
|
StopCond stop_condition;
|
||||||
|
|
||||||
|
PackStrategyNFP(opt::Optimizer<OptMethod> slv,
|
||||||
|
ArrangeKernel k = {},
|
||||||
|
ExecPolicy execpolicy = {},
|
||||||
|
double accur = 1.,
|
||||||
|
StopCond stop_cond = {})
|
||||||
|
: kernel{std::move(k)},
|
||||||
|
ep{std::move(execpolicy)},
|
||||||
|
accuracy{accur},
|
||||||
|
solver{std::move(slv)},
|
||||||
|
stop_condition{std::move(stop_cond)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
PackStrategyNFP(ArrangeKernel k = {},
|
||||||
|
ExecPolicy execpolicy = {},
|
||||||
|
double accur = 1.,
|
||||||
|
StopCond stop_cond = {})
|
||||||
|
: PackStrategyNFP{opt::Optimizer<OptMethod>{}, std::move(k),
|
||||||
|
std::move(execpolicy), accur, std::move(stop_cond)}
|
||||||
|
{
|
||||||
|
// Defaults for AlgNLoptSubplex
|
||||||
|
auto iters = static_cast<unsigned>(std::floor(1000 * accuracy));
|
||||||
|
auto optparams =
|
||||||
|
opt::StopCriteria{}.max_iterations(iters).rel_score_diff(
|
||||||
|
1e-20) /*.abs_score_diff(1e-20)*/;
|
||||||
|
|
||||||
|
solver.set_criteria(optparams);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class...Args>
|
||||||
|
struct PackStrategyTag_<PackStrategyNFP<Args...>>
|
||||||
|
{
|
||||||
|
using Tag = NFPPackingTag;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class PStrategy>
|
||||||
|
double pick_best_spot_on_nfp_verts_only(ArrItem &item,
|
||||||
|
const ExPolygons &nfp,
|
||||||
|
const Bed &bed,
|
||||||
|
const PStrategy &strategy)
|
||||||
|
{
|
||||||
|
using KernelT = KernelTraits<decltype(strategy.kernel)>;
|
||||||
|
|
||||||
|
auto score = -std::numeric_limits<double>::infinity();
|
||||||
|
Vec2crd orig_tr = get_translation(item);
|
||||||
|
Vec2crd translation{0, 0};
|
||||||
|
|
||||||
|
auto eval_fitness = [&score, &strategy, &item, &translation,
|
||||||
|
&orig_tr](const Vec2crd &p) {
|
||||||
|
set_translation(item, orig_tr);
|
||||||
|
Vec2crd ref_v = reference_vertex(item);
|
||||||
|
Vec2crd tr = p - ref_v;
|
||||||
|
double fitness = KernelT::placement_fitness(strategy.kernel, item, tr);
|
||||||
|
if (fitness > score) {
|
||||||
|
score = fitness;
|
||||||
|
translation = tr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const ExPolygon &expoly : nfp) {
|
||||||
|
for (const Point &p : expoly.contour) {
|
||||||
|
eval_fitness(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Polygon &h : expoly.holes)
|
||||||
|
for (const Point &p : h.points)
|
||||||
|
eval_fitness(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_translation(item, orig_tr + translation);
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CornerResult
|
||||||
|
{
|
||||||
|
size_t contour_id;
|
||||||
|
opt::Result<1> oresult;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed, class... Args>
|
||||||
|
double pick_best_spot_on_nfp(ArrItem &item,
|
||||||
|
const ExPolygons &nfp,
|
||||||
|
const Bed &bed,
|
||||||
|
const PackStrategyNFP<Args...> &strategy)
|
||||||
|
{
|
||||||
|
auto &ex_policy = strategy.ep;
|
||||||
|
using KernelT = KernelTraits<decltype(strategy.kernel)>;
|
||||||
|
|
||||||
|
auto score = -std::numeric_limits<double>::infinity();
|
||||||
|
Vec2crd orig_tr = get_translation(item);
|
||||||
|
Vec2crd translation{0, 0};
|
||||||
|
Vec2crd ref_v = reference_vertex(item);
|
||||||
|
|
||||||
|
auto edge_caches = reserve_vector<EdgeCache>(nfp.size());
|
||||||
|
auto sample_sets = reserve_vector<std::vector<ContourLocation>>(
|
||||||
|
nfp.size());
|
||||||
|
|
||||||
|
for (const ExPolygon &expoly : nfp) {
|
||||||
|
edge_caches.emplace_back(EdgeCache{&expoly});
|
||||||
|
edge_caches.back().sample_contour(strategy.accuracy,
|
||||||
|
sample_sets.emplace_back());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nthreads = execution::max_concurrency(ex_policy);
|
||||||
|
|
||||||
|
std::vector<CornerResult> gresults(edge_caches.size());
|
||||||
|
|
||||||
|
auto resultcmp = [](auto &a, auto &b) {
|
||||||
|
return a.oresult.score < b.oresult.score;
|
||||||
|
};
|
||||||
|
|
||||||
|
execution::for_each(
|
||||||
|
ex_policy, size_t(0), edge_caches.size(),
|
||||||
|
[&](size_t edge_cache_idx) {
|
||||||
|
auto &ec_contour = edge_caches[edge_cache_idx];
|
||||||
|
auto &corners = sample_sets[edge_cache_idx];
|
||||||
|
std::vector<CornerResult> results(corners.size());
|
||||||
|
|
||||||
|
auto cornerfn = [&](size_t i) {
|
||||||
|
ContourLocation cr = corners[i];
|
||||||
|
auto objfn = [&](opt::Input<1> &in) {
|
||||||
|
Vec2crd p = ec_contour.coords(ContourLocation{cr.contour_id, in[0]});
|
||||||
|
Vec2crd tr = p - ref_v;
|
||||||
|
|
||||||
|
return KernelT::placement_fitness(strategy.kernel, item, tr);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assuming that solver is a lightweight object
|
||||||
|
auto solver = strategy.solver;
|
||||||
|
solver.to_max();
|
||||||
|
auto oresult = solver.optimize(objfn,
|
||||||
|
opt::initvals({cr.dist}),
|
||||||
|
opt::bounds({{0., 1.}}));
|
||||||
|
|
||||||
|
results[i] = CornerResult{cr.contour_id, oresult};
|
||||||
|
};
|
||||||
|
|
||||||
|
execution::for_each(ex_policy, size_t(0), results.size(),
|
||||||
|
cornerfn, nthreads);
|
||||||
|
|
||||||
|
auto it = std::max_element(results.begin(), results.end(),
|
||||||
|
resultcmp);
|
||||||
|
|
||||||
|
if (it != results.end())
|
||||||
|
gresults[edge_cache_idx] = *it;
|
||||||
|
},
|
||||||
|
nthreads);
|
||||||
|
|
||||||
|
auto it = std::max_element(gresults.begin(), gresults.end(), resultcmp);
|
||||||
|
if (it != gresults.end()) {
|
||||||
|
score = it->oresult.score;
|
||||||
|
size_t path_id = std::distance(gresults.begin(), it);
|
||||||
|
size_t contour_id = it->contour_id;
|
||||||
|
double dist = it->oresult.optimum[0];
|
||||||
|
|
||||||
|
Vec2crd pos = edge_caches[path_id].coords(ContourLocation{contour_id, dist});
|
||||||
|
Vec2crd tr = pos - ref_v;
|
||||||
|
|
||||||
|
set_translation(item, orig_tr + tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Strategy, class ArrItem, class Bed, class RemIt>
|
||||||
|
bool pack(Strategy &strategy,
|
||||||
|
const Bed &bed,
|
||||||
|
ArrItem &item,
|
||||||
|
const PackStrategyContext<Strategy, ArrItem> &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items,
|
||||||
|
const NFPPackingTag &)
|
||||||
|
{
|
||||||
|
using KernelT = KernelTraits<decltype(strategy.kernel)>;
|
||||||
|
|
||||||
|
// The kernel might pack the item immediately
|
||||||
|
bool packed = KernelT::on_start_packing(strategy.kernel, item, bed,
|
||||||
|
packing_context, remaining_items);
|
||||||
|
|
||||||
|
double orig_rot = get_rotation(item);
|
||||||
|
double final_rot = 0.;
|
||||||
|
double final_score = -std::numeric_limits<double>::infinity();
|
||||||
|
Vec2crd orig_tr = get_translation(item);
|
||||||
|
Vec2crd final_tr = orig_tr;
|
||||||
|
|
||||||
|
bool cancelled = strategy.stop_condition();
|
||||||
|
const auto & rotations = allowed_rotations(item);
|
||||||
|
|
||||||
|
// Check all rotations but only if item is not already packed
|
||||||
|
for (auto rot_it = rotations.begin();
|
||||||
|
!cancelled && !packed && rot_it != rotations.end(); ++rot_it) {
|
||||||
|
|
||||||
|
double rot = *rot_it;
|
||||||
|
|
||||||
|
set_rotation(item, orig_rot + rot);
|
||||||
|
set_translation(item, orig_tr);
|
||||||
|
|
||||||
|
auto nfp = calculate_nfp(item, packing_context, bed,
|
||||||
|
strategy.stop_condition);
|
||||||
|
double score = NaNd;
|
||||||
|
if (!nfp.empty()) {
|
||||||
|
score = pick_best_spot_on_nfp(item, nfp, bed, strategy);
|
||||||
|
|
||||||
|
cancelled = strategy.stop_condition();
|
||||||
|
if (score > final_score) {
|
||||||
|
final_score = score;
|
||||||
|
final_rot = rot;
|
||||||
|
final_tr = get_translation(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the score is not valid, and the item is not already packed, or
|
||||||
|
// the packing was cancelled asynchronously by stop condition, then
|
||||||
|
// discard the packing
|
||||||
|
bool is_score_valid = !std::isnan(final_score) && !std::isinf(final_score);
|
||||||
|
packed = !cancelled && (packed || is_score_valid);
|
||||||
|
|
||||||
|
if (packed) {
|
||||||
|
set_translation(item, final_tr);
|
||||||
|
set_rotation(item, orig_rot + final_rot);
|
||||||
|
|
||||||
|
// Finally, consult the kernel if the packing is sane
|
||||||
|
packed = KernelT::on_item_packed(strategy.kernel, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // PACKSTRATEGYNFP_HPP
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
#ifndef RECTANGLEOVERFITPACKINGSTRATEGY_HPP
|
||||||
|
#define RECTANGLEOVERFITPACKINGSTRATEGY_HPP
|
||||||
|
|
||||||
|
#include "Kernels/RectangleOverfitKernelWrapper.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/Arrange/Core/NFP/PackStrategyNFP.hpp"
|
||||||
|
#include "libslic3r/Arrange/Core/Beds.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r { namespace arr2 {
|
||||||
|
|
||||||
|
using PostAlignmentFn = std::function<Vec2crd(const BoundingBox &bedbb,
|
||||||
|
const BoundingBox &pilebb)>;
|
||||||
|
|
||||||
|
struct CenterAlignmentFn {
|
||||||
|
Vec2crd operator() (const BoundingBox &bedbb,
|
||||||
|
const BoundingBox &pilebb)
|
||||||
|
{
|
||||||
|
return bedbb.center() - pilebb.center();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
struct RectangleOverfitPackingContext : public DefaultPackingContext<ArrItem>
|
||||||
|
{
|
||||||
|
BoundingBox limits;
|
||||||
|
int bed_index;
|
||||||
|
PostAlignmentFn post_alignment_fn;
|
||||||
|
|
||||||
|
explicit RectangleOverfitPackingContext(const BoundingBox limits,
|
||||||
|
int bedidx,
|
||||||
|
PostAlignmentFn alignfn = CenterAlignmentFn{})
|
||||||
|
: limits{limits}, bed_index{bedidx}, post_alignment_fn{alignfn}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void align_pile()
|
||||||
|
{
|
||||||
|
// Here, the post alignment can be safely done. No throwing
|
||||||
|
// functions are called!
|
||||||
|
if (fixed_items_range(*this).empty()) {
|
||||||
|
auto itms = packed_items_range(*this);
|
||||||
|
auto pilebb = bounding_box(itms);
|
||||||
|
|
||||||
|
for (auto &itm : itms) {
|
||||||
|
translate(itm, post_alignment_fn(limits, pilebb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RectangleOverfitPackingContext() { align_pile(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// With rectange bed, and no fixed items, an infinite bed with
|
||||||
|
// RectangleOverfitKernelWrapper can produce better results than a pure
|
||||||
|
// RectangleBed with inner-fit polygon calculation.
|
||||||
|
template<class ...Args>
|
||||||
|
struct RectangleOverfitPackingStrategy {
|
||||||
|
PackStrategyNFP<Args...> base_strategy;
|
||||||
|
|
||||||
|
PostAlignmentFn post_alignment_fn = CenterAlignmentFn{};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
using Context = RectangleOverfitPackingContext<ArrItem>;
|
||||||
|
|
||||||
|
RectangleOverfitPackingStrategy(PackStrategyNFP<Args...> s,
|
||||||
|
PostAlignmentFn post_align_fn)
|
||||||
|
: base_strategy{std::move(s)}, post_alignment_fn{post_align_fn}
|
||||||
|
{}
|
||||||
|
|
||||||
|
RectangleOverfitPackingStrategy(PackStrategyNFP<Args...> s)
|
||||||
|
: base_strategy{std::move(s)}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RectangleOverfitPackingStrategyTag {};
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
struct PackStrategyTag_<RectangleOverfitPackingStrategy<Args...>> {
|
||||||
|
using Tag = RectangleOverfitPackingStrategyTag;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
struct PackStrategyTraits_<RectangleOverfitPackingStrategy<Args...>> {
|
||||||
|
template<class ArrItem>
|
||||||
|
using Context = typename RectangleOverfitPackingStrategy<
|
||||||
|
Args...>::template Context<StripCVRef<ArrItem>>;
|
||||||
|
|
||||||
|
template<class ArrItem, class Bed>
|
||||||
|
static Context<ArrItem> create_context(
|
||||||
|
RectangleOverfitPackingStrategy<Args...> &ps,
|
||||||
|
const Bed &bed,
|
||||||
|
int bed_index)
|
||||||
|
{
|
||||||
|
return Context<ArrItem>{bounding_box(bed), bed_index,
|
||||||
|
ps.post_alignment_fn};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ArrItem>
|
||||||
|
struct PackingContextTraits_<RectangleOverfitPackingContext<ArrItem>>
|
||||||
|
: public PackingContextTraits_<DefaultPackingContext<ArrItem>>
|
||||||
|
{
|
||||||
|
static void add_packed_item(RectangleOverfitPackingContext<ArrItem> &ctx, ArrItem &itm)
|
||||||
|
{
|
||||||
|
ctx.add_packed_item(itm);
|
||||||
|
|
||||||
|
// to prevent coords going out of range
|
||||||
|
ctx.align_pile();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Strategy, class ArrItem, class Bed, class RemIt>
|
||||||
|
bool pack(Strategy &strategy,
|
||||||
|
const Bed &bed,
|
||||||
|
ArrItem &item,
|
||||||
|
const PackStrategyContext<Strategy, ArrItem> &packing_context,
|
||||||
|
const Range<RemIt> &remaining_items,
|
||||||
|
const RectangleOverfitPackingStrategyTag &)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (fixed_items_range(packing_context).empty()) {
|
||||||
|
auto &base = strategy.base_strategy;
|
||||||
|
PackStrategyNFP modded_strategy{
|
||||||
|
base.solver,
|
||||||
|
RectangleOverfitKernelWrapper{base.kernel, packing_context.limits},
|
||||||
|
base.ep, base.accuracy};
|
||||||
|
|
||||||
|
ret = pack(modded_strategy,
|
||||||
|
InfiniteBed{packing_context.limits.center()}, item,
|
||||||
|
packing_context, remaining_items, NFPPackingTag{});
|
||||||
|
} else {
|
||||||
|
ret = pack(strategy.base_strategy, bed, item, packing_context,
|
||||||
|
remaining_items, NFPPackingTag{});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::arr2
|
||||||
|
|
||||||
|
#endif // RECTANGLEOVERFITPACKINGSTRATEGY_HPP
|
||||||