Merge branch 'fs_dir_per_glyph_SPE-1597' into fs_svg

# Conflicts:
#	src/libslic3r/Emboss.cpp
#	src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
#	src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp
#	src/slic3r/GUI/TextLines.cpp
This commit is contained in:
Filip Sykala - NTB T15p 2023-08-08 17:13:15 +02:00
commit b699e6da9b
40 changed files with 5995 additions and 239 deletions

View File

@ -26,7 +26,6 @@ endif()
option(SLIC3R_STATIC "Compile PrusaSlicer with static libraries (Boost, TBB, glew)" ${SLIC3R_STATIC_INITIAL})
option(SLIC3R_GUI "Compile PrusaSlicer with GUI components (OpenGL, wxWidgets)" 1)
option(SLIC3R_FHS "Assume PrusaSlicer is to be installed in a FHS directory structure" 0)
option(SLIC3R_WX_STABLE "Build against wxWidgets stable (3.0) as oppsed to dev (3.1) on Linux" 0)
option(SLIC3R_PCH "Use precompiled headers" 1)
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
# Dependency report for PrusaSlicer
## Possible dynamic linking on Linux
* zlib: Strict dependency required from the system, linked dynamically. Many other libs depend on zlib.
* wxWidgets: searches for wx-3.1 by default, but with cmake option `SLIC3R_WX_STABLE=ON` it will use wx-3.0 bundled with most distros.
* wxWidgets >= 3.2
* libcurl
* tbb
* boost

View File

@ -87,7 +87,6 @@ And that's it. It is now possible to run the freshly built PrusaSlicer binary:
- `-DSLIC3R_ASAN=ON` enables gcc/clang address sanitizer (defaults to `OFF`, requires gcc>4.8 or clang>3.1)
- `-DSLIC3R_GTK=3` to use GTK3 (defaults to `2`). Note that wxWidgets must be built against the same GTK version.
- `-DSLIC3R_STATIC=ON` for static build (defaults to `OFF`)
- `-DSLIC3R_WX_STABLE=ON` to look for wxWidgets 3.0 (defaults to `OFF`)
- `-DCMAKE_BUILD_TYPE=Debug` to build in debug mode (defaults to `Release`)
- `-DSLIC3R_GUI=no` to build the console variant of PrusaSlicer
@ -101,13 +100,7 @@ As already mentioned above, dynamic linking of dependencies is possible, but Pru
The list of dependencies can be easily obtained by inspecting the CMake scripts in the `deps/` directory. Some of the dependencies don't have to be as recent as the versions listed - generally versions available on conservative Linux distros such as Debian stable, Ubuntu LTS releases or Fedora are likely sufficient. If you decide to build this way, it is your responsibility to make sure that CMake finds all required dependencies. It is possible to look at your distribution PrusaSlicer package to see how the package maintainers solved the dependency issues.
#### wxWidgets
By default, PrusaSlicer looks for wxWidgets 3.1. Our build script in fact downloads specific patched version of wxWidgets. If you want to link against wxWidgets 3.0 (which are still provided by most distributions because wxWidgets 3.1 have not yet been declared stable), you must set `-DSLIC3R_WX_STABLE=ON` when running CMake. Note that while PrusaSlicer can be linked against wWidgets 3.0, the combination is not well tested and there might be bugs in the resulting application.
When building on ubuntu 20.04 focal fossa, the package libwxgtk3.0-gtk3-dev needs to be installed instead of libwxgtk3.0-dev and you should use:
```
-DSLIC3R_WX_STABLE=1 -DSLIC3R_GTK=3
```
Note that you may need to use wxGTK with disabled EGL support for PrusaSlicer to work correctly: see [#9774](https://github.com/prusa3d/PrusaSlicer/issues/9774).
## Miscellaneous

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 794.8 681.4" style="enable-background:new 0 0 794.8 681.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:1.0002;stroke-miterlimit:11.3405;}
.st1{fill:#EFE4E4;stroke:#FFFFFF;stroke-width:1.0002;stroke-miterlimit:11.3405;}
.st2{enable-background:new ;}
.st3{fill:none;stroke:#FFFFFF;stroke-miterlimit:11.3386;}
</style>
<path class="st0" d="M23.2,0.5h756.1c8.3,0,15,5.5,15,12.3l0,0v626.3c0,6.8-6.7,12.3-15,12.3H15.5c-8.3,0-15-5.5-15-12.3l0,0v-620
C0.5,8.8,10.6,0.5,23.2,0.5z"/>
<polygon class="st1" points="530.6,680.9 264.2,680.9 238.5,651.4 556.8,651.4 "/>
<g class="st2">
<path class="st3" d="M342.5,609.5l2.7-0.2c0.1,0.9,0.4,1.6,0.9,2.2s1.2,1,2.2,1.4s2.1,0.5,3.4,0.5c1.1,0,2.1-0.1,2.9-0.4
c0.8-0.3,1.5-0.6,1.9-1.1c0.4-0.5,0.6-1,0.6-1.5c0-0.6-0.2-1.1-0.6-1.5s-1.1-0.8-2-1.1c-0.6-0.2-1.9-0.5-3.9-0.9
c-2-0.4-3.4-0.8-4.2-1.1c-1-0.4-1.8-1-2.3-1.7c-0.5-0.7-0.8-1.4-0.8-2.2c0-0.9,0.3-1.8,0.9-2.5c0.6-0.8,1.5-1.4,2.7-1.8
c1.2-0.4,2.5-0.6,4-0.6c1.6,0,3.1,0.2,4.3,0.6c1.2,0.4,2.2,1.1,2.9,1.9c0.7,0.8,1,1.8,1.1,2.8l-2.8,0.2c-0.1-1.1-0.7-2-1.5-2.6
c-0.9-0.6-2.1-0.9-3.8-0.9c-1.8,0-3,0.3-3.8,0.8c-0.8,0.5-1.2,1.2-1.2,1.9c0,0.6,0.3,1.2,0.9,1.6c0.6,0.4,2,0.8,4.4,1.3
c2.4,0.4,4,0.8,4.8,1.1c1.3,0.5,2.2,1.1,2.8,1.8c0.6,0.7,0.9,1.6,0.9,2.6c0,1-0.3,1.9-1,2.7c-0.7,0.8-1.6,1.5-2.9,2
s-2.7,0.7-4.2,0.7c-2,0-3.6-0.2-5-0.7c-1.3-0.5-2.4-1.2-3.1-2.1C343,611.7,342.6,610.7,342.5,609.5z"/>
</g>
<g class="st2">
<path class="st3" d="M357.3,608.7c0-2.4,0.8-4.2,2.4-5.3c1.4-1,3-1.4,5-1.4c2.2,0,4,0.6,5.3,1.8c1.4,1.2,2.1,2.8,2.1,4.8
c0,1.7-0.3,3-0.9,3.9s-1.5,1.7-2.7,2.2c-1.2,0.5-2.4,0.8-3.8,0.8c-2.2,0-4-0.6-5.4-1.7C358,612.6,357.3,610.9,357.3,608.7z
M360,608.7c0,1.7,0.4,2.9,1.3,3.7c0.9,0.8,2,1.2,3.3,1.2c1.3,0,2.4-0.4,3.3-1.2c0.9-0.8,1.3-2.1,1.3-3.8c0-1.6-0.4-2.8-1.3-3.7
c-0.9-0.8-2-1.2-3.3-1.2c-1.3,0-2.5,0.4-3.3,1.2C360.5,605.8,360,607.1,360,608.7z"/>
</g>
<g class="st2">
<path class="st3" d="M379.3,615.2l-6-13h2.8l3.4,7.8c0.4,0.8,0.7,1.7,1,2.6c0.2-0.7,0.6-1.5,1-2.5l3.5-7.9h2.8l-6,13H379.3z"/>
</g>
<g class="st2">
<path class="st3" d="M388.4,608.7c0-2.4,0.8-4.2,2.4-5.3c1.4-1,3-1.4,5-1.4c2.2,0,4,0.6,5.3,1.8s2.1,2.8,2.1,4.8
c0,1.7-0.3,3-0.9,3.9c-0.6,1-1.5,1.7-2.7,2.2c-1.2,0.5-2.4,0.8-3.8,0.8c-2.2,0-4-0.6-5.4-1.7C389.1,612.6,388.4,610.9,388.4,608.7z
M391.1,608.7c0,1.7,0.4,2.9,1.3,3.7c0.9,0.8,2,1.2,3.3,1.2c1.3,0,2.4-0.4,3.3-1.2c0.9-0.8,1.3-2.1,1.3-3.8c0-1.6-0.4-2.8-1.3-3.7
c-0.9-0.8-2-1.2-3.3-1.2c-1.3,0-2.5,0.4-3.3,1.2C391.6,605.8,391.1,607.1,391.1,608.7z"/>
<path class="st3" d="M406.3,615.2v-17.9h2.7v17.9H406.3z"/>
<path class="st3" d="M420.9,610.5l2.7-0.3c0.3,1.2,0.8,2.1,1.6,2.7s1.6,0.8,2.7,0.8c1.3,0,2.3-0.4,3.2-1.1c0.9-0.7,1.3-1.6,1.3-2.7
c0-1-0.4-1.8-1.2-2.5c-0.8-0.7-1.8-1-3.1-1c-0.5,0-1.1,0.1-1.9,0.2l0.3-1.9c0.2,0,0.3,0,0.4,0c1.1,0,2.2-0.2,3.1-0.7
c0.9-0.5,1.4-1.2,1.4-2.3c0-0.8-0.3-1.5-1-2c-0.7-0.5-1.5-0.8-2.6-0.8c-1,0-1.9,0.3-2.6,0.8s-1.1,1.3-1.3,2.4l-2.7-0.4
c0.3-1.5,1.1-2.6,2.2-3.4s2.6-1.2,4.3-1.2c1.2,0,2.3,0.2,3.3,0.6s1.8,1,2.3,1.7s0.8,1.5,0.8,2.3c0,0.8-0.3,1.5-0.8,2.1
c-0.5,0.6-1.3,1.1-2.3,1.5c1.3,0.2,2.3,0.8,3,1.5c0.7,0.8,1.1,1.7,1.1,2.9c0,1.6-0.7,2.9-2.1,4c-1.4,1.1-3.2,1.6-5.3,1.6
c-1.9,0-3.5-0.5-4.8-1.4C421.8,613.2,421.1,612,420.9,610.5z"/>
<path class="st3" d="M439,615.2v-17.9h7.5c1.7,0,3,0.1,3.9,0.3c1.3,0.2,2.3,0.7,3.2,1.3c1.2,0.8,2,1.8,2.6,3.1s0.9,2.7,0.9,4.3
c0,1.4-0.2,2.6-0.6,3.6c-0.4,1.1-0.9,1.9-1.5,2.6c-0.6,0.7-1.3,1.2-2,1.6c-0.7,0.4-1.6,0.7-2.6,0.9c-1,0.2-2.2,0.3-3.5,0.3H439z
M441.9,613.1h4.7c1.4,0,2.6-0.1,3.4-0.3s1.5-0.5,2-0.9c0.7-0.6,1.2-1.3,1.6-2.3c0.4-1,0.6-2.1,0.6-3.5c0-1.9-0.4-3.3-1.1-4.3
c-0.8-1-1.7-1.7-2.7-2c-0.8-0.2-2-0.4-3.7-0.4h-4.6V613.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 624.8 624.8" style="enable-background:new 0 0 624.8 624.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#FFFFFF;stroke-width:1.0002;stroke-miterlimit:11.3414;}
.st1{fill:#EFE4E4;stroke:#FFFFFF;stroke-width:1.0002;stroke-miterlimit:11.3414;}
.st2{enable-background:new ;}
.st3{fill:none;stroke:#FFFFFF;stroke-miterlimit:11.3386;}
</style>
<path class="st0" d="M18.3,0.5h594.1c6.4-0.1,11.6,4.9,11.8,11.3l0,0v574.1c0,6.2-5.3,11.2-11.8,11.2H12.3c-6.5,0-11.8-5-11.8-11.2
l0,0V17.5C0.5,8.1,8.5,0.5,18.3,0.5z"/>
<polygon class="st1" points="417,624.3 207.8,624.3 187.5,597.1 437.6,597.1 "/>
<g class="st2">
<path class="st3" d="M269.2,558.8l2.2-0.2c0.1,0.8,0.3,1.5,0.7,2c0.4,0.5,1,1,1.7,1.3c0.8,0.3,1.7,0.5,2.6,0.5
c0.9,0,1.6-0.1,2.3-0.4c0.7-0.2,1.2-0.6,1.5-1s0.5-0.9,0.5-1.4c0-0.5-0.2-1-0.5-1.4c-0.3-0.4-0.8-0.7-1.6-1
c-0.5-0.2-1.5-0.4-3.1-0.8c-1.6-0.4-2.7-0.7-3.3-1c-0.8-0.4-1.4-0.9-1.8-1.5c-0.4-0.6-0.6-1.3-0.6-2c0-0.8,0.2-1.6,0.7-2.3
s1.2-1.3,2.2-1.6c0.9-0.4,2-0.6,3.2-0.6c1.3,0,2.4,0.2,3.4,0.6c1,0.4,1.7,1,2.3,1.7c0.5,0.8,0.8,1.6,0.8,2.6l-2.2,0.2
c-0.1-1-0.5-1.8-1.2-2.4c-0.7-0.5-1.7-0.8-3-0.8c-1.4,0-2.4,0.2-3,0.7s-0.9,1.1-0.9,1.7c0,0.6,0.2,1.1,0.7,1.5
c0.4,0.4,1.6,0.8,3.4,1.2c1.9,0.4,3.1,0.8,3.8,1c1,0.4,1.7,1,2.2,1.7c0.5,0.7,0.7,1.5,0.7,2.3c0,0.9-0.3,1.7-0.8,2.5
c-0.5,0.8-1.3,1.4-2.3,1.8c-1,0.4-2.1,0.6-3.3,0.6c-1.6,0-2.9-0.2-3.9-0.7s-1.9-1.1-2.5-2C269.6,560.8,269.3,559.9,269.2,558.8z"/>
</g>
<g class="st2">
<path class="st3" d="M280.9,558.1c0-2.2,0.6-3.8,1.9-4.9c1.1-0.9,2.4-1.3,3.9-1.3c1.7,0,3.1,0.5,4.2,1.6c1.1,1.1,1.6,2.6,1.6,4.4
c0,1.5-0.2,2.7-0.7,3.6c-0.5,0.9-1.2,1.6-2.1,2c-0.9,0.5-1.9,0.7-3,0.7c-1.8,0-3.2-0.5-4.2-1.6
C281.4,561.6,280.9,560.1,280.9,558.1z M283,558.1c0,1.5,0.3,2.7,1,3.4c0.7,0.8,1.6,1.1,2.6,1.1c1.1,0,1.9-0.4,2.6-1.1s1-1.9,1-3.5
c0-1.5-0.4-2.6-1.1-3.3s-1.6-1.1-2.6-1.1c-1.1,0-1.9,0.4-2.6,1.1C283.4,555.4,283,556.6,283,558.1z"/>
</g>
<g class="st2">
<path class="st3" d="M298.1,564l-4.8-11.9h2.2l2.7,7.1c0.3,0.8,0.6,1.6,0.8,2.4c0.2-0.6,0.5-1.4,0.8-2.3l2.8-7.3h2.2l-4.7,11.9
H298.1z"/>
</g>
<g class="st2">
<path class="st3" d="M305.3,558.1c0-2.2,0.6-3.8,1.9-4.9c1.1-0.9,2.4-1.3,3.9-1.3c1.7,0,3.1,0.5,4.2,1.6c1.1,1.1,1.6,2.6,1.6,4.4
c0,1.5-0.2,2.7-0.7,3.6c-0.5,0.9-1.2,1.6-2.1,2c-0.9,0.5-1.9,0.7-3,0.7c-1.8,0-3.2-0.5-4.2-1.6
C305.8,561.6,305.3,560.1,305.3,558.1z M307.5,558.1c0,1.5,0.3,2.7,1,3.4c0.7,0.8,1.6,1.1,2.6,1.1c1.1,0,1.9-0.4,2.6-1.1
s1-1.9,1-3.5c0-1.5-0.4-2.6-1.1-3.3s-1.6-1.1-2.6-1.1c-1.1,0-1.9,0.4-2.6,1.1C307.8,555.4,307.5,556.6,307.5,558.1z"/>
<path class="st3" d="M319.4,564v-16.4h2.1V564H319.4z"/>
<path class="st3" d="M331,559.7l2.1-0.3c0.2,1.1,0.7,2,1.2,2.5c0.6,0.5,1.3,0.8,2.1,0.8c1,0,1.8-0.3,2.5-1c0.7-0.7,1-1.5,1-2.4
c0-0.9-0.3-1.7-1-2.3s-1.4-0.9-2.4-0.9c-0.4,0-0.9,0.1-1.5,0.2l0.2-1.8c0.1,0,0.3,0,0.3,0c0.9,0,1.7-0.2,2.4-0.7s1.1-1.1,1.1-2.1
c0-0.7-0.3-1.4-0.8-1.8c-0.5-0.5-1.2-0.7-2-0.7c-0.8,0-1.5,0.2-2.1,0.7c-0.5,0.5-0.9,1.2-1.1,2.2l-2.1-0.4c0.3-1.4,0.8-2.4,1.8-3.1
c0.9-0.7,2.1-1.1,3.4-1.1c0.9,0,1.8,0.2,2.6,0.6c0.8,0.4,1.4,0.9,1.8,1.6c0.4,0.7,0.6,1.4,0.6,2.1c0,0.7-0.2,1.4-0.6,1.9
s-1,1-1.8,1.4c1,0.2,1.8,0.7,2.4,1.4c0.6,0.7,0.8,1.6,0.8,2.7c0,1.4-0.5,2.7-1.6,3.7c-1.1,1-2.5,1.5-4.2,1.5
c-1.5,0-2.8-0.4-3.8-1.3C331.7,562.2,331.1,561.1,331,559.7z"/>
<path class="st3" d="M345.2,564v-16.4h5.9c1.3,0,2.4,0.1,3.1,0.2c1,0.2,1.8,0.6,2.5,1.2c0.9,0.7,1.6,1.7,2,2.8s0.7,2.4,0.7,3.9
c0,1.2-0.2,2.4-0.5,3.3c-0.3,1-0.7,1.8-1.2,2.4c-0.5,0.6-1,1.1-1.6,1.5c-0.6,0.4-1.3,0.6-2.1,0.8s-1.7,0.3-2.8,0.3H345.2z
M347.5,562.1h3.7c1.1,0,2-0.1,2.7-0.3c0.6-0.2,1.2-0.5,1.5-0.9c0.5-0.5,1-1.2,1.3-2.1c0.3-0.9,0.5-1.9,0.5-3.2c0-1.7-0.3-3-0.9-4
c-0.6-0.9-1.3-1.5-2.2-1.9c-0.6-0.2-1.6-0.3-3-0.3h-3.6V562.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

File diff suppressed because it is too large Load Diff

View File

@ -49,28 +49,12 @@ if (SLIC3R_GUI)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
if (SLIC3R_WX_STABLE)
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
else ()
find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl)
if (NOT wxWidgets_FOUND)
message(FATAL_ERROR "\nCould not find wxWidgets 3.1.\n"
"Hint: On Linux you can set -DSLIC3R_WX_STABLE=1 to use wxWidgets 3.0\n")
endif ()
endif ()
include(${wxWidgets_USE_FILE})
else ()
find_package(wxWidgets 3.1 COMPONENTS html adv gl core base)
if (NOT wxWidgets_FOUND)
message(STATUS "Trying to find wxWidgets in CONFIG mode...")
find_package(wxWidgets 3.2 CONFIG REQUIRED COMPONENTS html adv gl core base)
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
else ()
include(${wxWidgets_USE_FILE})
endif ()
endif ()
find_package(wxWidgets 3.2 MODULE REQUIRED COMPONENTS base core adv html gl)
include(${wxWidgets_USE_FILE})
slic3r_remap_configs(wx::wxhtml wx::wxadv wx::wxgl wx::wxcore wx::wxbase RelWithDebInfo Release)
if(UNIX)
message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")

View File

@ -1,8 +1,10 @@
#ifndef CSGMESH_HPP
#define CSGMESH_HPP
#include "libslic3r/Point.hpp"
#include <libslic3r/AnyPtr.hpp>
#include <admesh/stl.h>
#include <libslic3r/TriangleMesh.hpp>
namespace Slic3r { namespace csg {
@ -81,6 +83,35 @@ struct CSGPart {
{}
};
template<class Cont> bool is_all_positive(const Cont &csgmesh)
{
bool is_all_pos =
std::all_of(csgmesh.begin(),
csgmesh.end(),
[](auto &part) {
return csg::get_operation(part) == csg::CSGType::Union;
});
return is_all_pos;
}
template<class Cont>
indexed_triangle_set csgmesh_merge_positive_parts(const Cont &csgmesh)
{
indexed_triangle_set m;
for (auto &csgpart : csgmesh) {
auto op = csg::get_operation(csgpart);
const indexed_triangle_set * pmesh = csg::get_mesh(csgpart);
if (pmesh && op == csg::CSGType::Union) {
indexed_triangle_set mcpy = *pmesh;
its_transform(mcpy, csg::get_transform(csgpart), true);
its_merge(m, mcpy);
}
}
return m;
}
}} // namespace Slic3r::csg
#endif // CSGMESH_HPP

View File

@ -19,6 +19,10 @@
#include "libslic3r/Line.hpp"
#include "libslic3r/BoundingBox.hpp"
// Experimentaly suggested ration of font ascent by multiple fonts
// to get approx center of normal text line
const double ASCENT_CENTER = 1/3.; // 0.5 is above small letter
// every glyph's shape point is divided by SHAPE_SCALE - increase precission of fixed point value
// stored in fonts (to be able represents curve by sequence of lines)
static constexpr double SHAPE_SCALE = 0.001; // SCALING_FACTOR promile is fine enough
@ -1153,17 +1157,21 @@ std::optional<Glyph> Emboss::letter2glyph(const FontFile &font,
return priv::get_glyph(*font_info_opt, letter, flatness);
}
int Emboss::get_line_height(const FontFile &font, const FontProp &prop) {
const FontFile::Info &Emboss::get_font_info(const FontFile &font, const FontProp &prop)
{
unsigned int font_index = prop.collection_number.value_or(0);
assert(priv::is_valid(font, font_index));
const FontFile::Info &info = font.infos[font_index];
return font.infos[font_index];
}
int Emboss::get_line_height(const FontFile &font, const FontProp &prop) {
const FontFile::Info &info = get_font_info(font, prop);
int line_height = info.ascent - info.descent + info.linegap;
line_height += prop.line_gap.value_or(0);
return static_cast<int>(line_height / SHAPE_SCALE);
}
namespace {
ExPolygons letter2shapes(
wchar_t letter, Point &cursor, FontFileWithCache &font_with_cache, const FontProp &font_prop, fontinfo_opt& font_info_cache)
{
@ -1242,12 +1250,12 @@ namespace {
/// <summary>
/// Align shape against pivot
/// </summary>
/// <param name="type">Horizontal and vertical alignment</param>
/// <param name="shapes">Shapes to align
/// Prerequisities: shapes are aligned left top</param>
/// <param name="text">To detect end of lines</param>
/// <param name="line_height">Height of line for align[in font points]</param>
void align_shape(FontProp::Align type, ExPolygonsWithIds &shape, const std::wstring &text, int line_height);
/// <param name="text">To detect end of lines - to be able horizontal center the line</param>
/// <param name="prop">Containe Horizontal and vertical alignment</param>
/// <param name="font">Needed for scale and font size</param>
void align_shape(ExPolygonsWithIds &shapes, const std::wstring &text, const FontProp &prop, const FontFile &font);
}
ExPolygonsWithIds Emboss::text2vshapes(FontFileWithCache &font_with_cache, const std::wstring& text, const FontProp &font_prop, const std::function<bool()>& was_canceled){
@ -1273,7 +1281,7 @@ ExPolygonsWithIds Emboss::text2vshapes(FontFileWithCache &font_with_cache, const
result.push_back({id, letter2shapes(letter, cursor, font_with_cache, font_prop, font_info_cache)});
}
align_shape(font_prop.align, result, text, get_line_height(font, font_prop));
align_shape(result, text, font_prop, font);
return result;
}
@ -1417,8 +1425,7 @@ std::string Emboss::create_range_text(const std::string &text,
double Emboss::get_text_shape_scale(const FontProp &fp, const FontFile &ff)
{
size_t font_index = fp.collection_number.value_or(0);
const FontFile::Info &info = ff.infos[font_index];
const FontFile::Info &info = get_font_info(ff, fp);
double scale = fp.size_in_mm / (double) info.unit_per_em;
// Shape is scaled for store point coordinate as integer
return scale * SHAPE_SCALE;
@ -1889,20 +1896,22 @@ PolygonPoints Emboss::sample_slice(const TextLine &slice, const BoundingBoxes &b
}
namespace {
template<typename T> T get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, T line_height)
float get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp)
{
if (count_lines == 0)
return 0;
assert(count_lines != 0);
int line_height = get_line_height(ff, fp);
int ascent = get_font_info(ff, fp).ascent / SHAPE_SCALE;
float line_center = static_cast<float>(std::round(ascent * ASCENT_CENTER));
// direction of Y in 2d is from top to bottom
// zero is on base line of first line
switch (align) {
case FontProp::VerticalAlign::center: return ((count_lines - 1) / 2) * line_height + ((count_lines % 2 == 0) ? (line_height / 2) : 0);
case FontProp::VerticalAlign::bottom: return (count_lines - 1) * line_height;
case FontProp::VerticalAlign::top: // no change
default: break;
case FontProp::VerticalAlign::bottom: return line_height * (count_lines - 1);
case FontProp::VerticalAlign::top: return -ascent;
case FontProp::VerticalAlign::center:
default:
return -line_center + line_height * (count_lines - 1) / 2.;
}
return 0;
}
int32_t get_align_x_offset(FontProp::HorizontalAlign align, const BoundingBox &shape_bb, const BoundingBox &line_bb)
@ -1916,11 +1925,10 @@ int32_t get_align_x_offset(FontProp::HorizontalAlign align, const BoundingBox &s
return 0;
}
void align_shape(FontProp::Align type, ExPolygonsWithIds &shapes, const std::wstring &text, int line_height)
void align_shape(ExPolygonsWithIds &shapes, const std::wstring &text, const FontProp &prop, const FontFile &font)
{
constexpr FontProp::Align no_change(FontProp::HorizontalAlign::left, FontProp::VerticalAlign::top);
if (type == no_change)
return; // no alignment
// Shapes have to match letters in text
assert(shapes.size() == text.length());
BoundingBox shape_bb;
for (const ExPolygonsWithId& shape: shapes)
@ -1932,15 +1940,30 @@ void align_shape(FontProp::Align type, ExPolygonsWithIds &shapes, const std::wst
line_bb.merge(get_extents(shapes[j].expoly));
return line_bb;
};
int line_height = get_line_height(font, prop);
unsigned count_lines = get_count_lines(text);
int center_line = get_font_info(font, prop).ascent * ASCENT_CENTER;
int y_offset = get_align_y_offset(prop.align.second, count_lines, font, prop);
// Speed up for left aligned text
if (prop.align.first == FontProp::HorizontalAlign::left){
// already horizontaly aligned
for (ExPolygonsWithId& shape : shapes)
for (ExPolygon &s : shape.expoly)
s.translate(Point(0, y_offset));
return;
}
// Align x line by line
Point offset(
get_align_x_offset(type.first, shape_bb, get_line_bb(0)),
get_align_y_offset(type.second, get_count_lines(shapes), line_height));
assert(shapes.size() == text.length());
get_align_x_offset(prop.align.first, shape_bb, get_line_bb(0)),
y_offset);
for (size_t i = 0; i < shapes.size(); ++i) {
wchar_t letter = text[i];
if (letter == '\n'){
offset.x() = get_align_x_offset(type.first, shape_bb, get_line_bb(i+1));
offset.x() = get_align_x_offset(prop.align.first, shape_bb, get_line_bb(i + 1));
continue;
}
ExPolygons &shape = shapes[i].expoly;
@ -1950,8 +1973,10 @@ void align_shape(FontProp::Align type, ExPolygonsWithIds &shapes, const std::wst
}
} // namespace
double Emboss::get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, double line_height){
return ::get_align_y_offset<double>(align, count_lines, line_height);
double Emboss::get_align_y_offset_in_mm(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp){
float offset_in_font_point = get_align_y_offset(align, count_lines, ff, fp);
double scale = get_text_shape_scale(fp, ff);
return scale * offset_in_font_point;
}
#ifdef REMOVE_SPIKES

View File

@ -227,23 +227,29 @@ namespace Emboss
/// <returns>Conversion to mm</returns>
double get_text_shape_scale(const FontProp &fp, const FontFile &ff);
/// <summary>
/// getter of font info by collection defined in prop
/// </summary>
/// <param name="font">Contain infos about all fonts(collections) in file</param>
/// <param name="prop">Index of collection</param>
/// <returns>Ascent, descent, line gap</returns>
const FontFile::Info &get_font_info(const FontFile &font, const FontProp &prop);
/// <summary>
/// Read from font file and properties height of line with spacing
/// </summary>
/// <param name="font">Infos for collections</param>
/// <param name="prop">Collection index + Additional line gap</param>
/// <returns>Line height with spacing in ExPolygon size</returns>
/// <returns>Line height with spacing in scaled font points (same as ExPolygons)</returns>
int get_line_height(const FontFile &font, const FontProp &prop);
/// <summary>
/// Calculate Vertical align
/// </summary>
/// <typeparam name="T">double for mm</typeparam>
/// <param name="align">type</param>
/// <param name="align">Top | Center | Bottom</param>
/// <param name="count_lines"></param>
/// <param name="line_height"></param>
/// <returns>In same unit as line height</returns>
double get_align_y_offset(FontProp::VerticalAlign align, unsigned count_lines, double line_height);
/// <returns>Return align Y offset in mm</returns>
double get_align_y_offset_in_mm(FontProp::VerticalAlign align, unsigned count_lines, const FontFile &ff, const FontProp &fp);
/// <summary>
/// Project spatial point

View File

@ -516,7 +516,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
WipeTower::WipeTower(const PrintConfig& config, const PrintRegionConfig& default_region_config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
m_semm(config.single_extruder_multi_material.value),
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
m_wipe_tower_width(float(config.wipe_tower_width)),
@ -530,6 +530,8 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
m_no_sparse_layers(config.wipe_tower_no_sparse_layers),
m_gcode_flavor(config.gcode_flavor),
m_travel_speed(config.travel_speed),
m_infill_speed(default_region_config.infill_speed),
m_perimeter_speed(default_region_config.perimeter_speed),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
{
@ -541,6 +543,13 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
m_first_layer_speed = default_speed / 2.f;
// Autospeed may be used...
if (m_infill_speed == 0.f)
m_infill_speed = 80.f;
if (m_perimeter_speed == 0.f)
m_perimeter_speed = 80.f;
// If this is a single extruder MM printer, we will use all the SE-specific config values.
// Otherwise, the defaults will be used to turn off the SE stuff.
if (m_semm) {
@ -1034,7 +1043,7 @@ void WipeTower::toolchange_Wipe(
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height);
float dy = m_extra_spacing*m_perimeter_width;
const float target_speed = is_first_layer() ? m_first_layer_speed * 60.f : 4800.f;
const float target_speed = is_first_layer() ? m_first_layer_speed * 60.f : m_infill_speed * 60.f;
float wipe_speed = 0.33f * target_speed;
// if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway)
@ -1103,7 +1112,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
// Slow down on the 1st layer.
bool first_layer = is_first_layer();
float feedrate = first_layer ? m_first_layer_speed * 60.f : 2900.f;
float feedrate = first_layer ? m_first_layer_speed * 60.f : m_infill_speed * 60.f;
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
@ -1203,7 +1212,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
// First generate vector of annotated point which form the boundary.
std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) {
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 20.)
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 40.)
pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc);
pts.back().second = ArcEnd;
}
@ -1285,6 +1294,8 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
return poly;
};
feedrate = first_layer ? m_first_layer_speed * 60.f : m_perimeter_speed * 60.f;
// outer contour (always)
bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing;
Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone);

View File

@ -14,6 +14,7 @@ namespace Slic3r
class WipeTowerWriter;
class PrintConfig;
class PrintRegionConfig;
enum GCodeFlavor : unsigned char;
@ -129,7 +130,10 @@ public:
// y -- y coordinates of wipe tower in mm ( left bottom corner )
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm
WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool);
WipeTower(const PrintConfig& config,
const PrintRegionConfig& default_region_config,
const std::vector<std::vector<float>>& wiping_matrix,
size_t initial_tool);
// Set the extruder properties.
@ -269,6 +273,8 @@ private:
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
float m_travel_speed = 0.f;
float m_infill_speed = 0.f;
float m_perimeter_speed = 0.f;
float m_first_layer_speed = 0.f;
size_t m_first_layer_idx = size_t(-1);

View File

@ -1572,8 +1572,12 @@ void ModelObject::reset_instance_transformation(ModelObject* object, size_t src_
for (size_t i = 0; i < object->instances.size(); ++i) {
auto& obj_instance = object->instances[i];
const double rot_z = obj_instance->get_rotation().z();
obj_instance->set_transformation(Transformation(obj_instance->get_transformation().get_matrix_no_scaling_factor()));
Transformation inst_trafo = Transformation(obj_instance->get_transformation().get_matrix_no_scaling_factor());
if (obj_instance->is_left_handed())
inst_trafo = inst_trafo * Transformation(scale_transform(Vec3d(-1, 1, 1)));
obj_instance->set_transformation(inst_trafo);
Vec3d rotation = Vec3d::Zero();
if (!flip && !place_on_cut) {

View File

@ -675,7 +675,9 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
void PresetBundle::export_selections(AppConfig &config)
{
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() >= 1);
assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() > 1 || filaments.get_selected_preset().alias == extruders_filaments.front().get_selected_preset()->alias);
// #ysFIXME_delete_after_test !All filament selections are always saved in extruder_filaments (for MM and SM printers),
// so there is no need to control a correspondence between filaments and extruders_filaments
//assert(this->printers.get_edited_preset().printer_technology() != ptFFF || extruders_filaments.size() > 1 || filaments.get_selected_preset().alias == extruders_filaments.front().get_selected_preset()->alias);
config.clear_section("presets");
config.set("presets", "print", prints.get_selected_preset_name());
config.set("presets", "filament", extruders_filaments.front().get_selected_preset_name());

View File

@ -1453,7 +1453,7 @@ void Print::_make_wipe_tower()
this->throw_if_canceled();
// Initialize the wipe tower.
WipeTower wipe_tower(m_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
WipeTower wipe_tower(m_config, m_default_region_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract();
//wipe_tower.set_zhop();

View File

@ -814,15 +814,15 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "overhang_speed_2"
|| opt_key == "overhang_speed_3"
|| opt_key == "external_perimeter_speed"
|| opt_key == "infill_speed"
|| opt_key == "perimeter_speed"
|| opt_key == "small_perimeter_speed"
|| opt_key == "solid_infill_speed"
|| opt_key == "top_solid_infill_speed") {
invalidated |= m_print->invalidate_step(psGCodeExport);
} else if (
opt_key == "wipe_into_infill"
|| opt_key == "wipe_into_objects") {
|| opt_key == "wipe_into_objects"
|| opt_key == "infill_speed"
|| opt_key == "perimeter_speed") {
invalidated |= m_print->invalidate_step(psWipeTower);
invalidated |= m_print->invalidate_step(psGCodeExport);
} else {
@ -1539,21 +1539,33 @@ void PrintObject::discover_vertical_shells()
// Finally expand the infill a bit to remove tiny gaps between solid infill and the other regions.
narrow_sparse_infill_region_radius - tiny_overlap_radius, ClipperLib::jtSquare);
Polygons object_volume;
Polygons internal_volume;
{
Polygons shrinked_bottom_slice = idx_layer > 0 ? to_polygons(m_layers[idx_layer - 1]->lslices) : Polygons{};
Polygons shrinked_upper_slice = (idx_layer + 1) < m_layers.size() ?
to_polygons(m_layers[idx_layer + 1]->lslices) :
Polygons{};
internal_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
object_volume = intersection(shrinked_bottom_slice, shrinked_upper_slice);
internal_volume = closing(polygonsInternal, SCALED_EPSILON);
}
// The opening operation may cause scattered tiny drops on the smooth parts of the model, filter them out
// The regularization operation may cause scattered tiny drops on the smooth parts of the model, filter them out
// If the region checks both following conditions, it is removed:
// 1. the area is very small,
// OR the area is quite small and it is fully wrapped in model (not visible)
// the in-model condition is there due to small sloping surfaces, e.g. top of the hull of the benchy
// 2. the area does not fully cover an internal polygon
// This is there mainly for a very thin parts, where the solid layers would be missing if the part area is quite small
regularized_shell.erase(std::remove_if(regularized_shell.begin(), regularized_shell.end(),
[&min_perimeter_infill_spacing, &internal_volume](const ExPolygon &p) {
return p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
(p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
diff(to_polygons(p), internal_volume).empty());
[&internal_volume, &min_perimeter_infill_spacing,
&object_volume](const ExPolygon &p) {
return (p.area() < min_perimeter_infill_spacing * scaled(1.5) ||
(p.area() < min_perimeter_infill_spacing * scaled(8.0) &&
diff(to_polygons(p), object_volume).empty())) &&
diff(internal_volume,
expand(to_polygons(p), min_perimeter_infill_spacing))
.size() >= internal_volume.size();
}),
regularized_shell.end());
}

View File

@ -127,35 +127,6 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin
}
}
template<class Cont> bool is_all_positive(const Cont &csgmesh)
{
bool is_all_pos =
std::all_of(csgmesh.begin(),
csgmesh.end(),
[](auto &part) {
return csg::get_operation(part) == csg::CSGType::Union;
});
return is_all_pos;
}
template<class Cont>
static indexed_triangle_set csgmesh_merge_positive_parts(const Cont &csgmesh)
{
indexed_triangle_set m;
for (auto &csgpart : csgmesh) {
auto op = csg::get_operation(csgpart);
const indexed_triangle_set * pmesh = csg::get_mesh(csgpart);
if (pmesh && op == csg::CSGType::Union) {
indexed_triangle_set mcpy = *pmesh;
its_transform(mcpy, csg::get_transform(csgpart), true);
its_merge(m, mcpy);
}
}
return m;
}
indexed_triangle_set SLAPrint::Steps::generate_preview_vdb(
SLAPrintObject &po, SLAPrintObjectStep step)
{

View File

@ -49,7 +49,7 @@ struct FontProp
using Align = std::pair<HorizontalAlign, VerticalAlign>;
// change pivot of text
// When not set, center is used and is not stored
Align align = Align(HorizontalAlign::left, VerticalAlign::top);
Align align = Align(HorizontalAlign::center, VerticalAlign::center);
[[deprecated("Back compatibility only, now it is stored EmbossProjection like depth")]]
float emboss;

View File

@ -2757,6 +2757,11 @@ bool TickCodeInfo::add_tick(const int tick, Type type, const int extruder, doubl
bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
{
// Save previously value of the tick before the call a Dialog from get_... functions,
// otherwise a background process can change ticks values and current iterator wouldn't be valid for the moment of a Dialog close
// and PS will crash (see https://github.com/prusa3d/PrusaSlicer/issues/10941)
TickCode changed_tick = *it;
std::string edited_value;
if (it->type == ColorChange)
edited_value = get_new_color(it->color);
@ -2768,7 +2773,10 @@ bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
if (edited_value.empty())
return false;
TickCode changed_tick = *it;
// Update iterator. For this moment its value can be invalid
if (it = ticks.find(changed_tick); it == ticks.end())
return false;
if (it->type == ColorChange) {
if (it->color == edited_value)
return false;

View File

@ -4076,7 +4076,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
model_object->invalidate_bounding_box();
}
}
else if (v->is_wipe_tower)
else if (m_selection.is_wipe_tower() && v->is_wipe_tower)
// Move a wipe tower proxy.
wipe_tower_origin = v->get_volume_offset();
}

View File

@ -503,6 +503,11 @@ void ObjectManipulation::Show(const bool show)
}
m_word_local_combo->Show(show_world_local_combo);
m_empty_str->Show(!show_world_local_combo);
m_skew_label->Show(m_show_skew);
m_reset_skew_button->Show(m_show_skew);
m_parent->Layout();
}
}
@ -795,15 +800,22 @@ void ObjectManipulation::update_reset_buttons_visibility()
m_mirror_warning_bitmap->SetBitmap(show_mirror ? m_manifold_warning_bmp.bmp() : wxNullBitmap);
m_mirror_warning_bitmap->SetMinSize(show_mirror ? m_manifold_warning_bmp.GetSize() : wxSize(0, 0));
m_mirror_warning_bitmap->SetToolTip(show_mirror ? _L("Left handed") : "");
m_reset_skew_button->Show(show_skew);
m_skew_label->Show(show_skew);
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar();
if (!panel.IsFrozen()) {
panel.Freeze();
panel.Layout();
panel.Thaw();
if (m_show_skew == show_skew)
get_sizer()->Layout();
else {
// Call sidebar layout only if it's really needed,
// it means, when we show/hide additional line for skew information
m_show_skew = show_skew;
m_reset_skew_button->Show(m_show_skew);
m_skew_label->Show(m_show_skew);
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar();
if (!panel.IsFrozen()) {
panel.Freeze();
panel.Layout();
panel.Thaw();
}
}
});
}

View File

@ -169,6 +169,7 @@ private:
bool m_is_enabled { true };
bool m_is_enabled_size_and_scale { true };
bool m_show_skew { false };
public:
ObjectManipulation(wxWindow* parent);

View File

@ -1014,39 +1014,6 @@ std::optional<wxString> get_installed_face_name(const std::optional<std::string>
return {}; // not installed
}
bool get_line_height_offset(/* const*/ StyleManager &style_manager, double &line_height_mm, double &line_offset_mm)
{
assert(style_manager.is_active_font());
if (!style_manager.is_active_font())
return false;
const auto &ffc = style_manager.get_font_file_with_cache();
assert(ffc.has_value());
if (!ffc.has_value())
return false;
const auto &ff_ptr = ffc.font_file;
assert(ff_ptr != nullptr);
if (ff_ptr == nullptr)
return false;
const FontProp &fp = style_manager.get_font_prop();
const FontFile &ff = *ff_ptr;
double third_ascent_shape_size = ff.infos[fp.collection_number.value_or(0)].ascent / 3.;
int line_height_shape_size = get_line_height(ff, fp); // In shape size
double scale = get_text_shape_scale(fp, ff);
line_offset_mm = third_ascent_shape_size * scale / 0.001; // TODO:fix constatnt SHAPE_SCALE
line_height_mm = line_height_shape_size * scale;
if (line_height_mm < 0)
return false;
// fix for bad filled ascent in font file
if (line_offset_mm <= 0)
line_offset_mm = line_height_mm / 3;
return true;
}
void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /* const*/ StyleManager &style_manager, unsigned count_lines)
{
const GLVolume *gl_volume_ptr = selection.get_first_volume();
@ -1102,13 +1069,24 @@ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /*
Transform3d mv_trafo = gl_volume.get_volume_transformation().get_matrix();
if (es.fix_3mf_tr.has_value())
mv_trafo = mv_trafo * (es.fix_3mf_tr->inverse());
FontProp::VerticalAlign align = style_manager.get_font_prop().align.second;
double line_height_mm, line_offset_mm;
if (!get_line_height_offset(style_manager, line_height_mm, line_offset_mm))
return;
text_lines.init(mv_trafo, volumes, align, line_height_mm, line_offset_mm, count_lines);
text_lines.init(mv_trafo, volumes, style_manager, count_lines);
}
void init_new_text_line(TextLinesModel &text_lines, const Transform3d& new_text_tr, const ModelObject& mo, /* const*/ StyleManager &style_manager)
{
// prepare volumes to slice
ModelVolumePtrs volumes;
volumes.reserve(mo.volumes.size());
for (ModelVolume *volume : mo.volumes) {
// only part could be surface for volumes
if (!volume->is_model_part())
continue;
volumes.push_back(volume);
}
unsigned count_lines = 1;
text_lines.init(new_text_tr, volumes, style_manager, count_lines);
}
}
void GLGizmoEmboss::reinit_text_lines(unsigned count_lines) {
@ -1516,17 +1494,17 @@ void GLGizmoEmboss::draw_text_input()
append_warning(_u8L("Text contains character glyph (represented by '?') unknown by font."));
const FontProp &prop = m_style_manager.get_font_prop();
if (prop.skew.has_value()) append_warning(_u8L("Text input doesn't show font skew."));
if (prop.skew.has_value()) append_warning(_u8L("Text input doesn't show font skew."));
if (prop.boldness.has_value()) append_warning(_u8L("Text input doesn't show font boldness."));
if (prop.line_gap.has_value())
append_warning(_u8L("Text input doesn't show gap between lines."));
if (prop.line_gap.has_value()) append_warning(_u8L("Text input doesn't show gap between lines."));
auto &ff = m_style_manager.get_font_file_with_cache();
float imgui_size = StyleManager::get_imgui_font_size(prop, *ff.font_file, scale);
if (imgui_size > StyleManager::max_imgui_font_size)
append_warning(_u8L("Too tall, diminished font height inside text input."));
if (imgui_size < StyleManager::min_imgui_font_size)
append_warning(_u8L("Too small, enlarged font height inside text input."));
if (prop.align.first == FontProp::HorizontalAlign::center || prop.align.first == FontProp::HorizontalAlign::right)
bool is_multiline = m_text_lines.get_lines().size() > 1;
if (is_multiline && (prop.align.first == FontProp::HorizontalAlign::center || prop.align.first == FontProp::HorizontalAlign::right))
append_warning(_u8L("Text doesn't show current horizontal alignment."));
}
@ -2646,10 +2624,8 @@ void GLGizmoEmboss::draw_advanced()
return;
}
StyleManager::Style &current_style = m_style_manager.get_style();
FontProp &current_prop = current_style.prop;
const FontFile::Info &font_info = ff.font_file->infos[current_prop.collection_number.value_or(0)];
FontProp &font_prop = m_style_manager.get_font_prop();
const FontFile::Info &font_info = get_font_info(*ff.font_file, font_prop);
#ifdef SHOW_FONT_FILE_PROPERTY
ImGui::SameLine();
int cache_size = ff.has_value()? (int)ff.cache->size() : 0;
@ -2679,6 +2655,7 @@ void GLGizmoEmboss::draw_advanced()
m_imgui->disabled_begin(!can_use_surface);
const bool *def_use_surface = stored_style ?
&stored_style->projection.use_surface : nullptr;
StyleManager::Style &current_style = m_style_manager.get_style();
bool &use_surface = current_style.projection.use_surface;
if (rev_checkbox(tr.use_surface, use_surface, def_use_surface,
_u8L("Revert using of model surface."))) {
@ -2689,7 +2666,6 @@ void GLGizmoEmboss::draw_advanced()
}
m_imgui->disabled_end(); // !can_use_surface
FontProp& font_prop = m_style_manager.get_font_prop();
bool &per_glyph = font_prop.per_glyph;
bool can_use_per_glyph = (per_glyph) ? true : // already used surface must have option to uncheck
!is_the_only_one_part;
@ -2771,6 +2747,7 @@ void GLGizmoEmboss::draw_advanced()
int half_ascent = font_info.ascent / 2;
int min_char_gap = -half_ascent;
int max_char_gap = half_ascent;
FontProp &current_prop = current_style.prop;
if (rev_slider(tr.char_gap, current_prop.char_gap, def_char_gap, _u8L("Revert gap between characters"),
min_char_gap, max_char_gap, units_fmt, _L("Distance between characters"))){
// Condition prevent recalculation when insertint out of limits value by imgui input
@ -2926,8 +2903,7 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", tr.collection.c_str());
ImGui::SameLine(m_gui_cfg->advanced_input_offset);
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
unsigned int selected = current_prop.collection_number.has_value() ?
*current_prop.collection_number : 0;
unsigned int selected = current_prop.collection_number.value_or(0);
if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) {
for (unsigned int i = 0; i < ff.font_file->infos.size(); ++i) {
ImGui::PushID(1 << (10 + i));
@ -2957,9 +2933,13 @@ void GLGizmoEmboss::draw_advanced()
if (ImGui::Button(_u8L("Set text to face camera").c_str())) {
assert(get_selected_volume(m_parent.get_selection()) == m_volume);
const Camera &cam = wxGetApp().plater()->get_camera();
FontProp& fp = m_style_manager.get_font_prop();
if (face_selected_volume_to_camera(cam, m_parent) &&
(use_surface || m_style_manager.get_font_prop().per_glyph))
(use_surface || fp.per_glyph)) {
if (fp.per_glyph)
reinit_text_lines();
process();
}
} else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", _u8L("Orient the text towards the camera.").c_str());
}

View File

@ -465,14 +465,17 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
bool MeshRaycaster::intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const
{
point = trafo.inverse() * point;
Transform3d trafo_inv = trafo.inverse();
Vec3d to = trafo_inv * (point + direction);
point = trafo_inv * point;
direction = (to-point).normalized();
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
std::vector<AABBMesh::hit_result> neg_hits = m_emesh.query_ray_hits(point, -direction);
return !hits.empty() && !neg_hits.empty();
return !hits.empty() || !neg_hits.empty();
}

View File

@ -187,7 +187,9 @@ public:
const AABBMesh &get_aabb_mesh() const { return m_emesh; }
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
// Given a point and direction in world coords, returns whether the respective line
// intersects the mesh if it is transformed into world by trafo.
bool intersects_line(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
// Given a vector of points in woorld coordinates, this returns vector
// of indices of points that are visible (i.e. not cut by clipping plane

View File

@ -1277,9 +1277,11 @@ void Sidebar::show_info_sizer()
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
ModelObjectPtrs objects = p->plater->model().objects;
int obj_idx = selection.get_object_idx();
const int obj_idx = selection.get_object_idx();
const int inst_idx = selection.get_instance_idx();
if (m_mode < comExpert || objects.empty() || obj_idx < 0 || int(objects.size()) <= obj_idx ||
inst_idx < 0 || int(objects[obj_idx]->instances.size()) <= inst_idx ||
objects[obj_idx]->volumes.empty() || // hack to avoid crash when deleting the last object on the bed
(selection.is_single_full_object() && objects[obj_idx]->instances.size()> 1) ||
!(selection.is_single_full_instance() || selection.is_single_volume())) {
@ -1289,9 +1291,6 @@ void Sidebar::show_info_sizer()
const ModelObject* model_object = objects[obj_idx];
int inst_idx = selection.get_instance_idx();
assert(inst_idx >= 0);
bool imperial_units = wxGetApp().app_config->get_bool("use_inches");
double koef = imperial_units ? ObjectManipulation::mm_to_in : 1.0f;
@ -6506,9 +6505,12 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits);
if (csg::check_csgmesh_booleans(range(csgmesh)) == csgmesh.end()) {
auto csgrange = range(csgmesh);
if (csg::is_all_positive(csgrange)) {
mesh = TriangleMesh{csg::csgmesh_merge_positive_parts(csgrange)};
} else if (csg::check_csgmesh_booleans(csgrange) == csgrange.end()) {
try {
auto cgalm = csg::perform_csgmesh_booleans(range(csgmesh));
auto cgalm = csg::perform_csgmesh_booleans(csgrange);
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*cgalm);
} catch (...) {}
}
@ -7266,7 +7268,9 @@ void Plater::force_filament_cb_update()
// Update preset comboboxes on sidebar and filaments tab
p->sidebar->update_presets(Preset::TYPE_FILAMENT);
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->select_preset(wxGetApp().preset_bundle->filaments.get_selected_preset_name());
TabFilament* tab = dynamic_cast<TabFilament*>(wxGetApp().get_tab(Preset::TYPE_FILAMENT));
tab->select_preset(wxGetApp().preset_bundle->extruders_filaments[tab->get_active_extruder()].get_selected_preset_name());
}
void Plater::force_print_bed_update()

View File

@ -253,18 +253,37 @@ GLModel::Geometry create_geometry(const TextLines &lines)
void TextLinesModel::init(const Transform3d &text_tr,
const ModelVolumePtrs &volumes_to_slice,
FontProp::VerticalAlign align,
double line_height,
double offset,
/*const*/ Emboss::StyleManager &style_manager,
unsigned count_lines)
{
assert(style_manager.is_active_font());
if (!style_manager.is_active_font())
return;
const auto &ffc = style_manager.get_font_file_with_cache();
assert(ffc.has_value());
if (!ffc.has_value())
return;
const auto &ff_ptr = ffc.font_file;
assert(ff_ptr != nullptr);
if (ff_ptr == nullptr)
return;
const FontFile &ff = *ff_ptr;
const FontProp &fp = style_manager.get_font_prop();
FontProp::VerticalAlign align = fp.align.second;
double line_height_mm = calc_line_height_in_mm(ff, fp);
assert(line_height_mm > 0);
if (line_height_mm <= 0)
return;
m_model.reset();
m_lines.clear();
double first_line_center = offset + this->offset + get_align_y_offset(align, count_lines, line_height);
double first_line_center = this->offset + line_height_mm / 3 + get_align_y_offset_in_mm(align, count_lines, ff, fp);
std::vector<float> line_centers(count_lines);
for (size_t i = 0; i < count_lines; ++i)
line_centers[i] = static_cast<float>(first_line_center - i * line_height);
line_centers[i] = static_cast<float>(first_line_center - i * line_height_mm);
// contour transformation
Transform3d c_trafo = text_tr * get_rotation();
@ -283,6 +302,24 @@ void TextLinesModel::init(const Transform3d &text_tr,
}
}
// fix for text line out of object
// When move text close to edge - line center could be out of object
for (Polygons &contours: line_contours) {
if (!contours.empty())
continue;
// use line center at zero, there should be some contour.
float line_center = 0.f;
for (const ModelVolume *volume : volumes_to_slice) {
MeshSlicingParams slicing_params;
slicing_params.trafo = c_trafo_inv * volume->get_matrix();
const Polygons polys = Slic3r::slice_mesh(volume->mesh().its, line_center, slicing_params);
if (polys.empty())
continue;
contours.insert(contours.end(), polys.begin(), polys.end());
}
}
m_lines = select_closest_contour(line_contours);
assert(m_lines.size() == count_lines);
assert(line_centers.size() == count_lines);
@ -337,9 +374,9 @@ void TextLinesModel::render(const Transform3d &text_world)
shader->stop_using();
}
double TextLinesModel::calc_line_height(const Slic3r::Emboss::FontFile &ff, const FontProp &fp)
double TextLinesModel::calc_line_height_in_mm(const Slic3r::Emboss::FontFile &ff, const FontProp &fp)
{
int line_height = Emboss::get_line_height(ff, fp); // In shape size
double scale = Emboss::get_text_shape_scale(fp, ff);
int line_height = Slic3r::Emboss::get_line_height(ff, fp); // In shape size
double scale = Slic3r::Emboss::get_text_shape_scale(fp, ff);
return line_height * scale;
}

View File

@ -6,6 +6,7 @@
#include <libslic3r/Point.hpp>
#include <libslic3r/Emboss.hpp>
#include "slic3r/GUI/GLModel.hpp"
#include "slic3r/Utils/EmbossStyleManager.hpp"
namespace Slic3r {
class ModelVolume;
@ -24,11 +25,9 @@ public:
/// </summary>
/// <param name="text_tr">Transformation of text volume inside object (aka inside of instance)</param>
/// <param name="volumes_to_slice">Vector of volumes to be sliced</param>
/// <param name="align">Vertical (Y) align of the text</param>
/// <param name="line_height">Distance between lines [in mm]</param>
/// <param name="line_height">Offset from baseline [in mm]</param>
/// <param name="count_lines">Count lines(slices over volumes)</param>
void init(const Transform3d &text_tr, const ModelVolumePtrs& volumes_to_slice, FontProp::VerticalAlign align, double line_height, double offset, unsigned count_lines);
/// <param name="style_manager">Contain Font file, size and align</param>
/// <param name="count_lines">Count lines of embossed text(for veritcal alignment)</param>
void init(const Transform3d &text_tr, const ModelVolumePtrs &volumes_to_slice, /*const*/ Emboss::StyleManager &style_manager, unsigned count_lines);
void render(const Transform3d &text_world);
@ -36,7 +35,7 @@ public:
void reset() { m_model.reset(); m_lines.clear(); }
const Slic3r::Emboss::TextLines &get_lines() const { return m_lines; }
static double calc_line_height(const Slic3r::Emboss::FontFile& ff, const FontProp& fp); // return lineheight in mm
static double calc_line_height_in_mm(const Slic3r::Emboss::FontFile& ff, const FontProp& fp); // return lineheight in mm
private:
Slic3r::Emboss::TextLines m_lines;

View File

@ -295,25 +295,6 @@ void StyleManager::clear_glyphs_cache()
void StyleManager::clear_imgui_font() { m_style_cache.atlas.Clear(); }
#include "slic3r/GUI/TextLines.hpp"
double StyleManager::get_line_height()
{
assert(is_active_font());
if (!is_active_font())
return -1;
const auto &ffc = get_font_file_with_cache();
assert(ffc.has_value());
if (!ffc.has_value())
return -1;
const auto &ff_ptr = ffc.font_file;
assert(ff_ptr != nullptr);
if (ff_ptr == nullptr)
return -1;
const FontProp &fp = get_font_prop();
const FontFile &ff = *ff_ptr;
return TextLinesModel::calc_line_height(ff, fp);
}
ImFont *StyleManager::get_imgui_font()
{
if (!is_active_font()) return nullptr;
@ -428,12 +409,10 @@ float StyleManager::min_imgui_font_size = 18.f;
float StyleManager::max_imgui_font_size = 60.f;
float StyleManager::get_imgui_font_size(const FontProp &prop, const FontFile &file, double scale)
{
const auto &cn = prop.collection_number;
unsigned int font_index = (cn.has_value()) ? *cn : 0;
const auto &font_info = file.infos[font_index];
const FontFile::Info& info = get_font_info(file, prop);
// coeficient for convert line height to font size
float c1 = (font_info.ascent - font_info.descent + font_info.linegap) /
(float) font_info.unit_per_em;
float c1 = (info.ascent - info.descent + info.linegap) /
(float) info.unit_per_em;
// The point size is defined as 1/72 of the Anglo-Saxon inch (25.4 mm):
// It is approximately 0.0139 inch or 352.8 um.
@ -469,17 +448,12 @@ ImFont *StyleManager::create_imgui_font(const std::string &text, double scale)
ImFontConfig font_config;
// TODO: start using merge mode
//font_config.MergeMode = true;
unsigned int font_index = font_prop.collection_number.value_or(0);
const auto &font_info = font_file.infos[font_index];
if (font_prop.char_gap.has_value()) {
float coef = font_size / (double) font_info.unit_per_em;
font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap);
}
if (font_prop.line_gap.has_value()) {
float coef = font_size / (double) font_info.unit_per_em;
font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap);
}
int unit_per_em = get_font_info(font_file, font_prop).unit_per_em;
float coef = font_size / (double) unit_per_em;
if (font_prop.char_gap.has_value())
font_config.GlyphExtraSpacing.x = coef * (*font_prop.char_gap);
if (font_prop.line_gap.has_value())
font_config.GlyphExtraSpacing.y = coef * (*font_prop.line_gap);
font_config.FontDataOwnedByAtlas = false;

View File

@ -108,10 +108,6 @@ public:
// remove cached imgui font for actual selected font
void clear_imgui_font();
// calculate line height
// not const because access to font file which could be created.
double get_line_height(); /* const */
// getters for private data
const Style *get_stored_style() const;