mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Refactored PrintObject::m_copies to PrintInstances,
so that the ordering code at G-code export may work directly with pointers to PrintInstances instead of with pair of <PrintObject, copy idx>. Also the PrintInstance knows its source ModelInstance, which allows sorting of PrintInstances for sequential printing in the order they appear in Plater's object list.
This commit is contained in:
		
							parent
							
								
									cea7cbfaa0
								
							
						
					
					
						commit
						71fa411100
					
				
					 10 changed files with 226 additions and 209 deletions
				
			
		|  | @ -165,12 +165,12 @@ Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectP | |||
|              cnt = (cnt + 1) / 2; | ||||
|          } | ||||
|          // And collect copies of the objects.
 | ||||
|         for (const Point © : object->copies()) { | ||||
|         for (const PrintInstance &instance : object->instances()) { | ||||
|             // All the layers were reduced to the 1st item of polygons_per_layer.
 | ||||
|              size_t i = islands.size(); | ||||
|              polygons_append(islands, polygons_per_layer.front()); | ||||
|              for (; i < islands.size(); ++ i) | ||||
|                 islands[i].translate(copy); | ||||
|                 islands[i].translate(instance.shift); | ||||
|         } | ||||
|     } | ||||
|     return islands; | ||||
|  | @ -1088,49 +1088,38 @@ namespace DoExport { | |||
| } | ||||
| 
 | ||||
| // Sort the PrintObjects by their increasing Z, likely useful for avoiding colisions on Deltas during sequential prints.
 | ||||
| static inline std::vector<const PrintObject*> sort_objects_by_z(const Print &print) | ||||
| static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print) | ||||
| { | ||||
|     std::vector<const PrintObject*> objects(print.objects().begin(), print.objects().end()); | ||||
| 	std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); }); | ||||
| 	return objects; | ||||
| 	std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->size(2) < po2->size(2); }); | ||||
| 	std::vector<const PrintInstance*> instances; | ||||
| 	instances.reserve(objects.size()); | ||||
| 	for (const PrintObject *object : objects) | ||||
| 		for (size_t i = 0; i < object->instances().size(); ++ i) | ||||
| 			instances.emplace_back(&object->instances()[i]); | ||||
| 	return instances; | ||||
| } | ||||
| 
 | ||||
| // Produce a vector of PrintObjects in the order of their respective ModelObjects in print.model().
 | ||||
| static inline std::vector<const PrintObject*> sort_objects_by_model_order(const Print &print) | ||||
| static inline std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Print &print) | ||||
| { | ||||
| 	const Model &model = print.model(); | ||||
|     // Pair ModelObjects with PrintObjects, remember the order of ModelObjects in the model above.
 | ||||
| 	struct ModelObjectOrder { | ||||
| 		const ModelObject  *model_object; | ||||
| 		const PrintObject  *print_object; | ||||
| 		size_t 				order; | ||||
| 	}; | ||||
|     // Initialize model_object_order with ModelObjects and their order.
 | ||||
| 	std::vector<ModelObjectOrder> model_object_order; | ||||
| 	model_object_order.reserve(model.objects.size()); | ||||
|     { | ||||
| 	    size_t order = 0; | ||||
| 	    for (const ModelObject *model_object : model.objects) | ||||
|             model_object_order.emplace_back(ModelObjectOrder{ model_object, nullptr, order ++ }); | ||||
|     } | ||||
|     // Sort by pointer to ModelObject.
 | ||||
| 	std::sort(model_object_order.begin(), model_object_order.end(), [](const ModelObjectOrder &lhs, const ModelObjectOrder &rhs) { return lhs.model_object < rhs.model_object; }); | ||||
|     // Assign PrintObject pointer to ModelObject.
 | ||||
| 	for (const PrintObject *print_object : print.objects()) { | ||||
| 		auto it = Slic3r::lower_bound_by_predicate(model_object_order.begin(), model_object_order.end(), [print_object](const ModelObjectOrder &model_object_order) { return model_object_order.model_object < print_object->model_object(); }); | ||||
|         // The non-printable objects (objects outside of the print volume or suppressed objects) will have no partner in the print.objects() list.
 | ||||
| 		if (it != model_object_order.end() && it->model_object == print_object->model_object()) | ||||
| 			it->print_object = print_object; | ||||
| 	} | ||||
|     // Sort back to the initial order.
 | ||||
| 	std::sort(model_object_order.begin(), model_object_order.end(), [](const ModelObjectOrder &lhs, const ModelObjectOrder &rhs) { return lhs.order < rhs.order; }); | ||||
|     // Produce the output vector of PrintObjects, sorted by the order of ModelObjects in Model.
 | ||||
|     std::vector<const PrintObject*> objects; | ||||
|     objects.reserve(model_object_order.size()); | ||||
| 	for (ModelObjectOrder &order : model_object_order) | ||||
|         if (order.print_object != nullptr) | ||||
| 		    objects.emplace_back(order.print_object); | ||||
| 	return objects; | ||||
|     // Build up map from ModelInstance* to PrintInstance*
 | ||||
|     std::vector<std::pair<const ModelInstance*, const PrintInstance*>> model_instance_to_print_instance; | ||||
|     model_instance_to_print_instance.reserve(print.num_object_instances()); | ||||
|     for (const PrintObject *print_object : print.objects()) | ||||
|         for (const PrintInstance &print_instance : print_object->instances()) | ||||
|             model_instance_to_print_instance.emplace_back(print_instance.model_instance, &print_instance); | ||||
|     std::sort(model_instance_to_print_instance.begin(), model_instance_to_print_instance.end(), [](auto &l, auto &r) { return l.first < r.first; }); | ||||
| 
 | ||||
|     std::vector<const PrintInstance*> instances; | ||||
|     instances.reserve(model_instance_to_print_instance.size()); | ||||
|     for (const ModelObject *model_object : print.model().objects) | ||||
|         for (const ModelInstance *model_instance : model_object->instances) { | ||||
|             auto it = std::lower_bound(model_instance_to_print_instance.begin(), model_instance_to_print_instance.end(), std::make_pair(model_instance, nullptr), [](auto &l, auto &r) { return l.first < r.first; }); | ||||
|             if (it != model_instance_to_print_instance.end() && it->first == model_instance) | ||||
|                 instances.emplace_back(it->second); | ||||
|         } | ||||
|     return instances; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_THUMBNAIL_GENERATOR | ||||
|  | @ -1164,7 +1153,7 @@ void GCode::_do_export(Print& print, FILE* file) | |||
|             for (auto layer : object->support_layers()) | ||||
|                 zs.push_back(layer->print_z); | ||||
|             std::sort(zs.begin(), zs.end()); | ||||
|             m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); | ||||
|             m_layer_count += (unsigned int)(object->instances().size() * (std::unique(zs.begin(), zs.end()) - zs.begin())); | ||||
|         } | ||||
|     } else { | ||||
|         // Print all objects with the same print_z together.
 | ||||
|  | @ -1257,13 +1246,18 @@ void GCode::_do_export(Print& print, FILE* file) | |||
|     ToolOrdering tool_ordering; | ||||
|     unsigned int initial_extruder_id = (unsigned int)-1; | ||||
|     unsigned int final_extruder_id   = (unsigned int)-1; | ||||
|     size_t       initial_print_object_id = 0; | ||||
|     bool         has_wipe_tower      = false; | ||||
|     std::vector<const PrintInstance*> 					print_object_instances_ordering; | ||||
|     std::vector<const PrintInstance*>::const_iterator 	print_object_instance_sequential_active; | ||||
|     if (print.config().complete_objects.value) { | ||||
|         // Order object instances for sequential print.
 | ||||
|         print_object_instances_ordering = sort_object_instances_by_model_order(print); | ||||
| //        print_object_instances_ordering = sort_object_instances_by_max_z(print);
 | ||||
|         // Find the 1st printing object, find its tool ordering and the initial extruder ID.
 | ||||
|         for (; initial_print_object_id < print.objects().size(); ++initial_print_object_id) { | ||||
|             tool_ordering = ToolOrdering(*print.objects()[initial_print_object_id], initial_extruder_id); | ||||
|             if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) | ||||
|         print_object_instance_sequential_active = print_object_instances_ordering.begin(); | ||||
|         for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) { | ||||
|             tool_ordering = ToolOrdering(*(*print_object_instance_sequential_active)->print_object, initial_extruder_id); | ||||
|             if ((initial_extruder_id = tool_ordering.first_extruder()) != static_cast<unsigned int>(-1)) | ||||
|                 break; | ||||
|         } | ||||
|         // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
 | ||||
|  | @ -1283,6 +1277,8 @@ void GCode::_do_export(Print& print, FILE* file) | |||
|         // In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
 | ||||
|         // Therefore initialize the printing extruders from there.
 | ||||
|     	this->set_extruders(tool_ordering.all_extruders()); | ||||
|         // Order object instances using a nearest neighbor search.
 | ||||
|         print_object_instances_ordering = chain_print_object_instances(print); | ||||
|     } | ||||
|     if (initial_extruder_id == (unsigned int)-1) { | ||||
|         // Nothing to print!
 | ||||
|  | @ -1363,72 +1359,64 @@ void GCode::_do_export(Print& print, FILE* file) | |||
| 
 | ||||
|     // Do all objects for each layer.
 | ||||
|     if (print.config().complete_objects.value) { | ||||
|         // Print objects from the smallest to the tallest to avoid collisions
 | ||||
|         // when moving onto next object starting point.
 | ||||
|         std::vector<const PrintObject*> objects = sort_objects_by_model_order(print); | ||||
| //        std::vector<const PrintObject*> objects = sort_objects_by_z(print);
 | ||||
|         size_t finished_objects = 0; | ||||
|         for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) { | ||||
|             const PrintObject &object = *objects[object_id]; | ||||
|             for (const Point © : object.copies()) { | ||||
|                 // Get optimal tool ordering to minimize tool switches of a multi-exruder print.
 | ||||
|                 if (object_id != initial_print_object_id || © != object.copies().data()) { | ||||
|                     // Don't initialize for the first object and first copy.
 | ||||
|                     tool_ordering = ToolOrdering(object, final_extruder_id); | ||||
|                     unsigned int new_extruder_id = tool_ordering.first_extruder(); | ||||
|                     if (new_extruder_id == (unsigned int)-1) | ||||
|                         // Skip this object.
 | ||||
|                         continue; | ||||
|                     initial_extruder_id = new_extruder_id; | ||||
|                     final_extruder_id   = tool_ordering.last_extruder(); | ||||
|                     assert(final_extruder_id != (unsigned int)-1); | ||||
|                 } | ||||
|                 print.throw_if_canceled(); | ||||
|                 this->set_origin(unscale(copy)); | ||||
|                 if (finished_objects > 0) { | ||||
|                     // Move to the origin position for the copy we're going to print.
 | ||||
|                     // This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
 | ||||
|                     m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
 | ||||
|                     m_avoid_crossing_perimeters.use_external_mp_once = true; | ||||
|                     _write(file, this->retract()); | ||||
|                     _write(file, this->travel_to(Point(0, 0), erNone, "move to origin position for next object")); | ||||
|                     m_enable_cooling_markers = true; | ||||
|                     // Disable motion planner when traveling to first object point.
 | ||||
|                     m_avoid_crossing_perimeters.disable_once = true; | ||||
|                     // Ff we are printing the bottom layer of an object, and we have already finished
 | ||||
|                     // another one, set first layer temperatures. This happens before the Z move
 | ||||
|                     // is triggered, so machine has more time to reach such temperatures.
 | ||||
|                     m_placeholder_parser.set("current_object_idx", int(finished_objects)); | ||||
|                     std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id); | ||||
|                     // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
 | ||||
|                     this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); | ||||
|                     this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false); | ||||
|                     _writeln(file, between_objects_gcode); | ||||
|                 } | ||||
|                 // Reset the cooling buffer internal state (the current position, feed rate, accelerations).
 | ||||
|                 m_cooling_buffer->reset(); | ||||
|                 m_cooling_buffer->set_current_extruder(initial_extruder_id); | ||||
|                 // Pair the object layers with the support layers by z, extrude them.
 | ||||
|                 std::vector<LayerToPrint> layers_to_print = collect_layers_to_print(object); | ||||
|                 for (const LayerToPrint <p : layers_to_print) { | ||||
|                     std::vector<LayerToPrint> lrs; | ||||
|                     lrs.emplace_back(std::move(ltp)); | ||||
|                     this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), nullptr, © - object.copies().data()); | ||||
|                     print.throw_if_canceled(); | ||||
|                 } | ||||
| #ifdef HAS_PRESSURE_EQUALIZER | ||||
|                 if (m_pressure_equalizer) | ||||
|                     _write(file, m_pressure_equalizer->process("", true)); | ||||
| #endif /* HAS_PRESSURE_EQUALIZER */ | ||||
|                 ++ finished_objects; | ||||
|                 // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
 | ||||
|                 // Reset it when starting another object from 1st layer.
 | ||||
|                 m_second_layer_things_done = false; | ||||
|         const PrintObject *prev_object = (*print_object_instance_sequential_active)->print_object; | ||||
|         for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) { | ||||
|             const PrintObject &object = *(*print_object_instance_sequential_active)->print_object; | ||||
|             if (&object != prev_object || tool_ordering.first_extruder() != final_extruder_id) { | ||||
|                 tool_ordering = ToolOrdering(object, final_extruder_id); | ||||
|                 unsigned int new_extruder_id = tool_ordering.first_extruder(); | ||||
|                 if (new_extruder_id == (unsigned int)-1) | ||||
|                     // Skip this object.
 | ||||
|                     continue; | ||||
|                 initial_extruder_id = new_extruder_id; | ||||
|                 final_extruder_id   = tool_ordering.last_extruder(); | ||||
|                 assert(final_extruder_id != (unsigned int)-1); | ||||
|             } | ||||
|             print.throw_if_canceled(); | ||||
|             this->set_origin(unscale((*print_object_instance_sequential_active)->shift)); | ||||
|             if (finished_objects > 0) { | ||||
|                 // Move to the origin position for the copy we're going to print.
 | ||||
|                 // This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
 | ||||
|                 m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
 | ||||
|                 m_avoid_crossing_perimeters.use_external_mp_once = true; | ||||
|                 _write(file, this->retract()); | ||||
|                 _write(file, this->travel_to(Point(0, 0), erNone, "move to origin position for next object")); | ||||
|                 m_enable_cooling_markers = true; | ||||
|                 // Disable motion planner when traveling to first object point.
 | ||||
|                 m_avoid_crossing_perimeters.disable_once = true; | ||||
|                 // Ff we are printing the bottom layer of an object, and we have already finished
 | ||||
|                 // another one, set first layer temperatures. This happens before the Z move
 | ||||
|                 // is triggered, so machine has more time to reach such temperatures.
 | ||||
|                 m_placeholder_parser.set("current_object_idx", int(finished_objects)); | ||||
|                 std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id); | ||||
|                 // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
 | ||||
|                 this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); | ||||
|                 this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false); | ||||
|                 _writeln(file, between_objects_gcode); | ||||
|             } | ||||
|             // Reset the cooling buffer internal state (the current position, feed rate, accelerations).
 | ||||
|             m_cooling_buffer->reset(); | ||||
|             m_cooling_buffer->set_current_extruder(initial_extruder_id); | ||||
|             // Pair the object layers with the support layers by z, extrude them.
 | ||||
|             std::vector<LayerToPrint> layers_to_print = collect_layers_to_print(object); | ||||
|             for (const LayerToPrint <p : layers_to_print) { | ||||
|                 std::vector<LayerToPrint> lrs; | ||||
|                 lrs.emplace_back(std::move(ltp)); | ||||
|                 this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), nullptr, *print_object_instance_sequential_active - object.instances().data()); | ||||
|                 print.throw_if_canceled(); | ||||
|             } | ||||
| #ifdef HAS_PRESSURE_EQUALIZER | ||||
|             if (m_pressure_equalizer) | ||||
|                 _write(file, m_pressure_equalizer->process("", true)); | ||||
| #endif /* HAS_PRESSURE_EQUALIZER */ | ||||
|             ++ finished_objects; | ||||
|             // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
 | ||||
|             // Reset it when starting another object from 1st layer.
 | ||||
|             m_second_layer_things_done = false; | ||||
|             prev_object = &object; | ||||
|         } | ||||
|     } else { | ||||
|         // Order object instances using a nearest neighbor search.
 | ||||
|         std::vector<std::pair<size_t, size_t>> print_object_instances_ordering = chain_print_object_instances(print); | ||||
|         // Sort layers by Z.
 | ||||
|         // All extrusion moves with the same top layer height are extruded uninterrupted.
 | ||||
|         std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> layers_to_print = collect_layers_to_print(print); | ||||
|  | @ -1730,12 +1718,12 @@ inline std::vector<GCode::ObjectByExtruder::Island>& object_islands_by_extruder( | |||
| } | ||||
| 
 | ||||
| std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances( | ||||
| 	std::vector<GCode::ObjectByExtruder> 			&objects_by_extruder, | ||||
| 	const std::vector<LayerToPrint> 				&layers, | ||||
| 	std::vector<GCode::ObjectByExtruder> 		&objects_by_extruder, | ||||
| 	const std::vector<LayerToPrint> 			&layers, | ||||
| 	// Ordering must be defined for normal (non-sequential print).
 | ||||
| 	const std::vector<std::pair<size_t, size_t>> 	*ordering, | ||||
| 	const std::vector<const PrintInstance*> 	*ordering, | ||||
| 	// For sequential print, the instance of the object to be printing has to be defined.
 | ||||
| 	const size_t                     				 single_object_instance_idx) | ||||
| 	const size_t                     		 	 single_object_instance_idx) | ||||
| { | ||||
|     std::vector<InstanceToPrint> out; | ||||
| 
 | ||||
|  | @ -1762,13 +1750,13 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances( | |||
| 		if (! sorted.empty()) { | ||||
| 			const Print &print = *sorted.front().first->print(); | ||||
| 		    out.reserve(sorted.size()); | ||||
| 		    for (const std::pair<size_t, size_t> &instance_id : *ordering) { | ||||
| 		    	const PrintObject &print_object = *print.objects()[instance_id.first]; | ||||
| 		    for (const PrintInstance *instance : *ordering) { | ||||
| 		    	const PrintObject &print_object = *instance->print_object; | ||||
| 		    	std::pair<const PrintObject*, ObjectByExtruder*> key(&print_object, nullptr); | ||||
| 		    	auto it = std::lower_bound(sorted.begin(), sorted.end(), key); | ||||
| 		    	if (it != sorted.end() && it->first == &print_object) | ||||
| 		    		// ObjectByExtruder for this PrintObject was found.
 | ||||
| 					out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance_id.second); | ||||
| 					out.emplace_back(*it->second, it->second - objects_by_extruder.data(), print_object, instance - print_object.instances().data()); | ||||
| 		    } | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1912,16 +1900,16 @@ namespace Skirt { | |||
| // and performing the extruder specific extrusions together.
 | ||||
| void GCode::process_layer( | ||||
|     // Write into the output file.
 | ||||
|     FILE                            *file, | ||||
|     const Print                     &print, | ||||
|     FILE                            		*file, | ||||
|     const Print                    			&print, | ||||
|     // Set of object & print layers of the same PrintObject and with the same print_z.
 | ||||
|     const std::vector<LayerToPrint> &layers, | ||||
|     const LayerTools                &layer_tools, | ||||
|     const std::vector<LayerToPrint> 		&layers, | ||||
|     const LayerTools        		        &layer_tools, | ||||
| 	// Pairs of PrintObject index and its instance index.
 | ||||
| 	const std::vector<std::pair<size_t, size_t>> *ordering, | ||||
| 	const std::vector<const PrintInstance*> *ordering, | ||||
|     // If set to size_t(-1), then print all copies of all objects.
 | ||||
|     // Otherwise print a single copy of a single object.
 | ||||
|     const size_t                     single_object_instance_idx) | ||||
|     const size_t                     		 single_object_instance_idx) | ||||
| { | ||||
|     assert(! layers.empty()); | ||||
| //    assert(! layer_tools.extruders.empty());
 | ||||
|  | @ -2130,7 +2118,7 @@ void GCode::process_layer( | |||
| 	                            // by last extruder on this layer (could happen e.g. when a wiping object is taller than others - dontcare extruders are eradicated from layer_tools)
 | ||||
| 	                            correct_extruder_id = layer_tools.extruders.back(); | ||||
| 	                        } | ||||
|                         	entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->copies().size()); | ||||
|                         	entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(extrusions, correct_extruder_id, layer_to_print.object()->instances().size()); | ||||
| 	                        if (entity_overrides == nullptr) { | ||||
| 	                        	printing_extruders.emplace_back(correct_extruder_id); | ||||
| 	                        } else { | ||||
|  | @ -2244,7 +2232,7 @@ void GCode::process_layer( | |||
|                 if (this->config().gcode_label_objects) | ||||
|                     gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n"; | ||||
|                 // When starting a new object, use the external motion planner for the first travel move.
 | ||||
|                 const Point &offset = instance_to_print.print_object.copies()[instance_to_print.instance_id]; | ||||
|                 const Point &offset = instance_to_print.print_object.instances()[instance_to_print.instance_id].shift; | ||||
|                 std::pair<const PrintObject*, Point> this_object_copy(&instance_to_print.print_object, offset); | ||||
|                 if (m_last_obj_copy != this_object_copy) | ||||
|                     m_avoid_crossing_perimeters.use_external_mp_once = true; | ||||
|  |  | |||
|  | @ -226,7 +226,7 @@ private: | |||
|         const std::vector<LayerToPrint> &layers, | ||||
|         const LayerTools  				&layer_tools, | ||||
| 		// Pairs of PrintObject index and its instance index.
 | ||||
| 		const std::vector<std::pair<size_t, size_t>> *ordering, | ||||
| 		const std::vector<const PrintInstance*> *ordering, | ||||
|         // If set to size_t(-1), then print all copies of all objects.
 | ||||
|         // Otherwise print a single copy of a single object.
 | ||||
|         const size_t                     single_object_idx = size_t(-1)); | ||||
|  | @ -300,7 +300,7 @@ private: | |||
| 		// Object and Support layers for the current print_z, collected for a single object, or for possibly multiple objects with multiple instances.
 | ||||
| 		const std::vector<LayerToPrint> 				&layers, | ||||
| 		// Ordering must be defined for normal (non-sequential print).
 | ||||
| 		const std::vector<std::pair<size_t, size_t>> 	*ordering, | ||||
| 		const std::vector<const PrintInstance*>     	*ordering, | ||||
| 		// For sequential print, the instance of the object to be printing has to be defined.
 | ||||
| 		const size_t                     				 single_object_instance_idx); | ||||
| 
 | ||||
|  |  | |||
|  | @ -121,9 +121,9 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object | |||
|         if (support_layer) | ||||
|             for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) | ||||
|                 bbox_this.merge(extrusionentity_extents(extrusion_entity)); | ||||
|         for (const Point &offset : print_object.copies()) { | ||||
|         for (const PrintInstance &instance : print_object.instances()) { | ||||
|             BoundingBoxf bbox_translated(bbox_this); | ||||
|             bbox_translated.translate(unscale(offset)); | ||||
|             bbox_translated.translate(unscale(instance.shift)); | ||||
|             bbox.merge(bbox_translated); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -491,7 +491,7 @@ void ToolOrdering::assign_custom_gcodes(const Print &print) | |||
| 		if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) { | ||||
| 			// The custom G-code applies to the current layer.
 | ||||
| 			if ( tool_changes_as_color_changes || custom_gcode.gcode != ColorChangeCode ||  | ||||
|                 (custom_gcode.extruder <= num_extruders && extruder_printing_above[unsigned(custom_gcode.extruder - 1)])) | ||||
|                 (custom_gcode.extruder <= int(num_extruders) && extruder_printing_above[unsigned(custom_gcode.extruder - 1)])) | ||||
| 				// If it is color change, it will actually be useful as the exturder above will print.
 | ||||
|         		lt.custom_gcode = &custom_gcode; | ||||
| 			// Consume that custom G-code event.
 | ||||
|  | @ -602,7 +602,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int | |||
|         const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON); | ||||
|         if (this_layer == nullptr) | ||||
|         	continue; | ||||
|         size_t num_of_copies = object->copies().size(); | ||||
|         size_t num_of_copies = object->instances().size(); | ||||
| 
 | ||||
|         // iterate through copies (aka PrintObject instances) first, so that we mark neighbouring infills to minimize travel moves
 | ||||
|         for (unsigned int copy = 0; copy < num_of_copies; ++copy) { | ||||
|  | @ -677,7 +677,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print) | |||
|         const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON); | ||||
|         if (this_layer == nullptr) | ||||
|         	continue; | ||||
|         size_t num_of_copies = object->copies().size(); | ||||
|         size_t num_of_copies = object->instances().size(); | ||||
| 
 | ||||
|         for (size_t copy = 0; copy < num_of_copies; ++copy) {    // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
 | ||||
|             for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) { | ||||
|  |  | |||
|  | @ -326,7 +326,7 @@ unsigned int Print::num_object_instances() const | |||
| { | ||||
| 	unsigned int instances = 0; | ||||
|     for (const PrintObject *print_object : m_objects) | ||||
|         instances += (unsigned int)print_object->copies().size(); | ||||
|         instances += (unsigned int)print_object->instances().size(); | ||||
|     return instances; | ||||
| } | ||||
| 
 | ||||
|  | @ -447,33 +447,30 @@ static inline bool transform3d_equal(const Transform3d &lhs, const Transform3d & | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| struct PrintInstances | ||||
| struct PrintObjectTrafoAndInstances | ||||
| { | ||||
|     Transform3d     trafo; | ||||
|     Points          copies; | ||||
|     bool operator<(const PrintInstances &rhs) const { return transform3d_lower(this->trafo, rhs.trafo); } | ||||
|     Transform3d    	trafo; | ||||
|     PrintInstances	instances; | ||||
|     bool operator<(const PrintObjectTrafoAndInstances &rhs) const { return transform3d_lower(this->trafo, rhs.trafo); } | ||||
| }; | ||||
| 
 | ||||
| // Generate a list of trafos and XY offsets for instances of a ModelObject
 | ||||
| static std::vector<PrintInstances> print_objects_from_model_object(const ModelObject &model_object) | ||||
| static std::vector<PrintObjectTrafoAndInstances> print_objects_from_model_object(const ModelObject &model_object) | ||||
| { | ||||
|     std::set<PrintInstances> trafos; | ||||
|     PrintInstances           trafo; | ||||
|     trafo.copies.assign(1, Point()); | ||||
|     std::set<PrintObjectTrafoAndInstances> trafos; | ||||
|     PrintObjectTrafoAndInstances           trafo; | ||||
|     for (ModelInstance *model_instance : model_object.instances) | ||||
|         if (model_instance->is_printable()) { | ||||
|             trafo.trafo = model_instance->get_matrix(); | ||||
|             auto shift = Point::new_scale(trafo.trafo.data()[12], trafo.trafo.data()[13]); | ||||
|             // Set the Z axis of the transformation.
 | ||||
|             trafo.copies.front() = Point::new_scale(trafo.trafo.data()[12], trafo.trafo.data()[13]); | ||||
|             trafo.trafo.data()[12] = 0; | ||||
|             trafo.trafo.data()[13] = 0; | ||||
|             auto it = trafos.find(trafo); | ||||
|             if (it == trafos.end()) | ||||
|                 trafos.emplace(trafo); | ||||
|             else | ||||
|                 const_cast<PrintInstances&>(*it).copies.emplace_back(trafo.copies.front()); | ||||
|             // Search or insert a trafo.
 | ||||
|             auto it = trafos.emplace(trafo).first; | ||||
|             const_cast<PrintObjectTrafoAndInstances&>(*it).instances.emplace_back(PrintInstance{ nullptr, model_instance, shift }); | ||||
|         } | ||||
|     return std::vector<PrintInstances>(trafos.begin(), trafos.end()); | ||||
|     return std::vector<PrintObjectTrafoAndInstances>(trafos.begin(), trafos.end()); | ||||
| } | ||||
| 
 | ||||
| // Compare just the layer ranges and their layer heights, not the associated configs.
 | ||||
|  | @ -891,12 +888,27 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|             // Copy the ModelObject name, input_file and instances. The instances will be compared against PrintObject instances in the next step.
 | ||||
|             model_object.name       = model_object_new.name; | ||||
|             model_object.input_file = model_object_new.input_file; | ||||
|             model_object.clear_instances(); | ||||
|             model_object.instances.reserve(model_object_new.instances.size()); | ||||
|             for (const ModelInstance *model_instance : model_object_new.instances) { | ||||
|                 model_object.instances.emplace_back(new ModelInstance(*model_instance)); | ||||
|                 model_object.instances.back()->set_model_object(&model_object); | ||||
|             } | ||||
|             // Only refresh ModelInstances if there is any change.
 | ||||
|             if (model_object.instances.size() != model_object_new.instances.size() ||  | ||||
|             	! std::equal(model_object.instances.begin(), model_object.instances.end(), model_object_new.instances.begin(), [](auto l, auto r){ return l->id() == r->id(); })) { | ||||
|             	// G-code generator accesses model_object.instances to generate sequential print ordering matching the Plater object list.
 | ||||
|             	update_apply_status(this->invalidate_step(psGCodeExport)); | ||||
| 	            model_object.clear_instances(); | ||||
| 	            model_object.instances.reserve(model_object_new.instances.size()); | ||||
| 	            for (const ModelInstance *model_instance : model_object_new.instances) { | ||||
| 	                model_object.instances.emplace_back(new ModelInstance(*model_instance)); | ||||
| 	                model_object.instances.back()->set_model_object(&model_object); | ||||
| 	            } | ||||
| 	        } else { | ||||
| 	        	// Just synchronize the content of the instances. This avoids memory allocation and it does not invalidate ModelInstance pointers,
 | ||||
| 	        	// which may be accessed by G-code export in the meanwhile to deduce sequential print order.
 | ||||
|                 auto new_instance = model_object_new.instances.begin(); | ||||
| 				for (auto old_instance = model_object.instances.begin(); old_instance != model_object.instances.end(); ++ old_instance, ++ new_instance) { | ||||
| 					(*old_instance)->set_transformation((*new_instance)->get_transformation()); | ||||
|                     (*old_instance)->print_volume_state = (*new_instance)->print_volume_state; | ||||
|                     (*old_instance)->printable 		    = (*new_instance)->printable; | ||||
|   				} | ||||
| 	        } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -917,13 +929,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|             } | ||||
|             // Generate a list of trafos and XY offsets for instances of a ModelObject
 | ||||
|             PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders); | ||||
|             std::vector<PrintInstances> new_print_instances = print_objects_from_model_object(*model_object); | ||||
|             std::vector<PrintObjectTrafoAndInstances> new_print_instances = print_objects_from_model_object(*model_object); | ||||
|             if (old.empty()) { | ||||
|                 // Simple case, just generate new instances.
 | ||||
|                 for (const PrintInstances &print_instances : new_print_instances) { | ||||
|                 for (PrintObjectTrafoAndInstances &print_instances : new_print_instances) { | ||||
|                     PrintObject *print_object = new PrintObject(this, model_object, false); | ||||
| 					print_object->set_trafo(print_instances.trafo); | ||||
|                     print_object->set_copies(print_instances.copies); | ||||
| 					print_object->set_trafo_and_instances(print_instances.trafo, std::move(print_instances.instances)); | ||||
|                     print_object->config_apply(config); | ||||
|                     print_objects_new.emplace_back(print_object); | ||||
|                     // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
 | ||||
|  | @ -936,13 +947,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|             std::sort(old.begin(), old.end(), [](const PrintObjectStatus *lhs, const PrintObjectStatus *rhs){ return transform3d_lower(lhs->trafo, rhs->trafo); }); | ||||
|             // Merge the old / new lists.
 | ||||
|             auto it_old = old.begin(); | ||||
|             for (const PrintInstances &new_instances : new_print_instances) { | ||||
|             for (PrintObjectTrafoAndInstances &new_instances : new_print_instances) { | ||||
| 				for (; it_old != old.end() && transform3d_lower((*it_old)->trafo, new_instances.trafo); ++ it_old); | ||||
| 				if (it_old == old.end() || ! transform3d_equal((*it_old)->trafo, new_instances.trafo)) { | ||||
|                     // This is a new instance (or a set of instances with the same trafo). Just add it.
 | ||||
|                     PrintObject *print_object = new PrintObject(this, model_object, false); | ||||
|                     print_object->set_trafo(new_instances.trafo); | ||||
|                     print_object->set_copies(new_instances.copies); | ||||
| 					print_object->set_trafo_and_instances(new_instances.trafo, std::move(new_instances.instances)); | ||||
|                     print_object->config_apply(config); | ||||
|                     print_objects_new.emplace_back(print_object); | ||||
|                     // print_object_status.emplace(PrintObjectStatus(print_object, PrintObjectStatus::New));
 | ||||
|  | @ -951,7 +961,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ | |||
|                         const_cast<PrintObjectStatus*>(*it_old)->status = PrintObjectStatus::Deleted; | ||||
|                 } else { | ||||
|                     // The PrintObject already exists and the copies differ.
 | ||||
| 					PrintBase::ApplyStatus status = (*it_old)->print_object->set_copies(new_instances.copies); | ||||
| 					PrintBase::ApplyStatus status = (*it_old)->print_object->set_instances(std::move(new_instances.instances)); | ||||
|                     if (status != PrintBase::APPLY_STATUS_UNCHANGED) | ||||
| 						update_apply_status(status == PrintBase::APPLY_STATUS_INVALIDATED); | ||||
| 					print_objects_new.emplace_back((*it_old)->print_object); | ||||
|  | @ -1159,7 +1169,7 @@ std::string Print::validate() const | |||
|             Polygons convex_hulls_other; | ||||
|             for (const PrintObject *print_object : m_objects) { | ||||
|                 assert(! print_object->model_object()->instances.empty()); | ||||
|                 assert(! print_object->copies().empty()); | ||||
|                 assert(! print_object->instances().empty()); | ||||
|                 // Get convex hull of all meshes assigned to this print object.
 | ||||
|                 ModelInstance *model_instance0 = print_object->model_object()->instances.front(); | ||||
|                 Vec3d          rotation        = model_instance0->get_rotation(); | ||||
|  | @ -1174,9 +1184,9 @@ std::string Print::validate() const | |||
|                         Geometry::assemble_transform(Vec3d::Zero(), rotation, model_instance0->get_scaling_factor(), model_instance0->get_mirror())), | ||||
|                     float(scale_(0.5 * m_config.extruder_clearance_radius.value)), jtRound, float(scale_(0.1))).front(); | ||||
|                 // Now we check that no instance of convex_hull intersects any of the previously checked object instances.
 | ||||
|                 for (const Point © : print_object->copies()) { | ||||
|                 for (const PrintInstance &instance : print_object->instances()) { | ||||
|                     Polygon convex_hull = convex_hull0; | ||||
|                     convex_hull.translate(copy); | ||||
|                     convex_hull.translate(instance.shift); | ||||
|                     if (! intersection(convex_hulls_other, convex_hull).empty()) | ||||
|                         return L("Some objects are too close; your extruder will collide with them."); | ||||
|                     polygons_append(convex_hulls_other, convex_hull); | ||||
|  | @ -1187,7 +1197,7 @@ std::string Print::validate() const | |||
|         { | ||||
|             std::vector<coord_t> object_height; | ||||
|             for (const PrintObject *object : m_objects) | ||||
|                 object_height.insert(object_height.end(), object->copies().size(), object->size(2)); | ||||
|                 object_height.insert(object_height.end(), object->instances().size(), object->size(2)); | ||||
|             std::sort(object_height.begin(), object_height.end()); | ||||
|             // Ignore the tallest *copy* (this is why we repeat height for all of them):
 | ||||
|             // it will be printed as last one so its height doesn't matter.
 | ||||
|  | @ -1200,7 +1210,7 @@ std::string Print::validate() const | |||
|     if (m_config.spiral_vase) { | ||||
|         size_t total_copies_count = 0; | ||||
|         for (const PrintObject *object : m_objects) | ||||
|             total_copies_count += object->copies().size(); | ||||
|             total_copies_count += object->instances().size(); | ||||
|         // #4043
 | ||||
|         if (total_copies_count > 1 && ! m_config.complete_objects.value) | ||||
|             return L("The Spiral Vase option can only be used when printing a single object."); | ||||
|  | @ -1417,10 +1427,9 @@ BoundingBox Print::bounding_box() const | |||
| { | ||||
|     BoundingBox bb; | ||||
|     for (const PrintObject *object : m_objects) | ||||
|         for (Point copy : object->m_copies) { | ||||
|             bb.merge(copy); | ||||
|             copy += to_2d(object->size); | ||||
|             bb.merge(copy); | ||||
|         for (const PrintInstance &instance : object->instances()) { | ||||
|             bb.merge(instance.shift); | ||||
|             bb.merge(instance.shift + to_2d(object->size)); | ||||
|         } | ||||
|     return bb; | ||||
| } | ||||
|  | @ -1657,10 +1666,10 @@ void Print::_make_skirt() | |||
|                 append(object_points, extrusion_entity->as_polyline().points); | ||||
|         } | ||||
|         // Repeat points for each object copy.
 | ||||
|         for (const Point &shift : object->m_copies) { | ||||
|         for (const PrintInstance &instance : object->instances()) { | ||||
|             Points copy_points = object_points; | ||||
|             for (Point &pt : copy_points) | ||||
|                 pt += shift; | ||||
|                 pt += instance.shift; | ||||
|             append(points, copy_points); | ||||
|         } | ||||
|     } | ||||
|  | @ -1778,11 +1787,11 @@ void Print::_make_brim() | |||
|             object_islands.push_back(expoly.contour); | ||||
|         if (! object->support_layers().empty()) | ||||
|             object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON)); | ||||
|         islands.reserve(islands.size() + object_islands.size() * object->m_copies.size()); | ||||
|         for (const Point &pt : object->m_copies) | ||||
|         islands.reserve(islands.size() + object_islands.size() * object->instances().size()); | ||||
|         for (const PrintInstance &instance : object->instances()) | ||||
|             for (Polygon &poly : object_islands) { | ||||
|                 islands.push_back(poly); | ||||
|                 islands.back().translate(pt); | ||||
|                 islands.back().translate(instance.shift); | ||||
|             } | ||||
|     } | ||||
|     Polygons loops; | ||||
|  |  | |||
|  | @ -92,6 +92,21 @@ typedef std::vector<Layer*> LayerPtrs; | |||
| typedef std::vector<SupportLayer*> SupportLayerPtrs; | ||||
| class BoundingBoxf3;        // TODO: for temporary constructor parameter
 | ||||
| 
 | ||||
| // Single instance of a PrintObject.
 | ||||
| // As multiple PrintObjects may be generated for a single ModelObject (their instances differ in rotation around Z),
 | ||||
| // ModelObject's instancess will be distributed among these multiple PrintObjects.
 | ||||
| struct PrintInstance | ||||
| { | ||||
|     // Parent PrintObject
 | ||||
|     PrintObject 		*print_object; | ||||
|     // Source ModelInstance of a ModelObject, for which this print_object was created.
 | ||||
| 	const ModelInstance *model_instance; | ||||
| 	// Shift of this instance towards its PrintObject
 | ||||
| 	Point 				 shift; | ||||
| }; | ||||
| 
 | ||||
| typedef std::vector<PrintInstance> PrintInstances; | ||||
| 
 | ||||
| class PrintObject : public PrintObjectBaseWithState<Print, PrintObjectStep, posCount> | ||||
| { | ||||
| private: // Prevents erroneous use by other classes.
 | ||||
|  | @ -111,8 +126,8 @@ public: | |||
|     const LayerPtrs&        layers() const          { return m_layers; } | ||||
|     const SupportLayerPtrs& support_layers() const  { return m_support_layers; } | ||||
|     const Transform3d&      trafo() const           { return m_trafo; } | ||||
|     const Points&           copies() const          { return m_copies; } | ||||
|     const Point 			copy_center(size_t idx) const { return m_copies[idx] + m_copies_shift + Point(this->size.x() / 2, this->size.y() / 2); } | ||||
|     const PrintInstances&   instances() const       { return m_instances; } | ||||
|     const Point 			instance_center(size_t idx) const { return m_instances[idx].shift + m_copies_shift + Point(this->size.x() / 2, this->size.y() / 2); } | ||||
| 
 | ||||
|     // since the object is aligned to origin, bounding box coincides with size
 | ||||
|     BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); } | ||||
|  | @ -126,9 +141,9 @@ public: | |||
|     // This is the *total* layer count (including support layers)
 | ||||
|     // this value is not supposed to be compared with Layer::id
 | ||||
|     // since they have different semantics.
 | ||||
|     size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); } | ||||
|     size_t layer_count() const { return m_layers.size(); } | ||||
|     void clear_layers(); | ||||
|     size_t 			total_layer_count() const { return this->layer_count() + this->support_layer_count(); } | ||||
|     size_t 			layer_count() const { return m_layers.size(); } | ||||
|     void 			clear_layers(); | ||||
|     const Layer* 	get_layer(int idx) const { return m_layers[idx]; } | ||||
|     Layer* 			get_layer(int idx) 		 { return m_layers[idx]; } | ||||
|     // Get a layer exactly at print_z.
 | ||||
|  | @ -177,7 +192,7 @@ public: | |||
|     std::vector<ExPolygons>     slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); } | ||||
|     std::vector<ExPolygons>     slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); } | ||||
| 
 | ||||
| protected: | ||||
| private: | ||||
|     // to be called from Print only.
 | ||||
|     friend class Print; | ||||
| 
 | ||||
|  | @ -187,7 +202,8 @@ protected: | |||
|     void                    config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); } | ||||
|     void                    config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); } | ||||
|     void                    set_trafo(const Transform3d& trafo) { m_trafo = trafo; } | ||||
|     PrintBase::ApplyStatus  set_copies(const Points &points); | ||||
|     PrintBase::ApplyStatus  set_instances(PrintInstances &&instances); | ||||
|     void 					set_trafo_and_instances(const Transform3d& trafo, PrintInstances &&instances) { this->set_trafo(trafo); this->set_instances(std::move(instances)); } | ||||
|     // Invalidates the step, and its depending steps in PrintObject and Print.
 | ||||
|     bool                    invalidate_step(PrintObjectStep step); | ||||
|     // Invalidates all PrintObject and Print steps.
 | ||||
|  | @ -223,7 +239,7 @@ private: | |||
|     // Translation in Z + Rotation + Scaling / Mirroring.
 | ||||
|     Transform3d                             m_trafo = Transform3d::Identity(); | ||||
|     // Slic3r::Point objects in scaled G-code coordinates
 | ||||
|     Points                                  m_copies; | ||||
|     std::vector<PrintInstance>              m_instances; | ||||
|     // scaled coordinates to add to copies (to compensate for the alignment
 | ||||
|     // operated when creating the object but still preserving a coherent API
 | ||||
|     // for external callers)
 | ||||
|  |  | |||
|  | @ -60,32 +60,32 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta | |||
|     } | ||||
|      | ||||
|     if (add_instances) { | ||||
|         Points copies; | ||||
|         copies.reserve(m_model_object->instances.size()); | ||||
|         PrintInstances instances; | ||||
|         instances.reserve(m_model_object->instances.size()); | ||||
|         for (const ModelInstance *mi : m_model_object->instances) { | ||||
|             assert(mi->is_printable()); | ||||
|             const Vec3d& offset = mi->get_offset(); | ||||
|             copies.emplace_back(Point::new_scale(offset(0), offset(1))); | ||||
|             const Vec3d &offset = mi->get_offset(); | ||||
|             instances.emplace_back(PrintInstance{ nullptr, mi, Point::new_scale(offset(0), offset(1)) }); | ||||
|         } | ||||
|         this->set_copies(copies); | ||||
|         this->set_instances(std::move(instances)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| PrintBase::ApplyStatus PrintObject::set_copies(const Points &points) | ||||
| PrintBase::ApplyStatus PrintObject::set_instances(PrintInstances &&instances) | ||||
| { | ||||
|     // Order copies with a nearest-neighbor search.
 | ||||
|     std::vector<Point> copies; | ||||
|     copies.reserve(points.size()); | ||||
|     for (const Point &pt : points) | ||||
|         copies.emplace_back(pt + m_copies_shift); | ||||
|     // Invalidate and set copies.
 | ||||
|     PrintBase::ApplyStatus status = PrintBase::APPLY_STATUS_UNCHANGED; | ||||
|     if (copies != m_copies) { | ||||
|     bool equal_length = instances.size() == m_instances.size(); | ||||
|     bool equal = equal_length && std::equal(instances.begin(), instances.end(), m_instances.begin(),  | ||||
|     	[](const PrintInstance& lhs, const PrintInstance& rhs) { return lhs.model_instance == rhs.model_instance && lhs.shift == rhs.shift; }); | ||||
|     if (! equal) { | ||||
|         status = PrintBase::APPLY_STATUS_CHANGED; | ||||
|         if (m_print->invalidate_steps({ psSkirt, psBrim, psGCodeExport }) || | ||||
|             (copies.size() != m_copies.size() && m_print->invalidate_step(psWipeTower))) | ||||
|             (! equal_length && m_print->invalidate_step(psWipeTower))) | ||||
|             status = PrintBase::APPLY_STATUS_INVALIDATED; | ||||
|         m_copies = copies; | ||||
|         m_instances = instances; | ||||
| 	    for (PrintInstance &i : m_instances) | ||||
| 	    	i.print_object = this; | ||||
|     } | ||||
|     return status; | ||||
| } | ||||
|  | @ -669,7 +669,7 @@ void PrintObject::detect_surfaces_type() | |||
|                     m_print->throw_if_canceled(); | ||||
|                     // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << idx_region << " and layer " << layer->print_z;
 | ||||
|                     Layer       *layer  = m_layers[idx_layer]; | ||||
|                     LayerRegion *layerm = layer->get_region(idx_region); | ||||
|                     LayerRegion *layerm = layer->m_regions[idx_region]; | ||||
|                     // comparison happens against the *full* slices (considering all regions)
 | ||||
|                     // unless internal shells are requested
 | ||||
|                     Layer       *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr; | ||||
|  | @ -684,7 +684,7 @@ void PrintObject::detect_surfaces_type() | |||
|                     Surfaces top; | ||||
|                     if (upper_layer) { | ||||
|                         Polygons upper_slices = interface_shells ?  | ||||
|                             to_polygons(upper_layer->get_region(idx_region)->slices.surfaces) :  | ||||
|                             to_polygons(upper_layer->m_regions[idx_region]->slices.surfaces) :  | ||||
|                             to_polygons(upper_layer->lslices); | ||||
|                         surfaces_append(top, | ||||
|                             //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice.
 | ||||
|  | @ -727,7 +727,7 @@ void PrintObject::detect_surfaces_type() | |||
|                                 offset2_ex( | ||||
|                                     diff( | ||||
|                                         intersection(layerm_slices_surfaces, to_polygons(lower_layer->lslices)), // supported
 | ||||
|                                         to_polygons(lower_layer->get_region(idx_region)->slices.surfaces),  | ||||
|                                         to_polygons(lower_layer->m_regions[idx_region]->slices.surfaces),  | ||||
|                                         true),  | ||||
|                                     -offset, offset), | ||||
|                                 stBottom); | ||||
|  | @ -796,7 +796,7 @@ void PrintObject::detect_surfaces_type() | |||
|         if (interface_shells) { | ||||
|             // Move surfaces_new to layerm->slices.surfaces
 | ||||
|             for (size_t idx_layer = 0; idx_layer < m_layers.size(); ++ idx_layer) | ||||
|                 m_layers[idx_layer]->get_region(idx_region)->slices.surfaces = std::move(surfaces_new[idx_layer]); | ||||
|                 m_layers[idx_layer]->m_regions[idx_region]->slices.surfaces = std::move(surfaces_new[idx_layer]); | ||||
|         } | ||||
| 
 | ||||
|         BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start"; | ||||
|  | @ -806,7 +806,7 @@ void PrintObject::detect_surfaces_type() | |||
|             [this, idx_region, interface_shells, &surfaces_new](const tbb::blocked_range<size_t>& range) { | ||||
|                 for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { | ||||
|                     m_print->throw_if_canceled(); | ||||
|                     LayerRegion *layerm = m_layers[idx_layer]->get_region(idx_region); | ||||
|                     LayerRegion *layerm = m_layers[idx_layer]->m_regions[idx_region]; | ||||
|                     layerm->slices_to_fill_surfaces_clipped(); | ||||
| #ifdef SLIC3R_DEBUG_SLICE_PROCESSING | ||||
|                     layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final"); | ||||
|  |  | |||
|  | @ -1946,24 +1946,26 @@ ClipperLib::PolyNodes chain_clipper_polynodes(const Points &points, const Clippe | |||
| 	return chain_path_items(points, items); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::pair<size_t, size_t>> chain_print_object_instances(const Print &print) | ||||
| std::vector<const PrintInstance*> chain_print_object_instances(const Print &print) | ||||
| { | ||||
|     // Order objects using a nearest neighbor search.
 | ||||
|     Points object_reference_points; | ||||
|     std::vector<std::pair<size_t, size_t>> instances; | ||||
|     for (size_t i = 0; i < print.objects().size(); ++ i) { | ||||
|     	const PrintObject &object = *print.objects()[i]; | ||||
|     	for (size_t j = 0; j < object.copies().size(); ++ j) { | ||||
|         	object_reference_points.emplace_back(object.copy_center(j)); | ||||
|     	for (size_t j = 0; j < object.instances().size(); ++ j) { | ||||
|         	object_reference_points.emplace_back(object.instance_center(j)); | ||||
|         	instances.emplace_back(i, j); | ||||
|         } | ||||
|     } | ||||
| 	auto segment_end_point = [&object_reference_points](size_t idx, bool /* first_point */) -> const Point& { return object_reference_points[idx]; }; | ||||
| 	std::vector<std::pair<size_t, bool>> ordered = chain_segments_greedy<Point, decltype(segment_end_point)>(segment_end_point, instances.size(), nullptr); | ||||
|     std::vector<std::pair<size_t, size_t>> out; | ||||
|     std::vector<const PrintInstance*> out; | ||||
| 	out.reserve(instances.size()); | ||||
| 	for (auto &segment_and_reversal : ordered) | ||||
| 		out.emplace_back(instances[segment_and_reversal.first]); | ||||
| 	for (auto &segment_and_reversal : ordered) { | ||||
| 		const std::pair<size_t, size_t> &inst = instances[segment_and_reversal.first]; | ||||
| 		out.emplace_back(&print.objects()[inst.first]->instances()[inst.second]); | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,7 +30,8 @@ std::vector<ClipperLib::PolyNode*>	 chain_clipper_polynodes(const Points &points | |||
| // Chain instances of print objects by an approximate shortest path.
 | ||||
| // Returns pairs of PrintObject idx and instance of that PrintObject.
 | ||||
| class Print; | ||||
| std::vector<std::pair<size_t, size_t>> chain_print_object_instances(const Print &print); | ||||
| struct PrintInstance; | ||||
| std::vector<const PrintInstance*> 	 chain_print_object_instances(const Print &print); | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv