Merge branch 'ys_msw_dpi' of https://github.com/prusa3d/Slic3r into ys_msw_dpi

This commit is contained in:
bubnikv 2019-04-18 17:16:42 +02:00
commit 5e45cff855
55 changed files with 1384 additions and 1046 deletions

View file

@ -321,7 +321,7 @@ include_directories(${GLEW_INCLUDE_DIRS})
# l10n
set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization")
add_custom_target(pot
COMMAND xgettext --keyword=L --from-code=UTF-8 --debug
COMMAND xgettext --keyword=L --add-comments=TRN --from-code=UTF-8 --debug
-f "${L10N_DIR}/list.txt"
-o "${L10N_DIR}/Slic3rPE.pot"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}

View file

@ -61,3 +61,10 @@ Please note that the `CMAKE_OSX_DEPLOYMENT_TARGET` and `CMAKE_OSX_SYSROOT` optio
on both the dependencies bundle as well as Slic3r PE itself.
Official Mac Slic3r builds are currently built against SDK 10.9 to ensure compatibility with older Macs.
_Warning:_ XCode may be set such that it rejects SDKs bellow some version (silently, more or less).
This is set in the property list file
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist
To remove the limitation, simply delete the key `MinimumSDKVersion` from that file.

View file

@ -46,7 +46,7 @@ https://github.com/prusa3d/Slic3r/tree/master/resources/localization/list.txt.
2. Create template file(*.POT) with GNUgettext command:
```
xgettext --keyword=L --from-code=UTF-8 --debug -o Slic3rPE.pot -f list.txt
xgettext --keyword=L --add-comments=TRN --from-code=UTF-8 --debug -o Slic3rPE.pot -f list.txt
```
Use flag `--from-code=UTF-8` to specify that the source strings are in UTF-8 encoding

View file

@ -5,13 +5,13 @@
<g id="layers">
<g>
<g>
<rect x="1" y="13" fill="#808080" width="14" height="2"/>
<rect x="1" y="13" fill="#FFFFFF" width="14" height="2"/>
</g>
<g>
<rect x="1" y="10.6" fill="#808080" width="14" height="1.74"/>
<rect x="1" y="10.6" fill="#FFFFFF" width="14" height="1.74"/>
</g>
<g>
<rect x="1" y="8.19" fill="#808080" width="14" height="1.47"/>
<rect x="1" y="8.19" fill="#FFFFFF" width="14" height="1.47"/>
</g>
<g>
<rect x="1" y="5.79" fill="#ED6B21" width="14" height="1.2"/>
@ -20,7 +20,7 @@
<rect x="1" y="3.39" fill="#ED6B21" width="14" height="0.93"/>
</g>
<g>
<rect x="1" y="0.99" fill="#808080" width="14" height="0.67"/>
<rect x="1" y="0.99" fill="#FFFFFF" width="14" height="0.67"/>
</g>
</g>
</g>

Before

Width:  |  Height:  |  Size: 845 B

After

Width:  |  Height:  |  Size: 845 B

File diff suppressed because it is too large Load diff

View file

@ -173,7 +173,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
float alpha = m_wipe_tower_rotation/180.f * M_PI;
float alpha = m_wipe_tower_rotation/180.f * float(M_PI);
WipeTower::xy start_pos = tcr.start_pos;
WipeTower::xy end_pos = tcr.end_pos;
start_pos.rotate(alpha);
@ -519,43 +519,43 @@ void GCode::_do_export(Print &print, FILE *file)
// this->print_machine_envelope(file, print);
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
if (print.config().gcode_flavor.value == gcfMarlin) {
m_normal_time_estimator.set_max_acceleration(print.config().machine_max_acceleration_extruding.values[0]);
m_normal_time_estimator.set_retract_acceleration(print.config().machine_max_acceleration_retracting.values[0]);
m_normal_time_estimator.set_minimum_feedrate(print.config().machine_min_extruding_rate.values[0]);
m_normal_time_estimator.set_minimum_travel_feedrate(print.config().machine_min_travel_rate.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config().machine_max_acceleration_x.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config().machine_max_acceleration_y.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config().machine_max_acceleration_z.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config().machine_max_acceleration_e.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config().machine_max_feedrate_x.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config().machine_max_feedrate_y.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config().machine_max_feedrate_z.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config().machine_max_feedrate_e.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config().machine_max_jerk_x.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config().machine_max_jerk_y.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config().machine_max_jerk_z.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config().machine_max_jerk_e.values[0]);
m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]);
m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]);
m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]);
m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]);
if (m_silent_time_estimator_enabled)
{
m_silent_time_estimator.reset();
m_silent_time_estimator.set_dialect(print.config().gcode_flavor);
m_silent_time_estimator.set_max_acceleration(print.config().machine_max_acceleration_extruding.values[1]);
m_silent_time_estimator.set_retract_acceleration(print.config().machine_max_acceleration_retracting.values[1]);
m_silent_time_estimator.set_minimum_feedrate(print.config().machine_min_extruding_rate.values[1]);
m_silent_time_estimator.set_minimum_travel_feedrate(print.config().machine_min_travel_rate.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config().machine_max_acceleration_x.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config().machine_max_acceleration_y.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config().machine_max_acceleration_z.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config().machine_max_acceleration_e.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config().machine_max_feedrate_x.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config().machine_max_feedrate_y.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config().machine_max_feedrate_z.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config().machine_max_feedrate_e.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config().machine_max_jerk_x.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config().machine_max_jerk_y.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config().machine_max_jerk_z.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config().machine_max_jerk_e.values[1]);
m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[1]);
m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[1]);
m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[1]);
m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[1]);
if (print.config().single_extruder_multi_material) {
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
// are considered to be active for the single extruder multi-material printers only.
@ -1054,26 +1054,54 @@ void GCode::_do_export(Print &print, FILE *file)
print.m_print_statistics.clear();
print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms();
print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A";
for (const Extruder &extruder : m_writer.extruders()) {
double used_filament = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f);
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament));
_write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001);
if (filament_weight > 0.) {
print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight;
_write_format(file, "; filament used = %.1lf\n", filament_weight);
if (filament_cost > 0.) {
print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost;
_write_format(file, "; filament cost = %.1lf\n", filament_cost);
std::vector<Extruder> extruders = m_writer.extruders();
if (! extruders.empty()) {
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
for (const Extruder &extruder : extruders) {
double used_filament = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f);
double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
while (dst.second < extruder.id()) {
// Fill in the non-printing extruders with zeros.
dst.first += (dst.second > 0) ? ", 0" : "0";
++ dst.second;
}
if (dst.second > 0)
dst.first += ", ";
char buf[64];
sprintf(buf, tmpl, value);
dst.first += buf;
++ dst.second;
};
print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament));
append(out_filament_used_mm, "%.1lf", used_filament);
append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
if (filament_weight > 0.) {
print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight;
append(out_filament_used_g, "%.1lf", filament_weight);
if (filament_cost > 0.) {
print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost;
append(out_filament_cost, "%.1lf", filament_cost);
}
}
print.m_print_statistics.total_used_filament += used_filament;
print.m_print_statistics.total_extruded_volume += extruded_volume;
print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
}
print.m_print_statistics.total_used_filament += used_filament;
print.m_print_statistics.total_extruded_volume += extruded_volume;
print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
_writeln(file, out_filament_used_mm.first);
_writeln(file, out_filament_used_cm3.first);
if (out_filament_used_g.second)
_writeln(file, out_filament_used_g.first);
if (out_filament_cost.second)
_writeln(file, out_filament_cost.first);
}
_write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight);
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
_write_format(file, "; estimated printing time (normal mode) = %s\n", m_normal_time_estimator.get_time_dhms().c_str());
if (m_silent_time_estimator_enabled)
@ -1528,7 +1556,7 @@ void GCode::process_layer(
std::max<int>(region.config().perimeter_extruder.value - 1, 0);
// Let's recover vector of extruder overrides:
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->copies().size());
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, (int)layer_to_print.object()->copies().size());
// Now we must add this extrusion into the by_extruder map, once for each extruder that will print it:
for (unsigned int extruder : layer_tools.extruders)

View file

@ -197,7 +197,7 @@ private:
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
const float Filament_Area = M_PI * 1.75f * 1.75f / 4.f; // filament area in mm^2
const float Filament_Area = float(M_PI * 1.75f * 1.75f / 4.f); // filament area in mm^2
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
const float WT_EPSILON = 1e-3f;
@ -224,8 +224,8 @@ private:
bool m_retain_speed_override = true;
bool m_adhesion = true;
float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_extrusion_flow = 0.038; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
struct FilamentParameters {
@ -269,12 +269,12 @@ private:
{
if ( layer_height < 0 )
return m_extrusion_flow;
return layer_height * ( m_perimeter_width - layer_height * (1-M_PI/4.f)) / Filament_Area;
return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / Filament_Area;
}
// Calculates length of extrusion line to extrude given volume
float volume_to_length(float volume, float line_width, float layer_height) const {
return std::max(0., volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.))));
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
}
// Calculates depth for all layers and propagates them downwards

View file

