Merge remote-tracking branch 'remotes/prusa/master' into masterPE

This commit is contained in:
supermerill 2019-01-03 14:47:34 +01:00
commit 72d828cf74
119 changed files with 6602 additions and 3679 deletions

View File

@ -42,7 +42,24 @@ if (MSVC)
add_compile_options(-bigobj -Zm316) add_compile_options(-bigobj -Zm316)
endif () endif ()
message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
# Display and check CMAKE_PREFIX_PATH
message(STATUS "SLIC3R_STATIC: ${SLIC3R_STATIC}")
if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "")
message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH} (from cache or command line)")
set(PREFIX_PATH_CHECK ${CMAKE_PREFIX_PATH})
elseif (NOT "$ENV{CMAKE_PREFIX_PATH}" STREQUAL "")
message(STATUS "CMAKE_PREFIX_PATH: $ENV{CMAKE_PREFIX_PATH} (from environment)")
set(PREFIX_PATH_CHECK $ENV{CMAKE_PREFIX_PATH})
else ()
message(STATUS "CMAKE_PREFIX_PATH: (default)")
endif ()
foreach (DIR ${PREFIX_PATH_CHECK})
if (NOT EXISTS "${DIR}")
message(WARNING "CMAKE_PREFIX_PATH element doesn't exist: ${DIR}")
endif ()
endforeach ()
# Add our own cmake module path. # Add our own cmake module path.
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,6 +1,21 @@
min_slic3r_version = 1.42.0-alpha min_slic3r_version = 1.42.0-alpha
0.4.0-alpha3 Update of SLA profiles
0.4.0-alpha2 First SLA profiles 0.4.0-alpha2 First SLA profiles
min_slic3r_version = 1.41.1
0.3.3 Prusament PETG released
0.3.2 New MK2.5 and MK3 FW versions
0.3.1 New MK2.5 and MK3 FW versions
0.3.0 New MK2.5 and MK3 FW version
min_slic3r_version = 1.41.0-alpha min_slic3r_version = 1.41.0-alpha
0.2.9 New MK2.5 and MK3 FW versions
0.2.8 New MK2.5 and MK3 FW version
min_slic3r_version = 1.41.1
0.2.7 New MK2.5 and MK3 FW version
0.2.6 Added MMU2 MK2.5 settings
min_slic3r_version = 1.41.0-alpha
0.2.5 Prusament is out - added prusament settings
0.2.4 Added soluble support profiles for MMU2
0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit
0.2.2 Edited MMU2 Single mode purge line 0.2.2 Edited MMU2 Single mode purge line
0.2.1 Added PET and BVOH settings for MMU2 0.2.1 Added PET and BVOH settings for MMU2
0.2.0-beta5 Fixed MMU1 ramming parameters 0.2.0-beta5 Fixed MMU1 ramming parameters

View File

@ -5,7 +5,7 @@
name = Prusa Research name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs. # Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the Slic3r configuration to be downgraded. # This means, the server may force the Slic3r configuration to be downgraded.
config_version = 0.4.0-alpha2 config_version = 0.4.0-alpha3
# Where to get the updates from? # Where to get the updates from?
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
@ -18,30 +18,37 @@ config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/ma
[printer_model:MK3] [printer_model:MK3]
name = Original Prusa i3 MK3 name = Original Prusa i3 MK3
variants = 0.4; 0.25; 0.6 variants = 0.4; 0.25; 0.6
technology = FFF
[printer_model:MK2.5] [printer_model:MK2.5]
name = Original Prusa i3 MK2.5 name = Original Prusa i3 MK2.5
variants = 0.4; 0.25; 0.6 variants = 0.4; 0.25; 0.6
technology = FFF
[printer_model:MK2S] [printer_model:MK2S]
name = Original Prusa i3 MK2/S name = Original Prusa i3 MK2/S
variants = 0.4; 0.25; 0.6 variants = 0.4; 0.25; 0.6
technology = FFF
[printer_model:MK3MMU2] [printer_model:MK3MMU2]
name = Original Prusa i3 MK3 MMU 2.0 name = Original Prusa i3 MK3 MMU 2.0
variants = 0.4 variants = 0.4
technology = FFF
[printer_model:MK2SMM] [printer_model:MK2SMM]
name = Original Prusa i3 MK2/S MMU 1.0 name = Original Prusa i3 MK2/S MMU 1.0
variants = 0.4; 0.6 variants = 0.4; 0.6
technology = FFF
[printer_model:MK2.5MMU2] [printer_model:MK2.5MMU2]
name = Original Prusa i3 MK2.5 MMU 2.0 name = Original Prusa i3 MK2.5 MMU 2.0
variants = 0.4 variants = 0.4
technology = FFF
[printer_model:SL1] [printer_model:SL1]
name = Original Prusa SL1 name = Original Prusa SL1
variants = default; dummy variants = default
technology = SLA
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -1140,19 +1147,132 @@ min_fan_speed = 100
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
temperature = 220 temperature = 220
[sla_material:*common*] [sla_print:*common*]
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
layer_height = 0.05 layer_height = 0.05
initial_layer_height = 0.3 output_filename_format = [input_filename_base].dwz
pad_edge_radius = 0.5
pad_enable = 1
pad_max_merge_distance = 50
pad_wall_height = 3
pad_wall_thickness = 1
support_base_diameter = 3
support_base_height = 0.5
support_critical_angle = 45
support_density_at_45 = 250
support_density_at_horizontal = 500
support_head_front_diameter = 0.4
support_head_penetration = 0.4
support_head_width = 3
support_max_bridge_length = 10
support_minimal_z = 0
support_object_elevation = 5
support_pillar_diameter = 1
support_pillar_widening_factor = 0
supports_enable = 1
[sla_print:0.025 UltraDetail]
inherits = *common*
layer_height = 0.025
support_head_width = 2
[sla_print:0.035 Detail]
inherits = *common*
layer_height = 0.035
[sla_print:0.05 Normal]
inherits = *common*
layer_height = 0.05
[sla_print:0.1 Fast]
inherits = *common*
layer_height = 0.1
########### Materials 0.025
[sla_material:*common 0.05*]
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
compatible_prints_condition = layer_height == 0.05
exposure_time = 12
initial_exposure_time = 45
initial_layer_height = 0.5
material_correction_curing = 1,1,1
material_correction_printing = 1,1,1
material_notes =
[sla_material:*common 0.025*]
inherits = *common 0.05*
compatible_prints_condition = layer_height == 0.025
exposure_time = 10 exposure_time = 10
initial_exposure_time = 15 initial_exposure_time = 35
material_correction_printing = 1, 1, 1
material_correction_curing = 1, 1, 1
[sla_material:Material 1] [sla_material:*common 0.035*]
inherits = *common* inherits = *common 0.05*
compatible_prints_condition = layer_height == 0.035
exposure_time = 13
initial_exposure_time = 40
[sla_material:Material 2] [sla_material:*common 0.1*]
inherits = *common* inherits = *common 0.05*
compatible_prints_condition = layer_height == 0.1
exposure_time = 20
initial_exposure_time = 90
########### Materials 0.025
[sla_material:Jamg He Transparent Clear 0.025]
inherits = *common 0.025*
[sla_material:Jamg He Transparent Green 0.025]
inherits = *common 0.025*
[sla_material:Jamg He Transparent Orange 0.025]
inherits = *common 0.025*
[sla_material:Jamg He Transparent Red 0.025]
inherits = *common 0.025*
########### Materials 0.05
[sla_material:Jamg He Transparent Clear 0.05]
inherits = *common 0.05*
[sla_material:Jamg He Transparent Green 0.05]
inherits = *common 0.05*
[sla_material:Jamg He Transparent Orange 0.05]
inherits = *common 0.05*
[sla_material:Jamg He Transparent Red 0.05]
inherits = *common 0.05*
########### Materials 0.035
[sla_material:Jamg He Transparent Clear 0.035]
inherits = *common 0.035*
[sla_material:Jamg He Transparent Green 0.035]
inherits = *common 0.035*
[sla_material:Jamg He Transparent Orange 0.035]
inherits = *common 0.035*
[sla_material:Jamg He Transparent Red 0.035]
inherits = *common 0.035*
########### Materials 0.1
[sla_material:Jamg He Transparent Clear 0.1]
inherits = *common 0.1*
[sla_material:Jamg He Transparent Green 0.1]
inherits = *common 0.1*
[sla_material:Jamg He Transparent Orange 0.1]
inherits = *common 0.1*
[sla_material:Jamg He Transparent Red 0.1]
inherits = *common 0.1*
[printer:*common*] [printer:*common*]
printer_technology = FFF printer_technology = FFF
@ -1470,21 +1590,20 @@ end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG
printer_technology = SLA printer_technology = SLA
printer_model = SL1 printer_model = SL1
printer_variant = default printer_variant = default
default_sla_material_profile = Material 1 default_sla_material_profile = Jamg He Transparent Green 0.05
bed_shape = 0x0,150x0,150x100,0x100 default_sla_print_profile = 0.05 Normal
max_print_height = 100 bed_shape = 0.98x1.02,119.98x1.02,119.98x68.02,0.98x68.02
display_width = 150 display_height = 68.04
display_height = 100 display_orientation = portrait
display_pixels_x = 2000 display_pixels_x = 2560
display_pixels_y = 1000 display_pixels_y = 1440
display_width = 120.96
max_print_height = 150
printer_correction = 1,1,1 printer_correction = 1,1,1
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_PRUSA3D\nPRINTER_MODEL_SL1\n
[printer:Original Prusa SL1 dummy]
inherits = Original Prusa SL1
printer_variant = dummy
default_sla_material_profile = Material 2
# The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer. # The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer.
[obsolete_presets] [obsolete_presets]
print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2" print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2"
filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm" filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"
printer="Original Prusa SL1 dummy"

View File

@ -0,0 +1,53 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSE_EXTRA_MODULE_H
#define EIGEN_SPARSE_EXTRA_MODULE_H
#include "../../Eigen/Sparse"
#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
#include <vector>
#include <map>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <fstream>
#include <sstream>
#ifdef EIGEN_GOOGLEHASH_SUPPORT
#include <google/dense_hash_map>
#endif
/**
* \defgroup SparseExtra_Module SparseExtra module
*
* This module contains some experimental features extending the sparse module.
*
* \code
* #include <Eigen/SparseExtra>
* \endcode
*/
#include "src/SparseExtra/DynamicSparseMatrix.h"
#include "src/SparseExtra/BlockOfDynamicSparseMatrix.h"
#include "src/SparseExtra/RandomSetter.h"
#include "src/SparseExtra/MarketIO.h"
#if !defined(_WIN32)
#include <dirent.h>
#include "src/SparseExtra/MatrixMarketIterator.h"
#endif
#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
#endif // EIGEN_SPARSE_EXTRA_MODULE_H

View File

@ -0,0 +1,122 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSE_BLOCKFORDYNAMICMATRIX_H
#define EIGEN_SPARSE_BLOCKFORDYNAMICMATRIX_H
namespace Eigen {
#if 0
// NOTE Have to be reimplemented as a specialization of BlockImpl< DynamicSparseMatrix<_Scalar, _Options, _Index>, ... >
// See SparseBlock.h for an example
/***************************************************************************
* specialisation for DynamicSparseMatrix
***************************************************************************/
template<typename _Scalar, int _Options, typename _Index, int Size>
class SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options, _Index>, Size>
: public SparseMatrixBase<SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options, _Index>, Size> >
{
typedef DynamicSparseMatrix<_Scalar, _Options, _Index> MatrixType;
public:
enum { IsRowMajor = internal::traits<SparseInnerVectorSet>::IsRowMajor };
EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet)
class InnerIterator: public MatrixType::InnerIterator
{
public:
inline InnerIterator(const SparseInnerVectorSet& xpr, Index outer)
: MatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
{}
inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
protected:
Index m_outer;
};
inline SparseInnerVectorSet(const MatrixType& matrix, Index outerStart, Index outerSize)
: m_matrix(matrix), m_outerStart(outerStart), m_outerSize(outerSize)
{
eigen_assert( (outerStart>=0) && ((outerStart+outerSize)<=matrix.outerSize()) );
}
inline SparseInnerVectorSet(const MatrixType& matrix, Index outer)
: m_matrix(matrix), m_outerStart(outer), m_outerSize(Size)
{
eigen_assert(Size!=Dynamic);
eigen_assert( (outer>=0) && (outer<matrix.outerSize()) );
}
template<typename OtherDerived>
inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
{
if (IsRowMajor != ((OtherDerived::Flags&RowMajorBit)==RowMajorBit))
{
// need to transpose => perform a block evaluation followed by a big swap
DynamicSparseMatrix<Scalar,IsRowMajor?RowMajorBit:0> aux(other);
*this = aux.markAsRValue();
}
else
{
// evaluate/copy vector per vector
for (Index j=0; j<m_outerSize.value(); ++j)
{
SparseVector<Scalar,IsRowMajor ? RowMajorBit : 0> aux(other.innerVector(j));
m_matrix.const_cast_derived()._data()[m_outerStart+j].swap(aux._data());
}
}
return *this;
}
inline SparseInnerVectorSet& operator=(const SparseInnerVectorSet& other)
{
return operator=<SparseInnerVectorSet>(other);
}
Index nonZeros() const
{
Index count = 0;
for (Index j=0; j<m_outerSize.value(); ++j)
count += m_matrix._data()[m_outerStart+j].size();
return count;
}
const Scalar& lastCoeff() const
{
EIGEN_STATIC_ASSERT_VECTOR_ONLY(SparseInnerVectorSet);
eigen_assert(m_matrix.data()[m_outerStart].size()>0);
return m_matrix.data()[m_outerStart].vale(m_matrix.data()[m_outerStart].size()-1);
}
// template<typename Sparse>
// inline SparseInnerVectorSet& operator=(const SparseMatrixBase<OtherDerived>& other)
// {
// return *this;
// }
EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
protected:
const typename MatrixType::Nested m_matrix;
Index m_outerStart;
const internal::variable_if_dynamic<Index, Size> m_outerSize;
};
#endif
} // end namespace Eigen
#endif // EIGEN_SPARSE_BLOCKFORDYNAMICMATRIX_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,392 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_DYNAMIC_SPARSEMATRIX_H
#define EIGEN_DYNAMIC_SPARSEMATRIX_H
namespace Eigen {
/** \deprecated use a SparseMatrix in an uncompressed mode
*
* \class DynamicSparseMatrix
*
* \brief A sparse matrix class designed for matrix assembly purpose
*
* \param _Scalar the scalar type, i.e. the type of the coefficients
*
* Unlike SparseMatrix, this class provides a much higher degree of flexibility. In particular, it allows
* random read/write accesses in log(rho*outer_size) where \c rho is the probability that a coefficient is
* nonzero and outer_size is the number of columns if the matrix is column-major and the number of rows
* otherwise.
*
* Internally, the data are stored as a std::vector of compressed vector. The performances of random writes might
* decrease as the number of nonzeros per inner-vector increase. In practice, we observed very good performance
* till about 100 nonzeros/vector, and the performance remains relatively good till 500 nonzeros/vectors.
*
* \see SparseMatrix
*/
namespace internal {
template<typename _Scalar, int _Options, typename _StorageIndex>
struct traits<DynamicSparseMatrix<_Scalar, _Options, _StorageIndex> >
{
typedef _Scalar Scalar;
typedef _StorageIndex StorageIndex;
typedef Sparse StorageKind;
typedef MatrixXpr XprKind;
enum {
RowsAtCompileTime = Dynamic,
ColsAtCompileTime = Dynamic,
MaxRowsAtCompileTime = Dynamic,
MaxColsAtCompileTime = Dynamic,
Flags = _Options | NestByRefBit | LvalueBit,
CoeffReadCost = NumTraits<Scalar>::ReadCost,
SupportedAccessPatterns = OuterRandomAccessPattern
};
};
}
template<typename _Scalar, int _Options, typename _StorageIndex>
class DynamicSparseMatrix
: public SparseMatrixBase<DynamicSparseMatrix<_Scalar, _Options, _StorageIndex> >
{
typedef SparseMatrixBase<DynamicSparseMatrix> Base;
using Base::convert_index;
public:
EIGEN_SPARSE_PUBLIC_INTERFACE(DynamicSparseMatrix)
// FIXME: why are these operator already alvailable ???
// EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, +=)
// EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, -=)
typedef MappedSparseMatrix<Scalar,Flags> Map;
using Base::IsRowMajor;
using Base::operator=;
enum {
Options = _Options
};
protected:
typedef DynamicSparseMatrix<Scalar,(Flags&~RowMajorBit)|(IsRowMajor?RowMajorBit:0), StorageIndex> TransposedSparseMatrix;
Index m_innerSize;
std::vector<internal::CompressedStorage<Scalar,StorageIndex> > m_data;
public:
inline Index rows() const { return IsRowMajor ? outerSize() : m_innerSize; }
inline Index cols() const { return IsRowMajor ? m_innerSize : outerSize(); }
inline Index innerSize() const { return m_innerSize; }
inline Index outerSize() const { return convert_index(m_data.size()); }
inline Index innerNonZeros(Index j) const { return m_data[j].size(); }
std::vector<internal::CompressedStorage<Scalar,StorageIndex> >& _data() { return m_data; }
const std::vector<internal::CompressedStorage<Scalar,StorageIndex> >& _data() const { return m_data; }
/** \returns the coefficient value at given position \a row, \a col
* This operation involes a log(rho*outer_size) binary search.
*/
inline Scalar coeff(Index row, Index col) const
{
const Index outer = IsRowMajor ? row : col;
const Index inner = IsRowMajor ? col : row;
return m_data[outer].at(inner);
}
/** \returns a reference to the coefficient value at given position \a row, \a col
* This operation involes a log(rho*outer_size) binary search. If the coefficient does not
* exist yet, then a sorted insertion into a sequential buffer is performed.
*/
inline Scalar& coeffRef(Index row, Index col)
{
const Index outer = IsRowMajor ? row : col;
const Index inner = IsRowMajor ? col : row;
return m_data[outer].atWithInsertion(inner);
}
class InnerIterator;
class ReverseInnerIterator;
void setZero()
{
for (Index j=0; j<outerSize(); ++j)
m_data[j].clear();
}
/** \returns the number of non zero coefficients */
Index nonZeros() const
{
Index res = 0;
for (Index j=0; j<outerSize(); ++j)
res += m_data[j].size();
return res;
}
void reserve(Index reserveSize = 1000)
{
if (outerSize()>0)
{
Index reserveSizePerVector = (std::max)(reserveSize/outerSize(),Index(4));
for (Index j=0; j<outerSize(); ++j)
{
m_data[j].reserve(reserveSizePerVector);
}
}
}
/** Does nothing: provided for compatibility with SparseMatrix */
inline void startVec(Index /*outer*/) {}
/** \returns a reference to the non zero coefficient at position \a row, \a col assuming that:
* - the nonzero does not already exist
* - the new coefficient is the last one of the given inner vector.
*
* \sa insert, insertBackByOuterInner */
inline Scalar& insertBack(Index row, Index col)
{
return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row);
}
/** \sa insertBack */
inline Scalar& insertBackByOuterInner(Index outer, Index inner)
{
eigen_assert(outer<Index(m_data.size()) && inner<m_innerSize && "out of range");
eigen_assert(((m_data[outer].size()==0) || (m_data[outer].index(m_data[outer].size()-1)<inner))
&& "wrong sorted insertion");
m_data[outer].append(0, inner);
return m_data[outer].value(m_data[outer].size()-1);
}
inline Scalar& insert(Index row, Index col)
{
const Index outer = IsRowMajor ? row : col;
const Index inner = IsRowMajor ? col : row;
Index startId = 0;
Index id = static_cast<Index>(m_data[outer].size()) - 1;
m_data[outer].resize(id+2,1);
while ( (id >= startId) && (m_data[outer].index(id) > inner) )
{
m_data[outer].index(id+1) = m_data[outer].index(id);
m_data[outer].value(id+1) = m_data[outer].value(id);
--id;
}
m_data[outer].index(id+1) = inner;
m_data[outer].value(id+1) = 0;
return m_data[outer].value(id+1);
}
/** Does nothing: provided for compatibility with SparseMatrix */
inline void finalize() {}
/** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */
void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision())
{
for (Index j=0; j<outerSize(); ++j)
m_data[j].prune(reference,epsilon);
}
/** Resize the matrix without preserving the data (the matrix is set to zero)
*/
void resize(Index rows, Index cols)
{
const Index outerSize = IsRowMajor ? rows : cols;
m_innerSize = convert_index(IsRowMajor ? cols : rows);
setZero();
if (Index(m_data.size()) != outerSize)
{
m_data.resize(outerSize);
}
}
void resizeAndKeepData(Index rows, Index cols)
{
const Index outerSize = IsRowMajor ? rows : cols;
const Index innerSize = IsRowMajor ? cols : rows;
if (m_innerSize>innerSize)
{
// remove all coefficients with innerCoord>=innerSize
// TODO
//std::cerr << "not implemented yet\n";
exit(2);
}
if (m_data.size() != outerSize)
{
m_data.resize(outerSize);
}
}
/** The class DynamicSparseMatrix is deprectaed */
EIGEN_DEPRECATED inline DynamicSparseMatrix()
: m_innerSize(0), m_data(0)
{
eigen_assert(innerSize()==0 && outerSize()==0);
}
/** The class DynamicSparseMatrix is deprectaed */
EIGEN_DEPRECATED inline DynamicSparseMatrix(Index rows, Index cols)
: m_innerSize(0)
{
resize(rows, cols);
}
/** The class DynamicSparseMatrix is deprectaed */
template<typename OtherDerived>
EIGEN_DEPRECATED explicit inline DynamicSparseMatrix(const SparseMatrixBase<OtherDerived>& other)
: m_innerSize(0)
{
Base::operator=(other.derived());
}
inline DynamicSparseMatrix(const DynamicSparseMatrix& other)
: Base(), m_innerSize(0)
{
*this = other.derived();
}
inline void swap(DynamicSparseMatrix& other)
{
//EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n");
std::swap(m_innerSize, other.m_innerSize);
//std::swap(m_outerSize, other.m_outerSize);
m_data.swap(other.m_data);
}
inline DynamicSparseMatrix& operator=(const DynamicSparseMatrix& other)
{
if (other.isRValue())
{
swap(other.const_cast_derived());
}
else
{
resize(other.rows(), other.cols());
m_data = other.m_data;
}
return *this;
}
/** Destructor */
inline ~DynamicSparseMatrix() {}
public:
/** \deprecated
* Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */
EIGEN_DEPRECATED void startFill(Index reserveSize = 1000)
{
setZero();
reserve(reserveSize);
}
/** \deprecated use insert()
* inserts a nonzero coefficient at given coordinates \a row, \a col and returns its reference assuming that:
* 1 - the coefficient does not exist yet
* 2 - this the coefficient with greater inner coordinate for the given outer coordinate.
* In other words, assuming \c *this is column-major, then there must not exists any nonzero coefficient of coordinates
* \c i \c x \a col such that \c i >= \a row. Otherwise the matrix is invalid.
*
* \see fillrand(), coeffRef()
*/
EIGEN_DEPRECATED Scalar& fill(Index row, Index col)
{
const Index outer = IsRowMajor ? row : col;
const Index inner = IsRowMajor ? col : row;
return insertBack(outer,inner);
}
/** \deprecated use insert()
* Like fill() but with random inner coordinates.
* Compared to the generic coeffRef(), the unique limitation is that we assume
* the coefficient does not exist yet.
*/
EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col)
{
return insert(row,col);
}
/** \deprecated use finalize()
* Does nothing. Provided for compatibility with SparseMatrix. */
EIGEN_DEPRECATED void endFill() {}
# ifdef EIGEN_DYNAMICSPARSEMATRIX_PLUGIN
# include EIGEN_DYNAMICSPARSEMATRIX_PLUGIN
# endif
};
template<typename Scalar, int _Options, typename _StorageIndex>
class DynamicSparseMatrix<Scalar,_Options,_StorageIndex>::InnerIterator : public SparseVector<Scalar,_Options,_StorageIndex>::InnerIterator
{
typedef typename SparseVector<Scalar,_Options,_StorageIndex>::InnerIterator Base;
public:
InnerIterator(const DynamicSparseMatrix& mat, Index outer)
: Base(mat.m_data[outer]), m_outer(outer)
{}
inline Index row() const { return IsRowMajor ? m_outer : Base::index(); }
inline Index col() const { return IsRowMajor ? Base::index() : m_outer; }
inline Index outer() const { return m_outer; }
protected:
const Index m_outer;
};
template<typename Scalar, int _Options, typename _StorageIndex>
class DynamicSparseMatrix<Scalar,_Options,_StorageIndex>::ReverseInnerIterator : public SparseVector<Scalar,_Options,_StorageIndex>::ReverseInnerIterator
{
typedef typename SparseVector<Scalar,_Options,_StorageIndex>::ReverseInnerIterator Base;
public:
ReverseInnerIterator(const DynamicSparseMatrix& mat, Index outer)
: Base(mat.m_data[outer]), m_outer(outer)
{}
inline Index row() const { return IsRowMajor ? m_outer : Base::index(); }
inline Index col() const { return IsRowMajor ? Base::index() : m_outer; }
inline Index outer() const { return m_outer; }
protected:
const Index m_outer;
};
namespace internal {
template<typename _Scalar, int _Options, typename _StorageIndex>
struct evaluator<DynamicSparseMatrix<_Scalar,_Options,_StorageIndex> >
: evaluator_base<DynamicSparseMatrix<_Scalar,_Options,_StorageIndex> >
{
typedef _Scalar Scalar;
typedef DynamicSparseMatrix<_Scalar,_Options,_StorageIndex> SparseMatrixType;
typedef typename SparseMatrixType::InnerIterator InnerIterator;
typedef typename SparseMatrixType::ReverseInnerIterator ReverseInnerIterator;
enum {
CoeffReadCost = NumTraits<_Scalar>::ReadCost,
Flags = SparseMatrixType::Flags
};
evaluator() : m_matrix(0) {}
evaluator(const SparseMatrixType &mat) : m_matrix(&mat) {}
operator SparseMatrixType&() { return m_matrix->const_cast_derived(); }
operator const SparseMatrixType&() const { return *m_matrix; }
Scalar coeff(Index row, Index col) const { return m_matrix->coeff(row,col); }
Index nonZerosEstimate() const { return m_matrix->nonZeros(); }
const SparseMatrixType *m_matrix;
};
}
} // end namespace Eigen
#endif // EIGEN_DYNAMIC_SPARSEMATRIX_H

View File

@ -0,0 +1,275 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_SPARSE_MARKET_IO_H
#define EIGEN_SPARSE_MARKET_IO_H
#include <iostream>
namespace Eigen {
namespace internal
{
template <typename Scalar>
inline bool GetMarketLine (std::stringstream& line, Index& M, Index& N, Index& i, Index& j, Scalar& value)
{
line >> i >> j >> value;
i--;
j--;
if(i>=0 && j>=0 && i<M && j<N)
{
return true;
}
else
return false;
}
template <typename Scalar>
inline bool GetMarketLine (std::stringstream& line, Index& M, Index& N, Index& i, Index& j, std::complex<Scalar>& value)
{
Scalar valR, valI;
line >> i >> j >> valR >> valI;
i--;
j--;
if(i>=0 && j>=0 && i<M && j<N)
{
value = std::complex<Scalar>(valR, valI);
return true;
}
else
return false;
}
template <typename RealScalar>
inline void GetVectorElt (const std::string& line, RealScalar& val)
{
std::istringstream newline(line);
newline >> val;
}
template <typename RealScalar>
inline void GetVectorElt (const std::string& line, std::complex<RealScalar>& val)
{
RealScalar valR, valI;
std::istringstream newline(line);
newline >> valR >> valI;
val = std::complex<RealScalar>(valR, valI);
}
template<typename Scalar>
inline void putMarketHeader(std::string& header,int sym)
{
header= "%%MatrixMarket matrix coordinate ";
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
{
header += " complex";
if(sym == Symmetric) header += " symmetric";
else if (sym == SelfAdjoint) header += " Hermitian";
else header += " general";
}
else
{
header += " real";
if(sym == Symmetric) header += " symmetric";
else header += " general";
}
}
template<typename Scalar>
inline void PutMatrixElt(Scalar value, int row, int col, std::ofstream& out)
{
out << row << " "<< col << " " << value << "\n";
}
template<typename Scalar>
inline void PutMatrixElt(std::complex<Scalar> value, int row, int col, std::ofstream& out)
{
out << row << " " << col << " " << value.real() << " " << value.imag() << "\n";
}
template<typename Scalar>
inline void putVectorElt(Scalar value, std::ofstream& out)
{
out << value << "\n";
}
template<typename Scalar>
inline void putVectorElt(std::complex<Scalar> value, std::ofstream& out)
{
out << value.real << " " << value.imag()<< "\n";
}
} // end namepsace internal
inline bool getMarketHeader(const std::string& filename, int& sym, bool& iscomplex, bool& isvector)
{
sym = 0;
iscomplex = false;
isvector = false;
std::ifstream in(filename.c_str(),std::ios::in);
if(!in)
return false;
std::string line;
// The matrix header is always the first line in the file
std::getline(in, line); eigen_assert(in.good());
std::stringstream fmtline(line);
std::string substr[5];
fmtline>> substr[0] >> substr[1] >> substr[2] >> substr[3] >> substr[4];
if(substr[2].compare("array") == 0) isvector = true;
if(substr[3].compare("complex") == 0) iscomplex = true;
if(substr[4].compare("symmetric") == 0) sym = Symmetric;
else if (substr[4].compare("Hermitian") == 0) sym = SelfAdjoint;
return true;
}
template<typename SparseMatrixType>
bool loadMarket(SparseMatrixType& mat, const std::string& filename)
{
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::Index Index;
std::ifstream input(filename.c_str(),std::ios::in);
if(!input)
return false;
const int maxBuffersize = 2048;
char buffer[maxBuffersize];
bool readsizes = false;
typedef Triplet<Scalar,Index> T;
std::vector<T> elements;
Index M(-1), N(-1), NNZ(-1);
Index count = 0;
while(input.getline(buffer, maxBuffersize))
{
// skip comments
//NOTE An appropriate test should be done on the header to get the symmetry
if(buffer[0]=='%')
continue;
std::stringstream line(buffer);
if(!readsizes)
{
line >> M >> N >> NNZ;
if(M > 0 && N > 0 && NNZ > 0)
{
readsizes = true;
//std::cout << "sizes: " << M << "," << N << "," << NNZ << "\n";
mat.resize(M,N);
mat.reserve(NNZ);
}
}
else
{
Index i(-1), j(-1);
Scalar value;
if( internal::GetMarketLine(line, M, N, i, j, value) )
{
++ count;
elements.push_back(T(i,j,value));
}
else
std::cerr << "Invalid read: " << i << "," << j << "\n";
}
}
mat.setFromTriplets(elements.begin(), elements.end());
if(count!=NNZ)
std::cerr << count << "!=" << NNZ << "\n";
input.close();
return true;
}
template<typename VectorType>
bool loadMarketVector(VectorType& vec, const std::string& filename)
{
typedef typename VectorType::Scalar Scalar;
std::ifstream in(filename.c_str(), std::ios::in);
if(!in)
return false;
std::string line;
int n(0), col(0);
do
{ // Skip comments
std::getline(in, line); eigen_assert(in.good());
} while (line[0] == '%');
std::istringstream newline(line);
newline >> n >> col;
eigen_assert(n>0 && col>0);
vec.resize(n);
int i = 0;
Scalar value;
while ( std::getline(in, line) && (i < n) ){
internal::GetVectorElt(line, value);
vec(i++) = value;
}
in.close();
if (i!=n){
std::cerr<< "Unable to read all elements from file " << filename << "\n";
return false;
}
return true;
}
template<typename SparseMatrixType>
bool saveMarket(const SparseMatrixType& mat, const std::string& filename, int sym = 0)
{
typedef typename SparseMatrixType::Scalar Scalar;
std::ofstream out(filename.c_str(),std::ios::out);
if(!out)
return false;
out.flags(std::ios_base::scientific);
out.precision(64);
std::string header;
internal::putMarketHeader<Scalar>(header, sym);
out << header << std::endl;
out << mat.rows() << " " << mat.cols() << " " << mat.nonZeros() << "\n";
int count = 0;
for(int j=0; j<mat.outerSize(); ++j)
for(typename SparseMatrixType::InnerIterator it(mat,j); it; ++it)
{
++ count;
internal::PutMatrixElt(it.value(), it.row()+1, it.col()+1, out);
// out << it.row()+1 << " " << it.col()+1 << " " << it.value() << "\n";
}
out.close();
return true;
}
template<typename VectorType>
bool saveMarketVector (const VectorType& vec, const std::string& filename)
{
typedef typename VectorType::Scalar Scalar;
std::ofstream out(filename.c_str(),std::ios::out);
if(!out)
return false;
out.flags(std::ios_base::scientific);
out.precision(64);
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
out << "%%MatrixMarket matrix array complex general\n";
else
out << "%%MatrixMarket matrix array real general\n";
out << vec.size() << " "<< 1 << "\n";
for (int i=0; i < vec.size(); i++){
internal::putVectorElt(vec(i), out);
}
out.close();
return true;
}
} // end namespace Eigen
#endif // EIGEN_SPARSE_MARKET_IO_H

View File

@ -0,0 +1,247 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2012 Desire NUENTSA WAKAM <desire.nuentsa_wakam@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_BROWSE_MATRICES_H
#define EIGEN_BROWSE_MATRICES_H
namespace Eigen {
enum {
SPD = 0x100,
NonSymmetric = 0x0
};
/**
* @brief Iterator to browse matrices from a specified folder
*
* This is used to load all the matrices from a folder.
* The matrices should be in Matrix Market format
* It is assumed that the matrices are named as matname.mtx
* and matname_SPD.mtx if the matrix is Symmetric and positive definite (or Hermitian)
* The right hand side vectors are loaded as well, if they exist.
* They should be named as matname_b.mtx.
* Note that the right hand side for a SPD matrix is named as matname_SPD_b.mtx
*
* Sometimes a reference solution is available. In this case, it should be named as matname_x.mtx
*
* Sample code
* \code
*
* \endcode
*
* \tparam Scalar The scalar type
*/
template <typename Scalar>
class MatrixMarketIterator
{
typedef typename NumTraits<Scalar>::Real RealScalar;
public:
typedef Matrix<Scalar,Dynamic,1> VectorType;
typedef SparseMatrix<Scalar,ColMajor> MatrixType;
public:
MatrixMarketIterator(const std::string &folder)
: m_sym(0), m_isvalid(false), m_matIsLoaded(false), m_hasRhs(false), m_hasrefX(false), m_folder(folder)
{
m_folder_id = opendir(folder.c_str());
if(m_folder_id)
Getnextvalidmatrix();
}
~MatrixMarketIterator()
{
if (m_folder_id) closedir(m_folder_id);
}
inline MatrixMarketIterator& operator++()
{
m_matIsLoaded = false;
m_hasrefX = false;
m_hasRhs = false;
Getnextvalidmatrix();
return *this;
}
inline operator bool() const { return m_isvalid;}
/** Return the sparse matrix corresponding to the current file */
inline MatrixType& matrix()
{
// Read the matrix
if (m_matIsLoaded) return m_mat;
std::string matrix_file = m_folder + "/" + m_matname + ".mtx";
if ( !loadMarket(m_mat, matrix_file))
{
std::cerr << "Warning loadMarket failed when loading \"" << matrix_file << "\"" << std::endl;
m_matIsLoaded = false;
return m_mat;
}
m_matIsLoaded = true;
if (m_sym != NonSymmetric)
{
// Check whether we need to restore a full matrix:
RealScalar diag_norm = m_mat.diagonal().norm();
RealScalar lower_norm = m_mat.template triangularView<Lower>().norm();
RealScalar upper_norm = m_mat.template triangularView<Upper>().norm();
if(lower_norm>diag_norm && upper_norm==diag_norm)
{
// only the lower part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Lower>();
}
else if(upper_norm>diag_norm && lower_norm==diag_norm)
{
// only the upper part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Upper>();
}
}
return m_mat;
}
/** Return the right hand side corresponding to the current matrix.
* If the rhs file is not provided, a random rhs is generated
*/
inline VectorType& rhs()
{
// Get the right hand side
if (m_hasRhs) return m_rhs;
std::string rhs_file;
rhs_file = m_folder + "/" + m_matname + "_b.mtx"; // The pattern is matname_b.mtx
m_hasRhs = Fileexists(rhs_file);
if (m_hasRhs)
{
m_rhs.resize(m_mat.cols());
m_hasRhs = loadMarketVector(m_rhs, rhs_file);
}
if (!m_hasRhs)
{
// Generate a random right hand side
if (!m_matIsLoaded) this->matrix();
m_refX.resize(m_mat.cols());
m_refX.setRandom();
m_rhs = m_mat * m_refX;
m_hasrefX = true;
m_hasRhs = true;
}
return m_rhs;
}
/** Return a reference solution
* If it is not provided and if the right hand side is not available
* then refX is randomly generated such that A*refX = b
* where A and b are the matrix and the rhs.
* Note that when a rhs is provided, refX is not available
*/
inline VectorType& refX()
{
// Check if a reference solution is provided
if (m_hasrefX) return m_refX;
std::string lhs_file;
lhs_file = m_folder + "/" + m_matname + "_x.mtx";
m_hasrefX = Fileexists(lhs_file);
if (m_hasrefX)
{
m_refX.resize(m_mat.cols());
m_hasrefX = loadMarketVector(m_refX, lhs_file);
}
else
m_refX.resize(0);
return m_refX;
}
inline std::string& matname() { return m_matname; }
inline int sym() { return m_sym; }
bool hasRhs() {return m_hasRhs; }
bool hasrefX() {return m_hasrefX; }
bool isFolderValid() { return bool(m_folder_id); }
protected:
inline bool Fileexists(std::string file)
{
std::ifstream file_id(file.c_str());
if (!file_id.good() )
{
return false;
}
else
{
file_id.close();
return true;
}
}
void Getnextvalidmatrix( )
{
m_isvalid = false;
// Here, we return with the next valid matrix in the folder
while ( (m_curs_id = readdir(m_folder_id)) != NULL) {
m_isvalid = false;
std::string curfile;
curfile = m_folder + "/" + m_curs_id->d_name;
// Discard if it is a folder
if (m_curs_id->d_type == DT_DIR) continue; //FIXME This may not be available on non BSD systems
// struct stat st_buf;
// stat (curfile.c_str(), &st_buf);
// if (S_ISDIR(st_buf.st_mode)) continue;
// Determine from the header if it is a matrix or a right hand side
bool isvector,iscomplex=false;
if(!getMarketHeader(curfile,m_sym,iscomplex,isvector)) continue;
if(isvector) continue;
if (!iscomplex)
{
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
continue;
}
if (iscomplex)
{
if(internal::is_same<Scalar, float>::value || internal::is_same<Scalar, double>::value)
continue;
}
// Get the matrix name
std::string filename = m_curs_id->d_name;
m_matname = filename.substr(0, filename.length()-4);
// Find if the matrix is SPD
size_t found = m_matname.find("SPD");
if( (found!=std::string::npos) && (m_sym != NonSymmetric) )
m_sym = SPD;
m_isvalid = true;
break;
}
}
int m_sym; // Symmetry of the matrix
MatrixType m_mat; // Current matrix
VectorType m_rhs; // Current vector
VectorType m_refX; // The reference solution, if exists
std::string m_matname; // Matrix Name
bool m_isvalid;
bool m_matIsLoaded; // Determine if the matrix has already been loaded from the file
bool m_hasRhs; // The right hand side exists
bool m_hasrefX; // A reference solution is provided
std::string m_folder;
DIR * m_folder_id;
struct dirent *m_curs_id;
};
} // end namespace Eigen
#endif

View File

@ -0,0 +1,327 @@
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef EIGEN_RANDOMSETTER_H
#define EIGEN_RANDOMSETTER_H
namespace Eigen {
/** Represents a std::map
*
* \see RandomSetter
*/
template<typename Scalar> struct StdMapTraits
{
typedef int KeyType;
typedef std::map<KeyType,Scalar> Type;
enum {
IsSorted = 1
};
static void setInvalidKey(Type&, const KeyType&) {}
};
#ifdef EIGEN_UNORDERED_MAP_SUPPORT
/** Represents a std::unordered_map
*
* To use it you need to both define EIGEN_UNORDERED_MAP_SUPPORT and include the unordered_map header file
* yourself making sure that unordered_map is defined in the std namespace.
*
* For instance, with current version of gcc you can either enable C++0x standard (-std=c++0x) or do:
* \code
* #include <tr1/unordered_map>
* #define EIGEN_UNORDERED_MAP_SUPPORT
* namespace std {
* using std::tr1::unordered_map;
* }
* \endcode
*
* \see RandomSetter
*/
template<typename Scalar> struct StdUnorderedMapTraits
{
typedef int KeyType;
typedef std::unordered_map<KeyType,Scalar> Type;
enum {
IsSorted = 0
};
static void setInvalidKey(Type&, const KeyType&) {}
};
#endif // EIGEN_UNORDERED_MAP_SUPPORT
#ifdef _DENSE_HASH_MAP_H_
/** Represents a google::dense_hash_map
*
* \see RandomSetter
*/
template<typename Scalar> struct GoogleDenseHashMapTraits
{
typedef int KeyType;
typedef google::dense_hash_map<KeyType,Scalar> Type;
enum {
IsSorted = 0
};
static void setInvalidKey(Type& map, const KeyType& k)
{ map.set_empty_key(k); }
};
#endif
#ifdef _SPARSE_HASH_MAP_H_
/** Represents a google::sparse_hash_map
*
* \see RandomSetter
*/
template<typename Scalar> struct GoogleSparseHashMapTraits
{
typedef int KeyType;
typedef google::sparse_hash_map<KeyType,Scalar> Type;
enum {
IsSorted = 0
};
static void setInvalidKey(Type&, const KeyType&) {}
};
#endif
/** \class RandomSetter
*
* \brief The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access
*
* \tparam SparseMatrixType the type of the sparse matrix we are updating
* \tparam MapTraits a traits class representing the map implementation used for the temporary sparse storage.
* Its default value depends on the system.
* \tparam OuterPacketBits defines the number of rows (or columns) manage by a single map object
* as a power of two exponent.
*
* This class temporarily represents a sparse matrix object using a generic map implementation allowing for
* efficient random access. The conversion from the compressed representation to a hash_map object is performed
* in the RandomSetter constructor, while the sparse matrix is updated back at destruction time. This strategy
* suggest the use of nested blocks as in this example:
*
* \code
* SparseMatrix<double> m(rows,cols);
* {
* RandomSetter<SparseMatrix<double> > w(m);
* // don't use m but w instead with read/write random access to the coefficients:
* for(;;)
* w(rand(),rand()) = rand;
* }
* // when w is deleted, the data are copied back to m
* // and m is ready to use.
* \endcode
*
* Since hash_map objects are not fully sorted, representing a full matrix as a single hash_map would
* involve a big and costly sort to update the compressed matrix back. To overcome this issue, a RandomSetter
* use multiple hash_map, each representing 2^OuterPacketBits columns or rows according to the storage order.
* To reach optimal performance, this value should be adjusted according to the average number of nonzeros
* per rows/columns.
*
* The possible values for the template parameter MapTraits are:
* - \b StdMapTraits: corresponds to std::map. (does not perform very well)
* - \b GnuHashMapTraits: corresponds to __gnu_cxx::hash_map (available only with GCC)
* - \b GoogleDenseHashMapTraits: corresponds to google::dense_hash_map (best efficiency, reasonable memory consumption)
* - \b GoogleSparseHashMapTraits: corresponds to google::sparse_hash_map (best memory consumption, relatively good performance)
*
* The default map implementation depends on the availability, and the preferred order is:
* GoogleSparseHashMapTraits, GnuHashMapTraits, and finally StdMapTraits.
*
* For performance and memory consumption reasons it is highly recommended to use one of
* the Google's hash_map implementation. To enable the support for them, you have two options:
* - \#include <google/dense_hash_map> yourself \b before Eigen/Sparse header
* - define EIGEN_GOOGLEHASH_SUPPORT
* In the later case the inclusion of <google/dense_hash_map> is made for you.
*
* \see http://code.google.com/p/google-sparsehash/
*/
template<typename SparseMatrixType,
template <typename T> class MapTraits =
#if defined _DENSE_HASH_MAP_H_
GoogleDenseHashMapTraits
#elif defined _HASH_MAP
GnuHashMapTraits
#else
StdMapTraits
#endif
,int OuterPacketBits = 6>
class RandomSetter
{
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::StorageIndex StorageIndex;
struct ScalarWrapper
{
ScalarWrapper() : value(0) {}
Scalar value;
};
typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
static const int OuterPacketMask = (1 << OuterPacketBits) - 1;
enum {
SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
SetterRowMajor = SwapStorage ? 1-TargetRowMajor : TargetRowMajor
};
public:
/** Constructs a random setter object from the sparse matrix \a target
*
* Note that the initial value of \a target are imported. If you want to re-set
* a sparse matrix from scratch, then you must set it to zero first using the
* setZero() function.
*/
inline RandomSetter(SparseMatrixType& target)
: mp_target(&target)
{
const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
m_outerPackets = outerSize >> OuterPacketBits;
if (outerSize&OuterPacketMask)
m_outerPackets += 1;
m_hashmaps = new HashMapType[m_outerPackets];
// compute number of bits needed to store inner indices
Index aux = innerSize - 1;
m_keyBitsOffset = 0;
while (aux)
{
++m_keyBitsOffset;
aux = aux >> 1;
}
KeyType ik = (1<<(OuterPacketBits+m_keyBitsOffset));
for (Index k=0; k<m_outerPackets; ++k)
MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k],ik);
// insert current coeffs
for (Index j=0; j<mp_target->outerSize(); ++j)
for (typename SparseMatrixType::InnerIterator it(*mp_target,j); it; ++it)
(*this)(TargetRowMajor?j:it.index(), TargetRowMajor?it.index():j) = it.value();
}
/** Destructor updating back the sparse matrix target */
~RandomSetter()
{
KeyType keyBitsMask = (1<<m_keyBitsOffset)-1;
if (!SwapStorage) // also means the map is sorted
{
mp_target->setZero();
mp_target->makeCompressed();
mp_target->reserve(nonZeros());
Index prevOuter = -1;
for (Index k=0; k<m_outerPackets; ++k)
{
const Index outerOffset = (1<<OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
const Index inner = it->first & keyBitsMask;
if (prevOuter!=outer)
{
for (Index j=prevOuter+1;j<=outer;++j)
mp_target->startVec(j);
prevOuter = outer;
}
mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
}
}
mp_target->finalize();
}
else
{
VectorXi positions(mp_target->outerSize());
positions.setZero();
// pass 1
for (Index k=0; k<m_outerPackets; ++k)
{
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index outer = it->first & keyBitsMask;
++positions[outer];
}
}
// prefix sum
Index count = 0;
for (Index j=0; j<mp_target->outerSize(); ++j)
{
Index tmp = positions[j];
mp_target->outerIndexPtr()[j] = count;
positions[j] = count;
count += tmp;
}
mp_target->makeCompressed();
mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
mp_target->resizeNonZeros(count);
// pass 2
for (Index k=0; k<m_outerPackets; ++k)
{
const Index outerOffset = (1<<OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
const Index outer = it->first & keyBitsMask;
// sorted insertion
// Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
// moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
// small fraction of them have to be sorted, whence the following simple procedure:
Index posStart = mp_target->outerIndexPtr()[outer];
Index i = (positions[outer]++) - 1;
while ( (i >= posStart) && (mp_target->innerIndexPtr()[i] > inner) )
{
mp_target->valuePtr()[i+1] = mp_target->valuePtr()[i];
mp_target->innerIndexPtr()[i+1] = mp_target->innerIndexPtr()[i];
--i;
}
mp_target->innerIndexPtr()[i+1] = inner;
mp_target->valuePtr()[i+1] = it->second.value;
}
}
}
delete[] m_hashmaps;
}
/** \returns a reference to the coefficient at given coordinates \a row, \a col */
Scalar& operator() (Index row, Index col)
{
const Index outer = SetterRowMajor ? row : col;
const Index inner = SetterRowMajor ? col : row;
const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
const KeyType key = internal::convert_index<KeyType>((outerMinor<<m_keyBitsOffset) | inner);
return m_hashmaps[outerMajor][key].value;
}
/** \returns the number of non zero coefficients
*
* \note According to the underlying map/hash_map implementation,
* this function might be quite expensive.
*/
Index nonZeros() const
{
Index nz = 0;
for (Index k=0; k<m_outerPackets; ++k)
nz += static_cast<Index>(m_hashmaps[k].size());
return nz;
}
protected:
HashMapType* m_hashmaps;
SparseMatrixType* mp_target;
Index m_outerPackets;
unsigned char m_keyBitsOffset;
};
} // end namespace Eigen
#endif // EIGEN_RANDOMSETTER_H

View File

@ -13,8 +13,8 @@ namespace igl
// Define a standard value for double epsilon // Define a standard value for double epsilon
const double DOUBLE_EPS = 1.0e-14; const double DOUBLE_EPS = 1.0e-14;
const double DOUBLE_EPS_SQ = 1.0e-28; const double DOUBLE_EPS_SQ = 1.0e-28;
const float FLOAT_EPS = 1.0e-7; const float FLOAT_EPS = 1.0e-7f;
const float FLOAT_EPS_SQ = 1.0e-14; const float FLOAT_EPS_SQ = 1.0e-14f;
// Function returning EPS for corresponding type // Function returning EPS for corresponding type
template <typename S_type> IGL_INLINE S_type EPS(); template <typename S_type> IGL_INLINE S_type EPS();
template <typename S_type> IGL_INLINE S_type EPS_SQ(); template <typename S_type> IGL_INLINE S_type EPS_SQ();

View File

@ -545,8 +545,8 @@ public:
_NofitPolyPlacer& operator=(const _NofitPolyPlacer&) = default; _NofitPolyPlacer& operator=(const _NofitPolyPlacer&) = default;
#ifndef BP2D_COMPILER_MSVC12 // MSVC2013 does not support default move ctors #ifndef BP2D_COMPILER_MSVC12 // MSVC2013 does not support default move ctors
_NofitPolyPlacer(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default; _NofitPolyPlacer(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default;
_NofitPolyPlacer& operator=(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default; _NofitPolyPlacer& operator=(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default;
#endif #endif
static inline double overfit(const Box& bb, const RawShape& bin) { static inline double overfit(const Box& bb, const RawShape& bin) {

View File

@ -198,6 +198,10 @@ target_link_libraries(libslic3r
tbb tbb
) )
if(WIN32)
target_link_libraries(libslic3r Psapi.lib)
endif()
if(SLIC3R_PROFILE) if(SLIC3R_PROFILE)
target_link_libraries(slic3r Shiny) target_link_libraries(slic3r Shiny)
endif() endif()

View File

@ -1,6 +1,7 @@
#ifndef slic3r_Channel_hpp_ #ifndef slic3r_Channel_hpp_
#define slic3r_Channel_hpp_ #define slic3r_Channel_hpp_
#include <memory>
#include <deque> #include <deque>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
@ -13,32 +14,26 @@ namespace Slic3r {
template<class T> class Channel template<class T> class Channel
{ {
private:
using UniqueLock = std::unique_lock<std::mutex>;
using Queue = std::deque<T>;
public: public:
class Guard using UniqueLock = std::unique_lock<std::mutex>;
template<class Ptr> class Unlocker
{ {
public: public:
Guard(UniqueLock lock, const Queue &queue) : m_lock(std::move(lock)), m_queue(queue) {} Unlocker(UniqueLock lock) : m_lock(std::move(lock)) {}
Guard(const Guard &other) = delete; Unlocker(const Unlocker &other) noexcept : m_lock(std::move(other.m_lock)) {} // XXX: done beacuse of MSVC 2013 not supporting init of deleter by move
Guard(Guard &&other) = delete; Unlocker(Unlocker &&other) noexcept : m_lock(std::move(other.m_lock)) {}
~Guard() {} Unlocker& operator=(const Unlocker &other) = delete;
Unlocker& operator=(Unlocker &&other) { m_lock = std::move(other.m_lock); }
// Access trampolines void operator()(Ptr*) { m_lock.unlock(); }
size_t size() const noexcept { return m_queue.size(); }
bool empty() const noexcept { return m_queue.empty(); }
typename Queue::const_iterator begin() const noexcept { return m_queue.begin(); }
typename Queue::const_iterator end() const noexcept { return m_queue.end(); }
typename Queue::const_reference operator[](size_t i) const { return m_queue[i]; }
Guard& operator=(const Guard &other) = delete;
Guard& operator=(Guard &&other) = delete;
private: private:
UniqueLock m_lock; mutable UniqueLock m_lock; // XXX: mutable: see above
const Queue &m_queue;
}; };
using Queue = std::deque<T>;
using LockedConstPtr = std::unique_ptr<const Queue, Unlocker<const Queue>>;
using LockedPtr = std::unique_ptr<Queue, Unlocker<Queue>>;
Channel() {} Channel() {}
~Channel() {} ~Channel() {}
@ -56,7 +51,7 @@ public:
{ {
{ {
UniqueLock lock(m_mutex); UniqueLock lock(m_mutex);
m_queue.push_back(std::forward(item)); m_queue.push_back(std::forward<T>(item));
} }
if (! silent) { m_condition.notify_one(); } if (! silent) { m_condition.notify_one(); }
} }
@ -82,19 +77,21 @@ public:
} }
} }
// Unlocked observers // Unlocked observer/hint. Thread unsafe! Keep in mind you need to re-verify the result after locking.
// Thread unsafe! Keep in mind you need to re-verify the result after acquiring lock! size_t size_hint() const noexcept { return m_queue.size(); }
size_t size() const noexcept { return m_queue.size(); }
bool empty() const noexcept { return m_queue.empty(); }
Guard read() const LockedConstPtr lock_read() const
{ {
return Guard(UniqueLock(m_mutex), m_queue); return LockedConstPtr(&m_queue, Unlocker<const Queue>(UniqueLock(m_mutex)));
} }
LockedPtr lock_rw()
{
return LockedPtr(&m_queue, Unlocker<Queue>(UniqueLock(m_mutex)));
}
private: private:
Queue m_queue; Queue m_queue;
std::mutex m_mutex; mutable std::mutex m_mutex;
std::condition_variable m_condition; std::condition_variable m_condition;
}; };

View File

@ -483,8 +483,9 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const
t_options_map::const_iterator it2 = rhs.options.begin(); t_options_map::const_iterator it2 = rhs.options.begin();
t_options_map::const_iterator it2_end = rhs.options.end(); t_options_map::const_iterator it2_end = rhs.options.end();
for (; it1 != it1_end && it2 != it2_end; ++ it1, ++ it2) for (; it1 != it1_end && it2 != it2_end; ++ it1, ++ it2)
if (*it1->second != *it2->second) if (it1->first != it2->first || *it1->second != *it2->second)
return false; // key or value differ
return false;
return it1 == it1_end && it2 == it2_end; return it1 == it1_end && it2 == it2_end;
} }

View File

@ -1336,49 +1336,12 @@ namespace Slic3r {
void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform) void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
Slic3r::Geometry::Transformation t(transform); Slic3r::Geometry::Transformation t(transform);
// invalid scale value, return // invalid scale value, return
if (!t.get_scaling_factor().all()) if (!t.get_scaling_factor().all())
return; return;
instance.set_transformation(t); instance.set_transformation(t);
#else
// translation
Vec3d offset = transform.matrix().block(0, 3, 3, 1);
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
// mirror
// it is impossible to reconstruct the original mirroring factors from a matrix,
// we can only detect if the matrix contains a left handed reference system
// in which case we reorient it back to right handed by mirroring the x axis
Vec3d mirror = Vec3d::Ones();
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0)
{
mirror(0) = -1.0;
// remove mirror
m3x3.col(0) *= -1.0;
}
// scale
Vec3d scale(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm());
// invalid scale value, return
if ((scale(0) == 0.0) || (scale(1) == 0.0) || (scale(2) == 0.0))
return;
// remove scale
m3x3.col(0).normalize();
m3x3.col(1).normalize();
m3x3.col(2).normalize();
Vec3d rotation = Slic3r::Geometry::extract_euler_angles(m3x3);
instance.set_offset(offset);
instance.set_scaling_factor(scale);
instance.set_rotation(rotation);
instance.set_mirror(mirror);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes)
@ -1875,23 +1838,15 @@ namespace Slic3r {
vertices_count += stl.stats.shared_vertices; vertices_count += stl.stats.shared_vertices;
#if ENABLE_MODELVOLUME_TRANSFORM
const Transform3d& matrix = volume->get_matrix(); const Transform3d& matrix = volume->get_matrix();
#endif // ENABLE_MODELVOLUME_TRANSFORM
for (int i = 0; i < stl.stats.shared_vertices; ++i) for (int i = 0; i < stl.stats.shared_vertices; ++i)
{ {
stream << " <" << VERTEX_TAG << " "; stream << " <" << VERTEX_TAG << " ";
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3d v = matrix * stl.v_shared[i].cast<double>(); Vec3d v = matrix * stl.v_shared[i].cast<double>();
stream << "x=\"" << v(0) << "\" "; stream << "x=\"" << v(0) << "\" ";
stream << "y=\"" << v(1) << "\" "; stream << "y=\"" << v(1) << "\" ";
stream << "z=\"" << v(2) << "\" />\n"; stream << "z=\"" << v(2) << "\" />\n";
#else
stream << "x=\"" << stl.v_shared[i](0) << "\" ";
stream << "y=\"" << stl.v_shared[i](1) << "\" ";
stream << "z=\"" << stl.v_shared[i](2) << "\" />\n";
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
} }

View File

@ -96,7 +96,6 @@ static void extract_model_from_archive(
const char *model_xml = strstr(scene_xml_data.data(), model_name_tag); const char *model_xml = strstr(scene_xml_data.data(), model_name_tag);
const char *zero_tag = "<zero>"; const char *zero_tag = "<zero>";
const char *zero_xml = strstr(scene_xml_data.data(), zero_tag); const char *zero_xml = strstr(scene_xml_data.data(), zero_tag);
float trafo[3][4] = { 0 };
Vec3d instance_rotation = Vec3d::Zero(); Vec3d instance_rotation = Vec3d::Zero();
Vec3d instance_scaling_factor = Vec3d::Ones(); Vec3d instance_scaling_factor = Vec3d::Ones();
Vec3d instance_offset = Vec3d::Zero(); Vec3d instance_offset = Vec3d::Zero();
@ -124,19 +123,7 @@ static void extract_model_from_archive(
"[%f, %f, %f]", zero, zero+1, zero+2) == 3) { "[%f, %f, %f]", zero, zero+1, zero+2) == 3) {
instance_scaling_factor = Vec3d((double)scale[0], (double)scale[1], (double)scale[2]); instance_scaling_factor = Vec3d((double)scale[0], (double)scale[1], (double)scale[2]);
instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]); instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
Eigen::Matrix3f mat_rot, mat_scale, mat_trafo;
mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) *
Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) *
Eigen::AngleAxisf(-rotation[0], Eigen::Vector3f::UnitX());
mat_scale = Eigen::Scaling(scale[0], scale[1], scale[2]);
mat_trafo = mat_rot * mat_scale;
for (size_t r = 0; r < 3; ++ r) {
for (size_t c = 0; c < 3; ++ c)
trafo[r][c] += mat_trafo(r, c);
}
instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2])); instance_offset = Vec3d((double)(position[0] - zero[0]), (double)(position[1] - zero[1]), (double)(position[2] - zero[2]));
// CHECK_ME -> Is the following correct ?
trafo[2][3] = position[2] / (float)instance_scaling_factor(2);
trafo_set = true; trafo_set = true;
} }
const char *group_tag = "<group>"; const char *group_tag = "<group>";
@ -189,8 +176,6 @@ static void extract_model_from_archive(
// All the faces have been read. // All the faces have been read.
stl_get_size(&stl); stl_get_size(&stl);
mesh.repair(); mesh.repair();
// Transform the model.
stl_transform(&stl, &trafo[0][0]);
if (std::abs(stl.stats.min(2)) < EPSILON) if (std::abs(stl.stats.min(2)) < EPSILON)
stl.stats.min(2) = 0.; stl.stats.min(2) = 0.;
// Add a mesh to a model. // Add a mesh to a model.
@ -274,8 +259,6 @@ static void extract_model_from_archive(
memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50); memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
stl_get_size(&stl); stl_get_size(&stl);
mesh.repair(); mesh.repair();
// Transform the model.
stl_transform(&stl, &trafo[0][0]);
// Add a mesh to a model. // Add a mesh to a model.
if (mesh.facets_count() > 0) if (mesh.facets_count() > 0)
mesh_valid = true; mesh_valid = true;

View File

@ -423,7 +423,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
print->set_started(psGCodeExport); print->set_started(psGCodeExport);
BOOST_LOG_TRIVIAL(info) << "Exporting G-code..."; BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
// Remove the old g-code if it exists. // Remove the old g-code if it exists.
boost::nowide::remove(path); boost::nowide::remove(path);
@ -435,9 +435,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
if (file == nullptr) if (file == nullptr)
throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
m_enable_analyzer = preview_data != nullptr;
try { try {
m_placeholder_parser_failed_templates.clear(); m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, preview_data); this->_do_export(*print, file);
fflush(file); fflush(file);
if (ferror(file)) { if (ferror(file)) {
fclose(file); fclose(file);
@ -453,15 +455,6 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
} }
fclose(file); fclose(file);
if (print->config().remaining_times.value) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode";
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
if (m_silent_time_estimator_enabled) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode";
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
}
}
if (! m_placeholder_parser_failed_templates.empty()) { if (! m_placeholder_parser_failed_templates.empty()) {
// G-code export proceeded, but some of the PlaceholderParser substitutions failed. // G-code export proceeded, but some of the PlaceholderParser substitutions failed.
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n"; std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
@ -475,12 +468,30 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
throw std::runtime_error(msg); throw std::runtime_error(msg);
} }
if (print->config().remaining_times.value) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode";
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
m_normal_time_estimator.reset();
if (m_silent_time_estimator_enabled) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode";
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
m_silent_time_estimator.reset();
}
}
// starts analyzer calculations
if (m_enable_analyzer) {
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data";
m_analyzer.calc_gcode_preview_data(*preview_data);
m_analyzer.reset();
}
if (rename_file(path_tmp, path) != 0) if (rename_file(path_tmp, path) != 0)
throw std::runtime_error( throw std::runtime_error(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
"Is " + path_tmp + " locked?" + '\n'); "Is " + path_tmp + " locked?" + '\n');
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished"; BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
print->set_done(psGCodeExport); print->set_done(psGCodeExport);
// Write the profiler measurements to file // Write the profiler measurements to file
@ -488,7 +499,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str()); PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
} }
void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) void GCode::_do_export(Print &print, FILE *file)
{ {
PROFILE_FUNC(); PROFILE_FUNC();
@ -558,7 +569,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// resets analyzer // resets analyzer
m_analyzer.reset(); m_analyzer.reset();
m_enable_analyzer = preview_data != nullptr;
// resets analyzer's tracking data // resets analyzer's tracking data
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
@ -1034,12 +1044,6 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
_write(file, full_config); _write(file, full_config);
} }
print.throw_if_canceled(); print.throw_if_canceled();
// starts analyzer calculations
if (preview_data != nullptr) {
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data";
m_analyzer.calc_gcode_preview_data(*preview_data);
}
} }
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
@ -1231,7 +1235,7 @@ void GCode::process_layer(
const Print &print, const Print &print,
// Set of object & print layers of the same PrintObject and with the same print_z. // Set of object & print layers of the same PrintObject and with the same print_z.
const std::vector<LayerToPrint> &layers, const std::vector<LayerToPrint> &layers,
const LayerTools &layer_tools, const LayerTools &layer_tools,
// If set to size_t(-1), then print all copies of all objects. // If set to size_t(-1), then print all copies of all objects.
// Otherwise print a single copy of a single object. // Otherwise print a single copy of a single object.
const size_t single_object_idx) const size_t single_object_idx)
@ -1650,6 +1654,11 @@ void GCode::process_layer(
// printf("G-code after filter:\n%s\n", out.c_str()); // printf("G-code after filter:\n%s\n", out.c_str());
_write(file, gcode); _write(file, gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
", time estimator memory: " <<
format_memsize_MB(m_normal_time_estimator.memory_used() + m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0) <<
", analyzer memory: " <<
format_memsize_MB(m_analyzer.memory_used());
} }
void GCode::apply_print_config(const PrintConfig &print_config) void GCode::apply_print_config(const PrintConfig &print_config)

View File

@ -180,7 +180,7 @@ public:
static void append_full_config(const Print& print, std::string& str); static void append_full_config(const Print& print, std::string& str);
protected: protected:
void _do_export(Print &print, FILE *file, GCodePreviewData *preview_data); void _do_export(Print &print, FILE *file);
// Object and support extrusions of the same PrintObject at the same print_z. // Object and support extrusions of the same PrintObject at the same print_z.
struct LayerToPrint struct LayerToPrint

View File

@ -4,6 +4,7 @@
#include "../libslic3r.h" #include "../libslic3r.h"
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "../Utils.hpp"
#include "Print.hpp" #include "Print.hpp"
#include "Analyzer.hpp" #include "Analyzer.hpp"
@ -667,6 +668,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
{ {
static GCodePreviewData::Extrusion::Layer& get_layer_at_z(GCodePreviewData::Extrusion::LayersList& layers, float z) static GCodePreviewData::Extrusion::Layer& get_layer_at_z(GCodePreviewData::Extrusion::LayersList& layers, float z)
{ {
//FIXME this has a terrible time complexity
for (GCodePreviewData::Extrusion::Layer& layer : layers) for (GCodePreviewData::Extrusion::Layer& layer : layers)
{ {
// if layer found, return it // if layer found, return it
@ -852,20 +854,14 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
} }
} }
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2) // Return an estimate of the memory consumed by the time estimator.
size_t GCodeAnalyzer::memory_used() const
{ {
return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]), size_t out = sizeof(*this);
clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]), for (const std::pair<GCodeMove::EType, GCodeMovesList> &kvp : m_moves_map)
clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]), out += sizeof(kvp) + SLIC3R_STDVEC_MEMSIZE(kvp.second, GCodeMove);
clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3])); out += m_process_output.size();
} return out;
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color)
{
return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
clamp(0.0f, 1.0f, f * color.rgba[1]),
clamp(0.0f, 1.0f, f * color.rgba[2]),
clamp(0.0f, 1.0f, f * color.rgba[3]));
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -120,6 +120,9 @@ public:
// Calculates all data needed for gcode visualization // Calculates all data needed for gcode visualization
void calc_gcode_preview_data(GCodePreviewData& preview_data); void calc_gcode_preview_data(GCodePreviewData& preview_data);
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
static bool is_valid_extrusion_role(ExtrusionRole role); static bool is_valid_extrusion_role(ExtrusionRole role);
private: private:

View File

@ -2,6 +2,7 @@
#include "PreviewData.hpp" #include "PreviewData.hpp"
#include <float.h> #include <float.h>
#include <I18N.hpp> #include <I18N.hpp>
#include "Utils.hpp"
#include <boost/format.hpp> #include <boost/format.hpp>
@ -205,6 +206,18 @@ bool GCodePreviewData::Extrusion::is_role_flag_set(unsigned int flags, Extrusion
return GCodeAnalyzer::is_valid_extrusion_role(role) && (flags & (1 << (role - erPerimeter))) != 0; return GCodeAnalyzer::is_valid_extrusion_role(role) && (flags & (1 << (role - erPerimeter))) != 0;
} }
size_t GCodePreviewData::Extrusion::memory_used() const
{
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->layers, Layer);
for (const Layer &layer : this->layers) {
out += SLIC3R_STDVEC_MEMSIZE(layer.paths, ExtrusionPath);
for (const ExtrusionPath &path : layer.paths)
out += SLIC3R_STDVEC_MEMSIZE(path.polyline.points, Point);
}
return out;
}
const float GCodePreviewData::Travel::Default_Width = 0.075f; const float GCodePreviewData::Travel::Default_Width = 0.075f;
const float GCodePreviewData::Travel::Default_Height = 0.075f; const float GCodePreviewData::Travel::Default_Height = 0.075f;
const GCodePreviewData::Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] = const GCodePreviewData::Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
@ -224,6 +237,15 @@ void GCodePreviewData::Travel::set_default()
is_visible = false; is_visible = false;
} }
size_t GCodePreviewData::Travel::memory_used() const
{
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->polylines, Polyline);
for (const Polyline &polyline : this->polylines)
out += SLIC3R_STDVEC_MEMSIZE(polyline.polyline.points, Vec3crd);
return out;
}
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f); const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height) GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
@ -239,6 +261,11 @@ void GCodePreviewData::Retraction::set_default()
is_visible = false; is_visible = false;
} }
size_t GCodePreviewData::Retraction::memory_used() const
{
return sizeof(*this) + SLIC3R_STDVEC_MEMSIZE(this->positions, Position);
}
void GCodePreviewData::Shell::set_default() void GCodePreviewData::Shell::set_default()
{ {
is_visible = false; is_visible = false;
@ -486,4 +513,31 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
return items; return items;
} }
// Return an estimate of the memory consumed by the time estimator.
size_t GCodePreviewData::memory_used() const
{
return
this->extrusion.memory_used() +
this->travel.memory_used() +
this->retraction.memory_used() +
this->unretraction.memory_used() +
sizeof(shell) + sizeof(ranges);
}
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2)
{
return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]),
clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]),
clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]),
clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3]));
}
GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color)
{
return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
clamp(0.0f, 1.0f, f * color.rgba[1]),
clamp(0.0f, 1.0f, f * color.rgba[2]),
clamp(0.0f, 1.0f, f * color.rgba[3]));
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -22,6 +22,7 @@ public:
static const Color Dummy; static const Color Dummy;
}; };
// Color mapping from a <min, max> range into a smooth rainbow of 10 colors.
struct Range struct Range
{ {
static const unsigned int Colors_Count = 10; static const unsigned int Colors_Count = 10;
@ -45,9 +46,13 @@ public:
struct Ranges struct Ranges
{ {
// Color mapping by layer height.
Range height; Range height;
// Color mapping by extrusion width.
Range width; Range width;
// Color mapping by feedrate.
Range feedrate; Range feedrate;
// Color mapping by volumetric extrusion rate.
Range volumetric_rate; Range volumetric_rate;
}; };
@ -100,6 +105,9 @@ public:
void set_default(); void set_default();
bool is_role_flag_set(ExtrusionRole role) const; bool is_role_flag_set(ExtrusionRole role) const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
static bool is_role_flag_set(unsigned int flags, ExtrusionRole role); static bool is_role_flag_set(unsigned int flags, ExtrusionRole role);
}; };
@ -145,6 +153,9 @@ public:
size_t color_print_idx; size_t color_print_idx;
void set_default(); void set_default();
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
}; };
struct Retraction struct Retraction
@ -167,6 +178,9 @@ public:
bool is_visible; bool is_visible;
void set_default(); void set_default();
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
}; };
struct Shell struct Shell
@ -200,6 +214,9 @@ public:
std::string get_legend_title() const; std::string get_legend_title() const;
LegendItemsList get_legend_items(const std::vector<float>& tool_colors, const std::vector</*double*/std::pair<double, double>>& cp_values) const; LegendItemsList get_legend_items(const std::vector<float>& tool_colors, const std::vector</*double*/std::pair<double, double>>& cp_values) const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
}; };
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2); GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2);

View File

@ -290,7 +290,8 @@ namespace Slic3r {
// buffer line to export only when greater than 64K to reduce writing calls // buffer line to export only when greater than 64K to reduce writing calls
std::string export_line; std::string export_line;
char time_line[64]; char time_line[64];
while (std::getline(in, gcode_line)) G1LineIdToBlockIdMap::const_iterator it_line_id = _g1_line_ids.begin();
while (std::getline(in, gcode_line))
{ {
if (!in.good()) if (!in.good())
{ {
@ -310,29 +311,29 @@ namespace Slic3r {
// add remaining time lines where needed // add remaining time lines where needed
_parser.parse_line(gcode_line, _parser.parse_line(gcode_line,
[this, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line) [this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
{ {
if (line.cmd_is("G1")) if (line.cmd_is("G1"))
{ {
++g1_lines_count; ++g1_lines_count;
if (!line.has_e()) assert(it_line_id == _g1_line_ids.end() || it_line_id->first >= g1_lines_count);
return;
G1LineIdToBlockIdMap::const_iterator it = _g1_line_ids.find(g1_lines_count); const Block *block = nullptr;
if ((it != _g1_line_ids.end()) && (it->second < (unsigned int)_blocks.size())) if (it_line_id != _g1_line_ids.end() && it_line_id->first == g1_lines_count) {
{ if (line.has_e() && it_line_id->second < (unsigned int)_blocks.size())
const Block& block = _blocks[it->second]; block = &_blocks[it_line_id->second];
if (block.elapsed_time != -1.0f) ++it_line_id;
}
if (block != nullptr && block->elapsed_time != -1.0f) {
float block_remaining_time = _time - block->elapsed_time;
if (std::abs(last_recorded_time - block_remaining_time) > interval)
{ {
float block_remaining_time = _time - block.elapsed_time; sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / _time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
if (std::abs(last_recorded_time - block_remaining_time) > interval) gcode_line += time_line;
{
sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block.elapsed_time / _time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
gcode_line += time_line;
last_recorded_time = block_remaining_time; last_recorded_time = block_remaining_time;
}
} }
} }
} }
@ -667,6 +668,15 @@ namespace Slic3r {
return _get_time_minutes(get_time()); return _get_time_minutes(get_time());
} }
// Return an estimate of the memory consumed by the time estimator.
size_t GCodeTimeEstimator::memory_used() const
{
size_t out = sizeof(*this);
out += SLIC3R_STDVEC_MEMSIZE(this->_blocks, Block);
out += SLIC3R_STDVEC_MEMSIZE(this->_g1_line_ids, G1LineIdToBlockId);
return out;
}
void GCodeTimeEstimator::_reset() void GCodeTimeEstimator::_reset()
{ {
_curr.reset(); _curr.reset();
@ -1072,7 +1082,7 @@ namespace Slic3r {
// adds block to blocks list // adds block to blocks list
_blocks.emplace_back(block); _blocks.emplace_back(block);
_g1_line_ids.insert(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)_blocks.size() - 1)); _g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)_blocks.size() - 1));
} }
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)

View File

@ -209,7 +209,8 @@ namespace Slic3r {
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap; typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
#endif // ENABLE_MOVE_STATS #endif // ENABLE_MOVE_STATS
typedef std::map<unsigned int, unsigned int> G1LineIdToBlockIdMap; typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
private: private:
EMode _mode; EMode _mode;
@ -338,6 +339,9 @@ namespace Slic3r {
// Returns the estimated time, in minutes (integer) // Returns the estimated time, in minutes (integer)
std::string get_time_minutes() const; std::string get_time_minutes() const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
private: private:
void _reset(); void _reset();
void _reset_time(); void _reset_time();

View File

@ -946,7 +946,6 @@ Vec3d extract_euler_angles(const Transform3d& transform)
return extract_euler_angles(m); return extract_euler_angles(m);
} }
#if ENABLE_MODELVOLUME_TRANSFORM
Transformation::Flags::Flags() Transformation::Flags::Flags()
: dont_translate(true) : dont_translate(true)
, dont_rotate(true) , dont_rotate(true)
@ -1116,6 +1115,5 @@ Transformation Transformation::operator * (const Transformation& other) const
{ {
return Transformation(get_matrix() * other.get_matrix()); return Transformation(get_matrix() * other.get_matrix());
} }
#endif // ENABLE_MODELVOLUME_TRANSFORM
} } } }

View File

@ -167,7 +167,6 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
// Warning -> The transform should not contain any shear !!! // Warning -> The transform should not contain any shear !!!
Vec3d extract_euler_angles(const Transform3d& transform); Vec3d extract_euler_angles(const Transform3d& transform);
#if ENABLE_MODELVOLUME_TRANSFORM
class Transformation class Transformation
{ {
struct Flags struct Flags
@ -226,7 +225,6 @@ public:
Transformation operator * (const Transformation& other) const; Transformation operator * (const Transformation& other) const;
}; };
#endif // ENABLE_MODELVOLUME_TRANSFORM
} } } }

View File

@ -757,16 +757,11 @@ const BoundingBoxf3& ModelObject::bounding_box() const
BoundingBoxf3 raw_bbox; BoundingBoxf3 raw_bbox;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) if (v->is_model_part())
#if ENABLE_MODELVOLUME_TRANSFORM
{ {
TriangleMesh m = v->mesh; TriangleMesh m = v->mesh;
m.transform(v->get_matrix()); m.transform(v->get_matrix());
raw_bbox.merge(m.bounding_box()); raw_bbox.merge(m.bounding_box());
} }
#else
// mesh.bounding_box() returns a cached value.
raw_bbox.merge(v->mesh.bounding_box());
#endif // ENABLE_MODELVOLUME_TRANSFORM
BoundingBoxf3 bb; BoundingBoxf3 bb;
for (const ModelInstance *i : this->instances) for (const ModelInstance *i : this->instances)
bb.merge(i->transform_bounding_box(raw_bbox)); bb.merge(i->transform_bounding_box(raw_bbox));
@ -797,15 +792,24 @@ TriangleMesh ModelObject::raw_mesh() const
TriangleMesh mesh; TriangleMesh mesh;
for (const ModelVolume *v : this->volumes) for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) if (v->is_model_part())
#if ENABLE_MODELVOLUME_TRANSFORM
{ {
TriangleMesh vol_mesh(v->mesh); TriangleMesh vol_mesh(v->mesh);
vol_mesh.transform(v->get_matrix()); vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh); mesh.merge(vol_mesh);
} }
#else return mesh;
mesh.merge(v->mesh); }
#endif // ENABLE_MODELVOLUME_TRANSFORM
// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
TriangleMesh ModelObject::full_raw_mesh() const
{
TriangleMesh mesh;
for (const ModelVolume *v : this->volumes)
{
TriangleMesh vol_mesh(v->mesh);
vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh);
}
return mesh; return mesh;
} }
@ -819,13 +823,9 @@ BoundingBoxf3 ModelObject::raw_bounding_box() const
if (this->instances.empty()) if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances"); throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
#if ENABLE_MODELVOLUME_TRANSFORM
TriangleMesh vol_mesh(v->mesh); TriangleMesh vol_mesh(v->mesh);
vol_mesh.transform(v->get_matrix()); vol_mesh.transform(v->get_matrix());
bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true)); bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
#else
bb.merge(this->instances.front()->transform_mesh_bounding_box(v->mesh, true));
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
return bb; return bb;
} }
@ -834,7 +834,6 @@ BoundingBoxf3 ModelObject::raw_bounding_box() const
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
{ {
BoundingBoxf3 bb; BoundingBoxf3 bb;
#if ENABLE_MODELVOLUME_TRANSFORM
for (ModelVolume *v : this->volumes) for (ModelVolume *v : this->volumes)
{ {
if (v->is_model_part()) if (v->is_model_part())
@ -844,11 +843,6 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate)); bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate));
} }
} }
#else
for (ModelVolume *v : this->volumes)
if (v->is_model_part())
bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(&v->mesh, dont_translate));
#endif // ENABLE_MODELVOLUME_TRANSFORM
return bb; return bb;
} }
@ -866,15 +860,6 @@ void ModelObject::center_around_origin()
this->translate(shift); this->translate(shift);
this->origin_translation += shift; this->origin_translation += shift;
#if !ENABLE_MODELVOLUME_TRANSFORM
if (!this->instances.empty()) {
for (ModelInstance *i : this->instances) {
i->set_offset(i->get_offset() - shift);
}
this->invalidate_bounding_box();
}
#endif // !ENABLE_MODELVOLUME_TRANSFORM
} }
void ModelObject::ensure_on_bed() void ModelObject::ensure_on_bed()
@ -914,10 +899,6 @@ void ModelObject::scale(const Vec3d &versor)
{ {
v->scale(versor); v->scale(versor);
} }
#if !ENABLE_MODELVOLUME_TRANSFORM
// reset origin translation since it doesn't make sense anymore
this->origin_translation = Vec3d::Zero();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
@ -929,10 +910,6 @@ void ModelObject::rotate(double angle, Axis axis)
} }
center_around_origin(); center_around_origin();
#if !ENABLE_MODELVOLUME_TRANSFORM
this->origin_translation = Vec3d::Zero();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
@ -944,10 +921,6 @@ void ModelObject::rotate(double angle, const Vec3d& axis)
} }
center_around_origin(); center_around_origin();
#if !ENABLE_MODELVOLUME_TRANSFORM
this->origin_translation = Vec3d::Zero();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
@ -958,9 +931,16 @@ void ModelObject::mirror(Axis axis)
v->mirror(axis); v->mirror(axis);
} }
#if !ENABLE_MODELVOLUME_TRANSFORM this->invalidate_bounding_box();
this->origin_translation = Vec3d::Zero(); }
#endif // !ENABLE_MODELVOLUME_TRANSFORM
void ModelObject::scale_mesh(const Vec3d &versor)
{
for (ModelVolume *v : this->volumes)
{
v->scale_geometry(versor);
v->set_offset(versor.cwiseProduct(v->get_offset()));
}
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
@ -1150,7 +1130,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
new_object->instances.reserve(this->instances.size()); new_object->instances.reserve(this->instances.size());
for (const ModelInstance *model_instance : this->instances) for (const ModelInstance *model_instance : this->instances)
new_object->add_instance(*model_instance); new_object->add_instance(*model_instance);
#if ENABLE_MODELVOLUME_TRANSFORM
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh)); ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
new_vol->center_geometry(); new_vol->center_geometry();
@ -1161,9 +1140,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
} }
new_vol->set_offset(Vec3d::Zero()); new_vol->set_offset(Vec3d::Zero());
#else
new_object->add_volume(*volume, std::move(*mesh));
#endif // ENABLE_MODELVOLUME_TRANSFORM
new_objects->emplace_back(new_object); new_objects->emplace_back(new_object);
delete mesh; delete mesh;
} }
@ -1204,7 +1180,6 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
if (!v->is_model_part()) if (!v->is_model_part())
continue; continue;
#if ENABLE_MODELVOLUME_TRANSFORM
Transform3d mv = mi * v->get_matrix(); Transform3d mv = mi * v->get_matrix();
const TriangleMesh& hull = v->get_convex_hull(); const TriangleMesh& hull = v->get_convex_hull();
for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f) for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f)
@ -1214,15 +1189,6 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast<double>())); min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast<double>()));
min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast<double>())); min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast<double>()));
} }
#else
for (uint32_t f = 0; f < v->mesh.stl.stats.number_of_facets; ++f)
{
const stl_facet* facet = v->mesh.stl.facet_start + f;
min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[0].cast<double>()));
min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[1].cast<double>()));
min_z = std::min(min_z, Vec3d::UnitZ().dot(mi * facet->vertex[2].cast<double>()));
}
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
return min_z + inst->get_offset(Z); return min_z + inst->get_offset(Z);
@ -1239,11 +1205,7 @@ unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3
unsigned int inside_outside = 0; unsigned int inside_outside = 0;
for (const ModelVolume *vol : this->volumes) for (const ModelVolume *vol : this->volumes)
if (vol->is_model_part()) { if (vol->is_model_part()) {
#if ENABLE_MODELVOLUME_TRANSFORM
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix()); BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix() * vol->get_matrix());
#else
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(model_instance->get_matrix());
#endif // ENABLE_MODELVOLUME_TRANSFORM
if (print_volume.contains(bb)) if (print_volume.contains(bb))
inside_outside |= INSIDE; inside_outside |= INSIDE;
else if (print_volume.intersects(bb)) else if (print_volume.intersects(bb))
@ -1335,7 +1297,6 @@ int ModelVolume::extruder_id() const
return extruder_id; return extruder_id;
} }
#if ENABLE_MODELVOLUME_TRANSFORM
void ModelVolume::center_geometry() void ModelVolume::center_geometry()
{ {
Vec3d shift = -mesh.bounding_box().center(); Vec3d shift = -mesh.bounding_box().center();
@ -1343,7 +1304,6 @@ void ModelVolume::center_geometry()
m_convex_hull.translate((float)shift(0), (float)shift(1), (float)shift(2)); m_convex_hull.translate((float)shift(0), (float)shift(1), (float)shift(2));
translate(-shift); translate(-shift);
} }
#endif // ENABLE_MODELVOLUME_TRANSFORM
void ModelVolume::calculate_convex_hull() void ModelVolume::calculate_convex_hull()
{ {
@ -1403,9 +1363,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
std::string name = this->name; std::string name = this->name;
Model::reset_auto_extruder_id(); Model::reset_auto_extruder_id();
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3d offset = this->get_offset(); Vec3d offset = this->get_offset();
#endif // ENABLE_MODELVOLUME_TRANSFORM
for (TriangleMesh *mesh : meshptrs) { for (TriangleMesh *mesh : meshptrs) {
mesh->repair(); mesh->repair();
@ -1419,11 +1377,9 @@ size_t ModelVolume::split(unsigned int max_extruders)
else else
this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh))); this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
#if ENABLE_MODELVOLUME_TRANSFORM
this->object->volumes[ivolume]->set_offset(Vec3d::Zero()); this->object->volumes[ivolume]->set_offset(Vec3d::Zero());
this->object->volumes[ivolume]->center_geometry(); this->object->volumes[ivolume]->center_geometry();
this->object->volumes[ivolume]->translate(offset); this->object->volumes[ivolume]->translate(offset);
#endif // ENABLE_MODELVOLUME_TRANSFORM
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1); this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders));
delete mesh; delete mesh;
@ -1435,52 +1391,31 @@ size_t ModelVolume::split(unsigned int max_extruders)
void ModelVolume::translate(const Vec3d& displacement) void ModelVolume::translate(const Vec3d& displacement)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
set_offset(get_offset() + displacement); set_offset(get_offset() + displacement);
#else
mesh.translate((float)displacement(0), (float)displacement(1), (float)displacement(2));
m_convex_hull.translate((float)displacement(0), (float)displacement(1), (float)displacement(2));
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
void ModelVolume::scale(const Vec3d& scaling_factors) void ModelVolume::scale(const Vec3d& scaling_factors)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
set_scaling_factor(get_scaling_factor().cwiseProduct(scaling_factors)); set_scaling_factor(get_scaling_factor().cwiseProduct(scaling_factors));
#else
mesh.scale(scaling_factors);
m_convex_hull.scale(scaling_factors);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
void ModelVolume::rotate(double angle, Axis axis) void ModelVolume::rotate(double angle, Axis axis)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
switch (axis) switch (axis)
{ {
case X: { rotate(angle, Vec3d::UnitX()); break; } case X: { rotate(angle, Vec3d::UnitX()); break; }
case Y: { rotate(angle, Vec3d::UnitY()); break; } case Y: { rotate(angle, Vec3d::UnitY()); break; }
case Z: { rotate(angle, Vec3d::UnitZ()); break; } case Z: { rotate(angle, Vec3d::UnitZ()); break; }
} }
#else
mesh.rotate(angle, axis);
m_convex_hull.rotate(angle, axis);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
void ModelVolume::rotate(double angle, const Vec3d& axis) void ModelVolume::rotate(double angle, const Vec3d& axis)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
set_rotation(get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix())); set_rotation(get_rotation() + Geometry::extract_euler_angles(Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis)).toRotationMatrix()));
#else
mesh.rotate(angle, axis);
m_convex_hull.rotate(angle, axis);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
void ModelVolume::mirror(Axis axis) void ModelVolume::mirror(Axis axis)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3d mirror = get_mirror(); Vec3d mirror = get_mirror();
switch (axis) switch (axis)
{ {
@ -1489,65 +1424,14 @@ void ModelVolume::mirror(Axis axis)
case Z: { mirror(2) *= -1.0; break; } case Z: { mirror(2) *= -1.0; break; }
} }
set_mirror(mirror); set_mirror(mirror);
#else
mesh.mirror(axis);
m_convex_hull.mirror(axis);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
#if !ENABLE_MODELVOLUME_TRANSFORM void ModelVolume::scale_geometry(const Vec3d& versor)
void ModelInstance::set_rotation(const Vec3d& rotation)
{ {
set_rotation(X, rotation(0)); mesh.scale(versor);
set_rotation(Y, rotation(1)); m_convex_hull.scale(versor);
set_rotation(Z, rotation(2));
} }
void ModelInstance::set_rotation(Axis axis, double rotation)
{
static const double TWO_PI = 2.0 * (double)PI;
while (rotation < 0.0)
{
rotation += TWO_PI;
}
while (TWO_PI < rotation)
{
rotation -= TWO_PI;
}
m_rotation(axis) = rotation;
}
void ModelInstance::set_scaling_factor(const Vec3d& scaling_factor)
{
set_scaling_factor(X, scaling_factor(0));
set_scaling_factor(Y, scaling_factor(1));
set_scaling_factor(Z, scaling_factor(2));
}
void ModelInstance::set_scaling_factor(Axis axis, double scaling_factor)
{
m_scaling_factor(axis) = std::abs(scaling_factor);
}
void ModelInstance::set_mirror(const Vec3d& mirror)
{
set_mirror(X, mirror(0));
set_mirror(Y, mirror(1));
set_mirror(Z, mirror(2));
}
void ModelInstance::set_mirror(Axis axis, double mirror)
{
double abs_mirror = std::abs(mirror);
if (abs_mirror == 0.0)
mirror = 1.0;
else if (abs_mirror != 1.0)
mirror /= abs_mirror;
m_mirror(axis) = mirror;
}
#endif // !ENABLE_MODELVOLUME_TRANSFORM
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
{ {
mesh->transform(get_matrix(dont_translate)); mesh->transform(get_matrix(dont_translate));
@ -1564,29 +1448,17 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mes
// Scale the bounding box along the three axes. // Scale the bounding box along the three axes.
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
if (std::abs(get_scaling_factor((Axis)i)-1.0) > EPSILON) if (std::abs(get_scaling_factor((Axis)i)-1.0) > EPSILON)
{ {
bbox.min(i) *= get_scaling_factor((Axis)i); bbox.min(i) *= get_scaling_factor((Axis)i);
bbox.max(i) *= get_scaling_factor((Axis)i); bbox.max(i) *= get_scaling_factor((Axis)i);
#else
if (std::abs(this->m_scaling_factor(i) - 1.0) > EPSILON)
{
bbox.min(i) *= this->m_scaling_factor(i);
bbox.max(i) *= this->m_scaling_factor(i);
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
} }
// Translate the bounding box. // Translate the bounding box.
if (! dont_translate) { if (! dont_translate) {
#if ENABLE_MODELVOLUME_TRANSFORM
bbox.min += get_offset(); bbox.min += get_offset();
bbox.max += get_offset(); bbox.max += get_offset();
#else
bbox.min += this->m_offset;
bbox.max += this->m_offset;
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
} }
return bbox; return bbox;
@ -1604,30 +1476,12 @@ Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
void ModelInstance::transform_polygon(Polygon* polygon) const void ModelInstance::transform_polygon(Polygon* polygon) const
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
// CHECK_ME -> Is the following correct or it should take in account all three rotations ? // CHECK_ME -> Is the following correct or it should take in account all three rotations ?
polygon->rotate(get_rotation(Z)); // rotate around polygon origin polygon->rotate(get_rotation(Z)); // rotate around polygon origin
// CHECK_ME -> Is the following correct ? // CHECK_ME -> Is the following correct ?
polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin polygon->scale(get_scaling_factor(X), get_scaling_factor(Y)); // scale around polygon origin
#else
// CHECK_ME -> Is the following correct or it should take in account all three rotations ?
polygon->rotate(this->m_rotation(2)); // rotate around polygon origin
// CHECK_ME -> Is the following correct ?
polygon->scale(this->m_scaling_factor(0), this->m_scaling_factor(1)); // scale around polygon origin
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
#if !ENABLE_MODELVOLUME_TRANSFORM
Transform3d ModelInstance::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{
Vec3d translation = dont_translate ? Vec3d::Zero() : m_offset;
Vec3d rotation = dont_rotate ? Vec3d::Zero() : m_rotation;
Vec3d scale = dont_scale ? Vec3d::Ones() : m_scaling_factor;
Vec3d mirror = dont_mirror ? Vec3d::Ones() : m_mirror;
return Geometry::assemble_transform(translation, rotation, scale, mirror);
}
#endif // !ENABLE_MODELVOLUME_TRANSFORM
// Test whether the two models contain the same number of ModelObjects with the same set of IDs // Test whether the two models contain the same number of ModelObjects with the same set of IDs
// ordered in the same order. In that case it is not necessary to kill the background processing. // ordered in the same order. In that case it is not necessary to kill the background processing.
bool model_object_list_equal(const Model &model_old, const Model &model_new) bool model_object_list_equal(const Model &model_old, const Model &model_new)
@ -1671,10 +1525,9 @@ bool model_volume_list_changed(const ModelObject &model_object_old, const ModelO
return true; return true;
//FIXME test for the content of the mesh! //FIXME test for the content of the mesh!
#if ENABLE_MODELVOLUME_TRANSFORM
if (!mv_old.get_matrix().isApprox(mv_new.get_matrix())) if (!mv_old.get_matrix().isApprox(mv_new.get_matrix()))
return true; return true;
#endif // ENABLE_MODELVOLUME_TRANSFORM
++i_old; ++i_old;
++ i_new; ++ i_new;
} }

View File

@ -11,9 +11,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#if ENABLE_MODELVOLUME_TRANSFORM
#include "Geometry.hpp" #include "Geometry.hpp"
#endif // ENABLE_MODELVOLUME_TRANSFORM
namespace Slic3r { namespace Slic3r {
@ -218,6 +216,8 @@ public:
// Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes. // Non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
// Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter. // Currently used by ModelObject::mesh() and to calculate the 2D envelope for 2D platter.
TriangleMesh raw_mesh() const; TriangleMesh raw_mesh() const;
// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
TriangleMesh full_raw_mesh() const;
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied. // A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing. // This bounding box is only used for the actual slicing.
BoundingBoxf3 raw_bounding_box() const; BoundingBoxf3 raw_bounding_box() const;
@ -235,6 +235,9 @@ public:
void rotate(double angle, Axis axis); void rotate(double angle, Axis axis);
void rotate(double angle, const Vec3d& axis); void rotate(double angle, const Vec3d& axis);
void mirror(Axis axis); void mirror(Axis axis);
void scale_mesh(const Vec3d& versor);
size_t materials_count() const; size_t materials_count() const;
size_t facets_count() const; size_t facets_count() const;
bool needed_repair() const; bool needed_repair() const;
@ -329,10 +332,10 @@ public:
void rotate(double angle, const Vec3d& axis); void rotate(double angle, const Vec3d& axis);
void mirror(Axis axis); void mirror(Axis axis);
#if ENABLE_MODELVOLUME_TRANSFORM void scale_geometry(const Vec3d& versor);
// translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box // translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box
void center_geometry(); void center_geometry();
#endif // ENABLE_MODELVOLUME_TRANSFORM
void calculate_convex_hull(); void calculate_convex_hull();
const TriangleMesh& get_convex_hull() const; const TriangleMesh& get_convex_hull() const;
@ -341,7 +344,6 @@ public:
static Type type_from_string(const std::string &s); static Type type_from_string(const std::string &s);
static std::string type_to_string(const Type t); static std::string type_to_string(const Type t);
#if ENABLE_MODELVOLUME_TRANSFORM
const Geometry::Transformation& get_transformation() const { return m_transformation; } const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; } void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
@ -370,7 +372,6 @@ public:
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
#endif // ENABLE_MODELVOLUME_TRANSFORM
protected: protected:
friend class Print; friend class Print;
@ -388,9 +389,7 @@ private:
t_model_material_id m_material_id; t_model_material_id m_material_id;
// The convex hull of this model's mesh. // The convex hull of this model's mesh.
TriangleMesh m_convex_hull; TriangleMesh m_convex_hull;
#if ENABLE_MODELVOLUME_TRANSFORM
Geometry::Transformation m_transformation; Geometry::Transformation m_transformation;
#endif // ENABLE_MODELVOLUME_TRANSFORM
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object) ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
{ {
@ -400,7 +399,6 @@ private:
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {} mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {}
#if ENABLE_MODELVOLUME_TRANSFORM
// Copying an existing volume, therefore this volume will get a copy of the ID assigned. // Copying an existing volume, therefore this volume will get a copy of the ID assigned.
ModelVolume(ModelObject *object, const ModelVolume &other) : ModelVolume(ModelObject *object, const ModelVolume &other) :
ModelBase(other), // copy the ID ModelBase(other), // copy the ID
@ -416,25 +414,6 @@ private:
if (mesh.stl.stats.number_of_facets > 1) if (mesh.stl.stats.number_of_facets > 1)
calculate_convex_hull(); calculate_convex_hull();
} }
#else
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
ModelVolume(ModelObject *object, const ModelVolume &other) :
ModelBase(other), // copy the ID
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object)
{
if (! other.material_id().empty())
this->set_material_id(other.material_id());
}
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) :
name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object)
{
if (! other.material_id().empty())
this->set_material_id(other.material_id());
if (mesh.stl.stats.number_of_facets > 1)
calculate_convex_hull();
}
#endif // ENABLE_MODELVOLUME_TRANSFORM
ModelVolume& operator=(ModelVolume &rhs) = delete; ModelVolume& operator=(ModelVolume &rhs) = delete;
}; };
@ -453,14 +432,7 @@ public:
}; };
private: private:
#if ENABLE_MODELVOLUME_TRANSFORM
Geometry::Transformation m_transformation; Geometry::Transformation m_transformation;
#else
Vec3d m_offset; // in unscaled coordinates
Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point
Vec3d m_scaling_factor; // Scaling factors along the three axes
Vec3d m_mirror; // Mirroring along the three axes
#endif // ENABLE_MODELVOLUME_TRANSFORM
public: public:
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
@ -468,7 +440,6 @@ public:
ModelObject* get_object() const { return this->object; } ModelObject* get_object() const { return this->object; }
#if ENABLE_MODELVOLUME_TRANSFORM
const Geometry::Transformation& get_transformation() const { return m_transformation; } const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; } void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
@ -495,31 +466,6 @@ public:
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); }
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }
#else
const Vec3d& get_offset() const { return m_offset; }
double get_offset(Axis axis) const { return m_offset(axis); }
void set_offset(const Vec3d& offset) { m_offset = offset; }
void set_offset(Axis axis, double offset) { m_offset(axis) = offset; }
const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); }
void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double rotation);
Vec3d get_scaling_factor() const { return m_scaling_factor; }
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
void set_scaling_factor(const Vec3d& scaling_factor);
void set_scaling_factor(Axis axis, double scaling_factor);
const Vec3d& get_mirror() const { return m_mirror; }
double get_mirror(Axis axis) const { return m_mirror(axis); }
void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror);
#endif // ENABLE_MODELVOLUME_TRANSFORM
// To be called on an external mesh // To be called on an external mesh
void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
@ -532,11 +478,7 @@ public:
// To be called on an external polygon. It does not translate the polygon, only rotates and scales. // To be called on an external polygon. It does not translate the polygon, only rotates and scales.
void transform_polygon(Polygon* polygon) const; void transform_polygon(Polygon* polygon) const;
#if ENABLE_MODELVOLUME_TRANSFORM
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
#else
Transform3d get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
#endif // ENABLE_MODELVOLUME_TRANSFORM
bool is_printable() const { return print_volume_state == PVS_Inside; } bool is_printable() const { return print_volume_state == PVS_Inside; }
@ -552,17 +494,11 @@ private:
// Parent object, owning this instance. // Parent object, owning this instance.
ModelObject* object; ModelObject* object;
#if ENABLE_MODELVOLUME_TRANSFORM
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {} explicit ModelInstance(ModelObject *object) : object(object), print_volume_state(PVS_Inside) {}
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object, const ModelInstance &other) : explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {} m_transformation(other.m_transformation), object(object), print_volume_state(PVS_Inside) {}
#else
explicit ModelInstance(ModelObject *object) : m_offset(Vec3d::Zero()), m_rotation(Vec3d::Zero()), m_scaling_factor(Vec3d::Ones()), m_mirror(Vec3d::Ones()), object(object), print_volume_state(PVS_Inside) {}
explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
m_offset(other.m_offset), m_rotation(other.m_rotation), m_scaling_factor(other.m_scaling_factor), m_mirror(other.m_mirror), object(object), print_volume_state(PVS_Inside) {}
#endif // ENABLE_MODELVOLUME_TRANSFORM
ModelInstance() = delete; ModelInstance() = delete;
explicit ModelInstance(ModelInstance &&rhs) = delete; explicit ModelInstance(ModelInstance &&rhs) = delete;

View File

@ -135,11 +135,6 @@ objfunc(const PointImpl& bincenter,
const ItemGroup& remaining const ItemGroup& remaining
) )
{ {
using Coord = TCoord<PointImpl>;
static const double ROUNDNESS_RATIO = 0.5;
static const double DENSITY_RATIO = 1.0 - ROUNDNESS_RATIO;
// We will treat big items (compared to the print bed) differently // We will treat big items (compared to the print bed) differently
auto isBig = [bin_area](double a) { auto isBig = [bin_area](double a) {
return a/bin_area > BIG_ITEM_TRESHOLD ; return a/bin_area > BIG_ITEM_TRESHOLD ;
@ -516,8 +511,9 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
ModelInstance * finst = objptr->instances.front(); ModelInstance * finst = objptr->instances.front();
// Object instances should carry the same scaling and // Object instances should carry the same scaling and
// x, y rotation that is why we use the first instance // x, y rotation that is why we use the first instance.
rmesh.scale(finst->get_scaling_factor()); // The next line will apply only the full mirroring and scaling
rmesh.transform(finst->get_matrix(true, true, false, false));
rmesh.rotate_x(float(finst->get_rotation()(X))); rmesh.rotate_x(float(finst->get_rotation()(X)));
rmesh.rotate_y(float(finst->get_rotation()(Y))); rmesh.rotate_y(float(finst->get_rotation()(Y)));
@ -629,11 +625,12 @@ BedShapeHint bedShape(const Polyline &bed) {
avg_dist /= vertex_distances.size(); avg_dist /= vertex_distances.size();
Circle ret(center, avg_dist); Circle ret(center, avg_dist);
for (auto el: vertex_distances) for(auto el : vertex_distances)
{ {
if (abs(el - avg_dist) > 10 * SCALED_EPSILON) if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) {
ret = Circle(); ret = Circle();
break; break;
}
} }
return ret; return ret;
@ -665,8 +662,6 @@ bool arrange(Model &model,
std::function<void (unsigned)> progressind, std::function<void (unsigned)> progressind,
std::function<bool ()> stopcondition) std::function<bool ()> stopcondition)
{ {
using ArrangeResult = _IndexedPackGroup<PolygonImpl>;
bool ret = true; bool ret = true;
// Get the 2D projected shapes with their 3D model instance pointers // Get the 2D projected shapes with their 3D model instance pointers

View File

@ -18,8 +18,8 @@ void MultiPoint::scale(double factor_x, double factor_y)
{ {
for (Point &pt : points) for (Point &pt : points)
{ {
pt(0) *= factor_x; pt(0) = coord_t(pt(0) * factor_x);
pt(1) *= factor_y; pt(1) = coord_t(pt(1) * factor_y);
} }
} }
@ -83,7 +83,7 @@ MultiPoint::find_point(const Point &point) const
{ {
for (const Point &pt : this->points) for (const Point &pt : this->points)
if (pt == point) if (pt == point)
return &pt - &this->points.front(); return int(&pt - &this->points.front());
return -1; // not found return -1; // not found
} }
@ -202,6 +202,7 @@ Point MultiPoint::point_projection(const Point &point) const {
std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, const double tolerance) std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, const double tolerance)
{ {
std::vector<Point> result_pts; std::vector<Point> result_pts;
double tolerance_sq = tolerance * tolerance;
if (! pts.empty()) { if (! pts.empty()) {
const Point *anchor = &pts.front(); const Point *anchor = &pts.front();
size_t anchor_idx = 0; size_t anchor_idx = 0;
@ -215,18 +216,18 @@ std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, c
dpStack.reserve(pts.size()); dpStack.reserve(pts.size());
dpStack.emplace_back(floater_idx); dpStack.emplace_back(floater_idx);
for (;;) { for (;;) {
double max_distSq = 0.0; double max_dist_sq = 0.0;
size_t furthest_idx = anchor_idx; size_t furthest_idx = anchor_idx;
// find point furthest from line seg created by (anchor, floater) and note it // find point furthest from line seg created by (anchor, floater) and note it
for (size_t i = anchor_idx + 1; i < floater_idx; ++ i) { for (size_t i = anchor_idx + 1; i < floater_idx; ++ i) {
double dist = Line::distance_to_squared(pts[i], *anchor, *floater); double dist_sq = Line::distance_to_squared(pts[i], *anchor, *floater);
if (dist > max_distSq) { if (dist_sq > max_dist_sq) {
max_distSq = dist; max_dist_sq = dist_sq;
furthest_idx = i; furthest_idx = i;
} }
} }
// remove point if less than tolerance // remove point if less than tolerance
if (max_distSq <= tolerance) { if (max_dist_sq <= tolerance_sq) {
result_pts.emplace_back(*floater); result_pts.emplace_back(*floater);
anchor_idx = floater_idx; anchor_idx = floater_idx;
anchor = floater; anchor = floater;
@ -369,8 +370,8 @@ Points MultiPoint::visivalingam(const Points& pts, const double& tolerance)
void MultiPoint3::translate(double x, double y) void MultiPoint3::translate(double x, double y)
{ {
for (Vec3crd &p : points) { for (Vec3crd &p : points) {
p(0) += x; p(0) += coord_t(x);
p(1) += y; p(1) += coord_t(y);
} }
} }

View File

@ -8,13 +8,14 @@
#include "SupportMaterial.hpp" #include "SupportMaterial.hpp"
#include "GCode.hpp" #include "GCode.hpp"
#include "GCode/WipeTowerPrusaMM.hpp" #include "GCode/WipeTowerPrusaMM.hpp"
#include <algorithm> #include "Utils.hpp"
#include <unordered_set>
#include <boost/log/trivial.hpp>
#include "PrintExport.hpp" #include "PrintExport.hpp"
#include <algorithm>
#include <unordered_set>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/log/trivial.hpp>
//! macro used to mark string used at localization, //! macro used to mark string used at localization,
//! return same string //! return same string
@ -762,7 +763,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
update_apply_status(this->invalidate_all_steps()); update_apply_status(this->invalidate_all_steps());
for (PrintObject *object : m_objects) { for (PrintObject *object : m_objects) {
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
delete object; update_apply_status(object->invalidate_all_steps());
delete object;
} }
m_objects.clear(); m_objects.clear();
for (PrintRegion *region : m_regions) for (PrintRegion *region : m_regions)
@ -992,12 +994,9 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Deleted; const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Deleted;
} else { } else {
// The PrintObject already exists and the copies differ. // The PrintObject already exists and the copies differ.
if ((*it_old)->print_object->copies().size() != new_instances.copies.size()) PrintBase::ApplyStatus status = (*it_old)->print_object->set_copies(new_instances.copies);
update_apply_status(this->invalidate_step(psWipeTower)); if (status != PrintBase::APPLY_STATUS_UNCHANGED)
if ((*it_old)->print_object->set_copies(new_instances.copies)) { update_apply_status(status == PrintBase::APPLY_STATUS_INVALIDATED);
// Invalidated
update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psGCodeExport }));
}
print_objects_new.emplace_back((*it_old)->print_object); print_objects_new.emplace_back((*it_old)->print_object);
const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Reused; const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Reused;
} }
@ -1011,13 +1010,14 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
bool deleted_objects = false; bool deleted_objects = false;
for (auto &pos : print_object_status) for (auto &pos : print_object_status)
if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) { if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) {
// update_apply_status(pos.print_object->invalidate_all_steps()); update_apply_status(pos.print_object->invalidate_all_steps());
delete pos.print_object; delete pos.print_object;
deleted_objects = true; deleted_objects = true;
} }
if (new_objects || deleted_objects) if (new_objects || deleted_objects)
update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport })); update_apply_status(this->invalidate_steps({ psSkirt, psBrim, psWipeTower, psGCodeExport }));
update_apply_status(new_objects); if (new_objects)
update_apply_status(false);
} }
print_object_status.clear(); print_object_status.clear();
} }
@ -1055,10 +1055,12 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
goto print_object_end; goto print_object_end;
} else { } else {
this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders); this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders);
for (size_t i = 0; i < region_id; ++ i) for (size_t i = 0; i < region_id; ++i) {
if (m_regions[i]->config().equals(this_region_config)) const PrintRegion &region_other = *m_regions[i];
// Regions were merged. Reset this print_object. if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
goto print_object_end; // Regions were merged. Reset this print_object.
goto print_object_end;
}
this_region_config_set = true; this_region_config_set = true;
} }
} }
@ -1096,8 +1098,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
bool fresh = print_object.region_volumes.empty(); bool fresh = print_object.region_volumes.empty();
unsigned int volume_id = 0; unsigned int volume_id = 0;
for (const ModelVolume *volume : model_object.volumes) { for (const ModelVolume *volume : model_object.volumes) {
if (! volume->is_model_part() && ! volume->is_modifier()) if (! volume->is_model_part() && ! volume->is_modifier()) {
continue; ++ volume_id;
continue;
}
int region_id = -1; int region_id = -1;
if (&print_object == &print_object0) { if (&print_object == &print_object0) {
// Get the config applied to this volume. // Get the config applied to this volume.
@ -1105,9 +1109,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
// Find an existing print region with the same config. // Find an existing print region with the same config.
int idx_empty_slot = -1; int idx_empty_slot = -1;
for (int i = 0; i < (int)m_regions.size(); ++ i) { for (int i = 0; i < (int)m_regions.size(); ++ i) {
if (m_regions[i]->m_refcnt == 0) if (m_regions[i]->m_refcnt == 0) {
idx_empty_slot = i; if (idx_empty_slot == -1)
else if (config.equals(m_regions[i]->config())) { idx_empty_slot = i;
} else if (config.equals(m_regions[i]->config())) {
region_id = i; region_id = i;
break; break;
} }
@ -1473,7 +1478,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
// Slicing process, running at a background thread. // Slicing process, running at a background thread.
void Print::process() void Print::process()
{ {
BOOST_LOG_TRIVIAL(info) << "Staring the slicing process."; BOOST_LOG_TRIVIAL(info) << "Staring the slicing process." << log_memory_info();
for (PrintObject *obj : m_objects) for (PrintObject *obj : m_objects)
obj->make_perimeters(); obj->make_perimeters();
this->set_status(70, "Infilling layers"); this->set_status(70, "Infilling layers");
@ -1505,7 +1510,7 @@ void Print::process()
} }
this->set_done(psWipeTower); this->set_done(psWipeTower);
} }
BOOST_LOG_TRIVIAL(info) << "Slicing process finished."; BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info();
} }
// G-code export process, running at a background thread. // G-code export process, running at a background thread.
@ -1630,7 +1635,9 @@ void Print::_make_skirt()
{ {
Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, scale_(0.1)); Polygons loops = offset(convex_hull, distance, ClipperLib::jtRound, scale_(0.1));
Geometry::simplify_polygons(loops, scale_(0.05), &loops); Geometry::simplify_polygons(loops, scale_(0.05), &loops);
loop = loops.front(); if (loops.empty())
break;
loop = loops.front();
} }
// Extrude the skirt loop. // Extrude the skirt loop.
ExtrusionLoop eloop(elrSkirt); ExtrusionLoop eloop(elrSkirt);

View File

@ -107,8 +107,8 @@ public:
// adds region_id, too, if necessary // adds region_id, too, if necessary
void add_region_volume(unsigned int region_id, int volume_id) { void add_region_volume(unsigned int region_id, int volume_id) {
if (region_id >= region_volumes.size()) if (region_id >= region_volumes.size())
region_volumes.resize(region_id + 1); region_volumes.resize(region_id + 1);
region_volumes[region_id].push_back(volume_id); region_volumes[region_id].emplace_back(volume_id);
} }
// This is the *total* layer count (including support layers) // This is the *total* layer count (including support layers)
// this value is not supposed to be compared with Layer::id // this value is not supposed to be compared with Layer::id
@ -164,7 +164,7 @@ protected:
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } void set_trafo(const Transform3d& trafo) { m_trafo = trafo; }
bool set_copies(const Points &points); PrintBase::ApplyStatus set_copies(const Points &points);
// Invalidates the step, and its depending steps in PrintObject and Print. // Invalidates the step, and its depending steps in PrintObject and Print.
bool invalidate_step(PrintObjectStep step); bool invalidate_step(PrintObjectStep step);
// Invalidates all PrintObject and Print steps. // Invalidates all PrintObject and Print steps.

View File

@ -2670,7 +2670,9 @@ void PrintConfigDef::init_sla_params()
def = this->add("display_orientation", coEnum); def = this->add("display_orientation", coEnum);
def->label = L("Display orientation"); def->label = L("Display orientation");
def->tooltip = L("Display orientation"); def->tooltip = L("Set the actual LCD display orientation inside the SLA printer."
" Portrait mode will flip the meaning of display width and height parameters"
" and the output images will be rotated by 90 degrees.");
def->cli = "display-orientation=s"; def->cli = "display-orientation=s";
def->enum_keys_map = &ConfigOptionEnum<SLADisplayOrientation>::get_enum_values(); def->enum_keys_map = &ConfigOptionEnum<SLADisplayOrientation>::get_enum_values();
def->enum_values.push_back("landscape"); def->enum_values.push_back("landscape");

View File

@ -36,7 +36,7 @@ enum GCodeFlavor {
}; };
enum PrintHostType { enum PrintHostType {
htOctoPrint, htDuet, htOctoPrint, htDuet, htSL1,
}; };
enum InfillPattern { enum InfillPattern {

View File

@ -5,6 +5,7 @@
#include "SupportMaterial.hpp" #include "SupportMaterial.hpp"
#include "Surface.hpp" #include "Surface.hpp"
#include "Slicing.hpp" #include "Slicing.hpp"
#include "Utils.hpp"
#include <utility> #include <utility>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
@ -68,7 +69,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
this->layer_height_profile = model_object->layer_height_profile; this->layer_height_profile = model_object->layer_height_profile;
} }
bool PrintObject::set_copies(const Points &points) PrintBase::ApplyStatus PrintObject::set_copies(const Points &points)
{ {
// Order copies with a nearest-neighbor search. // Order copies with a nearest-neighbor search.
std::vector<Point> copies; std::vector<Point> copies;
@ -80,14 +81,15 @@ bool PrintObject::set_copies(const Points &points)
copies.emplace_back(points[point_idx] + m_copies_shift); copies.emplace_back(points[point_idx] + m_copies_shift);
} }
// Invalidate and set copies. // Invalidate and set copies.
bool invalidated = false; PrintBase::ApplyStatus status = PrintBase::APPLY_STATUS_UNCHANGED;
if (copies != m_copies) { if (copies != m_copies) {
invalidated = m_print->invalidate_steps({ psSkirt, psBrim, psGCodeExport }); status = PrintBase::APPLY_STATUS_CHANGED;
if (copies.size() != m_copies.size()) if (m_print->invalidate_steps({ psSkirt, psBrim, psGCodeExport }) ||
invalidated |= m_print->invalidate_step(psWipeTower); (copies.size() != m_copies.size() && m_print->invalidate_step(psWipeTower)))
status = PrintBase::APPLY_STATUS_INVALIDATED;
m_copies = copies; m_copies = copies;
} }
return invalidated; return status;
} }
// 1) Decides Z positions of the layers, // 1) Decides Z positions of the layers,
@ -132,7 +134,7 @@ void PrintObject::make_perimeters()
return; return;
m_print->set_status(20, "Generating perimeters"); m_print->set_status(20, "Generating perimeters");
BOOST_LOG_TRIVIAL(info) << "Generating perimeters..."; BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
// merge slices if they were split into types // merge slices if they were split into types
if (this->typed_slices) { if (this->typed_slices) {
@ -253,7 +255,7 @@ void PrintObject::prepare_infill()
// Decide what surfaces are to be filled. // Decide what surfaces are to be filled.
// Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured. // Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured.
// Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID. // Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID.
BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..."; BOOST_LOG_TRIVIAL(info) << "Preparing fill surfaces..." << log_memory_info();
for (auto *layer : m_layers) for (auto *layer : m_layers)
for (auto *region : layer->m_regions) { for (auto *region : layer->m_regions) {
region->prepare_fill_surfaces(); region->prepare_fill_surfaces();
@ -587,15 +589,15 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
// propagate to dependent steps // propagate to dependent steps
if (step == posPerimeters) { if (step == posPerimeters) {
invalidated |= this->invalidate_step(posPrepareInfill); invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill });
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
} else if (step == posPrepareInfill) { } else if (step == posPrepareInfill) {
invalidated |= this->invalidate_step(posInfill); invalidated |= this->invalidate_step(posInfill);
} else if (step == posInfill) { } else if (step == posInfill) {
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
} else if (step == posSlice) { } else if (step == posSlice) {
invalidated |= this->invalidate_steps({ posPerimeters, posSupportMaterial }); invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posSupportMaterial });
invalidated |= m_print->invalidate_step(psWipeTower); invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
} else if (step == posSupportMaterial) } else if (step == posSupportMaterial)
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim }); invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
@ -882,7 +884,7 @@ void PrintObject::count_distance_solid() {
// If a part of a region is of stBottom and stTop, the stBottom wins. // If a part of a region is of stBottom and stTop, the stBottom wins.
void PrintObject::detect_surfaces_type() void PrintObject::detect_surfaces_type()
{ {
BOOST_LOG_TRIVIAL(info) << "Detecting solid surfaces..."; BOOST_LOG_TRIVIAL(info) << "Detecting solid surfaces..." << log_memory_info();
// Interface shells: the intersecting parts are treated as self standing objects supporting each other. // Interface shells: the intersecting parts are treated as self standing objects supporting each other.
// Each of the objects will have a full number of top / bottom layers, even if these top / bottom layers // Each of the objects will have a full number of top / bottom layers, even if these top / bottom layers
@ -1076,7 +1078,7 @@ void PrintObject::detect_surfaces_type()
void PrintObject::process_external_surfaces() void PrintObject::process_external_surfaces()
{ {
BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..."; BOOST_LOG_TRIVIAL(info) << "Processing external surfaces..." << log_memory_info();
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) { for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) {
const PrintRegion &region = *m_print->regions()[region_id]; const PrintRegion &region = *m_print->regions()[region_id];
@ -1101,7 +1103,7 @@ void PrintObject::discover_vertical_shells()
{ {
PROFILE_FUNC(); PROFILE_FUNC();
BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..."; BOOST_LOG_TRIVIAL(info) << "Discovering vertical shells..." << log_memory_info();
struct DiscoverVerticalShellsCacheEntry struct DiscoverVerticalShellsCacheEntry
{ {
@ -1485,7 +1487,7 @@ void PrintObject::discover_vertical_shells()
sparse infill */ sparse infill */
void PrintObject::bridge_over_infill() void PrintObject::bridge_over_infill()
{ {
BOOST_LOG_TRIVIAL(info) << "Bridge over infill..."; BOOST_LOG_TRIVIAL(info) << "Bridge over infill..." << log_memory_info();
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) { for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
const PrintRegion &region = *m_print->regions()[region_id]; const PrintRegion &region = *m_print->regions()[region_id];
@ -1833,7 +1835,7 @@ bool PrintObject::update_layer_height_profile()
// this should be idempotent // this should be idempotent
void PrintObject::_slice() void PrintObject::_slice()
{ {
BOOST_LOG_TRIVIAL(info) << "Slicing objects..."; BOOST_LOG_TRIVIAL(info) << "Slicing objects..." << log_memory_info();
this->typed_slices = false; this->typed_slices = false;
@ -2064,15 +2066,11 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
TriangleMesh mesh; TriangleMesh mesh;
for (const ModelVolume *v : volumes) for (const ModelVolume *v : volumes)
#if ENABLE_MODELVOLUME_TRANSFORM
{ {
TriangleMesh vol_mesh(v->mesh); TriangleMesh vol_mesh(v->mesh);
vol_mesh.transform(v->get_matrix()); vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh); mesh.merge(vol_mesh);
} }
#else
mesh.merge(v->mesh);
#endif // ENABLE_MODELVOLUME_TRANSFORM
if (mesh.stl.stats.number_of_facets > 0) { if (mesh.stl.stats.number_of_facets > 0) {
mesh.transform(m_trafo); mesh.transform(m_trafo);
// apply XY shift // apply XY shift
@ -2197,7 +2195,7 @@ void PrintObject::_make_perimeters()
if (! this->set_started(posPerimeters)) if (! this->set_started(posPerimeters))
return; return;
BOOST_LOG_TRIVIAL(info) << "Generating perimeters..."; BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
// merge slices if they were split into types // merge slices if they were split into types
if (this->typed_slices) { if (this->typed_slices) {

View File

@ -3,23 +3,50 @@
#include "SLAAutoSupports.hpp" #include "SLAAutoSupports.hpp"
#include "Model.hpp" #include "Model.hpp"
#include "ExPolygon.hpp"
#include "SVG.hpp"
#include "Point.hpp"
#include "ClipperUtils.hpp"
#include <iostream> #include <iostream>
#include <random>
namespace Slic3r { namespace Slic3r {
SLAAutoSupports::SLAAutoSupports(ModelObject& mo, const SLAAutoSupports::Config& c) SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices, const std::vector<float>& heights,
: m_model_object(mo), mesh(), m_config(c) const Config& config, std::function<void(void)> throw_on_cancel)
{} : m_config(config), m_V(emesh.V), m_F(emesh.F), m_throw_on_cancel(throw_on_cancel)
{
// FIXME: It might be safer to get rid of the rand() calls altogether, because it is probably
// not always thread-safe and can be slow if it is.
srand(time(NULL)); // rand() is used by igl::random_point_on_mesh
// Find all separate islands that will need support. The coord_t number denotes height
// of a point just below the mesh (so that we can later project the point precisely
// on the mesh by raycasting (done by igl) and not risking we will place the point inside).
std::vector<std::pair<ExPolygon, coord_t>> islands = find_islands(slices, heights);
// Uniformly cover each of the islands with support points.
for (const auto& island : islands) {
std::vector<Vec3d> points = uniformly_cover(island);
m_throw_on_cancel();
project_upward_onto_mesh(points);
m_output.insert(m_output.end(), points.begin(), points.end());
m_throw_on_cancel();
}
// We are done with the islands. Let's sprinkle the rest of the mesh.
// The function appends to m_output.
sprinkle_mesh(mesh);
}
float SLAAutoSupports::approximate_geodesic_distance(const Vec3f& p1, const Vec3f& p2, Vec3f& n1, Vec3f& n2) float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2)
{ {
n1.normalize(); n1.normalize();
n2.normalize(); n2.normalize();
Vec3f v = (p2-p1); Vec3d v = (p2-p1);
v.normalize(); v.normalize();
float c1 = n1.dot(v); float c1 = n1.dot(v);
@ -32,15 +59,16 @@ float SLAAutoSupports::approximate_geodesic_distance(const Vec3f& p1, const Vec3
} }
void SLAAutoSupports::generate() void SLAAutoSupports::sprinkle_mesh(const TriangleMesh& mesh)
{ {
std::vector<Vec3d> points;
// Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation). // Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation).
// Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation. // Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation.
// The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for). // The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for).
// Results will be inverse-transformed to raw_mesh coordinates. // Results will be inverse-transformed to raw_mesh coordinates.
TriangleMesh mesh = m_model_object.raw_mesh(); //TriangleMesh mesh = m_model_object.raw_mesh();
Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/); //Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/);
mesh.transform(transformation_matrix); //mesh.transform(transformation_matrix);
// Check that the object is thick enough to produce any support points // Check that the object is thick enough to produce any support points
BoundingBoxf3 bb = mesh.bounding_box(); BoundingBoxf3 bb = mesh.bounding_box();
@ -48,30 +76,20 @@ void SLAAutoSupports::generate()
return; return;
// All points that we curretly have must be transformed too, so distance to them is correcly calculated. // All points that we curretly have must be transformed too, so distance to them is correcly calculated.
for (Vec3f& point : m_model_object.sla_support_points) //for (Vec3f& point : m_model_object.sla_support_points)
point = transformation_matrix.cast<float>() * point; // point = transformation_matrix.cast<float>() * point;
const stl_file& stl = mesh.stl;
Eigen::MatrixXf V;
Eigen::MatrixXi F;
V.resize(3 * stl.stats.number_of_facets, 3);
F.resize(stl.stats.number_of_facets, 3);
for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
const stl_facet* facet = stl.facet_start+i;
V(3*i+0, 0) = facet->vertex[0](0); V(3*i+0, 1) = facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2);
V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) = facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2);
V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) = facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2);
F(i, 0) = 3*i+0;
F(i, 1) = 3*i+1;
F(i, 2) = 3*i+2;
}
// In order to calculate distance to already placed points, we must keep know which facet the point lies on. // In order to calculate distance to already placed points, we must keep know which facet the point lies on.
std::vector<Vec3f> facets_normals; std::vector<Vec3d> facets_normals;
// Only points belonging to islands were added so far - they all lie on horizontal surfaces:
for (unsigned int i=0; i<m_output.size(); ++i)
facets_normals.push_back(Vec3d(0,0,-1));
// The AABB hierarchy will be used to find normals of already placed points. // The AABB hierarchy will be used to find normals of already placed points.
// The points added automatically will just push_back the new normal on the fly. // The points added automatically will just push_back the new normal on the fly.
igl::AABB<Eigen::MatrixXf,3> aabb; /*igl::AABB<Eigen::MatrixXf,3> aabb;
aabb.init(V, F); aabb.init(V, F);
for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) { for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) {
int facet_idx = 0; int facet_idx = 0;
@ -83,61 +101,69 @@ void SLAAutoSupports::generate()
Vec3f normal = a1.cross(a2); Vec3f normal = a1.cross(a2);
normal.normalize(); normal.normalize();
facets_normals.push_back(normal); facets_normals.push_back(normal);
} }*/
// New potential support point is randomly generated on the mesh and distance to all already placed points is calculated. // New potential support point is randomly generated on the mesh and distance to all already placed points is calculated.
// In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted. // In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted.
// The process stops after certain number of points is refused in a row. // The process stops after certain number of points is refused in a row.
Vec3f point; Vec3d point;
Vec3f normal; Vec3d normal;
int added_points = 0; int added_points = 0;
int refused_points = 0; int refused_points = 0;
const int refused_limit = 30; const int refused_limit = 30;
// Angle at which the density reaches zero: // Angle at which the density reaches zero:
const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal)); const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal));
srand(time(NULL)); // rand() is used by igl::random_point_on_mesh size_t cancel_test_cntr = 0;
while (refused_points < refused_limit) { while (refused_points < refused_limit) {
if (++ cancel_test_cntr == 500) {
// Don't call the cancellation routine too often as the multi-core cache synchronization
// may be pretty expensive.
m_throw_on_cancel();
cancel_test_cntr = 0;
}
// Place a random point on the mesh and calculate corresponding facet's normal: // Place a random point on the mesh and calculate corresponding facet's normal:
Eigen::VectorXi FI; Eigen::VectorXi FI;
Eigen::MatrixXf B; Eigen::MatrixXd B;
igl::random_points_on_mesh(1, V, F, B, FI); igl::random_points_on_mesh(1, m_V, m_F, B, FI);
point = B(0,0)*V.row(F(FI(0),0)) + point = B(0,0)*m_V.row(m_F(FI(0),0)) +
B(0,1)*V.row(F(FI(0),1)) + B(0,1)*m_V.row(m_F(FI(0),1)) +
B(0,2)*V.row(F(FI(0),2)); B(0,2)*m_V.row(m_F(FI(0),2));
if (point(2) - bb.min(2) < m_config.minimal_z) if (point(2) - bb.min(2) < m_config.minimal_z)
continue; continue;
Vec3f a1 = V.row(F(FI(0),1)) - V.row(F(FI(0),0)); Vec3d a1 = m_V.row(m_F(FI(0),1)) - m_V.row(m_F(FI(0),0));
Vec3f a2 = V.row(F(FI(0),2)) - V.row(F(FI(0),0)); Vec3d a2 = m_V.row(m_F(FI(0),2)) - m_V.row(m_F(FI(0),0));
normal = a1.cross(a2); normal = a1.cross(a2);
normal.normalize(); normal.normalize();
// calculate angle between the normal and vertical: // calculate angle between the normal and vertical:
float angle = angle_from_normal(normal); float angle = angle_from_normal(normal.cast<float>());
if (angle > threshold_angle) if (angle > threshold_angle)
continue; continue;
const float distance_limit = 1./(2.4*get_required_density(angle)); const float limit = distance_limit(angle);
bool add_it = true; bool add_it = true;
for (unsigned int i=0; i<m_model_object.sla_support_points.size(); ++i) { for (unsigned int i=0; i<points.size(); ++i) {
if (approximate_geodesic_distance(m_model_object.sla_support_points[i], point, facets_normals[i], normal) < distance_limit) { if (approximate_geodesic_distance(points[i], point, facets_normals[i], normal) < limit) {
add_it = false; add_it = false;
++refused_points; ++refused_points;
break; break;
} }
} }
if (add_it) { if (add_it) {
m_model_object.sla_support_points.push_back(point); points.push_back(point.cast<double>());
facets_normals.push_back(normal); facets_normals.push_back(normal);
++added_points; ++added_points;
refused_points = 0; refused_points = 0;
} }
} }
m_output.insert(m_output.end(), points.begin(), points.end());
// Now transform all support points to mesh coordinates: // Now transform all support points to mesh coordinates:
for (Vec3f& point : m_model_object.sla_support_points) //for (Vec3f& point : m_model_object.sla_support_points)
point = transformation_matrix.inverse().cast<float>() * point; // point = transformation_matrix.inverse().cast<float>() * point;
} }
@ -150,6 +176,160 @@ float SLAAutoSupports::get_required_density(float angle) const
return std::max(0.f, float(m_config.density_at_horizontal * cos(K*angle))); return std::max(0.f, float(m_config.density_at_horizontal * cos(K*angle)));
} }
float SLAAutoSupports::distance_limit(float angle) const
{
return 1./(2.4*get_required_density(angle));
}
#ifdef SLA_AUTOSUPPORTS_DEBUG
void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, std::string filename) const
{
BoundingBox bb(Point(-30000000, -30000000), Point(30000000, 30000000));
Slic3r::SVG svg_cummulative(filename, bb);
for (size_t i = 0; i < expolys.size(); ++ i) {
/*Slic3r::SVG svg("single"+std::to_string(i)+".svg", bb);
svg.draw(expolys[i]);
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
svg.Close();*/
svg_cummulative.draw(expolys[i]);
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
}
}
#endif /* SLA_AUTOSUPPORTS_DEBUG */
std::vector<std::pair<ExPolygon, coord_t>> SLAAutoSupports::find_islands(const std::vector<ExPolygons>& slices, const std::vector<float>& heights) const
{
std::vector<std::pair<ExPolygon, coord_t>> islands;
struct PointAccessor {
const Point* operator()(const Point &pt) const { return &pt; }
};
typedef ClosestPointInRadiusLookup<Point, PointAccessor> ClosestPointLookupType;
for (unsigned int i = 0; i<slices.size(); ++i) {
const ExPolygons& expolys_top = slices[i];
const ExPolygons& expolys_bottom = (i == 0 ? ExPolygons() : slices[i-1]);
std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i);
#ifdef SLA_AUTOSUPPORTS_DEBUG
output_expolygons(expolys_top, "top" + layer_num_str + ".svg");
#endif /* SLA_AUTOSUPPORTS_DEBUG */
ExPolygons diff = diff_ex(expolys_top, expolys_bottom);
#ifdef SLA_AUTOSUPPORTS_DEBUG
output_expolygons(diff, "diff" + layer_num_str + ".svg");
#endif /* SLA_AUTOSUPPORTS_DEBUG */
ClosestPointLookupType cpl(SCALED_EPSILON);
for (const ExPolygon& expol : expolys_top) {
for (const Point& p : expol.contour.points)
cpl.insert(p);
for (const Polygon& hole : expol.holes)
for (const Point& p : hole.points)
cpl.insert(p);
// the lookup structure now contains all points from the top slice
}
for (const ExPolygon& polygon : diff) {
// we want to check all boundary points of the diff polygon
bool island = true;
for (const Point& p : polygon.contour.points) {
if (cpl.find(p).second != 0) { // the point belongs to the bottom slice - this cannot be an island
island = false;
goto NO_ISLAND;
}
}
for (const Polygon& hole : polygon.holes)
for (const Point& p : hole.points)
if (cpl.find(p).second != 0) {
island = false;
goto NO_ISLAND;
}
if (island) { // all points of the diff polygon are from the top slice
islands.push_back(std::make_pair(polygon, scale_(i!=0 ? heights[i-1] : heights[0]-(heights[1]-heights[0]))));
}
NO_ISLAND: ;// continue with next ExPolygon
}
#ifdef SLA_AUTOSUPPORTS_DEBUG
//if (!islands.empty())
// output_expolygons(islands, "islands" + layer_num_str + ".svg");
#endif /* SLA_AUTOSUPPORTS_DEBUG */
m_throw_on_cancel();
}
return islands;
}
std::vector<Vec3d> SLAAutoSupports::uniformly_cover(const std::pair<ExPolygon, coord_t>& island)
{
int num_of_points = std::max(1, (int)(island.first.area()*pow(SCALING_FACTOR, 2) * get_required_density(0)));
// In case there is just one point to place, we'll place it into the polygon's centroid (unless it lies in a hole).
if (num_of_points == 1) {
Point out(island.first.contour.centroid());
for (const auto& hole : island.first.holes)
if (hole.contains(out))
goto HOLE_HIT;
return std::vector<Vec3d>{unscale(out(0), out(1), island.second)};
}
HOLE_HIT:
// In this case either the centroid lies in a hole, or there are multiple points
// to place. We will cover the island another way.
// For now we'll just place the points randomly not too close to the others.
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0., 1.);
std::vector<Vec3d> island_new_points;
const BoundingBox& bb = get_extents(island.first);
const int refused_limit = 30;
int refused_points = 0;
while (refused_points < refused_limit) {
Point out(bb.min(0) + bb.size()(0) * dis(gen),
bb.min(1) + bb.size()(1) * dis(gen)) ;
Vec3d unscaled_out = unscale(out(0), out(1), island.second);
bool add_it = true;
if (!island.first.contour.contains(out))
add_it = false;
else
for (const Polygon& hole : island.first.holes)
if (hole.contains(out))
add_it = false;
if (add_it) {
for (const Vec3d& p : island_new_points) {
if ((p - unscaled_out).squaredNorm() < distance_limit(0)) {
add_it = false;
++refused_points;
break;
}
}
}
if (add_it)
island_new_points.emplace_back(unscaled_out);
}
return island_new_points;
}
void SLAAutoSupports::project_upward_onto_mesh(std::vector<Vec3d>& points) const
{
Vec3f dir(0., 0., 1.);
igl::Hit hit{0, 0, 0.f, 0.f, 0.f};
for (Vec3d& p : points) {
igl::ray_mesh_intersect(p.cast<float>(), dir, m_V, m_F, hit);
int fid = hit.id;
Vec3f bc(1-hit.u-hit.v, hit.u, hit.v);
p = (bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2))).cast<double>();
}
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -3,15 +3,12 @@
#include <libslic3r/Point.hpp> #include <libslic3r/Point.hpp>
#include <libslic3r/TriangleMesh.hpp> #include <libslic3r/TriangleMesh.hpp>
#include <libslic3r/SLA/SLASupportTree.hpp>
// #define SLA_AUTOSUPPORTS_DEBUG
namespace Slic3r { namespace Slic3r {
class ModelObject;
class SLAAutoSupports { class SLAAutoSupports {
public: public:
struct Config { struct Config {
@ -20,22 +17,34 @@ public:
float minimal_z; float minimal_z;
}; };
SLAAutoSupports(ModelObject& mo, const SLAAutoSupports::Config& c); SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices,
void generate(); const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel);
const std::vector<Vec3d>& output() { return m_output; }
private: private:
std::vector<Vec3d> m_output;
std::vector<Vec3d> m_normals;
TriangleMesh mesh; TriangleMesh mesh;
static float angle_from_normal(const stl_normal& normal) { return acos((-normal.normalized())(2)); } static float angle_from_normal(const stl_normal& normal) { return acos((-normal.normalized())(2)); }
float get_required_density(float angle) const; float get_required_density(float angle) const;
static float approximate_geodesic_distance(const Vec3f& p1, const Vec3f& p2, Vec3f& n1, Vec3f& n2); float distance_limit(float angle) const;
static float approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2);
std::vector<std::pair<ExPolygon, coord_t>> find_islands(const std::vector<ExPolygons>& slices, const std::vector<float>& heights) const;
void sprinkle_mesh(const TriangleMesh& mesh);
std::vector<Vec3d> uniformly_cover(const std::pair<ExPolygon, coord_t>& island);
void project_upward_onto_mesh(std::vector<Vec3d>& points) const;
#ifdef SLA_AUTOSUPPORTS_DEBUG
void output_expolygons(const ExPolygons& expolys, std::string filename) const;
#endif /* SLA_AUTOSUPPORTS_DEBUG */
ModelObject& m_model_object;
SLAAutoSupports::Config m_config; SLAAutoSupports::Config m_config;
std::function<void(void)> m_throw_on_cancel;
const Eigen::MatrixXd& m_V;
const Eigen::MatrixXi& m_F;
}; };
} // namespace Slic3r } // namespace Slic3r

View File

@ -8,11 +8,12 @@
#include "SLABoilerPlate.hpp" #include "SLABoilerPlate.hpp"
#include "SLASpatIndex.hpp" #include "SLASpatIndex.hpp"
#include "SLABasePool.hpp" #include "SLABasePool.hpp"
#include <libnest2d/tools/benchmark.h>
#include "ClipperUtils.hpp"
#include "ClipperUtils.hpp"
#include "Model.hpp" #include "Model.hpp"
#include <boost/log/trivial.hpp>
/** /**
* Terminology: * Terminology:
* *
@ -612,7 +613,9 @@ double ray_mesh_intersect(const Vec3d& s,
const Vec3d& dir, const Vec3d& dir,
const EigenMesh3D& m); const EigenMesh3D& m);
PointSet normals(const PointSet& points, const EigenMesh3D& mesh); PointSet normals(const PointSet& points, const EigenMesh3D& mesh,
double eps = 0.05, // min distance from edges
std::function<void()> throw_on_cancel = [](){});
inline Vec2d to_vec2(const Vec3d& v3) { inline Vec2d to_vec2(const Vec3d& v3) {
return {v3(X), v3(Y)}; return {v3(X), v3(Y)};
@ -720,6 +723,10 @@ public:
return m_pad; return m_pad;
} }
void remove_pad() {
m_pad = Pad();
}
const Pad& pad() const { return m_pad; } const Pad& pad() const { return m_pad; }
// WITHOUT THE PAD!!! // WITHOUT THE PAD!!!
@ -1049,7 +1056,7 @@ bool SLASupportTree::generate(const PointSet &points,
tifcl(); tifcl();
// calculate the normals to the triangles belonging to filtered points // calculate the normals to the triangles belonging to filtered points
auto nmls = sla::normals(filt_pts, mesh); auto nmls = sla::normals(filt_pts, mesh, cfg.head_front_radius_mm, tifcl);
head_norm.resize(count, 3); head_norm.resize(count, 3);
head_pos.resize(count, 3); head_pos.resize(count, 3);
@ -1078,7 +1085,8 @@ bool SLASupportTree::generate(const PointSet &points,
double polar = std::acos(z / r); double polar = std::acos(z / r);
double azimuth = std::atan2(n(1), n(0)); double azimuth = std::atan2(n(1), n(0));
if(polar >= PI / 2) { // skip if the tilt is not sane // skip if the tilt is not sane
if(polar >= PI - cfg.normal_cutoff_angle) {
// We saturate the polar angle to 3pi/4 // We saturate the polar angle to 3pi/4
polar = std::max(polar, 3*PI / 4); polar = std::max(polar, 3*PI / 4);
@ -1109,7 +1117,9 @@ bool SLASupportTree::generate(const PointSet &points,
head_norm.row(pcount) = nn; head_norm.row(pcount) = nn;
++pcount; ++pcount;
} else { } else if( polar >= 3*PI/4 ) {
// Headless supports do not tilt like the headed ones so
// the normal should point almost to the ground.
headless_norm.row(hlcount) = nn; headless_norm.row(hlcount) = nn;
headless_pos.row(hlcount++) = hp; headless_pos.row(hlcount++) = hp;
} }
@ -1238,7 +1248,7 @@ bool SLASupportTree::generate(const PointSet &points,
result.add_bridge(sj, ej, pillar.r); result.add_bridge(sj, ej, pillar.r);
// double bridging: (crosses) // double bridging: (crosses)
if(bridge_distance > 2*cfg.base_radius_mm) { if(pillar_dist > 2*cfg.base_radius_mm) {
// If the columns are close together, no need to // If the columns are close together, no need to
// double bridge them // double bridge them
Vec3d bsj(ej(X), ej(Y), sj(Z)); Vec3d bsj(ej(X), ej(Y), sj(Z));
@ -1509,22 +1519,39 @@ bool SLASupportTree::generate(const PointSet &points,
{ {
// TODO: connect these to the ground pillars if possible // TODO: connect these to the ground pillars if possible
for(auto idx : nogndidx) { tifcl(); for(auto idx : nogndidx) { tifcl();
double gh = gndheight[idx];
double base_width = cfg.head_width_mm;
auto& head = result.head(idx); auto& head = result.head(idx);
// In this case there is no room for the base pinhead.
if(gh < head.fullwidth()) {
base_width = gh - 2 * cfg.head_front_radius_mm -
2*cfg.head_back_radius_mm + cfg.head_penetration_mm;
}
head.transform(); head.transform();
double gh = gndheight[idx];
Vec3d headend = head.junction_point(); Vec3d headend = head.junction_point();
Head base_head(cfg.head_back_radius_mm, Head base_head(cfg.head_back_radius_mm,
cfg.head_front_radius_mm, cfg.head_front_radius_mm,
cfg.head_width_mm, base_width,
cfg.head_penetration_mm, cfg.head_penetration_mm,
{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0},
{headend(X), headend(Y), headend(Z) - gh}); {headend(X), headend(Y), headend(Z) - gh});
base_head.transform(); base_head.transform();
double hl = head.fullwidth() - head.r_back_mm; // Robustness check:
if(headend(Z) < base_head.junction_point()(Z)) {
// This should not happen it is against all assumptions
BOOST_LOG_TRIVIAL(warning)
<< "Ignoring invalid supports connecting to model body";
continue;
}
double hl = base_head.fullwidth() - head.r_back_mm;
result.add_pillar(idx, result.add_pillar(idx,
Vec3d{headend(X), headend(Y), headend(Z) - gh + hl}, Vec3d{headend(X), headend(Y), headend(Z) - gh + hl},
@ -1547,7 +1574,7 @@ bool SLASupportTree::generate(const PointSet &points,
const double HWIDTH_MM = R/3; const double HWIDTH_MM = R/3;
// We will sink the pins into the model surface for a distance of 1/3 of // We will sink the pins into the model surface for a distance of 1/3 of
// HWIDTH_MM // the pin radius
for(int i = 0; i < headless_pts.rows(); i++) { tifcl(); for(int i = 0; i < headless_pts.rows(); i++) { tifcl();
Vec3d sp = headless_pts.row(i); Vec3d sp = headless_pts.row(i);
@ -1558,7 +1585,7 @@ bool SLASupportTree::generate(const PointSet &points,
Vec3d sj = sp + R * n; Vec3d sj = sp + R * n;
double dist = ray_mesh_intersect(sj, dir, emesh); double dist = ray_mesh_intersect(sj, dir, emesh);
if(std::isinf(dist) || std::isnan(dist)) continue; if(std::isinf(dist) || std::isnan(dist) || dist < 2*R) continue;
Vec3d ej = sj + (dist + HWIDTH_MM)* dir; Vec3d ej = sj + (dist + HWIDTH_MM)* dir;
result.add_compact_bridge(sp, ej, n, R); result.add_compact_bridge(sp, ej, n, R);
@ -1727,6 +1754,11 @@ const TriangleMesh &SLASupportTree::get_pad() const
return m_impl->pad().tmesh; return m_impl->pad().tmesh;
} }
void SLASupportTree::remove_pad()
{
m_impl->remove_pad();
}
SLASupportTree::SLASupportTree(const PointSet &points, SLASupportTree::SLASupportTree(const PointSet &points,
const EigenMesh3D& emesh, const EigenMesh3D& emesh,
const SupportConfig &cfg, const SupportConfig &cfg,

View File

@ -67,6 +67,10 @@ struct SupportConfig {
// The elevation in Z direction upwards. This is the space between the pad // The elevation in Z direction upwards. This is the space between the pad
// and the model object's bounding box bottom. // and the model object's bounding box bottom.
double object_elevation_mm = 10; double object_elevation_mm = 10;
// The max Z angle for a normal at which it will get completely ignored.
double normal_cutoff_angle = 110.0 * M_PI / 180.0;
}; };
struct PoolConfig; struct PoolConfig;
@ -164,6 +168,8 @@ public:
/// Get the pad geometry /// Get the pad geometry
const TriangleMesh& get_pad() const; const TriangleMesh& get_pad() const;
void remove_pad();
}; };
} }

View File

@ -1,3 +1,4 @@
#include <cmath>
#include "SLA/SLASupportTree.hpp" #include "SLA/SLASupportTree.hpp"
#include "SLA/SLABoilerPlate.hpp" #include "SLA/SLABoilerPlate.hpp"
#include "SLA/SLASpatIndex.hpp" #include "SLA/SLASpatIndex.hpp"
@ -9,15 +10,8 @@
#include "boost/geometry/index/rtree.hpp" #include "boost/geometry/index/rtree.hpp"
#include <igl/ray_mesh_intersect.h> #include <igl/ray_mesh_intersect.h>
//#if !defined(_MSC_VER) || defined(_WIN64)
#if 1
#define IGL_COMPATIBLE
#endif
#ifdef IGL_COMPATIBLE
#include <igl/point_mesh_squared_distance.h> #include <igl/point_mesh_squared_distance.h>
#endif #include <igl/remove_duplicate_vertices.h>
#include "SLASpatIndex.hpp" #include "SLASpatIndex.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
@ -84,33 +78,148 @@ size_t SpatIndex::size() const
return m_impl->m_store.size(); return m_impl->m_store.size();
} }
PointSet normals(const PointSet& points, const EigenMesh3D& mesh) { bool point_on_edge(const Vec3d& p, const Vec3d& e1, const Vec3d& e2,
if(points.rows() == 0 || mesh.V.rows() == 0 || mesh.F.rows() == 0) return {}; double eps = 0.05)
#ifdef IGL_COMPATIBLE {
using Line3D = Eigen::ParametrizedLine<double, 3>;
auto line = Line3D::Through(e1, e2);
double d = line.distance(p);
return std::abs(d) < eps;
}
template<class Vec> double distance(const Vec& pp1, const Vec& pp2) {
auto p = pp2 - pp1;
return std::sqrt(p.transpose() * p);
}
PointSet normals(const PointSet& points, const EigenMesh3D& emesh,
double eps,
std::function<void()> throw_on_cancel) {
if(points.rows() == 0 || emesh.V.rows() == 0 || emesh.F.rows() == 0)
return {};
Eigen::VectorXd dists; Eigen::VectorXd dists;
Eigen::VectorXi I; Eigen::VectorXi I;
PointSet C; PointSet C;
// We need to remove duplicate vertices and have a true index triangle
// structure
EigenMesh3D mesh;
Eigen::VectorXi SVI, SVJ;
static const double dEPS = 1e-6;
igl::remove_duplicate_vertices(emesh.V, emesh.F, dEPS,
mesh.V, SVI, SVJ, mesh.F);
igl::point_mesh_squared_distance( points, mesh.V, mesh.F, dists, I, C); igl::point_mesh_squared_distance( points, mesh.V, mesh.F, dists, I, C);
PointSet ret(I.rows(), 3); PointSet ret(I.rows(), 3);
for(int i = 0; i < I.rows(); i++) { for(int i = 0; i < I.rows(); i++) {
throw_on_cancel();
auto idx = I(i); auto idx = I(i);
auto trindex = mesh.F.row(idx); auto trindex = mesh.F.row(idx);
auto& p1 = mesh.V.row(trindex(0)); const Vec3d& p1 = mesh.V.row(trindex(0));
auto& p2 = mesh.V.row(trindex(1)); const Vec3d& p2 = mesh.V.row(trindex(1));
auto& p3 = mesh.V.row(trindex(2)); const Vec3d& p3 = mesh.V.row(trindex(2));
Eigen::Vector3d U = p2 - p1; // We should check if the point lies on an edge of the hosting triangle.
Eigen::Vector3d V = p3 - p1; // If it does than all the other triangles using the same two points
ret.row(i) = U.cross(V).normalized(); // have to be searched and the final normal should be some kind of
// aggregation of the participating triangle normals. We should also
// consider the cases where the support point lies right on a vertex
// of its triangle. The procedure is the same, get the neighbor
// triangles and calculate an average normal.
const Vec3d& p = C.row(i);
// mark the vertex indices of the edge. ia and ib marks and edge ic
// will mark a single vertex.
int ia = -1, ib = -1, ic = -1;
if(std::abs(distance(p, p1)) < eps) {
ic = trindex(0);
}
else if(std::abs(distance(p, p2)) < eps) {
ic = trindex(1);
}
else if(std::abs(distance(p, p3)) < eps) {
ic = trindex(2);
}
else if(point_on_edge(p, p1, p2, eps)) {
ia = trindex(0); ib = trindex(1);
}
else if(point_on_edge(p, p2, p3, eps)) {
ia = trindex(1); ib = trindex(2);
}
else if(point_on_edge(p, p1, p3, eps)) {
ia = trindex(0); ib = trindex(2);
}
// vector for the neigboring triangles including the detected one.
std::vector<Vec3i> neigh;
if(ic >= 0) { // The point is right on a vertex of the triangle
for(int n = 0; n < mesh.F.rows(); ++n) {
throw_on_cancel();
Vec3i ni = mesh.F.row(n);
if((ni(X) == ic || ni(Y) == ic || ni(Z) == ic))
neigh.emplace_back(ni);
}
}
else if(ia >= 0 && ib >= 0) { // the point is on and edge
// now get all the neigboring triangles
for(int n = 0; n < mesh.F.rows(); ++n) {
throw_on_cancel();
Vec3i ni = mesh.F.row(n);
if((ni(X) == ia || ni(Y) == ia || ni(Z) == ia) &&
(ni(X) == ib || ni(Y) == ib || ni(Z) == ib))
neigh.emplace_back(ni);
}
}
// Calculate the normals for the neighboring triangles
std::vector<Vec3d> neighnorms; neighnorms.reserve(neigh.size());
for(const Vec3i& tri : neigh) {
const Vec3d& pt1 = mesh.V.row(tri(0));
const Vec3d& pt2 = mesh.V.row(tri(1));
const Vec3d& pt3 = mesh.V.row(tri(2));
Eigen::Vector3d U = pt2 - pt1;
Eigen::Vector3d V = pt3 - pt1;
neighnorms.emplace_back(U.cross(V).normalized());
}
// Throw out duplicates. They would cause trouble with summing. We will
// use std::unique which works on sorted ranges. We will sort by the
// coefficient-wise sum of the normals. It should force the same
// elements to be consecutive.
std::sort(neighnorms.begin(), neighnorms.end(),
[](const Vec3d& v1, const Vec3d& v2){
return v1.sum() < v2.sum();
});
auto lend = std::unique(neighnorms.begin(), neighnorms.end(),
[](const Vec3d& n1, const Vec3d& n2) {
// Compare normals for equivalence. This is controvers stuff.
auto deq = [](double a, double b) { return std::abs(a-b) < 1e-3; };
return deq(n1(X), n2(X)) && deq(n1(Y), n2(Y)) && deq(n1(Z), n2(Z));
});
if(!neighnorms.empty()) { // there were neighbors to count with
// sum up the normals and then normalize the result again.
// This unification seems to be enough.
Vec3d sumnorm(0, 0, 0);
sumnorm = std::accumulate(neighnorms.begin(), lend, sumnorm);
sumnorm.normalize();
ret.row(i) = sumnorm;
}
else { // point lies safely within its triangle
Eigen::Vector3d U = p2 - p1;
Eigen::Vector3d V = p3 - p1;
ret.row(i) = U.cross(V).normalized();
}
} }
return ret; return ret;
#else // TODO: do something on 32 bit windows
return {};
#endif
} }
double ray_mesh_intersect(const Vec3d& s, double ray_mesh_intersect(const Vec3d& s,
@ -223,7 +332,7 @@ Segments model_boundary(const EigenMesh3D& emesh, double offs)
pp.emplace_back(p); pp.emplace_back(p);
} }
ExPolygons merged = union_ex(offset(pp, float(scale_(offs))), true); ExPolygons merged = union_ex(Slic3r::offset(pp, float(scale_(offs))), true);
for(auto& expoly : merged) { for(auto& expoly : merged) {
auto lines = expoly.lines(); auto lines = expoly.lines();

View File

@ -1,6 +1,7 @@
#include "SLAPrint.hpp" #include "SLAPrint.hpp"
#include "SLA/SLASupportTree.hpp" #include "SLA/SLASupportTree.hpp"
#include "SLA/SLABasePool.hpp" #include "SLA/SLABasePool.hpp"
#include "SLA/SLAAutoSupports.hpp"
#include "MTUtils.hpp" #include "MTUtils.hpp"
#include <unordered_set> #include <unordered_set>
@ -36,8 +37,7 @@ namespace {
const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS =
{ {
10, // slaposObjectSlice, 10, // slaposObjectSlice,
10, // slaposSupportIslands, 30, // slaposSupportPoints,
20, // slaposSupportPoints,
25, // slaposSupportTree, 25, // slaposSupportTree,
25, // slaposBasePool, 25, // slaposBasePool,
5, // slaposSliceSupports, 5, // slaposSliceSupports,
@ -47,8 +47,7 @@ const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS =
const std::array<std::string, slaposCount> OBJ_STEP_LABELS = const std::array<std::string, slaposCount> OBJ_STEP_LABELS =
{ {
L("Slicing model"), // slaposObjectSlice, L("Slicing model"), // slaposObjectSlice,
L("Generating islands"), // slaposSupportIslands, L("Generating support points"), // slaposSupportPoints,
L("Scanning model structure"), // slaposSupportPoints,
L("Generating support tree"), // slaposSupportTree, L("Generating support tree"), // slaposSupportTree,
L("Generating base pool"), // slaposBasePool, L("Generating base pool"), // slaposBasePool,
L("Slicing supports"), // slaposSliceSupports, L("Slicing supports"), // slaposSliceSupports,
@ -185,6 +184,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
update_apply_status(this->invalidate_all_steps()); update_apply_status(this->invalidate_all_steps());
for (SLAPrintObject *object : m_objects) { for (SLAPrintObject *object : m_objects) {
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted); model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
update_apply_status(object->invalidate_all_steps());
delete object; delete object;
} }
m_objects.clear(); m_objects.clear();
@ -377,11 +377,12 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
bool deleted_objects = false; bool deleted_objects = false;
for (auto &pos : print_object_status) for (auto &pos : print_object_status)
if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) { if (pos.status == PrintObjectStatus::Unknown || pos.status == PrintObjectStatus::Deleted) {
// update_apply_status(pos.print_object->invalidate_all_steps()); update_apply_status(pos.print_object->invalidate_all_steps());
delete pos.print_object; delete pos.print_object;
deleted_objects = true; deleted_objects = true;
} }
update_apply_status(new_objects); if (new_objects)
update_apply_status(false);
} }
this->update_object_placeholders(); this->update_object_placeholders();
@ -420,12 +421,34 @@ void swapXY(ExPolygon& expoly) {
} }
std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d,
float elevation,
float initial_layer_height,
float layer_height) const
{
std::vector<float> heights;
float minZ = float(bb3d.min(Z)) - float(elevation);
float maxZ = float(bb3d.max(Z));
auto flh = float(layer_height);
auto gnd = float(bb3d.min(Z));
// The first layer (the one before the initial height) is added only
// if there is no pad and no elevation value
if(minZ >= gnd) heights.emplace_back(minZ);
for(float h = minZ + initial_layer_height; h < maxZ; h += flh)
if(h >= gnd) heights.emplace_back(h);
return heights;
}
template<class...Args> template<class...Args>
void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) { void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
BOOST_LOG_TRIVIAL(info) << st << "% " << msg; BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(st, msg, std::forward<Args>(args)...); p.set_status(st, msg, std::forward<Args>(args)...);
} }
void SLAPrint::process() void SLAPrint::process()
{ {
using namespace sla; using namespace sla;
@ -462,47 +485,66 @@ void SLAPrint::process()
TriangleMesh mesh = po.transformed_mesh(); TriangleMesh mesh = po.transformed_mesh();
TriangleMeshSlicer slicer(&mesh); TriangleMeshSlicer slicer(&mesh);
auto bb3d = mesh.bounding_box();
double elevation = po.get_elevation();
float minZ = float(bb3d.min(Z)) - float(elevation);
float maxZ = float(bb3d.max(Z)) ;
auto flh = float(lh);
auto gnd = float(bb3d.min(Z));
// The 1D grid heights // The 1D grid heights
std::vector<float> heights; std::vector<float> heights = calculate_heights(mesh.bounding_box(),
float(po.get_elevation()),
// The first layer (the one before the initial height) is added only ilh, float(lh));
// if there is no pad and no elevation value
if(minZ >= gnd) heights.emplace_back(minZ);
for(float h = minZ + ilh; h < maxZ; h += flh)
if(h >= gnd) heights.emplace_back(h);
auto& layers = po.m_model_slices; layers.clear(); auto& layers = po.m_model_slices; layers.clear();
slicer.slice(heights, &layers, [this](){ throw_if_canceled(); }); slicer.slice(heights, &layers, [this](){ throw_if_canceled(); });
}; };
// this procedure simply converts the points and copies them into // In this step we check the slices, identify island and cover them with
// the support data cache // support points. Then we sprinkle the rest of the mesh.
auto support_points = [](SLAPrintObject& po) { auto support_points = [this, ilh](SLAPrintObject& po) {
ModelObject& mo = *po.m_model_object; const ModelObject& mo = *po.m_model_object;
po.m_supportdata.reset(new SLAPrintObject::SupportData()); po.m_supportdata.reset(new SLAPrintObject::SupportData());
po.m_supportdata->emesh = sla::to_eigenmesh(po.transformed_mesh());
if(!mo.sla_support_points.empty()) { BOOST_LOG_TRIVIAL(debug) << "Support point count "
po.m_supportdata->emesh = sla::to_eigenmesh(po.transformed_mesh()); << mo.sla_support_points.size();
// If there are no points on the front-end, we will do the
// autoplacement. Otherwise we will just blindly copy the frontend data
// into the backend cache.
if(mo.sla_support_points.empty()) {
// calculate heights of slices (slices are calculated already)
double lh = po.m_config.layer_height.getFloat();
std::vector<float> heights =
calculate_heights(po.transformed_mesh().bounding_box(),
float(po.get_elevation()),
ilh, float(lh));
this->throw_if_canceled();
SLAAutoSupports::Config config;
const SLAPrintObjectConfig& cfg = po.config();
config.minimal_z = float(cfg.support_minimal_z);
config.density_at_45 = cfg.support_density_at_45 / 10000.f;
config.density_at_horizontal = cfg.support_density_at_horizontal / 10000.f;
// Construction of this object does the calculation.
this->throw_if_canceled();
SLAAutoSupports auto_supports(po.transformed_mesh(),
po.m_supportdata->emesh,
po.get_model_slices(),
heights,
config,
[this]() { throw_if_canceled(); });
// Now let's extract the result.
const std::vector<Vec3d>& points = auto_supports.output();
this->throw_if_canceled();
po.m_supportdata->support_points = sla::to_point_set(points);
BOOST_LOG_TRIVIAL(debug) << "Automatic support points: "
<< po.m_supportdata->support_points.rows();
}
else {
// There are some points on the front-end, no calculation will be done.
po.m_supportdata->support_points = po.m_supportdata->support_points =
sla::to_point_set(po.transformed_support_points()); sla::to_point_set(po.transformed_support_points());
} else if(po.m_config.supports_enable.getBool()) {
// Supports are enabled but there are no support points to process.
// We throw here a runtime exception with some explanation and
// the background processing framework will handle it.
throw std::runtime_error(
L("Supports are enabled but no support points selected."
" Hint: create some support points or disable support "
"creation."));
} }
}; };
@ -545,8 +587,18 @@ void SLAPrint::process()
// Create the unified mesh // Create the unified mesh
auto rc = SlicingStatus::RELOAD_SCENE; auto rc = SlicingStatus::RELOAD_SCENE;
// This is to prevent "Done." being displayed during merged_mesh()
report_status(*this, -1, L("Visualizing supports")); report_status(*this, -1, L("Visualizing supports"));
po.m_supportdata->support_tree_ptr->merged_mesh(); po.m_supportdata->support_tree_ptr->merged_mesh();
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
<< po.m_supportdata->support_points.rows();
// Check the mesh for later troubleshooting.
if(po.support_mesh().empty())
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
report_status(*this, -1, L("Visualizing supports"), rc); report_status(*this, -1, L("Visualizing supports"), rc);
} catch(sla::SLASupportsStoppedException&) { } catch(sla::SLASupportsStoppedException&) {
// no need to rethrow // no need to rethrow
@ -560,9 +612,13 @@ void SLAPrint::process()
// and before the supports had been sliced. (or the slicing has to be // and before the supports had been sliced. (or the slicing has to be
// repeated) // repeated)
if(po.m_config.pad_enable.getBool() && if(!po.m_supportdata || !po.m_supportdata->support_tree_ptr) {
po.m_supportdata && BOOST_LOG_TRIVIAL(warning) << "Uninitialized support data at "
po.m_supportdata->support_tree_ptr) << "pad creation.";
return;
}
if(po.m_config.pad_enable.getBool())
{ {
double wt = po.m_config.pad_wall_thickness.getFloat(); double wt = po.m_config.pad_wall_thickness.getFloat();
double h = po.m_config.pad_wall_height.getFloat(); double h = po.m_config.pad_wall_height.getFloat();
@ -586,6 +642,8 @@ void SLAPrint::process()
pcfg.throw_on_cancel = thrfn; pcfg.throw_on_cancel = thrfn;
po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg); po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg);
} else {
po.m_supportdata->support_tree_ptr->remove_pad();
} }
po.throw_if_canceled(); po.throw_if_canceled();
@ -816,8 +874,7 @@ void SLAPrint::process()
// This is the actual order of steps done on each PrintObject // This is the actual order of steps done on each PrintObject
std::array<SLAPrintObjectStep, slaposCount> objectsteps = { std::array<SLAPrintObjectStep, slaposCount> objectsteps = {
slaposObjectSlice, // Support Islands will need this step slaposObjectSlice, // SupportPoints will need this step
slaposSupportIslands,
slaposSupportPoints, slaposSupportPoints,
slaposSupportTree, slaposSupportTree,
slaposBasePool, slaposBasePool,
@ -828,7 +885,6 @@ void SLAPrint::process()
std::array<slaposFn, slaposCount> pobj_program = std::array<slaposFn, slaposCount> pobj_program =
{ {
slice_model, slice_model,
[](SLAPrintObject&){}, // slaposSupportIslands now empty
support_points, support_points,
support_tree, support_tree,
base_pool, base_pool,
@ -866,6 +922,7 @@ void SLAPrint::process()
if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
pobj_program[currentstep](*po); pobj_program[currentstep](*po);
throw_if_canceled();
po->set_done(currentstep); po->set_done(currentstep);
} }
@ -891,6 +948,7 @@ void SLAPrint::process()
{ {
report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]); report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]);
print_program[currentstep](); print_program[currentstep]();
throw_if_canceled();
set_done(currentstep); set_done(currentstep);
} }
@ -1031,9 +1089,6 @@ bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step)
// propagate to dependent steps // propagate to dependent steps
if (step == slaposObjectSlice) { if (step == slaposObjectSlice) {
invalidated |= this->invalidate_all_steps(); invalidated |= this->invalidate_all_steps();
} else if (step == slaposSupportIslands) {
invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposSupportPoints) { } else if (step == slaposSupportPoints) {
invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices }); invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
@ -1083,12 +1138,13 @@ double SLAPrintObject::get_current_elevation() const
bool se = m_config.supports_enable.getBool(); bool se = m_config.supports_enable.getBool();
bool has_supports = is_step_done(slaposSupportTree); bool has_supports = is_step_done(slaposSupportTree);
bool has_pad = is_step_done(slaposBasePool); bool has_pad = is_step_done(slaposBasePool);
if(!has_supports && !has_pad) return 0;
if(!has_supports && !has_pad)
return 0;
else if(has_supports && !has_pad) else if(has_supports && !has_pad)
return se ? m_config.support_object_elevation.getFloat() : 0; return se ? m_config.support_object_elevation.getFloat() : 0;
else return get_elevation();
return 0; return get_elevation();
} }
namespace { // dummy empty static containers for return values in some methods namespace { // dummy empty static containers for return values in some methods
@ -1096,6 +1152,11 @@ const std::vector<ExPolygons> EMPTY_SLICES;
const TriangleMesh EMPTY_MESH; const TriangleMesh EMPTY_MESH;
} }
const Eigen::MatrixXd& SLAPrintObject::get_support_points() const
{
return m_supportdata->support_points;
}
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
{ {
// assert(is_step_done(slaposSliceSupports)); // assert(is_step_done(slaposSliceSupports));

View File

@ -18,7 +18,6 @@ enum SLAPrintStep : unsigned int {
enum SLAPrintObjectStep : unsigned int { enum SLAPrintObjectStep : unsigned int {
slaposObjectSlice, slaposObjectSlice,
slaposSupportIslands,
slaposSupportPoints, slaposSupportPoints,
slaposSupportTree, slaposSupportTree,
slaposBasePool, slaposBasePool,
@ -91,6 +90,9 @@ public:
const std::vector<ExPolygons>& get_model_slices() const; const std::vector<ExPolygons>& get_model_slices() const;
const std::vector<ExPolygons>& get_support_slices() const; const std::vector<ExPolygons>& get_support_slices() const;
// This method returns the support points of this SLAPrintObject.
const Eigen::MatrixXd& get_support_points() const;
// An index record referencing the slices // An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height // (get_model_slices(), get_support_slices()) where the keys are the height
// levels of the model in scaled-clipper coordinates. The levels correspond // levels of the model in scaled-clipper coordinates. The levels correspond
@ -188,7 +190,7 @@ public:
// Returns true if an object step is done on all objects and there's at least one object. // Returns true if an object step is done on all objects and there's at least one object.
bool is_step_done(SLAPrintObjectStep step) const; bool is_step_done(SLAPrintObjectStep step) const;
// Returns true if the last step was finished with success. // Returns true if the last step was finished with success.
bool finished() const override { return this->is_step_done(slaposIndexSlices); } bool finished() const override { return this->is_step_done(slaposIndexSlices) && this->Inherited::is_step_done(slapsRasterize); }
template<class Fmt> void export_raster(const std::string& fname) { template<class Fmt> void export_raster(const std::string& fname) {
if(m_printer) m_printer->save<Fmt>(fname); if(m_printer) m_printer->save<Fmt>(fname);
@ -226,6 +228,8 @@ private:
lref(std::cref(lyr)), copies(std::cref(cp)) {} lref(std::cref(lyr)), copies(std::cref(cp)) {}
}; };
std::vector<float> calculate_heights(const BoundingBoxf3& bb, float elevation, float initial_layer_height, float layer_height) const;
// One level may contain multiple slices from multiple objects and their // One level may contain multiple slices from multiple objects and their
// supports // supports
using LayerRefs = std::vector<LayerRef>; using LayerRefs = std::vector<LayerRef>;

View File

@ -10,36 +10,39 @@
// Log debug messages to console when changing selection // Log debug messages to console when changing selection
#define ENABLE_SELECTION_DEBUG_OUTPUT 0 #define ENABLE_SELECTION_DEBUG_OUTPUT 0
//============= //====================
// 1.42.0 techs // 1.42.0.alpha1 techs
//============= //====================
#define ENABLE_1_42_0 1 #define ENABLE_1_42_0_ALPHA1 1
// Uses a unique opengl context // Uses a unique opengl context
#define ENABLE_USE_UNIQUE_GLCONTEXT (1 && ENABLE_1_42_0) #define ENABLE_USE_UNIQUE_GLCONTEXT (1 && ENABLE_1_42_0_ALPHA1)
// Disable synchronization of unselected instances // Disable synchronization of unselected instances
#define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0) #define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0_ALPHA1)
// Modified camera target behavior
#define ENABLE_MODIFIED_CAMERA_TARGET (1 && ENABLE_1_42_0)
// Add Geometry::Transformation class and use it into ModelInstance, ModelVolume and GLVolume
#define ENABLE_MODELVOLUME_TRANSFORM (1 && ENABLE_1_42_0)
// Keeps objects on bed while scaling them using the scale gizmo // Keeps objects on bed while scaling them using the scale gizmo
#define ENABLE_ENSURE_ON_BED_WHILE_SCALING (1 && ENABLE_MODELVOLUME_TRANSFORM) #define ENABLE_ENSURE_ON_BED_WHILE_SCALING (1 && ENABLE_1_42_0_ALPHA1)
// All rotations made using the rotate gizmo are done with respect to the world reference system // All rotations made using the rotate gizmo are done with respect to the world reference system
#define ENABLE_WORLD_ROTATIONS (1 && ENABLE_1_42_0) #define ENABLE_WORLD_ROTATIONS (1 && ENABLE_1_42_0_ALPHA1)
// Scene's GUI made using imgui library // Scene's GUI made using imgui library
#define ENABLE_IMGUI (1 && ENABLE_1_42_0) #define ENABLE_IMGUI (1 && ENABLE_1_42_0_ALPHA1)
#define DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI (1 && ENABLE_IMGUI) #define DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI (1 && ENABLE_IMGUI)
// Modified Sla support gizmo // Modified Sla support gizmo
#define ENABLE_SLA_SUPPORT_GIZMO_MOD (1 && ENABLE_1_42_0) #define ENABLE_SLA_SUPPORT_GIZMO_MOD (1 && ENABLE_1_42_0_ALPHA1)
// Removes the wxNotebook from plater
#define ENABLE_REMOVE_TABS_FROM_PLATER (1 && ENABLE_1_42_0)
// Constrains the camera target into the scene bounding box
#define ENABLE_CONSTRAINED_CAMERA_TARGET (1 && ENABLE_1_42_0)
// Use wxDataViewRender instead of wxDataViewCustomRenderer // Use wxDataViewRender instead of wxDataViewCustomRenderer
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0) #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
// Adds background texture to toolbars // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active
#define ENABLE_TOOLBAR_BACKGROUND_TEXTURE (1 && ENABLE_1_42_0) #define ENABLE_RENDER_SELECTION_CENTER (0 && ENABLE_1_42_0_ALPHA1)
// Show visual hints in the 3D scene when sidebar matrix fields have focus
#define ENABLE_SIDEBAR_VISUAL_HINTS (1 && ENABLE_1_42_0_ALPHA1)
// Separate rendering for opaque and transparent volumes
#define ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_1_42_0_ALPHA1)
//====================
// 1.42.0.alpha2 techs
//====================
#define ENABLE_1_42_0_ALPHA2 1
#define ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION (1 && ENABLE_1_42_0_ALPHA2)
#endif // _technologies_h_ #endif // _technologies_h_

View File

@ -11,7 +11,13 @@
namespace Slic3r { namespace Slic3r {
extern void set_logging_level(unsigned int level); extern void set_logging_level(unsigned int level);
extern unsigned get_logging_level();
extern void trace(unsigned int level, const char *message); extern void trace(unsigned int level, const char *message);
// Format memory allocated, separate thousands by comma.
extern std::string format_memsize_MB(size_t n);
// Return string to be added to the boost::log output to inform about the current process memory allocation.
// The string is non-empty only if the loglevel >= info (3).
extern std::string log_memory_info();
extern void disable_multi_threading(); extern void disable_multi_threading();
// Set a path with GUI resource files. // Set a path with GUI resource files.
@ -182,7 +188,12 @@ public:
void reset() { closure = Closure(); } void reset() { closure = Closure(); }
}; };
} // namespace Slic3r } // namespace Slic3r
#if WIN32
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE)
#else
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + alignof(TYPE) - 1) / alignof(TYPE)) * alignof(TYPE)
#endif
#endif // slic3r_Utils_hpp_ #endif // slic3r_Utils_hpp_

View File

@ -8,6 +8,7 @@
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
#include <psapi.h>
#else #else
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -58,6 +59,18 @@ void set_logging_level(unsigned int level)
); );
} }
unsigned get_logging_level()
{
switch (logSeverity) {
case boost::log::trivial::fatal : return 0;
case boost::log::trivial::error : return 1;
case boost::log::trivial::warning : return 2;
case boost::log::trivial::info : return 3;
case boost::log::trivial::debug : return 4;
default: return 1;
}
}
// Force set_logging_level(<=error) after loading of the DLL. // Force set_logging_level(<=error) after loading of the DLL.
// Switch boost::filesystem to utf8. // Switch boost::filesystem to utf8.
static struct RunOnInit { static struct RunOnInit {
@ -365,4 +378,71 @@ std::string xml_escape(std::string text)
return text; return text;
} }
std::string format_memsize_MB(size_t n)
{
std::string out;
size_t n2 = 0;
size_t scale = 1;
// Round to MB
n += 500000;
n /= 1000000;
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
char buf[8];
sprintf(buf, "%d", n);
out = buf;
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
sprintf(buf, ",%03d", n);
out += buf;
}
return out + "MB";
}
#ifdef WIN32
#ifndef PROCESS_MEMORY_COUNTERS_EX
// MingW32 doesn't have this struct in psapi.h
typedef struct _PROCESS_MEMORY_COUNTERS_EX {
DWORD cb;
DWORD PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivateUsage;
} PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX;
#endif /* PROCESS_MEMORY_COUNTERS_EX */
std::string log_memory_info()
{
std::string out;
if (logSeverity <= boost::log::trivial::info) {
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId());
if (hProcess != nullptr) {
PROCESS_MEMORY_COUNTERS_EX pmc;
if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + " PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + " Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")";
CloseHandle(hProcess);
}
}
return out;
}
#else
std::string log_memory_info()
{
return std::string();
}
#endif
}; // namespace Slic3r }; // namespace Slic3r

View File

@ -10,6 +10,8 @@ add_library(libslic3r_gui STATIC
GUI/AboutDialog.hpp GUI/AboutDialog.hpp
GUI/SysInfoDialog.cpp GUI/SysInfoDialog.cpp
GUI/SysInfoDialog.hpp GUI/SysInfoDialog.hpp
GUI/KBShortcutsDialog.cpp
GUI/KBShortcutsDialog.hpp
GUI/AppConfig.cpp GUI/AppConfig.cpp
GUI/AppConfig.hpp GUI/AppConfig.hpp
GUI/BackgroundSlicingProcess.cpp GUI/BackgroundSlicingProcess.cpp

View File

@ -205,17 +205,7 @@ const float GLVolume::SLA_SUPPORT_COLOR[4] = { 0.75f, 0.75f, 0.75f, 1.0f };
const float GLVolume::SLA_PAD_COLOR[4] = { 0.0f, 0.2f, 0.0f, 1.0f }; const float GLVolume::SLA_PAD_COLOR[4] = { 0.0f, 0.2f, 0.0f, 1.0f };
GLVolume::GLVolume(float r, float g, float b, float a) GLVolume::GLVolume(float r, float g, float b, float a)
#if ENABLE_MODELVOLUME_TRANSFORM
: m_transformed_bounding_box_dirty(true) : m_transformed_bounding_box_dirty(true)
#else
: m_offset(Vec3d::Zero())
, m_rotation(Vec3d::Zero())
, m_scaling_factor(Vec3d::Ones())
, m_mirror(Vec3d::Ones())
, m_world_matrix(Transform3f::Identity())
, m_world_matrix_dirty(true)
, m_transformed_bounding_box_dirty(true)
#endif // ENABLE_MODELVOLUME_TRANSFORM
, m_sla_shift_z(0.0) , m_sla_shift_z(0.0)
, m_transformed_convex_hull_bounding_box_dirty(true) , m_transformed_convex_hull_bounding_box_dirty(true)
, m_convex_hull(nullptr) , m_convex_hull(nullptr)
@ -300,125 +290,18 @@ void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume)
color[3] = model_volume->is_model_part() ? 1.f : 0.5f; color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
} }
#if !ENABLE_MODELVOLUME_TRANSFORM
const Vec3d& GLVolume::get_rotation() const
{
return m_rotation;
}
void GLVolume::set_rotation(const Vec3d& rotation)
{
static const double TWO_PI = 2.0 * (double)PI;
if (m_rotation != rotation)
{
m_rotation = rotation;
for (int i = 0; i < 3; ++i)
{
while (m_rotation(i) < 0.0)
{
m_rotation(i) += TWO_PI;
}
while (TWO_PI < m_rotation(i))
{
m_rotation(i) -= TWO_PI;
}
}
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
const Vec3d& GLVolume::get_offset() const
{
return m_offset;
}
void GLVolume::set_offset(const Vec3d& offset)
{
if (m_offset != offset)
{
m_offset = offset;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
const Vec3d& GLVolume::get_scaling_factor() const
{
return m_scaling_factor;
}
void GLVolume::set_scaling_factor(const Vec3d& scaling_factor)
{
if (m_scaling_factor != scaling_factor)
{
m_scaling_factor = scaling_factor;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
const Vec3d& GLVolume::get_mirror() const
{
return m_mirror;
}
double GLVolume::get_mirror(Axis axis) const
{
return m_mirror(axis);
}
void GLVolume::set_mirror(const Vec3d& mirror)
{
if (m_mirror != mirror)
{
m_mirror = mirror;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
void GLVolume::set_mirror(Axis axis, double mirror)
{
if (m_mirror(axis) != mirror)
{
m_mirror(axis) = mirror;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
#endif // !ENABLE_MODELVOLUME_TRANSFORM
void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned) void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned)
{ {
m_convex_hull = convex_hull; m_convex_hull = convex_hull;
m_convex_hull_owned = owned; m_convex_hull_owned = owned;
} }
#if ENABLE_MODELVOLUME_TRANSFORM
Transform3d GLVolume::world_matrix() const Transform3d GLVolume::world_matrix() const
{ {
Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix();
m.translation()(2) += m_sla_shift_z; m.translation()(2) += m_sla_shift_z;
return m; return m;
} }
#else
const Transform3f& GLVolume::world_matrix() const
{
if (m_world_matrix_dirty)
{
m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor, m_mirror).cast<float>();
m_world_matrix_dirty = false;
}
return m_world_matrix;
}
#endif // ENABLE_MODELVOLUME_TRANSFORM
const BoundingBoxf3& GLVolume::transformed_bounding_box() const const BoundingBoxf3& GLVolume::transformed_bounding_box() const
{ {
@ -426,11 +309,7 @@ const BoundingBoxf3& GLVolume::transformed_bounding_box() const
if (m_transformed_bounding_box_dirty) if (m_transformed_bounding_box_dirty)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
m_transformed_bounding_box = bounding_box.transformed(world_matrix()); m_transformed_bounding_box = bounding_box.transformed(world_matrix());
#else
m_transformed_bounding_box = bounding_box.transformed(world_matrix().cast<double>());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_transformed_bounding_box_dirty = false; m_transformed_bounding_box_dirty = false;
} }
@ -441,17 +320,10 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
{ {
if (m_transformed_convex_hull_bounding_box_dirty) if (m_transformed_convex_hull_bounding_box_dirty)
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0)) if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0))
m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix()); m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix());
else else
m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix()); m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix());
#else
if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0))
m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix().cast<double>());
else
m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix().cast<double>());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_transformed_convex_hull_bounding_box_dirty = false; m_transformed_convex_hull_bounding_box_dirty = false;
} }
@ -502,11 +374,7 @@ void GLVolume::render() const
::glCullFace(GL_BACK); ::glCullFace(GL_BACK);
::glPushMatrix(); ::glPushMatrix();
#if ENABLE_MODELVOLUME_TRANSFORM
::glMultMatrixd(world_matrix().data()); ::glMultMatrixd(world_matrix().data());
#else
::glMultMatrixf(world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
if (this->indexed_vertex_array.indexed()) if (this->indexed_vertex_array.indexed())
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
else else
@ -544,11 +412,7 @@ void GLVolume::render_using_layer_height() const
glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width); glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
if (world_matrix_id >= 0) if (world_matrix_id >= 0)
#if ENABLE_MODELVOLUME_TRANSFORM
::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data()); ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data());
#else
::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
GLsizei w = (GLsizei)layer_height_texture_width(); GLsizei w = (GLsizei)layer_height_texture_width();
GLsizei h = (GLsizei)layer_height_texture_height(); GLsizei h = (GLsizei)layer_height_texture_height();
@ -608,11 +472,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0); ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
if (worldmatrix_id != -1) if (worldmatrix_id != -1)
#if ENABLE_MODELVOLUME_TRANSFORM
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data()); ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data());
#else
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
render(); render();
@ -631,11 +491,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0); ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
if (worldmatrix_id != -1) if (worldmatrix_id != -1)
#if ENABLE_MODELVOLUME_TRANSFORM
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data()); ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data());
#else
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
::glBindBuffer(GL_ARRAY_BUFFER, indexed_vertex_array.vertices_and_normals_interleaved_VBO_id); ::glBindBuffer(GL_ARRAY_BUFFER, indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))); ::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
@ -643,11 +499,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glPushMatrix(); ::glPushMatrix();
#if ENABLE_MODELVOLUME_TRANSFORM
::glMultMatrixd(world_matrix().data()); ::glMultMatrixd(world_matrix().data());
#else
::glMultMatrixf(world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
if (n_triangles > 0) if (n_triangles > 0)
{ {
@ -691,11 +543,7 @@ void GLVolume::render_legacy() const
::glPushMatrix(); ::glPushMatrix();
#if ENABLE_MODELVOLUME_TRANSFORM
::glMultMatrixd(world_matrix().data()); ::glMultMatrixd(world_matrix().data());
#else
::glMultMatrixf(world_matrix().data());
#endif // ENABLE_MODELVOLUME_TRANSFORM
if (n_triangles > 0) if (n_triangles > 0)
::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, indexed_vertex_array.triangle_indices.data() + tverts_range.first); ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, indexed_vertex_array.triangle_indices.data() + tverts_range.first);
@ -780,11 +628,7 @@ int GLVolumeCollection::load_object_volume(
const ModelVolume *model_volume = model_object->volumes[volume_idx]; const ModelVolume *model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id(); const int extruder_id = model_volume->extruder_id();
const ModelInstance *instance = model_object->instances[instance_idx]; const ModelInstance *instance = model_object->instances[instance_idx];
#if ENABLE_MODELVOLUME_TRANSFORM
const TriangleMesh& mesh = model_volume->mesh; const TriangleMesh& mesh = model_volume->mesh;
#else
TriangleMesh mesh = model_volume->mesh;
#endif // ENABLE_MODELVOLUME_TRANSFORM
float color[4]; float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
/* if (model_volume->is_support_blocker()) { /* if (model_volume->is_support_blocker()) {
@ -797,6 +641,9 @@ int GLVolumeCollection::load_object_volume(
color[2] = 1.0f; color[2] = 1.0f;
} }
color[3] = model_volume->is_model_part() ? 1.f : 0.5f; */ color[3] = model_volume->is_model_part() ? 1.f : 0.5f; */
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
this->volumes.emplace_back(new GLVolume(color)); this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back(); GLVolume &v = *this->volumes.back();
v.set_color_from_model_volume(model_volume); v.set_color_from_model_volume(model_volume);
@ -819,15 +666,8 @@ int GLVolumeCollection::load_object_volume(
} }
v.is_modifier = ! model_volume->is_model_part(); v.is_modifier = ! model_volume->is_model_part();
v.shader_outside_printer_detection_enabled = model_volume->is_model_part(); v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
#if ENABLE_MODELVOLUME_TRANSFORM
v.set_instance_transformation(instance->get_transformation()); v.set_instance_transformation(instance->get_transformation());
v.set_volume_transformation(model_volume->get_transformation()); v.set_volume_transformation(model_volume->get_transformation());
#else
v.set_offset(instance->get_offset());
v.set_rotation(instance->get_rotation());
v.set_scaling_factor(instance->get_scaling_factor());
v.set_mirror(instance->get_mirror());
#endif // ENABLE_MODELVOLUME_TRANSFORM
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
} }
@ -938,11 +778,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
else else
v.indexed_vertex_array.load_mesh_flat_shading(mesh); v.indexed_vertex_array.load_mesh_flat_shading(mesh);
#if ENABLE_MODELVOLUME_TRANSFORM
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
#else
v.set_offset(Vec3d(pos_x, pos_y, 0.0));
#endif // ENABLE_MODELVOLUME_TRANSFORM
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box(); v.bounding_box = v.indexed_vertex_array.bounding_box();
@ -953,12 +789,54 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
} }
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
typedef std::pair<GLVolume*, double> GLVolumeWithZ;
typedef std::vector<GLVolumeWithZ> GLVolumesWithZList;
GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type)
{
GLVolumesWithZList list;
for (GLVolume* volume : volumes)
{
bool is_transparent = (volume->render_color[3] < 1.0f);
if (((type == GLVolumeCollection::Opaque) && !is_transparent) ||
((type == GLVolumeCollection::Transparent) && is_transparent) ||
(type == GLVolumeCollection::All))
list.push_back(std::make_pair(volume, 0.0));
}
if ((type == GLVolumeCollection::Transparent) && (list.size() > 1))
{
Transform3d modelview_matrix;
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
for (GLVolumeWithZ& volume : list)
{
volume.second = volume.first->bounding_box.transformed(modelview_matrix * volume.first->world_matrix()).max(2);
}
std::sort(list.begin(), list.end(),
[](const GLVolumeWithZ& v1, const GLVolumeWithZ& v2) -> bool { return v1.second < v2.second; }
);
}
return list;
}
void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface) const
#else
void GLVolumeCollection::render_VBOs() const void GLVolumeCollection::render_VBOs() const
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
{ {
::glEnable(GL_BLEND); ::glEnable(GL_BLEND);
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
::glCullFace(GL_BACK); ::glCullFace(GL_BACK);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
if (disable_cullface)
::glDisable(GL_CULL_FACE);
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
::glEnableClientState(GL_VERTEX_ARRAY); ::glEnableClientState(GL_VERTEX_ARRAY);
::glEnableClientState(GL_NORMAL_ARRAY); ::glEnableClientState(GL_NORMAL_ARRAY);
@ -980,6 +858,18 @@ void GLVolumeCollection::render_VBOs() const
if (z_range_id != -1) if (z_range_id != -1)
::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range); ::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
GLVolumesWithZList to_render = volumes_to_render(this->volumes, type);
for (GLVolumeWithZ& volume : to_render)
{
if (volume.first->layer_height_texture_data.can_use())
volume.first->generate_layer_height_texture(volume.first->layer_height_texture_data.print_object, false);
else
volume.first->set_render_color();
volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
}
#else
for (GLVolume *volume : this->volumes) for (GLVolume *volume : this->volumes)
{ {
if (volume->layer_height_texture_data.can_use()) if (volume->layer_height_texture_data.can_use())
@ -989,6 +879,7 @@ void GLVolumeCollection::render_VBOs() const
volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
} }
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
::glBindBuffer(GL_ARRAY_BUFFER, 0); ::glBindBuffer(GL_ARRAY_BUFFER, 0);
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -996,27 +887,55 @@ void GLVolumeCollection::render_VBOs() const
::glDisableClientState(GL_VERTEX_ARRAY); ::glDisableClientState(GL_VERTEX_ARRAY);
::glDisableClientState(GL_NORMAL_ARRAY); ::glDisableClientState(GL_NORMAL_ARRAY);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
if (disable_cullface)
::glEnable(GL_CULL_FACE);
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
::glDisable(GL_BLEND); ::glDisable(GL_BLEND);
} }
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface) const
#else
void GLVolumeCollection::render_legacy() const void GLVolumeCollection::render_legacy() const
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
{ {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glCullFace(GL_BACK); glCullFace(GL_BACK);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
if (disable_cullface)
::glDisable(GL_CULL_FACE);
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
GLVolumesWithZList to_render = volumes_to_render(this->volumes, type);
for (GLVolumeWithZ& volume : to_render)
{
volume.first->set_render_color();
volume.first->render_legacy();
}
#else
for (GLVolume *volume : this->volumes) for (GLVolume *volume : this->volumes)
{ {
volume->set_render_color(); volume->set_render_color();
volume->render_legacy(); volume->render_legacy();
} }
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
if (disable_cullface)
::glEnable(GL_CULL_FACE);
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
@ -1868,6 +1787,290 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
#if ENABLE_SIDEBAR_VISUAL_HINTS
GLModel::GLModel()
: m_useVBOs(false)
{
m_volume.shader_outside_printer_detection_enabled = false;
}
GLModel::~GLModel()
{
m_volume.release_geometry();
}
void GLModel::set_color(const float* color, unsigned int size)
{
m_volume.set_render_color(color, size);
}
const Vec3d& GLModel::get_offset() const
{
return m_volume.get_volume_offset();
}
void GLModel::set_offset(const Vec3d& offset)
{
m_volume.set_volume_offset(offset);
}
const Vec3d& GLModel::get_rotation() const
{
return m_volume.get_volume_rotation();
}
void GLModel::set_rotation(const Vec3d& rotation)
{
m_volume.set_volume_rotation(rotation);
}
const Vec3d& GLModel::get_scale() const
{
return m_volume.get_volume_scaling_factor();
}
void GLModel::set_scale(const Vec3d& scale)
{
m_volume.set_volume_scaling_factor(scale);
}
void GLModel::render() const
{
if (m_useVBOs)
render_VBOs();
else
render_legacy();
}
void GLModel::render_VBOs() const
{
::glEnable(GL_BLEND);
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
::glCullFace(GL_BACK);
::glEnableClientState(GL_VERTEX_ARRAY);
::glEnableClientState(GL_NORMAL_ARRAY);
GLint current_program_id;
::glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id);
GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1;
GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
m_volume.render_VBOs(color_id, print_box_detection_id, -1);
::glBindBuffer(GL_ARRAY_BUFFER, 0);
::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
::glDisableClientState(GL_VERTEX_ARRAY);
::glDisableClientState(GL_NORMAL_ARRAY);
::glDisable(GL_BLEND);
}
void GLModel::render_legacy() const
{
::glEnable(GL_LIGHTING);
::glEnable(GL_BLEND);
::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
::glCullFace(GL_BACK);
::glEnableClientState(GL_VERTEX_ARRAY);
::glEnableClientState(GL_NORMAL_ARRAY);
m_volume.render_legacy();
::glDisableClientState(GL_VERTEX_ARRAY);
::glDisableClientState(GL_NORMAL_ARRAY);
::glDisable(GL_BLEND);
::glDisable(GL_LIGHTING);
}
bool GLArrow::on_init(bool useVBOs)
{
Pointf3s vertices;
std::vector<Vec3crd> triangles;
// bottom face
vertices.emplace_back(0.5, 0.0, -0.1);
vertices.emplace_back(0.5, 2.0, -0.1);
vertices.emplace_back(1.0, 2.0, -0.1);
vertices.emplace_back(0.0, 3.0, -0.1);
vertices.emplace_back(-1.0, 2.0, -0.1);
vertices.emplace_back(-0.5, 2.0, -0.1);
vertices.emplace_back(-0.5, 0.0, -0.1);
// top face
vertices.emplace_back(0.5, 0.0, 0.1);
vertices.emplace_back(0.5, 2.0, 0.1);
vertices.emplace_back(1.0, 2.0, 0.1);
vertices.emplace_back(0.0, 3.0, 0.1);
vertices.emplace_back(-1.0, 2.0, 0.1);
vertices.emplace_back(-0.5, 2.0, 0.1);
vertices.emplace_back(-0.5, 0.0, 0.1);
// bottom face
triangles.emplace_back(0, 6, 1);
triangles.emplace_back(6, 5, 1);
triangles.emplace_back(5, 4, 3);
triangles.emplace_back(5, 3, 1);
triangles.emplace_back(1, 3, 2);
// top face
triangles.emplace_back(7, 8, 13);
triangles.emplace_back(13, 8, 12);
triangles.emplace_back(12, 10, 11);
triangles.emplace_back(8, 10, 12);
triangles.emplace_back(8, 9, 10);
// side face
triangles.emplace_back(0, 1, 8);
triangles.emplace_back(8, 7, 0);
triangles.emplace_back(1, 2, 9);
triangles.emplace_back(9, 8, 1);
triangles.emplace_back(2, 3, 10);
triangles.emplace_back(10, 9, 2);
triangles.emplace_back(3, 4, 11);
triangles.emplace_back(11, 10, 3);
triangles.emplace_back(4, 5, 12);
triangles.emplace_back(12, 11, 4);
triangles.emplace_back(5, 6, 13);
triangles.emplace_back(13, 12, 5);
triangles.emplace_back(6, 0, 7);
triangles.emplace_back(7, 13, 6);
m_useVBOs = useVBOs;
if (m_useVBOs)
m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles));
else
m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles));
m_volume.finalize_geometry(m_useVBOs);
return true;
}
GLCurvedArrow::GLCurvedArrow(unsigned int resolution)
: GLModel()
, m_resolution(resolution)
{
if (m_resolution == 0)
m_resolution = 1;
}
bool GLCurvedArrow::on_init(bool useVBOs)
{
Pointf3s vertices;
std::vector<Vec3crd> triangles;
double ext_radius = 2.5;
double int_radius = 1.5;
double step = 0.5 * (double)PI / (double)m_resolution;
unsigned int vertices_per_level = 4 + 2 * m_resolution;
// bottom face
vertices.emplace_back(0.0, 1.5, -0.1);
vertices.emplace_back(0.0, 1.0, -0.1);
vertices.emplace_back(-1.0, 2.0, -0.1);
vertices.emplace_back(0.0, 3.0, -0.1);
vertices.emplace_back(0.0, 2.5, -0.1);
for (unsigned int i = 1; i <= m_resolution; ++i)
{
double angle = (double)i * step;
double x = ext_radius * ::sin(angle);
double y = ext_radius * ::cos(angle);
vertices.emplace_back(x, y, -0.1);
}
for (unsigned int i = 0; i < m_resolution; ++i)
{
double angle = (double)i * step;
double x = int_radius * ::cos(angle);
double y = int_radius * ::sin(angle);
vertices.emplace_back(x, y, -0.1);
}
// top face
vertices.emplace_back(0.0, 1.5, 0.1);
vertices.emplace_back(0.0, 1.0, 0.1);
vertices.emplace_back(-1.0, 2.0, 0.1);
vertices.emplace_back(0.0, 3.0, 0.1);
vertices.emplace_back(0.0, 2.5, 0.1);
for (unsigned int i = 1; i <= m_resolution; ++i)
{
double angle = (double)i * step;
double x = ext_radius * ::sin(angle);
double y = ext_radius * ::cos(angle);
vertices.emplace_back(x, y, 0.1);
}
for (unsigned int i = 0; i < m_resolution; ++i)
{
double angle = (double)i * step;
double x = int_radius * ::cos(angle);
double y = int_radius * ::sin(angle);
vertices.emplace_back(x, y, 0.1);
}
// bottom face
triangles.emplace_back(0, 1, 2);
triangles.emplace_back(0, 2, 4);
triangles.emplace_back(4, 2, 3);
int first_id = 4;
int last_id = (int)vertices_per_level;
triangles.emplace_back(last_id, 0, first_id);
triangles.emplace_back(last_id, first_id, first_id + 1);
for (unsigned int i = 1; i < m_resolution; ++i)
{
triangles.emplace_back(last_id - i, last_id - i + 1, first_id + i);
triangles.emplace_back(last_id - i, first_id + i, first_id + i + 1);
}
// top face
last_id += 1;
triangles.emplace_back(last_id + 0, last_id + 2, last_id + 1);
triangles.emplace_back(last_id + 0, last_id + 4, last_id + 2);
triangles.emplace_back(last_id + 4, last_id + 3, last_id + 2);
first_id = last_id + 4;
last_id = last_id + 4 + 2 * (int)m_resolution;
triangles.emplace_back(last_id, first_id, (int)vertices_per_level + 1);
triangles.emplace_back(last_id, first_id + 1, first_id);
for (unsigned int i = 1; i < m_resolution; ++i)
{
triangles.emplace_back(last_id - i, first_id + i, last_id - i + 1);
triangles.emplace_back(last_id - i, first_id + i + 1, first_id + i);
}
// side face
for (unsigned int i = 0; i < 4 + 2 * (unsigned int)m_resolution; ++i)
{
triangles.emplace_back(i, vertices_per_level + 2 + i, i + 1);
triangles.emplace_back(i, vertices_per_level + 1 + i, vertices_per_level + 2 + i);
}
triangles.emplace_back(vertices_per_level, vertices_per_level + 1, 0);
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
m_useVBOs = useVBOs;
if (m_useVBOs)
m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles));
else
m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles));
m_volume.finalize_geometry(m_useVBOs);
return true;
}
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) std::string _3DScene::get_gl_info(bool format_as_html, bool extensions)
{ {
return s_canvas_mgr.get_gl_info(format_as_html, extensions); return s_canvas_mgr.get_gl_info(format_as_html, extensions);

View File

@ -18,7 +18,6 @@ class SLAPrintObject;
enum SLAPrintObjectStep : unsigned int; enum SLAPrintObjectStep : unsigned int;
class Model; class Model;
class ModelObject; class ModelObject;
class GCodePreviewData;
class DynamicPrintConfig; class DynamicPrintConfig;
class ExtrusionPath; class ExtrusionPath;
class ExtrusionMultiPath; class ExtrusionMultiPath;
@ -258,23 +257,9 @@ public:
~GLVolume(); ~GLVolume();
private: private:
#if ENABLE_MODELVOLUME_TRANSFORM
Geometry::Transformation m_instance_transformation; Geometry::Transformation m_instance_transformation;
Geometry::Transformation m_volume_transformation; Geometry::Transformation m_volume_transformation;
#else
// Offset of the volume to be rendered.
Vec3d m_offset;
// Rotation around three axes of the volume to be rendered.
Vec3d m_rotation;
// Scale factor along the three axes of the volume to be rendered.
Vec3d m_scaling_factor;
// Mirroring along the three axes of the volume to be rendered.
Vec3d m_mirror;
// World matrix of the volume to be rendered.
mutable Transform3f m_world_matrix;
// Whether or not is needed to recalculate the world matrix.
mutable bool m_world_matrix_dirty;
#endif // ENABLE_MODELVOLUME_TRANSFORM
// Shift in z required by sla supports+pad // Shift in z required by sla supports+pad
double m_sla_shift_z; double m_sla_shift_z;
// Bounding box of this volume, in unscaled coordinates. // Bounding box of this volume, in unscaled coordinates.
@ -358,7 +343,6 @@ public:
// set color according to model volume // set color according to model volume
void set_color_from_model_volume(const ModelVolume *model_volume); void set_color_from_model_volume(const ModelVolume *model_volume);
#if ENABLE_MODELVOLUME_TRANSFORM
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; } const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); } void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
@ -412,21 +396,6 @@ public:
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
#else
const Vec3d& get_rotation() const;
void set_rotation(const Vec3d& rotation);
const Vec3d& get_scaling_factor() const;
void set_scaling_factor(const Vec3d& scaling_factor);
const Vec3d& get_mirror() const;
double get_mirror(Axis axis) const;
void set_mirror(const Vec3d& mirror);
void set_mirror(Axis axis, double mirror);
const Vec3d& get_offset() const;
void set_offset(const Vec3d& offset);
#endif // ENABLE_MODELVOLUME_TRANSFORM
double get_sla_shift_z() const { return m_sla_shift_z; } double get_sla_shift_z() const { return m_sla_shift_z; }
void set_sla_shift_z(double z) { m_sla_shift_z = z; } void set_sla_shift_z(double z) { m_sla_shift_z = z; }
@ -437,11 +406,8 @@ public:
int volume_idx() const { return this->composite_id.volume_id; } int volume_idx() const { return this->composite_id.volume_id; }
int instance_idx() const { return this->composite_id.instance_id; } int instance_idx() const { return this->composite_id.instance_id; }
#if ENABLE_MODELVOLUME_TRANSFORM
Transform3d world_matrix() const; Transform3d world_matrix() const;
#else
const Transform3f& world_matrix() const;
#endif // ENABLE_MODELVOLUME_TRANSFORM
const BoundingBoxf3& transformed_bounding_box() const; const BoundingBoxf3& transformed_bounding_box() const;
const BoundingBoxf3& transformed_convex_hull_bounding_box() const; const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
@ -492,15 +458,24 @@ public:
void reset_layer_height_texture_data() { layer_height_texture_data.reset(); } void reset_layer_height_texture_data() { layer_height_texture_data.reset(); }
#if ENABLE_MODELVOLUME_TRANSFORM
void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; } void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
#endif // ENABLE_MODELVOLUME_TRANSFORM
}; };
typedef std::vector<GLVolume*> GLVolumePtrs; typedef std::vector<GLVolume*> GLVolumePtrs;
class GLVolumeCollection class GLVolumeCollection
{ {
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
public:
enum ERenderType : unsigned char
{
Opaque,
Transparent,
All
};
private:
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
// min and max vertex of the print box volume // min and max vertex of the print box volume
float print_box_min[3]; float print_box_min[3];
float print_box_max[3]; float print_box_max[3];
@ -545,8 +520,13 @@ public:
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width);
// Render the volumes by OpenGL. // Render the volumes by OpenGL.
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
void render_VBOs(ERenderType type, bool disable_cullface) const;
void render_legacy(ERenderType type, bool disable_cullface) const;
#else
void render_VBOs() const; void render_VBOs() const;
void render_legacy() const; void render_legacy() const;
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
// Finalize the initialization of the geometry & indices, // Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects // upload the geometry and indices to OpenGL VBO objects
@ -583,6 +563,56 @@ private:
GLVolumeCollection& operator=(const GLVolumeCollection &); GLVolumeCollection& operator=(const GLVolumeCollection &);
}; };
#if ENABLE_SIDEBAR_VISUAL_HINTS
class GLModel
{
protected:
GLVolume m_volume;
bool m_useVBOs;
public:
GLModel();
virtual ~GLModel();
bool init(bool useVBOs) { return on_init(useVBOs); }
void set_color(const float* color, unsigned int size);
const Vec3d& get_offset() const;
void set_offset(const Vec3d& offset);
const Vec3d& get_rotation() const;
void set_rotation(const Vec3d& rotation);
const Vec3d& get_scale() const;
void set_scale(const Vec3d& scale);
void render() const;
protected:
virtual bool on_init(bool useVBOs) = 0;
private:
void render_VBOs() const;
void render_legacy() const;
};
class GLArrow : public GLModel
{
protected:
virtual bool on_init(bool useVBOs);
};
class GLCurvedArrow : public GLModel
{
unsigned int m_resolution;
public:
explicit GLCurvedArrow(unsigned int resolution);
protected:
virtual bool on_init(bool useVBOs);
};
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
class _3DScene class _3DScene
{ {
static GUI::GLCanvas3DManager s_canvas_mgr; static GUI::GLCanvas3DManager s_canvas_mgr;

View File

@ -15,8 +15,8 @@
#include "libslic3r/SLAPrint.hpp" #include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/GCode/PostProcessor.hpp" #include "libslic3r/GCode/PostProcessor.hpp"
#include "libslic3r/GCode/PreviewData.hpp"
//#undef NDEBUG
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
#include <cctype> #include <cctype>
@ -65,11 +65,6 @@ PrinterTechnology BackgroundSlicingProcess::current_printer_technology() const
return m_print->technology(); return m_print->technology();
} }
static bool isspace(int ch)
{
return std::isspace(ch) != 0;
}
// This function may one day be merged into the Print, but historically the print was separated // This function may one day be merged into the Print, but historically the print was separated
// from the G-code generator. // from the G-code generator.
void BackgroundSlicingProcess::process_fff() void BackgroundSlicingProcess::process_fff()
@ -88,6 +83,8 @@ void BackgroundSlicingProcess::process_fff()
m_print->set_status(95, "Running post-processing scripts"); m_print->set_status(95, "Running post-processing scripts");
run_post_process_scripts(export_path, m_fff_print->config()); run_post_process_scripts(export_path, m_fff_print->config());
m_print->set_status(100, "G-code file exported to " + export_path); m_print->set_status(100, "G-code file exported to " + export_path);
} else if (! m_upload_job.empty()) {
prepare_upload();
} else { } else {
m_print->set_status(100, "Slicing complete"); m_print->set_status(100, "Slicing complete");
} }
@ -154,6 +151,10 @@ void BackgroundSlicingProcess::process_sla()
if (! m_export_path.empty()) { if (! m_export_path.empty()) {
m_sla_print->export_raster<SLAZipFmt>(m_export_path); m_sla_print->export_raster<SLAZipFmt>(m_export_path);
m_print->set_status(100, "Zip file exported to " + m_export_path); m_print->set_status(100, "Zip file exported to " + m_export_path);
} else if (! m_upload_job.empty()) {
prepare_upload();
} else {
m_print->set_status(100, "Slicing complete");
} }
this->set_step_done(bspsGCodeFinalize); this->set_step_done(bspsGCodeFinalize);
} }
@ -351,6 +352,13 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
assert(m_print != nullptr); assert(m_print != nullptr);
assert(config.opt_enum<PrinterTechnology>("printer_technology") == m_print->technology()); assert(config.opt_enum<PrinterTechnology>("printer_technology") == m_print->technology());
Print::ApplyStatus invalidated = m_print->apply(model, config); Print::ApplyStatus invalidated = m_print->apply(model, config);
if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) != 0 && m_print->technology() == ptFFF &&
m_gcode_preview_data != nullptr && ! this->m_fff_print->is_step_done(psGCodeExport)) {
// Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint.
m_gcode_preview_data->reset();
}
return invalidated; return invalidated;
} }
@ -373,13 +381,10 @@ void BackgroundSlicingProcess::schedule_upload(Slic3r::PrintHostJob upload_job)
if (! m_export_path.empty()) if (! m_export_path.empty())
return; return;
const boost::filesystem::path path = boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path(".upload.%%%%-%%%%-%%%%-%%%%.gcode");
// Guard against entering the export step before changing the export path. // Guard against entering the export step before changing the export path.
tbb::mutex::scoped_lock lock(m_print->state_mutex()); tbb::mutex::scoped_lock lock(m_print->state_mutex());
this->invalidate_step(bspsGCodeFinalize); this->invalidate_step(bspsGCodeFinalize);
m_export_path = path.string(); m_export_path.clear();
m_upload_job = std::move(upload_job); m_upload_job = std::move(upload_job);
} }
@ -420,4 +425,35 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
return m_step_state.invalidate_all([this](){ this->stop_internal(); }); return m_step_state.invalidate_all([this](){ this->stop_internal(); });
} }
void BackgroundSlicingProcess::prepare_upload()
{
// A print host upload job has been scheduled, enqueue it to the printhost job queue
// XXX: is fs::path::string() right?
// Generate a unique temp path to which the gcode/zip file is copied/exported
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
if (m_print == m_fff_print) {
m_print->set_status(95, "Running post-processing scripts");
run_post_process_scripts(source_path.string(), m_fff_print->config());
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
}
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
} else {
m_sla_print->export_raster<SLAZipFmt>(source_path.string());
// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
}
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
m_upload_job.upload_data.source_path = std::move(source_path);
GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job));
}
}; // namespace Slic3r }; // namespace Slic3r

View File

@ -167,6 +167,7 @@ private:
bool invalidate_all_steps(); bool invalidate_all_steps();
// If the background processing stop was requested, throw CanceledException. // If the background processing stop was requested, throw CanceledException.
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); } void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
void prepare_upload();
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue. // wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
int m_event_slicing_completed_id = 0; int m_event_slicing_completed_id = 0;

View File

@ -163,17 +163,42 @@ void Field::get_value_by_opt_type(wxString& str)
break; } break; }
case coString: case coString:
case coStrings: case coStrings:
case coFloatOrPercent: case coFloatOrPercent: {
m_value = str.ToStdString(); if (m_opt.type == coFloatOrPercent && !str.IsEmpty() && str.Last() != '%')
break; {
double val;
if (!str.ToCDouble(&val))
{
show_error(m_parent, _(L("Input value contains incorrect symbol(s).\nUse, please, only digits")));
set_value(double_to_string(val), true);
}
else if (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max ||
m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1)
{
std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
const int nVal = int(val);
wxString msg_text = wxString::Format(_(L("Do you mean %d%% instead of %d %s?\n"
"Select YES if you want to change this value to %d%%, \n"
"or NO if you are sure that %d %s is a correct value.")), nVal, nVal, sidetext, nVal, nVal, sidetext);
auto dialog = new wxMessageDialog(m_parent, msg_text, _(L("Parameter validation")), wxICON_WARNING | wxYES | wxNO);
if (dialog->ShowModal() == wxID_YES) {
set_value(wxString::Format("%s%%", str), true);
str += "%%";
}
}
}
m_value = str.ToStdString();
break; }
default: default:
break; break;
} }
} }
bool TextCtrl::is_defined_input_value() const template<class T>
bool is_defined_input_value(wxWindow* win, const ConfigOptionType& type)
{ {
if (static_cast<wxTextCtrl*>(window)->GetValue().empty() && m_opt.type != coString && m_opt.type != coStrings) if (static_cast<T*>(win)->GetValue().empty() && type != coString && type != coStrings)
return false; return false;
return true; return true;
} }
@ -251,8 +276,7 @@ void TextCtrl::BUILD() {
e.Skip(); e.Skip();
temp->GetToolTip()->Enable(true); temp->GetToolTip()->Enable(true);
#endif // __WXGTK__ #endif // __WXGTK__
// if (!is_defined_input_value()) if (is_defined_input_value<wxTextCtrl>(window, m_opt.type))
if (is_defined_input_value())
on_change_field(); on_change_field();
else else
on_kill_focus(e); on_kill_focus(e);
@ -376,7 +400,11 @@ void SpinCtrl::BUILD() {
auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size,
0, min_val, max_val, default_value); 0, min_val, max_val, default_value);
// temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId()); #ifndef __WXOSX__
// #ys_FIXME_KILL_FOCUS
// wxEVT_KILL_FOCUS doesn't handled on OSX now (wxWidgets 3.1.1)
// So, we will update values on KILL_FOCUS & SPINCTRL events under MSW and GTK
// and on TEXT event under OSX
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e)
{ {
if (tmp_value < 0) if (tmp_value < 0)
@ -386,6 +414,10 @@ void SpinCtrl::BUILD() {
on_change_field(); on_change_field();
} }
}), temp->GetId()); }), temp->GetId());
temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId());
#endif
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
{ {
// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value // # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
@ -397,10 +429,14 @@ void SpinCtrl::BUILD() {
if (is_matched(value, "^\\d+$")) if (is_matched(value, "^\\d+$"))
tmp_value = std::stoi(value); tmp_value = std::stoi(value);
else tmp_value = -9999; else tmp_value = -9999;
// on_change_field(); #ifdef __WXOSX__
// # We don't reset tmp_value here because _on_change might put callbacks if (tmp_value < 0) {
// # in the CallAfter queue, and we want the tmp value to be available from if (m_on_kill_focus != nullptr)
// # them as well. m_on_kill_focus(m_opt_id);
}
else
on_change_field();
#endif
}), temp->GetId()); }), temp->GetId());
temp->SetToolTip(get_tooltip_text(text_value)); temp->SetToolTip(get_tooltip_text(text_value));
@ -432,9 +468,24 @@ void Choice::BUILD() {
} }
set_selection(); set_selection();
} }
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); // temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId());
temp->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); temp->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId());
if (temp->GetWindowStyle() != wxCB_READONLY) {
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) {
e.Skip();
double old_val = !m_value.empty() ? boost::any_cast<double>(m_value) : -99999;
if (is_defined_input_value<wxComboBox>(window, m_opt.type)) {
if (fabs(old_val - boost::any_cast<double>(get_value())) <= 0.0001)
return;
else
on_change_field();
}
else
on_kill_focus(e);
}), temp->GetId());
}
temp->SetToolTip(get_tooltip_text(temp->GetValue())); temp->SetToolTip(get_tooltip_text(temp->GetValue()));
} }
@ -632,9 +683,7 @@ boost::any& Choice::get_value()
if (m_opt_id == rp_option) if (m_opt_id == rp_option)
return m_value = boost::any(ret_str); return m_value = boost::any(ret_str);
if (m_opt.type != coEnum) if (m_opt.type == coEnum)
/*m_value = */get_value_by_opt_type(ret_str);
else
{ {
int ret_enum = static_cast<wxComboBox*>(window)->GetSelection(); int ret_enum = static_cast<wxComboBox*>(window)->GetSelection();
if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 ) if (m_opt_id.compare("top_fill_pattern") == 0 || m_opt_id.compare("bottom_fill_pattern") == 0 )
@ -671,7 +720,16 @@ boost::any& Choice::get_value()
m_value = static_cast<DenseInfillAlgo>(ret_enum); m_value = static_cast<DenseInfillAlgo>(ret_enum);
else if (m_opt_id.compare("display_orientation") == 0) else if (m_opt_id.compare("display_orientation") == 0)
m_value = static_cast<SLADisplayOrientation>(ret_enum); m_value = static_cast<SLADisplayOrientation>(ret_enum);
} }
else if (m_opt.gui_type == "f_enum_open") {
const int ret_enum = static_cast<wxComboBox*>(window)->GetSelection();
if (ret_enum < 0 || m_opt.enum_values.empty())
get_value_by_opt_type(ret_str);
else
m_value = atof(m_opt.enum_values[ret_enum].c_str());
}
else
get_value_by_opt_type(ret_str);
return m_value; return m_value;
} }
@ -735,8 +793,11 @@ void PointCtrl::BUILD()
temp->Add(new wxStaticText(m_parent, wxID_ANY, " y : "), 0, wxALIGN_CENTER_VERTICAL, 0); temp->Add(new wxStaticText(m_parent, wxID_ANY, " y : "), 0, wxALIGN_CENTER_VERTICAL, 0);
temp->Add(y_textctrl); temp->Add(y_textctrl);
x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId()); // x_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), x_textctrl->GetId());
y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId()); // y_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), y_textctrl->GetId());
x_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), x_textctrl->GetId());
y_textctrl->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { OnKillFocus(e, x_textctrl); }), y_textctrl->GetId());
// // recast as a wxWindow to fit the calling convention // // recast as a wxWindow to fit the calling convention
sizer = dynamic_cast<wxSizer*>(temp); sizer = dynamic_cast<wxSizer*>(temp);
@ -745,6 +806,16 @@ void PointCtrl::BUILD()
y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y)); y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y));
} }
void PointCtrl::OnKillFocus(wxEvent& e, wxTextCtrl* win)
{
e.Skip();
if (!win->GetValue().empty()) {
on_change_field();
}
else
on_kill_focus(e);
}
void PointCtrl::set_value(const Vec2d& value, bool change_event) void PointCtrl::set_value(const Vec2d& value, bool change_event)
{ {
m_disable_change_event = !change_event; m_disable_change_event = !change_event;

View File

@ -266,7 +266,6 @@ public:
} }
boost::any& get_value() override; boost::any& get_value() override;
bool is_defined_input_value() const ;
virtual void enable(); virtual void enable();
virtual void disable(); virtual void disable();
@ -395,6 +394,7 @@ public:
void BUILD() override; void BUILD() override;
void OnKillFocus(wxEvent& e, wxTextCtrl* win);
void set_value(const Vec2d& value, bool change_event = false); void set_value(const Vec2d& value, bool change_event = false);
void set_value(const boost::any& value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false);
boost::any& get_value() override; boost::any& get_value() override;

File diff suppressed because it is too large Load Diff

View File

@ -20,12 +20,15 @@ class wxTimerEvent;
class wxPaintEvent; class wxPaintEvent;
class wxGLCanvas; class wxGLCanvas;
class GLUquadric;
typedef class GLUquadric GLUquadricObj;
namespace Slic3r { namespace Slic3r {
class GLShader; class GLShader;
class ExPolygon; class ExPolygon;
class BackgroundSlicingProcess; class BackgroundSlicingProcess;
class GCodePreviewData;
namespace GUI { namespace GUI {
@ -94,18 +97,21 @@ template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
using Vec3dEvent = Event<Vec3d>; using Vec3dEvent = Event<Vec3d>;
template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>; template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
#if ENABLE_REMOVE_TABS_FROM_PLATER
wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); // data: +1 => increase, -1 => decrease wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); // data: +1 => increase, -1 => decrease
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
@ -153,15 +159,10 @@ class GLCanvas3D
float zoom; float zoom;
float phi; float phi;
// float distance; // float distance;
#if !ENABLE_CONSTRAINED_CAMERA_TARGET
Vec3d target;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
private: private:
#if ENABLE_CONSTRAINED_CAMERA_TARGET
Vec3d m_target; Vec3d m_target;
BoundingBoxf3 m_scene_box; BoundingBoxf3 m_scene_box;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
float m_theta; float m_theta;
public: public:
@ -172,13 +173,11 @@ class GLCanvas3D
float get_theta() const { return m_theta; } float get_theta() const { return m_theta; }
void set_theta(float theta); void set_theta(float theta);
#if ENABLE_CONSTRAINED_CAMERA_TARGET
const Vec3d& get_target() const { return m_target; } const Vec3d& get_target() const { return m_target; }
void set_target(const Vec3d& target, GLCanvas3D& canvas); void set_target(const Vec3d& target, GLCanvas3D& canvas);
const BoundingBoxf3& get_scene_box() const { return m_scene_box; } const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
void set_scene_box(const BoundingBoxf3& box, GLCanvas3D& canvas); void set_scene_box(const BoundingBoxf3& box, GLCanvas3D& canvas);
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
}; };
class Bed class Bed
@ -231,12 +230,20 @@ class GLCanvas3D
struct Axes struct Axes
{ {
static const double Radius;
static const double ArrowBaseRadius;
static const double ArrowLength;
Vec3d origin; Vec3d origin;
float length; Vec3d length;
GLUquadricObj* m_quadric;
Axes(); Axes();
~Axes();
void render(bool depth_test) const; void render() const;
private:
void render_axis(double length) const;
}; };
class Shader class Shader
@ -362,14 +369,8 @@ public:
enum EMode : unsigned char enum EMode : unsigned char
{ {
#if ENABLE_MODELVOLUME_TRANSFORM
Volume, Volume,
Instance Instance
#else
Volume,
Instance,
Object
#endif // ENABLE_MODELVOLUME_TRANSFORM
}; };
enum EType : unsigned char enum EType : unsigned char
@ -392,7 +393,6 @@ public:
struct VolumeCache struct VolumeCache
{ {
private: private:
#if ENABLE_MODELVOLUME_TRANSFORM
struct TransformCache struct TransformCache
{ {
Vec3d position; Vec3d position;
@ -409,24 +409,11 @@ public:
TransformCache m_volume; TransformCache m_volume;
TransformCache m_instance; TransformCache m_instance;
#else
Vec3d m_position;
Vec3d m_rotation;
Vec3d m_scaling_factor;
Transform3d m_rotation_matrix;
Transform3d m_scale_matrix;
#endif // ENABLE_MODELVOLUME_TRANSFORM
public: public:
#if ENABLE_MODELVOLUME_TRANSFORM
VolumeCache() {} VolumeCache() {}
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform); VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
#else
VolumeCache();
VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor);
#endif // ENABLE_MODELVOLUME_TRANSFORM
#if ENABLE_MODELVOLUME_TRANSFORM
const Vec3d& get_volume_position() const { return m_volume.position; } const Vec3d& get_volume_position() const { return m_volume.position; }
const Vec3d& get_volume_rotation() const { return m_volume.rotation; } const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; } const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
@ -442,13 +429,6 @@ public:
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; } const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; } const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; } const Transform3d& get_instance_mirror_matrix() const { return m_instance.mirror_matrix; }
#else
const Vec3d& get_position() const { return m_position; }
const Vec3d& get_rotation() const { return m_rotation; }
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
const Transform3d& get_rotation_matrix() const { return m_rotation_matrix; }
const Transform3d& get_scale_matrix() const { return m_scale_matrix; }
#endif // ENABLE_MODELVOLUME_TRANSFORM
}; };
typedef std::map<unsigned int, VolumeCache> VolumesCache; typedef std::map<unsigned int, VolumeCache> VolumesCache;
@ -481,10 +461,24 @@ public:
mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_dirty; mutable bool m_bounding_box_dirty;
#if ENABLE_RENDER_SELECTION_CENTER
GLUquadricObj* m_quadric;
#endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_SIDEBAR_VISUAL_HINTS
mutable GLArrow m_arrow;
mutable GLCurvedArrow m_curved_arrow;
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
public: public:
Selection(); Selection();
#if ENABLE_RENDER_SELECTION_CENTER
~Selection();
#endif // ENABLE_RENDER_SELECTION_CENTER
void set_volumes(GLVolumePtrs* volumes); void set_volumes(GLVolumePtrs* volumes);
#if ENABLE_SIDEBAR_VISUAL_HINTS
bool init(bool useVBOs);
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
Model* get_model() const { return m_model; } Model* get_model() const { return m_model; }
void set_model(Model* model); void set_model(Model* model);
@ -515,6 +509,7 @@ public:
bool is_wipe_tower() const { return m_type == WipeTower; } bool is_wipe_tower() const { return m_type == WipeTower; }
bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); } bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); }
bool is_single_modifier() const { return m_type == SingleModifier; } bool is_single_modifier() const { return m_type == SingleModifier; }
bool is_multiple_modifier() const { return m_type == MultipleModifier; }
bool is_single_full_instance() const; bool is_single_full_instance() const;
bool is_multiple_full_instance() const { return m_type == MultipleFullInstance; } bool is_multiple_full_instance() const { return m_type == MultipleFullInstance; }
bool is_single_full_object() const { return m_type == SingleFullObject; } bool is_single_full_object() const { return m_type == SingleFullObject; }
@ -526,6 +521,7 @@ public:
bool is_from_single_object() const; bool is_from_single_object() const;
bool contains_volume(unsigned int volume_idx) const { return std::find(m_list.begin(), m_list.end(), volume_idx) != m_list.end(); } bool contains_volume(unsigned int volume_idx) const { return std::find(m_list.begin(), m_list.end(), volume_idx) != m_list.end(); }
bool requires_uniform_scale() const;
// Returns the the object id if the selection is from a single object, otherwise is -1 // Returns the the object id if the selection is from a single object, otherwise is -1
int get_object_idx() const; int get_object_idx() const;
@ -545,7 +541,7 @@ public:
void start_dragging(); void start_dragging();
void translate(const Vec3d& displacement); void translate(const Vec3d& displacement, bool local = false);
void rotate(const Vec3d& rotation, bool local); void rotate(const Vec3d& rotation, bool local);
void flattening_rotate(const Vec3d& normal); void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale, bool local); void scale(const Vec3d& scale, bool local);
@ -557,6 +553,14 @@ public:
void erase(); void erase();
void render() const; void render() const;
#if ENABLE_RENDER_SELECTION_CENTER
void render_center() const;
#endif // ENABLE_RENDER_SELECTION_CENTER
#if ENABLE_SIDEBAR_VISUAL_HINTS
void render_sidebar_hints(const std::string& sidebar_field) const;
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
bool requires_local_axes() const;
private: private:
void _update_valid(); void _update_valid();
@ -572,6 +576,16 @@ public:
void _render_selected_volumes() const; void _render_selected_volumes() const;
void _render_synchronized_volumes() const; void _render_synchronized_volumes() const;
void _render_bounding_box(const BoundingBoxf3& box, float* color) const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const;
#if ENABLE_SIDEBAR_VISUAL_HINTS
void _render_sidebar_position_hints(const std::string& sidebar_field) const;
void _render_sidebar_rotation_hints(const std::string& sidebar_field) const;
void _render_sidebar_scale_hints(const std::string& sidebar_field) const;
void _render_sidebar_size_hints(const std::string& sidebar_field) const;
void _render_sidebar_position_hint(Axis axis) const;
void _render_sidebar_rotation_hint(Axis axis) const;
void _render_sidebar_scale_hint(Axis axis) const;
void _render_sidebar_size_hint(Axis axis, double length) const;
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
void _synchronize_unselected_instances(); void _synchronize_unselected_instances();
void _synchronize_unselected_volumes(); void _synchronize_unselected_volumes();
#if ENABLE_ENSURE_ON_BED_WHILE_SCALING #if ENABLE_ENSURE_ON_BED_WHILE_SCALING
@ -628,9 +642,7 @@ private:
bool m_enabled; bool m_enabled;
typedef std::map<EType, GLGizmoBase*> GizmosMap; typedef std::map<EType, GLGizmoBase*> GizmosMap;
GizmosMap m_gizmos; GizmosMap m_gizmos;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
BackgroundTexture m_background_texture; BackgroundTexture m_background_texture;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
EType m_current; EType m_current;
public: public:
@ -699,9 +711,8 @@ private:
void _render_current_gizmo(const Selection& selection) const; void _render_current_gizmo(const Selection& selection) const;
float _get_total_overlay_height() const; float _get_total_overlay_height() const;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float _get_total_overlay_width() const; float _get_total_overlay_width() const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
GLGizmoBase* _get_current() const; GLGizmoBase* _get_current() const;
}; };
@ -774,16 +785,11 @@ private:
Mouse m_mouse; Mouse m_mouse;
mutable Gizmos m_gizmos; mutable Gizmos m_gizmos;
mutable GLToolbar m_toolbar; mutable GLToolbar m_toolbar;
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
GLToolbar* m_view_toolbar; GLToolbar* m_view_toolbar;
#else
GLRadioToolbar* m_view_toolbar;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
ClippingPlane m_clipping_planes[2]; ClippingPlane m_clipping_planes[2];
bool m_use_clipping_planes; bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2]; mutable SlaCap m_sla_caps[2];
std::string m_sidebar_field;
mutable GLVolumeCollection m_volumes; mutable GLVolumeCollection m_volumes;
Selection m_selection; Selection m_selection;
@ -803,7 +809,6 @@ private:
bool m_legend_texture_enabled; bool m_legend_texture_enabled;
bool m_picking_enabled; bool m_picking_enabled;
bool m_moving_enabled; bool m_moving_enabled;
bool m_shader_enabled;
bool m_dynamic_background_enabled; bool m_dynamic_background_enabled;
bool m_multisample_allowed; bool m_multisample_allowed;
bool m_regenerate_volumes; bool m_regenerate_volumes;
@ -819,10 +824,6 @@ private:
wxWindow *m_external_gizmo_widgets_parent; wxWindow *m_external_gizmo_widgets_parent;
#endif // not ENABLE_IMGUI #endif // not ENABLE_IMGUI
#if !ENABLE_CONSTRAINED_CAMERA_TARGET
void viewport_changed();
#endif // !ENABLE_CONSTRAINED_CAMERA_TARGET
public: public:
GLCanvas3D(wxGLCanvas* canvas); GLCanvas3D(wxGLCanvas* canvas);
~GLCanvas3D(); ~GLCanvas3D();
@ -833,13 +834,7 @@ public:
wxGLCanvas* get_wxglcanvas() { return m_canvas; } wxGLCanvas* get_wxglcanvas() { return m_canvas; }
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_view_toolbar(GLToolbar* toolbar) { m_view_toolbar = toolbar; } void set_view_toolbar(GLToolbar* toolbar) { m_view_toolbar = toolbar; }
#else
void set_view_toolbar(GLRadioToolbar* toolbar) { m_view_toolbar = toolbar; }
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
bool init(bool useVBOs, bool use_legacy_opengl); bool init(bool useVBOs, bool use_legacy_opengl);
void post_event(wxEvent &&event); void post_event(wxEvent &&event);
@ -852,11 +847,7 @@ public:
unsigned int get_volumes_count() const; unsigned int get_volumes_count() const;
void reset_volumes(); void reset_volumes();
#if ENABLE_REMOVE_TABS_FROM_PLATER
int check_volumes_outside_state() const; int check_volumes_outside_state() const;
#else
int check_volumes_outside_state(const DynamicPrintConfig* config) const;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
void set_config(DynamicPrintConfig* config); void set_config(DynamicPrintConfig* config);
void set_process(BackgroundSlicingProcess* process); void set_process(BackgroundSlicingProcess* process);
@ -870,8 +861,7 @@ public:
// fills the m_bed.m_grid_lines and sets m_bed.m_origin. // fills the m_bed.m_grid_lines and sets m_bed.m_origin.
// Sets m_bed.m_polygon to limit the object placement. // Sets m_bed.m_polygon to limit the object placement.
void set_bed_shape(const Pointfs& shape); void set_bed_shape(const Pointfs& shape);
void set_bed_axes_length(double length);
void set_axes_length(float length);
void set_clipping_plane(unsigned int id, const ClippingPlane& plane) void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
{ {
@ -888,9 +878,7 @@ public:
float get_camera_zoom() const; float get_camera_zoom() const;
BoundingBoxf3 volumes_bounding_box() const; BoundingBoxf3 volumes_bounding_box() const;
#if ENABLE_CONSTRAINED_CAMERA_TARGET
BoundingBoxf3 scene_bounding_box() const; BoundingBoxf3 scene_bounding_box() const;
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
bool is_layers_editing_enabled() const; bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const; bool is_layers_editing_allowed() const;
@ -904,7 +892,6 @@ public:
void enable_moving(bool enable); void enable_moving(bool enable);
void enable_gizmos(bool enable); void enable_gizmos(bool enable);
void enable_toolbar(bool enable); void enable_toolbar(bool enable);
void enable_shader(bool enable);
void enable_force_zoom_to_bed(bool enable); void enable_force_zoom_to_bed(bool enable);
void enable_dynamic_background(bool enable); void enable_dynamic_background(bool enable);
void allow_multisample(bool allow); void allow_multisample(bool allow);
@ -914,9 +901,7 @@ public:
void zoom_to_bed(); void zoom_to_bed();
void zoom_to_volumes(); void zoom_to_volumes();
#if ENABLE_MODIFIED_CAMERA_TARGET
void zoom_to_selection(); void zoom_to_selection();
#endif // ENABLE_MODIFIED_CAMERA_TARGET
void select_view(const std::string& direction); void select_view(const std::string& direction);
void set_viewport_from_scene(const GLCanvas3D& other); void set_viewport_from_scene(const GLCanvas3D& other);
@ -982,11 +967,9 @@ public:
void update_gizmos_on_off_state(); void update_gizmos_on_off_state();
#if ENABLE_CONSTRAINED_CAMERA_TARGET
void viewport_changed(); void viewport_changed();
#endif // ENABLE_CONSTRAINED_CAMERA_TARGET
void handle_sidebar_focus_event(const std::string& opt_key) {} void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
private: private:
bool _is_shown_on_screen() const; bool _is_shown_on_screen() const;
@ -1011,9 +994,12 @@ private:
void _picking_pass() const; void _picking_pass() const;
void _render_background() const; void _render_background() const;
void _render_bed(float theta) const; void _render_bed(float theta) const;
void _render_axes(bool depth_test) const; void _render_axes() const;
void _render_objects() const; void _render_objects() const;
void _render_selection() const; void _render_selection() const;
#if ENABLE_RENDER_SELECTION_CENTER
void _render_selection_center() const;
#endif // ENABLE_RENDER_SELECTION_CENTER
void _render_warning_texture() const; void _render_warning_texture() const;
void _render_legend_texture() const; void _render_legend_texture() const;
void _render_layer_editing_overlay() const; void _render_layer_editing_overlay() const;
@ -1021,13 +1007,14 @@ private:
void _render_current_gizmo() const; void _render_current_gizmo() const;
void _render_gizmos_overlay() const; void _render_gizmos_overlay() const;
void _render_toolbar() const; void _render_toolbar() const;
#if ENABLE_REMOVE_TABS_FROM_PLATER
void _render_view_toolbar() const; void _render_view_toolbar() const;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_SHOW_CAMERA_TARGET #if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target() const; void _render_camera_target() const;
#endif // ENABLE_SHOW_CAMERA_TARGET #endif // ENABLE_SHOW_CAMERA_TARGET
void _render_sla_slices() const; void _render_sla_slices() const;
#if ENABLE_SIDEBAR_VISUAL_HINTS
void _render_selection_sidebar_hints() const;
#endif // ENABLE_SIDEBAR_VISUAL_HINTS
void _update_volumes_hover_state() const; void _update_volumes_hover_state() const;
void _update_gizmos_data(); void _update_gizmos_data();
@ -1087,14 +1074,11 @@ private:
bool _is_any_volume_outside() const; bool _is_any_volume_outside() const;
#if ENABLE_REMOVE_TABS_FROM_PLATER
void _resize_toolbars() const; void _resize_toolbars() const;
#else
void _resize_toolbar() const;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
static std::vector<float> _parse_colors(const std::vector<std::string>& colors); static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
public:
const Print* fff_print() const; const Print* fff_print() const;
const SLAPrint* sla_print() const; const SLAPrint* sla_print() const;
}; };

View File

@ -19,7 +19,6 @@ class ExPolygon;
typedef std::vector<ExPolygon> ExPolygons; typedef std::vector<ExPolygon> ExPolygons;
class ModelObject; class ModelObject;
class PrintObject; class PrintObject;
class GCodePreviewData;
namespace GUI { namespace GUI {

View File

@ -8,6 +8,7 @@
#include "libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/SLA/SLASupportTree.hpp" #include "libslic3r/SLA/SLASupportTree.hpp"
#include "libslic3r/SLAPrint.hpp"
#include <cstdio> #include <cstdio>
#include <numeric> #include <numeric>
@ -859,14 +860,10 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
bool single_selection = single_instance || single_volume; bool single_selection = single_instance || single_volume;
Vec3f scale = 100.0f * Vec3f::Ones(); Vec3f scale = 100.0f * Vec3f::Ones();
#if ENABLE_MODELVOLUME_TRANSFORM
if (single_instance) if (single_instance)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>(); scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>();
else if (single_volume) else if (single_volume)
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>(); scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
#else
Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_scaling_factor().cast<float>() : 100.0f * m_scale.cast<float>();
#endif // ENABLE_MODELVOLUME_TRANSFORM
if ((single_selection && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging) if ((single_selection && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging)
set_tooltip("X: " + format(scale(0), 4) + "%"); set_tooltip("X: " + format(scale(0), 4) + "%");
@ -914,37 +911,22 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
// gets transform from first selected volume // gets transform from first selected volume
const GLVolume* v = selection.get_volume(*idxs.begin()); const GLVolume* v = selection.get_volume(*idxs.begin());
#if ENABLE_MODELVOLUME_TRANSFORM
transform = v->get_instance_transformation().get_matrix(); transform = v->get_instance_transformation().get_matrix();
// gets angles from first selected volume // gets angles from first selected volume
angles = v->get_instance_rotation(); angles = v->get_instance_rotation();
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
grabber_size = v->get_instance_transformation().get_matrix(true, true, false, true) * box.size(); grabber_size = v->get_instance_transformation().get_matrix(true, true, false, true) * box.size();
#else
transform = v->world_matrix().cast<double>();
// gets angles from first selected volume
angles = v->get_rotation();
// consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror());
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
else if (single_volume) else if (single_volume)
{ {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
box = v->bounding_box; box = v->bounding_box;
#if ENABLE_MODELVOLUME_TRANSFORM
transform = v->world_matrix(); transform = v->world_matrix();
angles = Geometry::extract_euler_angles(transform); angles = Geometry::extract_euler_angles(transform);
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
grabber_size = v->get_volume_transformation().get_matrix(true, true, false, true) * box.size(); grabber_size = v->get_volume_transformation().get_matrix(true, true, false, true) * box.size();
#else
transform = v->world_matrix().cast<double>();
angles = Geometry::extract_euler_angles(transform);
// consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror());
#endif // ENABLE_MODELVOLUME_TRANSFORM
} }
else else
{ {
@ -1465,6 +1447,7 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
::glPushMatrix(); ::glPushMatrix();
::glMultMatrixd(m.data()); ::glMultMatrixd(m.data());
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
for (int i = 0; i < (int)m_planes.size(); ++i) for (int i = 0; i < (int)m_planes.size(); ++i)
{ {
if (i == m_hover_id) if (i == m_hover_id)
@ -1496,6 +1479,7 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
::glPushMatrix(); ::glPushMatrix();
::glMultMatrixd(m.data()); ::glMultMatrixd(m.data());
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
for (int i = 0; i < (int)m_planes.size(); ++i) for (int i = 0; i < (int)m_planes.size(); ++i)
{ {
::glColor3f(1.0f, 1.0f, picking_color_component(i)); ::glColor3f(1.0f, 1.0f, picking_color_component(i));
@ -1526,7 +1510,6 @@ void GLGizmoFlatten::update_planes()
{ {
TriangleMesh ch; TriangleMesh ch;
for (const ModelVolume* vol : m_model_object->volumes) for (const ModelVolume* vol : m_model_object->volumes)
#if ENABLE_MODELVOLUME_TRANSFORM
{ {
if (vol->type() != ModelVolume::Type::MODEL_PART) if (vol->type() != ModelVolume::Type::MODEL_PART)
continue; continue;
@ -1534,9 +1517,6 @@ void GLGizmoFlatten::update_planes()
vol_ch.transform(vol->get_matrix()); vol_ch.transform(vol->get_matrix());
ch.merge(vol_ch); ch.merge(vol_ch);
} }
#else
ch.merge(vol->get_convex_hull());
#endif // ENABLE_MODELVOLUME_TRANSFORM
ch = ch.convex_hull_3d(); ch = ch.convex_hull_3d();
@ -1786,6 +1766,18 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G
{ {
if (is_mesh_update_necessary()) if (is_mesh_update_necessary())
update_mesh(); update_mesh();
// If there are no points, let's ask the backend if it calculated some.
if (model_object->sla_support_points.empty() && m_parent.sla_print()->is_step_done(slaposSupportPoints)) {
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
if (po->model_object()->id() == model_object->id()) {
const Eigen::MatrixXd& points = po->get_support_points();
for (unsigned int i=0; i<points.rows();++i)
model_object->sla_support_points.push_back(Vec3f(po->trafo().inverse().cast<float>() * Vec3f(points(i,0), points(i,1), points(i,2))));
break;
}
}
}
} }
} }
#else #else
@ -2170,6 +2162,9 @@ void GLGizmoSlaSupports::render_tooltip_texture() const {
#if ENABLE_IMGUI #if ENABLE_IMGUI
void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection) void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas3D::Selection& selection)
{ {
bool first_run = true; // This is a hack to redraw the button when all points are removed,
// so it is not delayed until the background process finishes.
RENDER_AGAIN:
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
m_imgui->set_next_window_bg_alpha(0.5f); m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
@ -2184,22 +2179,11 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, const GLCanvas
m_imgui->end(); m_imgui->end();
if (remove_all_clicked) if (remove_all_clicked) {
delete_current_grabber(true); delete_current_grabber(true);
if (first_run) {
if (generate) { first_run = false;
const DynamicPrintConfig& cfg = *wxGetApp().get_tab(Preset::TYPE_SLA_PRINT)->get_config(); goto RENDER_AGAIN;
SLAAutoSupports::Config config;
config.density_at_horizontal = cfg.opt_int("support_density_at_horizontal") / 10000.f;
config.density_at_45 = cfg.opt_int("support_density_at_45") / 10000.f;
config.minimal_z = cfg.opt_float("support_minimal_z");
SLAAutoSupports sas(*m_model_object, config);
sas.generate();
m_grabbers.clear();
for (const Vec3f& point : m_model_object->sla_support_points) {
m_grabbers.push_back(Grabber());
m_grabbers.back().center = point.cast<double>();
} }
} }

View File

@ -436,7 +436,6 @@ protected:
class GLGizmoSlaSupports : public GLGizmoBase class GLGizmoSlaSupports : public GLGizmoBase
{ {
private: private:
SLAAutoSupports* m_sas = nullptr;
ModelObject* m_model_object = nullptr; ModelObject* m_model_object = nullptr;
#if ENABLE_SLA_SUPPORT_GIZMO_MOD #if ENABLE_SLA_SUPPORT_GIZMO_MOD
ModelObject* m_old_model_object = nullptr; ModelObject* m_old_model_object = nullptr;

View File

@ -36,7 +36,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmap
// Load a PNG with an alpha channel. // Load a PNG with an alpha channel.
wxImage image; wxImage image;
if (!image.LoadFile(filename, wxBITMAP_TYPE_PNG)) if (!image.LoadFile(wxString::FromUTF8(filename), wxBITMAP_TYPE_PNG))
{ {
reset(); reset();
return false; return false;

File diff suppressed because it is too large Load Diff

View File

@ -77,9 +77,7 @@ public:
void do_action(wxEvtHandler *target); void do_action(wxEvtHandler *target);
bool is_enabled() const; bool is_enabled() const;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool is_disabled() const; bool is_disabled() const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool is_hovered() const; bool is_hovered() const;
bool is_pressed() const; bool is_pressed() const;
@ -97,7 +95,6 @@ private:
// from left to right // from left to right
struct ItemsIconsTexture struct ItemsIconsTexture
{ {
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
struct Metadata struct Metadata
{ {
// path of the file containing the icons' texture // path of the file containing the icons' texture
@ -111,23 +108,11 @@ struct ItemsIconsTexture
Metadata(); Metadata();
}; };
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
GLTexture texture;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
Metadata metadata;
#else
// size of the square icons, in pixels
unsigned int items_icon_size;
// distance from the border, in pixels
unsigned int items_icon_border_size;
// distance between two adjacent icons (to avoid filtering artifacts), in pixels
unsigned int items_icon_gap_size;
ItemsIconsTexture(); GLTexture texture;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE Metadata metadata;
}; };
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
struct BackgroundTexture struct BackgroundTexture
{ {
struct Metadata struct Metadata
@ -149,19 +134,16 @@ struct BackgroundTexture
GLTexture texture; GLTexture texture;
Metadata metadata; Metadata metadata;
}; };
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
class GLToolbar class GLToolbar
{ {
public: public:
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
enum EType : unsigned char enum EType : unsigned char
{ {
Normal, Normal,
Radio, Radio,
Num_Types Num_Types
}; };
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
struct Layout struct Layout
{ {
@ -183,23 +165,17 @@ public:
}; };
EType type; EType type;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
EOrientation orientation; EOrientation orientation;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float top; float top;
float left; float left;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float border; float border;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float separator_size; float separator_size;
float gap_size; float gap_size;
float icons_scale; float icons_scale;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float width; float width;
float height; float height;
bool dirty; bool dirty;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
Layout(); Layout();
}; };
@ -207,47 +183,27 @@ public:
private: private:
typedef std::vector<GLToolbarItem*> ItemsList; typedef std::vector<GLToolbarItem*> ItemsList;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
EType m_type; EType m_type;
#else
GLCanvas3D& m_parent;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool m_enabled; bool m_enabled;
ItemsIconsTexture m_icons_texture; ItemsIconsTexture m_icons_texture;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
BackgroundTexture m_background_texture; BackgroundTexture m_background_texture;
mutable Layout m_layout; mutable Layout m_layout;
#else
Layout m_layout;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
ItemsList m_items; ItemsList m_items;
public: public:
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
explicit GLToolbar(EType type); explicit GLToolbar(EType type);
#else
explicit GLToolbar(GLCanvas3D& parent);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
~GLToolbar(); ~GLToolbar();
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture); bool init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture);
#else
bool init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
Layout::EType get_layout_type() const; Layout::EType get_layout_type() const;
void set_layout_type(Layout::EType type); void set_layout_type(Layout::EType type);
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
Layout::EOrientation get_layout_orientation() const; Layout::EOrientation get_layout_orientation() const;
void set_layout_orientation(Layout::EOrientation orientation); void set_layout_orientation(Layout::EOrientation orientation);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_position(float top, float left); void set_position(float top, float left);
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_border(float border); void set_border(float border);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_separator_size(float size); void set_separator_size(float size);
void set_gap_size(float size); void set_gap_size(float size);
void set_icons_scale(float scale); void set_icons_scale(float scale);
@ -263,169 +219,36 @@ public:
void enable_item(const std::string& name); void enable_item(const std::string& name);
void disable_item(const std::string& name); void disable_item(const std::string& name);
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void select_item(const std::string& name); void select_item(const std::string& name);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool is_item_pressed(const std::string& name) const; bool is_item_pressed(const std::string& name) const;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
bool is_item_disabled(const std::string& name) const; bool is_item_disabled(const std::string& name) const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent); std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
#else
std::string update_hover_state(const Vec2d& mouse_pos);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#else
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
#else
void update_hover_state(const Vec2d& mouse_pos);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
// returns the id of the item under the given mouse position or -1 if none // returns the id of the item under the given mouse position or -1 if none
int contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; int contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
void do_action(unsigned int item_id, GLCanvas3D& parent); void do_action(unsigned int item_id, GLCanvas3D& parent);
#else
// returns the id of the item under the given mouse position or -1 if none
int contains_mouse(const Vec2d& mouse_pos) const;
void do_action(unsigned int item_id);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void render(const GLCanvas3D& parent) const; void render(const GLCanvas3D& parent) const;
#else
void render() const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
private: private:
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void calc_layout() const; void calc_layout() const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
float get_width_horizontal() const; float get_width_horizontal() const;
float get_width_vertical() const; float get_width_vertical() const;
float get_height_horizontal() const; float get_height_horizontal() const;
float get_height_vertical() const; float get_height_vertical() const;
float get_main_size() const; float get_main_size() const;
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent); std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent); std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
#else
std::string update_hover_state_horizontal(const Vec2d& mouse_pos);
std::string update_hover_state_vertical(const Vec2d& mouse_pos);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#else
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
void update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
#else
void update_hover_state_horizontal(const Vec2d& mouse_pos);
void update_hover_state_vertical(const Vec2d& mouse_pos);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
int contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; int contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
int contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const; int contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
void render_horizontal(const GLCanvas3D& parent) const; void render_horizontal(const GLCanvas3D& parent) const;
void render_vertical(const GLCanvas3D& parent) const; void render_vertical(const GLCanvas3D& parent) const;
#else
int contains_mouse_horizontal(const Vec2d& mouse_pos) const;
int contains_mouse_vertical(const Vec2d& mouse_pos) const;
void render_horizontal() const;
void render_vertical() const;
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
}; };
#if !ENABLE_TOOLBAR_BACKGROUND_TEXTURE
class GLRadioToolbarItem
{
public:
struct Data
{
std::string name;
std::string tooltip;
unsigned int sprite_id;
wxEventType action_event;
Data();
};
enum EState : unsigned char
{
Normal,
Pressed,
Hover,
HoverPressed,
Num_States
};
private:
EState m_state;
Data m_data;
public:
GLRadioToolbarItem(const Data& data);
EState get_state() const;
void set_state(EState state);
const std::string& get_name() const;
const std::string& get_tooltip() const;
bool is_hovered() const;
bool is_pressed() const;
void do_action(wxEvtHandler *target);
void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const;
private:
GLTexture::Quad_UVs get_uvs(unsigned int texture_size, unsigned int border_size, unsigned int icon_size, unsigned int gap_size) const;
};
class GLRadioToolbar
{
typedef std::vector<GLRadioToolbarItem*> ItemsList;
ItemsIconsTexture m_icons_texture;
ItemsList m_items;
float m_top;
float m_left;
public:
GLRadioToolbar();
~GLRadioToolbar();
bool init(const std::string& icons_texture_filename, unsigned int items_icon_size, unsigned int items_icon_border_size, unsigned int items_icon_gap_size);
bool add_item(const GLRadioToolbarItem::Data& data);
float get_height() const;
void set_position(float top, float left);
void set_selection(const std::string& name);
// returns the id of the item under the given mouse position or -1 if none
int contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
void do_action(unsigned int item_id, GLCanvas3D& parent);
void render(const GLCanvas3D& parent) const;
};
#endif // !ENABLE_TOOLBAR_BACKGROUND_TEXTURE
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -4,6 +4,7 @@
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
#include <assert.h> #include <assert.h>
#include <string>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -316,6 +317,20 @@ std::string into_u8(const wxString &str)
return std::string(buffer_utf8.data()); return std::string(buffer_utf8.data());
} }
wxString from_path(const boost::filesystem::path &path)
{
#ifdef _WIN32
return wxString(path.string<std::wstring>());
#else
return wxString::FromUTF8(path.string<std::string>());
#endif
}
boost::filesystem::path into_path(const wxString &str)
{
return boost::filesystem::path(str.wx_str());
}
bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height) bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height)
{ {
const auto idx = wxDisplay::GetFromWindow(window); const auto idx = wxDisplay::GetFromWindow(window);
@ -379,7 +394,6 @@ void about()
{ {
AboutDialog dlg; AboutDialog dlg;
dlg.ShowModal(); dlg.ShowModal();
dlg.Destroy();
} }
void desktop_open_datadir_folder() void desktop_open_datadir_folder()

View File

@ -1,6 +1,10 @@
#ifndef slic3r_GUI_hpp_ #ifndef slic3r_GUI_hpp_
#define slic3r_GUI_hpp_ #define slic3r_GUI_hpp_
#include <boost/filesystem/path.hpp>
#include <wx/string.h>
#include "libslic3r/Config.hpp" #include "libslic3r/Config.hpp"
class wxWindow; class wxWindow;
@ -8,7 +12,6 @@ class wxMenuBar;
class wxNotebook; class wxNotebook;
class wxComboCtrl; class wxComboCtrl;
class wxFileDialog; class wxFileDialog;
class wxString;
class wxTopLevelWindow; class wxTopLevelWindow;
namespace Slic3r { namespace Slic3r {
@ -16,7 +19,6 @@ namespace Slic3r {
class AppConfig; class AppConfig;
class DynamicPrintConfig; class DynamicPrintConfig;
class Print; class Print;
class GCodePreviewData;
namespace GUI { namespace GUI {
@ -54,10 +56,16 @@ void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string
// encoded inside an int. // encoded inside an int.
int combochecklist_get_flags(wxComboCtrl* comboCtrl); int combochecklist_get_flags(wxComboCtrl* comboCtrl);
// Return wxString from std::string in UTF8 // wxString conversions:
// wxString from std::string in UTF8
wxString from_u8(const std::string &str); wxString from_u8(const std::string &str);
// Return std::string in UTF8 from wxString // std::string in UTF8 from wxString
std::string into_u8(const wxString &str); std::string into_u8(const wxString &str);
// wxString from boost path
wxString from_path(const boost::filesystem::path &path);
// boost path from wxString
boost::filesystem::path into_path(const wxString &str);
// Returns the dimensions of the screen on which the main frame is displayed // Returns the dimensions of the screen on which the main frame is displayed
bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height); bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height);

View File

@ -35,6 +35,7 @@
#include "Preferences.hpp" #include "Preferences.hpp"
#include "Tab.hpp" #include "Tab.hpp"
#include "SysInfoDialog.hpp" #include "SysInfoDialog.hpp"
#include "KBShortcutsDialog.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -42,7 +43,7 @@ namespace GUI {
wxString file_wildcards(FileType file_type, const std::string &custom_extension) wxString file_wildcards(FileType file_type, const std::string &custom_extension)
{ {
static const wxString defaults[FT_SIZE] = { static const std::string defaults[FT_SIZE] = {
/* FT_STL */ "STL files (*.stl)|*.stl;*.STL", /* FT_STL */ "STL files (*.stl)|*.stl;*.STL",
/* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", /* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ",
/* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", /* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML",
@ -53,16 +54,20 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI", /* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
/* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG", /* FT_SVG */ "SVG files (*.svg)|*.svg;*.SVG",
/* FT_PNGZIP */"Zipped PNG files (*.zip)|*.zip;*.ZIP", // This is lame, but that's what we use for SLA /* FT_PNGZIP */"Zipped PNG files (*.dwz)|*.dwz;*.DWZ", // This is lame, but that's what we use for SLA
}; };
wxString out = defaults[file_type]; std::string out = defaults[file_type];
if (! custom_extension.empty()) { if (! custom_extension.empty()) {
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. // Find the custom extension in the template.
out += ";*"; if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) {
out += from_u8(custom_extension); // The custom extension was not found in the template.
// Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it.
boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|");
out += std::string(";*") + custom_extension;
}
} }
return out; return wxString::FromUTF8(out.c_str());
} }
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); } static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
@ -73,7 +78,6 @@ GUI_App::GUI_App()
: wxApp() : wxApp()
#if ENABLE_IMGUI #if ENABLE_IMGUI
, m_imgui(new ImGuiWrapper()) , m_imgui(new ImGuiWrapper())
, m_printhost_queue(new PrintHostJobQueue())
#endif // ENABLE_IMGUI #endif // ENABLE_IMGUI
{} {}
@ -137,19 +141,23 @@ bool GUI_App::OnInit()
std::cerr << "Creating main frame..." << std::endl; std::cerr << "Creating main frame..." << std::endl;
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler()); wxImage::AddHandler(new wxPNGHandler());
mainframe = new MainFrame(no_plater, false); mainframe = new MainFrame();
sidebar().obj_list()->init_objects(); // propagate model objects to object list sidebar().obj_list()->init_objects(); // propagate model objects to object list
update_mode(); // update_mode(); // do that later
SetTopWindow(mainframe); SetTopWindow(mainframe);
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
CallAfter([this]() { CallAfter([this]() {
// temporary workaround for the correct behavior of the Scrolled sidebar panel // temporary workaround for the correct behavior of the Scrolled sidebar panel
auto& panel = sidebar(); auto& panel = sidebar();
if (panel.obj_list()->GetMinHeight() > 200) { if (panel.obj_list()->GetMinHeight() > 200) {
wxWindowUpdateLocker noUpdates_sidebar(&panel); wxWindowUpdateLocker noUpdates_sidebar(&panel);
panel.obj_list()->SetMinSize(wxSize(-1, 200)); panel.obj_list()->SetMinSize(wxSize(-1, 200));
panel.Layout(); // panel.Layout();
} }
update_mode(); // update view mode after fix of the object_list size
// to correct later layouts
}); });
// This makes CallAfter() work // This makes CallAfter() work
@ -175,6 +183,11 @@ bool GUI_App::OnInit()
if (app_config->dirty()) if (app_config->dirty())
app_config->save(); app_config->save();
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if (this->plater() != nullptr)
this->obj_manipul()->update_if_dirty();
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
}); });
// On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...) // On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...)
@ -275,16 +288,31 @@ void GUI_App::recreate_GUI()
{ {
std::cerr << "recreate_GUI" << std::endl; std::cerr << "recreate_GUI" << std::endl;
auto topwindow = GetTopWindow(); MainFrame* topwindow = dynamic_cast<MainFrame*>(GetTopWindow());
mainframe = new MainFrame(no_plater,false); mainframe = new MainFrame();
sidebar().obj_list()->init_objects(); // propagate model objects to object list sidebar().obj_list()->init_objects(); // propagate model objects to object list
update_mode(); // update_mode(); // do that later
if (topwindow) { if (topwindow) {
SetTopWindow(mainframe); SetTopWindow(mainframe);
topwindow->Destroy(); topwindow->Destroy();
} }
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
CallAfter([this]() {
// temporary workaround for the correct behavior of the Scrolled sidebar panel
auto& panel = sidebar();
if (panel.obj_list()->GetMinHeight() > 200) {
wxWindowUpdateLocker noUpdates_sidebar(&panel);
panel.obj_list()->SetMinSize(wxSize(-1, 200));
// panel.Layout();
}
update_mode(); // update view mode after fix of the object_list size
// to correct later layouts
});
mainframe->Show(true);
// On OSX the UI was not initialized correctly if the wizard was called // On OSX the UI was not initialized correctly if the wizard was called
// before the UI was up and running. // before the UI was up and running.
CallAfter([]() { CallAfter([]() {
@ -300,6 +328,13 @@ void GUI_App::system_info()
dlg.Destroy(); dlg.Destroy();
} }
void GUI_App::keyboard_shortcuts()
{
KBShortcutsDialog dlg;
dlg.ShowModal();
dlg.Destroy();
}
// static method accepting a wxWindow object as first parameter // static method accepting a wxWindow object as first parameter
bool GUI_App::catch_error(std::function<void()> cb, bool GUI_App::catch_error(std::function<void()> cb,
// wxMessageDialog* message_dialog, // wxMessageDialog* message_dialog,
@ -347,7 +382,7 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files)
input_files.Clear(); input_files.Clear();
wxFileDialog dialog(parent ? parent : GetTopWindow(), wxFileDialog dialog(parent ? parent : GetTopWindow(),
_(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")), _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")),
app_config->get_last_dir(), "", from_u8(app_config->get_last_dir()), "",
file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST); file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() == wxID_OK) if (dialog.ShowModal() == wxID_OK)
@ -424,9 +459,12 @@ bool GUI_App::select_language( wxArrayString & names,
{ {
m_wxLocale = new wxLocale; m_wxLocale = new wxLocale;
m_wxLocale->Init(identifiers[index]); m_wxLocale->Init(identifiers[index]);
m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); m_wxLocale->AddCatalogLookupPathPrefix(wxString::FromUTF8(localization_dir()));
m_wxLocale->AddCatalog(GetAppName()); m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE");
wxSetlocale(LC_NUMERIC, "C"); wxSetlocale(LC_NUMERIC, "C");
#ifdef WIN32
::SetLocaleInfoA(LOCALE_CUSTOM_DEFAULT, LOCALE_SDECIMAL, ".");
#endif /* WIN32 */
Preset::update_suffix_modified(); Preset::update_suffix_modified();
return true; return true;
} }
@ -451,10 +489,13 @@ bool GUI_App::load_language()
{ {
m_wxLocale = new wxLocale; m_wxLocale = new wxLocale;
m_wxLocale->Init(identifiers[i]); m_wxLocale->Init(identifiers[i]);
m_wxLocale->AddCatalogLookupPathPrefix(localization_dir()); m_wxLocale->AddCatalogLookupPathPrefix(wxString::FromUTF8(localization_dir()));
m_wxLocale->AddCatalog(GetAppName()); m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE");
wxSetlocale(LC_NUMERIC, "C"); wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified(); #ifdef WIN32
::SetLocaleInfoA(LOCALE_CUSTOM_DEFAULT, LOCALE_SDECIMAL, ".");
#endif /* WIN32 */
Preset::update_suffix_modified();
return true; return true;
} }
} }
@ -478,7 +519,7 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident
names.Clear(); names.Clear();
identifiers.Clear(); identifiers.Clear();
wxDir dir(localization_dir()); wxDir dir(wxString::FromUTF8(localization_dir()));
wxString filename; wxString filename;
const wxLanguageInfo * langinfo; const wxLanguageInfo * langinfo;
wxString name = wxLocale::GetLanguageName(wxLANGUAGE_DEFAULT); wxString name = wxLocale::GetLanguageName(wxLANGUAGE_DEFAULT);
@ -495,7 +536,8 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident
{ {
auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() +
filename + wxFileName::GetPathSeparator() + filename + wxFileName::GetPathSeparator() +
GetAppName() + wxT(".mo"); /*GetAppName()*/"Slic3rPE" +
wxT(".mo");
if (wxFileExists(full_file_name)) if (wxFileExists(full_file_name))
{ {
names.Add(langinfo->Description); names.Add(langinfo->Description);
@ -523,6 +565,13 @@ ConfigMenuIDs GUI_App::get_view_mode()
mode == "simple" ? ConfigMenuModeSimple : ConfigMenuModeAdvanced; mode == "simple" ? ConfigMenuModeSimple : ConfigMenuModeAdvanced;
} }
ConfigOptionMode GUI_App::get_opt_mode() {
const ConfigMenuIDs mode = wxGetApp().get_view_mode();
return mode == ConfigMenuModeSimple ? comSimple :
mode == ConfigMenuModeExpert ? comExpert : comAdvanced;
}
// Update view mode according to selected menu // Update view mode according to selected menu
void GUI_App::update_mode() void GUI_App::update_mode()
{ {
@ -537,10 +586,8 @@ void GUI_App::update_mode()
sidebar().Layout(); sidebar().Layout();
ConfigOptionMode opt_mode = mode == ConfigMenuModeSimple ? comSimple :
mode == ConfigMenuModeExpert ? comExpert : comAdvanced;
for (auto tab : tabs_list) for (auto tab : tabs_list)
tab->update_visibility(opt_mode); tab->update_visibility();
plater()->update_object_menu(); plater()->update_object_menu();
} }

View File

@ -71,7 +71,6 @@ static wxString dots("…", wxConvUTF8);
class GUI_App : public wxApp class GUI_App : public wxApp
{ {
bool no_plater{ false };
bool app_conf_exists{ false }; bool app_conf_exists{ false };
// Lock to guard the callback stack // Lock to guard the callback stack
@ -92,7 +91,7 @@ class GUI_App : public wxApp
std::unique_ptr<ImGuiWrapper> m_imgui; std::unique_ptr<ImGuiWrapper> m_imgui;
#endif // ENABLE_IMGUI #endif // ENABLE_IMGUI
std::unique_ptr<PrintHostJobQueue> m_printhost_queue; std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
public: public:
bool OnInit() override; bool OnInit() override;
@ -115,6 +114,7 @@ public:
void recreate_GUI(); void recreate_GUI();
void system_info(); void system_info();
void keyboard_shortcuts();
void load_project(wxWindow *parent, wxString& input_file); void load_project(wxWindow *parent, wxString& input_file);
void import_model(wxWindow *parent, wxArrayString& input_files); void import_model(wxWindow *parent, wxArrayString& input_files);
static bool catch_error(std::function<void()> cb, static bool catch_error(std::function<void()> cb,
@ -135,6 +135,7 @@ public:
Tab* get_tab(Preset::Type type); Tab* get_tab(Preset::Type type);
ConfigMenuIDs get_view_mode(); ConfigMenuIDs get_view_mode();
ConfigOptionMode get_opt_mode();
void update_mode(); void update_mode();
void add_config_menu(wxMenuBar *menu); void add_config_menu(wxMenuBar *menu);
@ -164,7 +165,7 @@ public:
ImGuiWrapper* imgui() { return m_imgui.get(); } ImGuiWrapper* imgui() { return m_imgui.get(); }
#endif // ENABLE_IMGUI #endif // ENABLE_IMGUI
PrintHostJobQueue& printhost_queue() { return *m_printhost_queue.get(); } PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); }
}; };
DECLARE_APP(GUI_App) DECLARE_APP(GUI_App)

View File

@ -840,27 +840,17 @@ void ObjectList::load_part( ModelObject* model_object,
if (model_object->origin_translation != Vec3d::Zero()) if (model_object->origin_translation != Vec3d::Zero())
{ {
object->center_around_origin(); object->center_around_origin();
#if !ENABLE_MODELVOLUME_TRANSFORM
object->ensure_on_bed();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
delta = model_object->origin_translation - object->origin_translation; delta = model_object->origin_translation - object->origin_translation;
} }
for (auto volume : object->volumes) { for (auto volume : object->volumes) {
#if ENABLE_MODELVOLUME_TRANSFORM
volume->center_geometry(); volume->center_geometry();
volume->translate(delta); volume->translate(delta);
#endif // ENABLE_MODELVOLUME_TRANSFORM
auto new_volume = model_object->add_volume(*volume); auto new_volume = model_object->add_volume(*volume);
new_volume->set_type(static_cast<ModelVolume::Type>(type)); new_volume->set_type(static_cast<ModelVolume::Type>(type));
new_volume->name = boost::filesystem::path(input_file).filename().string(); new_volume->name = boost::filesystem::path(input_file).filename().string();
part_names.Add(new_volume->name); part_names.Add(new_volume->name);
#if !ENABLE_MODELVOLUME_TRANSFORM
if (delta != Vec3d::Zero())
new_volume->translate(delta);
#endif // !ENABLE_MODELVOLUME_TRANSFORM
// set a default extruder value, since user can't add it manually // set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -903,10 +893,8 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int
auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh); auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh);
new_volume->set_type(static_cast<ModelVolume::Type>(type)); new_volume->set_type(static_cast<ModelVolume::Type>(type));
#if ENABLE_MODELVOLUME_TRANSFORM
new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2))); new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2)));
new_volume->center_geometry(); new_volume->center_geometry();
#endif // ENABLE_MODELVOLUME_TRANSFORM
new_volume->name = name; new_volume->name = name;
// set a default extruder value, since user can't add it manually // set a default extruder value, since user can't add it manually
@ -982,6 +970,10 @@ void ObjectList::del_instances_from_object(const int obj_idx)
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type) bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
{ {
if (obj_idx == 1000)
// Cannot delete a wipe tower.
return false;
if (type == itVolume) { if (type == itVolume) {
const auto volume = (*m_objects)[obj_idx]->volumes[idx]; const auto volume = (*m_objects)[obj_idx]->volumes[idx];
@ -1399,6 +1391,20 @@ void ObjectList::update_selections()
auto& selection = wxGetApp().plater()->canvas3D()->get_selection(); auto& selection = wxGetApp().plater()->canvas3D()->get_selection();
wxDataViewItemArray sels; wxDataViewItemArray sels;
// We doesn't update selection if SettingsItem for the current object/part is selected
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
{
const auto item = GetSelection();
if (selection.is_single_full_object() &&
m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
return;
if (selection.is_single_volume() || selection.is_modifier()) {
const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin());
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
return;
}
}
if (selection.is_single_full_object()) if (selection.is_single_full_object())
{ {
sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));

View File

@ -17,6 +17,12 @@ namespace GUI
ObjectManipulation::ObjectManipulation(wxWindow* parent) : ObjectManipulation::ObjectManipulation(wxWindow* parent) :
OG_Settings(parent, true) OG_Settings(parent, true)
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
, m_cache_position(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
, m_cache_rotation(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
, m_cache_scale(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
, m_cache_size(Vec3d(DBL_MAX, DBL_MAX, DBL_MAX))
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
{ {
m_og->set_name(_(L("Object Manipulation"))); m_og->set_name(_(L("Object Manipulation")));
m_og->label_width = 100; m_og->label_width = 100;
@ -25,18 +31,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) { m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) {
std::vector<std::string> axes{ "_x", "_y", "_z" }; std::vector<std::string> axes{ "_x", "_y", "_z" };
if (opt_key == "scale_unit") {
const wxString& selection = boost::any_cast<wxString>(value);
for (auto axis : axes) {
std::string key = "scale" + axis;
m_og->set_side_text(key, selection);
}
m_is_percent_scale = selection == _("%");
update_scale_values();
return;
}
std::string param; std::string param;
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
@ -50,30 +44,73 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
else if (param == "rotation") else if (param == "rotation")
change_rotation_value(new_value); change_rotation_value(new_value);
else if (param == "scale") else if (param == "scale")
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
{
change_scale_value(new_value); change_scale_value(new_value);
update_settings_value(wxGetApp().plater()->canvas3D()->get_selection());
}
#else
change_scale_value(new_value);
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
else if (param == "size")
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
{
change_size_value(new_value);
update_settings_value(wxGetApp().plater()->canvas3D()->get_selection());
}
#else
change_size_value(new_value);
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
}; };
m_og->m_fill_empty_value = [this](const std::string& opt_key) m_og->m_fill_empty_value = [this](const std::string& opt_key)
{ {
if (opt_key == "scale_unit") #if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
return; this->update_if_dirty();
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
std::string param; std::string param;
std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param));
double value = 0.0;
if (param == "position") { if (param == "position") {
int axis = opt_key.back() == 'x' ? 0 : int axis = opt_key.back() == 'x' ? 0 :
opt_key.back() == 'y' ? 1 : 2; opt_key.back() == 'y' ? 1 : 2;
m_og->set_value(opt_key, double_to_string(cache_position(axis))); value = m_cache_position(axis);
return; }
else if (param == "rotation") {
int axis = opt_key.back() == 'x' ? 0 :
opt_key.back() == 'y' ? 1 : 2;
value = m_cache_rotation(axis);
}
else if (param == "scale") {
int axis = opt_key.back() == 'x' ? 0 :
opt_key.back() == 'y' ? 1 : 2;
value = m_cache_scale(axis);
}
else if (param == "size") {
int axis = opt_key.back() == 'x' ? 0 :
opt_key.back() == 'y' ? 1 : 2;
value = m_cache_size(axis);
} }
m_og->set_value(opt_key, double_to_string(0.0)); m_og->set_value(opt_key, double_to_string(value));
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false);
}; };
m_og->m_set_focus = [this](const std::string& opt_key) m_og->m_set_focus = [this](const std::string& opt_key)
{ {
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key); #if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
this->update_if_dirty();
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true);
}; };
ConfigOptionDef def; ConfigOptionDef def;
@ -106,59 +143,37 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext)
{ {
Line line = { _(option_name), "" }; Line line = { _(option_name), "" };
if (option_name == "Scale") {
line.near_label_widget = [](wxWindow* parent) {
auto btn = new PrusaLockButton(parent, wxID_ANY);
btn->Bind(wxEVT_BUTTON, [btn](wxCommandEvent &event) {
event.Skip();
wxTheApp->CallAfter([btn]() {
wxGetApp().obj_manipul()->set_uniform_scaling(btn->IsLocked());
});
});
return btn;
};
}
ConfigOptionDef def; ConfigOptionDef def;
def.type = coFloat; def.type = coFloat;
def.default_value = new ConfigOptionFloat(0.0); def.default_value = new ConfigOptionFloat(0.0);
def.width = 50; def.width = 50;
if (option_name == "Rotation") if (option_name == "Rotation")
{
def.min = -360; def.min = -360;
def.max = 360;
}
const std::string lower_name = boost::algorithm::to_lower_copy(option_name); const std::string lower_name = boost::algorithm::to_lower_copy(option_name);
std::vector<std::string> axes{ "x", "y", "z" }; std::vector<std::string> axes{ "x", "y", "z" };
for (auto axis : axes) { for (auto axis : axes) {
if (axis == "z" && option_name != "Scale") if (axis == "z")
def.sidetext = sidetext; def.sidetext = sidetext;
Option option = Option(def, lower_name + "_" + axis); Option option = Option(def, lower_name + "_" + axis);
option.opt.full_width = true; option.opt.full_width = true;
line.append_option(option); line.append_option(option);
} }
if (option_name == "Scale")
{
def.width = 45;
def.type = coStrings;
def.gui_type = "select_open";
def.enum_labels.push_back(L("%"));
def.enum_labels.push_back(L("mm"));
def.default_value = new ConfigOptionStrings{ "mm" };
const Option option = Option(def, lower_name + "_unit");
line.append_option(option);
}
return line; return line;
}; };
// Settings table // Settings table
m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label); m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label);
m_og->append_line(add_og_to_object_settings(L("Rotation"), "°")); m_og->append_line(add_og_to_object_settings(L("Rotation"), "°"), &m_rotate_Label);
m_og->append_line(add_og_to_object_settings(L("Scale"), "mm")); m_og->append_line(add_og_to_object_settings(L("Scale"), "%"), &m_scale_Label);
m_og->append_line(add_og_to_object_settings(L("Size"), "mm"));
/* Unused parameter at this time /* Unused parameter at this time
def.label = L("Place on bed"); def.label = L("Place on bed");
@ -191,289 +206,269 @@ bool ObjectManipulation::IsShown()
void ObjectManipulation::UpdateAndShow(const bool show) void ObjectManipulation::UpdateAndShow(const bool show)
{ {
if (show) if (show) {
update_settings_value(wxGetApp().plater()->canvas3D()->get_selection()); update_settings_value(wxGetApp().plater()->canvas3D()->get_selection());
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
update_if_dirty();
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
}
OG_Settings::UpdateAndShow(show); OG_Settings::UpdateAndShow(show);
} }
int ObjectManipulation::ol_selection()
{
return wxGetApp().obj_list()->get_selected_obj_idx();
}
void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection)
{ {
wxString move_label = _(L("Position")); m_new_move_label_string = L("Position:");
#if ENABLE_MODELVOLUME_TRANSFORM m_new_rotate_label_string = L("Rotation:");
if (selection.is_single_full_instance() || selection.is_single_full_object()) m_new_scale_label_string = L("Scale factors:");
#else if (selection.is_single_full_instance())
if (selection.is_single_full_object())
{ {
auto obj_idx = selection.get_object_idx(); // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
if (obj_idx >=0 && !wxGetApp().model_objects()->empty() && (*wxGetApp().model_objects())[obj_idx]->instances.size() == 1) const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
{ m_new_position = volume->get_instance_offset();
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first m_new_rotation = volume->get_instance_rotation();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_scale = volume->get_instance_scaling_factor();
update_position_value(volume->get_offset()); int obj_idx = volume->object_idx();
update_rotation_value(volume->get_rotation()); if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size()))
update_scale_value(volume->get_scaling_factor()); m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size();
m_og->enable();
}
else else
reset_settings_value(); // this should never happen
m_new_size = Vec3d::Zero();
m_new_enabled = true;
} }
else if (selection.is_single_full_instance()) else if (selection.is_single_full_object())
#endif // ENABLE_MODELVOLUME_TRANSFORM
{ {
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first const BoundingBoxf3& box = selection.get_bounding_box();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = box.center();
#if ENABLE_MODELVOLUME_TRANSFORM m_new_rotation = Vec3d::Zero();
update_position_value(volume->get_instance_offset()); m_new_scale = Vec3d(1.0, 1.0, 1.0);
update_rotation_value(volume->get_instance_rotation()); m_new_size = box.size();
update_scale_value(volume->get_instance_scaling_factor()); m_new_rotate_label_string = L("Rotate:");
#else m_new_scale_label_string = L("Scale:");
update_position_value(volume->get_offset()); m_new_enabled = true;
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
}
else if (selection.is_wipe_tower())
{
// the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_MODELVOLUME_TRANSFORM
update_position_value(volume->get_volume_offset());
update_rotation_value(volume->get_volume_rotation());
update_scale_value(volume->get_volume_scaling_factor());
#else
update_position_value(volume->get_offset());
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
} }
else if (selection.is_single_modifier() || selection.is_single_volume()) else if (selection.is_single_modifier() || selection.is_single_volume())
{ {
// the selection contains a single volume // the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_MODELVOLUME_TRANSFORM m_new_position = volume->get_volume_offset();
update_position_value(volume->get_volume_offset()); m_new_rotation = volume->get_volume_rotation();
update_rotation_value(volume->get_volume_rotation()); m_new_scale = volume->get_volume_scaling_factor();
update_scale_value(volume->get_volume_scaling_factor()); m_new_size = volume->get_instance_transformation().get_matrix(true, true) * volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size();
#else m_new_enabled = true;
update_position_value(volume->get_offset());
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
} }
else if (wxGetApp().obj_list()->multiple_selection()) else if (wxGetApp().obj_list()->multiple_selection())
{ {
reset_settings_value(); reset_settings_value();
move_label = _(L("Displacement")); m_new_move_label_string = L("Translate:");
m_og->enable(); m_new_rotate_label_string = L("Rotate:");
m_new_scale_label_string = L("Scale:");
m_new_size = selection.get_bounding_box().size();
m_new_enabled = true;
} }
else else
reset_settings_value(); reset_settings_value();
m_move_Label->SetLabel(move_label); #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_og->get_field("scale_unit")->disable();// temporary decision update_if_dirty();
#else
m_dirty = true;
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
}
void ObjectManipulation::update_if_dirty()
{
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
if (_(m_new_move_label_string) != m_move_Label->GetLabel())
m_move_Label->SetLabel(_(m_new_move_label_string));
if (_(m_new_rotate_label_string) != m_rotate_Label->GetLabel())
m_rotate_Label->SetLabel(_(m_new_rotate_label_string));
if (_(m_new_scale_label_string) != m_scale_Label->GetLabel())
m_scale_Label->SetLabel(_(m_new_scale_label_string));
if (m_cache_position(0) != m_new_position(0))
m_og->set_value("position_x", double_to_string(m_new_position(0), 2));
if (m_cache_position(1) != m_new_position(1))
m_og->set_value("position_y", double_to_string(m_new_position(1), 2));
if (m_cache_position(2) != m_new_position(2))
m_og->set_value("position_z", double_to_string(m_new_position(2), 2));
m_cache_position = m_new_position;
auto scale = m_new_scale * 100.0;
if (m_cache_scale(0) != scale(0))
m_og->set_value("scale_x", double_to_string(scale(0), 2));
if (m_cache_scale(1) != scale(1))
m_og->set_value("scale_y", double_to_string(scale(1), 2));
if (m_cache_scale(2) != scale(2))
m_og->set_value("scale_z", double_to_string(scale(2), 2));
m_cache_scale = scale;
if (m_cache_size(0) != m_new_size(0))
m_og->set_value("size_x", double_to_string(m_new_size(0), 2));
if (m_cache_size(1) != m_new_size(1))
m_og->set_value("size_y", double_to_string(m_new_size(1), 2));
if (m_cache_size(2) != m_new_size(2))
m_og->set_value("size_z", double_to_string(m_new_size(2), 2));
m_cache_size = m_new_size;
if (m_cache_rotation(0) != m_new_rotation(0))
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2));
if (m_cache_rotation(1) != m_new_rotation(1))
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2));
if (m_cache_rotation(2) != m_new_rotation(2))
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2));
m_cache_rotation = m_new_rotation;
if (m_new_enabled)
m_og->enable();
else
m_og->disable();
#else
if (! m_dirty)
return;
m_move_Label->SetLabel(_(m_new_move_label_string));
m_rotate_Label->SetLabel(_(m_new_rotate_label_string));
m_scale_Label->SetLabel(_(m_new_scale_label_string));
m_og->set_value("position_x", double_to_string(m_new_position(0), 2));
m_og->set_value("position_y", double_to_string(m_new_position(1), 2));
m_og->set_value("position_z", double_to_string(m_new_position(2), 2));
m_cache_position = m_new_position;
auto scale = m_new_scale * 100.0;
m_og->set_value("scale_x", double_to_string(scale(0), 2));
m_og->set_value("scale_y", double_to_string(scale(1), 2));
m_og->set_value("scale_z", double_to_string(scale(2), 2));
m_cache_scale = scale;
m_og->set_value("size_x", double_to_string(m_new_size(0), 2));
m_og->set_value("size_y", double_to_string(m_new_size(1), 2));
m_og->set_value("size_z", double_to_string(m_new_size(2), 2));
m_cache_size = m_new_size;
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2));
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2));
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2));
m_cache_rotation = m_new_rotation;
if (m_new_enabled)
m_og->enable();
else
m_og->disable();
m_dirty = false;
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
} }
void ObjectManipulation::reset_settings_value() void ObjectManipulation::reset_settings_value()
{ {
reset_position_value(); m_new_position = Vec3d::Zero();
reset_rotation_value(); m_new_rotation = Vec3d::Zero();
reset_scale_value(); m_new_scale = Vec3d::Ones();
m_og->disable(); m_new_size = Vec3d::Zero();
m_new_enabled = false;
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_dirty = true;
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
} }
wxString def_0 {"0"};
wxString def_100 {"100"};
void ObjectManipulation::reset_position_value()
{
m_og->set_value("position_x", def_0);
m_og->set_value("position_y", def_0);
m_og->set_value("position_z", def_0);
cache_position = { 0., 0., 0. };
}
void ObjectManipulation::reset_rotation_value()
{
m_og->set_value("rotation_x", def_0);
m_og->set_value("rotation_y", def_0);
m_og->set_value("rotation_z", def_0);
}
void ObjectManipulation::reset_scale_value()
{
m_is_percent_scale = true;
m_og->set_value("scale_unit", _("%"));
m_og->set_value("scale_x", def_100);
m_og->set_value("scale_y", def_100);
m_og->set_value("scale_z", def_100);
}
void ObjectManipulation::update_values()
{
int selection = ol_selection();
if (selection < 0 || wxGetApp().mainframe->m_plater->model().objects.size() <= selection) {
m_og->set_value("position_x", def_0);
m_og->set_value("position_y", def_0);
m_og->set_value("position_z", def_0);
m_og->set_value("scale_x" , def_0);
m_og->set_value("scale_y" , def_0);
m_og->set_value("scale_z" , def_0);
m_og->set_value("rotation_x", def_0);
m_og->set_value("rotation_y", def_0);
m_og->set_value("rotation_z", def_0);
m_og->disable();
return;
}
m_is_percent_scale = boost::any_cast<wxString>(m_og->get_value("scale_unit")) == _("%");
update_position_values();
update_scale_values();
update_rotation_values();
m_og->enable();
}
void ObjectManipulation::update_scale_values()
{
int selection = ol_selection();
ModelObjectPtrs& objects = wxGetApp().mainframe->m_plater->model().objects;
auto instance = objects[selection]->instances.front();
auto size = objects[selection]->instance_bounding_box(0).size();
if (m_is_percent_scale) {
m_og->set_value("scale_x", double_to_string(instance->get_scaling_factor(X) * 100, 2));
m_og->set_value("scale_y", double_to_string(instance->get_scaling_factor(Y) * 100, 2));
m_og->set_value("scale_z", double_to_string(instance->get_scaling_factor(Z) * 100, 2));
}
else {
m_og->set_value("scale_x", double_to_string(size(0), 2));
m_og->set_value("scale_y", double_to_string(size(1), 2));
m_og->set_value("scale_z", double_to_string(size(2), 2));
}
}
void ObjectManipulation::update_position_values()
{
auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front();
m_og->set_value("position_x", double_to_string(instance->get_offset(X), 2));
m_og->set_value("position_y", double_to_string(instance->get_offset(Y), 2));
m_og->set_value("position_z", double_to_string(instance->get_offset(Z), 2));
}
void ObjectManipulation::update_position_value(const Vec3d& position)
{
m_og->set_value("position_x", double_to_string(position(0), 2));
m_og->set_value("position_y", double_to_string(position(1), 2));
m_og->set_value("position_z", double_to_string(position(2), 2));
cache_position = position;
}
void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor)
{
// this is temporary
// to be able to update the values as size
// we need to store somewhere the original size
// or have it passed as parameter
if (!m_is_percent_scale) {
m_is_percent_scale = true;
m_og->set_value("scale_unit", _("%"));
}
auto scale = scaling_factor * 100.0;
m_og->set_value("scale_x", double_to_string(scale(0), 2));
m_og->set_value("scale_y", double_to_string(scale(1), 2));
m_og->set_value("scale_z", double_to_string(scale(2), 2));
}
void ObjectManipulation::update_rotation_values()
{
update_rotation_value(wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front()->get_rotation());
}
void ObjectManipulation::update_rotation_value(double angle, Axis axis)
{
std::string axis_str;
switch (axis) {
case X: {
axis_str = "rotation_x";
break; }
case Y: {
axis_str = "rotation_y";
break; }
case Z: {
axis_str = "rotation_z";
break; }
}
m_og->set_value(axis_str, round_nearest(int(Geometry::rad2deg(angle)), 0));
}
void ObjectManipulation::update_rotation_value(const Vec3d& rotation)
{
m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(rotation(0)), 0), 2));
m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(rotation(1)), 0), 2));
m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(rotation(2)), 0), 2));
}
void ObjectManipulation::change_position_value(const Vec3d& position) void ObjectManipulation::change_position_value(const Vec3d& position)
{ {
Vec3d displacement(position - cache_position);
auto canvas = wxGetApp().plater()->canvas3D(); auto canvas = wxGetApp().plater()->canvas3D();
canvas->get_selection().start_dragging(); GLCanvas3D::Selection& selection = canvas->get_selection();
canvas->get_selection().translate(displacement); selection.start_dragging();
selection.translate(position - m_cache_position, selection.requires_local_axes());
canvas->do_move(); canvas->do_move();
cache_position = position; m_cache_position = position;
} }
void ObjectManipulation::change_rotation_value(const Vec3d& rotation) void ObjectManipulation::change_rotation_value(const Vec3d& rotation)
{ {
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
const GLCanvas3D::Selection& selection = canvas->get_selection();
Vec3d rad_rotation; Vec3d rad_rotation;
for (size_t i = 0; i < 3; ++i) for (size_t i = 0; i < 3; ++i)
{
rad_rotation(i) = Geometry::deg2rad(rotation(i)); rad_rotation(i) = Geometry::deg2rad(rotation(i));
auto canvas = wxGetApp().plater()->canvas3D(); }
canvas->get_selection().start_dragging(); canvas->get_selection().start_dragging();
canvas->get_selection().rotate(rad_rotation, false); canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance());
canvas->do_rotate(); canvas->do_rotate();
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_cache_rotation = rotation;
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
} }
void ObjectManipulation::change_scale_value(const Vec3d& scale) void ObjectManipulation::change_scale_value(const Vec3d& scale)
{ {
Vec3d scaling_factor; Vec3d scaling_factor = scale;
if (m_is_percent_scale) const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
scaling_factor = scale*0.01; if (selection.requires_uniform_scale())
else { {
int selection = ol_selection(); Vec3d abs_scale_diff = (scale - m_cache_scale).cwiseAbs();
ModelObjectPtrs& objects = *wxGetApp().model_objects(); double max_diff = abs_scale_diff(X);
Axis max_diff_axis = X;
auto size = objects[selection]->instance_bounding_box(0).size(); if (max_diff < abs_scale_diff(Y))
for (size_t i = 0; i < 3; ++i) {
scaling_factor(i) = scale(i) / size(i); max_diff = abs_scale_diff(Y);
max_diff_axis = Y;
}
if (max_diff < abs_scale_diff(Z))
{
max_diff = abs_scale_diff(Z);
max_diff_axis = Z;
}
scaling_factor = Vec3d(scale(max_diff_axis), scale(max_diff_axis), scale(max_diff_axis));
} }
scaling_factor *= 0.01;
auto canvas = wxGetApp().plater()->canvas3D(); auto canvas = wxGetApp().plater()->canvas3D();
canvas->get_selection().start_dragging(); canvas->get_selection().start_dragging();
canvas->get_selection().scale(scaling_factor, false); canvas->get_selection().scale(scaling_factor, false);
canvas->do_scale(); canvas->do_scale();
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_cache_scale = scale;
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
} }
void ObjectManipulation::print_cashe_value(const std::string& label, const Vec3d& v) void ObjectManipulation::change_size_value(const Vec3d& size)
{ {
std::cout << label << " => " << " X:" << v(0) << " Y:" << v(1) << " Z:" << v(2) << std::endl; const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
Vec3d ref_size = m_cache_size;
if (selection.is_single_full_instance())
{
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
ref_size = volume->bounding_box.size();
}
change_scale_value(100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
#if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
m_cache_size = size;
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
} }
} //namespace GUI } //namespace GUI

View File

@ -14,12 +14,35 @@ namespace GUI {
class ObjectManipulation : public OG_Settings class ObjectManipulation : public OG_Settings
{ {
bool m_is_percent_scale = false; // true -> percentage scale unit #if ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
// false -> uniform scale unit Vec3d m_cache_position;
bool m_is_uniform_scale = false; // It indicates if scale is uniform Vec3d m_cache_rotation;
Vec3d m_cache_scale;
Vec3d m_cache_size;
#else
Vec3d m_cache_position{ 0., 0., 0. };
Vec3d m_cache_rotation{ 0., 0., 0. };
Vec3d m_cache_scale{ 100., 100., 100. };
Vec3d m_cache_size{ 0., 0., 0. };
#endif // ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
Vec3d cache_position { 0., 0., 0. };
wxStaticText* m_move_Label = nullptr; wxStaticText* m_move_Label = nullptr;
wxStaticText* m_scale_Label = nullptr;
wxStaticText* m_rotate_Label = nullptr;
#if !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
// Needs to be updated from OnIdle?
bool m_dirty = false;
#endif // !ENABLE_IMPROVED_SIDEBAR_OBJECTS_MANIPULATION
// Cached labels for the delayed update, not localized!
std::string m_new_move_label_string;
std::string m_new_rotate_label_string;
std::string m_new_scale_label_string;
Vec3d m_new_position;
Vec3d m_new_rotation;
Vec3d m_new_scale;
Vec3d m_new_size;
bool m_new_enabled;
public: public:
ObjectManipulation(wxWindow* parent); ObjectManipulation(wxWindow* parent);
@ -29,38 +52,24 @@ public:
bool IsShown() override; bool IsShown() override;
void UpdateAndShow(const bool show) override; void UpdateAndShow(const bool show) override;
int ol_selection(); void update_settings_value(const GLCanvas3D::Selection& selection);
void update_settings_value(const GLCanvas3D::Selection& selection); // Called from the App to update the UI if dirty.
void update_if_dirty();
private:
void reset_settings_value(); void reset_settings_value();
void reset_position_value();
void reset_rotation_value();
void reset_scale_value();
void update_values(); // update size values after scale unit changing or "gizmos"
// update position values displacements or "gizmos" void update_size_value(const Vec3d& size);
void update_position_values();
void update_position_value(const Vec3d& position);
// update scale values after scale unit changing or "gizmos"
void update_scale_values();
void update_scale_value(const Vec3d& scaling_factor);
// update rotation values object selection changing
void update_rotation_values();
// update rotation value after "gizmos" // update rotation value after "gizmos"
void update_rotation_value(double angle, Axis axis);
void update_rotation_value(const Vec3d& rotation); void update_rotation_value(const Vec3d& rotation);
void set_uniform_scaling(const bool uniform_scale) { m_is_uniform_scale = uniform_scale; }
// change values // change values
void change_position_value(const Vec3d& position); void change_position_value(const Vec3d& position);
void change_rotation_value(const Vec3d& rotation); void change_rotation_value(const Vec3d& rotation);
void change_scale_value(const Vec3d& scale); void change_scale_value(const Vec3d& scale);
void change_size_value(const Vec3d& size);
private:
void print_cashe_value(const std::string& label, const Vec3d& value);
}; };
}} }}

View File

@ -27,7 +27,6 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_REMOVE_TABS_FROM_PLATER
View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
: m_canvas_widget(nullptr) : m_canvas_widget(nullptr)
, m_canvas(nullptr) , m_canvas(nullptr)
@ -70,7 +69,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba
m_canvas->set_config(config); m_canvas->set_config(config);
m_canvas->enable_gizmos(true); m_canvas->enable_gizmos(true);
m_canvas->enable_toolbar(true); m_canvas->enable_toolbar(true);
m_canvas->enable_shader(true);
m_canvas->enable_force_zoom_to_bed(true); m_canvas->enable_force_zoom_to_bed(true);
#if !ENABLE_IMGUI #if !ENABLE_IMGUI
@ -92,11 +90,7 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba
return true; return true;
} }
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void View3D::set_view_toolbar(GLToolbar* toolbar) void View3D::set_view_toolbar(GLToolbar* toolbar)
#else
void View3D::set_view_toolbar(GLRadioToolbar* toolbar)
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
{ {
if (m_canvas != nullptr) if (m_canvas != nullptr)
m_canvas->set_view_toolbar(toolbar); m_canvas->set_view_toolbar(toolbar);
@ -189,13 +183,8 @@ void View3D::render()
if (m_canvas != nullptr) if (m_canvas != nullptr)
m_canvas->render(); m_canvas->render();
} }
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_REMOVE_TABS_FROM_PLATER
Preview::Preview(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func) Preview::Preview(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
#else
Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
: m_canvas_widget(nullptr) : m_canvas_widget(nullptr)
, m_canvas(nullptr) , m_canvas(nullptr)
, m_double_slider_sizer(nullptr) , m_double_slider_sizer(nullptr)
@ -214,51 +203,27 @@ Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSli
, m_preferred_color_mode("feature") , m_preferred_color_mode("feature")
, m_loaded(false) , m_loaded(false)
, m_enabled(false) , m_enabled(false)
, m_force_sliders_full_range(false)
, m_schedule_background_process(schedule_background_process_func) , m_schedule_background_process(schedule_background_process_func)
{ {
#if ENABLE_REMOVE_TABS_FROM_PLATER
if (init(parent, config, process, gcode_preview_data)) if (init(parent, config, process, gcode_preview_data))
{ {
show_hide_ui_elements("none"); show_hide_ui_elements("none");
load_print(); load_print();
} }
#else
if (init(notebook, config, process, gcode_preview_data))
{
notebook->AddPage(this, _(L("Preview")));
show_hide_ui_elements("none");
load_print();
}
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
} }
#if ENABLE_REMOVE_TABS_FROM_PLATER
bool Preview::init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data) bool Preview::init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data)
#else
bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data)
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
{ {
#if ENABLE_REMOVE_TABS_FROM_PLATER
if ((config == nullptr) || (process == nullptr) || (gcode_preview_data == nullptr)) if ((config == nullptr) || (process == nullptr) || (gcode_preview_data == nullptr))
return false; return false;
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)) if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize))
return false; return false;
#else
if ((notebook == nullptr) || (config == nullptr) || (process == nullptr) || (gcode_preview_data == nullptr))
return false;
// creates this panel add append it to the given notebook as a new page
if (!Create(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize))
return false;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this); m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this);
_3DScene::add_canvas(m_canvas_widget); _3DScene::add_canvas(m_canvas_widget);
m_canvas = _3DScene::get_canvas(this->m_canvas_widget); m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
m_canvas->enable_shader(true);
m_canvas->set_config(m_config); m_canvas->set_config(m_config);
m_canvas->set_process(process); m_canvas->set_process(process);
m_canvas->enable_legend_texture(true); m_canvas->enable_legend_texture(true);
@ -368,43 +333,27 @@ Preview::~Preview()
} }
} }
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void Preview::set_view_toolbar(GLToolbar* toolbar) void Preview::set_view_toolbar(GLToolbar* toolbar)
#else
void Preview::set_view_toolbar(GLRadioToolbar* toolbar)
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
{ {
if (m_canvas != nullptr) if (m_canvas != nullptr)
m_canvas->set_view_toolbar(toolbar); m_canvas->set_view_toolbar(toolbar);
} }
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
void Preview::set_number_extruders(unsigned int number_extruders) void Preview::set_number_extruders(unsigned int number_extruders)
{ {
if (m_number_extruders != number_extruders) if (m_number_extruders != number_extruders)
{ {
m_number_extruders = number_extruders; m_number_extruders = number_extruders;
int type = 0; // color by a feature type int tool_idx = m_choice_view_type->FindString(_(L("Tool")));
if (number_extruders > 1) int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type
{ m_choice_view_type->SetSelection(type);
int tool_idx = m_choice_view_type->FindString(_(L("Tool"))); if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
int type = (number_extruders > 1) ? tool_idx /* color by a tool number */ : 0; // color by a feature type m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
m_choice_view_type->SetSelection(type);
if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
m_gcode_preview_data->extrusion.view_type = (GCodePreviewData::Extrusion::EViewType)type;
m_preferred_color_mode = (type == tool_idx) ? "tool_or_feature" : "feature"; m_preferred_color_mode = (type == tool_idx) ? "tool_or_feature" : "feature";
}
} }
} }
void Preview::reset_gcode_preview_data()
{
m_gcode_preview_data->reset();
m_canvas->reset_legend_texture();
}
void Preview::set_canvas_as_dirty() void Preview::set_canvas_as_dirty()
{ {
m_canvas->set_as_dirty(); m_canvas->set_as_dirty();
@ -455,6 +404,7 @@ void Preview::load_print()
void Preview::reload_print(bool force) void Preview::reload_print(bool force)
{ {
m_canvas->reset_volumes(); m_canvas->reset_volumes();
m_canvas->reset_legend_texture();
m_loaded = false; m_loaded = false;
if (!IsShown() && !force) if (!IsShown() && !force)
@ -523,14 +473,14 @@ void Preview::show_hide_ui_elements(const std::string& what)
void Preview::reset_sliders() void Preview::reset_sliders()
{ {
m_enabled = false; m_enabled = false;
reset_double_slider(); // reset_double_slider();
m_double_slider_sizer->Hide((size_t)0); m_double_slider_sizer->Hide((size_t)0);
} }
void Preview::update_sliders(const std::vector<double>& layers_z) void Preview::update_sliders(const std::vector<double>& layers_z)
{ {
m_enabled = true; m_enabled = true;
update_double_slider(layers_z, m_force_sliders_full_range); update_double_slider(layers_z);
m_double_slider_sizer->Show((size_t)0); m_double_slider_sizer->Show((size_t)0);
Layout(); Layout();
} }
@ -596,7 +546,8 @@ void Preview::create_double_slider()
auto& config = wxGetApp().preset_bundle->project_config; auto& config = wxGetApp().preset_bundle->project_config;
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues()); ((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
m_schedule_background_process(); m_schedule_background_process();
int type = m_choice_view_type->FindString(_(L("Color Print"))); bool color_print = !config.option<ConfigOptionFloats>("colorprint_heights")->values.empty();
int type = m_choice_view_type->FindString(color_print ? _(L("Color Print")) : _(L("Feature type")) );
if (m_choice_view_type->GetSelection() != type) { if (m_choice_view_type->GetSelection() != type) {
m_choice_view_type->SetSelection(type); m_choice_view_type->SetSelection(type);
if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types))
@ -606,26 +557,70 @@ void Preview::create_double_slider()
}); });
} }
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
// Returns -1 if there is no such member.
static int find_close_layer_idx(const std::vector<double>& zs, double &z, double eps)
{
if (zs.empty())
return -1;
auto it_h = std::lower_bound(zs.begin(), zs.end(), z);
if (it_h == zs.end()) {
auto it_l = it_h;
-- it_l;
if (z - *it_l < eps)
return int(zs.size() - 1);
} else if (it_h == zs.begin()) {
if (*it_h - z < eps)
return 0;
} else {
auto it_l = it_h;
-- it_l;
double dist_l = z - *it_l;
double dist_h = *it_h - z;
if (std::min(dist_l, dist_h) < eps) {
return (dist_l < dist_h) ? int(it_l - zs.begin()) : int(it_h - zs.begin());
}
}
return -1;
}
void Preview::update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range) void Preview::update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range)
{ {
// Save the initial slider span.
double z_low = m_slider->GetLowerValueD();
double z_high = m_slider->GetHigherValueD();
bool was_empty = m_slider->GetMaxValue() == 0;
bool span_changed = layers_z.empty() || std::abs(layers_z.back() - m_slider->GetMaxValueD()) > 1e-6;
force_sliders_full_range |= was_empty | span_changed;
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
std::vector<std::pair<int, double>> values; std::vector<std::pair<int, double>> values;
fill_slider_values(values, layers_z); fill_slider_values(values, layers_z);
m_slider->SetMaxValue(layers_z.size() - 1);
if (force_sliders_full_range)
m_slider->SetHigherValue(layers_z.size() - 1);
m_slider->SetSliderValues(values); m_slider->SetSliderValues(values);
const double z_low = m_slider->GetLowerValueD(); assert(m_slider->GetMinValue() == 0);
const double z_high = m_slider->GetHigherValueD(); m_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1);
int idx_low = 0;
int idx_high = m_slider->GetMaxValue();
if (! layers_z.empty()) {
if (! snap_to_min) {
int idx_new = find_close_layer_idx(layers_z, z_low, 1e-6);
if (idx_new != -1)
idx_low = idx_new;
}
if (! snap_to_max) {
int idx_new = find_close_layer_idx(layers_z, z_high, 1e-6);
if (idx_new != -1)
idx_high = idx_new;
}
}
m_slider->SetSelectionSpan(idx_low, idx_high);
const auto& config = wxGetApp().preset_bundle->project_config; const auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values; const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
m_slider->SetTicksValues(ticks_from_config); m_slider->SetTicksValues(ticks_from_config);
set_double_slider_thumbs(layers_z, z_low, z_high);
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
if (color_print_enable) { if (color_print_enable) {
const auto& config = wxGetApp().preset_bundle->full_config(); const auto& config = wxGetApp().preset_bundle->full_config();
@ -647,8 +642,7 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
// All ticks that would end up outside the slider range should be erased. // All ticks that would end up outside the slider range should be erased.
// TODO: this should be placed into more appropriate part of code, // TODO: this should be placed into more appropriate part of code,
// this function is e.g. not called when the last object is deleted // this function is e.g. not called when the last object is deleted
auto& config = wxGetApp().preset_bundle->project_config; std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
unsigned int old_size = ticks_from_config.size(); unsigned int old_size = ticks_from_config.size();
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(), ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
[values](double val) { return values.back().second < val; }), [values](double val) { return values.back().second < val; }),
@ -657,32 +651,6 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
m_schedule_background_process(); m_schedule_background_process();
} }
void Preview::set_double_slider_thumbs(const std::vector<double> &layers_z,
const double z_low,
const double z_high)
{
// Force slider full range only when slider is created.
// Support selected diapason on the all next steps
if (z_high == 0.0) {
m_slider->SetLowerValue(0);
m_slider->SetHigherValue(layers_z.size() - 1);
return;
}
for (int i = layers_z.size() - 1; i >= 0; i--)
// if (z_low >= layers_z[i]) {
if (fabs(z_low - layers_z[i]) <= 1e-6) {
m_slider->SetLowerValue(i);
break;
}
for (int i = layers_z.size() - 1; i >= 0; i--)
// if (z_high >= layers_z[i]) {
if (fabs(z_high-layers_z[i]) <= 1e-6) {
m_slider->SetHigherValue(i);
break;
}
}
void Preview::reset_double_slider() void Preview::reset_double_slider()
{ {
m_slider->SetHigherValue(0); m_slider->SetHigherValue(0);
@ -701,7 +669,7 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event)
if (key == 'U' || key == 'D') { if (key == 'U' || key == 'D') {
const int new_pos = key == 'U' ? m_slider->GetHigherValue() + 1 : m_slider->GetHigherValue() - 1; const int new_pos = key == 'U' ? m_slider->GetHigherValue() + 1 : m_slider->GetHigherValue() - 1;
m_slider->SetHigherValue(new_pos); m_slider->SetHigherValue(new_pos);
if (event.ShiftDown()) m_slider->SetLowerValue(m_slider->GetHigherValue()); if (event.ShiftDown() || m_slider->is_one_layer()) m_slider->SetLowerValue(m_slider->GetHigherValue());
} }
else if (key == 'S') else if (key == 'S')
m_slider->ChangeOneLayerLock(); m_slider->ChangeOneLayerLock();
@ -763,7 +731,8 @@ void Preview::load_print_as_fff()
// Collect colors per extruder. // Collect colors per extruder.
std::vector<std::string> colors; std::vector<std::string> colors;
if (!m_gcode_preview_data->empty() || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool)) bool gcode_preview_data_valid = print->is_step_done(psGCodeExport) && ! m_gcode_preview_data->empty();
if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool))
{ {
const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(m_config->option("extruder_colour")); const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(m_config->option("extruder_colour"));
const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(m_config->option("filament_colour")); const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(m_config->option("filament_colour"));
@ -786,18 +755,8 @@ void Preview::load_print_as_fff()
if (IsShown()) if (IsShown())
{ {
// used to set the sliders to the extremes of the current zs range if (gcode_preview_data_valid)
m_force_sliders_full_range = false;
if (m_gcode_preview_data->empty())
{ {
// load skirt and brim
m_canvas->load_preview(colors);
show_hide_ui_elements("simple");
}
else
{
m_force_sliders_full_range = (m_canvas->get_volumes_count() == 0);
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors); m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
show_hide_ui_elements("full"); show_hide_ui_elements("full");
@ -809,8 +768,15 @@ void Preview::load_print_as_fff()
reset_sliders(); reset_sliders();
m_canvas_widget->Refresh(); m_canvas_widget->Refresh();
} }
}
else
{
// load skirt and brim
m_canvas->load_preview(colors);
show_hide_ui_elements("simple");
} }
if (n_layers > 0) if (n_layers > 0)
update_sliders(m_canvas->get_current_print_zs(true)); update_sliders(m_canvas->get_current_print_zs(true));
@ -856,7 +822,6 @@ void Preview::load_print_as_sla()
{ {
std::vector<double> layer_zs; std::vector<double> layer_zs;
std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs)); std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs));
m_force_sliders_full_range = true;
update_sliders(layer_zs); update_sliders(layer_zs);
} }

View File

@ -21,24 +21,13 @@ class DynamicPrintConfig;
class Print; class Print;
class BackgroundSlicingProcess; class BackgroundSlicingProcess;
class GCodePreviewData; class GCodePreviewData;
#if ENABLE_REMOVE_TABS_FROM_PLATER
class Model; class Model;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
namespace GUI { namespace GUI {
class GLCanvas3D; class GLCanvas3D;
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#if ENABLE_REMOVE_TABS_FROM_PLATER
class GLToolbar; class GLToolbar;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#else
#if ENABLE_REMOVE_TABS_FROM_PLATER
class GLRadioToolbar;
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#if ENABLE_REMOVE_TABS_FROM_PLATER
class View3D : public wxPanel class View3D : public wxPanel
{ {
wxGLCanvas* m_canvas_widget; wxGLCanvas* m_canvas_widget;
@ -59,11 +48,7 @@ public:
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
GLCanvas3D* get_canvas3d() { return m_canvas; } GLCanvas3D* get_canvas3d() { return m_canvas; }
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_view_toolbar(GLToolbar* toolbar); void set_view_toolbar(GLToolbar* toolbar);
#else
void set_view_toolbar(GLRadioToolbar* toolbar);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_as_dirty(); void set_as_dirty();
void set_bed_shape(const Pointfs& shape); void set_bed_shape(const Pointfs& shape);
@ -89,7 +74,6 @@ public:
private: private:
bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process);
}; };
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
class Preview : public wxPanel class Preview : public wxPanel
{ {
@ -117,30 +101,18 @@ class Preview : public wxPanel
bool m_loaded; bool m_loaded;
bool m_enabled; bool m_enabled;
bool m_force_sliders_full_range;
PrusaDoubleSlider* m_slider {nullptr}; PrusaDoubleSlider* m_slider {nullptr};
public: public:
#if ENABLE_REMOVE_TABS_FROM_PLATER
Preview(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){}); Preview(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
#else
Preview(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
virtual ~Preview(); virtual ~Preview();
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
#if ENABLE_REMOVE_TABS_FROM_PLATER
#if ENABLE_TOOLBAR_BACKGROUND_TEXTURE
void set_view_toolbar(GLToolbar* toolbar); void set_view_toolbar(GLToolbar* toolbar);
#else
void set_view_toolbar(GLRadioToolbar* toolbar);
#endif // ENABLE_TOOLBAR_BACKGROUND_TEXTURE
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
void set_number_extruders(unsigned int number_extruders); void set_number_extruders(unsigned int number_extruders);
void reset_gcode_preview_data();
void set_canvas_as_dirty(); void set_canvas_as_dirty();
void set_enabled(bool enabled); void set_enabled(bool enabled);
void set_bed_shape(const Pointfs& shape); void set_bed_shape(const Pointfs& shape);
@ -154,11 +126,7 @@ public:
void refresh_print(); void refresh_print();
private: private:
#if ENABLE_REMOVE_TABS_FROM_PLATER
bool init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data); bool init(wxWindow* parent, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data);
#else
bool init(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data);
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
void bind_event_handlers(); void bind_event_handlers();
void unbind_event_handlers(); void unbind_event_handlers();
@ -178,12 +146,9 @@ private:
// Create/Update/Reset double slider on 3dPreview // Create/Update/Reset double slider on 3dPreview
void create_double_slider(); void create_double_slider();
void update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range); void update_double_slider(const std::vector<double>& layers_z, bool force_sliders_full_range = false);
void fill_slider_values(std::vector<std::pair<int, double>> &values, void fill_slider_values(std::vector<std::pair<int, double>> &values,
const std::vector<double> &layers_z); const std::vector<double> &layers_z);
void set_double_slider_thumbs( const std::vector<double> &layers_z,
const double z_low,
const double z_high);
void reset_double_slider(); void reset_double_slider();
// update DoubleSlider after keyDown in canvas // update DoubleSlider after keyDown in canvas
void update_double_slider_from_canvas(wxKeyEvent& event); void update_double_slider_from_canvas(wxKeyEvent& event);

View File

@ -0,0 +1,167 @@
#include "KBShortcutsDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include <wx/scrolwin.h>
#include "GUI_App.hpp"
namespace Slic3r {
namespace GUI {
KBShortcutsDialog::KBShortcutsDialog()
: wxDialog(NULL, wxID_ANY, _(L("Slic3r Prusa Edition - Keyboard Shortcuts")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
auto main_sizer = new wxBoxSizer(wxVERTICAL);
// logo
wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_32px.png")), wxBITMAP_TYPE_PNG);
// fonts
wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
#ifdef __WXOSX__
head_font.SetPointSize(14);
#else
head_font.SetPointSize(12);
#endif // __WXOSX__
const wxFont& font = wxGetApp().small_font();
const wxFont& bold_font = wxGetApp().bold_font();
fill_shortcuts();
auto panel = new wxPanel(this);
auto main_grid_sizer = new wxFlexGridSizer(2, 10, 10);
panel->SetSizer(main_grid_sizer);
main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0);
wxBoxSizer* l_sizer = new wxBoxSizer(wxVERTICAL);
main_grid_sizer->Add(l_sizer, 0);
wxBoxSizer* r_sizer = new wxBoxSizer(wxVERTICAL);
main_grid_sizer->Add(r_sizer, 0);
for (auto& sc : m_full_shortcuts)
{
auto sizer = sc.first == _(L("Main Shortcuts")) ? l_sizer : r_sizer;
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(hsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
// logo
auto *logo = new wxStaticBitmap(panel, wxID_ANY, logo_bmp);
hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15);
// head
wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(200,-1));
head->SetFont(head_font);
hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL);
// Shortcuts list
auto grid_sizer = new wxFlexGridSizer(2, 5, 15);
sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT| wxRIGHT, 15);
for (auto pair : sc.second)
{
auto shortcut = new wxStaticText(panel, wxID_ANY, _(pair.first));
shortcut->SetFont(bold_font);
grid_sizer->Add(shortcut, -1, wxALIGN_CENTRE_VERTICAL);
auto description = new wxStaticText(panel, wxID_ANY, _(pair.second));
description->SetFont(font);
grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL);
}
}
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
this->SetEscapeId(wxID_OK);
this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK);
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15);
this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this);
SetSizer(main_sizer);
main_sizer->SetSizeHints(this);
}
void KBShortcutsDialog::fill_shortcuts()
{
#ifdef __WXOSX__
const std::string ctrl = "";
const std::string alt = "";
#else
const std::string ctrl = "Ctrl+";
const std::string alt = "Alt+";
#endif // __WXOSX__
Shortcuts main_shortcuts;
main_shortcuts.reserve(25);
main_shortcuts.push_back(Shortcut(ctrl+"O" ,L("Open project STL/OBJ/AMF/3MF with config, delete bed")));
main_shortcuts.push_back(Shortcut(ctrl+"I" ,L("Import STL/OBJ/AMF/3MF without config, keep bed")));
main_shortcuts.push_back(Shortcut(ctrl+"L" ,L("Load Config from .ini/amf/3mf/gcode")));
main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export Gcode")));
main_shortcuts.push_back(Shortcut(ctrl+"S" ,L("Save project (3MF)")));
main_shortcuts.push_back(Shortcut(ctrl+alt+"L" ,L("Load Config from .ini/amf/3mf/gcode and merge")));
main_shortcuts.push_back(Shortcut(ctrl+"R" ,L("(Re)slice")));
main_shortcuts.push_back(Shortcut(ctrl+"U" ,L("Quick slice")));
main_shortcuts.push_back(Shortcut(ctrl+"Shift+U" ,L("Repeat last quick slice")));
main_shortcuts.push_back(Shortcut(ctrl+"1" ,L("Select Plater Tab")));
main_shortcuts.push_back(Shortcut(ctrl+alt+"U" ,L("Quick slice and Save as")));
main_shortcuts.push_back(Shortcut(ctrl+"2" ,L("Select Print Settings Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Setting Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Setting Tab")));
main_shortcuts.push_back(Shortcut(ctrl+"5" ,L("Switch to 3D")));
main_shortcuts.push_back(Shortcut(ctrl+"6" ,L("Switch to Preview")));
main_shortcuts.push_back(Shortcut(ctrl+"P" ,L("Preferences")));
main_shortcuts.push_back(Shortcut("0-6" ,L("Camera view ")));
main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object ")));
main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object")));
main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list")));
main_shortcuts.push_back(Shortcut("PgUp/PgDn" ,L("Switch between 3D and Preview")));
main_shortcuts.push_back(Shortcut("Shift+LeftMouse" ,L("Select multiple object/Move multiple object")));
m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts);
Shortcuts plater_shortcuts;
plater_shortcuts.reserve(20);
plater_shortcuts.push_back(Shortcut("A", L("Arrange")));
plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects")));
plater_shortcuts.push_back(Shortcut("Del", L("Delete selected")));
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete all")));
plater_shortcuts.push_back(Shortcut("M", L("Gizmo move")));
plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale")));
plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate")));
plater_shortcuts.push_back(Shortcut("C", L("Gizmo cut")));
plater_shortcuts.push_back(Shortcut("F", L("Gizmo Place face on bed")));
plater_shortcuts.push_back(Shortcut("L", L("Gizmo SLA support points")));
plater_shortcuts.push_back(Shortcut("B", L("Zoom to Bed")));
plater_shortcuts.push_back(Shortcut("Z", L("Zoom to all objects in scene, if none selected")));
plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object")));
plater_shortcuts.push_back(Shortcut("I", L("Zoom in")));
plater_shortcuts.push_back(Shortcut("O", L("Zoom out")));
plater_shortcuts.push_back(Shortcut("ESC", L("Unselect gizmo, keep object selection")));
m_full_shortcuts.emplace(_(L("Plater Shortcuts")), plater_shortcuts);
Shortcuts preview_shortcuts;
preview_shortcuts.reserve(2);
preview_shortcuts.push_back(Shortcut(L("Arrow Up"), L("Upper Layer")));
preview_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Lower Layer")));
m_full_shortcuts.emplace(_(L("Preview Shortcuts")), preview_shortcuts);
}
void KBShortcutsDialog::onCloseDialog(wxEvent &)
{
this->EndModal(wxID_CLOSE);
this->Close();
}
} // namespace GUI
} // namespace Slic3r

View File

@ -0,0 +1,32 @@
#ifndef slic3r_GUI_KBShortcutsDialog_hpp_
#define slic3r_GUI_KBShortcutsDialog_hpp_
#include <wx/wx.h>
#include <map>
namespace Slic3r {
namespace GUI {
class KBShortcutsDialog : public wxDialog
{
typedef std::pair<std::string, std::string> Shortcut;
typedef std::vector< Shortcut > Shortcuts;
typedef std::map<wxString, Shortcuts> ShortcutsMap;
wxString text_info {wxEmptyString};
ShortcutsMap m_full_shortcuts;
public:
KBShortcutsDialog();
void fill_shortcuts();
private:
void onCloseDialog(wxEvent &);
};
} // namespace GUI
} // namespace Slic3r
#endif

View File

@ -18,6 +18,7 @@
#include "ProgressStatusBar.hpp" #include "ProgressStatusBar.hpp"
#include "3DScene.hpp" #include "3DScene.hpp"
#include "AppConfig.hpp" #include "AppConfig.hpp"
#include "PrintHostDialogs.hpp"
#include "wxExtensions.hpp" #include "wxExtensions.hpp"
#include "I18N.hpp" #include "I18N.hpp"
@ -27,10 +28,9 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
MainFrame::MainFrame(const bool no_plater, const bool loaded) : MainFrame::MainFrame() :
wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE), wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE),
m_no_plater(no_plater), m_printhost_queue_dlg(new PrintHostQueueDialog(this))
m_loaded(loaded)
{ {
// Load the icon either from the exe, or from the ico file. // Load the icon either from the exe, or from the ico file.
#if _WIN32 #if _WIN32
@ -123,11 +123,9 @@ void MainFrame::init_tabpanel()
} }
}); });
if (!m_no_plater) { m_plater = new Slic3r::GUI::Plater(m_tabpanel, this);
m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); wxGetApp().plater_ = m_plater;
wxGetApp().plater_ = m_plater; m_tabpanel->AddPage(m_plater, _(L("Plater")));
m_tabpanel->AddPage(m_plater, _(L("Plater")));
}
// The following event is emited by Tab implementation on config value change. // The following event is emited by Tab implementation on config value change.
Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this); Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this);
@ -226,7 +224,7 @@ void MainFrame::init_menubar()
wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("Open…\tCtrl+O")), _(L("Open a project file")), wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("Open…\tCtrl+O")), _(L("Open a project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "brick_add.png"); [this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "brick_add.png");
wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("Save\tCtrl+S")), _(L("Save current project file")), wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("Save\tCtrl+S")), _(L("Save current project file")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(m_plater->get_project_filename().wx_str()); }, "disk.png"); [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "disk.png");
wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save as…\tCtrl+Alt+S")), _(L("Save current project file as")), wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save as…\tCtrl+Alt+S")), _(L("Save current project file as")),
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "disk.png"); [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "disk.png");
@ -325,43 +323,46 @@ void MainFrame::init_menubar()
{ {
size_t tab_offset = 0; size_t tab_offset = 0;
if (m_plater) { if (m_plater) {
#if ENABLE_REMOVE_TABS_FROM_PLATER append_menu_item(windowMenu, wxID_HIGHEST + 1, L("Plater Tab\tCtrl+1"), L("Show the plater"),
append_menu_item(windowMenu, wxID_ANY, L("Plater Tab\tCtrl+1"), L("Show the plater"),
[this](wxCommandEvent&) { select_tab(0); }, "application_view_tile.png"); [this](wxCommandEvent&) { select_tab(0); }, "application_view_tile.png");
#else
append_menu_item(windowMenu, wxID_ANY, L("Select Plater Tab\tCtrl+1"), L("Show the plater"),
[this](wxCommandEvent&) { select_tab(0); }, "application_view_tile.png");
#endif // ENABLE_REMOVE_TABS_FROM_PLATER
tab_offset += 1; tab_offset += 1;
} }
if (tab_offset > 0) { if (tab_offset > 0) {
windowMenu->AppendSeparator(); windowMenu->AppendSeparator();
} }
#if ENABLE_REMOVE_TABS_FROM_PLATER append_menu_item(windowMenu, wxID_HIGHEST + 2, L("Print Settings Tab\tCtrl+2"), L("Show the print settings"),
append_menu_item(windowMenu, wxID_ANY, L("Print Settings Tab\tCtrl+2"), L("Show the print settings"),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog.png"); [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog.png");
append_menu_item(windowMenu, wxID_ANY, L("Filament Settings Tab\tCtrl+3"), L("Show the filament settings"), append_menu_item(windowMenu, wxID_HIGHEST + 3, L("Filament Settings Tab\tCtrl+3"), L("Show the filament settings"),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png"); [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png");
append_menu_item(windowMenu, wxID_ANY, L("Printer Settings Tab\tCtrl+4"), L("Show the printer settings"), append_menu_item(windowMenu, wxID_HIGHEST + 4, L("Printer Settings Tab\tCtrl+4"), L("Show the printer settings"),
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png"); [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png");
if (m_plater) { if (m_plater) {
windowMenu->AppendSeparator(); windowMenu->AppendSeparator();
wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_ANY, L("3D\tCtrl+5"), L("Show the 3D editing view"), wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_HIGHEST + 5, L("3D\tCtrl+5"), L("Show the 3D editing view"),
[this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, ""); [this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "");
wxMenuItem* item_preview = append_menu_item(windowMenu, wxID_ANY, L("Preview\tCtrl+6"), L("Show the 3D slices preview"), wxMenuItem* item_preview = append_menu_item(windowMenu, wxID_HIGHEST + 6, L("Preview\tCtrl+6"), L("Show the 3D slices preview"),
[this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, ""); [this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "");
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_3d->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_3d->GetId());
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_preview->GetId()); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_change_view()); }, item_preview->GetId());
} }
#else
append_menu_item(windowMenu, wxID_ANY, L("Select Print Settings Tab\tCtrl+2"), L("Show the print settings"), #if _WIN32
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog.png"); // This is needed on Windows to fake the CTRL+# of the window menu when using the numpad
append_menu_item(windowMenu, wxID_ANY, L("Select Filament Settings Tab\tCtrl+3"), L("Show the filament settings"), wxAcceleratorEntry entries[6];
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png"); entries[0].Set(wxACCEL_CTRL, WXK_NUMPAD1, wxID_HIGHEST + 1);
append_menu_item(windowMenu, wxID_ANY, L("Select Printer Settings Tab\tCtrl+4"), L("Show the printer settings"), entries[1].Set(wxACCEL_CTRL, WXK_NUMPAD2, wxID_HIGHEST + 2);
[this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png"); entries[2].Set(wxACCEL_CTRL, WXK_NUMPAD3, wxID_HIGHEST + 3);
#endif // ENABLE_REMOVE_TABS_FROM_PLATER entries[3].Set(wxACCEL_CTRL, WXK_NUMPAD4, wxID_HIGHEST + 4);
entries[4].Set(wxACCEL_CTRL, WXK_NUMPAD5, wxID_HIGHEST + 5);
entries[5].Set(wxACCEL_CTRL, WXK_NUMPAD6, wxID_HIGHEST + 6);
wxAcceleratorTable accel(6, entries);
SetAcceleratorTable(accel);
#endif // _WIN32
windowMenu->AppendSeparator();
append_menu_item(windowMenu, wxID_ANY, L("Print Host Upload Queue"), L("Display the Print Host Upload Queue window"),
[this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "arrow_up.png");
} }
// View menu // View menu
@ -415,6 +416,9 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/supermerill/issues/new"); }); [this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/supermerill/issues/new"); });
append_menu_item(helpMenu, wxID_ANY, _(L("About Slic3r")), _(L("Show about dialog")), append_menu_item(helpMenu, wxID_ANY, _(L("About Slic3r")), _(L("Show about dialog")),
[this](wxCommandEvent&) { Slic3r::GUI::about(); }); [this](wxCommandEvent&) { Slic3r::GUI::about(); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + "\t?", _(L("Show the list of the keyboard shortcuts")),
[this](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); });
} }
// menubar // menubar
@ -795,7 +799,7 @@ void MainFrame::on_value_changed(wxCommandEvent& event)
void MainFrame::update_ui_from_settings() void MainFrame::update_ui_from_settings()
{ {
bool bp_on = wxGetApp().app_config->get("background_processing") == "1"; bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
m_menu_item_reslice_now->Enable(bp_on); m_menu_item_reslice_now->Enable(!bp_on);
m_plater->sidebar().show_reslice(!bp_on); m_plater->sidebar().show_reslice(!bp_on);
m_plater->sidebar().Layout(); m_plater->sidebar().Layout();
if (m_plater) if (m_plater)

View File

@ -21,7 +21,9 @@ class ProgressStatusBar;
namespace GUI namespace GUI
{ {
class Tab; class Tab;
class PrintHostQueueDialog;
enum QuickSlice enum QuickSlice
{ {
@ -40,10 +42,7 @@ struct PresetTab {
class MainFrame : public wxFrame class MainFrame : public wxFrame
{ {
bool m_no_plater; bool m_loaded {false};
bool m_loaded;
int m_lang_ch_event;
int m_preferences_event;
wxString m_qs_last_input_file = wxEmptyString; wxString m_qs_last_input_file = wxEmptyString;
wxString m_qs_last_output_file = wxEmptyString; wxString m_qs_last_output_file = wxEmptyString;
@ -52,6 +51,8 @@ class MainFrame : public wxFrame
wxMenuItem* m_menu_item_repeat { nullptr }; wxMenuItem* m_menu_item_repeat { nullptr };
wxMenuItem* m_menu_item_reslice_now { nullptr }; wxMenuItem* m_menu_item_reslice_now { nullptr };
PrintHostQueueDialog *m_printhost_queue_dlg;
std::string get_base_name(const wxString full_name) const ; std::string get_base_name(const wxString full_name) const ;
std::string get_dir_name(const wxString full_name) const ; std::string get_dir_name(const wxString full_name) const ;
@ -67,8 +68,7 @@ class MainFrame : public wxFrame
bool can_delete_all() const; bool can_delete_all() const;
public: public:
MainFrame() {} MainFrame();
MainFrame(const bool no_plater, const bool loaded);
~MainFrame() {} ~MainFrame() {}
Plater* plater() { return m_plater; } Plater* plater() { return m_plater; }
@ -93,6 +93,8 @@ public:
void select_tab(size_t tab) const; void select_tab(size_t tab) const;
void select_view(const std::string& direction); void select_view(const std::string& direction);
PrintHostQueueDialog* printhost_queue_dlg() { return m_printhost_queue_dlg; }
Plater* m_plater { nullptr }; Plater* m_plater { nullptr };
wxNotebook* m_tabpanel { nullptr }; wxNotebook* m_tabpanel { nullptr };
wxProgressDialog* m_progress_dialog { nullptr }; wxProgressDialog* m_progress_dialog { nullptr };

View File

@ -6,6 +6,7 @@
#include <wx/button.h> #include <wx/button.h>
#include <wx/statbmp.h> #include <wx/statbmp.h>
#include <wx/scrolwin.h> #include <wx/scrolwin.h>
#include <wx/clipbrd.h>
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
@ -61,8 +62,11 @@ MsgDialog::~MsgDialog() {}
// ErrorDialog // ErrorDialog
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) : ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG)) : MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")),
wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG),
wxID_NONE)
, msg(msg)
{ {
auto *panel = new wxScrolledWindow(this); auto *panel = new wxScrolledWindow(this);
auto *p_sizer = new wxBoxSizer(wxVERTICAL); auto *p_sizer = new wxBoxSizer(wxVERTICAL);
@ -77,6 +81,20 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) :
content_sizer->Add(panel, 1, wxEXPAND); content_sizer->Add(panel, 1, wxEXPAND);
auto *btn_copy = new wxButton(this, wxID_ANY, _(L("Copy to clipboard")));
btn_copy->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) {
if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new wxTextDataObject(this->msg)); // Note: the clipboard takes ownership of the pointer
wxTheClipboard->Close();
}
});
auto *btn_ok = new wxButton(this, wxID_OK);
btn_ok->SetFocus();
btn_sizer->Add(btn_copy, 0, wxRIGHT, HORIZ_SPACING);
btn_sizer->Add(btn_ok);
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT)); SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT));
Fit(); Fit();
} }

View File

@ -50,14 +50,18 @@ protected:
// Generic error dialog, used for displaying exceptions // Generic error dialog, used for displaying exceptions
struct ErrorDialog : MsgDialog class ErrorDialog : public MsgDialog
{ {
public:
ErrorDialog(wxWindow *parent, const wxString &msg); ErrorDialog(wxWindow *parent, const wxString &msg);
ErrorDialog(ErrorDialog &&) = delete; ErrorDialog(ErrorDialog &&) = delete;
ErrorDialog(const ErrorDialog &) = delete; ErrorDialog(const ErrorDialog &) = delete;
ErrorDialog &operator=(ErrorDialog &&) = delete; ErrorDialog &operator=(ErrorDialog &&) = delete;
ErrorDialog &operator=(const ErrorDialog &) = delete; ErrorDialog &operator=(const ErrorDialog &) = delete;
virtual ~ErrorDialog(); virtual ~ErrorDialog();
private:
wxString msg;
}; };

File diff suppressed because it is too large Load Diff

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