diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp
index 9f18405b7..0dc528819 100644
--- a/src/libslic3r/Brim.cpp
+++ b/src/libslic3r/Brim.cpp
@@ -230,14 +230,11 @@ static Polylines connect_brim_lines(Polylines &&polylines, const Polygons &brim_
     if (polylines.empty())
         return Polylines();
 
-    std::vector<Points> polylines_points(polylines.size() + brim_area.size());
-    for (const Polyline &poly : polylines)
-        polylines_points[&poly - &polylines.front()] = poly.points;
-    for (const Polygon &poly : brim_area)
-        polylines_points.emplace_back(poly.points);
+    BoundingBox bbox = get_extents(polylines);
+    bbox.merge(get_extents(brim_area));
 
-    EdgeGrid::Grid grid(get_extents(polylines).inflated(SCALED_EPSILON));
-    grid.create(polylines_points, coord_t(scale_(10.)));
+    EdgeGrid::Grid grid(bbox.inflated(SCALED_EPSILON));
+    grid.create(brim_area, polylines, coord_t(scale_(10.)));
 
     struct Visitor
     {
diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp
index e5e8718c3..5e541ab69 100644
--- a/src/libslic3r/EdgeGrid.cpp
+++ b/src/libslic3r/EdgeGrid.cpp
@@ -34,76 +34,82 @@ EdgeGrid::Grid::~Grid()
 
 void EdgeGrid::Grid::create(const Polygons &polygons, coord_t resolution)
 {
-	// Count the contours.
-	size_t ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j].points.empty())
-			++ ncontours;
-
 	// Collect the contours.
-	m_contours.assign(ncontours, nullptr);
-	ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j].points.empty())
-			m_contours[ncontours ++] = &polygons[j].points;
+	m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return ! p.empty(); }));
+	for (const Polygon &polygon : polygons)
+		if (! polygon.empty())
+			m_contours.emplace_back(polygon.points, false);
 
 	create_from_m_contours(resolution);
 }
 
 void EdgeGrid::Grid::create(const std::vector<const Polygon*> &polygons, coord_t resolution)
 {
-	// Count the contours.
-	size_t ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j]->points.empty())
-			++ ncontours;
-
 	// Collect the contours.
-	m_contours.assign(ncontours, nullptr);
-	ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j]->points.empty())
-			m_contours[ncontours ++] = &polygons[j]->points;
+	m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Polygon *p) { return ! p->empty(); }));
+	for (const Polygon *polygon : polygons)
+		if (! polygon->empty())
+			m_contours.emplace_back(polygon->points, false);
 
 	create_from_m_contours(resolution);	
 }
 
-void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution)
+void EdgeGrid::Grid::create(const std::vector<Points> &polygons, coord_t resolution, bool open_polylines)
 {
-	// Count the contours.
-	size_t ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j].empty())
-			++ ncontours;
-
 	// Collect the contours.
-	m_contours.assign(ncontours, nullptr);
-	ncontours = 0;
-	for (size_t j = 0; j < polygons.size(); ++ j)
-		if (! polygons[j].empty())
-			m_contours[ncontours ++] = &polygons[j];
+	m_contours.reserve(std::count_if(polygons.begin(), polygons.end(), [](const Points &p) { return p.size() > 1; }));
+	for (const Points &points : polygons) 
+		if (points.size() > 1) {
+			const Point *begin = points.data();
+			const Point *end   = points.data() + points.size();
+			bool 		 open  = open_polylines;
+			if (open_polylines) {
+				if (*begin == end[-1]) {
+					open = false;
+					-- end;
+				}
+			} else
+				assert(*begin != end[-1]);
+			m_contours.emplace_back(begin, end, open);
+		}
+
+	create_from_m_contours(resolution);
+}
+
+void EdgeGrid::Grid::create(const Polygons &polygons, const Polylines &polylines, coord_t resolution)
+{
+	// Collect the contours.
+	m_contours.reserve(
+		std::count_if(polygons.begin(), polygons.end(), [](const Polygon &p) { return p.size() > 1; }) +
+		std::count_if(polylines.begin(), polylines.end(), [](const Polyline &p) { return p.size() > 1; }));
+
+	for (const Polyline &polyline : polylines)
+		if (polyline.size() > 1) {
+			const Point *begin = polyline.points.data();
+			const Point *end   = polyline.points.data() + polyline.size();
+			bool 		 open  = true;
+			if (*begin == end[-1]) {
+				open = false;
+				-- end;
+			}
+			m_contours.emplace_back(begin, end, open);
+		}
+
+	for (const Polygon &polygon : polygons)
+		if (polygon.size() > 1)
+			m_contours.emplace_back(polygon.points, false);
 
 	create_from_m_contours(resolution);
 }
 
 void EdgeGrid::Grid::create(const ExPolygon &expoly, coord_t resolution)
 {
-	// Count the contours.
-	size_t ncontours = 0;
-	if (! expoly.contour.points.empty())
-		++ ncontours;
-	for (size_t j = 0; j < expoly.holes.size(); ++ j)
-		if (! expoly.holes[j].points.empty())
-			++ ncontours;
-
-	// Collect the contours.
-	m_contours.assign(ncontours, nullptr);
-	ncontours = 0;
-	if (! expoly.contour.points.empty())
-		m_contours[ncontours++] = &expoly.contour.points;
-	for (size_t j = 0; j < expoly.holes.size(); ++ j)
-		if (! expoly.holes[j].points.empty())
-			m_contours[ncontours++] = &expoly.holes[j].points;
+	m_contours.reserve((expoly.contour.empty() ? 0 : 1) + std::count_if(expoly.holes.begin(), expoly.holes.end(), [](const Polygon &p) { return ! p.empty(); }));
+	if (! expoly.contour.empty())
+		m_contours.emplace_back(expoly.contour.points, false);
+	for (const Polygon &hole : expoly.holes)
+		if (! hole.empty())
+			m_contours.emplace_back(hole.points, false);
 
 	create_from_m_contours(resolution);
 }
@@ -112,25 +118,20 @@ void EdgeGrid::Grid::create(const ExPolygons &expolygons, coord_t resolution)
 {
 	// Count the contours.
 	size_t ncontours = 0;
-	for (size_t i = 0; i < expolygons.size(); ++ i) {
-		const ExPolygon &expoly = expolygons[i];
-		if (! expoly.contour.points.empty())
+	for (const ExPolygon &expoly : expolygons) {
+		if (! expoly.contour.empty())
 			++ ncontours;
-		for (size_t j = 0; j < expoly.holes.size(); ++ j)
-			if (! expoly.holes[j].points.empty())
-				++ ncontours;
+		ncontours += std::count_if(expoly.holes.begin(), expoly.holes.end(), [](const Polygon &p) { return ! p.empty(); });
 	}
 
 	// Collect the contours.
-	m_contours.assign(ncontours, nullptr);
-	ncontours = 0;
-	for (size_t i = 0; i < expolygons.size(); ++ i) {
-		const ExPolygon &expoly = expolygons[i];
-		if (! expoly.contour.points.empty())
-			m_contours[ncontours++] = &expoly.contour.points;
-		for (size_t j = 0; j < expoly.holes.size(); ++ j)
-			if (! expoly.holes[j].points.empty())
-				m_contours[ncontours++] = &expoly.holes[j].points;
+	m_contours.reserve(ncontours);
+	for (const ExPolygon &expoly : expolygons) {
+		if (! expoly.contour.empty())
+			m_contours.emplace_back(expoly.contour.points, false);
+		for (const Polygon &hole : expoly.holes)
+			if (! hole.empty())
+				m_contours.emplace_back(hole.points, false);
 	}
 
 	create_from_m_contours(resolution);
@@ -146,11 +147,13 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 {
 	assert(resolution > 0);
 	// 1) Measure the bounding box.
-	for (size_t i = 0; i < m_contours.size(); ++ i) {
-		const Slic3r::Points &pts = *m_contours[i];
-		for (size_t j = 0; j < pts.size(); ++ j)
-			m_bbox.merge(pts[j]);
+	for (const Contour &contour : m_contours) {
+		assert(contour.num_segments() > 0);
+		assert(*contour.begin() != contour.end()[-1]);
+		for (const Slic3r::Point &pt : contour) 
+			m_bbox.merge(pt);
 	}
+
 	coord_t eps = 16;
 	m_bbox.min(0) -= eps;
 	m_bbox.min(1) -= eps;
@@ -165,11 +168,11 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 
 	// 3) First round of contour rasterization, count the edges per grid cell.
 	for (size_t i = 0; i < m_contours.size(); ++ i) {
-		const Slic3r::Points &pts = *m_contours[i];
-		for (size_t j = 0; j < pts.size(); ++ j) {
+		const Contour &contour = m_contours[i];
+		for (size_t j = 0; j < contour.num_segments(); ++ j) {
 			// End points of the line segment.
-			Slic3r::Point p1(pts[j]);
-			Slic3r::Point p2 = pts[(j + 1 == pts.size()) ? 0 : j + 1];
+			Slic3r::Point p1(contour.segment_start(j));
+			Slic3r::Point p2(contour.segment_end(j));
 			p1(0) -= m_bbox.min(0);
 			p1(1) -= m_bbox.min(1);
 			p2(0) -= m_bbox.min(0);
@@ -328,9 +331,9 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
 
 	assert(visitor.i == 0);
 	for (; visitor.i < m_contours.size(); ++ visitor.i) {
-		const Slic3r::Points &pts = *m_contours[visitor.i];
-		for (visitor.j = 0; visitor.j < pts.size(); ++ visitor.j)
-			this->visit_cells_intersecting_line(pts[visitor.j], pts[(visitor.j + 1 == pts.size()) ? 0 : visitor.j + 1], visitor);
+		const Contour &contour = m_contours[visitor.i];
+		for (visitor.j = 0; visitor.j < contour.num_segments(); ++ visitor.j)
+			this->visit_cells_intersecting_line(contour.segment_start(visitor.j), contour.segment_end(visitor.j), visitor);
 	}
 }
 
@@ -696,11 +699,12 @@ void EdgeGrid::Grid::calculate_sdf()
 			const Cell &cell = m_cells[r * m_cols + c];
 			// For each segment in the cell:
 			for (size_t i = cell.begin; i != cell.end; ++ i) {
-				const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
+				const Contour &contour = m_contours[m_cell_data[i].first];
+				assert(contour.closed());
 				size_t ipt = m_cell_data[i].second;
 				// End points of the line segment.
-				const Slic3r::Point &p1 = pts[ipt];
-				const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
+				const Slic3r::Point &p1 = contour.segment_start(ipt);
+				const Slic3r::Point &p2 = contour.segment_end(ipt);
 				// Segment vector
 				const Slic3r::Point v_seg = p2 - p1;
 				// l2 of v_seg
@@ -724,7 +728,7 @@ void EdgeGrid::Grid::calculate_sdf()
 							double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
 							if (dabs < d_min) {
 								// Previous point.
-								const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
+								const Slic3r::Point &p0 = contour.segment_prev(ipt);
 								Slic3r::Point v_seg_prev = p1 - p0;
 								int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
 								if (t2_pt > 0) {
@@ -1044,7 +1048,7 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
 	return f;
 }
 
-EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt, coord_t search_radius) const 
+EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point_signed_distance(const Point &pt, coord_t search_radius) const 
 {
 	BoundingBox bbox;
 	bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1));
@@ -1083,12 +1087,13 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
 		for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
 			const Cell &cell = m_cells[r * m_cols + c];
 			for (size_t i = cell.begin; i < cell.end; ++ i) {
-				const size_t          contour_idx = m_cell_data[i].first;
-				const Slic3r::Points &pts         = *m_contours[contour_idx];
+				const size_t   contour_idx = m_cell_data[i].first;
+				const Contour &contour     = m_contours[contour_idx];
+				assert(contour.closed());
 				size_t ipt = m_cell_data[i].second;
 				// End points of the line segment.
-				const Slic3r::Point &p1 = pts[ipt];
-				const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
+				const Slic3r::Point &p1 = contour.segment_start(ipt);
+				const Slic3r::Point &p2 = contour.segment_end(ipt);
 				const Slic3r::Point v_seg = p2 - p1;
 				const Slic3r::Point v_pt  = pt - p1;
 				// dot(p2-p1, pt-p1)
@@ -1100,7 +1105,7 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
 					double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
 					if (dabs < d_min) {
 						// Previous point.
-						const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
+						const Slic3r::Point &p0 = contour.segment_prev(ipt);
 						Slic3r::Point v_seg_prev = p1 - p0;
 						int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
 						if (t2_pt > 0) {
@@ -1156,9 +1161,9 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
 		assert(result.t >= 0. && result.t <= 1.);
 #ifndef NDEBUG
 		{
-			const Slic3r::Points &pts = *m_contours[result.contour_idx];
-			const Slic3r::Point  &p1  = pts[result.start_point_idx];
-			const Slic3r::Point  &p2  = pts[(result.start_point_idx + 1 == pts.size()) ? 0 : result.start_point_idx + 1];
+			const Contour   &contour = m_contours[result.contour_idx];
+			const Slic3r::Point &p1  = contour.segment_start(result.start_point_idx);
+			const Slic3r::Point &p2  = contour.segment_end(result.start_point_idx);
 			Vec2d vfoot;
 			if (result.t == 0)
 				vfoot = p1.cast<double>() - pt.cast<double>();
@@ -1212,11 +1217,12 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
 		for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
 			const Cell &cell = m_cells[r * m_cols + c];
 			for (size_t i = cell.begin; i < cell.end; ++ i) {
-				const Slic3r::Points &pts = *m_contours[m_cell_data[i].first];
+				const Contour &contour = m_contours[m_cell_data[i].first];
+				assert(contour.closed());
 				size_t ipt = m_cell_data[i].second;
 				// End points of the line segment.
-				const Slic3r::Point &p1 = pts[ipt];
-				const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
+				const Slic3r::Point &p1 = contour.segment_start(ipt);
+				const Slic3r::Point &p2 = contour.segment_end(ipt);
 				Slic3r::Point v_seg = p2 - p1;
 				Slic3r::Point v_pt  = pt - p1;
 				// dot(p2-p1, pt-p1)
@@ -1228,7 +1234,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
 					double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
 					if (dabs < d_min) {
 						// Previous point.
-						const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
+						const Slic3r::Point &p0 = contour.segment_prev(ipt);
 						Slic3r::Point v_seg_prev = p1 - p0;
 						int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
 						if (t2_pt > 0) {
@@ -1418,26 +1424,26 @@ std::vector<std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge>>
 			const Cell &cell = m_cells[r * m_cols + c];
 			// For each pair of segments in the cell:
 			for (size_t i = cell.begin; i != cell.end; ++ i) {
-				const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
+				const Contour &icontour = m_contours[m_cell_data[i].first];
 				size_t ipt = m_cell_data[i].second;
 				// End points of the line segment and their vector.
-				const Slic3r::Point &ip1 = ipts[ipt];
-				const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
+				const Slic3r::Point &ip1 = icontour.segment_start(ipt);
+				const Slic3r::Point &ip2 = icontour.segment_end(ipt);
 				for (size_t j = i + 1; j != cell.end; ++ j) {
-					const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
-					size_t 				  jpt  = m_cell_data[j].second;
+					const Contour   &jcontour = m_contours[m_cell_data[j].first];
+					size_t 				  jpt = m_cell_data[j].second;
 					// End points of the line segment and their vector.
-					const Slic3r::Point  &jp1  = jpts[jpt];
-					const Slic3r::Point  &jp2  = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
-					if (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2))
+					const Slic3r::Point  &jp1 = jcontour.segment_start(jpt);
+					const Slic3r::Point  &jp2 = jcontour.segment_end(jpt);
+					if (&icontour == &jcontour && (&ip1 == &jp2 || &jp1 == &ip2))
 						// Segments of the same contour share a common vertex.
 						continue;
 					if (Geometry::segments_intersect(ip1, ip2, jp1, jp2)) {
 						// The two segments intersect. Add them to the output.
-						int jfirst = (&jpts < &ipts) || (&jpts == &ipts && jpt < ipt);
+						int jfirst = (&jcontour < &icontour) || (&jcontour == &icontour && jpt < ipt);
 						out.emplace_back(jfirst ? 
-							std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)) : 
-							std::make_pair(std::make_pair(&ipts, ipt), std::make_pair(&jpts, jpt)));
+							std::make_pair(std::make_pair(&icontour, ipt), std::make_pair(&jcontour, jpt)) : 
+							std::make_pair(std::make_pair(&icontour, ipt), std::make_pair(&jcontour, jpt)));
 					}
 				}
 			}
@@ -1455,18 +1461,18 @@ bool EdgeGrid::Grid::has_intersecting_edges() const
 			const Cell &cell = m_cells[r * m_cols + c];
 			// For each pair of segments in the cell:
 			for (size_t i = cell.begin; i != cell.end; ++ i) {
-				const Slic3r::Points &ipts = *m_contours[m_cell_data[i].first];
+				const Contour &icontour = m_contours[m_cell_data[i].first];
 				size_t ipt = m_cell_data[i].second;
 				// End points of the line segment and their vector.
-				const Slic3r::Point &ip1 = ipts[ipt];
-				const Slic3r::Point &ip2 = ipts[(ipt + 1 == ipts.size()) ? 0 : ipt + 1];
+				const Slic3r::Point &ip1 = icontour.segment_start(ipt);
+				const Slic3r::Point &ip2 = icontour.segment_end(ipt);
 				for (size_t j = i + 1; j != cell.end; ++ j) {
-					const Slic3r::Points &jpts = *m_contours[m_cell_data[j].first];
+					const Contour    &jcontour = m_contours[m_cell_data[j].first];
 					size_t 				  jpt  = m_cell_data[j].second;
 					// End points of the line segment and their vector.
-					const Slic3r::Point  &jp1  = jpts[jpt];
-					const Slic3r::Point  &jp2  = jpts[(jpt + 1 == jpts.size()) ? 0 : jpt + 1];
-					if (! (&ipts == &jpts && (&ip1 == &jp2 || &jp1 == &ip2)) && 
+					const Slic3r::Point  &jp1  = jcontour.segment_start(jpt);
+					const Slic3r::Point  &jp2  = jcontour.segment_end(jpt);
+					if (! (&icontour == &jcontour && (&ip1 == &jp2 || &jp1 == &ip2)) && 
 						Geometry::segments_intersect(ip1, ip2, jp1, jp2))
 						return true;
 				}
@@ -1601,22 +1607,27 @@ void export_intersections_to_svg(const std::string &filename, const Polygons &po
     SVG svg(filename.c_str(), bbox);
     svg.draw(union_ex(polygons), "gray", 0.25f);
     svg.draw_outline(polygons, "black");
-    std::set<const Points*> intersecting_contours;
+    std::set<const EdgeGrid::Contour*> intersecting_contours;
     for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &ie : intersections) {
     	intersecting_contours.insert(ie.first.first);
     	intersecting_contours.insert(ie.second.first);
     }
     // Highlight the contours with intersections.
     coord_t line_width = coord_t(scale_(0.01));
-    for (const Points *ic : intersecting_contours) {
-	    svg.draw_outline(Polygon(*ic), "green");
-	    svg.draw_outline(Polygon(*ic), "black", line_width);
+    for (const EdgeGrid::Contour *ic : intersecting_contours) {
+		if (ic->open())
+			svg.draw(Polyline(Points(ic->begin(), ic->end())), "green");
+		else {
+			Polygon polygon(Points(ic->begin(), ic->end()));
+			svg.draw_outline(polygon, "green");
+			svg.draw_outline(polygon, "black", line_width);
+		}
     }
 	// Paint the intersections.
     for (const std::pair<EdgeGrid::Grid::ContourEdge, EdgeGrid::Grid::ContourEdge> &intersecting_edges : intersections) {
     	auto edge = [](const EdgeGrid::Grid::ContourEdge &e) {
-    		return Line(e.first->at(e.second),
-    					e.first->at((e.second + 1 == e.first->size()) ? 0 : e.second + 1));
+    		return Line(e.first->segment_start(e.second),
+    					e.first->segment_end(e.second));
     	};
         svg.draw(edge(intersecting_edges.first), "red", line_width);
         svg.draw(edge(intersecting_edges.second), "red", line_width);
diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp
index ef09e28dd..42d8d92c2 100644
--- a/src/libslic3r/EdgeGrid.hpp
+++ b/src/libslic3r/EdgeGrid.hpp
@@ -12,6 +12,63 @@
 namespace Slic3r {
 namespace EdgeGrid {
 
+
+class Contour {
+public:
+	Contour() = default;
+	Contour(const Slic3r::Point *begin, const Slic3r::Point *end, bool open) : m_begin(begin), m_end(end), m_open(open) {}
+	Contour(const Slic3r::Point *data, size_t size, bool open) : Contour(data, data + size, open) {}
+	Contour(const std::vector<Slic3r::Point> &pts, bool open) : Contour(pts.data(), pts.size(), open) {}
+
+	const Slic3r::Point *begin()  const { return m_begin; }
+	const Slic3r::Point *end()    const { return m_end; }
+	bool                 open()   const { return m_open; }
+	bool                 closed() const { return ! m_open; }
+
+	// Start point of a segment idx.
+	const Slic3r::Point& segment_start(size_t idx) const {
+		assert(idx < this->num_segments());
+		return m_begin[idx];
+	}
+
+	// End point of a segment idx.
+	const Slic3r::Point& segment_end(size_t idx) const {
+		assert(idx < this->num_segments());
+		const Slic3r::Point *ptr = m_begin + idx + 1;
+		return ptr == m_end ? *m_begin : *ptr;
+	}
+
+	// Start point of a segment preceding idx.
+	const Slic3r::Point& segment_prev(size_t idx) const {
+		assert(idx < this->num_segments());
+		assert(idx > 0 || ! m_open);
+		return idx == 0 ? m_end[-1] : m_begin[idx - 1];
+	}
+
+	// Index of a segment preceding idx.
+	const size_t 		 segment_idx_prev(size_t idx) const {
+		assert(idx < this->num_segments());
+		assert(idx > 0 || ! m_open);
+		return (idx == 0 ? this->size() : idx) - 1;
+	}
+
+	// Index of a segment preceding idx.
+	const size_t 		 segment_idx_next(size_t idx) const {
+		assert(idx < this->num_segments());
+		++ idx;
+		return m_begin + idx == m_end ? 0 : idx;
+	}
+
+	size_t               num_segments() const { return this->size() - (m_open ? 1 : 0); }
+
+private:
+	size_t  			 size() const { return m_end - m_begin; }
+
+	const Slic3r::Point *m_begin { nullptr };
+	const Slic3r::Point *m_end   { nullptr };
+	bool                 m_open  { false };
+};
+
 class Grid
 {
 public:
@@ -21,14 +78,24 @@ public:
 
 	void set_bbox(const BoundingBox &bbox) { m_bbox = bbox; }
 
+	// Fill in the grid with open polylines or closed contours.
+	// If open flag is indicated, then polylines_or_polygons are considered to be open by default.
+	// Only if the first point of a polyline is equal to the last point of a polyline, 
+	// then the polyline is considered to be closed and the last repeated point is removed when
+	// inserted into the EdgeGrid.
+	// Most of the Grid functions expect all the contours to be closed, you have been warned!
+	void create(const std::vector<Points> &polylines_or_polygons, coord_t resolution, bool open);
+	void create(const Polygons &polygons, const Polylines &polylines, coord_t resolution);
+
+	// Fill in the grid with closed contours.
 	void create(const Polygons &polygons, coord_t resolution);
 	void create(const std::vector<const Polygon*> &polygons, coord_t resolution);
-	void create(const std::vector<Points> &polygons, coord_t resolution);
+	void create(const std::vector<Points> &polygons, coord_t resolution) { this->create(polygons, resolution, false); }
 	void create(const ExPolygon &expoly, coord_t resolution);
 	void create(const ExPolygons &expolygons, coord_t resolution);
 	void create(const ExPolygonCollection &expolygons, coord_t resolution);
 
-	const std::vector<const Slic3r::Points*>& contours() const { return m_contours; }
+	const std::vector<Contour>& contours() const { return m_contours; }
 
 #if 0
 	// Test, whether the edges inside the grid intersect with the polygons provided.
@@ -45,12 +112,14 @@ public:
 
 	// Fill in a rough m_signed_distance_field from the edge grid.
 	// The rough SDF is used by signed_distance() for distances outside of the search_radius.
+	// Only call this function for closed contours!
 	void calculate_sdf();
 
 	// Return an estimate of the signed distance based on m_signed_distance_field grid.
 	float signed_distance_bilinear(const Point &pt) const;
 
 	// Calculate a signed distance to the contours in search_radius from the point.
+	// Only call this function for closed contours!
 	struct ClosestPointResult {
 		size_t contour_idx  	= size_t(-1);
 		size_t start_point_idx  = size_t(-1);
@@ -61,12 +130,14 @@ public:
 
 		bool valid() const { return contour_idx != size_t(-1); }
 	};
-	ClosestPointResult closest_point(const Point &pt, coord_t search_radius) const;
+	ClosestPointResult closest_point_signed_distance(const Point &pt, coord_t search_radius) const;
 
+	// Only call this function for closed contours!
 	bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = nullptr) const;
 
 	// Calculate a signed distance to the contours in search_radius from the point. If no edge is found in search_radius,
 	// return an interpolated value from m_signed_distance_field, if it exists.
+	// Only call this function for closed contours!
 	bool signed_distance(const Point &pt, coord_t search_radius, coordf_t &result_min_dist) const;
 
 	const BoundingBox& 	bbox() const { return m_bbox; }
@@ -77,8 +148,8 @@ public:
 	// For supports: Contours enclosing the rasterized edges.
 	Polygons 			contours_simplified(coord_t offset, bool fill_holes) const;
 
-	typedef std::pair<const Slic3r::Points*, size_t> ContourPoint;
-	typedef std::pair<const Slic3r::Points*, size_t> ContourEdge;
+	typedef std::pair<const Contour*, size_t> ContourPoint;
+	typedef std::pair<const Contour*, size_t> ContourEdge;
 	std::vector<std::pair<ContourEdge, ContourEdge>> intersecting_edges() const;
 	bool 											 has_intersecting_edges() const;
 
@@ -256,16 +327,16 @@ public:
 
 	std::pair<const Slic3r::Point&, const Slic3r::Point&> segment(const std::pair<size_t, size_t> &contour_and_segment_idx) const
 	{
-		const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
-		size_t ipt = contour_and_segment_idx.second;
-		return std::pair<const Slic3r::Point&, const Slic3r::Point&>(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
+		const Contour &contour = m_contours[contour_and_segment_idx.first];
+		size_t iseg = contour_and_segment_idx.second;
+		return std::pair<const Slic3r::Point&, const Slic3r::Point&>(contour.segment_start(iseg), contour.segment_end(iseg));
 	}
 
 	Line line(const std::pair<size_t, size_t> &contour_and_segment_idx) const
 	{
-		const Slic3r::Points &ipts = *m_contours[contour_and_segment_idx.first];
-		size_t ipt = contour_and_segment_idx.second;
-		return Line(ipts[ipt], ipts[ipt + 1 == ipts.size() ? 0 : ipt + 1]);
+		const Contour &contour = m_contours[contour_and_segment_idx.first];
+		size_t iseg = contour_and_segment_idx.second;
+		return Line(contour.segment_start(iseg), contour.segment_end(iseg));
 	}
 
 protected:
@@ -302,7 +373,7 @@ protected:
 	// Referencing the source contours.
 	// This format allows one to work with any Slic3r fixed point contour format
 	// (Polygon, ExPolygon, ExPolygonCollection etc).
-	std::vector<const Slic3r::Points*>			m_contours;
+	std::vector<Contour>						m_contours;
 
 	// Referencing a contour and a line segment of m_contours.
 	std::vector<std::pair<size_t, size_t> >		m_cell_data;
diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp
index 1e50ade5a..9610582f7 100644
--- a/src/libslic3r/ElephantFootCompensation.cpp
+++ b/src/libslic3r/ElephantFootCompensation.cpp
@@ -104,7 +104,7 @@ std::vector<float> contour_distance(const EdgeGrid::Grid &grid, const size_t idx
 								double param_hi;
 								double param_end = resampled_point_parameters.back().curve_parameter;
 								{
-									const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
+									const EdgeGrid::Contour &contour = grid.contours()[it_contour_and_segment->first];
 									size_t ipt = it_contour_and_segment->second;
 									ResampledPoint key(ipt, false, 0.);
 									auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); };
@@ -112,7 +112,7 @@ std::vector<float> contour_distance(const EdgeGrid::Grid &grid, const size_t idx
 									assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated);
 									double t2 = cross2(dir, vptpt2) / denom;
 									assert(t2 > - EPSILON && t2 < 1. + EPSILON);
-									if (++ ipt == ipts.size())
+									if (contour.begin() + (++ ipt) == contour.end())
 										param_hi = t2 * dir2.norm();
 									else
 										param_hi = it->curve_parameter + t2 * dir2.norm();
@@ -251,7 +251,7 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
 #endif
 		struct Visitor {
 			Visitor(const EdgeGrid::Grid &grid, const size_t idx_contour, const std::vector<ResampledPoint> &resampled_point_parameters, double dist_same_contour_accept, double dist_same_contour_reject) :
-				grid(grid), idx_contour(idx_contour), contour(*grid.contours()[idx_contour]), resampled_point_parameters(resampled_point_parameters), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
+				grid(grid), idx_contour(idx_contour), contour(grid.contours()[idx_contour]), resampled_point_parameters(resampled_point_parameters), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
 
 			void init(const Points &contour, const Point &apoint) {
                 this->idx_point  = &apoint - contour.data();
@@ -283,15 +283,15 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
 							double param_lo = resampled_point_parameters[this->idx_point].curve_parameter;
 							double param_hi;
 							double param_end = resampled_point_parameters.back().curve_parameter;
-							const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
-							const size_t		  ipt  = it_contour_and_segment->second;
+							const EdgeGrid::Contour &contour = grid.contours()[it_contour_and_segment->first];
+							const size_t		     ipt     = it_contour_and_segment->second;
 							{
 								ResampledPoint key(ipt, false, 0.);
 								auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); };
 								auto it = std::lower_bound(resampled_point_parameters.begin(), resampled_point_parameters.end(), key, lower);
 								assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated);
 								param_hi = t * sqrt(l2);
-								if (ipt + 1 < ipts.size())
+								if (contour.begin() + ipt + 1 < contour.end())
 									param_hi += it->curve_parameter;
 							}
 							if (param_lo > param_hi)
@@ -307,9 +307,9 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
 								// Bulge is estimated by 0.6 of the circle circumference drawn around the bisector.
 								// Test whether the contour is convex or concave.
 								bool inside = 
-									(t == 0.) ? this->inside_corner(ipts, ipt, this->point) :
-									(t == 1.) ? this->inside_corner(ipts, ipt + 1 == ipts.size() ? 0 : ipt + 1, this->point) :
-									this->left_of_segment(ipts, ipt, this->point);
+									(t == 0.) ? this->inside_corner(contour, ipt, this->point) :
+									(t == 1.) ? this->inside_corner(contour, contour.segment_idx_next(ipt), this->point) :
+									this->left_of_segment(contour, ipt, this->point);
 								accept = inside && dist_along_contour > 0.6 * M_PI * dist;
 							}
 					    }
@@ -329,7 +329,7 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
 
 			const EdgeGrid::Grid 			   &grid;
 			const size_t 		  				idx_contour;
-			const Points					   &contour;
+			const EdgeGrid::Contour			   &contour;
 			const std::vector<ResampledPoint>  &resampled_point_parameters;
 			const double                        dist_same_contour_accept;
 			const double 						dist_same_contour_reject;
@@ -358,24 +358,28 @@ std::vector<float> contour_distance2(const EdgeGrid::Grid &grid, const size_t id
 				return Vec2d(- v.y(), v.x());
 			}
 
-			static bool inside_corner(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) {
-				const Vec2d pt = pt_oposite.cast<double>();
-				size_t iprev = prev_idx_modulo(i, contour);
-				size_t inext = next_idx_modulo(i, contour);
-				Vec2d v1 = (contour[i] - contour[iprev]).cast<double>();
-				Vec2d v2 = (contour[inext] - contour[i]).cast<double>();
-				bool  left_of_v1 = cross2(v1, pt - contour[iprev].cast<double>()) > 0.;
-				bool  left_of_v2 = cross2(v2, pt - contour[i    ].cast<double>()) > 0.;
-				return cross2(v1, v2) > 0 ? 
-					left_of_v1 && left_of_v2 : // convex corner
-					left_of_v1 || left_of_v2;  // concave corner
-			}
-			static bool left_of_segment(const Slic3r::Points &contour, size_t i, const Point &pt_oposite) {
-				const Vec2d pt = pt_oposite.cast<double>();
-				size_t inext = next_idx_modulo(i, contour);
-				Vec2d v = (contour[inext] - contour[i]).cast<double>();
-				return cross2(v, pt - contour[i].cast<double>()) > 0.;
-			}
+            static bool inside_corner(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
+            {
+                const Vec2d pt         = pt_oposite.cast<double>();
+                const Point &pt_prev   = contour.segment_prev(i);
+                const Point &pt_this   = contour.segment_start(i);
+                const Point &pt_next   = contour.segment_end(i);
+                Vec2d       v1         = (pt_this - pt_prev).cast<double>();
+                Vec2d       v2         = (pt_next - pt_this).cast<double>();
+                bool        left_of_v1 = cross2(v1, pt - pt_prev.cast<double>()) > 0.;
+                bool        left_of_v2 = cross2(v2, pt - pt_this.cast<double>()) > 0.;
+                return cross2(v1, v2) > 0 ? left_of_v1 && left_of_v2 : // convex corner
+                                            left_of_v1 || left_of_v2;                   // concave corner
+            }
+
+            static bool left_of_segment(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
+            {
+                const Vec2d  pt      = pt_oposite.cast<double>();
+                const Point &pt_this = contour.segment_start(i);
+                const Point &pt_next = contour.segment_end(i);
+                Vec2d        v       = (pt_next - pt_this).cast<double>();
+                return cross2(v, pt - pt_this.cast<double>()) > 0.;
+            }
 		} visitor(grid, idx_contour, resampled_point_parameters, 0.5 * compensation * M_PI, search_radius);
 
 		out.reserve(contour.size());
diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp
index af53907c7..6ebc6023c 100644
--- a/src/libslic3r/Fill/FillBase.cpp
+++ b/src/libslic3r/Fill/FillBase.cpp
@@ -1129,7 +1129,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
 			intersection_points.reserve(infill_ordered.size() * 2);
 			for (const Polyline &pl : infill_ordered)
 				for (const Point *pt : { &pl.points.front(), &pl.points.back() }) {
-					EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, coord_t(SCALED_EPSILON));
+					EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point_signed_distance(*pt, coord_t(SCALED_EPSILON));
 					if (cp.valid()) {
 						// The infill end point shall lie on the contour.
 						assert(cp.distance <= 3.);
diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
index f1d895372..853dc722b 100644
--- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
+++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp
@@ -596,7 +596,7 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid,
     {
         struct Visitor {
             Visitor(const EdgeGrid::Grid &grid, const size_t contour_idx, const std::vector<float> &polygon_distances, double dist_same_contour_accept, double dist_same_contour_reject) :
-                grid(grid), idx_contour(contour_idx), contour(*grid.contours()[contour_idx]), boundary_parameters(polygon_distances), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
+                grid(grid), idx_contour(contour_idx), contour(grid.contours()[contour_idx]), boundary_parameters(polygon_distances), dist_same_contour_accept(dist_same_contour_accept), dist_same_contour_reject(dist_same_contour_reject) {}
 
             void init(const Points &contour, const Point &apoint)
             {
@@ -630,12 +630,12 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid,
                             // Complex case: The closest segment originates from the same contour as the starting point.
                             // Reject the closest point if its distance along the contour is reasonable compared to the current contour bisector
                             // (this->pt, foot).
-                            const Slic3r::Points &ipts      = *grid.contours()[it_contour_and_segment->first];
-                            double                param_lo  = boundary_parameters[this->idx_point];
-                            double                param_hi  = t * sqrt(l2);
-                            double                param_end = boundary_parameters.back();
+                            const EdgeGrid::Contour &contour   = grid.contours()[it_contour_and_segment->first];
+                            double                   param_lo  = boundary_parameters[this->idx_point];
+                            double                   param_hi  = t * sqrt(l2);
+                            double                   param_end = boundary_parameters.back();
                             const size_t ipt = it_contour_and_segment->second;
-                            if (ipt + 1 < ipts.size())
+                            if (contour.begin() + ipt + 1 < contour.end())
                                 param_hi += boundary_parameters[ipt > 0 ? ipt - 1 : 0];
                             if (param_lo > param_hi)
                                 std::swap(param_lo, param_hi);
@@ -649,9 +649,9 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid,
                                 // longer than the bisector. That is, the path shall not bulge away from the bisector too much.
                                 // Bulge is estimated by 0.6 of the circle circumference drawn around the bisector.
                                 // Test whether the contour is convex or concave.
-                                bool inside = (t == 0.) ? this->inside_corner(ipts, ipt, this->point) :
-                                              (t == 1.) ? this->inside_corner(ipts, ipt + 1 == ipts.size() ? 0 : ipt + 1, this->point) :
-                                                          this->left_of_segment(ipts, ipt, this->point);
+                                bool inside = (t == 0.) ? this->inside_corner(contour, ipt, this->point) :
+                                              (t == 1.) ? this->inside_corner(contour, contour.segment_idx_next(ipt), this->point) :
+                                                          this->left_of_segment(contour, ipt, this->point);
                                 accept      = inside && dist_along_contour > 0.6 * M_PI * dist;
                             }
                         }
@@ -668,7 +668,7 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid,
 
             const EdgeGrid::Grid 			   &grid;
             const size_t 		  				idx_contour;
-            const Points					   &contour;
+            const EdgeGrid::Contour            &contour;
 
             const std::vector<float>           &boundary_parameters;
             const double                        dist_same_contour_accept;
@@ -691,25 +691,27 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid     &grid,
                 return Vec2d(-v1.y() - v2.y(), v1.x() + v2.x());
             }
 
-            static bool inside_corner(const Slic3r::Points &contour, size_t i, const Point &pt_oposite)
+            static bool inside_corner(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
             {
                 const Vec2d pt         = pt_oposite.cast<double>();
-                size_t      iprev      = prev_idx_modulo(i, contour);
-                size_t      inext      = next_idx_modulo(i, contour);
-                Vec2d       v1         = (contour[i] - contour[iprev]).cast<double>();
-                Vec2d       v2         = (contour[inext] - contour[i]).cast<double>();
-                bool        left_of_v1 = cross2(v1, pt - contour[iprev].cast<double>()) > 0.;
-                bool        left_of_v2 = cross2(v2, pt - contour[i].cast<double>()) > 0.;
+                const Point &pt_prev   = contour.segment_prev(i);
+                const Point &pt_this   = contour.segment_start(i);
+                const Point &pt_next   = contour.segment_end(i);
+                Vec2d       v1         = (pt_this - pt_prev).cast<double>();
+                Vec2d       v2         = (pt_next - pt_this).cast<double>();
+                bool        left_of_v1 = cross2(v1, pt - pt_prev.cast<double>()) > 0.;
+                bool        left_of_v2 = cross2(v2, pt - pt_this.cast<double>()) > 0.;
                 return cross2(v1, v2) > 0 ? left_of_v1 && left_of_v2 : // convex corner
                                             left_of_v1 || left_of_v2;                   // concave corner
             }
 
-            static bool left_of_segment(const Slic3r::Points &contour, size_t i, const Point &pt_oposite)
+            static bool left_of_segment(const EdgeGrid::Contour &contour, size_t i, const Point &pt_oposite)
             {
-                const Vec2d pt    = pt_oposite.cast<double>();
-                size_t      inext = next_idx_modulo(i, contour);
-                Vec2d       v     = (contour[inext] - contour[i]).cast<double>();
-                return cross2(v, pt - contour[i].cast<double>()) > 0.;
+                const Vec2d  pt      = pt_oposite.cast<double>();
+                const Point &pt_this = contour.segment_start(i);
+                const Point &pt_next = contour.segment_end(i);
+                Vec2d        v       = (pt_next - pt_this).cast<double>();
+                return cross2(v, pt - pt_this.cast<double>()) > 0.;
             }
         } visitor(grid, contour_idx, poly_distances, 0.5 * compensation * M_PI, search_radius);