@ -38,7 +38,6 @@ static const std::string MOVE_TYPE_STR[Slic3r::GCodeTimeEstimator::Block::Num_Ty
#endif // ENABLE_MOVE_STATS
namespace Slic3r {
void GCodeTimeEstimator::Feedrates::reset()
{
feedrate = 0.0f;
@ -695,6 +694,8 @@ namespace Slic3r {
set_axis_position(X, 0.0f);
set_axis_position(Y, 0.0f);
set_axis_position(Z, 0.0f);
if (get_e_local_positioning_type() == Absolute)
set_axis_position(E, 0.0f);
set_additional_time(0.0f);
@ -715,7 +716,6 @@ namespace Slic3r {
_blocks.clear();
}
void GCodeTimeEstimator::_calculate_time()
{
PROFILE_FUNC();

View file

@ -943,7 +943,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
// This method is cheap in that it does not make any unnecessary copy of the volume meshes.
// This method is used by the auto arrange function.
Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance)
Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
{
Points pts;
for (const ModelVolume *v : this->volumes)
@ -1189,6 +1189,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
volume->mesh.transform(instance_matrix * volume_matrix, true);
// Perform cut
volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer tms(&volume->mesh);
tms.cut(float(z), &upper_mesh, &lower_mesh);

View file

@ -234,7 +234,7 @@ public:
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
// This method is cheap in that it does not make any unnecessary copy of the volume meshes.
// This method is used by the auto arrange function.
Polygon convex_hull_2d(const Transform3d &trafo_instance);
Polygon convex_hull_2d(const Transform3d &trafo_instance) const;
#if ENABLE_VOLUMES_CENTERING_FIXES
void center_around_origin(bool include_modifiers = true);

View file

@ -1,5 +1,6 @@
#include "ModelArrange.hpp"
#include "Model.hpp"
#include "Geometry.hpp"
#include "SVG.hpp"
#include <libnest2d.h>
@ -551,7 +552,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
ret.reserve(s);
for(ModelObject* objptr : model.objects) {
if(objptr) {
if (! objptr->instances.empty()) {
// TODO export the exact 2D projection. Cannot do it as libnest2d
// does not support concave shapes (yet).
@ -572,23 +573,23 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
clpath = Slic3rMultiPoint_to_ClipperPath(p);
}
Vec3d rotation0 = objptr->instances.front()->get_rotation();
rotation0(2) = 0.;
for(ModelInstance* objinst : objptr->instances) {
if(objinst) {
ClipperLib::Polygon pn;
pn.Contour = clpath;
ClipperLib::Polygon pn;
pn.Contour = clpath;
// Efficient conversion to item.
Item item(std::move(pn));
// Efficient conversion to item.
Item item(std::move(pn));
// Invalid geometries would throw exceptions when arranging
if(item.vertexCount() > 3) {
item.rotation(objinst->get_rotation(Z));
item.translation({
ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR)
});
ret.emplace_back(objinst, item);
}
// Invalid geometries would throw exceptions when arranging
if(item.vertexCount() > 3) {
item.rotation(float(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()))),
item.translation({
ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR)
});
ret.emplace_back(objinst, item);
}
}
}

View file

@ -1139,31 +1139,29 @@ std::string Print::validate() const
// Check horizontal clearance.
{
Polygons convex_hulls_other;
for (const PrintObject *object : m_objects) {
for (const PrintObject *print_object : m_objects) {
assert(! print_object->model_object()->instances.empty());
assert(! print_object->copies().empty());
// Get convex hull of all meshes assigned to this print object.
Polygon convex_hull;
{
Polygons mesh_convex_hulls;
for (const std::vector<int> &volumes : object->region_volumes)
for (int volume_id : volumes)
mesh_convex_hulls.emplace_back(object->model_object()->volumes[volume_id]->mesh.convex_hull());
// make a single convex hull for all of them
convex_hull = Slic3r::Geometry::convex_hull(mesh_convex_hulls);
}
// Apply the same transformations we apply to the actual meshes when slicing them.
object->model_object()->instances.front()->transform_polygon(&convex_hull);
ModelInstance *model_instance0 = print_object->model_object()->instances.front();
Vec3d rotation = model_instance0->get_rotation();
rotation.z() = 0.;
// Calculate the convex hull of a printable object centered around X=0,Y=0.
// Grow convex hull with the clearance margin.
// FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
// which causes that the warning will be showed after arrangement with the
// appropriate object distance. Even if I set this to jtMiter the warning still shows up.
convex_hull = offset(convex_hull, scale_(m_config.extruder_clearance_radius.value)/2, jtRound, scale_(0.1)).front();
Polygon convex_hull0 = offset(
print_object->model_object()->convex_hull_2d(
Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
scale_(m_config.extruder_clearance_radius.value) / 2., jtRound, scale_(0.1)).front();
// Now we check that no instance of convex_hull intersects any of the previously checked object instances.
for (const Point &copy : object->m_copies) {
Polygon p = convex_hull;
p.translate(copy);
if (! intersection(convex_hulls_other, p).empty())
for (const Point &copy : print_object->m_copies) {
Polygon convex_hull = convex_hull0;
convex_hull.translate(copy);
if (! intersection(convex_hulls_other, convex_hull).empty())
return L("Some objects are too close; your extruder will collide with them.");
polygons_append(convex_hulls_other, p);
polygons_append(convex_hulls_other, convex_hull);
}
}
}

View file

@ -2926,7 +2926,7 @@ CLIActionsConfigDef::CLIActionsConfigDef()
// Actions:
def = this->add("export_obj", coBool);
def->label = L("Export SVG");
def->label = L("Export OBJ");
def->tooltip = L("Export the model(s) as OBJ.");
def->default_value = new ConfigOptionBool(false);

View file

@ -1813,6 +1813,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
TriangleMeshSlicer mslicer;
const Print *print = this->print();
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
mslicer.init(&mesh, callback);
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
m_print->throw_if_canceled();
@ -1840,6 +1841,7 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
TriangleMeshSlicer mslicer;
const Print *print = this->print();
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
mslicer.init(&mesh, callback);
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
m_print->throw_if_canceled();

View file

@ -552,6 +552,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
float layerh, ThrowOnCancel thrfn)
{
TriangleMesh m = mesh;
m.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&m);
auto bb = mesh.bounding_box();

View file

@ -817,6 +817,10 @@ public:
meshcache = mesh(merged);
// The mesh will be passed by const-pointer to TriangleMeshSlicer,
// which will need this.
meshcache.require_shared_vertices();
// TODO: Is this necessary?
//meshcache.repair();
@ -2231,6 +2235,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
TriangleMesh fullmesh = m_impl->merged_mesh();
fullmesh.merge(get_pad());
fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&fullmesh);
SlicedSupports ret;
slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn);
@ -2243,6 +2248,7 @@ SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
{
TriangleMesh fullmesh = m_impl->merged_mesh();
fullmesh.merge(get_pad());
fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&fullmesh);
SlicedSupports ret;
slicer.slice(heights, cr, &ret, get().ctl().cancelfn);

View file

@ -598,8 +598,9 @@ std::string SLAPrint::validate() const
for(SLAPrintObject * po : m_objects) {
const ModelObject *mo = po->model_object();
bool supports_en = po->config().supports_enable.getBool();
if(po->config().supports_enable.getBool() &&
if(supports_en &&
mo->sla_points_status == sla::PointsStatus::UserModified &&
mo->sla_support_points.empty())
return L("Cannot proceed without support points! "
@ -613,7 +614,7 @@ std::string SLAPrint::validate() const
2 * cfg.head_back_radius_mm -
cfg.head_penetration_mm;
if(pinhead_width > cfg.object_elevation_mm)
if(supports_en && pinhead_width > cfg.object_elevation_mm)
return L("Elevation is too low for object.");
}
@ -696,6 +697,7 @@ void SLAPrint::process()
po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z)));
if(slindex_it == po.m_slice_index.end())
//TRN To be shown at the status bar on SLA slicing error.
throw std::runtime_error(L("Slicing had to be stopped "
"due to an internal error."));
@ -706,6 +708,7 @@ void SLAPrint::process()
po.m_model_height_levels.emplace_back(it->slice_level());
}
mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&mesh);
po.m_model_slices.clear();

View file

@ -160,17 +160,13 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object
m_support_material_interface_flow = m_support_material_flow;
}
// Evaluate the XY gap between the object outer perimeters and the support structures.
// Evaluate the XY gap between the object outer perimeters and the support structures.
coordf_t external_perimeter_width = 0.;
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
if (! object->region_volumes[region_id].empty()) {
const PrintRegionConfig &config = object->print()->get_region(region_id)->config();
coordf_t width = config.external_perimeter_extrusion_width.get_abs_value(slicing_params.layer_height);
if (width <= 0.)
width = m_print_config->nozzle_diameter.get_at(config.perimeter_extruder-1);
external_perimeter_width = std::max(external_perimeter_width, width);
}
}
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id)
if (! object->region_volumes[region_id].empty())
external_perimeter_width = std::max(external_perimeter_width,
(coordf_t)object->print()->get_region(region_id)->flow(frExternalPerimeter, slicing_params.layer_height, false, false, -1, *object).width);
m_gap_xy = m_object_config->support_material_xy_spacing.get_abs_value(external_perimeter_width);
m_can_merge_support_regions = m_object_config->support_material_extruder.value == m_object_config->support_material_interface_extruder.value;

View file

@ -607,10 +607,12 @@ void TriangleMesh::require_shared_vertices()
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
}
void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type throw_on_cancel)
void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callback_type throw_on_cancel)
{
mesh = _mesh;
_mesh->require_shared_vertices();
if (! mesh->has_shared_vertices())
throw std::invalid_argument("TriangleMeshSlicer was passed a mesh without shared vertices.");
throw_on_cancel();
facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);

View file

@ -67,18 +67,17 @@ public:
TriangleMesh convex_hull_3d() const;
void reset_repair_stats();
bool needed_repair() const;
void require_shared_vertices();
bool has_shared_vertices() const { return stl.v_shared != NULL; }
size_t facets_count() const { return this->stl.stats.number_of_facets; }
bool empty() const { return this->facets_count() == 0; }
bool is_splittable() const;
stl_file stl;
bool repaired;
private:
void require_shared_vertices();
std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const;
friend class TriangleMeshSlicer;
};
enum FacetEdgeType {
@ -159,9 +158,8 @@ class TriangleMeshSlicer
public:
typedef std::function<void()> throw_on_cancel_callback_type;
TriangleMeshSlicer() : mesh(nullptr) {}
// Not quite nice, but the constructor and init() methods require non-const mesh pointer to be able to call mesh->require_shared_vertices()
TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); }
void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
TriangleMeshSlicer(const TriangleMesh* mesh) { this->init(mesh, [](){}); }
void init(const TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
void slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
enum FacetSliceType {

View file

@ -88,7 +88,7 @@ std::string string_printf(const char *format, ...);
extern std::string timestamp_str();
// Standard "generated by Slic3r version xxx timestamp xxx" header string,
// to be placed at the top of Slic3r generated files.
inline std::string header_slic3r_generated() { return std::string("generated by " SLIC3R_FORK_NAME " " SLIC3R_VERSION " " ) + timestamp_str(); }
inline std::string header_slic3r_generated() { return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " " ) + timestamp_str(); }
// getpid platform wrapper
extern unsigned get_current_pid();

View file

@ -1,7 +1,8 @@
#ifndef __SLIC3R_VERSION_H
#define __SLIC3R_VERSION_H
#define SLIC3R_FORK_NAME "@SLIC3R_FORK_NAME@"
#define SLIC3R_APP_NAME "@SLIC3R_APP_NAME@"
#define SLIC3R_APP_KEY "@SLIC3R_APP_KEY@"
#define SLIC3R_VERSION "@SLIC3R_VERSION@"
#define SLIC3R_BUILD "@SLIC3R_BUILD@"

View file

@ -7,12 +7,12 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@
BLOCK "040904E4"
{
VALUE "CompanyName", "Prusa Research"
VALUE "FileDescription", "Slic3r Prusa Edition"
VALUE "FileDescription", "@SLIC3R_APP_NAME@"
VALUE "FileVersion", "@SLIC3R_BUILD_ID@"
VALUE "ProductName", "Slic3r Prusa Edition"
VALUE "ProductName", "@SLIC3R_APP_NAME@"
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
VALUE "InternalName", "Slic3r Prusa Edition"
VALUE "LegalCopyright", "Copyright \251 2011-2017 Alessandro Ranelucci, \251 2016 Prusa Research"
VALUE "InternalName", "@SLIC3R_APP_NAME@"
VALUE "LegalCopyright", "Copyright \251 2011-2019 Alessandro Ranelucci, \251 2016-2019 Prusa Research"
VALUE "OriginalFilename", "slic3r.exe"
}
}

View file

@ -3,15 +3,15 @@
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>Slic3r</string>
<string>@SLIC3R_APP_KEY@</string>
<key>CFBundleGetInfoString</key>
<string>Slic3r Copyright (C) 2011-2017 Alessandro Ranellucci, (C) 2016-2018 Prusa Reseach</string>
<string>@SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2019 Prusa Reseach</string>
<key>CFBundleIconFile</key>
<string>Slic3r.icns</string>
<key>CFBundleName</key>
<string>Slic3r</string>
<string>@SLIC3R_APP_KEY@</string>
<key>CFBundleShortVersionString</key>
<string>Slic3r @SLIC3R_BUILD_ID@</string>
<string>@SLIC3R_APP_NAME@ @SLIC3R_BUILD_ID@</string>
<key>CFBundleIdentifier</key>
<string>com.prusa3d.slic3r/</string>
<key>CFBundleInfoDictionaryVersion</key>

View file

@ -568,7 +568,7 @@ bool CLI::setup(int argc, char **argv)
void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const
{
boost::nowide::cout
<< "Slic3r Prusa Edition " << SLIC3R_BUILD
<< SLIC3R_APP_NAME << " " << SLIC3R_BUILD
#ifdef SLIC3R_GUI
<< " (with GUI support)"
#else /* SLIC3R_GUI */

View file

@ -32,7 +32,7 @@ void AboutDialogLogo::onRepaint(wxEvent &event)
}
AboutDialog::AboutDialog()
: DPIDialog(NULL, wxID_ANY, _(L("About Slic3r")), wxDefaultPosition,
: DPIDialog(NULL, wxID_ANY, wxString::Format(_(L("About %s")), SLIC3R_APP_NAME), wxDefaultPosition,
wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
SetFont(wxGetApp().normal_font());
@ -55,7 +55,7 @@ AboutDialog::AboutDialog()
// title
{
wxStaticText* title = new wxStaticText(this, wxID_ANY, "Slic3r Prusa Edition", wxDefaultPosition, wxDefaultSize);
wxStaticText* title = new wxStaticText(this, wxID_ANY, SLIC3R_APP_NAME, wxDefaultPosition, wxDefaultSize);
wxFont title_font = GUI::wxGetApp().bold_font();// wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
// title_font.SetWeight(wxFONTWEIGHT_BOLD);
title_font.SetFamily(wxFONTFAMILY_ROMAN);

View file

@ -16,6 +16,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/GCode/PostProcessor.hpp"
#include "libslic3r/GCode/PreviewData.hpp"
#include "libslic3r/libslic3r.h"
#include <cassert>
#include <stdexcept>
@ -390,7 +391,7 @@ void BackgroundSlicingProcess::prepare_upload()
// 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(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%");
/ boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%");
if (m_print == m_fff_print) {
m_print->set_status(95, "Running post-processing scripts");

View file

@ -261,9 +261,6 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
{
width = width * 0.1f * Slic3r::GUI::wxGetApp().em_unit() + 0.5f;
height = height * 0.1f * Slic3r::GUI::wxGetApp().em_unit() + 0.5f;
wxImage image(width, height);
image.InitAlpha();
unsigned char* imgdata = image.GetData();

View file

@ -281,13 +281,14 @@ void ConfigWizardPage::append_spacer(int space)
// Wizard pages
PageWelcome::PageWelcome(ConfigWizard *parent)
: ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the Slic3r %s")), ConfigWizard::name()), _(L("Welcome")))
: ConfigWizardPage(parent, wxString::Format(_(L("Welcome to the %s %s")), SLIC3R_APP_NAME, ConfigWizard::name()), _(L("Welcome")))
, cbox_reset(nullptr)
{
if (wizard_p()->run_reason == ConfigWizard::RR_DATA_EMPTY) {
wxString::Format(_(L("Run %s")), ConfigWizard::name());
append_text(wxString::Format(
_(L("Hello, welcome to Slic3r Prusa Edition! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")),
_(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")),
SLIC3R_APP_NAME,
ConfigWizard::name())
);
} else {
@ -398,7 +399,9 @@ PageUpdate::PageUpdate(ConfigWizard *parent)
auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for application updates")));
box_slic3r->SetValue(app_config->get("version_check") == "1");
append(box_slic3r);
append_text(_(L("If enabled, Slic3r checks for new versions of Slic3r PE online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.")));
append_text(wxString::Format(_(L("If enabled, Slic3r checks for new versions of %s online. When a new version becomes available, "
"a notification is displayed at the next application startup (never during program usage). "
"This is only a notification mechanisms, no automatic installation is done.")), SLIC3R_APP_NAME));
append_spacer(VERTICAL_SPACING);
@ -420,7 +423,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent)
PageVendors::PageVendors(ConfigWizard *parent)
: ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors")))
{
append_text(_(L("Pick another vendor supported by Slic3r PE:")));
append_text(wxString::Format(_(L("Pick another vendor supported by %s:")), SLIC3R_APP_NAME));
auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
@ -779,6 +782,8 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
const int yoff_text = bullet_h > em_h ? (bullet_h - em_h) / 2 : 0;
const int yinc = item_height();
int index_width = 0;
unsigned y = 0;
for (size_t i = 0; i < items.size(); i++) {
const Item& item = items[i];
@ -796,8 +801,18 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
else if (i < item_active) { dc.DrawBitmap(bullet_black.bmp(), x, y + yoff_icon, false); }
else if (i > item_active) { dc.DrawBitmap(bullet_white.bmp(), x, y + yoff_icon, false); }
dc.DrawText(item.label, x + bullet_w + em/2, y + yoff_text);
x += + bullet_w + em/2;
const auto text_size = dc.GetTextExtent(item.label);
dc.DrawText(item.label, x, y + yoff_text);
y += yinc;
index_width = std::max(index_width, (int)x + text_size.x);
}
if (GetMinSize().x < index_width) {
CallAfter([this, index_width]() {
SetMinSize(wxSize(index_width, GetMinSize().y));
});
}
}

View file

@ -1486,6 +1486,8 @@ void GLCanvas3D::enable_layers_editing(bool enable)
if (v->is_modifier)
v->force_transparent = enable;
}
set_as_dirty();
}
void GLCanvas3D::enable_legend_texture(bool enable)
@ -1654,7 +1656,7 @@ void GLCanvas3D::render()
#endif // !ENABLE_SVG_ICONS
_render_toolbar();
_render_view_toolbar();
if (m_layers_editing.last_object_id >= 0)
if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f))
m_layers_editing.render_overlay(*this);
wxGetApp().imgui()->render();
@ -2254,6 +2256,22 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL));
break;
#ifdef __APPLE__
case 'c':
case 'C':
#else /* __APPLE__ */
case WXK_CONTROL_C:
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_COPY));
break;
#ifdef __APPLE__
case 'v':
case 'V':
#else /* __APPLE__ */
case WXK_CONTROL_V:
#endif /* __APPLE__ */
post_event(SimpleEvent(EVT_GLTOOLBAR_PASTE));
break;
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
#else /* __APPLE__ */
@ -2372,6 +2390,10 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
}
}
// Inform gizmos about the event so they have the opportunity to react.
if (m_gizmos.on_mouse_wheel(evt, *this))
return;
// Calculate the zoom delta and apply it to the current zoom factor
float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta();
set_camera_zoom(zoom);
@ -2596,7 +2618,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_selection.remove(m_hover_volume_id);
else
{
m_selection.add(m_hover_volume_id, !ctrl_down);
m_selection.add(m_hover_volume_id, !ctrl_down, true);
m_mouse.drag.move_requires_threshold = !already_selected;
if (already_selected)
m_mouse.set_move_start_threshold_position_2D_as_invalid();
@ -3676,8 +3698,8 @@ void GLCanvas3D::_render_objects() const
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
m_shader.start_using();
if (m_picking_enabled && m_layers_editing.is_enabled() && m_layers_editing.last_object_id != -1) {
int object_id = m_layers_editing.last_object_id;
if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
int object_id = m_layers_editing.last_object_id;
m_volumes.render_VBOs(GLVolumeCollection::Opaque, false, m_camera.get_view_matrix(), [object_id](const GLVolume &volume) {
// Which volume to paint without the layer height profile shader?
return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);

View file

@ -34,7 +34,7 @@
#include "../Utils/PresetUpdater.hpp"
#include "../Utils/PrintHost.hpp"
#include "ConfigWizard_private.hpp"
#include "ConfigWizard.hpp"
#include "slic3r/Config/Snapshot.hpp"
#include "ConfigSnapshotDialog.hpp"
#include "FirmwareDialog.hpp"
@ -149,8 +149,8 @@ bool GUI_App::on_init_inner()
wxCHECK_MSG(wxDirExists(resources_dir), false,
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
SetAppName("Slic3rPE-beta");
SetAppDisplayName("Slic3r Prusa Edition");
SetAppName(SLIC3R_APP_KEY "-beta");
SetAppDisplayName(SLIC3R_APP_NAME);
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
// wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0);
@ -230,7 +230,7 @@ bool GUI_App::on_init_inner()
// and after MainFrame is created & shown.
// The extra CallAfter() is needed because of Mac, where this is the only way
// to popup a modal dialog on start without screwing combo boxes.
// This is ugly but I honestly found not better way to do it.
// This is ugly but I honestly found no better way to do it.
// Neither wxShowEvent nor wxWindowCreateEvent work reliably.
static bool once = true;
if (once) {
@ -381,7 +381,7 @@ void GUI_App::recreate_GUI()
topwindow->Destroy();
}
dlg.Update(80, _(L("Loading of a current presets")) + dots);
dlg.Update(80, _(L("Loading of current presets")) + dots);
m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg()));
@ -513,7 +513,7 @@ bool GUI_App::select_language( wxArrayString & names,
m_wxLocale = new wxLocale;
m_wxLocale->Init(identifiers[index]);
m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir()));
m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE");
m_wxLocale->AddCatalog("Slic3rPE");
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified();
@ -542,7 +542,7 @@ bool GUI_App::load_language()
m_wxLocale = new wxLocale;
m_wxLocale->Init(identifiers[i]);
m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir()));
m_wxLocale->AddCatalog(/*GetAppName()*/"Slic3rPE");
m_wxLocale->AddCatalog("Slic3rPE");
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified();
@ -586,9 +586,7 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident
if (langinfo != NULL)
{
auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() +
filename + wxFileName::GetPathSeparator() +
/*GetAppName()*/"Slic3rPE" +
wxT(".mo");
filename + wxFileName::GetPathSeparator() + "Slic3rPE" + wxT(".mo");
if (wxFileExists(full_file_name))
{
names.Add(langinfo->Description);

View file

@ -543,12 +543,13 @@ void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
for (const size_t object : object_idxs)
{
add_object_to_list(object);
m_parts_changed = true;
parts_changed(object);
items.Add(m_objects_model->GetItemById(object));
}
m_parts_changed = true;
wxGetApp().plater()->changed_objects(object_idxs);
m_parts_changed = false;
select_items(items);
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
@ -644,6 +645,10 @@ void ObjectList::key_event(wxKeyEvent& event)
}
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
select_item_all_children();
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
else
event.Skip();
}

View file

@ -16,7 +16,7 @@
namespace Slic3r {
namespace GUI {
const float GLGizmoBase::Grabber::SizeFactor = 0.025f;
const float GLGizmoBase::Grabber::SizeFactor = 0.05f;
const float GLGizmoBase::Grabber::MinHalfSize = 1.5f;
const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f;
@ -53,7 +53,7 @@ float GLGizmoBase::Grabber::get_half_size(float size) const
float GLGizmoBase::Grabber::get_dragging_half_size(float size) const
{
return std::max(size * SizeFactor * DraggingScaleFactor, MinHalfSize);
return get_half_size(size) * DraggingScaleFactor;
}
void GLGizmoBase::Grabber::render(float size, const float* render_color, bool use_lighting) const

View file

@ -150,7 +150,8 @@ void GLGizmoMove3D::on_render(const Selection& selection) const
glsafe(::glEnd());
// draw grabber
m_grabbers[m_hover_id].render(true, box.max_size());
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
m_grabbers[m_hover_id].render(true, mean_size);
render_grabber_extension((Axis)m_hover_id, box, false);
}
}

View file

@ -51,6 +51,9 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
return;
}
if (m_model_object != model_object)
m_print_object_idx = -1;
m_model_object = model_object;
m_active_instance = selection.get_instance_idx();
@ -89,54 +92,113 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
// we'll recover current look direction from the modelview matrix (in world coords):
Eigen::Matrix<double, 4, 4, Eigen::DontAlign> modelview_matrix;
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
if (m_quadric != nullptr && selection.is_from_single_instance())
render_points(selection, direction_to_camera, false);
render_points(selection, false);
render_selection_rectangle();
render_clipping_plane(selection, direction_to_camera);
render_clipping_plane(selection);
glsafe(::glDisable(GL_BLEND));
}
void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const Vec3d& direction_to_camera) const
void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
{
if (m_clipping_plane_distance == 0.f)
return;
if (m_clipping_plane_normal == Vec3d::Zero())
reset_clipping_plane_normal();
const Vec3d& direction_to_camera = m_clipping_plane_normal;
// First cache instance transformation to be used later.
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
Transform3f instance_matrix = vol->get_instance_transformation().get_matrix().cast<float>();
Transform3f instance_matrix_no_translation_no_scaling = vol->get_instance_transformation().get_matrix(true,false,true).cast<float>();
Vec3f scaling = vol->get_instance_scaling_factor().cast<float>();
Vec3d instance_offset = vol->get_instance_offset();
// Calculate distance from mesh origin to the clipping plane (in mesh coordinates).
Vec3f up_noscale = instance_matrix_no_translation_no_scaling.inverse() * direction_to_camera.cast<float>();
Vec3f up = Vec3f(up_noscale(0)*scaling(0), up_noscale(1)*scaling(1), up_noscale(2)*scaling(2));
float height_mesh = (m_active_instance_bb_radius - m_clipping_plane_distance * 2*m_active_instance_bb_radius) * (up_noscale.norm()/up.norm());
if (m_clipping_plane_distance != m_old_clipping_plane_distance
|| m_old_direction_to_camera != direction_to_camera) {
// Get transformation of the supports and calculate how far from its origin the clipping plane is.
Transform3d supports_trafo = Transform3d::Identity();
supports_trafo = supports_trafo.rotate(Eigen::AngleAxisd(vol->get_instance_rotation()(2), Vec3d::UnitZ()));
Vec3f up_supports = (supports_trafo.inverse() * direction_to_camera).cast<float>();
supports_trafo = supports_trafo.pretranslate(Vec3d(instance_offset(0), instance_offset(1), vol->get_sla_shift_z()));
// Instance and supports origin do not coincide, so the following is quite messy:
float height_supports = height_mesh * (up.norm() / up_supports.norm()) + instance_offset(2) * (direction_to_camera(2) / direction_to_camera.norm());
std::vector<ExPolygons> list_of_expolys;
// In case either of these was recently changed, the cached triangulated ExPolygons are invalid now.
// We are gonna recalculate them both for the object and for the support structures.
if (m_clipping_plane_distance != m_old_clipping_plane_distance
|| m_old_clipping_plane_normal != direction_to_camera) {
m_old_clipping_plane_normal = direction_to_camera;
m_old_clipping_plane_distance = m_clipping_plane_distance;
// Now initialize the TMS for the object, perform the cut and save the result.
if (! m_tms) {
m_tms.reset(new TriangleMeshSlicer);
m_tms->init(const_cast<TriangleMesh*>(&m_mesh), [](){});
m_tms->init(m_mesh, [](){});
}
std::vector<ExPolygons> list_of_expolys;
m_tms->set_up_direction(up);
m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){});
m_triangles = triangulate_expolygons_2f(list_of_expolys[0]);
m_old_direction_to_camera = direction_to_camera;
m_old_clipping_plane_distance = m_clipping_plane_distance;
// Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = m_parent.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
if (m_print_object_idx >= 0) {
const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_print_object_idx];
if (print_object->is_step_done(slaposSupportTree)) {
// If the supports are already calculated, save the timestamp of the respective step
// so we can later tell they were recalculated.
size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
if (!m_supports_tms || (int)timestamp != m_old_timestamp) {
// The timestamp has changed - stash the mesh and initialize the TMS.
m_supports_mesh = &print_object->support_mesh();
m_supports_tms.reset(new TriangleMeshSlicer);
// The mesh should already have the shared vertices calculated.
m_supports_tms->init(m_supports_mesh, [](){});
m_old_timestamp = timestamp;
}
// The TMS is initialized - let's do the cutting:
list_of_expolys.clear();
m_supports_tms->set_up_direction(up_supports);
m_supports_tms->slice(std::vector<float>{height_supports}, 0.f, &list_of_expolys, [](){});
m_supports_triangles = triangulate_expolygons_2f(list_of_expolys[0]);
}
else {
// The supports are not valid. We better dump the cached data.
m_supports_tms.reset();
m_supports_triangles.clear();
}
}
}
// At this point we have the triangulated cuts for both the object and supports - let's render.
if (! m_triangles.empty()) {
::glPushMatrix();
::glTranslated(0.0, 0.0, m_z_shift);
@ -145,12 +207,30 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const
q.setFromTwoVectors(Vec3f::UnitZ(), up);
Eigen::AngleAxisf aa(q);
::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2));
::glTranslatef(0.f, 0.f, -0.001f); // to make sure the cut is safely beyond the near clipping plane
::glColor3f(1.0f, 0.37f, 0.0f);
::glBegin(GL_TRIANGLES);
::glTranslatef(0.f, 0.f, 0.01f); // to make sure the cut does not intersect the structure itself
::glColor3f(1.0f, 0.37f, 0.0f);
::glBegin(GL_TRIANGLES);
for (const Vec2f& point : m_triangles)
::glVertex3f(point(0), point(1), height_mesh);
::glEnd();
::glPopMatrix();
}
if (! m_supports_triangles.empty() && !m_editing_mode) {
// The supports are hidden in the editing mode, so it makes no sense to render the cuts.
::glPushMatrix();
::glMultMatrixd(supports_trafo.data());
Eigen::Quaternionf q;
q.setFromTwoVectors(Vec3f::UnitZ(), up_supports);
Eigen::AngleAxisf aa(q);
::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2));
::glTranslatef(0.f, 0.f, 0.01f);
::glColor3f(1.0f, 0.f, 0.37f);
::glBegin(GL_TRIANGLES);
for (const Vec2f& point : m_supports_triangles)
::glVertex3f(point(0), point(1), height_supports);
::glEnd();
::glPopMatrix();
}
@ -206,16 +286,10 @@ void GLGizmoSlaSupports::render_selection_rectangle() const
void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const
{
glsafe(::glEnable(GL_DEPTH_TEST));
// we'll recover current look direction from the modelview matrix (in world coords):
Eigen::Matrix<double, 4, 4, Eigen::DontAlign> modelview_matrix;
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
render_points(selection, direction_to_camera, true);
render_points(selection, true);
}
void GLGizmoSlaSupports::render_points(const Selection& selection, const Vec3d& direction_to_camera, bool picking) const
void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) const
{
if (!picking)
glsafe(::glEnable(GL_LIGHTING));
@ -234,7 +308,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, const Vec3d&
const sla::SupportPoint& support_point = m_editing_mode_cache[i].support_point;
const bool& point_selected = m_editing_mode_cache[i].selected;
if (is_point_clipped(support_point.pos.cast<double>(), direction_to_camera))
if (is_point_clipped(support_point.pos.cast<double>()))
continue;
// First decide about the color of the point.
@ -308,8 +382,10 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, const Vec3d&
bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point, const Vec3d& direction_to_camera) const
bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
{
const Vec3d& direction_to_camera = m_clipping_plane_normal;
if (m_clipping_plane_distance == 0.f)
return false;
@ -332,9 +408,12 @@ void GLGizmoSlaSupports::update_mesh()
wxBusyCursor wait;
Eigen::MatrixXf& V = m_V;
Eigen::MatrixXi& F = m_F;
// We rely on SLA model object having a single volume,
// this way we can use that mesh directly.
// This mesh does not account for the possible Z up SLA offset.
m_mesh = m_model_object->raw_mesh();
const stl_file& stl = m_mesh.stl;
m_mesh = &m_model_object->volumes.front()->mesh;
const_cast<TriangleMesh*>(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this
const stl_file& stl = m_mesh->stl;
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) {
@ -376,9 +455,6 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
// we'll recover current look direction from the modelview matrix (in world coords):
Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
point1(2) -= m_z_shift;
point2(2) -= m_z_shift;
@ -405,7 +481,7 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0)));
b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0)));
result = 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));
if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast<double>(), direction_to_camera))
if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast<double>()))
break;
}
@ -510,7 +586,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z);
out_y = m_canvas_height - out_y;
if (rectangle.contains(Point(out_x, out_y)) && !is_point_clipped(support_point.pos.cast<double>(), direction_to_camera.cast<double>())) {
if (rectangle.contains(Point(out_x, out_y)) && !is_point_clipped(support_point.pos.cast<double>())) {
bool is_obscured = false;
// Cast a ray in the direction of the camera and look for intersection with the mesh:
std::vector<igl::Hit> hits;
@ -534,7 +610,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
Vec3f bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
Vec3f hit_pos = 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));
if (is_point_clipped(hit_pos.cast<double>(), direction_to_camera.cast<double>())) {
if (is_point_clipped(hit_pos.cast<double>())) {
hits.erase(hits.begin()+j);
--j;
}
@ -626,6 +702,23 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
}
}
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f);
m_parent.set_as_dirty();
return true;
}
if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f);
m_parent.set_as_dirty();
return true;
}
if (action == SLAGizmoEventType::ResetClippingPlane) {
reset_clipping_plane_normal();
return true;
}
return false;
}
@ -709,11 +802,12 @@ ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const
if (!m_model_object || m_state == Off)
return ClippingPlane::ClipsNothing();
Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix;
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
//Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix;
//::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
// we'll recover current look direction from the modelview matrix (in world coords):
Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
//Vec3d direction_to_camera(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
const Vec3d& direction_to_camera = m_clipping_plane_normal;
float dist = direction_to_camera.dot(m_model_object->instances[m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift));
return ClippingPlane(-direction_to_camera.normalized(),(dist - (-m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_active_instance_bb_radius));
@ -872,18 +966,27 @@ RENDER_AGAIN:
m_imgui->text("");
m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points (will be autogenerated)" :
(m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" :
(m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" :
(m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS"))));
m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? _(L("No points (will be autogenerated)")) :
(m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? _(L("Autogenerated points (no modifications)")) :
(m_model_object->sla_points_status == sla::PointsStatus::UserModified ? _(L("User-modified points")) :
(m_model_object->sla_points_status == sla::PointsStatus::Generating ? _(L("Generation in progress...")) : "UNKNOWN STATUS"))));
}
// Following is rendered in both editing and non-editing mode:
m_imgui->text("Clipping of view: ");
ImGui::SameLine();
if (m_clipping_plane_distance == 0.f)
m_imgui->text("Clipping of view: ");
else {
if (m_imgui->button(_(L("Reset direction [R] ")))) {
wxGetApp().CallAfter([this](){
reset_clipping_plane_normal();
});
}
}
ImGui::SameLine(140.f);
ImGui::PushItemWidth(150.0f);
bool value_changed = ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f");
ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f");
m_imgui->end();
@ -972,12 +1075,12 @@ void GLGizmoSlaSupports::on_set_state()
m_editing_mode = false; // so it is not active next time the gizmo opens
m_editing_mode_cache.clear();
m_clipping_plane_distance = 0.f;
// Release copy of the mesh, triangle slicer and the AABB spatial search structure.
m_mesh.clear();
// Release triangle mesh slicer and the AABB spatial search structure.
m_AABB.deinit();
m_V = Eigen::MatrixXf();
m_F = Eigen::MatrixXi();
m_tms.reset(nullptr);
m_tms.reset();
m_supports_tms.reset();
});
}
m_old_state = m_state;
@ -1126,5 +1229,17 @@ void GLGizmoSlaSupports::switch_to_editing_mode()
m_editing_mode = true;
}
void GLGizmoSlaSupports::reset_clipping_plane_normal() const
{
Eigen::Matrix<double, 4, 4, Eigen::DontAlign> modelview_matrix;
::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
m_clipping_plane_normal = Vec3d(modelview_matrix.data()[2], modelview_matrix.data()[6], modelview_matrix.data()[10]);
m_parent.set_as_dirty();
}
} // namespace GUI
} // namespace Slic3r

View file

@ -36,8 +36,13 @@ private:
Eigen::MatrixXf m_V; // vertices
Eigen::MatrixXi m_F; // facets indices
igl::AABB<Eigen::MatrixXf,3> m_AABB;
TriangleMesh m_mesh;
const TriangleMesh* m_mesh;
mutable const TriangleMesh* m_supports_mesh;
mutable std::vector<Vec2f> m_triangles;
mutable std::vector<Vec2f> m_supports_triangles;
mutable int m_old_timestamp = -1;
mutable int m_print_object_idx = -1;
mutable int m_print_objects_count = -1;
class CacheEntry {
public:
@ -68,8 +73,8 @@ private:
virtual void on_render_for_picking(const Selection& selection) const;
void render_selection_rectangle() const;
void render_points(const Selection& selection, const Vec3d& direction_to_camera, bool picking = false) const;
void render_clipping_plane(const Selection& selection, const Vec3d& direction_to_camera) const;
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
bool is_mesh_update_necessary() const;
void update_mesh();
void update_cache_entry_normal(unsigned int i) const;
@ -79,11 +84,11 @@ private:
bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
float m_new_point_head_diameter; // Size of a new point.
float m_minimal_point_distance = 20.f;
float m_density = 100.f;
mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
float m_clipping_plane_distance = 0.f;
mutable float m_old_clipping_plane_distance = 0.f;
mutable Vec3d m_old_direction_to_camera;
mutable Vec3d m_old_clipping_plane_normal;
mutable Vec3d m_clipping_plane_normal = Vec3d::Zero();
enum SelectionRectangleStatus {
srOff = 0,
@ -101,10 +106,11 @@ private:
int m_canvas_height;
mutable std::unique_ptr<TriangleMeshSlicer> m_tms;
mutable std::unique_ptr<TriangleMeshSlicer> m_supports_tms;
std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
bool is_point_clipped(const Vec3d& point, const Vec3d& direction_to_camera) const;
void find_intersecting_facets(const igl::AABB<Eigen::MatrixXf, 3>* aabb, const Vec3f& normal, double offset, std::vector<unsigned int>& out) const;
bool is_point_clipped(const Vec3d& point) const;
//void find_intersecting_facets(const igl::AABB<Eigen::MatrixXf, 3>* aabb, const Vec3f& normal, double offset, std::vector<unsigned int>& out) const;
// Methods that do the model_object and editing cache synchronization,
// editing mode selection, etc:
@ -120,6 +126,7 @@ private:
void get_data_from_backend();
void auto_generate();
void switch_to_editing_mode();
void reset_clipping_plane_normal() const;
protected:
void on_set_state() override;

View file

@ -14,7 +14,10 @@ enum class SLAGizmoEventType {
ApplyChanges,
DiscardChanges,
AutomaticGeneration,
ManualEditing
ManualEditing,
MouseWheelUp,
MouseWheelDown,
ResetClippingPlane
};
#include "slic3r/GUI/Gizmos/GLGizmoMove.hpp"

View file

@ -520,6 +520,23 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection&
glsafe(::glPopMatrix());
}
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas)
{
bool processed = false;
if (m_current == SlaSupports) {
float rot = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta();
if (gizmo_event((rot > 0.f ? SLAGizmoEventType::MouseWheelUp : SLAGizmoEventType::MouseWheelDown), Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
processed = true;
}
return processed;
}
bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
{
Point pos(evt.GetX(), evt.GetY());
@ -761,6 +778,16 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
break;
}
case 'r' :
case 'R' :
{
if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::ResetClippingPlane))
processed = true;
break;
}
#ifdef __APPLE__
case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
#else /* __APPLE__ */
@ -794,7 +821,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
}
}
if (!processed)
if (!processed && !evt.HasModifiers())
{
if (handle_shortcut(keyCode, canvas.get_selection()))
{

View file

@ -157,6 +157,7 @@ public:
const std::string& get_tooltip() const { return m_tooltip; }
bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas);
bool on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas);
bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas);
bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas);

View file

@ -10,7 +10,7 @@ namespace Slic3r {
namespace GUI {
KBShortcutsDialog::KBShortcutsDialog()
: DPIDialog(NULL, wxID_ANY, _(L("Slic3r Prusa Edition - Keyboard Shortcuts")),
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
@ -136,6 +136,8 @@ void KBShortcutsDialog::fill_shortcuts()
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(ctrl+"C", L("Copy to clipboard")));
plater_shortcuts.push_back(Shortcut(ctrl+"V", L("Paste from clipboard")));
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")));
@ -177,8 +179,8 @@ void KBShortcutsDialog::fill_shortcuts()
Shortcuts layers_slider_shortcuts;
layers_slider_shortcuts.reserve(6);
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Up"), L("Move current slider thump Up")));
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Move current slider thump Down")));
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Up"), L("Move current slider thumb Up")));
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Move current slider thumb Down")));
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Left"), L("Set upper thumb to current slider thumb")));
layers_slider_shortcuts.push_back(Shortcut(L("Arrow Right"),L("Set lower thumb to current slider thumb")));
layers_slider_shortcuts.push_back(Shortcut("+", L("Add color change marker for current layer")));

View file

@ -403,9 +403,9 @@ void MainFrame::init_menubar()
editMenu->AppendSeparator();
wxMenuItem* item_copy = append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + "\tCtrl+C", _(L("Copy selection to clipboard")),
wxMenuItem* item_copy = append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C", _(L("Copy selection to clipboard")),
[this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, "copy_menu");
wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + "\tCtrl+V", _(L("Paste clipboard")),
wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V", _(L("Paste clipboard")),
[this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "paste_menu");
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId());
@ -505,9 +505,9 @@ void MainFrame::init_menubar()
[this](wxCommandEvent&) { wxGetApp().system_info(); });
append_menu_item(helpMenu, wxID_ANY, _(L("Show &Configuration Folder")), _(L("Show user configuration folder (datadir)")),
[this](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); });
append_menu_item(helpMenu, wxID_ANY, _(L("Report an I&ssue")), _(L("Report an issue on the Slic3r Prusa Edition")),
append_menu_item(helpMenu, wxID_ANY, _(L("Report an I&ssue")), wxString::Format(_(L("Report an issue on %s")), SLIC3R_APP_NAME),
[this](wxCommandEvent&) { wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/issues/new"); });
append_menu_item(helpMenu, wxID_ANY, _(L("&About Slic3r")), _(L("Show about dialog")),
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_(L("&About %s")), SLIC3R_APP_NAME), _(L("Show about dialog")),
[this](wxCommandEvent&) { Slic3r::GUI::about(); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + sep + "&?", _(L("Show the list of the keyboard shortcuts")),
@ -776,7 +776,7 @@ void MainFrame::export_configbundle()
// Ask user for a file name.
auto dlg = new wxFileDialog(this, _(L("Save presets bundle as:")),
!m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(),
"Slic3r_config_bundle.ini",
SLIC3R_APP_KEY "_config_bundle.ini",
file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
wxString file;
if (dlg->ShowModal() == wxID_OK)

View file

@ -280,7 +280,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 *
cfg.set_key_value("extruder_colour", colors);
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg);
wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this);
wxGetApp().preset_bundle->update_platter_filament_ui(extruder_idx, this, wxGetApp().em_unit());
wxGetApp().plater()->on_config_change(cfg);
}
dialog->Destroy();
@ -813,7 +813,7 @@ void Sidebar::update_all_preset_comboboxes()
// update the dirty flags.
if (print_tech == ptFFF) {
for (size_t i = 0; i < p->combos_filament.size(); ++i)
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i], wxGetApp().em_unit());
}
p->show_preset_comboboxes();
}
@ -837,7 +837,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
}
for (size_t i = 0; i < filament_cnt; i++) {
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i], wxGetApp().em_unit());
}
break;
@ -872,7 +872,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
// // update the dirty flags.
// if (print_tech == ptFFF) {
// for (size_t i = 0; i < p->combos_filament.size(); ++ i)
// preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
// preset_bundle.update_platter_filament_ui(i, p->combos_filament[i], wxGetApp().em_unit());
// }
// p->show_preset_comboboxes();
update_all_preset_comboboxes();
@ -1239,8 +1239,8 @@ struct Plater::priv
wxString project_filename;
BackgroundSlicingProcess background_process;
std::atomic<bool> arranging;
std::atomic<bool> rotoptimizing;
bool arranging;
bool rotoptimizing;
bool delayed_scene_refresh;
std::string delayed_error_message;
@ -1403,8 +1403,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
, view_toolbar(GLToolbar::Radio)
#endif // ENABLE_SVG_ICONS
{
arranging.store(false);
rotoptimizing.store(false);
arranging = false;
rotoptimizing = false;
background_process.set_fff_print(&fff_print);
background_process.set_sla_print(&sla_print);
background_process.set_gcode_preview_data(&gcode_preview_data);
@ -1703,6 +1703,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
break;
}
// is there any advanced config data ?
auto opt_keys = model_object->config.keys();
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
{
advanced = true;
break;
}
// is there any modifier ?
for (const ModelVolume* model_volume : model_object->volumes)
{
@ -1711,6 +1719,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
advanced = true;
break;
}
// is there any advanced config data ?
opt_keys = model_volume->config.keys();
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
{
advanced = true;
break;
}
}
if (advanced)
@ -2079,15 +2095,14 @@ void Plater::priv::mirror(Axis axis)
void Plater::priv::arrange()
{
// don't do anything if currently arranging. Then this is a re-entrance
if(arranging.load()) return;
// Guard the arrange process
arranging.store(true);
if (arranging) { return; }
arranging = true;
Slic3r::ScopeGuard arranging_guard([this]() { arranging = false; });
wxBusyCursor wait;
this->background_process.stop();
unsigned count = 0;
for(auto obj : model.objects) count += obj->instances.size();
@ -2103,14 +2118,14 @@ void Plater::priv::arrange()
statusbar()->set_progress(count - st);
statusbar()->set_status_text(msg);
// ok, this is dangerous, but we are protected by the atomic flag
// ok, this is dangerous, but we are protected by the flag
// 'arranging' and the arrange button is also disabled.
// This call is needed for the cancel button to work.
wxYieldIfNeeded();
};
statusbar()->set_cancel_callback([this, statusfn](){
arranging.store(false);
arranging = false;
statusfn(0, L("Arranging canceled"));
});
@ -2146,7 +2161,7 @@ void Plater::priv::arrange()
hint,
false, // create many piles not just one pile
[statusfn](unsigned st) { statusfn(st, arrangestr); },
[this] () { return !arranging.load(); });
[this] () { return !arranging; });
} catch(std::exception& /*e*/) {
GUI::show_error(this->q, L("Could not arrange model objects! "
"Some geometries may be invalid."));
@ -2155,7 +2170,6 @@ void Plater::priv::arrange()
statusfn(0, L("Arranging done."));
statusbar()->set_range(prev_range);
statusbar()->set_cancel_callback(); // remove cancel button
arranging.store(false);
// Do a full refresh of scene tree, including regenerating all the GLVolumes.
//FIXME The update function shall just reload the modified matrices.
@ -2170,11 +2184,12 @@ void Plater::priv::sla_optimize_rotation() {
// running we should probably disable explicit slicing and background
// processing
if(rotoptimizing.load()) return;
rotoptimizing.store(true);
if (rotoptimizing) { return; }
rotoptimizing = true;
Slic3r::ScopeGuard rotoptimizing_guard([this]() { rotoptimizing = false; });
int obj_idx = get_selected_object_idx();
if(obj_idx < 0) { rotoptimizing.store(false); return; }
if (obj_idx < 0) { return; }
ModelObject * o = model.objects[size_t(obj_idx)];
@ -2192,14 +2207,14 @@ void Plater::priv::sla_optimize_rotation() {
};
statusbar()->set_cancel_callback([this, stfn](){
rotoptimizing.store(false);
rotoptimizing = false;
stfn(0, L("Orientation search canceled"));
});
auto r = sla::find_best_rotation(
*o, .005f,
[stfn](unsigned s) { stfn(s, L("Searching for optimal orientation")); },
[this](){ return !rotoptimizing.load(); }
[this](){ return !rotoptimizing; }
);
const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
@ -2212,7 +2227,7 @@ void Plater::priv::sla_optimize_rotation() {
double mindist = 6.0; // FIXME
double offs = mindist / 2.0 - EPSILON;
if(rotoptimizing.load()) // wasn't canceled
if(rotoptimizing) // wasn't canceled
for(ModelInstance * oi : o->instances) {
oi->set_rotation({r[X], r[Y], r[Z]});
@ -2262,7 +2277,6 @@ void Plater::priv::sla_optimize_rotation() {
stfn(0, L("Orientation found."));
statusbar()->set_range(prev_range);
statusbar()->set_cancel_callback();
rotoptimizing.store(false);
update(true);
}
@ -2440,6 +2454,11 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
bool Plater::priv::restart_background_process(unsigned int state)
{
if (arranging || rotoptimizing) {
// Avoid a race condition
return false;
}
if ( ! this->background_process.empty() &&
(state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 &&
( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) ||
@ -2650,7 +2669,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
// TODO: ?
if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) {
// Only update the platter UI for the 2nd and other filaments.
wxGetApp().preset_bundle->update_platter_filament_ui(idx, combo);
wxGetApp().preset_bundle->update_platter_filament_ui(idx, combo, wxGetApp().em_unit());
}
else {
wxWindowUpdateLocker noUpdates(sidebar->presets_panel());
@ -2666,6 +2685,11 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
{
if (evt.status.percent >= -1) {
if (arranging || rotoptimizing) {
// Avoid a race condition
return;
}
this->statusbar()->set_progress(evt.status.percent);
this->statusbar()->set_status_text(_(L(evt.status.text)) + wxString::FromUTF8(""));
}
@ -3123,12 +3147,20 @@ bool Plater::priv::can_delete_all() const
bool Plater::priv::can_increase_instances() const
{
if (arranging || rotoptimizing) {
return false;
}
int obj_idx = get_selected_object_idx();
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size());
}
bool Plater::priv::can_decrease_instances() const
{
if (arranging || rotoptimizing) {
return false;
}
int obj_idx = get_selected_object_idx();
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
}
@ -3145,7 +3177,7 @@ bool Plater::priv::can_split_to_volumes() const
bool Plater::priv::can_arrange() const
{
return !model.objects.empty() && !arranging.load();
return !model.objects.empty() && !arranging;
}
bool Plater::priv::can_layers_editing() const
@ -3286,9 +3318,9 @@ void Plater::remove_selected()
void Plater::increase_instances(size_t num)
{
if (! can_increase_instances()) { return; }
int obj_idx = p->get_selected_object_idx();
if (obj_idx == -1)
return;
ModelObject* model_object = p->model.objects[obj_idx];
ModelInstance* model_instance = model_object->instances.back();
@ -3320,9 +3352,9 @@ void Plater::increase_instances(size_t num)
void Plater::decrease_instances(size_t num)
{
if (! can_decrease_instances()) { return; }
int obj_idx = p->get_selected_object_idx();
if (obj_idx == -1)
return;
ModelObject* model_object = p->model.objects[obj_idx];
if (model_object->instances.size() > num) {
@ -3618,7 +3650,7 @@ void Plater::on_extruders_change(int num_extruders)
choices.push_back(choice);
// initialize selection
wxGetApp().preset_bundle->update_platter_filament_ui(i, choice);
wxGetApp().preset_bundle->update_platter_filament_ui(i, choice, wxGetApp().em_unit());
++i;
}
@ -3768,6 +3800,36 @@ void Plater::changed_object(int obj_idx)
this->p->schedule_background_process();
}
void Plater::changed_objects(const std::vector<size_t>& object_idxs)
{
if (object_idxs.empty())
return;
auto list = wxGetApp().obj_list();
wxASSERT(list != nullptr);
if (list == nullptr)
return;
if (list->is_parts_changed()) {
for (int obj_idx : object_idxs)
{
if (obj_idx < p->model.objects.size())
// recenter and re - align to Z = 0
p->model.objects[obj_idx]->ensure_on_bed();
}
if (this->p->printer_technology == ptSLA) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data, update the 3D scene.
this->p->update_restart_background_process(true, false);
}
else
p->view3D->reload_scene(false);
}
// update print
this->p->schedule_background_process();
}
void Plater::schedule_background_process()
{
this->p->schedule_background_process();

View file

@ -167,6 +167,7 @@ public:
void reslice();
void reslice_SLA_supports(const ModelObject &object);
void changed_object(int obj_idx);
void changed_objects(const std::vector<size_t>& object_idxs);
void schedule_background_process();
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
void send_gcode();

View file

@ -60,7 +60,7 @@ void PreferencesDialog::build()
// Please keep in sync with ConfigWizard
def.label = L("Check for application updates");
def.type = coBool;
def.tooltip = L("If enabled, Slic3r checks for new versions of Slic3r PE online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
def.tooltip = L("If enabled, Slic3r checks for new versions of " SLIC3R_APP_NAME " online. When a new version becomes available a notification is displayed at the next application startup (never during program usage). This is only a notification mechanisms, no automatic installation is done.");
def.default_value = new ConfigOptionBool(app_config->get("version_check") == "1");
option = Option (def, "version_check");
m_optgroup->append_single_option_line(option);

View file

@ -1451,7 +1451,7 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
this->load_compatible_bitmaps(window);
}
void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui, const int em/* = 10*/)
{
if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA ||
this->filament_presets.size() <= idx_extruder )
@ -1476,6 +1476,18 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
wxString selected_str = "";
if (!this->filaments().front().is_visible)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
/* It's supposed that standard size of an icon is 16px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
* and scale then in respect to em_unit value
*/
const float scale_f = em * 0.1f;
const int icon_height = 16 * scale_f + 0.5f;
const int normal_icon_width = 16 * scale_f + 0.5f;
const int space_icon_width = 2 * scale_f + 0.5f;
const int wide_icon_width = 24 * scale_f + 0.5f;
const int thin_icon_width = 8 * scale_f + 0.5f;
for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++i) {
const Preset &preset = this->filaments.preset(i);
bool selected = this->filament_presets[idx_extruder] == preset.name;
@ -1499,17 +1511,17 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(16, 16) : *m_bitmapIncompatible);
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(normal_icon_width, icon_height) : *m_bitmapIncompatible);
// Paint the color bars.
parse_color(filament_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? 24 : 16, 16, rgb));
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? wide_icon_width : normal_icon_width, icon_height, rgb));
if (! single_bar) {
parse_color(extruder_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(8, 16, rgb));
bmps.emplace_back(m_bitmapCache->mksolid(thin_icon_width, icon_height, rgb));
}
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmapCache->mkclear(2, 16));
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmapLock : m_bitmapCache->mkclear(16, 16));
bmps.emplace_back(m_bitmapCache->mkclear(space_icon_width, icon_height));
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmapLock : m_bitmapCache->mkclear(normal_icon_width, icon_height));
// (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
bitmap = m_bitmapCache->insert(bitmap_key, bmps);
}

View file

@ -107,7 +107,7 @@ public:
void export_configbundle(const std::string &path, bool export_system_settings = false);
// Update a filament selection combo box on the platter for an idx_extruder.
void update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui);
void update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui, const int em = 10);
// Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed);

View file

@ -99,7 +99,7 @@ void Selection::set_model(Model* model)
update_valid();
}
void Selection::add(unsigned int volume_idx, bool as_single_selection)
void Selection::add(unsigned int volume_idx, bool as_single_selection, bool check_for_already_contained)
{
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
return;
@ -110,7 +110,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection)
return;
bool keep_instance_mode = (m_mode == Instance) && !as_single_selection;
bool already_contained = contains_volume(volume_idx);
bool already_contained = check_for_already_contained && contains_volume(volume_idx);
// resets the current list if needed
bool needs_reset = as_single_selection && !already_contained;

View file

@ -210,7 +210,7 @@ public:
EMode get_mode() const { return m_mode; }
void set_mode(EMode mode) { m_mode = mode; }
void add(unsigned int volume_idx, bool as_single_selection = true);
void add(unsigned int volume_idx, bool as_single_selection = true, bool check_for_already_contained = false);
void remove(unsigned int volume_idx);
void add_object(unsigned int object_idx, bool as_single_selection = true);

View file

@ -22,7 +22,7 @@ std::string get_main_info(bool format_as_html)
std::string line_end = format_as_html ? "<br>" : "\n";
if (!format_as_html)
out << b_start << SLIC3R_FORK_NAME << b_end << line_end;
out << b_start << SLIC3R_APP_NAME << b_end << line_end;
out << b_start << "Version: " << b_end << SLIC3R_VERSION << line_end;
out << b_start << "Build: " << b_end << SLIC3R_BUILD << line_end;
out << line_end;
@ -41,7 +41,7 @@ std::string get_main_info(bool format_as_html)
}
SysInfoDialog::SysInfoDialog()
: DPIDialog(NULL, wxID_ANY, _(L("Slic3r Prusa Edition - System Information")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("System Information")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
SetBackgroundColour(bgr_clr);
@ -64,7 +64,7 @@ SysInfoDialog::SysInfoDialog()
// title
{
wxStaticText* title = new wxStaticText(this, wxID_ANY, SLIC3R_FORK_NAME, wxDefaultPosition, wxDefaultSize);
wxStaticText* title = new wxStaticText(this, wxID_ANY, SLIC3R_APP_NAME, wxDefaultPosition, wxDefaultSize);
wxFont title_font = wxGetApp().bold_font();//wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
// title_font.SetWeight(wxFONTWEIGHT_BOLD);
title_font.SetFamily(wxFONTFAMILY_ROMAN);

View file

@ -27,7 +27,7 @@ static const std::string CONFIG_UPDATE_WIKI_URL("https://github.com/prusa3d/Slic
// MsgUpdateSlic3r
MsgUpdateSlic3r::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_online) :
MsgDialog(nullptr, _(L("Update available")), _(L("New version of Slic3r PE is available"))),
MsgDialog(nullptr, _(L("Update available")), wxString::Format(_(L("New version of %s is available")), SLIC3R_APP_NAME)),
ver_current(ver_current),
ver_online(ver_online)
{
@ -113,17 +113,17 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, w
{
logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192));
auto *text = new wxStaticText(this, wxID_ANY, _(L(
"This version of Slic3r PE is not compatible with currently installed configuration bundles.\n"
"This probably happened as a result of running an older Slic3r PE after using a newer one.\n\n"
auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
"This version of %s is not compatible with currently installed configuration bundles.\n"
"This probably happened as a result of running an older %s after using a newer one.\n\n"
"You may either exit Slic3r and try again with a newer version, or you may re-run the initial configuration. "
"Doing so will create a backup snapshot of the existing configuration before installing files compatible with this Slic3r.\n"
)));
)), SLIC3R_APP_NAME, SLIC3R_APP_NAME));
text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
content_sizer->Add(text);
auto *text2 = new wxStaticText(this, wxID_ANY, wxString::Format(_(L("This Slic3r PE version: %s")), SLIC3R_VERSION));
auto *text2 = new wxStaticText(this, wxID_ANY, wxString::Format(_(L("This %s version: %s")), SLIC3R_APP_NAME, SLIC3R_VERSION));
text2->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
content_sizer->Add(text2);
content_sizer->AddSpacer(VERT_SPACING);
@ -168,7 +168,7 @@ MsgDataLegacy::MsgDataLegacy() :
{
auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(
_(L(
"Slic3r PE now uses an updated configuration structure.\n\n"
"%s now uses an updated configuration structure.\n\n"
"So called 'System presets' have been introduced, which hold the built-in default settings for various "
"printers. These System presets cannot be modified, instead, users now may create their "
@ -178,7 +178,7 @@ MsgDataLegacy::MsgDataLegacy() :
"Please proceed with the %s that follows to set up the new presets "
"and to choose whether to enable automatic preset updates."
)),
ConfigWizard::name()
SLIC3R_APP_NAME, ConfigWizard::name()
));
text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
content_sizer->Add(text);

View file

@ -88,7 +88,7 @@ Http::priv::priv(const std::string &url)
set_timeout_connect(DEFAULT_TIMEOUT_CONNECT);
::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally
::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_FORK_NAME "/" SLIC3R_VERSION);
::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_APP_NAME "/" SLIC3R_VERSION);
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer.front());
}
@ -228,6 +228,7 @@ std::string Http::priv::body_size_error()
void Http::priv::http_perform()
{
::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
::curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb);
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this));
::curl_easy_setopt(curl, CURLOPT_READFUNCTION, form_file_read_cb);

View file

@ -208,7 +208,7 @@ void PresetUpdater::priv::sync_version() const
{
if (! enabled_version_check) { return; }
BOOST_LOG_TRIVIAL(info) << boost::format("Downloading Slic3rPE online version from: `%1%`") % version_check_url;
BOOST_LOG_TRIVIAL(info) << boost::format("Downloading %1% online version from: `%2%`") % SLIC3R_APP_NAME % version_check_url;
Http::get(version_check_url)
.size_limit(SLIC3R_VERSION_BODY_MAX)
@ -224,7 +224,7 @@ void PresetUpdater::priv::sync_version() const
})
.on_complete([&](std::string body, unsigned /* http_status */) {
boost::trim(body);
BOOST_LOG_TRIVIAL(info) << boost::format("Got Slic3rPE online version: `%1%`. Sending to GUI thread...") % body;
BOOST_LOG_TRIVIAL(info) << boost::format("Got %1% online version: `%2%`. Sending to GUI thread...") % SLIC3R_APP_NAME % body;
wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE);
evt->SetString(GUI::from_u8(body));

View file

@ -1,7 +1,8 @@
# Included by CMakeLists, edited by the build script
# (the version numbers are generated by the build script from the git current label)
set(SLIC3R_FORK_NAME "Slic3r Prusa Edition")
set(SLIC3R_APP_NAME "Slic3r Prusa Edition")
set(SLIC3R_APP_KEY "Slic3rPE")
set(SLIC3R_VERSION "1.42.0-beta2")
set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}")

View file

@ -180,6 +180,8 @@ SV*
TriangleMesh::slice(z)
std::vector<double> z
CODE:
THIS->require_shared_vertices(); // TriangleMeshSlicer needs this
// convert doubles to floats
std::vector<float> z_f = cast<float>(z);
@ -210,6 +212,7 @@ TriangleMesh::cut(z, upper, lower)
TriangleMesh* upper;
TriangleMesh* lower;
CODE:
THIS->require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer mslicer(THIS);
mslicer.cut(z, upper, lower);

View file

@ -32,7 +32,7 @@ DEBUG_OUT_PATH_PREFIX()
SV*
FORK_NAME()
CODE:
RETVAL = newSVpv(SLIC3R_FORK_NAME, 0);
RETVAL = newSVpv(SLIC3R_APP_NAME, 0);
OUTPUT: RETVAL
void