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 | # l10n | ||||||
| set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") | set(L10N_DIR "${SLIC3R_RESOURCES_DIR}/localization") | ||||||
| add_custom_target(pot | 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" |         -f "${L10N_DIR}/list.txt" | ||||||
|         -o "${L10N_DIR}/Slic3rPE.pot" |         -o "${L10N_DIR}/Slic3rPE.pot" | ||||||
|     WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} |     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. | 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. | 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: | 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 |     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 id="layers"> | ||||||
| 	<g> | 	<g> | ||||||
| 		<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> | ||||||
| 		<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> | ||||||
| 		<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> | ||||||
| 		<g> | 		<g> | ||||||
| 			<rect x="1" y="5.79" fill="#ED6B21" width="14" height="1.2"/> | 			<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"/> | 			<rect x="1" y="3.39" fill="#ED6B21" width="14" height="0.93"/> | ||||||
| 		</g> | 		</g> | ||||||
| 		<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> | 	</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
 |     // 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
 |     // 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 start_pos = tcr.start_pos; | ||||||
|     WipeTower::xy end_pos = tcr.end_pos; |     WipeTower::xy end_pos = tcr.end_pos; | ||||||
|     start_pos.rotate(alpha); |     start_pos.rotate(alpha); | ||||||
|  | @ -519,43 +519,43 @@ void GCode::_do_export(Print &print, FILE *file) | ||||||
|     // this->print_machine_envelope(file, print);
 |     // this->print_machine_envelope(file, print);
 | ||||||
|     // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
 |     // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
 | ||||||
|     if (print.config().gcode_flavor.value == gcfMarlin) { |     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_max_acceleration((float)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_retract_acceleration((float)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_feedrate((float)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_minimum_travel_feedrate((float)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::X, (float)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::Y, (float)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::Z, (float)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_acceleration(GCodeTimeEstimator::E, (float)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::X, (float)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::Y, (float)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::Z, (float)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_feedrate(GCodeTimeEstimator::E, (float)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::X, (float)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::Y, (float)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::Z, (float)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_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]); | ||||||
| 
 | 
 | ||||||
|         if (m_silent_time_estimator_enabled) |         if (m_silent_time_estimator_enabled) | ||||||
|         { |         { | ||||||
|             m_silent_time_estimator.reset(); |             m_silent_time_estimator.reset(); | ||||||
|             m_silent_time_estimator.set_dialect(print.config().gcode_flavor); |             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_max_acceleration((float)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_retract_acceleration((float)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_feedrate((float)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_minimum_travel_feedrate((float)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::X, (float)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::Y, (float)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::Z, (float)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_acceleration(GCodeTimeEstimator::E, (float)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::X, (float)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::Y, (float)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::Z, (float)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_feedrate(GCodeTimeEstimator::E, (float)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::X, (float)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::Y, (float)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::Z, (float)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_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[1]); | ||||||
|             if (print.config().single_extruder_multi_material) { |             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
 |                 // 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.
 |                 // are considered to be active for the single extruder multi-material printers only.
 | ||||||
|  | @ -1054,26 +1054,54 @@ void GCode::_do_export(Print &print, FILE *file) | ||||||
|     print.m_print_statistics.clear(); |     print.m_print_statistics.clear(); | ||||||
|     print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms(); |     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"; |     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(); | ||||||
|         double used_filament   = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f); |     if (! extruders.empty()) { | ||||||
|         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
 |         std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0); | ||||||
|         double filament_weight = extruded_volume * extruder.filament_density() * 0.001; |         std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0); | ||||||
|         double filament_cost   = filament_weight * extruder.filament_cost()    * 0.001; |         std::pair<std::string, unsigned int> out_filament_used_g  ("; filament used [g] = ", 0); | ||||||
|         print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament)); |         std::pair<std::string, unsigned int> out_filament_cost    ("; filament cost = ", 0); | ||||||
|         _write_format(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001); |         for (const Extruder &extruder : extruders) { | ||||||
|         if (filament_weight > 0.) { |             double used_filament   = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f); | ||||||
|             print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight; |             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
 | ||||||
|             _write_format(file, "; filament used = %.1lf\n", filament_weight); |             double filament_weight = extruded_volume * extruder.filament_density() * 0.001; | ||||||
|             if (filament_cost > 0.) { |             double filament_cost   = filament_weight * extruder.filament_cost()    * 0.001; | ||||||
|                 print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost; |             auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) { | ||||||
|                 _write_format(file, "; filament cost = %.1lf\n", filament_cost); |                 while (dst.second < extruder.id()) { | ||||||
|  |                     // Fill in the non-printing extruders with zeros.
 | ||||||
|  |                     dst.first += (dst.second > 0) ? ", 0" : "0"; | ||||||
|  |                     ++ dst.second; | ||||||
|  |                 } | ||||||
|  |                 if (dst.second > 0) | ||||||
|  |                     dst.first += ", "; | ||||||
|  |                 char buf[64]; | ||||||
|  | 				sprintf(buf, tmpl, value); | ||||||
|  |                 dst.first += buf; | ||||||
|  |                 ++ dst.second; | ||||||
|  |             }; | ||||||
|  |             print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>(extruder.id(), (float)used_filament)); | ||||||
|  |             append(out_filament_used_mm,  "%.1lf", used_filament); | ||||||
|  |             append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001); | ||||||
|  |             if (filament_weight > 0.) { | ||||||
|  |                 print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight; | ||||||
|  |                 append(out_filament_used_g, "%.1lf", filament_weight); | ||||||
|  |                 if (filament_cost > 0.) { | ||||||
|  |                     print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost; | ||||||
|  |                     append(out_filament_cost, "%.1lf", filament_cost); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |             print.m_print_statistics.total_used_filament += used_filament; | ||||||
|  |             print.m_print_statistics.total_extruded_volume += extruded_volume; | ||||||
|  |             print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.; | ||||||
|  |             print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.; | ||||||
|         } |         } | ||||||
|         print.m_print_statistics.total_used_filament += used_filament; |         _writeln(file, out_filament_used_mm.first); | ||||||
|         print.m_print_statistics.total_extruded_volume += extruded_volume; | 		_writeln(file, out_filament_used_cm3.first); | ||||||
|         print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.; | 		if (out_filament_used_g.second) | ||||||
|         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_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, "; 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()); |     _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) |     if (m_silent_time_estimator_enabled) | ||||||
|  | @ -1528,7 +1556,7 @@ void GCode::process_layer( | ||||||
|                             std::max<int>(region.config().perimeter_extruder.value - 1, 0); |                             std::max<int>(region.config().perimeter_extruder.value - 1, 0); | ||||||
| 
 | 
 | ||||||
|                         // Let's recover vector of extruder overrides:
 |                         // 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:
 |                         // 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) |                         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 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 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; |     const float WT_EPSILON            = 1e-3f; | ||||||
| 
 | 
 | ||||||
|  | @ -224,8 +224,8 @@ private: | ||||||
|     bool 			m_retain_speed_override		= true; |     bool 			m_retain_speed_override		= true; | ||||||
|     bool            m_adhesion                  = 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_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.038; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
 | 	float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     struct FilamentParameters { |     struct FilamentParameters { | ||||||
|  | @ -269,12 +269,12 @@ private: | ||||||
| 	{ | 	{ | ||||||
| 		if ( layer_height < 0 ) | 		if ( layer_height < 0 ) | ||||||
| 			return m_extrusion_flow; | 			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
 | 	// Calculates length of extrusion line to extrude given volume
 | ||||||
| 	float volume_to_length(float volume, float line_width, float layer_height) const { | 	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
 | 	// 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
 | #endif // ENABLE_MOVE_STATS
 | ||||||
| 
 | 
 | ||||||
| namespace Slic3r { | namespace Slic3r { | ||||||
| 
 |  | ||||||
|     void GCodeTimeEstimator::Feedrates::reset() |     void GCodeTimeEstimator::Feedrates::reset() | ||||||
|     { |     { | ||||||
|         feedrate = 0.0f; |         feedrate = 0.0f; | ||||||
|  | @ -695,6 +694,8 @@ namespace Slic3r { | ||||||
|         set_axis_position(X, 0.0f); |         set_axis_position(X, 0.0f); | ||||||
|         set_axis_position(Y, 0.0f); |         set_axis_position(Y, 0.0f); | ||||||
|         set_axis_position(Z, 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); |         set_additional_time(0.0f); | ||||||
| 
 | 
 | ||||||
|  | @ -715,7 +716,6 @@ namespace Slic3r { | ||||||
|         _blocks.clear(); |         _blocks.clear(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     void GCodeTimeEstimator::_calculate_time() |     void GCodeTimeEstimator::_calculate_time() | ||||||
|     { |     { | ||||||
|         PROFILE_FUNC(); |         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.
 | // 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 cheap in that it does not make any unnecessary copy of the volume meshes.
 | ||||||
| // This method is used by the auto arrange function.
 | // 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; |     Points pts; | ||||||
|     for (const ModelVolume *v : this->volumes) |     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); |             volume->mesh.transform(instance_matrix * volume_matrix, true); | ||||||
| 
 | 
 | ||||||
|             // Perform cut
 |             // Perform cut
 | ||||||
|  |             volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
 | ||||||
|             TriangleMeshSlicer tms(&volume->mesh); |             TriangleMeshSlicer tms(&volume->mesh); | ||||||
|             tms.cut(float(z), &upper_mesh, &lower_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.
 |     // 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 cheap in that it does not make any unnecessary copy of the volume meshes.
 | ||||||
|     // This method is used by the auto arrange function.
 |     // 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 | #if ENABLE_VOLUMES_CENTERING_FIXES | ||||||
|     void center_around_origin(bool include_modifiers = true); |     void center_around_origin(bool include_modifiers = true); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include "ModelArrange.hpp" | #include "ModelArrange.hpp" | ||||||
| #include "Model.hpp" | #include "Model.hpp" | ||||||
|  | #include "Geometry.hpp" | ||||||
| #include "SVG.hpp" | #include "SVG.hpp" | ||||||
| 
 | 
 | ||||||
| #include <libnest2d.h> | #include <libnest2d.h> | ||||||
|  | @ -551,7 +552,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | ||||||
|     ret.reserve(s); |     ret.reserve(s); | ||||||
| 
 | 
 | ||||||
|     for(ModelObject* objptr : model.objects) { |     for(ModelObject* objptr : model.objects) { | ||||||
|         if(objptr) { |         if (! objptr->instances.empty()) { | ||||||
| 
 | 
 | ||||||
|             // TODO export the exact 2D projection. Cannot do it as libnest2d
 |             // TODO export the exact 2D projection. Cannot do it as libnest2d
 | ||||||
|             // does not support concave shapes (yet).
 |             // does not support concave shapes (yet).
 | ||||||
|  | @ -572,23 +573,23 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | ||||||
|                 clpath = Slic3rMultiPoint_to_ClipperPath(p); |                 clpath = Slic3rMultiPoint_to_ClipperPath(p); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             Vec3d rotation0 = objptr->instances.front()->get_rotation(); | ||||||
|  |             rotation0(2) = 0.; | ||||||
|             for(ModelInstance* objinst : objptr->instances) { |             for(ModelInstance* objinst : objptr->instances) { | ||||||
|                 if(objinst) { |                 ClipperLib::Polygon pn; | ||||||
|                     ClipperLib::Polygon pn; |                 pn.Contour = clpath; | ||||||
|                     pn.Contour = clpath; |  | ||||||
| 
 | 
 | ||||||
|                     // Efficient conversion to item.
 |                 // Efficient conversion to item.
 | ||||||
|                     Item item(std::move(pn)); |                 Item item(std::move(pn)); | ||||||
| 
 | 
 | ||||||
|                     // Invalid geometries would throw exceptions when arranging
 |                 // Invalid geometries would throw exceptions when arranging
 | ||||||
|                     if(item.vertexCount() > 3) { |                 if(item.vertexCount() > 3) { | ||||||
|                         item.rotation(objinst->get_rotation(Z)); |                     item.rotation(float(Geometry::rotation_diff_z(rotation0, objinst->get_rotation()))), | ||||||
|                         item.translation({ |                     item.translation({ | ||||||
|                         ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), |                     ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), | ||||||
|                         ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) |                     ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) | ||||||
|                         }); |                     }); | ||||||
|                         ret.emplace_back(objinst, item); |                     ret.emplace_back(objinst, item); | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1139,31 +1139,29 @@ std::string Print::validate() const | ||||||
|         // Check horizontal clearance.
 |         // Check horizontal clearance.
 | ||||||
|         { |         { | ||||||
|             Polygons convex_hulls_other; |             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.
 |                 // Get convex hull of all meshes assigned to this print object.
 | ||||||
|                 Polygon convex_hull; |                 ModelInstance *model_instance0 = print_object->model_object()->instances.front(); | ||||||
|                 { |                 Vec3d          rotation        = model_instance0->get_rotation(); | ||||||
|                     Polygons mesh_convex_hulls; |                 rotation.z() = 0.; | ||||||
|                     for (const std::vector<int> &volumes : object->region_volumes) |                 // Calculate the convex hull of a printable object centered around X=0,Y=0. 
 | ||||||
|                         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); |  | ||||||
|                 // Grow convex hull with the clearance margin.
 |                 // Grow convex hull with the clearance margin.
 | ||||||
|                 // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
 |                 // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
 | ||||||
|                 // which causes that the warning will be showed after arrangement with the
 |                 // 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.
 |                 // 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.
 |                 // Now we check that no instance of convex_hull intersects any of the previously checked object instances.
 | ||||||
|                 for (const Point © : object->m_copies) { |                 for (const Point © : print_object->m_copies) { | ||||||
|                     Polygon p = convex_hull; |                     Polygon convex_hull = convex_hull0; | ||||||
|                     p.translate(copy); |                     convex_hull.translate(copy); | ||||||
|                     if (! intersection(convex_hulls_other, p).empty()) |                     if (! intersection(convex_hulls_other, convex_hull).empty()) | ||||||
|                         return L("Some objects are too close; your extruder will collide with them."); |                         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:
 |     // Actions:
 | ||||||
|     def = this->add("export_obj", coBool); |     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->tooltip = L("Export the model(s) as OBJ."); | ||||||
|     def->default_value = new ConfigOptionBool(false); |     def->default_value = new ConfigOptionBool(false); | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -1813,6 +1813,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, | ||||||
|             TriangleMeshSlicer mslicer; |             TriangleMeshSlicer mslicer; | ||||||
|             const Print *print = this->print(); |             const Print *print = this->print(); | ||||||
|             auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); |             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.init(&mesh, callback); | ||||||
| 			mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); | 			mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); | ||||||
|             m_print->throw_if_canceled(); |             m_print->throw_if_canceled(); | ||||||
|  | @ -1840,6 +1841,7 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, | ||||||
|         TriangleMeshSlicer mslicer; |         TriangleMeshSlicer mslicer; | ||||||
|         const Print *print = this->print(); |         const Print *print = this->print(); | ||||||
|         auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();}); |         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.init(&mesh, callback); | ||||||
|         mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); |         mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback); | ||||||
|         m_print->throw_if_canceled(); |         m_print->throw_if_canceled(); | ||||||
|  |  | ||||||
|  | @ -552,6 +552,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h, | ||||||
|                 float layerh, ThrowOnCancel thrfn) |                 float layerh, ThrowOnCancel thrfn) | ||||||
| { | { | ||||||
|     TriangleMesh m = mesh; |     TriangleMesh m = mesh; | ||||||
|  |     m.require_shared_vertices(); // TriangleMeshSlicer needs this
 | ||||||
|     TriangleMeshSlicer slicer(&m); |     TriangleMeshSlicer slicer(&m); | ||||||
| 
 | 
 | ||||||
|     auto bb = mesh.bounding_box(); |     auto bb = mesh.bounding_box(); | ||||||
|  |  | ||||||
|  | @ -817,6 +817,10 @@ public: | ||||||
| 
 | 
 | ||||||
|         meshcache = mesh(merged); |         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?
 |         // TODO: Is this necessary?
 | ||||||
|         //meshcache.repair();
 |         //meshcache.repair();
 | ||||||
| 
 | 
 | ||||||
|  | @ -2231,6 +2235,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | ||||||
| 
 | 
 | ||||||
|     TriangleMesh fullmesh = m_impl->merged_mesh(); |     TriangleMesh fullmesh = m_impl->merged_mesh(); | ||||||
|     fullmesh.merge(get_pad()); |     fullmesh.merge(get_pad()); | ||||||
|  |     fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
 | ||||||
|     TriangleMeshSlicer slicer(&fullmesh); |     TriangleMeshSlicer slicer(&fullmesh); | ||||||
|     SlicedSupports ret; |     SlicedSupports ret; | ||||||
|     slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn); |     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(); |     TriangleMesh fullmesh = m_impl->merged_mesh(); | ||||||
|     fullmesh.merge(get_pad()); |     fullmesh.merge(get_pad()); | ||||||
|  |     fullmesh.require_shared_vertices(); // TriangleMeshSlicer needs this
 | ||||||
|     TriangleMeshSlicer slicer(&fullmesh); |     TriangleMeshSlicer slicer(&fullmesh); | ||||||
|     SlicedSupports ret; |     SlicedSupports ret; | ||||||
|     slicer.slice(heights, cr, &ret, get().ctl().cancelfn); |     slicer.slice(heights, cr, &ret, get().ctl().cancelfn); | ||||||
|  |  | ||||||
|  | @ -598,8 +598,9 @@ std::string SLAPrint::validate() const | ||||||
|     for(SLAPrintObject * po : m_objects) { |     for(SLAPrintObject * po : m_objects) { | ||||||
| 
 | 
 | ||||||
|         const ModelObject *mo = po->model_object(); |         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_points_status == sla::PointsStatus::UserModified && | ||||||
|            mo->sla_support_points.empty()) |            mo->sla_support_points.empty()) | ||||||
|             return L("Cannot proceed without support points! " |             return L("Cannot proceed without support points! " | ||||||
|  | @ -613,7 +614,7 @@ std::string SLAPrint::validate() const | ||||||
|                 2 * cfg.head_back_radius_mm - |                 2 * cfg.head_back_radius_mm - | ||||||
|                 cfg.head_penetration_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."); |             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))); |                 po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z))); | ||||||
| 
 | 
 | ||||||
|         if(slindex_it == po.m_slice_index.end()) |         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 " |             throw std::runtime_error(L("Slicing had to be stopped " | ||||||
|                                        "due to an internal error.")); |                                        "due to an internal error.")); | ||||||
| 
 | 
 | ||||||
|  | @ -706,6 +708,7 @@ void SLAPrint::process() | ||||||
|             po.m_model_height_levels.emplace_back(it->slice_level()); |             po.m_model_height_levels.emplace_back(it->slice_level()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
 | ||||||
|         TriangleMeshSlicer slicer(&mesh); |         TriangleMeshSlicer slicer(&mesh); | ||||||
| 
 | 
 | ||||||
|         po.m_model_slices.clear(); |         po.m_model_slices.clear(); | ||||||
|  |  | ||||||
|  | @ -160,17 +160,13 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object | ||||||
|         m_support_material_interface_flow = m_support_material_flow; |         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.
 |     // Evaluate the XY gap between the object outer perimeters and the support structures.
 | ||||||
|     coordf_t external_perimeter_width = 0.; |     coordf_t external_perimeter_width = 0.; | ||||||
|     for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { |     for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) | ||||||
|         if (! object->region_volumes[region_id].empty()) { |         if (! object->region_volumes[region_id].empty()) | ||||||
|             const PrintRegionConfig &config = object->print()->get_region(region_id)->config(); |             external_perimeter_width = std::max(external_perimeter_width, | ||||||
|             coordf_t width = config.external_perimeter_extrusion_width.get_abs_value(slicing_params.layer_height); |                 (coordf_t)object->print()->get_region(region_id)->flow(frExternalPerimeter, slicing_params.layer_height, false, false, -1, *object).width); | ||||||
|             if (width <= 0.) |  | ||||||
|                 width = m_print_config->nozzle_diameter.get_at(config.perimeter_extruder-1); |  | ||||||
|             external_perimeter_width = std::max(external_perimeter_width, width); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     m_gap_xy = m_object_config->support_material_xy_spacing.get_abs_value(external_perimeter_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; |     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"; |     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 = _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(); |     throw_on_cancel(); | ||||||
|     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1); |     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); |     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; |     TriangleMesh convex_hull_3d() const; | ||||||
|     void reset_repair_stats(); |     void reset_repair_stats(); | ||||||
|     bool needed_repair() const; |     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; } |     size_t facets_count() const { return this->stl.stats.number_of_facets; } | ||||||
|     bool   empty() const { return this->facets_count() == 0; } |     bool   empty() const { return this->facets_count() == 0; } | ||||||
| 
 |  | ||||||
|     bool is_splittable() const; |     bool is_splittable() const; | ||||||
| 
 | 
 | ||||||
|     stl_file stl; |     stl_file stl; | ||||||
|     bool repaired; |     bool repaired; | ||||||
|      | 
 | ||||||
| private: | private: | ||||||
|     void require_shared_vertices(); |  | ||||||
|     std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const; |     std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const; | ||||||
|     friend class TriangleMeshSlicer; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum FacetEdgeType {  | enum FacetEdgeType {  | ||||||
|  | @ -159,9 +158,8 @@ class TriangleMeshSlicer | ||||||
| public: | public: | ||||||
|     typedef std::function<void()> throw_on_cancel_callback_type; |     typedef std::function<void()> throw_on_cancel_callback_type; | ||||||
|     TriangleMeshSlicer() : mesh(nullptr) {} |     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(const TriangleMesh* mesh) { this->init(mesh, [](){}); } | ||||||
| 	TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); } |     void init(const TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel); | ||||||
|     void init(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, 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; |     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 { |     enum FacetSliceType { | ||||||
|  |  | ||||||
|  | @ -88,7 +88,7 @@ std::string string_printf(const char *format, ...); | ||||||
| extern std::string timestamp_str(); | extern std::string timestamp_str(); | ||||||
| // Standard "generated by Slic3r version xxx timestamp xxx" header string, 
 | // Standard "generated by Slic3r version xxx timestamp xxx" header string, 
 | ||||||
| // to be placed at the top of Slic3r generated files.
 | // 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
 | // getpid platform wrapper
 | ||||||
| extern unsigned get_current_pid(); | extern unsigned get_current_pid(); | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| #ifndef __SLIC3R_VERSION_H | #ifndef __SLIC3R_VERSION_H | ||||||
| #define __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_VERSION "@SLIC3R_VERSION@" | ||||||
| #define SLIC3R_BUILD "@SLIC3R_BUILD@" | #define SLIC3R_BUILD "@SLIC3R_BUILD@" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,12 +7,12 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@ | ||||||
|   BLOCK "040904E4" |   BLOCK "040904E4" | ||||||
|   { |   { | ||||||
|    VALUE "CompanyName", "Prusa Research" |    VALUE "CompanyName", "Prusa Research" | ||||||
|    VALUE "FileDescription", "Slic3r Prusa Edition" |    VALUE "FileDescription", "@SLIC3R_APP_NAME@" | ||||||
|    VALUE "FileVersion", "@SLIC3R_BUILD_ID@" |    VALUE "FileVersion", "@SLIC3R_BUILD_ID@" | ||||||
|    VALUE "ProductName", "Slic3r Prusa Edition" |    VALUE "ProductName", "@SLIC3R_APP_NAME@" | ||||||
|    VALUE "ProductVersion", "@SLIC3R_BUILD_ID@" |    VALUE "ProductVersion", "@SLIC3R_BUILD_ID@" | ||||||
|    VALUE "InternalName", "Slic3r Prusa Edition" |    VALUE "InternalName", "@SLIC3R_APP_NAME@" | ||||||
|    VALUE "LegalCopyright", "Copyright \251 2011-2017 Alessandro Ranelucci, \251 2016 Prusa Research" |    VALUE "LegalCopyright", "Copyright \251 2011-2019 Alessandro Ranelucci, \251 2016-2019 Prusa Research" | ||||||
|    VALUE "OriginalFilename", "slic3r.exe" |    VALUE "OriginalFilename", "slic3r.exe" | ||||||
|   } |   } | ||||||
|  } |  } | ||||||
|  |  | ||||||
|  | @ -3,15 +3,15 @@ | ||||||
| <plist version="1.0"> | <plist version="1.0"> | ||||||
| <dict> | <dict> | ||||||
|   <key>CFBundleExecutable</key> |   <key>CFBundleExecutable</key> | ||||||
|   <string>Slic3r</string> |   <string>@SLIC3R_APP_KEY@</string> | ||||||
|   <key>CFBundleGetInfoString</key> |   <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> |   <key>CFBundleIconFile</key> | ||||||
|   <string>Slic3r.icns</string> |   <string>Slic3r.icns</string> | ||||||
|   <key>CFBundleName</key> |   <key>CFBundleName</key> | ||||||
|   <string>Slic3r</string> |   <string>@SLIC3R_APP_KEY@</string> | ||||||
|   <key>CFBundleShortVersionString</key> |   <key>CFBundleShortVersionString</key> | ||||||
|   <string>Slic3r @SLIC3R_BUILD_ID@</string> |   <string>@SLIC3R_APP_NAME@ @SLIC3R_BUILD_ID@</string> | ||||||
|   <key>CFBundleIdentifier</key> |   <key>CFBundleIdentifier</key> | ||||||
|   <string>com.prusa3d.slic3r/</string> |   <string>com.prusa3d.slic3r/</string> | ||||||
|   <key>CFBundleInfoDictionaryVersion</key> |   <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  | void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const  | ||||||
| { | { | ||||||
|     boost::nowide::cout |     boost::nowide::cout | ||||||
| 		<< "Slic3r Prusa Edition " << SLIC3R_BUILD  | 		<< SLIC3R_APP_NAME << " " << SLIC3R_BUILD  | ||||||
| #ifdef SLIC3R_GUI | #ifdef SLIC3R_GUI | ||||||
|         << " (with GUI support)" |         << " (with GUI support)" | ||||||
| #else /* SLIC3R_GUI */ | #else /* SLIC3R_GUI */ | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ void AboutDialogLogo::onRepaint(wxEvent &event) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AboutDialog::AboutDialog() | 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) |                 wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) | ||||||
| { | { | ||||||
|     SetFont(wxGetApp().normal_font()); |     SetFont(wxGetApp().normal_font()); | ||||||
|  | @ -55,7 +55,7 @@ AboutDialog::AboutDialog() | ||||||
| 
 | 
 | ||||||
|     // title
 |     // 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);
 |         wxFont title_font = GUI::wxGetApp().bold_font();// wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
 | ||||||
| //         title_font.SetWeight(wxFONTWEIGHT_BOLD);
 | //         title_font.SetWeight(wxFONTWEIGHT_BOLD);
 | ||||||
|         title_font.SetFamily(wxFONTFAMILY_ROMAN); |         title_font.SetFamily(wxFONTFAMILY_ROMAN); | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| #include "libslic3r/Utils.hpp" | #include "libslic3r/Utils.hpp" | ||||||
| #include "libslic3r/GCode/PostProcessor.hpp" | #include "libslic3r/GCode/PostProcessor.hpp" | ||||||
| #include "libslic3r/GCode/PreviewData.hpp" | #include "libslic3r/GCode/PreviewData.hpp" | ||||||
|  | #include "libslic3r/libslic3r.h" | ||||||
| 
 | 
 | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
|  | @ -390,7 +391,7 @@ void BackgroundSlicingProcess::prepare_upload() | ||||||
| 
 | 
 | ||||||
| 	// Generate a unique temp path to which the gcode/zip file is copied/exported
 | 	// 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::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) { | 	if (m_print == m_fff_print) { | ||||||
| 		m_print->set_status(95, "Running post-processing scripts"); | 		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) | 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); |     wxImage image(width, height); | ||||||
|     image.InitAlpha(); |     image.InitAlpha(); | ||||||
|     unsigned char* imgdata = image.GetData(); |     unsigned char* imgdata = image.GetData(); | ||||||
|  |  | ||||||
|  | @ -281,13 +281,14 @@ void ConfigWizardPage::append_spacer(int space) | ||||||
| // Wizard pages
 | // Wizard pages
 | ||||||
| 
 | 
 | ||||||
| PageWelcome::PageWelcome(ConfigWizard *parent) | 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) |     , cbox_reset(nullptr) | ||||||
| { | { | ||||||
|     if (wizard_p()->run_reason == ConfigWizard::RR_DATA_EMPTY) { |     if (wizard_p()->run_reason == ConfigWizard::RR_DATA_EMPTY) { | ||||||
|         wxString::Format(_(L("Run %s")), ConfigWizard::name()); |         wxString::Format(_(L("Run %s")), ConfigWizard::name()); | ||||||
|         append_text(wxString::Format( |         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()) |             ConfigWizard::name()) | ||||||
|         ); |         ); | ||||||
|     } else { |     } else { | ||||||
|  | @ -398,7 +399,9 @@ PageUpdate::PageUpdate(ConfigWizard *parent) | ||||||
|     auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for application updates"))); |     auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for application updates"))); | ||||||
|     box_slic3r->SetValue(app_config->get("version_check") == "1"); |     box_slic3r->SetValue(app_config->get("version_check") == "1"); | ||||||
|     append(box_slic3r); |     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); |     append_spacer(VERTICAL_SPACING); | ||||||
| 
 | 
 | ||||||
|  | @ -420,7 +423,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent) | ||||||
| PageVendors::PageVendors(ConfigWizard *parent) | PageVendors::PageVendors(ConfigWizard *parent) | ||||||
|     : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) |     : 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); |     auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); | ||||||
|     boldfont.SetWeight(wxFONTWEIGHT_BOLD); |     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 yoff_text = bullet_h > em_h ? (bullet_h - em_h) / 2 : 0; | ||||||
|     const int yinc = item_height(); |     const int yinc = item_height(); | ||||||
| 
 | 
 | ||||||
|  |     int index_width = 0; | ||||||
|  | 
 | ||||||
|     unsigned y = 0; |     unsigned y = 0; | ||||||
|     for (size_t i = 0; i < items.size(); i++) { |     for (size_t i = 0; i < items.size(); i++) { | ||||||
|         const Item& item = items[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_black.bmp(), x, y + yoff_icon, false); } | ||||||
|         else if (i > item_active)  { dc.DrawBitmap(bullet_white.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; |         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) |         if (v->is_modifier) | ||||||
|             v->force_transparent = enable; |             v->force_transparent = enable; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     set_as_dirty(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GLCanvas3D::enable_legend_texture(bool enable) | void GLCanvas3D::enable_legend_texture(bool enable) | ||||||
|  | @ -1654,7 +1656,7 @@ void GLCanvas3D::render() | ||||||
| #endif // !ENABLE_SVG_ICONS
 | #endif // !ENABLE_SVG_ICONS
 | ||||||
|     _render_toolbar(); |     _render_toolbar(); | ||||||
|     _render_view_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); |         m_layers_editing.render_overlay(*this); | ||||||
| 
 | 
 | ||||||
|     wxGetApp().imgui()->render(); |     wxGetApp().imgui()->render(); | ||||||
|  | @ -2254,6 +2256,22 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) | ||||||
| #endif /* __APPLE__ */ | #endif /* __APPLE__ */ | ||||||
|                 post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); |                 post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); | ||||||
|         break; |         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__ | #ifdef __APPLE__ | ||||||
|         case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
 |         case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
 | ||||||
| #else /* __APPLE__ */ | #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
 |     // Calculate the zoom delta and apply it to the current zoom factor
 | ||||||
|     float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); |     float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); | ||||||
|     set_camera_zoom(zoom); |     set_camera_zoom(zoom); | ||||||
|  | @ -2596,7 +2618,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | ||||||
|                         m_selection.remove(m_hover_volume_id); |                         m_selection.remove(m_hover_volume_id); | ||||||
|                     else |                     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; |                         m_mouse.drag.move_requires_threshold = !already_selected; | ||||||
|                         if (already_selected) |                         if (already_selected) | ||||||
|                             m_mouse.set_move_start_threshold_position_2D_as_invalid(); |                             m_mouse.set_move_start_threshold_position_2D_as_invalid(); | ||||||
|  | @ -3676,8 +3698,8 @@ void GLCanvas3D::_render_objects() const | ||||||
|         m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data()); |         m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data()); | ||||||
| 
 | 
 | ||||||
|         m_shader.start_using(); |         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; |             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) { |             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?
 |                 // Which volume to paint without the layer height profile shader?
 | ||||||
|                 return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); |                 return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "../Utils/PresetUpdater.hpp" | #include "../Utils/PresetUpdater.hpp" | ||||||
| #include "../Utils/PrintHost.hpp" | #include "../Utils/PrintHost.hpp" | ||||||
| #include "ConfigWizard_private.hpp" | #include "ConfigWizard.hpp" | ||||||
| #include "slic3r/Config/Snapshot.hpp" | #include "slic3r/Config/Snapshot.hpp" | ||||||
| #include "ConfigSnapshotDialog.hpp" | #include "ConfigSnapshotDialog.hpp" | ||||||
| #include "FirmwareDialog.hpp" | #include "FirmwareDialog.hpp" | ||||||
|  | @ -149,8 +149,8 @@ bool GUI_App::on_init_inner() | ||||||
|     wxCHECK_MSG(wxDirExists(resources_dir), false, |     wxCHECK_MSG(wxDirExists(resources_dir), false, | ||||||
|         wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir)); |         wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir)); | ||||||
| 
 | 
 | ||||||
|     SetAppName("Slic3rPE-beta"); |     SetAppName(SLIC3R_APP_KEY "-beta"); | ||||||
|     SetAppDisplayName("Slic3r Prusa Edition"); |     SetAppDisplayName(SLIC3R_APP_NAME); | ||||||
| 
 | 
 | ||||||
| // Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
 | // Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
 | ||||||
| //    wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0);
 | //    wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0);
 | ||||||
|  | @ -230,7 +230,7 @@ bool GUI_App::on_init_inner() | ||||||
|         // and after MainFrame is created & shown.
 |         // and after MainFrame is created & shown.
 | ||||||
|         // The extra CallAfter() is needed because of Mac, where this is the only way
 |         // 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.
 |         // 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.
 |         // Neither wxShowEvent nor wxWindowCreateEvent work reliably.
 | ||||||
|         static bool once = true; |         static bool once = true; | ||||||
|         if (once) { |         if (once) { | ||||||
|  | @ -381,7 +381,7 @@ void GUI_App::recreate_GUI() | ||||||
|         topwindow->Destroy(); |         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())); |     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 = new wxLocale; | ||||||
|         m_wxLocale->Init(identifiers[index]); |         m_wxLocale->Init(identifiers[index]); | ||||||
| 		m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir())); | 		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.
 | 		//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
 | ||||||
| 		wxSetlocale(LC_NUMERIC, "C"); | 		wxSetlocale(LC_NUMERIC, "C"); | ||||||
|         Preset::update_suffix_modified(); |         Preset::update_suffix_modified(); | ||||||
|  | @ -542,7 +542,7 @@ bool GUI_App::load_language() | ||||||
|             m_wxLocale = new wxLocale; |             m_wxLocale = new wxLocale; | ||||||
|             m_wxLocale->Init(identifiers[i]); |             m_wxLocale->Init(identifiers[i]); | ||||||
| 			m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir())); | 			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.
 | 			//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
 | ||||||
|             wxSetlocale(LC_NUMERIC, "C"); |             wxSetlocale(LC_NUMERIC, "C"); | ||||||
| 			Preset::update_suffix_modified(); | 			Preset::update_suffix_modified(); | ||||||
|  | @ -586,9 +586,7 @@ void GUI_App::get_installed_languages(wxArrayString & names, wxArrayLong & ident | ||||||
|         if (langinfo != NULL) |         if (langinfo != NULL) | ||||||
|         { |         { | ||||||
|             auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + |             auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + | ||||||
|                 filename + wxFileName::GetPathSeparator() + |                 filename + wxFileName::GetPathSeparator() + "Slic3rPE" + wxT(".mo"); | ||||||
|                 /*GetAppName()*/"Slic3rPE" +  |  | ||||||
|                 wxT(".mo"); |  | ||||||
|             if (wxFileExists(full_file_name)) |             if (wxFileExists(full_file_name)) | ||||||
|             { |             { | ||||||
|                 names.Add(langinfo->Description); |                 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) |     for (const size_t object : object_idxs) | ||||||
|     { |     { | ||||||
|         add_object_to_list(object); |         add_object_to_list(object); | ||||||
|         m_parts_changed = true; |  | ||||||
|         parts_changed(object); |  | ||||||
| 
 |  | ||||||
|         items.Add(m_objects_model->GetItemById(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); |     select_items(items); | ||||||
| #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 | #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 | ||||||
|     selection_changed(); |     selection_changed(); | ||||||
|  | @ -644,6 +645,10 @@ void ObjectList::key_event(wxKeyEvent& event) | ||||||
|     } |     } | ||||||
|     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) |     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) | ||||||
|         select_item_all_children(); |         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 |     else | ||||||
|         event.Skip(); |         event.Skip(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
| namespace Slic3r { | namespace Slic3r { | ||||||
| namespace GUI { | 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::MinHalfSize = 1.5f; | ||||||
| const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f; | 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 | 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 | 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()); |         glsafe(::glEnd()); | ||||||
| 
 | 
 | ||||||
|         // draw grabber
 |         // 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); |         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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (m_model_object != model_object) | ||||||
|  |         m_print_object_idx = -1; | ||||||
|  | 
 | ||||||
|     m_model_object = model_object; |     m_model_object = model_object; | ||||||
|     m_active_instance = selection.get_instance_idx(); |     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_BLEND)); | ||||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); |     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(); |     m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); | ||||||
| 
 | 
 | ||||||
|     if (m_quadric != nullptr && selection.is_from_single_instance()) |     if (m_quadric != nullptr && selection.is_from_single_instance()) | ||||||
|         render_points(selection, direction_to_camera, false); |         render_points(selection, false); | ||||||
| 
 | 
 | ||||||
|     render_selection_rectangle(); |     render_selection_rectangle(); | ||||||
|     render_clipping_plane(selection, direction_to_camera); |     render_clipping_plane(selection); | ||||||
| 
 | 
 | ||||||
|     glsafe(::glDisable(GL_BLEND)); |     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) |     if (m_clipping_plane_distance == 0.f) | ||||||
|         return; |         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()); |     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 = 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>(); |     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>(); |     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_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)); |     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()); |     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 |     // Get transformation of the supports and calculate how far from its origin the clipping plane is.
 | ||||||
|      || m_old_direction_to_camera != direction_to_camera) { |     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) { |         if (! m_tms) { | ||||||
|             m_tms.reset(new TriangleMeshSlicer); |             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->set_up_direction(up); | ||||||
|         m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){}); |         m_tms->slice(std::vector<float>{height_mesh}, 0.f, &list_of_expolys, [](){}); | ||||||
|         m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); |         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()) { | 	if (! m_triangles.empty()) { | ||||||
| 		::glPushMatrix(); | 		::glPushMatrix(); | ||||||
| 		::glTranslated(0.0, 0.0, m_z_shift); | 		::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); | 		q.setFromTwoVectors(Vec3f::UnitZ(), up); | ||||||
| 		Eigen::AngleAxisf aa(q); | 		Eigen::AngleAxisf aa(q); | ||||||
| 		::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); | 		::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); |         ::glColor3f(1.0f, 0.37f, 0.0f); | ||||||
|  |         ::glBegin(GL_TRIANGLES); | ||||||
|         for (const Vec2f& point : m_triangles) |         for (const Vec2f& point : m_triangles) | ||||||
|             ::glVertex3f(point(0), point(1), height_mesh); |             ::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(); |         ::glEnd(); | ||||||
| 		::glPopMatrix(); | 		::glPopMatrix(); | ||||||
| 	} | 	} | ||||||
|  | @ -206,16 +286,10 @@ void GLGizmoSlaSupports::render_selection_rectangle() const | ||||||
| void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const | void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const | ||||||
| { | { | ||||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); |     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||||
| 
 |     render_points(selection, true); | ||||||
|     // 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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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) |     if (!picking) | ||||||
|         glsafe(::glEnable(GL_LIGHTING)); |         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 sla::SupportPoint& support_point = m_editing_mode_cache[i].support_point; | ||||||
|         const bool& point_selected = m_editing_mode_cache[i].selected; |         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; |             continue; | ||||||
| 
 | 
 | ||||||
|         // First decide about the color of the point.
 |         // 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) |     if (m_clipping_plane_distance == 0.f) | ||||||
|         return false; |         return false; | ||||||
| 
 | 
 | ||||||
|  | @ -332,9 +408,12 @@ void GLGizmoSlaSupports::update_mesh() | ||||||
|     wxBusyCursor wait; |     wxBusyCursor wait; | ||||||
|     Eigen::MatrixXf& V = m_V; |     Eigen::MatrixXf& V = m_V; | ||||||
|     Eigen::MatrixXi& F = m_F; |     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.
 |     // This mesh does not account for the possible Z up SLA offset.
 | ||||||
|     m_mesh = m_model_object->raw_mesh(); |     m_mesh = &m_model_object->volumes.front()->mesh; | ||||||
|     const stl_file& stl = m_mesh.stl; |     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); |     V.resize(3 * stl.stats.number_of_facets, 3); | ||||||
|     F.resize(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) { |     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 Selection& selection = m_parent.get_selection(); | ||||||
|     const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); |     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; |     point1(2) -= m_z_shift; | ||||||
| 	point2(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))); |         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))); |         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)); |         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; |             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); |                   ::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; |                   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; |                     bool is_obscured = false; | ||||||
|                     // Cast a ray in the direction of the camera and look for intersection with the mesh:
 |                     // Cast a ray in the direction of the camera and look for intersection with the mesh:
 | ||||||
|                     std::vector<igl::Hit> hits; |                     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 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)); |                                 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); |                                     hits.erase(hits.begin()+j); | ||||||
|                                     --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; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -709,11 +802,12 @@ ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const | ||||||
|     if (!m_model_object || m_state == Off) |     if (!m_model_object || m_state == Off) | ||||||
|         return ClippingPlane::ClipsNothing(); |         return ClippingPlane::ClipsNothing(); | ||||||
| 
 | 
 | ||||||
|     Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix; |     //Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix;
 | ||||||
|     ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); |     //::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data());
 | ||||||
| 
 |  | ||||||
|     // we'll recover current look direction from the modelview matrix (in world coords):
 |     // 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)); |     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)); |     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_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points  (will be autogenerated)" : |         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 ? "Autogenerated points (no modifications)" : |                      (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? _(L("Autogenerated points (no modifications)")) : | ||||||
|                      (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" : |                      (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? _(L("User-modified points")) : | ||||||
|                      (m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS")))); |                      (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:
 |     // Following is rendered in both editing and non-editing mode:
 | ||||||
|     m_imgui->text("Clipping of view: "); |     if (m_clipping_plane_distance == 0.f) | ||||||
|     ImGui::SameLine(); |         m_imgui->text("Clipping of view: "); | ||||||
|  |     else { | ||||||
|  |         if (m_imgui->button(_(L("Reset direction [R] ")))) { | ||||||
|  |             wxGetApp().CallAfter([this](){ | ||||||
|  |                     reset_clipping_plane_normal(); | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ImGui::SameLine(140.f); | ||||||
|     ImGui::PushItemWidth(150.0f); |     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(); |     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 = false; // so it is not active next time the gizmo opens
 | ||||||
|                 m_editing_mode_cache.clear(); |                 m_editing_mode_cache.clear(); | ||||||
|                 m_clipping_plane_distance = 0.f; |                 m_clipping_plane_distance = 0.f; | ||||||
|                 // Release copy of the mesh, triangle slicer and the AABB spatial search structure.
 |                 // Release triangle mesh slicer and the AABB spatial search structure.
 | ||||||
| 				m_mesh.clear(); |  | ||||||
|                 m_AABB.deinit(); |                 m_AABB.deinit(); | ||||||
| 				m_V = Eigen::MatrixXf(); | 				m_V = Eigen::MatrixXf(); | ||||||
| 				m_F = Eigen::MatrixXi(); | 				m_F = Eigen::MatrixXi(); | ||||||
|                 m_tms.reset(nullptr); |                 m_tms.reset(); | ||||||
|  |                 m_supports_tms.reset(); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         m_old_state = m_state; |         m_old_state = m_state; | ||||||
|  | @ -1126,5 +1229,17 @@ void GLGizmoSlaSupports::switch_to_editing_mode() | ||||||
|     m_editing_mode = true; |     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 GUI
 | ||||||
| } // namespace Slic3r
 | } // namespace Slic3r
 | ||||||
|  |  | ||||||
|  | @ -36,8 +36,13 @@ private: | ||||||
|     Eigen::MatrixXf m_V; // vertices
 |     Eigen::MatrixXf m_V; // vertices
 | ||||||
|     Eigen::MatrixXi m_F; // facets indices
 |     Eigen::MatrixXi m_F; // facets indices
 | ||||||
|     igl::AABB<Eigen::MatrixXf,3> m_AABB; |     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_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 { |     class CacheEntry { | ||||||
|     public: |     public: | ||||||
|  | @ -68,8 +73,8 @@ private: | ||||||
|     virtual void on_render_for_picking(const Selection& selection) const; |     virtual void on_render_for_picking(const Selection& selection) const; | ||||||
| 
 | 
 | ||||||
|     void render_selection_rectangle() const; |     void render_selection_rectangle() const; | ||||||
|     void render_points(const Selection& selection, const Vec3d& direction_to_camera, bool picking = false) const; |     void render_points(const Selection& selection, bool picking = false) const; | ||||||
|     void render_clipping_plane(const Selection& selection, const Vec3d& direction_to_camera) const; |     void render_clipping_plane(const Selection& selection) const; | ||||||
|     bool is_mesh_update_necessary() const; |     bool is_mesh_update_necessary() const; | ||||||
|     void update_mesh(); |     void update_mesh(); | ||||||
|     void update_cache_entry_normal(unsigned int i) const; |     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).
 |     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_new_point_head_diameter;        // Size of a new point.
 | ||||||
|     float m_minimal_point_distance = 20.f; |     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
 |     mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
 | ||||||
|     float m_clipping_plane_distance = 0.f; |     float m_clipping_plane_distance = 0.f; | ||||||
|     mutable float m_old_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 { |     enum SelectionRectangleStatus { | ||||||
|         srOff = 0, |         srOff = 0, | ||||||
|  | @ -101,10 +106,11 @@ private: | ||||||
|     int m_canvas_height; |     int m_canvas_height; | ||||||
| 
 | 
 | ||||||
|     mutable std::unique_ptr<TriangleMeshSlicer> m_tms; |     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; |     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; |     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; |     //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,
 |     // Methods that do the model_object and editing cache synchronization,
 | ||||||
|     // editing mode selection, etc:
 |     // editing mode selection, etc:
 | ||||||
|  | @ -120,6 +126,7 @@ private: | ||||||
|     void get_data_from_backend(); |     void get_data_from_backend(); | ||||||
|     void auto_generate(); |     void auto_generate(); | ||||||
|     void switch_to_editing_mode(); |     void switch_to_editing_mode(); | ||||||
|  |     void reset_clipping_plane_normal() const; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     void on_set_state() override; |     void on_set_state() override; | ||||||
|  |  | ||||||
|  | @ -14,7 +14,10 @@ enum class SLAGizmoEventType { | ||||||
|     ApplyChanges, |     ApplyChanges, | ||||||
|     DiscardChanges, |     DiscardChanges, | ||||||
|     AutomaticGeneration, |     AutomaticGeneration, | ||||||
|     ManualEditing |     ManualEditing, | ||||||
|  |     MouseWheelUp, | ||||||
|  |     MouseWheelDown, | ||||||
|  |     ResetClippingPlane | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" | #include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" | ||||||
|  |  | ||||||
|  | @ -520,6 +520,23 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& | ||||||
|     glsafe(::glPopMatrix()); |     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) | bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | ||||||
| { | { | ||||||
|     Point pos(evt.GetX(), evt.GetY()); |     Point pos(evt.GetX(), evt.GetY()); | ||||||
|  | @ -761,6 +778,16 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas) | ||||||
| 
 | 
 | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         case 'r' : | ||||||
|  |         case 'R' : | ||||||
|  |         { | ||||||
|  |             if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::ResetClippingPlane)) | ||||||
|  |                 processed = true; | ||||||
|  | 
 | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
| #ifdef __APPLE__ | #ifdef __APPLE__ | ||||||
|         case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
 |         case WXK_BACK: // the low cost Apple solutions are not equipped with a Delete key, use Backspace instead.
 | ||||||
| #else /* __APPLE__ */ | #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())) |         if (handle_shortcut(keyCode, canvas.get_selection())) | ||||||
|         { |         { | ||||||
|  |  | ||||||
|  | @ -157,6 +157,7 @@ public: | ||||||
|     const std::string& get_tooltip() const { return m_tooltip; } |     const std::string& get_tooltip() const { return m_tooltip; } | ||||||
| 
 | 
 | ||||||
|     bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas); |     bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas); | ||||||
|  |     bool on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas); | ||||||
|     bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas); |     bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas); | ||||||
|     bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas); |     bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ namespace Slic3r { | ||||||
| namespace GUI { | namespace GUI { | ||||||
| 
 | 
 | ||||||
| KBShortcutsDialog::KBShortcutsDialog() | 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) |      wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) | ||||||
| { | { | ||||||
| 	SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | 	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(ctrl+"A",   L("Select All objects"))); | ||||||
|     plater_shortcuts.push_back(Shortcut("Del",      L("Delete selected"))); |     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+"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("M",        L("Gizmo move"))); | ||||||
|     plater_shortcuts.push_back(Shortcut("S",        L("Gizmo scale"))); |     plater_shortcuts.push_back(Shortcut("S",        L("Gizmo scale"))); | ||||||
|     plater_shortcuts.push_back(Shortcut("R",        L("Gizmo rotate"))); |     plater_shortcuts.push_back(Shortcut("R",        L("Gizmo rotate"))); | ||||||
|  | @ -177,8 +179,8 @@ void KBShortcutsDialog::fill_shortcuts() | ||||||
|     Shortcuts layers_slider_shortcuts; |     Shortcuts layers_slider_shortcuts; | ||||||
|     layers_slider_shortcuts.reserve(6); |     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 Up"),   L("Move current slider thumb Up"))); | ||||||
|     layers_slider_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Move current slider thump Down"))); |     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 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("Arrow Right"),L("Set lower thumb to current slider thumb"))); | ||||||
|     layers_slider_shortcuts.push_back(Shortcut("+",             L("Add color change marker for current layer"))); |     layers_slider_shortcuts.push_back(Shortcut("+",             L("Add color change marker for current layer"))); | ||||||
|  |  | ||||||
|  | @ -403,9 +403,9 @@ void MainFrame::init_menubar() | ||||||
| 
 | 
 | ||||||
|         editMenu->AppendSeparator(); |         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"); |             [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"); |             [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "paste_menu"); | ||||||
| 
 | 
 | ||||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId()); |         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(); }); |             [this](wxCommandEvent&) { wxGetApp().system_info(); }); | ||||||
|         append_menu_item(helpMenu, wxID_ANY, _(L("Show &Configuration Folder")), _(L("Show user configuration folder (datadir)")), |         append_menu_item(helpMenu, wxID_ANY, _(L("Show &Configuration Folder")), _(L("Show user configuration folder (datadir)")), | ||||||
|             [this](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); }); |             [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"); }); |             [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(); }); |             [this](wxCommandEvent&) { Slic3r::GUI::about(); }); | ||||||
|         helpMenu->AppendSeparator(); |         helpMenu->AppendSeparator(); | ||||||
|         append_menu_item(helpMenu, wxID_ANY, _(L("Keyboard Shortcuts")) + sep + "&?", _(L("Show the list of the keyboard shortcuts")), |         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.
 |     // Ask user for a file name.
 | ||||||
|     auto dlg = new wxFileDialog(this, _(L("Save presets bundle as:")), |     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(), |         !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); |         file_wildcards(FT_INI), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); | ||||||
|     wxString file; |     wxString file; | ||||||
|     if (dlg->ShowModal() == wxID_OK) |     if (dlg->ShowModal() == wxID_OK) | ||||||
|  |  | ||||||
|  | @ -280,7 +280,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * | ||||||
|                 cfg.set_key_value("extruder_colour", colors); |                 cfg.set_key_value("extruder_colour", colors); | ||||||
| 
 | 
 | ||||||
|                 wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg); |                 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); |                 wxGetApp().plater()->on_config_change(cfg); | ||||||
|             } |             } | ||||||
|             dialog->Destroy(); |             dialog->Destroy(); | ||||||
|  | @ -813,7 +813,7 @@ void Sidebar::update_all_preset_comboboxes() | ||||||
|     // update the dirty flags.
 |     // update the dirty flags.
 | ||||||
|     if (print_tech == ptFFF) { |     if (print_tech == ptFFF) { | ||||||
|         for (size_t i = 0; i < p->combos_filament.size(); ++i) |         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(); |     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++) { |         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; |         break; | ||||||
|  | @ -872,7 +872,7 @@ void Sidebar::update_presets(Preset::Type preset_type) | ||||||
| // 		// update the dirty flags.
 | // 		// update the dirty flags.
 | ||||||
| //         if (print_tech == ptFFF) {
 | //         if (print_tech == ptFFF) {
 | ||||||
| //             for (size_t i = 0; i < p->combos_filament.size(); ++ i)
 | //             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();
 | // 		p->show_preset_comboboxes();
 | ||||||
|         update_all_preset_comboboxes(); |         update_all_preset_comboboxes(); | ||||||
|  | @ -1239,8 +1239,8 @@ struct Plater::priv | ||||||
|     wxString project_filename; |     wxString project_filename; | ||||||
| 
 | 
 | ||||||
|     BackgroundSlicingProcess    background_process; |     BackgroundSlicingProcess    background_process; | ||||||
|     std::atomic<bool>           arranging; |     bool                        arranging; | ||||||
|     std::atomic<bool>           rotoptimizing; |     bool                        rotoptimizing; | ||||||
|     bool                        delayed_scene_refresh; |     bool                        delayed_scene_refresh; | ||||||
|     std::string                 delayed_error_message; |     std::string                 delayed_error_message; | ||||||
| 
 | 
 | ||||||
|  | @ -1403,8 +1403,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) | ||||||
|     , view_toolbar(GLToolbar::Radio) |     , view_toolbar(GLToolbar::Radio) | ||||||
| #endif // ENABLE_SVG_ICONS
 | #endif // ENABLE_SVG_ICONS
 | ||||||
| { | { | ||||||
|     arranging.store(false); |     arranging = false; | ||||||
|     rotoptimizing.store(false); |     rotoptimizing = false; | ||||||
|     background_process.set_fff_print(&fff_print); |     background_process.set_fff_print(&fff_print); | ||||||
| 	background_process.set_sla_print(&sla_print); | 	background_process.set_sla_print(&sla_print); | ||||||
|     background_process.set_gcode_preview_data(&gcode_preview_data); |     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; |                         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 ?
 |                     // is there any modifier ?
 | ||||||
|                     for (const ModelVolume* model_volume : model_object->volumes) |                     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; |                             advanced = true; | ||||||
|                             break; |                             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) |                     if (advanced) | ||||||
|  | @ -2079,15 +2095,14 @@ void Plater::priv::mirror(Axis axis) | ||||||
| 
 | 
 | ||||||
| void Plater::priv::arrange() | void Plater::priv::arrange() | ||||||
| { | { | ||||||
|     // don't do anything if currently arranging. Then this is a re-entrance
 |     if (arranging) { return; } | ||||||
|     if(arranging.load()) return; |     arranging = true; | ||||||
| 
 |     Slic3r::ScopeGuard arranging_guard([this]() { arranging = false; }); | ||||||
|     // Guard the arrange process
 |  | ||||||
|     arranging.store(true); |  | ||||||
| 
 | 
 | ||||||
|     wxBusyCursor wait; |     wxBusyCursor wait; | ||||||
| 
 | 
 | ||||||
|     this->background_process.stop(); |     this->background_process.stop(); | ||||||
|  | 
 | ||||||
|     unsigned count = 0; |     unsigned count = 0; | ||||||
|     for(auto obj : model.objects) count += obj->instances.size(); |     for(auto obj : model.objects) count += obj->instances.size(); | ||||||
| 
 | 
 | ||||||
|  | @ -2103,14 +2118,14 @@ void Plater::priv::arrange() | ||||||
|         statusbar()->set_progress(count - st); |         statusbar()->set_progress(count - st); | ||||||
|         statusbar()->set_status_text(msg); |         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.
 |         // 'arranging' and the arrange button is also disabled.
 | ||||||
|         // This call is needed for the cancel button to work.
 |         // This call is needed for the cancel button to work.
 | ||||||
|         wxYieldIfNeeded(); |         wxYieldIfNeeded(); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     statusbar()->set_cancel_callback([this, statusfn](){ |     statusbar()->set_cancel_callback([this, statusfn](){ | ||||||
|         arranging.store(false); |         arranging = false; | ||||||
|         statusfn(0, L("Arranging canceled")); |         statusfn(0, L("Arranging canceled")); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | @ -2146,7 +2161,7 @@ void Plater::priv::arrange() | ||||||
|                      hint, |                      hint, | ||||||
|                      false, // create many piles not just one pile
 |                      false, // create many piles not just one pile
 | ||||||
|                      [statusfn](unsigned st) { statusfn(st, arrangestr); }, |                      [statusfn](unsigned st) { statusfn(st, arrangestr); }, | ||||||
|                      [this] () { return !arranging.load(); }); |                      [this] () { return !arranging; }); | ||||||
|     } catch(std::exception& /*e*/) { |     } catch(std::exception& /*e*/) { | ||||||
|         GUI::show_error(this->q, L("Could not arrange model objects! " |         GUI::show_error(this->q, L("Could not arrange model objects! " | ||||||
|                                    "Some geometries may be invalid.")); |                                    "Some geometries may be invalid.")); | ||||||
|  | @ -2155,7 +2170,6 @@ void Plater::priv::arrange() | ||||||
|     statusfn(0, L("Arranging done.")); |     statusfn(0, L("Arranging done.")); | ||||||
|     statusbar()->set_range(prev_range); |     statusbar()->set_range(prev_range); | ||||||
|     statusbar()->set_cancel_callback(); // remove cancel button
 |     statusbar()->set_cancel_callback(); // remove cancel button
 | ||||||
|     arranging.store(false); |  | ||||||
| 
 | 
 | ||||||
|     // Do a full refresh of scene tree, including regenerating all the GLVolumes.
 |     // Do a full refresh of scene tree, including regenerating all the GLVolumes.
 | ||||||
|     //FIXME The update function shall just reload the modified matrices.
 |     //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
 |     // running we should probably disable explicit slicing and background
 | ||||||
|     // processing
 |     // processing
 | ||||||
| 
 | 
 | ||||||
|     if(rotoptimizing.load()) return; |     if (rotoptimizing) { return; } | ||||||
|     rotoptimizing.store(true); |     rotoptimizing = true; | ||||||
|  |     Slic3r::ScopeGuard rotoptimizing_guard([this]() { rotoptimizing = false; }); | ||||||
| 
 | 
 | ||||||
|     int obj_idx = get_selected_object_idx(); |     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)]; |     ModelObject * o = model.objects[size_t(obj_idx)]; | ||||||
| 
 | 
 | ||||||
|  | @ -2192,14 +2207,14 @@ void Plater::priv::sla_optimize_rotation() { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     statusbar()->set_cancel_callback([this, stfn](){ |     statusbar()->set_cancel_callback([this, stfn](){ | ||||||
|         rotoptimizing.store(false); |         rotoptimizing = false; | ||||||
|         stfn(0, L("Orientation search canceled")); |         stfn(0, L("Orientation search canceled")); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     auto r = sla::find_best_rotation( |     auto r = sla::find_best_rotation( | ||||||
|                 *o, .005f, |                 *o, .005f, | ||||||
|                 [stfn](unsigned s) { stfn(s, L("Searching for optimal orientation")); }, |                 [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"); |     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 mindist = 6.0; // FIXME
 | ||||||
|     double offs = mindist / 2.0 - EPSILON; |     double offs = mindist / 2.0 - EPSILON; | ||||||
| 
 | 
 | ||||||
|     if(rotoptimizing.load()) // wasn't canceled
 |     if(rotoptimizing) // wasn't canceled
 | ||||||
|     for(ModelInstance * oi : o->instances) { |     for(ModelInstance * oi : o->instances) { | ||||||
|         oi->set_rotation({r[X], r[Y], r[Z]}); |         oi->set_rotation({r[X], r[Y], r[Z]}); | ||||||
| 
 | 
 | ||||||
|  | @ -2262,7 +2277,6 @@ void Plater::priv::sla_optimize_rotation() { | ||||||
|     stfn(0, L("Orientation found.")); |     stfn(0, L("Orientation found.")); | ||||||
|     statusbar()->set_range(prev_range); |     statusbar()->set_range(prev_range); | ||||||
|     statusbar()->set_cancel_callback(); |     statusbar()->set_cancel_callback(); | ||||||
|     rotoptimizing.store(false); |  | ||||||
| 
 | 
 | ||||||
|     update(true); |     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.
 | // Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
 | ||||||
| bool Plater::priv::restart_background_process(unsigned int state) | bool Plater::priv::restart_background_process(unsigned int state) | ||||||
| { | { | ||||||
|  |     if (arranging || rotoptimizing) { | ||||||
|  |         // Avoid a race condition
 | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 	if ( ! this->background_process.empty() && | 	if ( ! this->background_process.empty() && | ||||||
| 		 (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 && | 		 (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 && | ||||||
| 		 ( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) || | 		 ( ((state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART) != 0 && ! this->background_process.finished()) || | ||||||
|  | @ -2650,7 +2669,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt) | ||||||
|     // TODO: ?
 |     // TODO: ?
 | ||||||
|     if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) { |     if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) { | ||||||
|         // Only update the platter UI for the 2nd and other filaments.
 |         // 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 { |     else { | ||||||
|         wxWindowUpdateLocker noUpdates(sidebar->presets_panel()); |         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) | void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) | ||||||
| { | { | ||||||
|     if (evt.status.percent >= -1) { |     if (evt.status.percent >= -1) { | ||||||
|  |         if (arranging || rotoptimizing) { | ||||||
|  |             // Avoid a race condition
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         this->statusbar()->set_progress(evt.status.percent); |         this->statusbar()->set_progress(evt.status.percent); | ||||||
|         this->statusbar()->set_status_text(_(L(evt.status.text)) + wxString::FromUTF8("…")); |         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 | bool Plater::priv::can_increase_instances() const | ||||||
| { | { | ||||||
|  |     if (arranging || rotoptimizing) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     int obj_idx = get_selected_object_idx(); |     int obj_idx = get_selected_object_idx(); | ||||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); |     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Plater::priv::can_decrease_instances() const | bool Plater::priv::can_decrease_instances() const | ||||||
| { | { | ||||||
|  |     if (arranging || rotoptimizing) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     int obj_idx = get_selected_object_idx(); |     int obj_idx = get_selected_object_idx(); | ||||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1); |     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 | bool Plater::priv::can_arrange() const | ||||||
| { | { | ||||||
|     return !model.objects.empty() && !arranging.load(); |     return !model.objects.empty() && !arranging; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Plater::priv::can_layers_editing() const | bool Plater::priv::can_layers_editing() const | ||||||
|  | @ -3286,9 +3318,9 @@ void Plater::remove_selected() | ||||||
| 
 | 
 | ||||||
| void Plater::increase_instances(size_t num) | void Plater::increase_instances(size_t num) | ||||||
| { | { | ||||||
|  |     if (! can_increase_instances()) { return; } | ||||||
|  | 
 | ||||||
|     int obj_idx = p->get_selected_object_idx(); |     int obj_idx = p->get_selected_object_idx(); | ||||||
|     if (obj_idx == -1) |  | ||||||
|         return; |  | ||||||
| 
 | 
 | ||||||
|     ModelObject* model_object = p->model.objects[obj_idx]; |     ModelObject* model_object = p->model.objects[obj_idx]; | ||||||
|     ModelInstance* model_instance = model_object->instances.back(); |     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) | void Plater::decrease_instances(size_t num) | ||||||
| { | { | ||||||
|  |     if (! can_decrease_instances()) { return; } | ||||||
|  | 
 | ||||||
|     int obj_idx = p->get_selected_object_idx(); |     int obj_idx = p->get_selected_object_idx(); | ||||||
|     if (obj_idx == -1) |  | ||||||
|         return; |  | ||||||
| 
 | 
 | ||||||
|     ModelObject* model_object = p->model.objects[obj_idx]; |     ModelObject* model_object = p->model.objects[obj_idx]; | ||||||
|     if (model_object->instances.size() > num) { |     if (model_object->instances.size() > num) { | ||||||
|  | @ -3618,7 +3650,7 @@ void Plater::on_extruders_change(int num_extruders) | ||||||
|         choices.push_back(choice); |         choices.push_back(choice); | ||||||
| 
 | 
 | ||||||
|         // initialize selection
 |         // initialize selection
 | ||||||
|         wxGetApp().preset_bundle->update_platter_filament_ui(i, choice); |         wxGetApp().preset_bundle->update_platter_filament_ui(i, choice, wxGetApp().em_unit()); | ||||||
|         ++i; |         ++i; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -3768,6 +3800,36 @@ void Plater::changed_object(int obj_idx) | ||||||
|     this->p->schedule_background_process(); |     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() | void Plater::schedule_background_process() | ||||||
| { | { | ||||||
|     this->p->schedule_background_process();     |     this->p->schedule_background_process();     | ||||||
|  |  | ||||||
|  | @ -167,6 +167,7 @@ public: | ||||||
|     void reslice(); |     void reslice(); | ||||||
|     void reslice_SLA_supports(const ModelObject &object); |     void reslice_SLA_supports(const ModelObject &object); | ||||||
|     void changed_object(int obj_idx); |     void changed_object(int obj_idx); | ||||||
|  |     void changed_objects(const std::vector<size_t>& object_idxs); | ||||||
|     void schedule_background_process(); |     void schedule_background_process(); | ||||||
|     void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); |     void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); | ||||||
|     void send_gcode(); |     void send_gcode(); | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ void PreferencesDialog::build() | ||||||
| 	// Please keep in sync with ConfigWizard
 | 	// Please keep in sync with ConfigWizard
 | ||||||
| 	def.label = L("Check for application updates"); | 	def.label = L("Check for application updates"); | ||||||
| 	def.type = coBool; | 	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"); | 	def.default_value = new ConfigOptionBool(app_config->get("version_check") == "1"); | ||||||
| 	option = Option (def, "version_check"); | 	option = Option (def, "version_check"); | ||||||
| 	m_optgroup->append_single_option_line(option); | 	m_optgroup->append_single_option_line(option); | ||||||
|  |  | ||||||
|  | @ -1451,7 +1451,7 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window) | ||||||
|     this->load_compatible_bitmaps(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 || |     if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA || | ||||||
|         this->filament_presets.size() <= idx_extruder ) |         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 = ""; | 	wxString selected_str = ""; | ||||||
| 	if (!this->filaments().front().is_visible) | 	if (!this->filaments().front().is_visible) | ||||||
|         ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap)); |         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) { | 	for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++i) { | ||||||
|         const Preset &preset    = this->filaments.preset(i); |         const Preset &preset    = this->filaments.preset(i); | ||||||
|         bool          selected  = this->filament_presets[idx_extruder] == preset.name; |         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; |             std::vector<wxBitmap> bmps; | ||||||
|             if (wide_icons) |             if (wide_icons) | ||||||
|                 // Paint a red flag for incompatible presets.
 |                 // 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.
 |             // Paint the color bars.
 | ||||||
|             parse_color(filament_rgb, rgb); |             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) { |             if (! single_bar) { | ||||||
|                 parse_color(extruder_rgb, rgb); |                 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.
 |             // Paint a lock at the system presets.
 | ||||||
|             bmps.emplace_back(m_bitmapCache->mkclear(2, 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(16, 16)); |             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));
 | //                 (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
 | ||||||
|             bitmap = m_bitmapCache->insert(bitmap_key, bmps); |             bitmap = m_bitmapCache->insert(bitmap_key, bmps); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -107,7 +107,7 @@ public: | ||||||
|     void                        export_configbundle(const std::string &path, bool export_system_settings = false); |     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.
 |     // 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.
 |     // Enable / disable the "- default -" preset.
 | ||||||
|     void                        set_default_suppressed(bool default_suppressed); |     void                        set_default_suppressed(bool default_suppressed); | ||||||
|  |  | ||||||
|  | @ -99,7 +99,7 @@ void Selection::set_model(Model* model) | ||||||
|     update_valid(); |     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)) |     if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx)) | ||||||
|         return; |         return; | ||||||
|  | @ -110,7 +110,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     bool keep_instance_mode = (m_mode == Instance) && !as_single_selection; |     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
 |     // resets the current list if needed
 | ||||||
|     bool needs_reset = as_single_selection && !already_contained; |     bool needs_reset = as_single_selection && !already_contained; | ||||||
|  |  | ||||||
|  | @ -210,7 +210,7 @@ public: | ||||||
|     EMode get_mode() const { return m_mode; } |     EMode get_mode() const { return m_mode; } | ||||||
|     void set_mode(EMode mode) { m_mode = 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 remove(unsigned int volume_idx); | ||||||
| 
 | 
 | ||||||
|     void add_object(unsigned int object_idx, bool as_single_selection = true); |     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"; |     std::string line_end = format_as_html ? "<br>" : "\n"; | ||||||
| 
 | 
 | ||||||
|     if (!format_as_html) |     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 << "Version:   "             << b_end << SLIC3R_VERSION << line_end; | ||||||
|     out << b_start << "Build:     "             << b_end << SLIC3R_BUILD << line_end; |     out << b_start << "Build:     "             << b_end << SLIC3R_BUILD << line_end; | ||||||
|     out << line_end; |     out << line_end; | ||||||
|  | @ -41,7 +41,7 @@ std::string get_main_info(bool format_as_html) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SysInfoDialog::SysInfoDialog() | 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); | 	wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); | ||||||
| 	SetBackgroundColour(bgr_clr); | 	SetBackgroundColour(bgr_clr); | ||||||
|  | @ -64,7 +64,7 @@ SysInfoDialog::SysInfoDialog() | ||||||
| 
 | 
 | ||||||
|     // title
 |     // 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);
 |         wxFont title_font = wxGetApp().bold_font();//wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
 | ||||||
| //         title_font.SetWeight(wxFONTWEIGHT_BOLD);
 | //         title_font.SetWeight(wxFONTWEIGHT_BOLD);
 | ||||||
|         title_font.SetFamily(wxFONTFAMILY_ROMAN); |         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::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_online) : | 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_current(ver_current), | ||||||
| 	ver_online(ver_online) | 	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)); | 	logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192)); | ||||||
| 
 | 
 | ||||||
| 	auto *text = new wxStaticText(this, wxID_ANY, _(L( | 	auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L( | ||||||
| 		"This version of Slic3r PE is not compatible with currently installed configuration bundles.\n" | 		"This version of %s 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" | 		"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. " | 		"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" | 		"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()); | 	text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); | ||||||
| 	content_sizer->Add(text); | 	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()); | 	text2->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); | ||||||
| 	content_sizer->Add(text2); | 	content_sizer->Add(text2); | ||||||
| 	content_sizer->AddSpacer(VERT_SPACING); | 	content_sizer->AddSpacer(VERT_SPACING); | ||||||
|  | @ -168,7 +168,7 @@ MsgDataLegacy::MsgDataLegacy() : | ||||||
| { | { | ||||||
| 	auto *text = new wxStaticText(this, wxID_ANY, wxString::Format( | 	auto *text = new wxStaticText(this, wxID_ANY, wxString::Format( | ||||||
| 		_(L( | 		_(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 " | 			"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 " | 			"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 " | 			"Please proceed with the %s that follows to set up the new presets " | ||||||
| 			"and to choose whether to enable automatic preset updates." | 			"and to choose whether to enable automatic preset updates." | ||||||
| 		)), | 		)), | ||||||
| 		ConfigWizard::name() | 		SLIC3R_APP_NAME, ConfigWizard::name() | ||||||
| 	)); | 	)); | ||||||
| 	text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); | 	text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); | ||||||
| 	content_sizer->Add(text); | 	content_sizer->Add(text); | ||||||
|  |  | ||||||
|  | @ -88,7 +88,7 @@ Http::priv::priv(const std::string &url) | ||||||
| 
 | 
 | ||||||
| 	set_timeout_connect(DEFAULT_TIMEOUT_CONNECT); | 	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_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()); | 	::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() | void Http::priv::http_perform() | ||||||
| { | { | ||||||
| 	::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); | 	::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_WRITEFUNCTION, writecb); | ||||||
| 	::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this)); | 	::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this)); | ||||||
| 	::curl_easy_setopt(curl, CURLOPT_READFUNCTION, form_file_read_cb); | 	::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; } | 	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) | 	Http::get(version_check_url) | ||||||
| 		.size_limit(SLIC3R_VERSION_BODY_MAX) | 		.size_limit(SLIC3R_VERSION_BODY_MAX) | ||||||
|  | @ -224,7 +224,7 @@ void PresetUpdater::priv::sync_version() const | ||||||
| 		}) | 		}) | ||||||
| 		.on_complete([&](std::string body, unsigned /* http_status */) { | 		.on_complete([&](std::string body, unsigned /* http_status */) { | ||||||
| 			boost::trim(body); | 			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); | 			wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); | ||||||
| 			evt->SetString(GUI::from_u8(body)); | 			evt->SetString(GUI::from_u8(body)); | ||||||
|  |  | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| # Included by CMakeLists, edited by the build script
 | # Included by CMakeLists, edited by the build script
 | ||||||
| # (the version numbers are generated by the build script from the git current label)
 | # (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_VERSION "1.42.0-beta2") | ||||||
| set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN") | set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN") | ||||||
| set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}") | set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}") | ||||||
|  |  | ||||||
|  | @ -180,6 +180,8 @@ SV* | ||||||
| TriangleMesh::slice(z) | TriangleMesh::slice(z) | ||||||
|     std::vector<double> z |     std::vector<double> z | ||||||
|     CODE: |     CODE: | ||||||
|  |         THIS->require_shared_vertices(); // TriangleMeshSlicer needs this | ||||||
|  | 
 | ||||||
|         // convert doubles to floats |         // convert doubles to floats | ||||||
|         std::vector<float> z_f = cast<float>(z); |         std::vector<float> z_f = cast<float>(z); | ||||||
|          |          | ||||||
|  | @ -210,6 +212,7 @@ TriangleMesh::cut(z, upper, lower) | ||||||
|     TriangleMesh*   upper; |     TriangleMesh*   upper; | ||||||
|     TriangleMesh*   lower; |     TriangleMesh*   lower; | ||||||
|     CODE: |     CODE: | ||||||
|  |         THIS->require_shared_vertices(); // TriangleMeshSlicer needs this | ||||||
|         TriangleMeshSlicer mslicer(THIS); |         TriangleMeshSlicer mslicer(THIS); | ||||||
|         mslicer.cut(z, upper, lower); |         mslicer.cut(z, upper, lower); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ DEBUG_OUT_PATH_PREFIX() | ||||||
| SV* | SV* | ||||||
| FORK_NAME() | FORK_NAME() | ||||||
|     CODE: |     CODE: | ||||||
|         RETVAL = newSVpv(SLIC3R_FORK_NAME, 0); |         RETVAL = newSVpv(SLIC3R_APP_NAME, 0); | ||||||
|     OUTPUT: RETVAL |     OUTPUT: RETVAL | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv