Merge branch 'master' into fs_emboss

This commit is contained in:
Filip Sykala 2021-12-13 10:52:04 +01:00
commit 88523bceb6
101 changed files with 219622 additions and 137511 deletions

1
.gitignore vendored
View file

@ -17,3 +17,4 @@ local-lib
/.vscode/
build-linux/*
deps/build-linux/*
**/.DS_Store

View file

@ -478,13 +478,27 @@ find_package(cereal REQUIRED)
# l10n
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
add_custom_target(gettext_make_pot
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug
COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --debug --boost
-f "${L10N_DIR}/list.txt"
-o "${L10N_DIR}/PrusaSlicer.pot"
COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${L10N_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generate pot file from strings in the source tree"
)
add_custom_target(gettext_merge_po_with_pot
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Merge localization po with new generted pot file"
)
file(GLOB L10N_PO_FILES "${L10N_DIR}/*/PrusaSlicer*.po")
foreach(po_file ${L10N_PO_FILES})
GET_FILENAME_COMPONENT(po_dir "${po_file}" DIRECTORY)
SET(po_new_file "${po_dir}/PrusaSlicer_.po")
add_custom_command(
TARGET gettext_merge_po_with_pot PRE_BUILD
COMMAND msgmerge -N -o ${po_file} ${po_file} "${L10N_DIR}/PrusaSlicer.pot"
DEPENDS ${po_file}
)
endforeach()
add_custom_target(gettext_po_to_mo
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Generate localization po files (binary) from mo files (texts)"
@ -495,7 +509,8 @@ foreach(po_file ${L10N_PO_FILES})
SET(mo_file "${po_dir}/PrusaSlicer.mo")
add_custom_command(
TARGET gettext_po_to_mo PRE_BUILD
COMMAND msgfmt ARGS -o ${mo_file} ${po_file}
COMMAND msgfmt ARGS --check-format -o ${mo_file} ${po_file}
#COMMAND msgfmt ARGS --check-compatibility -o ${mo_file} ${po_file}
DEPENDS ${po_file}
)
endforeach()

View file

@ -6,7 +6,8 @@
@ECHO Performs initial build or rebuild of the app (build) and deps (build/deps).
@ECHO Default options are determined from build directories and system state.
@ECHO.
@ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-DESTDIR ^<directory^>]
@ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-VERSION ^<version^>]
@ECHO [-PRODUCT ^<product^>] [-DESTDIR ^<directory^>]
@ECHO [-STEPS ^<all^|all-dirty^|app^|app-dirty^|deps^|deps-dirty^>]
@ECHO [-RUN ^<console^|custom^|none^|viewer^|window^>]
@ECHO.
@ -14,6 +15,10 @@
@ECHO Default: %PS_ARCH_HOST%
@ECHO -c -CONFIG MSVC project config
@ECHO Default: %PS_CONFIG_DEFAULT%
@ECHO -v -VERSION Major version number of MSVC installation to use for build
@ECHO Default: %PS_VERSION_SUPPORTED%
@ECHO -p -PRODUCT Product ID of MSVC installation to use for build
@ECHO Default: %PS_PRODUCT_DEFAULT%
@ECHO -s -STEPS Performs only the specified build steps:
@ECHO all - clean and build deps and app
@ECHO all-dirty - build deps and app without cleaning
@ -55,6 +60,23 @@ SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt
SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME%
SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo"
REM The officially supported toolchain version is 16 (Visual Studio 2019)
REM TODO: Update versions after Boost gets rolled to 1.78 or later
SET PS_VERSION_SUPPORTED=16
SET PS_VERSION_EXCEEDED=17
SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
FOR /F "tokens=4 USEBACKQ delims=." %%I IN (`"%VSWHERE%" -nologo -property productId`) DO SET PS_PRODUCT_DEFAULT=%%I
IF "%PS_PRODUCT_DEFAULT%" EQU "" (
SET EXIT_STATUS=-1
@ECHO ERROR: No Visual Studio installation found. 1>&2
GOTO :HELP
)
REM Default to the latest supported version if multiple are available
FOR /F "tokens=1 USEBACKQ delims=." %%I IN (
`^""%VSWHERE%" -version "[%PS_VERSION_SUPPORTED%,%PS_VERSION_EXCEEDED%)" -latest -nologo -property catalog_buildVersion^"`
) DO SET PS_VERSION_SUPPORTED=%%I
REM Probe build directories and system state for reasonable default arguments
pushd %~dp0
SET PS_CONFIG=RelWithDebInfo
@ -62,6 +84,8 @@ SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64%
CALL :TOLOWER PS_ARCH
SET PS_RUN=none
SET PS_DESTDIR=
SET PS_VERSION=
SET PS_PRODUCT=%PS_PRODUCT_DEFAULT%
CALL :RESOLVE_DESTDIR_CACHE
REM Set up parameters used by help menu
@ -75,7 +99,7 @@ SET EXIT_STATUS=1
SET PS_CURRENT_STEP=arguments
SET PARSER_STATE=
SET PARSER_FAIL=
FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN" PARSER_STATE "%%~I"
FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN VERSION PRODUCT" PARSER_STATE "%%~I"
IF "%PARSER_FAIL%" NEQ "" (
@ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
GOTO :HELP
@ -124,6 +148,15 @@ IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" (
@ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty"
GOTO :HELP
)
IF DEFINED PS_VERSION (
SET /A PS_VERSION_EXCEEDED=%PS_VERSION% + 1
) ELSE SET PS_VERSION=%PS_VERSION_SUPPORTED%
SET MSVC_FILTER=-products Microsoft.VisualStudio.Product.%PS_PRODUCT% -version "[%PS_VERSION%,%PS_VERSION_EXCEEDED%)"
FOR /F "tokens=* USEBACKQ" %%I IN (`^""%VSWHERE%" %MSVC_FILTER% -nologo -property installationPath^"`) DO SET MSVC_DIR=%%I
IF NOT EXIST "%MSVC_DIR%" (
@ECHO ERROR: Compatible Visual Studio installation not found. 1>&2
GOTO :HELP
)
REM Give the user a chance to cancel if we found something odd.
IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
@ECHO.
@ -142,9 +175,6 @@ SET PS_CURRENT_STEP=environment
@ECHO ** Run App: %PS_RUN%
@ECHO ** Deps path: %PS_DESTDIR%
@ECHO ** Using Microsoft Visual Studio installation found at:
SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
FOR /F "tokens=* USEBACKQ" %%I IN (`"%VSWHERE%" -nologo -property installationPath`) DO SET MSVC_DIR=%%I
@ECHO ** %MSVC_DIR%
CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
IF %ERRORLEVEL% NEQ 0 GOTO :END
@ -276,7 +306,7 @@ REM Functions and stubs start here.
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
REM Copy a legacy file if we don't have one in the proper location.
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%" > nul 2> nul
CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (

View file

@ -13,7 +13,7 @@ prusaslicer_add_cmake_project(wxWidgets
# GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"
# GIT_TAG tm_cross_compile #${_wx_git_tag}
URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip
URL_HASH SHA256=ed36a2159c781cce07b06378664e683ebd8cb2f51914aba9acd3bfca3d63d7d3
URL_HASH SHA256=22f9393f80b94ea84e68b925cd95e0dc63e14dc7a72d8ca292b12404ccf98d1b
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG
CMAKE_ARGS
-DwxBUILD_PRECOMP=ON

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -88,6 +88,7 @@ src/libslic3r/ExtrusionEntity.cpp
src/libslic3r/Flow.cpp
src/libslic3r/Format/3mf.cpp
src/libslic3r/Format/AMF.cpp
src/libslic3r/GCode/PostProcessor.cpp
src/libslic3r/miniz_extension.cpp
src/libslic3r/Preset.cpp
src/libslic3r/Print.cpp

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
min_slic3r_version = 2.4.0-beta4
0.1.1 Added Ender 2 Pro
min_slic3r_version = 2.3.2-alpha0
0.1.0 Added Ender-7, Sermoon D1, CR-10 SMART
min_slic3r_version = 2.3.1-beta

View file

@ -5,7 +5,7 @@
name = Creality
# 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.
config_version = 0.1.0
config_version = 0.1.1
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -104,6 +104,15 @@ bed_model = ender2_bed.stl
bed_texture = ender2.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:ENDER2PRO]
name = Creality Ender-2 Pro
variants = 0.4
technology = FFF
family = ENDER
bed_model = ender2pro_bed.stl
bed_texture = ender2pro.svg
default_materials = Generic PLA @CREALITY; Generic PETG @CREALITY; Generic ABS @CREALITY; Creality PLA @CREALITY; Prusament PLA @CREALITY; Prusament PETG @CREALITY; AzureFilm PLA @CREALITY; Devil Design PLA @CREALITY; Devil Design PLA Matt @CREALITY; Devil Design PLA Galaxy @CREALITY; Extrudr PLA NX2 @CREALITY; Real Filament PLA @CREALITY; Velleman PLA @CREALITY; 3DJAKE ecoPLA @CREALITY; 3DJAKE ecoPLA Matt @CREALITY; 3DJAKE ecoPLA Tough @CREALITY; 123-3D Jupiter PLA @CREALITY
[printer_model:CR5PRO]
name = Creality CR-5 Pro
variants = 0.4
@ -1002,6 +1011,14 @@ max_print_height = 200
printer_model = ENDER2
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER2\nPRINTER_HAS_BOWDEN
[printer:Creality Ender-2 Pro]
inherits = *common*
renamed_from = "Creality ENDER-2 Pro"
bed_shape = 0x0,165x0,165x165,0x165
max_print_height = 180
printer_model = ENDER2PRO
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_CREALITY\nPRINTER_MODEL_ENDER2\nPRINTER_HAS_BOWDEN
[printer:Creality CR-5 Pro]
inherits = *common*; *slowabl*; *descendingz*
retract_length = 6

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View file

@ -0,0 +1,622 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
sodipodi:docname="ender2pro.svg"
inkscape:version="1.1.1 (c3084ef, 2021-09-22)"
id="svg1883"
version="1.1"
viewBox="0 0 166.02917 166.02917"
height="166.02917mm"
width="166.02917mm"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs1877" />
<sodipodi:namedview
inkscape:snap-page="false"
inkscape:window-maximized="0"
inkscape:window-y="25"
inkscape:window-x="448"
inkscape:window-height="1227"
inkscape:window-width="1600"
borderlayer="false"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="273.25679"
inkscape:cx="270.34593"
inkscape:zoom="1.3741653"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
borderopacity="1"
bordercolor="#f14bac"
pagecolor="#5d5d5d"
id="base"
inkscape:pagecheckerboard="0"
width="165mm">
<inkscape:grid
id="grid2446"
type="xygrid"
originx="0.52916899"
originy="0.52917032" />
</sodipodi:namedview>
<metadata
id="metadata1880">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer"
transform="translate(0.529169,0.52917033)"
style="display:inline">
<path
id="rect346"
style="display:inline;fill:#ffffff;fill-rule:evenodd;stroke-width:0.236623"
d="m 97.449555,145.09211 v 10.20042 h 55.800205 v -10.20042 z m 8.336955,1.83245 c 0.71438,0 1.36733,0.36191 1.77302,0.97927 0.41451,0.635 0.44959,1.3049 0.44959,2.08101 v 3.35173 h -1.83452 v -3.80132 c 0,-0.45861 -0.1058,-0.68781 -0.40566,-0.68781 -0.32632,0 -0.37052,0.26448 -0.37052,0.68781 v 3.80132 h -1.84278 v -3.35173 -0.17622 c 0,-0.47625 0.0176,-0.97906 0.26458,-1.56114 0.34396,-0.81139 1.11963,-1.32292 1.96629,-1.32292 z m 23.56859,0 c 1.3141,0 2.23139,0.97896 2.23139,2.11667 0,0.53798 -0.21188,0.9526 -0.47646,1.42885 l -0.59066,1.06712 h 1.05833 v 1.79937 h -4.10104 l 2.24896,-3.78375 c 0.0529,-0.097 0.0966,-0.24691 0.0966,-0.40566 0,-0.34396 -0.19392,-0.52038 -0.55552,-0.52038 -0.32632,0 -0.55552,0.22924 -0.55552,0.54674 0,0.17639 0.0619,0.29983 0.22066,0.40566 l -0.79375,1.36736 c -0.7232,-0.37042 -1.09399,-0.9616 -1.09399,-1.78181 0,-1.25236 0.95278,-2.24017 2.31097,-2.24017 z m 7.62124,0 c 1.33173,0 2.33732,1.01458 2.33732,2.2934 0,1.19063 -0.90833,1.98438 -2.13423,1.98438 -0.0882,0 -0.1943,3e-5 -0.3266,-0.009 v -1.56114 c 0.0441,0.009 0.0882,0.009 0.12351,0.009 0.33514,0 0.55604,-0.22052 0.55604,-0.52038 0,-0.28222 -0.23816,-0.5116 -0.52038,-0.5116 -0.42334,0 -0.52039,0.31761 -0.52039,0.89969 v 3.82767 h -1.87843 v -3.51038 -0.29972 c 0,-0.44097 0.0264,-0.88171 0.27337,-1.38441 0.37041,-0.75847 1.13729,-1.2175 2.08979,-1.2175 z m 11.27321,0 c 0.88195,0 1.7024,0.35312 2.31976,0.97048 0.59972,0.60855 0.95239,1.44619 0.95239,2.30167 0,0.74084 -0.25548,1.48184 -0.73173,2.07274 -0.60854,0.75848 -1.52618,1.19063 -2.54042,1.19063 -0.74083,0 -1.48135,-0.25601 -2.06344,-0.73226 -0.75847,-0.61736 -1.19941,-1.54333 -1.19941,-2.53111 0,-0.8643 0.34382,-1.68431 0.96119,-2.30167 0.60854,-0.61736 1.46382,-0.97048 2.30166,-0.97048 z m -46.61317,0.12351 h 1.20871 v 1.83451 h -1.19941 c -0.23813,0 -0.37052,0.0528 -0.37052,0.29094 0,0.23812 0.12358,0.31781 0.37052,0.31781 h 1.11983 v 1.40198 h -1.29656 c -0.23813,0 -0.36174,0.0533 -0.36174,0.29146 0,0.23812 0.11479,0.31729 0.36174,0.31729 h 1.37614 v 1.83451 h -1.05833 -0.24702 c -0.44097,0 -0.86437,-0.0177 -1.30534,-0.2558 -0.590907,-0.32631 -0.91726,-0.88201 -0.91726,-1.43763 v -2.3549 c 0,-0.73201 0.02649,-1.28733 0.652674,-1.79886 0.414516,-0.34395 0.952186,-0.44131 1.666566,-0.44131 z m 7.23418,0 h 1.85208 0.34365 c 0.49389,0 1.0675,0.0268 1.76424,0.31781 1.14652,0.47625 1.86086,1.56083 1.86086,2.83083 0,1.27882 -0.71437,2.35507 -1.85208,2.84014 -0.46743,0.19403 -0.97045,0.29972 -1.50843,0.29972 h -0.29973 v -1.87844 h 0.3266 c 0.9084,0 1.45521,-0.52055 1.45521,-1.2702 0,-0.82903 -0.5733,-1.26142 -1.71101,-1.26142 H 110.749 v 4.41006 h -1.87844 z m 8.71678,0 h 1.2082 v 1.83451 h -1.19941 c -0.23813,0 -0.37052,0.0528 -0.37052,0.29094 0,0.23812 0.12357,0.31781 0.37052,0.31781 h 1.12034 v 1.40198 h -1.29656 c -0.23812,0 -0.36174,0.0533 -0.36174,0.29146 0,0.23812 0.1148,0.31729 0.36174,0.31729 h 1.37563 v 1.83451 h -1.05834 -0.24701 c -0.44097,0 -0.86386,-0.0177 -1.30483,-0.2558 -0.5909,-0.32631 -0.91726,-0.88201 -0.91726,-1.43763 v -2.3549 c 0,-0.73201 0.0265,-1.28733 0.65268,-1.79886 0.41451,-0.34395 0.95219,-0.44131 1.66656,-0.44131 z m 1.96319,0 h 2.30167 c 0.55562,0 1.05816,0.009 1.63142,0.43253 0.54681,0.40569 0.85577,1.02264 0.85577,1.69292 -10e-6,0.65264 -0.29122,1.16455 -0.88212,1.62316 l 1.09347,2.53989 h -1.97559 l -0.85524,-1.97559 v -1.6583 h 0.20257 c 0.33514,0 0.51159,-0.0968 0.51159,-0.44079 0,-0.35278 -0.18527,-0.41445 -0.51159,-0.41445 h -0.49351 v 4.48913 h -1.87844 z m 20.29127,0 h 2.30218 c 0.55563,0 1.05816,0.009 1.63143,0.43253 0.5468,0.40569 0.85524,1.02264 0.85524,1.69292 0,0.65264 -0.2907,1.16455 -0.8816,1.62316 l 1.09348,2.53989 h -1.97559 l -0.85525,-1.97559 v -1.6583 h 0.20257 c 0.33514,0 0.5116,-0.0968 0.5116,-0.44079 0,-0.35278 -0.18528,-0.41445 -0.5116,-0.41445 h -0.49402 v 4.48913 h -1.87844 z m 8.41654,1.71979 c -0.78493,0 -1.42834,0.64392 -1.42834,1.42885 0,0.79375 0.63459,1.42007 1.42834,1.42007 0.79375,0 1.42007,-0.62632 1.42007,-1.42007 0,-0.78493 -0.63514,-1.42885 -1.42007,-1.42885 z" />
</g>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1"
style="display:inline"
transform="translate(0.529169,0.52917033)">
<path
id="path2643"
d="M 0.04966897,0.04966897 H 164.95033 V 164.95033 H 0.04966897 Z"
style="fill:none;stroke:#ffffff;stroke-width:1.09934;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2645"
d="M 75,-0.13595834 V 164.82762"
style="fill:none;stroke:#ffffff;stroke-width:0.786424;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2647"
d="M 0.01821215,90 H 164.98179"
style="fill:none;stroke:#ffffff;stroke-width:0.786424;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2649"
d="M 25.012141,-0.13595834 V 164.82762"
style="fill:none;stroke:#ffffff;stroke-width:0.524283;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2651"
d="M 50.006071,-0.13595834 V 164.82762"
style="fill:none;stroke:#ffffff;stroke-width:0.524283;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2653"
d="M 99.993929,-0.28314159 V 144.6248"
style="fill:none;stroke:#ffffff;stroke-width:0.49138;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path2655"
d="M 124.98786,-0.26523432 V 144.6672"
style="fill:none;stroke:#ffffff;stroke-width:0.527872;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2655-2"
d="M 150.02344,-0.26523432 V 144.6672"
style="display:inline;fill:none;stroke:#ffffff;stroke-width:0.527872;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.524282;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 164.98179,40.012141 H 0.01821435"
id="path2649-5" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:0.524282;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 164.98155,14.979971 H 0.01797199"
id="path2649-5-8" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.524282;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 164.98179,65.006071 H 0.01821435"
id="path2651-4" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.524282;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 164.98179,114.99393 H 0.01821435"
id="path2653-9" />
<path
style="fill:none;stroke:#ffffff;stroke-width:0.524282;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 164.98179,139.98786 H 0.01821435"
id="path2655-5" />
<path
id="path2681"
d="M 4.9735417,-0.26458333 V 165.26458"
style="fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.5, 0.25;stroke-dashoffset:0;stroke-opacity:1" />
<path
id="path2683"
d="M 9.9972278,165.26483 V -0.23826333"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524189, 0.262094;stroke-dashoffset:0;stroke-opacity:1" />
<path
id="path2685"
d="M 15.013135,-0.23826333 V 165.26483"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524189, 0.262094;stroke-dashoffset:0;stroke-opacity:1" />
<path
id="path2687"
d="M 20.029042,165.26483 V -0.23826333"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524189, 0.262094;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524188, 0.262094;stroke-dashoffset:0;stroke-opacity:1"
d="M 29.981509,-0.52917033 V 164.97393"
id="path2681-2" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524188, 0.262094;stroke-dashoffset:0;stroke-opacity:1"
d="M 34.997416,164.97393 V -0.52917033"
id="path2683-1" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524188, 0.262094;stroke-dashoffset:0;stroke-opacity:1"
d="M 40.013322,-0.52917033 V 164.97393"
id="path2685-5" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262094;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524188, 0.262094;stroke-dashoffset:0;stroke-opacity:1"
d="M 45.029231,164.97393 V -0.52917033"
id="path2687-4" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 54.970379,0.04904167 V 164.52883"
id="path2681-9" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 59.987388,164.52883 V 0.04904167"
id="path2683-8" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 65.004395,0.04904167 V 164.52883"
id="path2685-4" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 70.021405,164.52883 V 0.04904167"
id="path2687-7" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 80.002511,-0.52917033 V 163.95062"
id="path2681-3" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 85.01952,163.95062 V -0.52917033"
id="path2683-6" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 90.036528,-0.52917033 V 163.95062"
id="path2685-3" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.261312;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522622, 0.261312;stroke-dashoffset:0;stroke-opacity:1"
d="M 95.053538,163.95062 V -0.52917033"
id="path2687-44" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.245348;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.490694, 0.245348;stroke-dashoffset:0;stroke-opacity:1"
d="M 104.96427,0.04904167 V 145.04904"
id="path2681-36" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.264112;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.528224, 0.264112;stroke-dashoffset:0;stroke-opacity:1"
d="M 109.9988,145.04903 109.98118,0.04904167"
id="path2683-5"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.263959;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.527917, 0.263959;stroke-dashoffset:0;stroke-opacity:1"
d="M 114.99919,0.04904227 V 145.04899"
id="path2685-7"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.263959;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.527917, 0.263959;stroke-dashoffset:0;stroke-opacity:1"
d="M 119.99653,145.04899 120.01412,0.04904227"
id="path2687-48"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.263598;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.527194, 0.263598;stroke-dashoffset:0;stroke-opacity:1"
d="M 129.95634,0.04904227 129.99163,144.64899"
id="path2681-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.263598;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.527194, 0.263598;stroke-dashoffset:0;stroke-opacity:1"
d="M 134.98904,144.64899 V 0.04904227"
id="path2683-0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.245849;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.491697, 0.245849;stroke-dashoffset:0;stroke-opacity:1"
d="M 140.00037,0.04903965 V 145.04904"
id="path2685-2"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.245078;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.490154, 0.245078;stroke-dashoffset:0;stroke-opacity:1"
d="M 145.0201,144.64901 V 0.04903965"
id="path2687-47" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.261383;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522763, 0.261383;stroke-dashoffset:0;stroke-opacity:1"
d="M 155.02037,164.52883 V 0.04882967"
id="path2687-47-8" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.261383;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.522763, 0.261383;stroke-dashoffset:0;stroke-opacity:1"
d="M 160.01152,164.45083 V -0.02917033"
id="path2687-47-8-9" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 164.70884,19.961975 0.05273017,20.006069"
id="path2681-39"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 164.12698,9.9619027 -0.5291339,10.005993"
id="path2681-39-4"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 164.12698,4.9619027 -0.5291339,5.0059927"
id="path2681-39-4-7"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 0.05273017,25.005541 164.70884,24.979083"
id="path2683-3"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 164.70884,29.996193 0.05273017,30.005013"
id="path2685-51"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 0.05273017,35.004485 164.70884,35.013284"
id="path2687-486"
sodipodi:nodetypes="cc" />
<path
id="path2681-2-1"
d="M 164.9998,45.003429 H 0.05273017"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2683-1-9"
d="M 0.05273017,50.002901 164.9998,49.985263"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2685-5-4"
d="M 164.9998,55.002373 H 0.05273017"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2687-4-9"
d="M 0.05273017,60.001845 164.9998,60.019483"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2681-9-6"
d="M 164.4179,69.947875 0.05273017,70.00079"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2683-8-0"
d="M 0.05273017,75.000262 164.4179,74.964985"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2685-4-7"
d="M 164.4179,79.982096 0.05273017,79.999734"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2681-3-7"
d="M 164.9998,94.980512 0.05273017,94.99815"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2683-6-0"
d="M 0.05273017,99.997622 H 164.9998"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2685-3-3"
d="M 164.9998,105.01473 H -0.529169"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1" />
<path
id="path2687-44-3"
d="M 0.05273017,109.99657 164.9998,110.03186"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2681-36-5"
d="M 164.4179,119.9426 0.05273017,119.99551"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2683-5-1"
d="M 0.05273017,124.99498 164.4179,124.95969"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2685-7-5"
d="M 164.4179,129.97682 0.05273017,129.99445"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2687-48-9"
d="M 0.05273017,134.99393 H 164.4179"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2681-0-8"
d="M 165,145 H 0"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262203;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524403, 0.262203;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2683-0-5"
d="M 0,150 H 97.464513"
style="fill:none;stroke:#fdfdfd;stroke-width:0.240862;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.481723, 0.240862;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2685-2-7"
d="M 150,155 H 0"
style="fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
id="path2687-47-6"
d="M 0,160 H 165"
style="fill:none;stroke:#fdfdfd;stroke-width:0.262666;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.525331, 0.262666;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
id="path2683-5-5"
d="M 110,165 V 155"
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path2683-5-5-7"
d="m 104.90153,164.99983 v -10"
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="M 115,165 V 155"
id="path2683-5-5-6"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="M 120,165 V 155"
id="path2683-5-5-0"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="M 130,165 V 155"
id="path2683-5-5-9"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="M 135,165 V 155"
id="path2683-5-5-2"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="m 139.99583,164.79728 v -10"
id="path2683-5-5-2-6"
sodipodi:nodetypes="cc" />
<path
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.499999, 0.25;stroke-dashoffset:0;stroke-opacity:1"
d="m 144.99583,165.13073 v -10"
id="path2683-5-5-2-6-8"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#ffffff;stroke-width:0.487698;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 125,155.41867 v 9.51398"
id="path2655-0" />
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#ffffff;stroke-width:0.487698;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 150,155 v 9.51398"
id="path2655-0-5" />
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#ffffff;stroke-width:0.483417;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 99.99783,155.30367 v 9.34772"
id="path2655-0-9" />
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-4"
aria-label="125">
<path
id="path188"
d="M 121.63635,2.0732279 V 1.8863313 h 0.2868 V 1.1628608 l -0.24977,0.1378039 -0.0689,-0.1713936 0.35743,-0.18861909 h 0.17656 V 1.8863313 h 0.24718 v 0.1868966 z" />
<path
id="path190"
d="M 122.58805,2.0732279 V 1.9181985 l 0.26614,-0.2661338 q 0.0749,-0.074931 0.11972,-0.1291912 0.0456,-0.05426 0.0698,-0.096463 0.025,-0.043064 0.0327,-0.079237 0.008,-0.036174 0.008,-0.074931 0,-0.031867 -0.0103,-0.060289 -0.0103,-0.029283 -0.0301,-0.049954 -0.0198,-0.021532 -0.05,-0.03359 -0.0301,-0.012919 -0.0689,-0.012919 -0.0663,0 -0.12316,0.029283 -0.0568,0.028422 -0.10766,0.076654 l -0.1111,-0.1429716 q 0.0732,-0.068041 0.1645,-0.10852056 0.0922,-0.0413412 0.19895,-0.0413412 0.0827,0 0.14987,0.0215319 0.0672,0.0206706 0.11455,0.0620118 0.0482,0.041341 0.0741,0.1033529 0.0267,0.062012 0.0267,0.1429716 0,0.067179 -0.0181,0.125746 -0.0181,0.057705 -0.0525,0.112827 -0.0344,0.055122 -0.0853,0.1102431 -0.0499,0.055122 -0.11455,0.1162721 l -0.16364,0.1558906 h 0.47456 v 0.1937868 z" />
<path
id="path192"
d="m 124.31491,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.10507,0.1179946 -0.0672,0.048231 -0.15848,0.073208 -0.0913,0.024977 -0.19809,0.024977 -0.0267,0 -0.0568,-0.00172 -0.0301,-0.00172 -0.0611,-0.00431 -0.031,-0.00258 -0.0603,-0.00689 -0.0293,-0.00345 -0.0543,-0.00775 V 1.8863313 q 0.0491,0.012058 0.11282,0.019809 0.0637,0.00689 0.13006,0.00689 0.12919,0 0.19637,-0.049093 0.068,-0.049954 0.068,-0.1378039 0,-0.091295 -0.0629,-0.1352201 -0.0629,-0.044786 -0.20326,-0.044786 H 123.6035 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.081 q 0.0861,0 0.1645,0.015503 0.0784,0.015503 0.1378,0.05426 0.0603,0.037896 0.0956,0.1033529 0.0362,0.065457 0.0362,0.1653647 z" />
</g>
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-9"
aria-label="100">
<path
id="path181"
d="M 96.636346,2.0732279 V 1.8863313 H 96.92315 V 1.1628608 l -0.249769,0.1378039 -0.0689,-0.1713936 0.357429,-0.18861909 h 0.176561 V 1.8863313 h 0.247186 v 0.1868966 z" />
<path
id="path183"
d="m 98.401097,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03015,0.1093818 -0.08871,0.185174 -0.0577,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171393,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03014,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.08441,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171394,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666626,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03015,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03014,0.050815 -0.04823,0.1274686 -0.01722,0.076653 -0.01722,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.62e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 L 97.76806,1.7571402 q 0.02756,0.083544 0.07751,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01723,-0.077515 0.01723,-0.1817289 z" />
<path
id="path185"
d="m 99.372615,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03014,0.1093818 -0.08871,0.185174 -0.05771,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171394,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03014,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171393,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666627,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03014,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03014,0.050815 -0.04823,0.1274686 -0.01723,0.076653 -0.01723,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.61e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 l -0.419441,0.3031686 q 0.02756,0.083544 0.07752,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01722,-0.077515 0.01722,-0.1817289 z" />
</g>
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-99"
aria-label="25">
<path
id="path166"
style="stroke-width:0.264583"
d="M 22.616538,2.0732279 V 1.9181985 l 0.266134,-0.2661338 q 0.07493,-0.074931 0.119717,-0.1291912 0.04565,-0.05426 0.06976,-0.096463 0.02498,-0.043064 0.03273,-0.079237 0.0078,-0.036174 0.0078,-0.074931 0,-0.031867 -0.01034,-0.060289 -0.01034,-0.029283 -0.03014,-0.049954 -0.01981,-0.021532 -0.04995,-0.03359 -0.03015,-0.012919 -0.0689,-0.012919 -0.06632,0 -0.123163,0.029283 -0.05684,0.028422 -0.107659,0.076654 L 22.611371,1.0784559 q 0.07321,-0.068041 0.164503,-0.10852056 0.09216,-0.0413412 0.198955,-0.0413412 0.08268,0 0.149861,0.0215319 0.06718,0.0206706 0.11455,0.0620118 0.04823,0.041341 0.07407,0.1033529 0.0267,0.062012 0.0267,0.1429716 0,0.067179 -0.01809,0.125746 -0.01809,0.057705 -0.05254,0.112827 -0.03445,0.055122 -0.08527,0.1102431 -0.04995,0.055122 -0.114549,0.1162721 l -0.163642,0.1558906 h 0.474562 v 0.1937868 z" />
<path
id="path168"
style="stroke-width:0.264583"
d="m 24.343394,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105076,0.1179946 -0.06718,0.048231 -0.158474,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05685,-0.00172 -0.03014,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112827,0.019809 0.06374,0.00689 0.130053,0.00689 0.129191,0 0.19637,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 23.631981 V 0.94754221 h 0.649401 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164504,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z" />
</g>
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-3"
aria-label="50">
<path
id="path171"
style="stroke-width:0.264583"
d="m 48.371874,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105075,0.1179946 -0.06718,0.048231 -0.158475,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05684,-0.00172 -0.03015,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112827,0.019809 0.06373,0.00689 0.130052,0.00689 0.129191,0 0.196371,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 47.660462 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164503,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z" />
<path
id="path173"
style="stroke-width:0.264583"
d="m 49.401097,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03014,0.1093818 -0.08871,0.185174 -0.0577,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171393,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03015,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171394,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666626,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03014,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03015,0.050815 -0.04823,0.1274686 -0.01723,0.076653 -0.01723,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.62e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 L 48.76806,1.7571402 q 0.02756,0.083544 0.07751,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01723,-0.077515 0.01723,-0.1817289 z" />
</g>
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-7"
aria-label="75">
<path
id="path176"
style="stroke-width:0.264583"
d="M 72.926595,2.0732279 H 72.688884 L 73.136746,1.150803 H 72.596727 V 0.94754221 h 0.782037 V 1.1309937 Z" />
<path
id="path178"
style="stroke-width:0.264583"
d="m 74.343392,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105076,0.1179946 -0.06718,0.048231 -0.158474,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05684,-0.00172 -0.03014,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112826,0.019809 0.06373,0.00689 0.130053,0.00689 0.129191,0 0.19637,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 73.631979 V 0.94754221 H 74.28138 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164504,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z" />
</g>
<g
transform="translate(0.04335936,162.09955)"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text966-0-5-1"
aria-label="150">
<path
id="path195"
style="stroke-width:0.264583"
d="M 146.47099,2.0732279 V 1.8863313 h 0.2868 V 1.1628608 l -0.24977,0.1378039 -0.0689,-0.1713936 0.35743,-0.18861909 h 0.17656 V 1.8863313 h 0.24719 v 0.1868966 z" />
<path
id="path197"
style="stroke-width:0.264583"
d="m 148.17803,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.10508,0.1179946 -0.0672,0.048231 -0.15847,0.073208 -0.0913,0.024977 -0.1981,0.024977 -0.0267,0 -0.0568,-0.00172 -0.0301,-0.00172 -0.0611,-0.00431 -0.031,-0.00258 -0.0603,-0.00689 -0.0293,-0.00345 -0.0543,-0.00775 V 1.8863313 q 0.0491,0.012058 0.11283,0.019809 0.0637,0.00689 0.13005,0.00689 0.12919,0 0.19637,-0.049093 0.068,-0.049954 0.068,-0.1378039 0,-0.091295 -0.0629,-0.1352201 -0.0629,-0.044786 -0.20326,-0.044786 h -0.22049 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.081 q 0.0861,0 0.1645,0.015503 0.0784,0.015503 0.13781,0.05426 0.0603,0.037896 0.0956,0.1033529 0.0362,0.065457 0.0362,0.1653647 z" />
<path
id="path199"
style="stroke-width:0.264583"
d="m 149.20726,1.505648 q 0,0.1386652 -0.0301,0.2480471 -0.0301,0.1093818 -0.0887,0.185174 -0.0577,0.074931 -0.14125,0.1145495 -0.0835,0.039619 -0.1912,0.039619 -0.093,0 -0.1714,-0.032728 -0.0784,-0.032729 -0.13522,-0.1024917 -0.0568,-0.070624 -0.0887,-0.1800063 -0.0319,-0.1093819 -0.0319,-0.2618275 0,-0.1386652 0.0301,-0.248047 0.031,-0.1093819 0.0887,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.1912,-0.0396186 0.093,0 0.1714,0.0327284 0.0784,0.0327284 0.13436,0.10249171 0.0568,0.069763 0.0887,0.179145 0.0319,0.1093819 0.0319,0.2626879 z m -0.66663,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.002,0.030145 l 0.42203,-0.3048912 q -0.0301,-0.085266 -0.0801,-0.125746 -0.0491,-0.041341 -0.11627,-0.041341 -0.0482,0 -0.0896,0.024977 -0.0413,0.024116 -0.0723,0.074931 -0.0301,0.050815 -0.0482,0.1274686 -0.0172,0.076653 -0.0172,0.1817289 z m 0.45475,0.00345 q 0,-0.014642 -8.6e-4,-0.029283 -8.6e-4,-0.015503 -8.6e-4,-0.029283 l -0.41944,0.3031686 q 0.0276,0.083544 0.0775,0.1240235 0.05,0.04048 0.11628,0.04048 0.0482,0 0.0896,-0.024977 0.0422,-0.024977 0.0723,-0.074931 0.031,-0.050815 0.0482,-0.1274686 0.0172,-0.077515 0.0172,-0.1817289 z" />
</g>
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.262146;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.524292, 0.262146;stroke-dashoffset:0;stroke-opacity:1"
d="M 164.9998,84.999206 0.63463045,85.016844"
id="path2685-4-7-5" />
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.263112;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.526224, 0.263112;stroke-dashoffset:0;stroke-opacity:1"
d="m 153.34858,150 h 11.07649"
id="path2683-0-5-5" />
<path
sodipodi:nodetypes="cc"
style="display:inline;fill:none;stroke:#fdfdfd;stroke-width:0.263112;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.526224, 0.263112;stroke-dashoffset:0;stroke-opacity:1"
d="m 153.01348,155.00039 h 11.07649"
id="path2683-0-5-5-7" />
<g
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.81944px;line-height:1.25;font-family:'Bauhaus 93';-inkscape-font-specification:'Bauhaus 93, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
id="text893"
aria-label="ENDER 2">
<g
id="g220" />
</g>
<g
aria-label="125"
id="text966-0-4-0"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-120.58115,39.81636)">
<path
d="M 121.63635,2.0732279 V 1.8863313 h 0.2868 V 1.1628608 l -0.24977,0.1378039 -0.0689,-0.1713936 0.35743,-0.18861909 h 0.17656 V 1.8863313 h 0.24718 v 0.1868966 z"
id="path188-1" />
<path
d="M 122.58805,2.0732279 V 1.9181985 l 0.26614,-0.2661338 q 0.0749,-0.074931 0.11972,-0.1291912 0.0456,-0.05426 0.0698,-0.096463 0.025,-0.043064 0.0327,-0.079237 0.008,-0.036174 0.008,-0.074931 0,-0.031867 -0.0103,-0.060289 -0.0103,-0.029283 -0.0301,-0.049954 -0.0198,-0.021532 -0.05,-0.03359 -0.0301,-0.012919 -0.0689,-0.012919 -0.0663,0 -0.12316,0.029283 -0.0568,0.028422 -0.10766,0.076654 l -0.1111,-0.1429716 q 0.0732,-0.068041 0.1645,-0.10852056 0.0922,-0.0413412 0.19895,-0.0413412 0.0827,0 0.14987,0.0215319 0.0672,0.0206706 0.11455,0.0620118 0.0482,0.041341 0.0741,0.1033529 0.0267,0.062012 0.0267,0.1429716 0,0.067179 -0.0181,0.125746 -0.0181,0.057705 -0.0525,0.112827 -0.0344,0.055122 -0.0853,0.1102431 -0.0499,0.055122 -0.11455,0.1162721 l -0.16364,0.1558906 h 0.47456 v 0.1937868 z"
id="path190-2" />
<path
d="m 124.31491,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.10507,0.1179946 -0.0672,0.048231 -0.15848,0.073208 -0.0913,0.024977 -0.19809,0.024977 -0.0267,0 -0.0568,-0.00172 -0.0301,-0.00172 -0.0611,-0.00431 -0.031,-0.00258 -0.0603,-0.00689 -0.0293,-0.00345 -0.0543,-0.00775 V 1.8863313 q 0.0491,0.012058 0.11282,0.019809 0.0637,0.00689 0.13006,0.00689 0.12919,0 0.19637,-0.049093 0.068,-0.049954 0.068,-0.1378039 0,-0.091295 -0.0629,-0.1352201 -0.0629,-0.044786 -0.20326,-0.044786 H 123.6035 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.081 q 0.0861,0 0.1645,0.015503 0.0784,0.015503 0.1378,0.05426 0.0603,0.037896 0.0956,0.1033529 0.0362,0.065457 0.0362,0.1653647 z"
id="path192-3" />
</g>
<g
aria-label="100"
id="text966-0-9-0"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-95.765044,64.636453)">
<path
d="M 96.636346,2.0732279 V 1.8863313 H 96.92315 V 1.1628608 l -0.249769,0.1378039 -0.0689,-0.1713936 0.357429,-0.18861909 h 0.176561 V 1.8863313 h 0.247186 v 0.1868966 z"
id="path181-5" />
<path
d="m 98.401097,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03015,0.1093818 -0.08871,0.185174 -0.0577,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171393,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03014,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.08441,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171394,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666626,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03015,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03014,0.050815 -0.04823,0.1274686 -0.01722,0.076653 -0.01722,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.62e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 L 97.76806,1.7571402 q 0.02756,0.083544 0.07751,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01723,-0.077515 0.01723,-0.1817289 z"
id="path183-5" />
<path
d="m 99.372615,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03014,0.1093818 -0.08871,0.185174 -0.05771,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171394,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03014,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171393,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666627,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03014,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03014,0.050815 -0.04823,0.1274686 -0.01723,0.076653 -0.01723,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.61e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 l -0.419441,0.3031686 q 0.02756,0.083544 0.07752,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01722,-0.077515 0.01722,-0.1817289 z"
id="path185-2" />
</g>
<g
aria-label="25"
id="text966-0-99-1"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-21.665685,139.65487)">
<path
d="M 22.616538,2.0732279 V 1.9181985 l 0.266134,-0.2661338 q 0.07493,-0.074931 0.119717,-0.1291912 0.04565,-0.05426 0.06976,-0.096463 0.02498,-0.043064 0.03273,-0.079237 0.0078,-0.036174 0.0078,-0.074931 0,-0.031867 -0.01034,-0.060289 -0.01034,-0.029283 -0.03014,-0.049954 -0.01981,-0.021532 -0.04995,-0.03359 -0.03015,-0.012919 -0.0689,-0.012919 -0.06632,0 -0.123163,0.029283 -0.05684,0.028422 -0.107659,0.076654 L 22.611371,1.0784559 q 0.07321,-0.068041 0.164503,-0.10852056 0.09216,-0.0413412 0.198955,-0.0413412 0.08268,0 0.149861,0.0215319 0.06718,0.0206706 0.11455,0.0620118 0.04823,0.041341 0.07407,0.1033529 0.0267,0.062012 0.0267,0.1429716 0,0.067179 -0.01809,0.125746 -0.01809,0.057705 -0.05254,0.112827 -0.03445,0.055122 -0.08527,0.1102431 -0.04995,0.055122 -0.114549,0.1162721 l -0.163642,0.1558906 h 0.474562 v 0.1937868 z"
style="stroke-width:0.264583"
id="path166-8" />
<path
d="m 24.343394,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105076,0.1179946 -0.06718,0.048231 -0.158474,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05685,-0.00172 -0.03014,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112827,0.019809 0.06374,0.00689 0.130053,0.00689 0.129191,0 0.19637,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 23.631981 V 0.94754221 h 0.649401 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164504,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z"
style="stroke-width:0.264583"
id="path168-6" />
</g>
<g
aria-label="50"
id="text966-0-3-4"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-46.758479,114.60519)">
<path
d="m 48.371874,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105075,0.1179946 -0.06718,0.048231 -0.158475,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05684,-0.00172 -0.03015,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112827,0.019809 0.06373,0.00689 0.130052,0.00689 0.129191,0 0.196371,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 47.660462 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164503,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z"
style="stroke-width:0.264583"
id="path171-2" />
<path
d="m 49.401097,1.505648 q 0,0.1386652 -0.03014,0.2480471 -0.03014,0.1093818 -0.08871,0.185174 -0.0577,0.074931 -0.141249,0.1145495 -0.08354,0.039619 -0.191203,0.039619 -0.09302,0 -0.171393,-0.032728 -0.07838,-0.032729 -0.13522,-0.1024917 -0.05684,-0.070624 -0.08871,-0.1800063 -0.03187,-0.1093819 -0.03187,-0.2618275 0,-0.1386652 0.03015,-0.248047 0.03101,-0.1093819 0.08871,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.191203,-0.0396186 0.09302,0 0.171394,0.0327284 0.07838,0.0327284 0.134359,0.10249171 0.05684,0.069763 0.08871,0.179145 0.03187,0.1093819 0.03187,0.2626887 z m -0.666626,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.0017,0.030145 l 0.422047,-0.304896 q -0.03014,-0.085266 -0.0801,-0.125746 -0.04909,-0.041341 -0.116272,-0.041341 -0.04823,0 -0.08957,0.024977 -0.04134,0.024116 -0.07235,0.074931 -0.03015,0.050815 -0.04823,0.1274686 -0.01723,0.076653 -0.01723,0.1817289 z m 0.454753,0.00345 q 0,-0.014642 -8.62e-4,-0.029283 -8.61e-4,-0.015503 -8.61e-4,-0.029283 L 48.76806,1.7571402 q 0.02756,0.083544 0.07751,0.1240235 0.04995,0.04048 0.116272,0.04048 0.04823,0 0.08957,-0.024977 0.0422,-0.024977 0.07235,-0.074931 0.03101,-0.050815 0.04823,-0.1274686 0.01723,-0.077515 0.01723,-0.1817289 z"
style="stroke-width:0.264583"
id="path173-7" />
</g>
<g
aria-label="75"
id="text966-0-7-6"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-71.57512,90.04448)">
<path
d="M 72.926595,2.0732279 H 72.688884 L 73.136746,1.150803 H 72.596727 V 0.94754221 h 0.782037 V 1.1309937 Z"
style="stroke-width:0.264583"
id="path176-3" />
<path
d="m 74.343392,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.105076,0.1179946 -0.06718,0.048231 -0.158474,0.073208 -0.0913,0.024977 -0.198093,0.024977 -0.0267,0 -0.05684,-0.00172 -0.03014,-0.00172 -0.06115,-0.00431 -0.03101,-0.00258 -0.06029,-0.00689 -0.02928,-0.00345 -0.05426,-0.00775 V 1.8863313 q 0.04909,0.012058 0.112826,0.019809 0.06373,0.00689 0.130053,0.00689 0.129191,0 0.19637,-0.049093 0.06804,-0.049954 0.06804,-0.1378039 0,-0.091295 -0.06287,-0.1352201 -0.06287,-0.044786 -0.203261,-0.044786 H 73.631979 V 0.94754221 H 74.28138 V 1.1456353 h -0.45303 v 0.229099 h 0.08096 q 0.08613,0 0.164504,0.015503 0.07838,0.015503 0.137804,0.05426 0.06029,0.037896 0.0956,0.1033529 0.03617,0.065457 0.03617,0.1653647 z"
style="stroke-width:0.264583"
id="path178-3" />
</g>
<g
aria-label="150"
id="text966-0-5-1-6"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:1.76389px;line-height:1.25;font-family:Consolas;-inkscape-font-specification:'Consolas, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
transform="translate(-145.49952,14.988432)">
<path
d="M 146.47099,2.0732279 V 1.8863313 h 0.2868 V 1.1628608 l -0.24977,0.1378039 -0.0689,-0.1713936 0.35743,-0.18861909 h 0.17656 V 1.8863313 h 0.24719 v 0.1868966 z"
style="stroke-width:0.264583"
id="path195-7" />
<path
d="m 148.17803,1.7132152 q 0,0.090434 -0.0379,0.1610583 -0.0379,0.069763 -0.10508,0.1179946 -0.0672,0.048231 -0.15847,0.073208 -0.0913,0.024977 -0.1981,0.024977 -0.0267,0 -0.0568,-0.00172 -0.0301,-0.00172 -0.0611,-0.00431 -0.031,-0.00258 -0.0603,-0.00689 -0.0293,-0.00345 -0.0543,-0.00775 V 1.8863313 q 0.0491,0.012058 0.11283,0.019809 0.0637,0.00689 0.13005,0.00689 0.12919,0 0.19637,-0.049093 0.068,-0.049954 0.068,-0.1378039 0,-0.091295 -0.0629,-0.1352201 -0.0629,-0.044786 -0.20326,-0.044786 h -0.22049 V 0.94754221 h 0.6494 V 1.1456353 h -0.45303 v 0.229099 h 0.081 q 0.0861,0 0.1645,0.015503 0.0784,0.015503 0.13781,0.05426 0.0603,0.037896 0.0956,0.1033529 0.0362,0.065457 0.0362,0.1653647 z"
style="stroke-width:0.264583"
id="path197-7" />
<path
d="m 149.20726,1.505648 q 0,0.1386652 -0.0301,0.2480471 -0.0301,0.1093818 -0.0887,0.185174 -0.0577,0.074931 -0.14125,0.1145495 -0.0835,0.039619 -0.1912,0.039619 -0.093,0 -0.1714,-0.032728 -0.0784,-0.032729 -0.13522,-0.1024917 -0.0568,-0.070624 -0.0887,-0.1800063 -0.0319,-0.1093819 -0.0319,-0.2618275 0,-0.1386652 0.0301,-0.248047 0.031,-0.1093819 0.0887,-0.1843127 0.0577,-0.075792 0.14211,-0.11541081 0.0844,-0.0396186 0.1912,-0.0396186 0.093,0 0.1714,0.0327284 0.0784,0.0327284 0.13436,0.10249171 0.0568,0.069763 0.0887,0.179145 0.0319,0.1093819 0.0319,0.2626879 z m -0.66663,0.00345 q 0,0.017225 0,0.032728 0,0.014642 0.002,0.030145 l 0.42203,-0.3048912 q -0.0301,-0.085266 -0.0801,-0.125746 -0.0491,-0.041341 -0.11627,-0.041341 -0.0482,0 -0.0896,0.024977 -0.0413,0.024116 -0.0723,0.074931 -0.0301,0.050815 -0.0482,0.1274686 -0.0172,0.076653 -0.0172,0.1817289 z m 0.45475,0.00345 q 0,-0.014642 -8.6e-4,-0.029283 -8.6e-4,-0.015503 -8.6e-4,-0.029283 l -0.41944,0.3031686 q 0.0276,0.083544 0.0775,0.1240235 0.05,0.04048 0.11628,0.04048 0.0482,0 0.0896,-0.024977 0.0422,-0.024977 0.0723,-0.074931 0.031,-0.050815 0.0482,-0.1274686 0.0172,-0.077515 0.0172,-0.1817289 z"
style="stroke-width:0.264583"
id="path199-0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -0,0 +1,198 @@
solid OpenSCAD_Model
facet normal 0 0 -1
outer loop
vertex 56.25 -82.5 -3
vertex 82.5 82.5 -3
vertex 82.5 -82.5 -3
endloop
endfacet
facet normal 0 0 -1
outer loop
vertex -56.25 -82.5 -3
vertex 56.25 -82.5 -3
vertex 41.25 -97.5 -3
endloop
endfacet
facet normal 0 0 -1
outer loop
vertex -56.25 -82.5 -3
vertex 41.25 -97.5 -3
vertex -41.25 -97.5 -3
endloop
endfacet
facet normal 0 0 -1
outer loop
vertex 56.25 -82.5 -3
vertex -56.25 -82.5 -3
vertex 82.5 82.5 -3
endloop
endfacet
facet normal 0 0 -1
outer loop
vertex -82.5 82.5 -3
vertex -56.25 -82.5 -3
vertex -82.5 -82.5 -3
endloop
endfacet
facet normal 0 0 -1
outer loop
vertex -56.25 -82.5 -3
vertex -82.5 82.5 -3
vertex 82.5 82.5 -3
endloop
endfacet
facet normal -1 0 0
outer loop
vertex -82.5 -82.5 -3
vertex -82.5 82.5 0
vertex -82.5 82.5 -3
endloop
endfacet
facet normal -1 -0 0
outer loop
vertex -82.5 82.5 0
vertex -82.5 -82.5 -3
vertex -82.5 -82.5 0
endloop
endfacet
facet normal 0 0 1
outer loop
vertex 82.5 82.5 0
vertex 56.25 -82.5 0
vertex 82.5 -82.5 0
endloop
endfacet
facet normal 0 0 1
outer loop
vertex -56.25 -82.5 0
vertex 56.25 -82.5 0
vertex 82.5 82.5 0
endloop
endfacet
facet normal 0 0 1
outer loop
vertex 56.25 -82.5 0
vertex -56.25 -82.5 0
vertex 41.25 -97.5 0
endloop
endfacet
facet normal 0 0 1
outer loop
vertex 41.25 -97.5 0
vertex -56.25 -82.5 0
vertex -41.25 -97.5 0
endloop
endfacet
facet normal -0 0 1
outer loop
vertex -82.5 82.5 0
vertex -56.25 -82.5 0
vertex 82.5 82.5 0
endloop
endfacet
facet normal 0 0 1
outer loop
vertex -56.25 -82.5 0
vertex -82.5 82.5 0
vertex -82.5 -82.5 0
endloop
endfacet
facet normal 0 1 -0
outer loop
vertex 82.5 82.5 -3
vertex -82.5 82.5 0
vertex 82.5 82.5 0
endloop
endfacet
facet normal 0 1 0
outer loop
vertex -82.5 82.5 0
vertex 82.5 82.5 -3
vertex -82.5 82.5 -3
endloop
endfacet
facet normal 1 -0 0
outer loop
vertex 82.5 -82.5 0
vertex 82.5 82.5 -3
vertex 82.5 82.5 0
endloop
endfacet
facet normal 1 0 0
outer loop
vertex 82.5 82.5 -3
vertex 82.5 -82.5 0
vertex 82.5 -82.5 -3
endloop
endfacet
facet normal 0 -1 0
outer loop
vertex -82.5 -82.5 -3
vertex -56.25 -82.5 0
vertex -82.5 -82.5 0
endloop
endfacet
facet normal 0 -1 -0
outer loop
vertex -56.25 -82.5 0
vertex -82.5 -82.5 -3
vertex -56.25 -82.5 -3
endloop
endfacet
facet normal 0 -1 0
outer loop
vertex 56.25 -82.5 -3
vertex 82.5 -82.5 0
vertex 56.25 -82.5 0
endloop
endfacet
facet normal 0 -1 -0
outer loop
vertex 82.5 -82.5 0
vertex 56.25 -82.5 -3
vertex 82.5 -82.5 -3
endloop
endfacet
facet normal 0 -1 0
outer loop
vertex -41.25 -97.5 -3
vertex 41.25 -97.5 0
vertex -41.25 -97.5 0
endloop
endfacet
facet normal 0 -1 -0
outer loop
vertex 41.25 -97.5 0
vertex -41.25 -97.5 -3
vertex 41.25 -97.5 -3
endloop
endfacet
facet normal -0.707107 -0.707107 0
outer loop
vertex -41.25 -97.5 -3
vertex -56.25 -82.5 0
vertex -56.25 -82.5 -3
endloop
endfacet
facet normal -0.707107 -0.707107 0
outer loop
vertex -56.25 -82.5 0
vertex -41.25 -97.5 -3
vertex -41.25 -97.5 0
endloop
endfacet
facet normal 0.707107 -0.707107 0
outer loop
vertex 41.25 -97.5 0
vertex 56.25 -82.5 -3
vertex 56.25 -82.5 0
endloop
endfacet
facet normal 0.707107 -0.707107 0
outer loop
vertex 56.25 -82.5 -3
vertex 41.25 -97.5 0
vertex 41.25 -97.5 -3
endloop
endfacet
endsolid OpenSCAD_Model

View file

@ -35,7 +35,22 @@
#include "SVG.hpp"
#include <tbb/parallel_for.h>
#include <tbb/pipeline.h>
// Intel redesigned some TBB interface considerably when merging TBB with their oneAPI set of libraries, see GH #7332.
// We are using quite an old TBB 2017 U7. Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
#if ! defined(TBB_VERSION_MAJOR)
#include <tbb/version.h>
#endif
#if ! defined(TBB_VERSION_MAJOR)
static_assert(false, "TBB_VERSION_MAJOR not defined");
#endif
#if TBB_VERSION_MAJOR >= 2021
#include <tbb/parallel_pipeline.h>
using slic3r_tbb_filtermode = tbb::filter_mode;
#else
#include <tbb/pipeline.h>
using slic3r_tbb_filtermode = tbb::filter;
#endif
#include <Shiny/Shiny.h>
@ -1500,7 +1515,7 @@ void GCode::process_layers(
{
// The pipeline is variable: The vase mode filter is optional.
size_t layer_to_print_idx = 0;
const auto generator = tbb::make_filter<void, GCode::LayerResult>(tbb::filter::serial_in_order,
const auto generator = tbb::make_filter<void, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[this, &print, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> GCode::LayerResult {
if (layer_to_print_idx == layers_to_print.size()) {
fc.stop();
@ -1514,16 +1529,16 @@ void GCode::process_layers(
return this->process_layer(print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
}
});
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(tbb::filter::serial_in_order,
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in) -> GCode::LayerResult {
spiral_vase.enable(in.spiral_vase_enable);
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
});
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(tbb::filter::serial_in_order,
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto output = tbb::make_filter<std::string, void>(tbb::filter::serial_in_order,
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
);
@ -1546,7 +1561,7 @@ void GCode::process_layers(
{
// The pipeline is variable: The vase mode filter is optional.
size_t layer_to_print_idx = 0;
const auto generator = tbb::make_filter<void, GCode::LayerResult>(tbb::filter::serial_in_order,
const auto generator = tbb::make_filter<void, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
if (layer_to_print_idx == layers_to_print.size()) {
fc.stop();
@ -1557,16 +1572,16 @@ void GCode::process_layers(
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
}
});
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(tbb::filter::serial_in_order,
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(slic3r_tbb_filtermode::serial_in_order,
[&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in)->GCode::LayerResult {
spiral_vase.enable(in.spiral_vase_enable);
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
});
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(tbb::filter::serial_in_order,
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(slic3r_tbb_filtermode::serial_in_order,
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in)->std::string {
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
});
const auto output = tbb::make_filter<std::string, void>(tbb::filter::serial_in_order,
const auto output = tbb::make_filter<std::string, void>(slic3r_tbb_filtermode::serial_in_order,
[&output_stream](std::string s) { output_stream.write(s); }
);

View file

@ -498,7 +498,7 @@ Point SeamPlacer::calculate_seam(const Layer& layer, const SeamPosition seam_pos
else if (seam_position == spRear) {
// Object is centered around (0,0) in its current coordinate system.
last_pos.x() = 0;
last_pos.y() += coord_t(3. * po->bounding_box().radius());
last_pos.y() = coord_t(3. * po->bounding_box().radius());
last_pos_weight = 5.f;
} if (seam_position == spNearest) {
// last_pos already contains current nozzle position

View file

@ -92,6 +92,25 @@ void Layer::restore_untyped_slices()
}
}
// Similar to Layer::restore_untyped_slices()
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
// Only resetting layerm->slices if Slice::extra_perimeters is always zero or it will not be used anymore
// after the perimeter generator.
void Layer::restore_untyped_slices_no_extra_perimeters()
{
if (layer_needs_raw_backup(this)) {
for (LayerRegion *layerm : m_regions)
if (! layerm->region().config().extra_perimeters.value)
layerm->slices.set(layerm->raw_slices, stInternal);
} else {
assert(m_regions.size() == 1);
LayerRegion *layerm = m_regions.front();
// This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions.
//if (! layerm->region().config().extra_perimeters.value)
layerm->slices.set(this->lslices, stInternal);
}
}
ExPolygons Layer::merged(float offset_scaled) const
{
assert(offset_scaled >= 0.f);
@ -179,7 +198,7 @@ void Layer::make_perimeters()
// group slices (surfaces) according to number of extra perimeters
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
for (LayerRegion *layerm : layerms) {
for (Surface &surface : layerm->slices.surfaces)
for (const Surface &surface : layerm->slices.surfaces)
slices[surface.extra_perimeters].emplace_back(surface);
if (layerm->region().config().fill_density > layerm_config->region().config().fill_density)
layerm_config = layerm;

View file

@ -137,6 +137,8 @@ public:
//FIXME Review whether not to simplify the code by keeping the raw_slices all the time.
void backup_untyped_slices();
void restore_untyped_slices();
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
void restore_untyped_slices_no_extra_perimeters();
// Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices.
ExPolygons merged(float offset) const;
template <class T> bool any_internal_region_slice_contains(const T &item) const {

View file

@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
// so we're safe. This guarantees idempotence of prepare_infill() also in case
// that combine_infill() turns some fill_surface into VOID surfaces.
// Collect polygons per surface type.
std::vector<SurfacesPtr> by_surface;
by_surface.assign(size_t(stCount), SurfacesPtr());
std::array<SurfacesPtr, size_t(stCount)> by_surface;
for (Surface &surface : this->slices.surfaces)
by_surface[size_t(surface.surface_type)].emplace_back(&surface);
// Trim surfaces by the fill_boundaries.

View file

@ -1210,6 +1210,7 @@ void PrintConfigDef::init_fff_params()
def->tooltip = L("When printing with very low layer heights, you might still want to print a thicker "
"bottom layer to improve adhesion and tolerance for non perfect build plates.");
def->sidetext = L("mm");
def->min = 0;
def->ratio_over = "layer_height";
def->set_default_value(new ConfigOptionFloatOrPercent(0.35, false));
@ -1404,10 +1405,10 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("10");
def->enum_values.push_back("1000");
def->enum_labels.push_back(L("0 (no open anchors)"));
def->enum_labels.push_back("1 mm");
def->enum_labels.push_back("2 mm");
def->enum_labels.push_back("5 mm");
def->enum_labels.push_back("10 mm");
def->enum_labels.push_back(L("1 mm"));
def->enum_labels.push_back(L("2 mm"));
def->enum_labels.push_back(L("5 mm"));
def->enum_labels.push_back(L("10 mm"));
def->enum_labels.push_back(L("1000 (unlimited)"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(600, true));
@ -1427,10 +1428,10 @@ void PrintConfigDef::init_fff_params()
def->gui_type = def_infill_anchor_min->gui_type;
def->enum_values = def_infill_anchor_min->enum_values;
def->enum_labels.push_back(L("0 (not anchored)"));
def->enum_labels.push_back("1 mm");
def->enum_labels.push_back("2 mm");
def->enum_labels.push_back("5 mm");
def->enum_labels.push_back("10 mm");
def->enum_labels.push_back(L("1 mm"));
def->enum_labels.push_back(L("2 mm"));
def->enum_labels.push_back(L("5 mm"));
def->enum_labels.push_back(L("10 mm"));
def->enum_labels.push_back(L("1000 (unlimited)"));
def->mode = def_infill_anchor_min->mode;
def->set_default_value(new ConfigOptionFloatOrPercent(50, false));
@ -2565,9 +2566,10 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("0");
def->enum_values.push_back("0.1");
def->enum_values.push_back("0.2");
def->enum_labels.push_back(L("same as top"));
def->enum_labels.push_back(L("0.1"));
def->enum_labels.push_back(L("0.2"));
//TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible
def->enum_labels.push_back(L("Same as top"));
def->enum_labels.push_back("0.1");
def->enum_labels.push_back("0.2");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
@ -2649,7 +2651,8 @@ void PrintConfigDef::init_fff_params()
def->min = -1;
def->enum_values.push_back("-1");
append(def->enum_values, support_material_interface_layers->enum_values);
def->enum_labels.push_back(L("same as top"));
//TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible
def->enum_labels.push_back(L("Same as top"));
append(def->enum_labels, support_material_interface_layers->enum_labels);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInt(-1));
@ -3772,7 +3775,7 @@ void PrintConfigDef::init_sla_params()
def->enum_labels.push_back(L("Slow"));
def->enum_labels.push_back(L("Fast"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<SLAMaterialSpeed>(slamsSlow));
def->set_default_value(new ConfigOptionEnum<SLAMaterialSpeed>(slamsFast));
}
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)

View file

@ -6,6 +6,7 @@
#include "Geometry.hpp"
#include "I18N.hpp"
#include "Layer.hpp"
#include "MutablePolygon.hpp"
#include "SupportMaterial.hpp"
#include "Surface.hpp"
#include "Slicing.hpp"
@ -226,6 +227,17 @@ void PrintObject::prepare_infill()
m_print->set_status(30, L("Preparing infill"));
if (m_typed_slices) {
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
// The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells()
// with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe
// to reset to the untyped slices before re-runnning detect_surfaces_type().
for (Layer* layer : m_layers) {
layer->restore_untyped_slices_no_extra_perimeters();
m_print->throw_if_canceled();
}
}
// This will assign a type (top/bottom/internal) to $layerm->slices.
// Then the classifcation of $layerm->slices is transfered onto
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
@ -1709,9 +1721,6 @@ void PrintObject::clip_fill_surfaces()
Layer *layer = m_layers[layer_id];
Layer *lower_layer = m_layers[layer_id - 1];
// Detect things that we need to support.
// Cummulative slices.
Polygons slices;
polygons_append(slices, layer->lslices);
// Cummulative fill surfaces.
Polygons fill_surfaces;
// Solid surfaces to be supported.
@ -1736,7 +1745,7 @@ void PrintObject::clip_fill_surfaces()
{
// Get perimeters area as the difference between slices and fill_surfaces
// Only consider the area that is not supported by lower perimeters
Polygons perimeters = intersection(diff(slices, fill_surfaces), lower_layer_fill_surfaces);
Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces);
// Only consider perimeter areas that are at least one extrusion width thick.
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
//Should the pw not be half of the current value?
@ -1746,9 +1755,15 @@ void PrintObject::clip_fill_surfaces()
// Append such thick perimeters to the areas that need support
polygons_append(overhangs, opening(perimeters, pw));
}
// Find new internal infill.
polygons_append(overhangs, std::move(upper_internal));
upper_internal = intersection(overhangs, lower_layer_internal_surfaces);
// Merge the new overhangs, find new internal infill.
polygons_append(upper_internal, std::move(overhangs));
static constexpr const auto closing_radius = scaled<float>(2.f);
upper_internal = intersection(
// Regularize the overhang regions, so that the infill areas will not become excessively jagged.
smooth_outward(
closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.),
scaled<coord_t>(0.1)),
lower_layer_internal_surfaces);
// Apply new internal infill to regions.
for (LayerRegion *layerm : lower_layer->m_regions) {
if (layerm->region().config().fill_density.value == 0)
@ -1785,7 +1800,7 @@ void PrintObject::discover_horizontal_shells()
if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 &&
(i % region_config.solid_infill_every_layers) == 0) {
// Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge.
SurfaceType type = (region_config.fill_density == 100) ? stInternalSolid : stInternalBridge;
SurfaceType type = (region_config.fill_density == 100 || region_config.solid_infill_every_layers == 1) ? stInternalSolid : stInternalBridge;
for (Surface &surface : layerm->fill_surfaces.surfaces)
if (surface.surface_type == stInternal)
surface.surface_type = type;

View file

@ -1340,7 +1340,10 @@ namespace SupportMaterialInternal {
// so we take the largest value and also apply safety offset to be ensure no gaps
// are left in between
Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter);
float w = float(std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing()));
//FIXME one may want to use a maximum of bridging flow width and normal flow width, as the perimeters are calculated using the normal flow
// and then turned to bridging flow, thus their centerlines are derived from non-bridging flow and expanding them by a bridging flow
// may not expand them to the edge of their respective islands.
const float w = float(0.5 * std::max(perimeter_bridge_flow.scaled_width(), perimeter_bridge_flow.scaled_spacing())) + scaled<float>(0.001);
for (Polyline &polyline : overhang_perimeters)
if (polyline.is_straight()) {
// This is a bridge
@ -1355,7 +1358,7 @@ namespace SupportMaterialInternal {
supported[j] = true;
if (supported[0] && supported[1])
// Offset a polyline into a thick line.
polygons_append(bridges, offset(polyline, 0.5f * w + 10.f));
polygons_append(bridges, offset(polyline, w));
}
bridges = union_(bridges);
}
@ -3044,7 +3047,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
raft = diff(expand(raft, step), trimming);
} else
raft = diff(raft, trimming);
if (contacts != nullptr)
if (! interface_polygons.empty())
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
}
if (! brim.empty()) {

View file

@ -358,8 +358,9 @@ void TriangleSelector::precompute_all_neighbors_recursive(const int facet_idx, c
assert(tr->children[i] < int(m_triangles.size()));
// Recursion, deep first search over the children of this triangle.
// All children of this triangle were created by splitting a single source triangle of the original mesh.
this->precompute_all_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i),
this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out,
const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
this->precompute_all_neighbors_recursive(tr->children[i], child_neighbors,
this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), neighbors_out,
neighbors_propagated_out);
}
}
@ -784,33 +785,29 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo
// Return neighbors of the ith child of a triangle given neighbors of the triangle.
// If such a neighbor doesn't exist, return the neighbor from the previous depth.
Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const
Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors_propagated, int child_idx, const Vec3i &child_neighbors) const
{
int i = tr.special_side();
int j = next_idx_modulo(i, 3);
int k = next_idx_modulo(j, 3);
Vec3i out;
auto replace_if_not_exists = [&out](int index_to_replace, int neighbor) {
Vec3i out = child_neighbors;
auto replace_if_not_exists = [&out, &neighbors_propagated](int index_to_replace, int neighbor_idx) {
if (out(index_to_replace) == -1)
out(index_to_replace) = neighbor;
out(index_to_replace) = neighbors_propagated(neighbor_idx);
};
switch (tr.number_of_split_sides()) {
case 1:
switch (child_idx) {
case 0:
out(0) = neighbors(i);
out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second);
replace_if_not_exists(1, neighbors(j));
out(2) = tr.children[1];
replace_if_not_exists(0, i);
replace_if_not_exists(1, j);
break;
default:
assert(child_idx == 1);
out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First);
replace_if_not_exists(0, neighbors(j));
out(1) = neighbors(k);
out(2) = tr.children[0];
replace_if_not_exists(0, j);
replace_if_not_exists(1, k);
break;
}
break;
@ -818,25 +815,17 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec
case 2:
switch (child_idx) {
case 0:
out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second);
replace_if_not_exists(0, neighbors(i));
out(1) = tr.children[1];
out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First);
replace_if_not_exists(2, neighbors(k));
replace_if_not_exists(0, i);
replace_if_not_exists(2, k);
break;
case 1:
assert(child_idx == 1);
out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First);
replace_if_not_exists(0, neighbors(i));
out(1) = tr.children[2];
out(2) = tr.children[0];
replace_if_not_exists(0, i);
break;
default:
assert(child_idx == 2);
out(0) = neighbors(j);
out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second);
replace_if_not_exists(1, neighbors(k));
out(2) = tr.children[1];
replace_if_not_exists(0, j);
replace_if_not_exists(1, k);
break;
}
break;
@ -845,31 +834,19 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec
assert(tr.special_side() == 0);
switch (child_idx) {
case 0:
out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second);
replace_if_not_exists(0, neighbors(0));
out(1) = tr.children[3];
out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First);
replace_if_not_exists(2, neighbors(2));
replace_if_not_exists(0, 0);
replace_if_not_exists(2, 2);
break;
case 1:
out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First);
replace_if_not_exists(0, neighbors(0));
out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second);
replace_if_not_exists(1, neighbors(1));
out(2) = tr.children[3];
replace_if_not_exists(0, 0);
replace_if_not_exists(1, 1);
break;
case 2:
out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First);
replace_if_not_exists(0, neighbors(1));
out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second);
replace_if_not_exists(1, neighbors(2));
out(2) = tr.children[3];
replace_if_not_exists(0, 1);
replace_if_not_exists(1, 2);
break;
default:
assert(child_idx == 3);
out(0) = tr.children[1];
out(1) = tr.children[2];
out(2) = tr.children[0];
break;
}
break;
@ -1527,7 +1504,9 @@ void TriangleSelector::get_seed_fill_contour_recursive(const int facet_idx, cons
assert(tr->children[i] < int(m_triangles.size()));
// Recursion, deep first search over the children of this triangle.
// All children of this triangle were created by splitting a single source triangle of the original mesh.
this->get_seed_fill_contour_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), edges_out);
const Vec3i child_neighbors = this->child_neighbors(*tr, neighbors, i);
this->get_seed_fill_contour_recursive(tr->children[i], child_neighbors,
this->child_neighbors_propagated(*tr, neighbors_propagated, i, child_neighbors), edges_out);
}
}
} else if (tr->is_selected_by_seed_fill()) {

View file

@ -349,7 +349,7 @@ private:
int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0});
void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state);
Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const;
Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const;
Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors_propagated, int child_idx, const Vec3i &child_neighbors) const;
// Return child of itriangle at a CCW oriented side (vertexi, vertexj), either first or 2nd part.
// If itriangle == -1 or if the side sharing (vertexi, vertexj) is not split, return -1.
enum class Partition {

View file

@ -47,6 +47,16 @@
// We are using quite an old TBB 2017 U7, which does not support global control API officially.
// Before we update our build servers, let's use the old API, which is deprecated in up to date TBB.
#include <tbb/tbb.h>
#if ! defined(TBB_VERSION_MAJOR)
#include <tbb/version.h>
#endif
#if ! defined(TBB_VERSION_MAJOR)
static_assert(false, "TBB_VERSION_MAJOR not defined");
#endif
#if TBB_VERSION_MAJOR >= 2021
#define TBB_HAS_GLOBAL_CONTROL
#endif
#ifdef TBB_HAS_GLOBAL_CONTROL
#include <tbb/global_control.h>
#else

View file

@ -109,7 +109,7 @@ wxString BedShape::get_full_name_with_params()
default:
// rectangle, convex, concave...
out += "\n" + _(get_option_label(Parameter::RectSize)) + ": [" + ConfigOptionPoint(to_2d(m_build_volume.bounding_volume().size())).serialize() + "]";
out += "\n" + _(get_option_label(Parameter::RectOrigin)) + ": [" + ConfigOptionPoint(to_2d(m_build_volume.bounding_volume().min)).serialize() + "]";
out += "\n" + _(get_option_label(Parameter::RectOrigin)) + ": [" + ConfigOptionPoint(- to_2d(m_build_volume.bounding_volume().min)).serialize() + "]";
break;
}
return out;
@ -124,7 +124,7 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
default:
// rectangle, convex, concave...
optgroup->set_value("rect_size" , new ConfigOptionPoints{ to_2d(m_build_volume.bounding_volume().size()) });
optgroup->set_value("rect_origin" , new ConfigOptionPoints{ to_2d(m_build_volume.bounding_volume().min) });
optgroup->set_value("rect_origin" , new ConfigOptionPoints{ - to_2d(m_build_volume.bounding_volume().min) });
}
}

View file

@ -254,8 +254,8 @@ void BitmapComboBox::DrawBackground_(wxDC& dc, const wxRect& rect, int WXUNUSED(
dc.SetTextForeground(flags & ODCB_PAINTING_DISABLED ? wxColour(108,108,108) : wxGetApp().get_label_clr_default());
wxColour selCol = flags & ODCB_PAINTING_DISABLED ?
#ifdef _MSW_DAEK_MODE
wxRGBToColour(NppDarkMode::InvertLightnessSofter(NppDarkMode::GetBackgroundColor())) :
#ifdef _MSW_DARK_MODE
wxRGBToColour(NppDarkMode::GetSofterBackgroundColor()) :
#else
wxGetApp().get_highlight_default_clr() :
#endif

View file

@ -47,8 +47,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->opt_float("layer_height") < EPSILON)
{
const wxString msg_text = _(L("Layer height is not valid.\n\nThe layer height will be reset to 0.01."));
//wxMessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
MessageDialog dialog(nullptr, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@ -60,8 +59,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
if (config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value < EPSILON)
{
const wxString msg_text = _(L("First layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
//wxMessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
MessageDialog dialog(nullptr, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
is_msg_dlg_already_exist = true;
dialog.ShowModal();
@ -90,8 +88,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"- Detect thin walls disabled"));
if (is_global_config)
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable Spiral Vase?"));
//wxMessageDialog dialog(nullptr, msg_text, _(L("Spiral Vase")),
MessageDialog dialog(nullptr, msg_text, _(L("Spiral Vase")),
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Spiral Vase")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@ -126,8 +123,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"(both support_material_extruder and support_material_interface_extruder need to be set to 0)."));
if (is_global_config)
msg_text += "\n\n" + _(L("Shall I adjust those settings in order to enable the Wipe Tower?"));
//wxMessageDialog dialog (nullptr, msg_text, _(L("Wipe Tower")),
MessageDialog dialog (nullptr, msg_text, _(L("Wipe Tower")),
MessageDialog dialog (m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@ -147,8 +143,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"need to be synchronized with the object layers."));
if (is_global_config)
msg_text += "\n\n" + _(L("Shall I synchronize support layers in order to enable the Wipe Tower?"));
//wxMessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")),
MessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")),
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Wipe Tower")),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@ -169,7 +164,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
"- Detect bridging perimeters"));
if (is_global_config)
msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?"));
MessageDialog dialog(nullptr, msg_text, _L("Support Generator"), wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Support Generator"), wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK));
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
if (!is_global_config || answer == wxID_YES) {
@ -200,8 +195,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
_(fill_pattern_def->enum_labels[it_pattern - fill_pattern_def->enum_values.begin()]));
if (is_global_config)
msg_text += "\n\n" + _L("Shall I switch to rectilinear fill pattern?");
//wxMessageDialog dialog(nullptr, msg_text, _L("Infill"),
MessageDialog dialog(nullptr, msg_text, _L("Infill"),
MessageDialog dialog(m_msg_dlg_parent, msg_text, _L("Infill"),
wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) );
DynamicPrintConfig new_conf = *config;
auto answer = dialog.ShowModal();
@ -331,8 +325,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
if (head_penetration > head_width) {
wxString msg_text = _(L("Head penetration should not be greater than the head width."));
//wxMessageDialog dialog(nullptr, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
MessageDialog dialog(nullptr, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
if (dialog.ShowModal() == wxID_OK) {
new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width));
@ -345,8 +338,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
if (pinhead_d > pillar_d) {
wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter."));
//wxMessageDialog dialog(nullptr, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
MessageDialog dialog(nullptr, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
MessageDialog dialog(m_msg_dlg_parent, msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
DynamicPrintConfig new_conf = *config;
if (dialog.ShowModal() == wxID_OK) {

View file

@ -30,15 +30,18 @@ class ConfigManipulation
// callback to propagation of changed value, if needed
std::function<void(const std::string&, const boost::any&)> cb_value_change = nullptr;
ModelConfig* local_config = nullptr;
wxWindow* m_msg_dlg_parent {nullptr};
public:
ConfigManipulation(std::function<void()> load_config,
std::function<void(const std::string&, bool toggle, int opt_index)> cb_toggle_field,
std::function<void(const std::string&, const boost::any&)> cb_value_change,
ModelConfig* local_config = nullptr) :
ModelConfig* local_config = nullptr,
wxWindow* msg_dlg_parent = nullptr) :
load_config(load_config),
cb_toggle_field(cb_toggle_field),
cb_value_change(cb_value_change),
m_msg_dlg_parent(msg_dlg_parent),
local_config(local_config) {}
ConfigManipulation() {}

View file

@ -627,7 +627,7 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin
list_printer->SetMinSize(wxSize(23*em, list_h));
list_type->SetMinSize(wxSize(8*em, list_h));
list_type->SetMinSize(wxSize(13*em, list_h));
list_vendor->SetMinSize(wxSize(13*em, list_h));
list_profile->SetMinSize(wxSize(23*em, list_h));

View file

@ -1,6 +1,5 @@
#include "libslic3r/libslic3r.h"
#include "DoubleSlider.hpp"
#include "DoubleSlider_Utils.hpp"
#include "libslic3r/GCode.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
@ -27,7 +26,6 @@
#include <cmath>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <random>
#include "Field.hpp"
#include "format.hpp"
#include "NotificationManager.hpp"
@ -2562,7 +2560,7 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) {
#if 1
if (ticks.empty())
return get_opposite_color((*m_colors)[0]);
return color_generator.get_opposite_color((*m_colors)[0]);
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick);
if (before_tick_it == ticks.end())
@ -2571,24 +2569,24 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
if (--before_tick_it; before_tick_it->type == ColorChange)
break;
if (before_tick_it->type == ColorChange)
return get_opposite_color(before_tick_it->color);
return get_opposite_color((*m_colors)[0]);
return color_generator.get_opposite_color(before_tick_it->color);
return color_generator.get_opposite_color((*m_colors)[0]);
}
if (before_tick_it == ticks.begin())
{
const std::string& frst_color = (*m_colors)[0];
if (before_tick_it->type == ColorChange)
return get_opposite_color(frst_color, before_tick_it->color);
return color_generator.get_opposite_color(frst_color, before_tick_it->color);
auto next_tick_it = before_tick_it;
while (next_tick_it != ticks.end())
if (++next_tick_it; next_tick_it->type == ColorChange)
break;
if (next_tick_it->type == ColorChange)
return get_opposite_color(frst_color, next_tick_it->color);
return color_generator.get_opposite_color(frst_color, next_tick_it->color);
return get_opposite_color(frst_color);
return color_generator.get_opposite_color(frst_color);
}
std::string frst_color = "";
@ -2609,13 +2607,13 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
if (before_tick_it->type == ColorChange) {
if (frst_color.empty())
return get_opposite_color(before_tick_it->color);
return get_opposite_color(before_tick_it->color, frst_color);
return color_generator.get_opposite_color(before_tick_it->color);
return color_generator.get_opposite_color(before_tick_it->color, frst_color);
}
if (frst_color.empty())
return get_opposite_color((*m_colors)[0]);
return get_opposite_color((*m_colors)[0], frst_color);
return color_generator.get_opposite_color((*m_colors)[0]);
return color_generator.get_opposite_color((*m_colors)[0], frst_color);
#else
const std::vector<std::string>& colors = ColorPrintColors::get();
if (ticks.empty())

View file

@ -3,6 +3,7 @@
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
#include "DoubleSlider_Utils.hpp"
#include <wx/window.h>
#include <wx/control.h>
@ -118,6 +119,7 @@ class TickCodeInfo
// int m_default_color_idx = 0;
std::vector<std::string>* m_colors {nullptr};
ColorGenerator color_generator;
std::string get_color_for_tick(TickCode tick, Type type, const int extruder);

View file

@ -1,173 +1,191 @@
#include <stdio.h>
#include <random>
#include "wx/colour.h"
// next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
typedef struct {
double r; // a fraction between 0 and 1
double g; // a fraction between 0 and 1
double b; // a fraction between 0 and 1
} rgb;
typedef struct {
double h; // angle in degrees
double s; // a fraction between 0 and 1
double v; // a fraction between 0 and 1
} hsv;
static hsv rgb2hsv(rgb in);
static rgb hsv2rgb(hsv in);
hsv rgb2hsv(rgb in)
class ColorGenerator
{
hsv out;
double min, max, delta;
// Some of next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
typedef struct {
double r; // a fraction between 0 and 1
double g; // a fraction between 0 and 1
double b; // a fraction between 0 and 1
} rgb;
min = in.r < in.g ? in.r : in.g;
min = min < in.b ? min : in.b;
typedef struct {
double h; // angle in degrees
double s; // a fraction between 0 and 1
double v; // a fraction between 0 and 1
} hsv;
max = in.r > in.g ? in.r : in.g;
max = max > in.b ? max : in.b;
//static hsv rgb2hsv(rgb in);
//static rgb hsv2rgb(hsv in);
out.v = max; // v
delta = max - min;
if (delta < 0.00001)
hsv rgb2hsv(rgb in)
{
out.s = 0;
out.h = 0; // undefined, maybe nan?
hsv out;
double min, max, delta;
min = in.r < in.g ? in.r : in.g;
min = min < in.b ? min : in.b;
max = in.r > in.g ? in.r : in.g;
max = max > in.b ? max : in.b;
out.v = max; // v
delta = max - min;
if (delta < 0.00001)
{
out.s = 0;
out.h = 0; // undefined, maybe nan?
return out;
}
if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash
out.s = (delta / max); // s
}
else {
// if max is 0, then r = g = b = 0
// s = 0, h is undefined
out.s = 0.0;
out.h = NAN; // its now undefined
return out;
}
if (in.r >= max) // > is bogus, just keeps compilor happy
out.h = (in.g - in.b) / delta; // between yellow & magenta
else
if (in.g >= max)
out.h = 2.0 + (in.b - in.r) / delta; // between cyan & yellow
else
out.h = 4.0 + (in.r - in.g) / delta; // between magenta & cyan
out.h *= 60.0; // degrees
if (out.h < 0.0)
out.h += 360.0;
return out;
}
if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash
out.s = (delta / max); // s
} else {
// if max is 0, then r = g = b = 0
// s = 0, h is undefined
out.s = 0.0;
out.h = NAN; // its now undefined
hsv rgb2hsv(const std::string& str_clr_in)
{
wxColour clr(str_clr_in);
rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 };
return rgb2hsv(in);
}
rgb hsv2rgb(hsv in)
{
double hh, p, q, t, ff;
long i;
rgb out;
if (in.s <= 0.0) { // < is bogus, just shuts up warnings
out.r = in.v;
out.g = in.v;
out.b = in.v;
return out;
}
hh = in.h;
if (hh >= 360.0) hh -= 360.0;//hh = 0.0;
hh /= 60.0;
i = (long)hh;
ff = hh - i;
p = in.v * (1.0 - in.s);
q = in.v * (1.0 - (in.s * ff));
t = in.v * (1.0 - (in.s * (1.0 - ff)));
switch (i) {
case 0:
out.r = in.v;
out.g = t;
out.b = p;
break;
case 1:
out.r = q;
out.g = in.v;
out.b = p;
break;
case 2:
out.r = p;
out.g = in.v;
out.b = t;
break;
case 3:
out.r = p;
out.g = q;
out.b = in.v;
break;
case 4:
out.r = t;
out.g = p;
out.b = in.v;
break;
case 5:
default:
out.r = in.v;
out.g = p;
out.b = q;
break;
}
return out;
}
if( in.r >= max ) // > is bogus, just keeps compilor happy
out.h = ( in.g - in.b ) / delta; // between yellow & magenta
else
if( in.g >= max )
out.h = 2.0 + ( in.b - in.r ) / delta; // between cyan & yellow
else
out.h = 4.0 + ( in.r - in.g ) / delta; // between magenta & cyan
out.h *= 60.0; // degrees
std::random_device rd;
if( out.h < 0.0 )
out.h += 360.0;
public:
return out;
}
ColorGenerator() {}
~ColorGenerator() {}
hsv rgb2hsv(const std::string& str_clr_in)
{
wxColour clr(str_clr_in);
rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 };
return rgb2hsv(in);
}
double rand_val()
{
std::mt19937 rand_generator(rd());
rgb hsv2rgb(hsv in)
{
double hh, p, q, t, ff;
long i;
rgb out;
if(in.s <= 0.0) { // < is bogus, just shuts up warnings
out.r = in.v;
out.g = in.v;
out.b = in.v;
return out;
// this value will be used for Saturation and Value
// to avoid extremely light/dark colors, take this value from range [0.65; 1.0]
std::uniform_real_distribution<double> distrib(0.65, 1.0);
return distrib(rand_generator);
}
hh = in.h;
if (hh >= 360.0) hh -= 360.0;//hh = 0.0;
hh /= 60.0;
i = (long)hh;
ff = hh - i;
p = in.v * (1.0 - in.s);
q = in.v * (1.0 - (in.s * ff));
t = in.v * (1.0 - (in.s * (1.0 - ff)));
switch(i) {
case 0:
out.r = in.v;
out.g = t;
out.b = p;
break;
case 1:
out.r = q;
out.g = in.v;
out.b = p;
break;
case 2:
out.r = p;
out.g = in.v;
out.b = t;
break;
case 3:
out.r = p;
out.g = q;
out.b = in.v;
break;
case 4:
out.r = t;
out.g = p;
out.b = in.v;
break;
case 5:
default:
out.r = in.v;
out.g = p;
out.b = q;
break;
std::string get_opposite_color(const std::string& color)
{
std::string opp_color = "";
hsv hsv_clr = rgb2hsv(color);
hsv_clr.h += 65; // 65 instead 60 to avoid circle values
hsv_clr.s = rand_val();
hsv_clr.v = rand_val();
rgb rgb_opp_color = hsv2rgb(hsv_clr);
wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
opp_color = clr_str.ToStdString();
return opp_color;
}
return out;
}
double rand_val()
{
return 0.1 * (10 - rand() % 8);
}
std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd)
{
std::string opp_color = "";
std::string get_opposite_color(const std::string& color)
{
std::string opp_color = "";
hsv hsv_frst = rgb2hsv(color_frst);
hsv hsv_scnd = rgb2hsv(color_scnd);
hsv hsv_clr = rgb2hsv(color);
hsv_clr.h += 65; // 65 instead 60 to avoid circle values
hsv_clr.s = rand_val();
hsv_clr.v = rand_val();
double delta_h = fabs(hsv_frst.h - hsv_scnd.h);
double start_h = delta_h > 180 ? std::min<double>(hsv_scnd.h, hsv_frst.h) : std::max<double>(hsv_scnd.h, hsv_frst.h);
start_h += 5; // to avoid circle change of colors for 120 deg
if (delta_h < 180)
delta_h = 360 - delta_h;
rgb rgb_opp_color = hsv2rgb(hsv_clr);
hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() };
rgb rgb_opp_color = hsv2rgb(hsv_opp);
wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
opp_color = clr_str.ToStdString();
wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
opp_color = clr_str.ToStdString();
return opp_color;
}
std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd)
{
std::string opp_color = "";
hsv hsv_frst = rgb2hsv(color_frst);
hsv hsv_scnd = rgb2hsv(color_scnd);
double delta_h = fabs(hsv_frst.h - hsv_scnd.h);
double start_h = delta_h > 180 ? std::min<double>(hsv_scnd.h, hsv_frst.h) : std::max<double>(hsv_scnd.h, hsv_frst.h);
start_h += 5; // to avoid circle change of colors for 120 deg
if (delta_h < 180)
delta_h = 360 - delta_h;
hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() };
rgb rgb_opp_color = hsv2rgb(hsv_opp);
wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
opp_color = clr_str.ToStdString();
return opp_color;
}
return opp_color;
}
};

View file

@ -161,7 +161,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
intervals_box_sizer->Add(m_intervals_grid_sizer, 0, wxLEFT, em);
option_sizer->Add(intervals_box_sizer, 0, wxEXPAND);
m_random_sequence = new wxCheckBox(this, wxID_ANY, "Random sequence");
m_random_sequence = new wxCheckBox(this, wxID_ANY, _L("Random sequence"));
m_random_sequence->SetValue(m_sequence.random_sequence);
m_random_sequence->SetToolTip(_L("If enabled, random sequence of the selected extruders will be used."));
m_random_sequence->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {
@ -169,7 +169,7 @@ ExtruderSequenceDialog::ExtruderSequenceDialog(const DoubleSlider::ExtrudersSequ
m_color_repetition->Enable(m_sequence.random_sequence);
});
m_color_repetition = new wxCheckBox(this, wxID_ANY, "Allow next color repetition");
m_color_repetition = new wxCheckBox(this, wxID_ANY, _L("Allow next color repetition"));
m_color_repetition->SetValue(m_sequence.color_repetition);
m_color_repetition->SetToolTip(_L("If enabled, a repetition of the next random color will be allowed."));
m_color_repetition->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& e) {m_sequence.color_repetition = e.IsChecked(); });

View file

@ -291,6 +291,16 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
case coString:
case coStrings:
case coFloatOrPercent: {
if (m_opt.type == coFloatOrPercent && m_opt.opt_key == "first_layer_height" && !str.IsEmpty() && str.Last() == '%') {
// Workaroud to avoid of using of the % for first layer height
// see https://github.com/prusa3d/PrusaSlicer/issues/7418
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str()));
const wxString stVal = double_to_string(0.01, 2);
set_value(stVal, true);
m_value = into_u8(stVal);;
break;
}
if (m_opt.type == coFloatOrPercent && !str.IsEmpty() && str.Last() != '%')
{
double val = 0.;

View file

@ -581,14 +581,14 @@ void GCodeViewer::init()
case EMoveType::Retract:
case EMoveType::Unretract:
case EMoveType::Seam: {
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
buffer.shader = "gouraud_light_instanced";
buffer.model.model.init_from(diamond(16));
buffer.model.color = option_color(type);
buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
}
else {
// if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
// buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
// buffer.shader = "gouraud_light_instanced";
// buffer.model.model.init_from(diamond(16));
// buffer.model.color = option_color(type);
// buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
// }
// else {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel;
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
buffer.shader = "gouraud_light";
@ -596,7 +596,7 @@ void GCodeViewer::init()
buffer.model.data = diamond(16);
buffer.model.color = option_color(type);
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
}
// }
break;
}
case EMoveType::Wipe:
@ -977,8 +977,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
for (const RenderPath& path : t_buffer.render_paths) {
colors.push_back(path.color);
}
std::sort(colors.begin(), colors.end());
colors.erase(std::unique(colors.begin(), colors.end()), colors.end());
sort_remove_duplicates(colors);
// save materials file
boost::filesystem::path mat_filename(filename);
@ -1447,7 +1446,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
static const unsigned int progress_threshold = 1000;
wxProgressDialog* progress_dialog = wxGetApp().is_gcode_viewer() ?
new wxProgressDialog(_L("Generating toolpaths"), "...",
100, wxGetApp().plater(), wxPD_AUTO_HIDE | wxPD_APP_MODAL) : nullptr;
100, wxGetApp().mainframe, wxPD_AUTO_HIDE | wxPD_APP_MODAL) : nullptr;
wxBusyCursor busy;
@ -2020,13 +2019,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
// roles -> remove duplicates
std::sort(m_roles.begin(), m_roles.end());
m_roles.erase(std::unique(m_roles.begin(), m_roles.end()), m_roles.end());
sort_remove_duplicates(m_roles);
m_roles.shrink_to_fit();
// extruder ids -> remove duplicates
std::sort(m_extruder_ids.begin(), m_extruder_ids.end());
m_extruder_ids.erase(std::unique(m_extruder_ids.begin(), m_extruder_ids.end()), m_extruder_ids.end());
sort_remove_duplicates(m_extruder_ids);
m_extruder_ids.shrink_to_fit();
// set layers z range
@ -2374,8 +2371,10 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
}
RenderPath key{ tbuffer_id, color, static_cast<unsigned int>(ibuffer_id), path_id };
if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key))
render_path = const_cast<RenderPath*>(&(*buffer.render_paths.emplace(key).first));
if (render_path == nullptr || !RenderPathPropertyEqual()(*render_path, key)) {
buffer.render_paths.emplace_back(key);
render_path = const_cast<RenderPath*>(&buffer.render_paths.back());
}
unsigned int delta_1st = 0;
if (sub_path.first.s_id < m_sequential_view.current.first && m_sequential_view.current.first <= sub_path.last.s_id)
@ -2433,6 +2432,14 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif
}
// Removes empty render paths and sort.
for (size_t b = 0; b < m_buffers.size(); ++b) {
TBuffer* buffer = const_cast<TBuffer*>(&m_buffers[b]);
buffer->render_paths.erase(std::remove_if(buffer->render_paths.begin(), buffer->render_paths.end(),
[](const auto &path){ return path.sizes.empty() || path.offsets.empty(); }),
buffer->render_paths.end());
}
// second pass: for buffers using instanced and batched models, update the instances render ranges
for (size_t b = 0; b < m_buffers.size(); ++b) {
TBuffer& buffer = const_cast<TBuffer&>(m_buffers[b]);
@ -2624,12 +2631,7 @@ void GCodeViewer::render_toolpaths()
float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast<float>(viewport[3]) / (2.0f * static_cast<float>(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) :
static_cast<float>(viewport[3]) * 0.0005;
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_points = [this, zoom, point_size, near_plane_height]
#else
auto render_as_points = [zoom, point_size, near_plane_height]
#endif // ENABLE_GCODE_VIEWER_STATISTICS
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) {
#if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS
shader.set_uniform("use_fixed_screen_size", 1);
#else
@ -2640,65 +2642,76 @@ void GCodeViewer::render_toolpaths()
shader.set_uniform("percent_center_radius", 0.33f);
shader.set_uniform("point_size", point_size);
shader.set_uniform("near_plane_height", near_plane_height);
};
auto render_as_points = [
#if ENABLE_GCODE_VIEWER_STATISTICS
this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE));
glsafe(::glEnable(GL_POINT_SPRITE));
for (const RenderPath& path : buffer.render_paths) {
if (path.ibuffer_id == ibuffer_id) {
shader.set_uniform("uniform_color", path.color);
glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
const RenderPath& path = *it;
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_points_calls_count;
++m_statistics.gl_multi_points_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
}
glsafe(::glDisable(GL_POINT_SPRITE));
glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE));
};
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_lines = [this, light_intensity]
#else
auto render_as_lines = [light_intensity]
#endif // ENABLE_GCODE_VIEWER_STATISTICS
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
auto shader_init_as_lines = [light_intensity](GLShaderProgram &shader) {
shader.set_uniform("light_intensity", light_intensity);
for (const RenderPath& path : buffer.render_paths) {
if (path.ibuffer_id == ibuffer_id) {
shader.set_uniform("uniform_color", path.color);
glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
};
auto render_as_lines = [
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_lines_calls_count;
this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
const RenderPath& path = *it;
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_lines_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
}
};
auto render_as_triangles = [
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_triangles = [this]
#else
auto render_as_triangles = []
this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
(const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) {
for (const RenderPath& path : buffer.render_paths) {
if (path.ibuffer_id == ibuffer_id) {
shader.set_uniform("uniform_color", path.color);
glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
](std::vector<RenderPath>::iterator it_path, std::vector<RenderPath>::iterator it_end, GLShaderProgram& shader, int uniform_color) {
for (auto it = it_path; it != it_end && it_path->ibuffer_id == it->ibuffer_id; ++it) {
const RenderPath& path = *it;
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
glsafe(::glUniform4fv(uniform_color, 1, static_cast<const GLfloat*>(path.color.data())));
glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_triangles_calls_count;
++m_statistics.gl_multi_triangles_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
}
};
auto render_as_instanced_model = [
#if ENABLE_GCODE_VIEWER_STATISTICS
auto render_as_instanced_model = [this]
#else
auto render_as_instanced_model = []
this
#endif // ENABLE_GCODE_VIEWER_STATISTICS
(TBuffer& buffer, GLShaderProgram & shader) {
](TBuffer& buffer, GLShaderProgram & shader) {
for (auto& range : buffer.model.instances.render_ranges.ranges) {
if (range.vbo == 0 && range.count > 0) {
glsafe(::glGenBuffers(1, &range.vbo));
@ -2803,8 +2816,20 @@ void GCodeViewer::render_toolpaths()
shader->set_uniform("emission_factor", 0.0f);
}
else {
for (size_t j = 0; j < buffer.indices.size(); ++j) {
const IBuffer& i_buffer = buffer.indices[j];
switch (buffer.render_primitive_type) {
case TBuffer::ERenderPrimitiveType::Point: shader_init_as_points(*shader); break;
case TBuffer::ERenderPrimitiveType::Line: shader_init_as_lines(*shader); break;
default: break;
}
int uniform_color = shader->get_uniform_location("uniform_color");
auto it_path = buffer.render_paths.begin();
for (unsigned int ibuffer_id = 0; ibuffer_id < static_cast<unsigned int>(buffer.indices.size()); ++ibuffer_id) {
const IBuffer& i_buffer = buffer.indices[ibuffer_id];
// Skip all paths with ibuffer_id < ibuffer_id.
for (; it_path != buffer.render_paths.end() && it_path->ibuffer_id < ibuffer_id; ++ it_path) ;
if (it_path == buffer.render_paths.end() || it_path->ibuffer_id > ibuffer_id)
// Not found. This shall not happen.
continue;
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo));
glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes()));
@ -2817,19 +2842,20 @@ void GCodeViewer::render_toolpaths()
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
// Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors.
switch (buffer.render_primitive_type)
{
case TBuffer::ERenderPrimitiveType::Point: {
render_as_points(buffer, static_cast<unsigned int>(j), *shader);
render_as_points(it_path, buffer.render_paths.end(), *shader, uniform_color);
break;
}
case TBuffer::ERenderPrimitiveType::Line: {
glsafe(::glLineWidth(static_cast<GLfloat>(line_width(zoom))));
render_as_lines(buffer, static_cast<unsigned int>(j), *shader);
render_as_lines(it_path, buffer.render_paths.end(), *shader, uniform_color);
break;
}
case TBuffer::ERenderPrimitiveType::Triangle: {
render_as_triangles(buffer, static_cast<unsigned int>(j), *shader);
render_as_triangles(it_path, buffer.render_paths.end(), *shader, uniform_color);
break;
}
default: { break; }

View file

@ -259,14 +259,6 @@ class GCodeViewer
return false;
}
};
// // for unordered_set implementation of render_paths
// struct RenderPathPropertyHash {
// size_t operator() (const RenderPath &p) const {
// // Convert the RGB value to an integer hash.
//// return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.ibuffer_id);
// return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.ibuffer_id);
// }
// };
struct RenderPathPropertyLower {
bool operator() (const RenderPath &l, const RenderPath &r) const {
if (l.tbuffer_id < r.tbuffer_id)
@ -319,9 +311,7 @@ class GCodeViewer
std::string shader;
std::vector<Path> paths;
// std::set seems to perform significantly better, at least on Windows.
// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
std::set<RenderPath, RenderPathPropertyLower> render_paths;
std::vector<RenderPath> render_paths;
bool visible{ false };
void reset();

View file

@ -2761,7 +2761,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
// if the event is not allowed to be passed further.
// https://github.com/prusa3d/PrusaSlicer/issues/2750
evt.Skip();
// evt.Skip() used to trigger the needed screen refresh, but it does no more. wxWakeUpIdle() seem to work now.
wxWakeUpIdle();
#endif /* __WXMSW__ */
// Performs layers editing updates, if enabled

View file

@ -358,12 +358,38 @@ bool GLShaderProgram::set_uniform(const char* name, const Vec3d& value) const
int GLShaderProgram::get_attrib_location(const char* name) const
{
return (m_id > 0) ? ::glGetAttribLocation(m_id, name) : -1;
assert(m_id > 0);
if (m_id <= 0)
// Shader program not loaded. This should not happen.
return -1;
auto it = std::find_if(m_attrib_location_cache.begin(), m_attrib_location_cache.end(), [name](const auto& p) { return p.first == name; });
if (it != m_attrib_location_cache.end())
// Attrib ID cached.
return it->second;
int id = ::glGetAttribLocation(m_id, name);
const_cast<GLShaderProgram*>(this)->m_attrib_location_cache.push_back({ name, id });
return id;
}
int GLShaderProgram::get_uniform_location(const char* name) const
{
return (m_id > 0) ? ::glGetUniformLocation(m_id, name) : -1;
assert(m_id > 0);
if (m_id <= 0)
// Shader program not loaded. This should not happen.
return -1;
auto it = std::find_if(m_uniform_location_cache.begin(), m_uniform_location_cache.end(), [name](const auto &p) { return p.first == name; });
if (it != m_uniform_location_cache.end())
// Uniform ID cached.
return it->second;
int id = ::glGetUniformLocation(m_id, name);
const_cast<GLShaderProgram*>(this)->m_uniform_location_cache.push_back({ name, id });
return id;
}
} // namespace Slic3r

View file

@ -29,6 +29,8 @@ public:
private:
std::string m_name;
unsigned int m_id{ 0 };
std::vector<std::pair<std::string, int>> m_attrib_location_cache;
std::vector<std::pair<std::string, int>> m_uniform_location_cache;
public:
~GLShaderProgram();

View file

@ -352,7 +352,7 @@ void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_su
add_config_substitutions(substitution.substitutions, changes);
}
InfoDialog msg(nullptr, _L("Configuration bundle was loaded, however some configuration values were not recognized."), substitution_message(changes));
InfoDialog msg(nullptr, _L("Configuration bundle was loaded, however some configuration values were not recognized."), substitution_message(changes), true);
msg.ShowModal();
}
@ -363,7 +363,7 @@ void show_substitutions_info(const ConfigSubstitutions& config_substitutions, co
InfoDialog msg(nullptr,
format_wxstr(_L("Configuration file \"%1%\" was loaded, however some configuration values were not recognized."), from_u8(filename)),
substitution_message(changes));
substitution_message(changes), true);
msg.ShowModal();
}

View file

@ -883,6 +883,8 @@ void GUI_App::init_app_config()
dir = wxFileName::GetHomeDir() + wxS("/.config");
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
#endif
} else {
m_datadir_redefined = true;
}
if (!app_config)
@ -915,6 +917,10 @@ void GUI_App::init_app_config()
// returns true if found newer version and user agreed to use it
bool GUI_App::check_older_app_config(Semver current_version, bool backup)
{
// If the config folder is redefined - do not check
if (m_datadir_redefined)
return false;
// find other version app config (alpha / beta / release)
std::string config_path = app_config->config_path();
boost::filesystem::path parent_file_path(config_path);
@ -942,26 +948,34 @@ bool GUI_App::check_older_app_config(Semver current_version, bool backup)
return false;
BOOST_LOG_TRIVIAL(info) << "last app config file used: " << m_older_data_dir_path;
// ask about using older data folder
RichMessageDialog msg(nullptr, backup ?
wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
"\nIts version is %s."
"\nLast version you used in current configuration folder is %s."
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
"\nWould you like to copy found configuration to your current configuration folder?"
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one. Overwriting any existing file with matching name."
"\nIf you select no, you will continue with current configuration.")
, m_older_data_dir_path, last_semver.to_string(), current_version.to_string())
: wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
"\nIts version is %s."
"\nThere is no configuration file in current configuration folder."
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
"\nWould you like to copy found configuration to your current configuration folder?"
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one."
"\nIf you select no, you will start with clean installation with configuration wizard.")
, m_older_data_dir_path, last_semver.to_string())
, _L("PrusaSlicer"), /*wxICON_QUESTION | */wxYES_NO);
// See GH issue #7469.
wxInitAllImageHandlers();
InfoDialog msg(nullptr
, format_wxstr(_L("You are opening %1% version %2%."), SLIC3R_APP_NAME, SLIC3R_VERSION)
, backup ?
format_wxstr(_L(
"The active configuration was created by <b>%1% %2%</b>,"
"\nwhile a newer configuration was found in <b>%3%</b>"
"\ncreated by <b>%1% %4%</b>."
"\n\nShall the newer configuration be imported?"
"\nIf so, your active configuration will be backed up before importing the new configuration."
)
, SLIC3R_APP_NAME, current_version.to_string(), m_older_data_dir_path, last_semver.to_string())
: format_wxstr(_L(
"An existing configuration was found in <b>%3%</b>"
"\ncreated by <b>%1% %2%</b>."
"\n\nShall this configuration be imported?"
)
, SLIC3R_APP_NAME, last_semver.to_string(), m_older_data_dir_path)
, true, wxYES_NO);
if (backup) {
msg.SetButtonLabel(wxID_YES, _L("Import"));
msg.SetButtonLabel(wxID_NO, _L("Don't import"));
}
if (msg.ShowModal() == wxID_YES) {
std::string snapshot_id;
if (backup) {
@ -2156,9 +2170,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
local_menu->Append(config_id_base + ConfigMenuLanguage, _L("&Language"));
if (is_editor()) {
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _L("Flash printer &firmware"), _L("Upload a firmware image into an Arduino based printer"));
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _L("Flash Printer &Firmware"), _L("Upload a firmware image into an Arduino based printer"));
// TODO: for when we're able to flash dictionaries
// local_menu->Append(config_id_base + FirmwareMenuDict, _L("Flash language file"), _L("Upload a language dictionary file into a Prusa printer"));
// local_menu->Append(config_id_base + FirmwareMenuDict, _L("Flash Language File"), _L("Upload a language dictionary file into a Prusa printer"));
}
local_menu->Bind(wxEVT_MENU, [this, config_id_base](wxEvent &event) {

View file

@ -353,6 +353,7 @@ private:
void check_updates(const bool verbose);
bool m_init_app_config_from_older { false };
bool m_datadir_redefined { false };
std::string m_older_data_dir_path;
boost::optional<Semver> m_last_config_version;
};

View file

@ -350,7 +350,8 @@ void ObjectList::get_selection_indexes(std::vector<int>& obj_idxs, std::vector<i
{
wxDataViewItemArray sels;
GetSelections(sels);
assert(!sels.IsEmpty());
if (sels.IsEmpty())
return;
if ( m_objects_model->GetItemType(sels[0]) & itVolume ||
(sels.Count()==1 && m_objects_model->GetItemType(m_objects_model->GetParent(sels[0])) & itVolume) ) {
@ -425,7 +426,7 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol
if (!stats.manifold()) {
remaining_info = format_wxstr(_L_PLURAL("%1$d open edge", "%1$d open edges", stats.open_edges), stats.open_edges);
tooltip += _L("Remaning errors") + ":\n";
tooltip += _L("Remaining errors") + ":\n";
tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d open edge", "%1$d open edges", stats.open_edges), stats.open_edges) + "\n";
}
@ -1461,7 +1462,7 @@ void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>&
else
wxGetApp().import_model(parent, input_files);
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().plater(), wxPD_AUTO_HIDE);
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().mainframe wxPD_AUTO_HIDE);
wxBusyCursor busy;
for (size_t i = 0; i < input_files.size(); ++i) {
@ -1521,7 +1522,7 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
else
wxGetApp().import_model(parent, input_files);
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().plater(), wxPD_AUTO_HIDE);
wxProgressDialog dlg(_L("Loading") + dots, "", 100, wxGetApp().mainframe, wxPD_AUTO_HIDE);
wxBusyCursor busy;
const int obj_idx = get_selected_obj_idx();
@ -1571,7 +1572,7 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
for (auto object : model.objects) {
if (model_object.origin_translation != Vec3d::Zero()) {
object->center_around_origin();
Vec3d delta = model_object.origin_translation - object->origin_translation;
const Vec3d delta = model_object.origin_translation - object->origin_translation;
for (auto volume : object->volumes) {
volume->translate(delta);
}
@ -1585,6 +1586,12 @@ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolum
new_volume->name = boost::filesystem::path(input_file).filename().string();
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
// update source data
new_volume->source.input_file = input_file;
new_volume->source.object_idx = obj_idx;
new_volume->source.volume_idx = int(model_object.volumes.size()) - 1;
if (model.objects.size() == 1 && model.objects.front()->volumes.size() == 1)
new_volume->source.mesh_offset = model.objects.front()->volumes.front()->source.mesh_offset;
if (from_galery) {
// Transform the new modifier to be aligned with the print bed.
@ -4140,7 +4147,7 @@ void ObjectList::fix_through_netfabb()
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
// Open a progress dialog.
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, plater,
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, find_toplevel_parent(plater),
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
int model_idx{ 0 };
if (vol_idxs.empty()) {

View file

@ -110,12 +110,6 @@ bool ObjectSettings::update_settings_list()
update_settings_list();
m_parent->Layout();
});
/* Check overriden options list after deleting.
* Some options couldn't be deleted because of another one.
* Like, we couldn't delete fill pattern, if fill density is set to 100%
*/
update_config_values(config);
});
return btn;
};
@ -227,11 +221,12 @@ void ObjectSettings::update_config_values(ModelConfig* config)
update_config_values(config);
if (is_added) {
wxTheApp->CallAfter([this]() {
// #ysFIXME - Delete after testing! Very likely this CallAfret is no needed
// wxTheApp->CallAfter([this]() {
wxWindowUpdateLocker noUpdates(m_parent);
update_settings_list();
m_parent->Layout();
});
// });
}
};
@ -253,9 +248,9 @@ void ObjectSettings::update_config_values(ModelConfig* config)
{
const int obj_idx = objects_model->GetObjectIdByItem(item);
assert(obj_idx >= 0);
// for object's part first of all update konfiguration from object
main_config.apply(wxGetApp().model().objects[obj_idx]->config.get(), true);
printer_technology == ptFFF ? config_manipulation.update_print_fff_config(&main_config) :
config_manipulation.update_print_sla_config(&main_config) ;
// and then from its own config
}
main_config.apply(config->get(), true);

View file

@ -550,24 +550,24 @@ RENDER_AGAIN:
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
ImGui::PushItemWidth(window_width - settings_sliders_left);
m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm");
if (ImGui::IsItemHovered())
if (m_imgui->get_last_slider_status().hovered)
m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width);
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider
bool slider_released =m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
if (current_mode >= quality_mode) {
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("quality"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f");
if (ImGui::IsItemHovered())
if (m_imgui->get_last_slider_status().hovered)
m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width);
slider_clicked |= ImGui::IsItemClicked();
slider_edited |= ImGui::IsItemEdited();
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
}
if (current_mode >= closing_d_mode) {
@ -575,12 +575,12 @@ RENDER_AGAIN:
m_imgui->text(m_desc.at("closing_distance"));
ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x);
m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
if (ImGui::IsItemHovered())
if (m_imgui->get_last_slider_status().hovered)
m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width);
slider_clicked |= ImGui::IsItemClicked();
slider_edited |= ImGui::IsItemEdited();
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
}
if (slider_clicked) {
@ -627,9 +627,9 @@ RENDER_AGAIN:
//complete non-sense.
diam = std::clamp(diam, 0.1f, diameter_upper_cap);
m_new_hole_radius = diam / 2.f;
bool clicked = ImGui::IsItemClicked();
bool edited = ImGui::IsItemEdited();
bool deactivated = ImGui::IsItemDeactivatedAfterEdit();
bool clicked = m_imgui->get_last_slider_status().clicked;
bool edited = m_imgui->get_last_slider_status().edited;
bool deactivated = m_imgui->get_last_slider_status().deactivated_after_edit;
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc["hole_depth"]);
@ -638,9 +638,9 @@ RENDER_AGAIN:
// Same as above:
m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f);
clicked |= ImGui::IsItemClicked();
edited |= ImGui::IsItemEdited();
deactivated |= ImGui::IsItemDeactivatedAfterEdit();
clicked |= m_imgui->get_last_slider_status().clicked;
edited |= m_imgui->get_last_slider_status().edited;
deactivated |= m_imgui->get_last_slider_status().deactivated_after_edit;;
// Following is a nasty way to:
// - save the initial value of the slider before one starts messing with it

View file

@ -245,7 +245,7 @@ std::vector<std::vector<GLGizmoPainterBase::ProjectedMousePosition>> GLGizmoPain
const Camera &camera = wxGetApp().plater()->get_camera();
std::vector<ProjectedMousePosition> mesh_hit_points;
mesh_hit_points.reserve(mouse_position.size());
mesh_hit_points.reserve(mouse_positions.size());
// In mesh_hit_points only the last item could have mesh_id == -1, any other items mustn't.
for (const Vec2d &mp : mouse_positions) {
@ -859,9 +859,9 @@ void GLPaintContour::finalize_geometry()
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->m_contour_EBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
this->contour_indices.clear();
}
}

View file

@ -687,16 +687,16 @@ RENDER_AGAIN:
// - take correct undo/redo snapshot after the user is done with moving the slider
float initial_value = m_new_point_head_diameter;
m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
if (ImGui::IsItemClicked()) {
if (m_imgui->get_last_slider_status().clicked) {
if (m_old_point_head_diameter == 0.f)
m_old_point_head_diameter = initial_value;
}
if (ImGui::IsItemEdited()) {
if (m_imgui->get_last_slider_status().edited) {
for (auto& cache_entry : m_editing_cache)
if (cache_entry.selected)
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
if (m_imgui->get_last_slider_status().deactivated_after_edit) {
// momentarily restore the old value to take snapshot
for (auto& cache_entry : m_editing_cache)
if (cache_entry.selected)
@ -747,18 +747,18 @@ RENDER_AGAIN:
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm");
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider
bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider
bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("points_density"));
ImGui::SameLine(settings_sliders_left);
m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%");
slider_clicked |= ImGui::IsItemClicked();
slider_edited |= ImGui::IsItemEdited();
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
slider_clicked |= m_imgui->get_last_slider_status().clicked;
slider_edited |= m_imgui->get_last_slider_status().edited;
slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit;
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
m_minimal_point_distance_stash = minimal_point_distance;

View file

@ -509,6 +509,12 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float
str_label = str_label.substr(0, pos) + str_label.substr(pos + 2);
bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power);
m_last_slider_status.hovered = ImGui::IsItemHovered();
m_last_slider_status.edited = ImGui::IsItemEdited();
m_last_slider_status.clicked = ImGui::IsItemClicked();
m_last_slider_status.deactivated_after_edit = ImGui::IsItemDeactivatedAfterEdit();
if (!tooltip.empty() && ImGui::IsItemHovered())
this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width);

View file

@ -40,6 +40,13 @@ class ImGuiWrapper
std::string m_clipboard_text;
public:
struct LastSliderStatus {
bool hovered { false };
bool edited { false };
bool clicked { false };
bool deactivated_after_edit { false };
};
ImGuiWrapper();
~ImGuiWrapper();
@ -63,6 +70,7 @@ public:
ImVec2 get_item_spacing() const;
float get_slider_float_height() const;
const LastSliderStatus& get_last_slider_status() const { return m_last_slider_status; }
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
void set_next_window_bg_alpha(float alpha);
@ -171,6 +179,8 @@ private:
static const char* clipboard_get(void* user_data);
static void clipboard_set(void* user_data, const char* text);
LastSliderStatus m_last_slider_status;
};

View file

@ -1094,7 +1094,7 @@ static wxMenu* generate_help_menu()
else
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&About %s"), GCODEVIEWER_APP_NAME), _L("Show about dialog"),
[](wxCommandEvent&) { Slic3r::GUI::about(); });
append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the day"), _L("Opens Tip of the day notification in bottom right corner or shows another tip if already opened."),
append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the Day"), _L("Opens Tip of the day notification in bottom right corner or shows another tip if already opened."),
[](wxCommandEvent&) { wxGetApp().plater()->get_notification_manager()->push_hint_notification(false); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _L("Keyboard Shortcuts") + sep + "&?", _L("Show the list of the keyboard shortcuts"),
@ -1188,9 +1188,9 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { save_project(); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save(); }, this);
#ifdef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Save project &as") + dots + "\tCtrl+Shift+S", _L("Save current project file as"),
append_menu_item(fileMenu, wxID_ANY, _L("Save Project &as") + dots + "\tCtrl+Shift+S", _L("Save current project file as"),
#else
append_menu_item(fileMenu, wxID_ANY, _L("Save project &as") + dots + "\tCtrl+Alt+S", _L("Save current project file as"),
append_menu_item(fileMenu, wxID_ANY, _L("Save Project &as") + dots + "\tCtrl+Alt+S", _L("Save current project file as"),
#endif // __APPLE__
[this](wxCommandEvent&) { save_project_as(); }, "save", nullptr,
[this](){return m_plater != nullptr && can_save_as(); }, this);
@ -1202,11 +1202,11 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
append_menu_item(import_menu, wxID_ANY, _L("Import STL (imperial units)"), _L("Load an model saved with imperial units"),
append_menu_item(import_menu, wxID_ANY, _L("Import STL (Imperial Units)"), _L("Load an model saved with imperial units"),
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(true); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S archive") + dots, _L("Load an SL1 / Sl1S archive"),
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S Archive") + dots, _L("Load an SL1 / Sl1S archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr && !m_plater->is_any_job_running(); }, this);
@ -1214,7 +1214,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(import_menu, wxID_ANY, _L("Import &Config") + dots + "\tCtrl+L", _L("Load exported configuration file"),
[this](wxCommandEvent&) { load_config_file(); }, "import_config", nullptr,
[]() {return true; }, this);
append_menu_item(import_menu, wxID_ANY, _L("Import Config from &project") + dots +"\tCtrl+Alt+L", _L("Load configuration from project file"),
append_menu_item(import_menu, wxID_ANY, _L("Import Config from &Project") + dots +"\tCtrl+Alt+L", _L("Load configuration from project file"),
[this](wxCommandEvent&) { if (m_plater) m_plater->extract_config_from_project(); }, "import_config", nullptr,
[]() {return true; }, this);
import_menu->AppendSeparator();
@ -1232,22 +1232,22 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, "export_gcode", nullptr,
[this](){return can_send_gcode(); }, this);
m_changeable_menu_items.push_back(item_send_gcode);
append_menu_item(export_menu, wxID_ANY, _L("Export G-code to SD card / Flash drive") + dots + "\tCtrl+U", _L("Export current plate as G-code to SD card / Flash drive"),
append_menu_item(export_menu, wxID_ANY, _L("Export G-code to SD Card / Flash Drive") + dots + "\tCtrl+U", _L("Export current plate as G-code to SD card / Flash drive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(true); }, "export_to_sd", nullptr,
[this]() {return can_export_gcode_sd(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _L("Export plate as &STL") + dots, _L("Export current plate as STL"),
append_menu_item(export_menu, wxID_ANY, _L("Export Plate as &STL") + dots, _L("Export current plate as STL"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "export_plater", nullptr,
[this](){return can_export_model(); }, this);
append_menu_item(export_menu, wxID_ANY, _L("Export plate as STL &including supports") + dots, _L("Export current plate as STL including supports"),
append_menu_item(export_menu, wxID_ANY, _L("Export Plate as STL &Including Supports") + dots, _L("Export current plate as STL including supports"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(true); }, "export_plater", nullptr,
[this](){return can_export_supports(); }, this);
// Deprecating AMF export. Let's wait for user feedback.
// append_menu_item(export_menu, wxID_ANY, _L("Export plate as &AMF") + dots, _L("Export current plate as AMF"),
// append_menu_item(export_menu, wxID_ANY, _L("Export Plate as &AMF") + dots, _L("Export current plate as AMF"),
// [this](wxCommandEvent&) { if (m_plater) m_plater->export_amf(); }, "export_plater", nullptr,
// [this](){return can_export_model(); }, this);
export_menu->AppendSeparator();
append_menu_item(export_menu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
append_menu_item(export_menu, wxID_ANY, _L("Export &Toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[this]() {return can_export_toolpaths(); }, this);
export_menu->AppendSeparator();
@ -1262,7 +1262,7 @@ void MainFrame::init_menubar_as_editor()
[]() {return true; }, this);
append_submenu(fileMenu, export_menu, wxID_ANY, _L("&Export"), "");
append_menu_item(fileMenu, wxID_ANY, _L("Ejec&t SD card / Flash drive") + dots + "\tCtrl+T", _L("Eject SD card / Flash drive after the G-code was exported to it."),
append_menu_item(fileMenu, wxID_ANY, _L("Ejec&t SD Card / Flash Drive") + dots + "\tCtrl+T", _L("Eject SD card / Flash drive after the G-code was exported to it."),
[this](wxCommandEvent&) { if (m_plater) m_plater->eject_drive(); }, "eject_sd", nullptr,
[this]() {return can_eject(); }, this);
@ -1298,7 +1298,7 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { repair_stl(); }, "wrench", nullptr,
[]() { return true; }, this);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_ANY, _L("&G-code preview") + dots, _L("Open G-code viewer"),
append_menu_item(fileMenu, wxID_ANY, _L("&G-code Preview") + dots, _L("Open G-code viewer"),
[this](wxCommandEvent&) { start_new_gcodeviewer_open_file(this); }, "", nullptr);
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_EXIT, _L("&Quit"), wxString::Format(_L("Quit %s"), SLIC3R_APP_NAME),
@ -1316,17 +1316,17 @@ void MainFrame::init_menubar_as_editor()
#else
wxString hotkey_delete = "Del";
#endif
append_menu_item(editMenu, wxID_ANY, _L("&Select all") + sep + GUI::shortkey_ctrl_prefix() + sep_space + "A",
append_menu_item(editMenu, wxID_ANY, _L("&Select All") + sep + GUI::shortkey_ctrl_prefix() + sep_space + "A",
_L("Selects all objects"), [this](wxCommandEvent&) { m_plater->select_all(); },
"", nullptr, [this](){return can_select(); }, this);
append_menu_item(editMenu, wxID_ANY, _L("D&eselect all") + sep + "Esc",
append_menu_item(editMenu, wxID_ANY, _L("D&eselect All") + sep + "Esc",
_L("Deselects all objects"), [this](wxCommandEvent&) { m_plater->deselect_all(); },
"", nullptr, [this](){return can_deselect(); }, this);
editMenu->AppendSeparator();
append_menu_item(editMenu, wxID_ANY, _L("&Delete selected") + sep + hotkey_delete,
append_menu_item(editMenu, wxID_ANY, _L("&Delete Selected") + sep + hotkey_delete,
_L("Deletes the current selection"),[this](wxCommandEvent&) { m_plater->remove_selected(); },
"remove_menu", nullptr, [this](){return can_delete(); }, this);
append_menu_item(editMenu, wxID_ANY, _L("Delete &all") + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete,
append_menu_item(editMenu, wxID_ANY, _L("Delete &All") + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete,
_L("Deletes all objects"), [this](wxCommandEvent&) { m_plater->reset_with_confirm(); },
"delete_all_menu", nullptr, [this](){return can_delete_all(); }, this);
@ -1348,11 +1348,11 @@ void MainFrame::init_menubar_as_editor()
editMenu->AppendSeparator();
#ifdef __APPLE__
append_menu_item(editMenu, wxID_ANY, _L("Re&load from disk") + dots + "\tCtrl+Shift+R",
append_menu_item(editMenu, wxID_ANY, _L("Re&load from Disk") + dots + "\tCtrl+Shift+R",
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); },
"", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this);
#else
append_menu_item(editMenu, wxID_ANY, _L("Re&load from disk") + sep + "F5",
append_menu_item(editMenu, wxID_ANY, _L("Re&load from Disk") + sep + "F5",
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); },
"", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this);
#endif // __APPLE__
@ -1410,11 +1410,11 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "upload_queue", nullptr, []() {return true; }, this);
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, _L("Open new instance") + "\tCtrl+Shift+I", _L("Open a new PrusaSlicer instance"),
append_menu_item(windowMenu, wxID_ANY, _L("Open New Instance") + "\tCtrl+Shift+I", _L("Open a new PrusaSlicer instance"),
[](wxCommandEvent&) { start_new_slicer(); }, "", nullptr, [this]() {return m_plater != nullptr && wxGetApp().app_config->get("single_instance") != "1"; }, this);
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, _L("Compare presets")/* + "\tCtrl+F"*/, _L("Compare presets"),
append_menu_item(windowMenu, wxID_ANY, _L("Compare Presets")/* + "\tCtrl+F"*/, _L("Compare presets"),
[this](wxCommandEvent&) { diff_dialog.show();}, "compare", nullptr, []() {return true; }, this);
}
@ -1424,15 +1424,15 @@ void MainFrame::init_menubar_as_editor()
viewMenu = new wxMenu();
add_common_view_menu_items(viewMenu, this, std::bind(&MainFrame::can_change_view, this));
viewMenu->AppendSeparator();
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &labels") + sep + "E", _L("Show object/instance labels in 3D scene"),
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Labels") + sep + "E", _L("Show object/instance labels in 3D scene"),
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse sidebar") + sep + "Shift+" + sep_space + "Tab", _L("Collapse sidebar"),
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse Sidebar") + sep + "Shift+" + sep_space + "Tab", _L("Collapse sidebar"),
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
#ifndef __APPLE__
// OSX adds its own menu item to toggle fullscreen.
append_menu_check_item(viewMenu, wxID_ANY, _L("&Full screen") + "\t" + "F11", _L("Full screen"),
append_menu_check_item(viewMenu, wxID_ANY, _L("&Fullscreen") + "\t" + "F11", _L("Fullscreen"),
[this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen(),
// wxFULLSCREEN_ALL: wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION
wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION); },
@ -1519,16 +1519,16 @@ void MainFrame::init_menubar_as_gcodeviewer()
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->load_gcode(); }, "open", nullptr,
[this]() {return m_plater != nullptr; }, this);
#ifdef __APPLE__
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from disk") + dots + "\tCtrl+Shift+R",
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from Disk") + dots + "\tCtrl+Shift+R",
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
#else
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from disk") + sep + "F5",
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from Disk") + sep + "F5",
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
#endif // __APPLE__
fileMenu->AppendSeparator();
append_menu_item(fileMenu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
append_menu_item(fileMenu, wxID_ANY, _L("Export &Toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
[this]() {return can_export_toolpaths(); }, this);
append_menu_item(fileMenu, wxID_ANY, _L("Open &PrusaSlicer") + dots, _L("Open PrusaSlicer"),

View file

@ -202,7 +202,7 @@ public:
SettingsDialog m_settings_dialog;
DiffPresetDialog diff_dialog;
wxWindow* m_plater_page{ nullptr };
wxProgressDialog* m_progress_dialog { nullptr };
// wxProgressDialog* m_progress_dialog { nullptr };
PrintHostQueueDialog* m_printhost_queue_dlg;
// std::shared_ptr<ProgressStatusBar> m_statusbar;

View file

@ -63,6 +63,15 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
SetSizerAndFit(main_sizer);
}
void MsgDialog::SetButtonLabel(wxWindowID btn_id, const wxString& label, bool set_focus/* = false*/)
{
if (wxButton* btn = get_button(btn_id)) {
btn->SetLabel(label);
if (set_focus)
btn->SetFocus();
}
}
wxButton* MsgDialog::add_button(wxWindowID btn_id, bool set_focus /*= false*/, const wxString& label/* = wxString()*/)
{
wxButton* btn = new wxButton(this, btn_id, label);
@ -98,7 +107,7 @@ void MsgDialog::finalize()
// Text shown as HTML, so that mouse selection and Ctrl-V to copy will work.
static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxString msg, bool monospaced_font = false)
static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxString msg, bool monospaced_font = false, bool is_marked_msg = false)
{
wxHtmlWindow* html = new wxHtmlWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
@ -154,7 +163,7 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
}
html->SetMinSize(page_size);
std::string msg_escaped = xml_escape(msg.ToUTF8().data());
std::string msg_escaped = xml_escape(msg.ToUTF8().data(), is_marked_msg);
boost::replace_all(msg_escaped, "\r\n", "<br>");
boost::replace_all(msg_escaped, "\n", "<br>");
if (monospaced_font)
@ -242,11 +251,11 @@ int RichMessageDialog::ShowModal()
// InfoDialog
InfoDialog::InfoDialog(wxWindow* parent, const wxString &title, const wxString& msg)
: MsgDialog(parent, wxString::Format(_L("%s information"), SLIC3R_APP_NAME), title, wxOK | wxICON_INFORMATION)
InfoDialog::InfoDialog(wxWindow* parent, const wxString &title, const wxString& msg, bool is_marked_msg/* = false*/, long style/* = wxOK | wxICON_INFORMATION*/)
: MsgDialog(parent, wxString::Format(_L("%s information"), SLIC3R_APP_NAME), title, style)
, msg(msg)
{
add_msg_content(this, content_sizer, msg);
add_msg_content(this, content_sizer, msg, false, is_marked_msg);
finalize();
}

View file

@ -30,7 +30,7 @@ struct MsgDialog : wxDialog
MsgDialog &operator=(const MsgDialog &) = delete;
virtual ~MsgDialog() = default;
// TODO: refactor with CreateStdDialogButtonSizer usage
void SetButtonLabel(wxWindowID btn_id, const wxString& label, bool set_focus = false);
protected:
enum {
@ -111,6 +111,7 @@ public:
class MessageDialog : public MsgDialog
{
public:
// NOTE! Don't change a signature of contsrucor. It have to be tha same as for wxMessageDialog
MessageDialog( wxWindow *parent,
const wxString& message,
const wxString& caption = wxEmptyString,
@ -130,6 +131,7 @@ class RichMessageDialog : public MsgDialog
bool m_checkBoxValue{ false };
public:
// NOTE! Don't change a signature of contsrucor. It have to be tha same as for wxRichMessageDialog
RichMessageDialog( wxWindow *parent,
const wxString& message,
const wxString& caption = wxEmptyString,
@ -293,7 +295,9 @@ public:
const wxString& message,
const wxString& caption = wxEmptyString,
long style = wxOK)
: wxRichMessageDialog(parent, message, caption, style) {}
: wxRichMessageDialog(parent, message, caption, style) {
this->SetEscapeId(wxID_CANCEL);
}
~RichMessageDialog() {}
};
#endif
@ -302,7 +306,7 @@ public:
class InfoDialog : public MsgDialog
{
public:
InfoDialog(wxWindow *parent, const wxString &title, const wxString &msg);
InfoDialog(wxWindow *parent, const wxString &title, const wxString &msg, bool is_marked = false, long style = wxOK| wxICON_INFORMATION);
InfoDialog(InfoDialog&&) = delete;
InfoDialog(const InfoDialog&) = delete;
InfoDialog&operator=(InfoDialog&&) = delete;

View file

@ -79,7 +79,6 @@ void OG_CustomCtrl::init_ctrl_lines()
// if we have a single option with no label, no sidetext just add it directly to sizer
if (option_set.size() == 1 && opt_group->label_width == 0 && option_set.front().opt.full_width &&
option_set.front().opt.label.empty() &&
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
line.get_extra_widgets().size() == 0)
{
@ -157,7 +156,6 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
// If we have a single option with no sidetext
const std::vector<Option>& option_set = line.get_options();
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
option_set.front().opt.label.empty() &&
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0)
{
h_pos += 3 * blinking_button_width;
@ -167,13 +165,14 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/)
break;
}
bool is_multioption_line = option_set.size() > 1;
for (auto opt : option_set) {
Field* field = opt_group->get_field(opt.opt_id);
correct_line_height(ctrl_line.height, field->getWindow());
ConfigOptionDef option = opt.opt;
// add label if any
if (!option.label.empty()) {
if (is_multioption_line && !option.label.empty()) {
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") : _(option.label);
@ -581,7 +580,6 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
// If we have a single option with no sidetext just add it directly to the grid sizer
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
option_set.front().opt.label.empty() &&
option_set.front().side_widget == nullptr && og_line.get_extra_widgets().size() == 0)
{
if (field && field->undo_to_sys_bitmap())
@ -595,11 +593,12 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos)
}
size_t bmp_rect_id = 0;
bool is_multioption_line = option_set.size() > 1;
for (const Option& opt : option_set) {
field = ctrl->opt_group->get_field(opt.opt_id);
ConfigOptionDef option = opt.opt;
// add label if any
if (!option.label.empty()) {
if (is_multioption_line && !option.label.empty()) {
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") : _(option.label);

View file

@ -2,11 +2,13 @@
#include "ConfigExceptions.hpp"
#include "Plater.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "OG_CustomCtrl.hpp"
#include "MsgDialog.hpp"
#include "format.hpp"
#include <utility>
#include <wx/bookctrl.h>
#include <wx/numformatter.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
@ -247,7 +249,6 @@ void OptionsGroup::activate_line(Line& line)
// if we have a single option with no label, no sidetext just add it directly to sizer
if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width &&
option_set.front().opt.label.empty() &&
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
line.get_extra_widgets().size() == 0) {
@ -326,7 +327,6 @@ void OptionsGroup::activate_line(Line& line)
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
// If we have a single option with no sidetext just add it directly to the grid sizer
if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
option_set.front().opt.label.empty() &&
option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
const auto& option = option_set.front();
const auto& field = build_field(option);
@ -341,11 +341,12 @@ void OptionsGroup::activate_line(Line& line)
return;
}
bool is_multioption_line = option_set.size() > 1;
for (auto opt : option_set) {
ConfigOptionDef option = opt.opt;
wxSizer* sizer_tmp = sizer;
// add label if any
if (!option.label.empty() && !custom_ctrl) {
if ((is_multioption_line || line.label.IsEmpty()) && !option.label.empty() && !custom_ctrl) {
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") :
@ -507,15 +508,13 @@ void OptionsGroup::clear(bool destroy_custom_ctrl)
m_fields.clear();
}
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const {
// Line retval{ _(option.opt.label), _(option.opt.tooltip) };
Line OptionsGroup::create_single_option_line(const Option& option, const std::string& path/* = std::string()*/) const
{
wxString tooltip = _(option.opt.tooltip);
edit_tooltip(tooltip);
Line retval{ _(option.opt.label), tooltip };
retval.label_path = path;
Option tmp(option);
tmp.opt.label = std::string("");
retval.append_option(tmp);
retval.append_option(option);
return retval;
}
@ -981,9 +980,12 @@ bool OptionsGroup::launch_browser(const std::string& path_end)
bool launch = true;
if (get_app_config()->get("suppress_hyperlinks").empty()) {
RichMessageDialog dialog(nullptr, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO);
wxWindow* parent = wxGetApp().mainframe->m_tabpanel;
RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO);
dialog.ShowCheckBox(_L("Remember my choice"));
int answer = dialog.ShowModal();
if (answer == wxID_CANCEL)
return false;
if (dialog.IsCheckBoxChecked()) {
wxString preferences_item = _L("Suppress to open hyperlink in browser");
@ -992,7 +994,7 @@ bool OptionsGroup::launch_browser(const std::string& path_end)
_L("You will not be asked about it again on label hovering.") + "\n\n" +
format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item);
MessageDialog msg_dlg(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION);
if (msg_dlg.ShowModal() == wxID_CANCEL)
return false;
@ -1032,9 +1034,6 @@ void ogStaticText::SetText(const wxString& value, bool wrap/* = true*/)
void ogStaticText::SetPathEnd(const std::string& link)
{
if (get_app_config()->get("suppress_hyperlinks") != "1")
SetToolTip(OptionsGroup::get_url(link));
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& event) {
if (HasCapture())
return;
@ -1048,7 +1047,11 @@ void ogStaticText::SetPathEnd(const std::string& link)
OptionsGroup::launch_browser(link);
event.Skip();
} );
Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& event) { FocusText(true) ; event.Skip(); });
Bind(wxEVT_ENTER_WINDOW, [this, link](wxMouseEvent& event) {
SetToolTip(OptionsGroup::get_url(get_app_config()->get("suppress_hyperlinks") != "1" ? link : std::string()));
FocusText(true);
event.Skip();
});
Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { FocusText(false); event.Skip(); });
}

View file

@ -226,6 +226,9 @@ ObjectInfo::ObjectInfo(wxWindow *parent) :
Add(sizer_manifold, 0, wxEXPAND | wxTOP, 4);
sla_hidden_items = { label_volume, info_volume, /*label_materials, info_materials*/ };
// Fixes layout issues on plater, short BitmapComboBoxes with some Windows scaling, see GH issue #7414.
this->Show(false);
}
void ObjectInfo::show_sizer(bool show)
@ -1263,7 +1266,11 @@ void Sidebar::show_info_sizer()
if (selection.is_single_volume()) {
std::vector<int> obj_idxs, vol_idxs;
wxGetApp().obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
assert(vol_idxs.size() == 1);
if (vol_idxs.size() != 1)
// Case when this fuction is called between update selection in ObjectList and on Canvas
// Like after try to delete last solid part in object, the object is selected in ObjectLIst when just a part is still selected on Canvas
// see https://github.com/prusa3d/PrusaSlicer/issues/7408
return;
vol = model_object->volumes[vol_idxs[0]];
t = model_object->instances[inst_idx]->get_matrix() * vol->get_matrix();
}
@ -2355,7 +2362,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
const auto loading = _L("Loading") + dots;
wxProgressDialog dlg(loading, "", 100, q, wxPD_AUTO_HIDE);
wxProgressDialog dlg(loading, "", 100, find_toplevel_parent(q), wxPD_AUTO_HIDE);
wxBusyCursor busy;
auto *new_model = (!load_model || one_by_one) ? nullptr : new Slic3r::Model();
@ -3652,12 +3659,12 @@ void Plater::priv::reload_from_disk()
if (has_source || has_name) {
int new_volume_idx = -1;
int new_object_idx = -1;
if (has_source) {
// take idxs from source
new_volume_idx = old_volume->source.volume_idx;
new_object_idx = old_volume->source.object_idx;
}
else {
// if (has_source) {
// // take idxs from source
// new_volume_idx = old_volume->source.volume_idx;
// new_object_idx = old_volume->source.object_idx;
// }
// else {
// take idxs from the 1st matching volume
for (size_t o = 0; o < new_model.objects.size(); ++o) {
ModelObject* obj = new_model.objects[o];
@ -3673,39 +3680,40 @@ void Plater::priv::reload_from_disk()
if (found)
break;
}
}
// }
if (new_object_idx < 0 && (int)new_model.objects.size() <= new_object_idx) {
if (new_object_idx < 0 || int(new_model.objects.size()) <= new_object_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
ModelObject* new_model_object = new_model.objects[new_object_idx];
if (new_volume_idx < 0 && (int)new_model.objects.size() <= new_volume_idx) {
if (new_volume_idx < 0 || int(new_model_object->volumes.size()) <= new_volume_idx) {
fail_list.push_back(from_u8(has_source ? old_volume->source.input_file : old_volume->name));
continue;
}
if (new_volume_idx < (int)new_model_object->volumes.size()) {
old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]);
ModelVolume* new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
assert(! old_volume->source.is_converted_from_inches || ! old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
else if (old_volume->source.is_converted_from_meters)
new_volume->convert_from_meters();
std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
if (!sinking)
old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
sla::reproject_points_and_holes(old_model_object);
}
old_model_object->add_volume(*new_model_object->volumes[new_volume_idx]);
ModelVolume* new_volume = old_model_object->volumes.back();
new_volume->set_new_unique_id();
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
new_volume->set_transformation(old_volume->get_transformation());
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
new_volume->source.object_idx = old_volume->source.object_idx;
new_volume->source.volume_idx = old_volume->source.volume_idx;
assert(! old_volume->source.is_converted_from_inches || ! old_volume->source.is_converted_from_meters);
if (old_volume->source.is_converted_from_inches)
new_volume->convert_from_imperial_units();
else if (old_volume->source.is_converted_from_meters)
new_volume->convert_from_meters();
std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
if (!sinking)
old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
sla::reproject_points_and_holes(old_model_object);
}
}
}
@ -6314,15 +6322,6 @@ void Plater::force_print_bed_update()
void Plater::on_activate()
{
#if defined(__linux__) || defined(_WIN32)
// Activating the main frame, and no window has keyboard focus.
// Set the keyboard focus to the visible Canvas3D.
if (this->p->view3D->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
CallAfter([this]() { this->p->view3D->get_wxglcanvas()->SetFocus(); });
else if (this->p->preview->IsShown() && wxWindow::FindFocus() != this->p->view3D->get_wxglcanvas())
CallAfter([this]() { this->p->preview->get_wxglcanvas()->SetFocus(); });
#endif
this->p->show_delayed_error_message();
}
@ -6890,7 +6889,6 @@ wxMenu* Plater::instance_menu() { return p->menus.instance_menu();
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
{

View file

@ -9,7 +9,6 @@
#include "Notebook.hpp"
#include "ButtonsDescription.hpp"
#include "OG_CustomCtrl.hpp"
#include <initializer_list>
namespace Slic3r {
@ -346,7 +345,7 @@ void PreferencesDialog::build(size_t selected_tab)
def.label = L("Sequential slider applied only to top layer");
def.type = coBool;
def.tooltip = L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer."
def.tooltip = L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer. "
"If disabled, changes made using the sequential slider, in preview, apply to the whole gcode.");
def.set_default_value(new ConfigOptionBool{ app_config->get("seq_top_layer_only") == "1" });
option = Option(def, "seq_top_layer_only");
@ -466,7 +465,7 @@ void PreferencesDialog::build(size_t selected_tab)
#ifdef _WIN32
// Add "Dark Mode" tab
if (is_editor) {
{
// Add "Dark Mode" tab
m_optgroup_dark_mode = create_options_tab(_L("Dark mode (experimental)"), tabs);
m_optgroup_dark_mode->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
@ -486,7 +485,7 @@ void PreferencesDialog::build(size_t selected_tab)
{
def.label = L("Use system menu for application");
def.type = coBool;
def.tooltip = L("If enabled, application will use the standart Windows system menu,\n"
def.tooltip = L("If enabled, application will use the standard Windows system menu,\n"
"but on some combination of display scales it can looks ugly. If disabled, old UI will be used.");
def.set_default_value(new ConfigOptionBool{ app_config->get("sys_menu_enabled") == "1" });
option = Option(def, "sys_menu_enabled");
@ -519,21 +518,29 @@ void PreferencesDialog::build(size_t selected_tab)
this->CenterOnParent();
}
void PreferencesDialog::update_ctrls_alignment()
std::vector<ConfigOptionsGroup*> PreferencesDialog::optgroups()
{
int max_ctrl_width{ 0 };
std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
std::vector<ConfigOptionsGroup*> out;
out.reserve(4);
for (ConfigOptionsGroup* opt : { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get()
#ifdef _WIN32
, m_optgroup_dark_mode.get()
#endif // _WIN32
};
for (auto og : og_list) {
})
if (opt)
out.emplace_back(opt);
return out;
}
void PreferencesDialog::update_ctrls_alignment()
{
int max_ctrl_width{ 0 };
for (ConfigOptionsGroup* og : this->optgroups())
if (int max = og->custom_ctrl->get_max_win_width();
max_ctrl_width < max)
max_ctrl_width = max;
}
if (max_ctrl_width)
for (auto og : og_list)
for (ConfigOptionsGroup* og : this->optgroups())
og->custom_ctrl->set_max_win_width(max_ctrl_width);
}
@ -622,9 +629,8 @@ void PreferencesDialog::accept(wxEvent&)
void PreferencesDialog::on_dpi_changed(const wxRect &suggested_rect)
{
m_optgroup_general->msw_rescale();
m_optgroup_camera->msw_rescale();
m_optgroup_gui->msw_rescale();
for (ConfigOptionsGroup* og : this->optgroups())
og->msw_rescale();
msw_buttons_rescale(this, em_unit(), { wxID_OK, wxID_CANCEL });
@ -788,7 +794,7 @@ void PreferencesDialog::init_highlighter(const t_config_option_key& opt_key)
});
std::pair<OG_CustomCtrl*, bool*> ctrl = { nullptr, nullptr };
for (auto opt_group : { m_optgroup_general, m_optgroup_camera, m_optgroup_gui }) {
for (ConfigOptionsGroup* opt_group : this->optgroups()) {
ctrl = opt_group->get_custom_ctrl_with_blinking_ptr(opt_key, -1);
if (ctrl.first && ctrl.second) {
m_highlighter.init(ctrl);

View file

@ -6,6 +6,7 @@
#include <wx/dialog.h>
#include <wx/timer.h>
#include <vector>
#include <map>
class wxColourPickerCtrl;
@ -61,6 +62,7 @@ protected:
void create_settings_mode_widget();
void create_settings_text_color_widget();
void init_highlighter(const t_config_option_key& opt_key);
std::vector<ConfigOptionsGroup*> optgroups();
struct PreferencesHighlighter
{

View file

@ -98,8 +98,9 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo
}
if (post_actions.has(PrintHostPostUploadAction::StartSimulation)) {
auto* btn_print = add_button(wxID_YES, false, _L("Upload and Simulate"));
btn_print->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
// Using wxID_MORE as a button identifier to be different from the other buttons, wxID_MORE has no other meaning here.
auto* btn_simulate = add_button(wxID_MORE, false, _L("Upload and Simulate"));
btn_simulate->Bind(wxEVT_BUTTON, [this, validate_path](wxCommandEvent&) {
if (validate_path(txt_filename->GetValue())) {
post_upload_action = PrintHostPostUploadAction::StartSimulation;
EndDialog(wxID_OK);

View file

@ -289,7 +289,9 @@ void Tab::create_preset_tab()
// There is used just additional sizer for m_mode_sizer with right alignment
if (m_mode_sizer) {
auto mode_sizer = new wxBoxSizer(wxVERTICAL);
mode_sizer->Add(m_mode_sizer, 1, wxALIGN_RIGHT);
// Don't set the 2nd parameter to 1, making the sizer rubbery scalable in Y axis may lead
// to wrong vertical size assigned to wxBitmapComboBoxes, see GH issue #7176.
mode_sizer->Add(m_mode_sizer, 0, wxALIGN_RIGHT);
m_hsizer->Add(mode_sizer, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, wxOSX ? 15 : 10);
}
@ -885,6 +887,10 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
}
m_postpone_update_ui = false;
// When all values are rolled, then we hane to update whole tab in respect to the reverted values
update();
update_changed_ui();
}
@ -1148,6 +1154,13 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
if (opt_key == "extruders_count")
wxGetApp().plater()->on_extruders_change(boost::any_cast<size_t>(value));
if (m_postpone_update_ui) {
// It means that not all values are rolled to the system/last saved values jet.
// And call of the update() can causes a redundant check of the config values,
// see https://github.com/prusa3d/PrusaSlicer/issues/7146
return;
}
update();
}
@ -1731,7 +1744,9 @@ void TabPrint::update_description_lines()
if (m_active_page && m_active_page->title() == "Output options" && m_post_process_explanation) {
m_post_process_explanation->SetText(
_u8L("Post processing scripts shall modify G-code file in place."));
#ifndef __linux__
m_post_process_explanation->SetPathEnd("post-processing-scripts_283913");
#endif // __linux__
}
}
@ -4479,7 +4494,7 @@ ConfigManipulation Tab::get_config_manipulation()
return on_value_change(opt_key, value);
};
return ConfigManipulation(load_config, cb_toggle_field, cb_value_change);
return ConfigManipulation(load_config, cb_toggle_field, cb_value_change, nullptr, this);
}

View file

@ -891,18 +891,14 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
{
if (!evt.IsChecked())
return;
wxString preferences_item = m_app_config_key == "default_action_on_new_project" ? _L("Ask for unsaved changes when creating new project") :
wxString preferences_item = m_app_config_key == "default_action_on_new_project" ? _L("Ask for unsaved changes when creating new project") :
m_app_config_key == "default_action_on_select_preset" ? _L("Ask for unsaved changes when selecting new preset") :
_L("Ask for unsaved changes when ??closing application??") ;
_L("Ask to save unsaved changes when closing the application or when loading a new project") ;
wxString action = m_app_config_key == "default_action_on_new_project" ? _L("You will not be asked about the unsaved changes the next time you create new project") :
m_app_config_key == "default_action_on_select_preset" ? _L("You will not be asked about the unsaved changes the next time you switch a preset") :
_L("You will not be asked about the unsaved changes the next time you: \n"
"- close the application,\n"
"- load project,\n"
"- process Undo / Redo with a change of print technology,\n"
"- take/load snapshot,\n"
"- load config file/bundle,\n"
"- export config_bundle") ;
"- Closing PrusaSlicer while some presets are modified,\n"
"- Loading a new project while some presets are modified") ;
wxString msg = _L("PrusaSlicer will remember your action.") + "\n\n" + action + "\n\n" +
format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto be asked about unsaved changes again."), preferences_item);
@ -1494,7 +1490,7 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
});
}
m_show_all_presets = new wxCheckBox(this, wxID_ANY, _L("Show all preset (including incompatible)"));
m_show_all_presets = new wxCheckBox(this, wxID_ANY, _L("Show all presets (including incompatible)"));
m_show_all_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
bool show_all = m_show_all_presets->GetValue();
for (auto preset_combos : m_preset_combos) {
@ -1555,7 +1551,7 @@ void DiffPresetDialog::update_bundles_from_app()
void DiffPresetDialog::show(Preset::Type type /* = Preset::TYPE_INVALID*/)
{
this->SetTitle(type == Preset::TYPE_INVALID ? _L("Compare Presets") : format_wxstr(_L("Compare %1% Presets"), wxGetApp().get_tab(type)->name()));
this->SetTitle(_L("Compare Presets"));
m_view_type = type;
update_bundles_from_app();

View file

@ -112,7 +112,17 @@ SCENARIO("2D convex hull of sinking object", "[3mf]") {
{ -91501496, 4243 }
};
bool res = hull_2d.points == result;
// Allow 1um error due to floating point rounding.
bool res = hull_2d.points.size() == result.size();
if (res)
for (size_t i = 0; i < result.size(); ++ i) {
const Point &p1 = result[i];
const Point &p2 = hull_2d.points[i];
if (std::abs(p1.x() - p2.x()) > 1 || std::abs(p1.y() - p2.y()) > 1) {
res = false;
break;
}
}
THEN("2D convex hull should match with reference") {
REQUIRE(res);

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