mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 04:02:52 -06:00 
			
		
		
		
	Merge branch 'ys_msw_dpi' of https://github.com/prusa3d/Slic3r into ys_msw_dpi
This commit is contained in:
		
						commit
						5e45cff855
					
				
					 55 changed files with 1384 additions and 1046 deletions
				
			
		|  | @ -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} | ||||
|  |  | |||
|  | @ -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. | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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
											
										
									
								
							|  | @ -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,19 +1054,39 @@ 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()) { | ||||
|     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)); | ||||
|         _write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001); | ||||
|             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; | ||||
|             _write_format(file, "; filament used = %.1lf\n", 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; | ||||
|                 _write_format(file, "; filament cost = %.1lf\n", filament_cost); | ||||
|                     append(out_filament_cost, "%.1lf", filament_cost); | ||||
|                 } | ||||
|             } | ||||
|             print.m_print_statistics.total_used_filament += used_filament; | ||||
|  | @ -1074,6 +1094,14 @@ void GCode::_do_export(Print &print, FILE *file) | |||
|             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) | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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,8 +573,9 @@ 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; | ||||
| 
 | ||||
|  | @ -582,7 +584,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | |||
| 
 | ||||
|                 // Invalid geometries would throw exceptions when arranging
 | ||||
|                 if(item.vertexCount() > 3) { | ||||
|                         item.rotation(objinst->get_rotation(Z)); | ||||
|                     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) | ||||
|  | @ -592,7 +594,6 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | |||
|             } | ||||
|         } | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
|  |  | |||
|  | @ -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 © : object->m_copies) { | ||||
|                     Polygon p = convex_hull; | ||||
|                     p.translate(copy); | ||||
|                     if (! intersection(convex_hulls_other, p).empty()) | ||||
|                 for (const Point © : 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); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -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); | ||||
|      | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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@" | ||||
| 
 | ||||
|  |  | |||
|  | @ -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" | ||||
|   } | ||||
|  } | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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"); | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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)); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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,7 +3698,7 @@ 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) { | ||||
|         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?
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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
 | ||||
| 		::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); | ||||
|         ::glColor3f(1.0f, 0.37f, 0.0f); | ||||
|         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:
 | ||||
|     if (m_clipping_plane_distance == 0.f) | ||||
|         m_imgui->text("Clipping of view: "); | ||||
|     ImGui::SameLine(); | ||||
|     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
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -14,7 +14,10 @@ enum class SLAGizmoEventType { | |||
|     ApplyChanges, | ||||
|     DiscardChanges, | ||||
|     AutomaticGeneration, | ||||
|     ManualEditing | ||||
|     ManualEditing, | ||||
|     MouseWheelUp, | ||||
|     MouseWheelDown, | ||||
|     ResetClippingPlane | ||||
| }; | ||||
| 
 | ||||
| #include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" | ||||
|  |  | |||
|  | @ -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())) | ||||
|         { | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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"))); | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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();     | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
| 		} | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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)); | ||||
|  |  | |||
|  | @ -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}") | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv