mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	A simple algorithm to follow the boundary of polygons
This commit is contained in:
		
							parent
							
								
									e04c6a4d17
								
							
						
					
					
						commit
						7a4ba7d131
					
				
					 2 changed files with 112 additions and 3 deletions
				
			
		|  | @ -176,6 +176,93 @@ namespace Slic3r { | |||
|         return islands; | ||||
|     } | ||||
| 
 | ||||
|     Matrix2d rotation_by_direction(const Point &direction) | ||||
|     { | ||||
|         Matrix2d rotation; | ||||
|         rotation.block<1, 2>(0, 0) = direction.cast<double>() / direction.cast<double>().norm(); | ||||
|         rotation(1, 0)             = -rotation(0, 1); | ||||
|         rotation(1, 1)             = rotation(0, 0); | ||||
| 
 | ||||
|         return rotation; | ||||
|     } | ||||
| 
 | ||||
|     Polyline AvoidCrossingPerimeters2::travel_to(const GCode &gcodegen, const Point &point) | ||||
|     { | ||||
|         const Point &start                 = gcodegen.last_pos(); | ||||
|         const Point &end                   = point; | ||||
|         const Point  direction             = end - start; | ||||
|         Matrix2d     transform_to_x_axis   = rotation_by_direction(direction); | ||||
|         Matrix2d     transform_from_x_axis = transform_to_x_axis.transpose(); | ||||
| 
 | ||||
|         const Line travel_line((transform_to_x_axis * start.cast<double>()).cast<coord_t>(), | ||||
|                                (transform_to_x_axis * end.cast<double>()).cast<coord_t>()); | ||||
| 
 | ||||
|         Polygons borders; | ||||
|         borders.reserve(gcodegen.layer()->lslices.size()); | ||||
| 
 | ||||
|         for (const ExPolygon &ex_polygon : gcodegen.layer()->lslices) { | ||||
|             borders.emplace_back(ex_polygon.contour); | ||||
| 
 | ||||
|             for (const Polygon &hole : ex_polygon.holes) borders.emplace_back(hole); | ||||
|         } | ||||
| 
 | ||||
|         std::vector<Intersection> intersections; | ||||
|         for (size_t border_idx = 0; border_idx < borders.size(); ++border_idx) { | ||||
|             const Polygon &border       = borders[border_idx]; | ||||
|             Lines          border_lines = border.lines(); | ||||
| 
 | ||||
|             for (size_t line_idx = 0; line_idx < border_lines.size(); ++line_idx) { | ||||
|                 const Line &border_line = border_lines[line_idx]; | ||||
|                 Line border_line_transformed((transform_to_x_axis * border_line.a.cast<double>()).cast<coord_t>(), | ||||
|                                              (transform_to_x_axis * border_line.b.cast<double>()).cast<coord_t>()); | ||||
| 
 | ||||
|                 Point intersection_transformed; | ||||
| 
 | ||||
|                 if (travel_line.intersection(border_line_transformed, &intersection_transformed)) | ||||
|                     intersections.emplace_back(border_idx, line_idx, intersection_transformed); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Sort intersections from the nearest to the farthest
 | ||||
|         std::sort(intersections.begin(), intersections.end()); | ||||
| 
 | ||||
|         //        Polyline result(start, end);
 | ||||
|         Polyline result; | ||||
|         result.append(start); | ||||
| 
 | ||||
|         for (auto it_first = intersections.begin(); it_first != intersections.end(); ++it_first) { | ||||
|             const Intersection &intersection_first = *it_first; | ||||
| 
 | ||||
|             for (auto it_second = it_first + 1; it_second != intersections.end(); ++it_second) { | ||||
|                 const Intersection &intersection_second = *it_second; | ||||
| 
 | ||||
|                 if (intersection_first.border_idx == intersection_second.border_idx) { | ||||
|                     Lines border_lines = borders[intersection_first.border_idx].lines(); | ||||
| 
 | ||||
|                     // Append the nearest intersection into the path
 | ||||
|                     result.append((transform_from_x_axis * intersection_first.point.cast<double>()).cast<coord_t>()); | ||||
| 
 | ||||
|                     // Append the path around the border into the path
 | ||||
|                     for (size_t line_idx = intersection_first.line_idx; line_idx != intersection_second.line_idx;) { | ||||
|                         result.append(border_lines[line_idx].b); | ||||
| 
 | ||||
|                         if (++line_idx == border_lines.size()) line_idx = 0; | ||||
|                     } | ||||
| 
 | ||||
|                     // Append the farthest intersection into the path
 | ||||
|                     result.append((transform_from_x_axis * intersection_second.point.cast<double>()).cast<coord_t>()); | ||||
| 
 | ||||
|                     // Skip intersections in between
 | ||||
|                     it_first = it_second; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         result.append(end); | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     std::string OozePrevention::pre_toolchange(GCode& gcodegen) | ||||
|     { | ||||
|  |  | |||
|  | @ -46,13 +46,13 @@ public: | |||
|     bool disable_once; | ||||
|      | ||||
|     AvoidCrossingPerimeters() : use_external_mp(false), use_external_mp_once(false), disable_once(true) {} | ||||
|     ~AvoidCrossingPerimeters() {} | ||||
|     virtual ~AvoidCrossingPerimeters() = default; | ||||
| 
 | ||||
|     void reset() { m_external_mp.reset(); m_layer_mp.reset(); } | ||||
| 	void init_external_mp(const Print &print); | ||||
|     void init_layer_mp(const ExPolygons &islands) { m_layer_mp = Slic3r::make_unique<MotionPlanner>(islands); } | ||||
| 
 | ||||
|     Polyline travel_to(const GCode &gcodegen, const Point &point); | ||||
|     virtual Polyline travel_to(const GCode &gcodegen, const Point &point); | ||||
| 
 | ||||
| private: | ||||
|     // For initializing the regions to avoid.
 | ||||
|  | @ -62,6 +62,28 @@ private: | |||
|     std::unique_ptr<MotionPlanner> m_layer_mp; | ||||
| }; | ||||
| 
 | ||||
| class AvoidCrossingPerimeters2 : public AvoidCrossingPerimeters | ||||
| { | ||||
| protected: | ||||
|     struct Intersection | ||||
|     { | ||||
|         size_t border_idx; | ||||
|         size_t line_idx; | ||||
|         Point  point; | ||||
| 
 | ||||
|         Intersection(size_t border_idx, size_t line_idx, Point point) | ||||
|             : border_idx(border_idx), line_idx(line_idx), point(point){}; | ||||
| 
 | ||||
|         inline bool operator<(const Intersection &other) const { return this->point.x() < other.point.x(); } | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     AvoidCrossingPerimeters2() : AvoidCrossingPerimeters() {} | ||||
| 
 | ||||
|     virtual ~AvoidCrossingPerimeters2() = default; | ||||
| 
 | ||||
|     virtual Polyline travel_to(const GCode &gcodegen, const Point &point) override; | ||||
| }; | ||||
| 
 | ||||
| class OozePrevention { | ||||
| public: | ||||
|  | @ -326,7 +348,7 @@ private: | |||
|     std::set<std::string>               m_placeholder_parser_failed_templates; | ||||
|     OozePrevention                      m_ooze_prevention; | ||||
|     Wipe                                m_wipe; | ||||
|     AvoidCrossingPerimeters             m_avoid_crossing_perimeters; | ||||
|     AvoidCrossingPerimeters2            m_avoid_crossing_perimeters; | ||||
|     bool                                m_enable_loop_clipping; | ||||
|     // If enabled, the G-code generator will put following comments at the ends
 | ||||
|     // of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukáš Hejl
						Lukáš Hejl