From 3ab886b747c4742d1662a415d683857003c0388b Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 4 Jun 2019 18:25:53 +0200
Subject: [PATCH 01/22] Fix of mesh decimation (the admesh library). Fixes
 "Unable to save project (#2445)"

---
 src/admesh/connect.cpp         | 474 ++++++++++++++++-----------------
 src/admesh/shared.cpp          | 417 ++++++++++++++---------------
 src/admesh/stl.h               |   2 +
 src/admesh/util.cpp            |  47 ++++
 src/libslic3r/TriangleMesh.cpp |  36 ++-
 5 files changed, 495 insertions(+), 481 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index fb3213219..3069251d3 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -37,7 +37,6 @@ static void stl_match_neighbors_nearby(stl_file *stl,
                                        stl_hash_edge *edge_a, stl_hash_edge *edge_b);
 static void stl_record_neighbors(stl_file *stl,
                                  stl_hash_edge *edge_a, stl_hash_edge *edge_b);
-static void stl_initialize_facet_check_exact(stl_file *stl);
 static void stl_initialize_facet_check_nearby(stl_file *stl);
 static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b);
 static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
@@ -47,63 +46,90 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
                                  stl_hash_edge *edge_a, stl_hash_edge *edge_b));
 static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b);
 static void stl_free_edges(stl_file *stl);
-static void stl_remove_facet(stl_file *stl, int facet_number);
 static void stl_change_vertices(stl_file *stl, int facet_num, int vnot,
                                 stl_vertex new_vertex);
 static void stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
     stl_hash_edge *edge_b, int *facet1, int *vertex1,
     int *facet2, int *vertex2,
     stl_vertex *new_vertex1, stl_vertex *new_vertex2);
-static void stl_remove_degenerate(stl_file *stl, int facet);
 extern int stl_check_normal_vector(stl_file *stl,
                                    int facet_num, int normal_fix_flag);
-static void stl_update_connects_remove_1(stl_file *stl, int facet_num);
+
+static inline size_t hash_size_from_nr_faces(const size_t nr_faces)
+{
+	// Good primes for addressing a cca. 30 bit space.
+	// https://planetmath.org/goodhashtableprimes
+	static std::vector<uint32_t> primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
+	// Find a prime number for 50% filling of the shared triangle edges in the mesh.
+	auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1);
+	return (it == primes.end()) ? primes.back() : *it;
+}
 
 // This function builds the neighbors list.  No modifications are made
 // to any of the facets.  The edges are said to match only if all six
 // floats of the first edge matches all six floats of the second edge.
 void stl_check_facets_exact(stl_file *stl)
 {
-  if (stl->error)
-	  return;
+	if (stl->error)
+		return;
 
-  stl->stats.connected_edges = 0;
-  stl->stats.connected_facets_1_edge = 0;
-  stl->stats.connected_facets_2_edge = 0;
-  stl->stats.connected_facets_3_edge = 0;
+  	stl->stats.connected_edges         = 0;
+  	stl->stats.connected_facets_1_edge = 0;
+  	stl->stats.connected_facets_2_edge = 0;
+  	stl->stats.connected_facets_3_edge = 0;
 
-  // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
-  // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
-  // will break the references.
-  for (int i = 0; i < stl->stats.number_of_facets;) {
-	  stl_facet &facet = stl->facet_start[i];
-	  if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
-		  // Remove the degenerate facet.
-		  facet = stl->facet_start[--stl->stats.number_of_facets];
-		  stl->stats.facets_removed += 1;
-		  stl->stats.degenerate_facets += 1;
-	  } else
-		  ++ i;
-  }
+  	// If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
+  	// Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
+  	// will break the references.
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets;) {
+		stl_facet &facet = stl->facet_start[i];
+	  	if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
+		  	// Remove the degenerate facet.
+		  	facet = stl->facet_start[--stl->stats.number_of_facets];
+		  	stl->stats.facets_removed += 1;
+		  	stl->stats.degenerate_facets += 1;
+	  	} else
+		  	++ i;
+  	}
 
-  // Connect neighbor edges.
-  stl_initialize_facet_check_exact(stl);
-  for (int i = 0; i < stl->stats.number_of_facets; i++) {
-	const stl_facet &facet = stl->facet_start[i];
-    for (int j = 0; j < 3; j++) {
-	  stl_hash_edge  edge;
-	  edge.facet_number = i;
-      edge.which_edge = j;
-      stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
-      insert_hash_edge(stl, edge, stl_record_neighbors);
-    }
-  }
-  stl_free_edges(stl);
+  	// Initialize hash table.
+	stl->stats.malloced   = 0;
+	stl->stats.freed      = 0;
+	stl->stats.collisions = 0;
+	stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+		// initialize neighbors list to -1 to mark unconnected edges
+		stl->neighbors_start[i].neighbor[0] = -1;
+		stl->neighbors_start[i].neighbor[1] = -1;
+		stl->neighbors_start[i].neighbor[2] = -1;
+	}
+	stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
+	if (stl->heads == NULL)
+		perror("stl_initialize_facet_check_exact");
+	stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
+	if (stl->tail == NULL) 
+		perror("stl_initialize_facet_check_exact");
+	stl->tail->next = stl->tail;
+	for (int i = 0; i < stl->M; ++ i)
+		stl->heads[i] = stl->tail;
+
+  	// Connect neighbor edges.
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+		const stl_facet &facet = stl->facet_start[i];
+		for (int j = 0; j < 3; ++ j) {
+			stl_hash_edge  edge;
+			edge.facet_number = i;
+			edge.which_edge = j;
+			stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
+			insert_hash_edge(stl, edge, stl_record_neighbors);
+		}
+	}
+	stl_free_edges(stl);
 
 #if 0
-  printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", 
-    stl->stats.number_of_facets, stl->stats.number_of_facets * 3, 
-    stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges);
+	printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", 
+    	stl->stats.number_of_facets, stl->stats.number_of_facets * 3, 
+    	stl->stats.connected_edges, stl->stats.number_of_facets * 3 - stl->stats.connected_edges);
 #endif
 }
 
@@ -141,48 +167,6 @@ static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_ve
   }
 }
 
-static inline size_t hash_size_from_nr_faces(const size_t nr_faces)
-{
-	// Good primes for addressing a cca. 30 bit space.
-	// https://planetmath.org/goodhashtableprimes
-	static std::vector<uint32_t> primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
-	// Find a prime number for 50% filling of the shared triangle edges in the mesh.
-	auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1);
-	return (it == primes.end()) ? primes.back() : *it;
-}
-
-static void
-stl_initialize_facet_check_exact(stl_file *stl) {
-  int i;
-
-  if (stl->error) return;
-
-  stl->stats.malloced = 0;
-  stl->stats.freed = 0;
-  stl->stats.collisions = 0;
-
-  stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets);
-
-  for (i = 0; i < stl->stats.number_of_facets ; i++) {
-    /* initialize neighbors list to -1 to mark unconnected edges */
-    stl->neighbors_start[i].neighbor[0] = -1;
-    stl->neighbors_start[i].neighbor[1] = -1;
-    stl->neighbors_start[i].neighbor[2] = -1;
-  }
-
-  stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
-  if(stl->heads == NULL) perror("stl_initialize_facet_check_exact");
-
-  stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
-  if(stl->tail == NULL) perror("stl_initialize_facet_check_exact");
-
-  stl->tail->next = stl->tail;
-
-  for(i = 0; i < stl->M; i++) {
-    stl->heads[i] = stl->tail;
-  }
-}
-
 static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
                  void (*match_neighbors)(stl_file *stl,
                      stl_hash_edge *edge_a, stl_hash_edge *edge_b))
@@ -264,7 +248,7 @@ void stl_check_facets_nearby(stl_file *stl, float tolerance)
 
   stl_initialize_facet_check_nearby(stl);
 
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
     //FIXME is the copy necessary?
     stl_facet facet = stl->facet_start[i];
     for (int j = 0; j < 3; j++) {
@@ -348,7 +332,7 @@ static void stl_initialize_facet_check_nearby(stl_file *stl)
   /*  tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
   /*  tolerance *= 0.5;*/
 
-  stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets);
+  stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
 
   stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
   if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby");
@@ -611,181 +595,170 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
   }
 }
 
-static void
-stl_remove_facet(stl_file *stl, int facet_number) {
-  int neighbor[3];
-  int vnot[3];
-  int i;
-  int j;
+static void remove_facet(stl_file *stl, int facet_number)
+{
+	assert(! stl->error);
+	++ stl->stats.facets_removed;
+	/* Update list of connected edges */
+	stl_neighbors &neighbors = stl->neighbors_start[facet_number];
+	// Update statistics on unconnected triangle edges.
+	switch ((neighbors.neighbor[0] == -1) + (neighbors.neighbor[1] == -1) + (neighbors.neighbor[2] == -1)) {
+	case 0: // Facet has 3 neighbors
+		-- stl->stats.connected_facets_3_edge;
+		-- stl->stats.connected_facets_2_edge;
+		-- stl->stats.connected_facets_1_edge;
+		break;
+	case 1: // Facet has 2 neighbors
+		-- stl->stats.connected_facets_2_edge;
+		-- stl->stats.connected_facets_1_edge;
+		break;
+	case 2: // Facet has 1 neighbor
+		-- stl->stats.connected_facets_1_edge;
+	case 3: // Facet has 0 neighbors
+		break;
+	default:
+		assert(false);
+	}
 
-  if (stl->error) return;
+  	if (facet_number == -- stl->stats.number_of_facets)
+  		// Removing the last face is easy, just forget the last face.
+  		return;
 
-  stl->stats.facets_removed += 1;
-  /* Update list of connected edges */
-  j = ((stl->neighbors_start[facet_number].neighbor[0] == -1) +
-       (stl->neighbors_start[facet_number].neighbor[1] == -1) +
-       (stl->neighbors_start[facet_number].neighbor[2] == -1));
-  if(j == 2) {
-    stl->stats.connected_facets_1_edge -= 1;
-  } else if(j == 1) {
-    stl->stats.connected_facets_2_edge -= 1;
-    stl->stats.connected_facets_1_edge -= 1;
-  } else if(j == 0) {
-    stl->stats.connected_facets_3_edge -= 1;
-    stl->stats.connected_facets_2_edge -= 1;
-    stl->stats.connected_facets_1_edge -= 1;
-  }
+  	// Copy the face and neighborship from the last face to facet_number.
+  	stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
+  	neighbors = stl->neighbors_start[stl->stats.number_of_facets];
+  	// Update neighborship of faces, which used to point to the last face, now moved to facet_number.
+  	for (int i = 0; i < 3; ++ i)
+    	if (neighbors.neighbor[i] != -1) {
+	    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
+	  		if (other_face_idx != stl->stats.number_of_facets) {
+	    		printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets);
+	    		return;
+	  		}
+	  		other_face_idx = facet_number;
+  		}
+}
 
-  stl->facet_start[facet_number] =
-    stl->facet_start[stl->stats.number_of_facets - 1];
-  /* I could reallocate at this point, but it is not really necessary. */
-  stl->neighbors_start[facet_number] =
-    stl->neighbors_start[stl->stats.number_of_facets - 1];
-  stl->stats.number_of_facets -= 1;
+static void remove_degenerate(stl_file *stl, int facet) 
+{
+	assert(! stl->error);
 
-  for(i = 0; i < 3; i++) {
-    neighbor[i] = stl->neighbors_start[facet_number].neighbor[i];
-    vnot[i] = stl->neighbors_start[facet_number].which_vertex_not[i];
-  }
+	// Update statistics on face connectivity.
+	auto stl_update_connects_remove_1 = [stl](int facet_num) {
+		assert(! stl->error);
+		//FIXME when decreasing 3_edge, should I increase 2_edge etc?
+		switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
+		case 0: // Facet has 3 neighbors
+			-- stl->stats.connected_facets_3_edge; break;
+		case 1: // Facet has 2 neighbors
+			-- stl->stats.connected_facets_2_edge; break;
+		case 2: // Facet has 1 neighbor
+			-- stl->stats.connected_facets_1_edge; break;
+		case 3: // Facet has 0 neighbors
+			break;
+		default:
+			assert(false);
+	  	}
+	};
 
-  for(i = 0; i < 3; i++) {
-    if(neighbor[i] != -1) {
-      if(stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3] !=
-          stl->stats.number_of_facets) {
-        printf("\
-in stl_remove_facet: neighbor = %d numfacets = %d this is wrong\n",
-               stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3],
-               stl->stats.number_of_facets);
-        return;
-      }
-      stl->neighbors_start[neighbor[i]].neighbor[(vnot[i] + 1)% 3]
-        = facet_number;
-    }
-  }
+	int edge_to_collapse = 0;
+   	if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
+		if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
+			// All 3 vertices are equal. Collapse the edge with no neighbor if it exists.
+			const int *nbr = stl->neighbors_start[facet].neighbor;
+			edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2;
+		} else {
+			edge_to_collapse = 0;
+		}
+  	} else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
+		edge_to_collapse = 1;
+  	} else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
+		edge_to_collapse = 2;
+  	} else {
+    	// No degenerate. Function shouldn't have been called.
+    	return;
+  	}
+
+	int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse };
+	int neighbor[] = {
+		stl->neighbors_start[facet].neighbor[edge[0]],
+		stl->neighbors_start[facet].neighbor[edge[1]],
+		stl->neighbors_start[facet].neighbor[edge[2]]
+	};
+	int vnot[] = {
+		stl->neighbors_start[facet].which_vertex_not[edge[0]],
+		stl->neighbors_start[facet].which_vertex_not[edge[1]],
+		stl->neighbors_start[facet].which_vertex_not[edge[2]]
+	};
+	// Update statistics on edge connectivity.
+  	if (neighbor[0] == -1)
+    	stl_update_connects_remove_1(neighbor[1]);
+  	if (neighbor[1] == -1)
+    	stl_update_connects_remove_1(neighbor[0]);
+
+  	if (neighbor[0] >= 0) {
+		if (neighbor[1] >= 0) {
+			// Adjust the "flip" flag for the which_vertex_not values.
+			if (vnot[0] > 2) {
+				if (vnot[1] > 2) {
+					// The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face
+					// the two remaining neighbors will be oriented correctly.
+					vnot[0] -= 3;
+					vnot[1] -= 3;
+				} else
+					// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
+					// After removal, the two neighbors will have their normals flipped.
+					vnot[1] += 3;
+			} else if (vnot[1] > 2)
+				// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
+				// After removal, the two neighbors will have their normals flipped.
+				vnot[0] += 3;
+		}
+		stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1];
+    	stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1];
+  	}
+  	if (neighbor[1] >= 0) {
+		stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0];
+    	stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
+  	}
+	if (neighbor[2] >= 0) {
+		stl_update_connects_remove_1(neighbor[2]);
+		stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
+	}
+
+  	remove_facet(stl, facet);
 }
 
 void stl_remove_unconnected_facets(stl_file *stl)
 {
-  /* A couple of things need to be done here.  One is to remove any */
-  /* completely unconnected facets (0 edges connected) since these are */
-  /* useless and could be completely wrong.   The second thing that needs to */
-  /* be done is to remove any degenerate facets that were created during */
-  /* stl_check_facets_nearby(). */
-  if (stl->error)
-    return;
+	// A couple of things need to be done here.  One is to remove any completely unconnected facets (0 edges connected) since these are
+	// useless and could be completely wrong.   The second thing that needs to be done is to remove any degenerate facets that were created during
+	// stl_check_facets_nearby().
+	if (stl->error)
+		return;
 
-  // remove degenerate facets
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
-    if(stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
-       stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
-       stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
-      stl_remove_degenerate(stl, i);
-      i--;
-    }
-  }
+	// remove degenerate facets
+	for (uint32_t i = 0; i < stl->stats.number_of_facets;)
+		if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
+			stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
+			stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
+			remove_degenerate(stl, i);
+//			assert(stl_validate(stl));
+		} else
+			++ i;
 
-  if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) {
-    // remove completely unconnected facets
-    for (int i = 0; i < stl->stats.number_of_facets; i++) {
-      if (stl->neighbors_start[i].neighbor[0] == -1 &&
-          stl->neighbors_start[i].neighbor[1] == -1 &&
-          stl->neighbors_start[i].neighbor[2] == -1) {
-        // This facet is completely unconnected.  Remove it.
-        stl_remove_facet(stl, i);
-        -- i;
-      }
-    }
-  }
-}
-
-static void
-stl_remove_degenerate(stl_file *stl, int facet) {
-  int edge1;
-  int edge2;
-  int edge3;
-  int neighbor1;
-  int neighbor2;
-  int neighbor3;
-  int vnot1;
-  int vnot2;
-  int vnot3;
-
-  if (stl->error) return;
-
-  if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1] &&
-      stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
-    /* all 3 vertices are equal.  Just remove the facet.  I don't think*/
-    /* this is really possible, but just in case... */
-    printf("removing a facet in stl_remove_degenerate\n");
-    stl_remove_facet(stl, facet);
-    return;
-  }
-
-  if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
-    edge1 = 1;
-    edge2 = 2;
-    edge3 = 0;
-  } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
-    edge1 = 0;
-    edge2 = 2;
-    edge3 = 1;
-  } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
-    edge1 = 0;
-    edge2 = 1;
-    edge3 = 2;
-  } else {
-    /* No degenerate. Function shouldn't have been called. */
-    return;
-  }
-  neighbor1 = stl->neighbors_start[facet].neighbor[edge1];
-  neighbor2 = stl->neighbors_start[facet].neighbor[edge2];
-
-  if(neighbor1 == -1) {
-    stl_update_connects_remove_1(stl, neighbor2);
-  }
-  if(neighbor2 == -1) {
-    stl_update_connects_remove_1(stl, neighbor1);
-  }
-
-
-  neighbor3 = stl->neighbors_start[facet].neighbor[edge3];
-  vnot1 = stl->neighbors_start[facet].which_vertex_not[edge1];
-  vnot2 = stl->neighbors_start[facet].which_vertex_not[edge2];
-  vnot3 = stl->neighbors_start[facet].which_vertex_not[edge3];
-
-  if(neighbor1 >= 0){
-    stl->neighbors_start[neighbor1].neighbor[(vnot1 + 1) % 3] = neighbor2;
-    stl->neighbors_start[neighbor1].which_vertex_not[(vnot1 + 1) % 3] = vnot2;
-  }
-  if(neighbor2 >= 0){
-    stl->neighbors_start[neighbor2].neighbor[(vnot2 + 1) % 3] = neighbor1;
-    stl->neighbors_start[neighbor2].which_vertex_not[(vnot2 + 1) % 3] = vnot1;
-  }
-
-  stl_remove_facet(stl, facet);
-
-  if(neighbor3 >= 0) {
-    stl_update_connects_remove_1(stl, neighbor3);
-    stl->neighbors_start[neighbor3].neighbor[(vnot3 + 1) % 3] = -1;
-  }
-}
-
-void
-stl_update_connects_remove_1(stl_file *stl, int facet_num) {
-  int j;
-
-  if (stl->error) return;
-  /* Update list of connected edges */
-  j = ((stl->neighbors_start[facet_num].neighbor[0] == -1) +
-       (stl->neighbors_start[facet_num].neighbor[1] == -1) +
-       (stl->neighbors_start[facet_num].neighbor[2] == -1));
-  if(j == 0) {		       /* Facet has 3 neighbors */
-    stl->stats.connected_facets_3_edge -= 1;
-  } else if(j == 1) {	     /* Facet has 2 neighbors */
-    stl->stats.connected_facets_2_edge -= 1;
-  } else if(j == 2) {	     /* Facet has 1 neighbor  */
-    stl->stats.connected_facets_1_edge -= 1;
-  }
+	if (stl->stats.connected_facets_1_edge < (int)stl->stats.number_of_facets) {
+		// remove completely unconnected facets
+		for (uint32_t i = 0; i < stl->stats.number_of_facets;)
+			if (stl->neighbors_start[i].neighbor[0] == -1 &&
+				stl->neighbors_start[i].neighbor[1] == -1 &&
+				stl->neighbors_start[i].neighbor[2] == -1) {
+				// This facet is completely unconnected.  Remove it.
+				remove_facet(stl, i);
+				assert(stl_validate(stl));
+			} else
+				++ i;
+	}
 }
 
 void
@@ -801,7 +774,6 @@ stl_fill_holes(stl_file *stl) {
   int next_edge;
   int pivot_vertex;
   int next_facet;
-  int i;
   int j;
   int k;
 
@@ -809,7 +781,7 @@ stl_fill_holes(stl_file *stl) {
 
   /* Insert all unconnected edges into hash list */
   stl_initialize_facet_check_nearby(stl);
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     facet = stl->facet_start[i];
     for(j = 0; j < 3; j++) {
       if(stl->neighbors_start[i].neighbor[j] != -1) continue;
@@ -822,7 +794,7 @@ stl_fill_holes(stl_file *stl) {
     }
   }
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     facet = stl->facet_start[i];
     neighbors_initial[0] = stl->neighbors_start[i].neighbor[0];
     neighbors_initial[1] = stl->neighbors_start[i].neighbor[1];
@@ -900,7 +872,7 @@ stl_add_facet(stl_file *stl, stl_facet *new_facet) {
   if (stl->error) return;
 
   stl->stats.facets_added += 1;
-  if(stl->stats.facets_malloced < stl->stats.number_of_facets + 1) {
+  if(stl->stats.facets_malloced < (int)stl->stats.number_of_facets + 1) {
     stl->facet_start = (stl_facet*)realloc(stl->facet_start,
                                            (sizeof(stl_facet) * (stl->stats.facets_malloced + 256)));
     if(stl->facet_start == NULL) perror("stl_add_facet");
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index c8c17ccd5..2ad270903 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -23,242 +23,239 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <vector>
+
 #include <boost/nowide/cstdio.hpp>
 
 #include "stl.h"
 
-void
-stl_invalidate_shared_vertices(stl_file *stl) {
-  if (stl->error) return;
+void stl_invalidate_shared_vertices(stl_file *stl)
+{
+ 	if (stl->error) 
+    	return;
 
-  if (stl->v_indices != NULL) {
-    free(stl->v_indices);
-    stl->v_indices = NULL;
-  }
-  if (stl->v_shared != NULL) {
-    free(stl->v_shared);
-    stl->v_shared = NULL;
-  }
+  	if (stl->v_indices != nullptr) {
+    	free(stl->v_indices);
+    	stl->v_indices = nullptr;
+  	}
+  	if (stl->v_shared != nullptr) {
+    	free(stl->v_shared);
+    	stl->v_shared = nullptr;
+	}
 }
 
-void
-stl_generate_shared_vertices(stl_file *stl) {
-  int i;
-  int j;
-  int first_facet;
-  int direction;
-  int facet_num;
-  int vnot;
-  int next_edge;
-  int pivot_vertex;
-  int next_facet;
-  int reversed;
+void stl_generate_shared_vertices(stl_file *stl)
+{
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+	/* make sure this function is idempotent and does not leak memory */
+	stl_invalidate_shared_vertices(stl);
 
-  /* make sure this function is idempotent and does not leak memory */
-  stl_invalidate_shared_vertices(stl);
+	// 3 indices to vertex per face
+	stl->v_indices = (v_indices_struct*)calloc(stl->stats.number_of_facets, sizeof(v_indices_struct));
+	if (stl->v_indices == nullptr) 
+		perror("stl_generate_shared_vertices");
+	// Shared vertices (3D coordinates)
+	stl->v_shared = (stl_vertex*)calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex));
+	if (stl->v_shared == nullptr) 
+		perror("stl_generate_shared_vertices");
+	stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
+	stl->stats.shared_vertices = 0;
 
-  stl->v_indices = (v_indices_struct*)
-                   calloc(stl->stats.number_of_facets, sizeof(v_indices_struct));
-  if(stl->v_indices == NULL) perror("stl_generate_shared_vertices");
-  stl->v_shared = (stl_vertex*)
-                  calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex));
-  if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
-  stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
-  stl->stats.shared_vertices = 0;
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+		// vertex index -1 means no shared vertex was assigned yet.
+		stl->v_indices[i].vertex[0] = -1;
+		stl->v_indices[i].vertex[1] = -1;
+		stl->v_indices[i].vertex[2] = -1;
+	}
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    stl->v_indices[i].vertex[0] = -1;
-    stl->v_indices[i].vertex[1] = -1;
-    stl->v_indices[i].vertex[2] = -1;
-  }
+	// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
+	// while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
+	// are marked with a unique fan_traversal_stamp.
+	unsigned int			  fan_traversal_stamp = 0;
+	std::vector<unsigned int> fan_traversal_facet_visited(stl->stats.number_of_facets, 0);
 
+	for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
+		for (int j = 0; j < 3; ++ j) {
+			if (stl->v_indices[facet_idx].vertex[j] != -1)
+				// Shared vertex was already assigned.
+				continue;
+			// Create a new shared vertex.
+			if (stl->stats.shared_vertices == stl->stats.shared_malloced) {
+				stl->stats.shared_malloced += 1024;
+				stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->stats.shared_malloced * sizeof(stl_vertex));
+				if(stl->v_shared == nullptr) 
+					perror("stl_generate_shared_vertices");
+			}
+			stl->v_shared[stl->stats.shared_vertices] = stl->facet_start[facet_idx].vertex[j];
+			// Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
+			int  facet_in_fan_idx 	= facet_idx;
+			bool edge_direction 	= false;
+			bool traversal_reversed = false;
+			int  vnot      			= (j + 2) % 3;
+			// Increase the 
+			++ fan_traversal_stamp;
+			for (;;) {
+				// Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index.
+				int next_edge    = 0;
+				// Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex.
+				int pivot_vertex = 0;
+				if (vnot > 2) {
+					// The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore
+					// the neighboring facet is flipped.
+			  		if (! edge_direction) {
+			    		pivot_vertex = (vnot + 2) % 3;
+			    		next_edge    = pivot_vertex;			    		
+			  		} else {
+			    		pivot_vertex = (vnot + 1) % 3;
+			    		next_edge    = vnot % 3;
+			  		}
+			  		edge_direction = ! edge_direction;
+				} else {
+					// The neighboring facet is correctly oriented.
+			  		if (! edge_direction) {
+			    		pivot_vertex = (vnot + 1) % 3;
+			    		next_edge    = vnot;
+			  		} else {
+			    		pivot_vertex = (vnot + 2) % 3;
+			    		next_edge    = pivot_vertex;
+			  		}
+				}
+				stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->stats.shared_vertices;
+				fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    first_facet = i;
-    for(j = 0; j < 3; j++) {
-      if(stl->v_indices[i].vertex[j] != -1) {
-        continue;
-      }
-      if(stl->stats.shared_vertices == stl->stats.shared_malloced) {
-        stl->stats.shared_malloced += 1024;
-        stl->v_shared = (stl_vertex*)realloc(stl->v_shared,
-                                             stl->stats.shared_malloced * sizeof(stl_vertex));
-        if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
-      }
+				// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
+				int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge];
+				if (next_facet == -1) {
+					// No neighbor going in the current direction.
+					if (traversal_reversed) {
+						// Went to one limit, then turned back and reached the other limit. Quit the fan traversal.
+					    break;
+					} else {
+						// Reached the first limit. Now try to reverse and traverse up to the other limit.
+					    edge_direction        = true;
+					    vnot 	         	  = (j + 1) % 3;
+					    traversal_reversed    = true;
+				    	facet_in_fan_idx      = facet_idx;
+					}
+				} else if (next_facet == facet_idx) {
+					// Traversed a closed fan all around.
+//					assert(! traversal_reversed);
+					break;
+				} else if (next_facet >= (int)stl->stats.number_of_facets) {
+					// The mesh is not valid!
+					// assert(false);
+					break;
+				} else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) {
+					// Traversed a closed fan all around, but did not reach the starting face.
+					// This indicates an invalid geometry (non-manifold).
+					//assert(false);
+					break;
+				} else {
+					// Continue traversal.
+					// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
+					vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge];
+					facet_in_fan_idx = next_facet;
+				}
+			}
 
-      stl->v_shared[stl->stats.shared_vertices] =
-        stl->facet_start[i].vertex[j];
-
-      direction = 0;
-      reversed = 0;
-      facet_num = i;
-      vnot = (j + 2) % 3;
-
-      for(;;) {
-        if(vnot > 2) {
-          if(direction == 0) {
-            pivot_vertex = (vnot + 2) % 3;
-            next_edge = pivot_vertex;
-            direction = 1;
-          } else {
-            pivot_vertex = (vnot + 1) % 3;
-            next_edge = vnot % 3;
-            direction = 0;
-          }
-        } else {
-          if(direction == 0) {
-            pivot_vertex = (vnot + 1) % 3;
-            next_edge = vnot;
-          } else {
-            pivot_vertex = (vnot + 2) % 3;
-            next_edge = pivot_vertex;
-          }
-        }
-        stl->v_indices[facet_num].vertex[pivot_vertex] =
-          stl->stats.shared_vertices;
-
-        next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
-        if(next_facet == -1) {
-          if(reversed) {
-            break;
-          } else {
-            direction = 1;
-            vnot = (j + 1) % 3;
-            reversed = 1;
-            facet_num = first_facet;
-          }
-        } else if(next_facet != first_facet) {
-          vnot = stl->neighbors_start[facet_num].
-                 which_vertex_not[next_edge];
-          facet_num = next_facet;
-        } else {
-          break;
-        }
-      }
-      stl->stats.shared_vertices += 1;
-    }
-  }
+			++ stl->stats.shared_vertices;
+		}
+	}
 }
 
-void
-stl_write_off(stl_file *stl, const char *file) {
-  int i;
-  FILE      *fp;
-  char      *error_msg;
+void stl_write_off(stl_file *stl, const char *file)
+{
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+	/* Open the file */
+	FILE *fp = boost::nowide::fopen(file, "w");
+	if (fp == nullptr) {
+		char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
+		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
+		perror(error_msg);
+		free(error_msg);
+		stl->error = 1;
+		return;
+	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    stl->error = 1;
-    return;
-  }
-
-  fprintf(fp, "OFF\n");
-  fprintf(fp, "%d %d 0\n",
-          stl->stats.shared_vertices, stl->stats.number_of_facets);
-
-  for(i = 0; i < stl->stats.shared_vertices; i++) {
-    fprintf(fp, "\t%f %f %f\n",
-            stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-  }
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
-            stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
-  }
-  fclose(fp);
+	fprintf(fp, "OFF\n");
+	fprintf(fp, "%d %d 0\n", stl->stats.shared_vertices, stl->stats.number_of_facets);
+	for (int i = 0; i < stl->stats.shared_vertices; ++ i)
+		fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+		fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
+	fclose(fp);
 }
 
-void
-stl_write_vrml(stl_file *stl, const char *file) {
-  int i;
-  FILE      *fp;
-  char      *error_msg;
+void stl_write_vrml(stl_file *stl, const char *file)
+{
+  	if (stl->error) 
+  		return;
 
-  if (stl->error) return;
+	/* Open the file */
+  	FILE *fp = boost::nowide::fopen(file, "w");
+	if (fp == nullptr) {
+  		char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
+		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
+		perror(error_msg);
+		free(error_msg);
+		stl->error = 1;
+		return;
+	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    stl->error = 1;
-    return;
-  }
+	fprintf(fp, "#VRML V1.0 ascii\n\n");
+	fprintf(fp, "Separator {\n");
+	fprintf(fp, "\tDEF STLShape ShapeHints {\n");
+	fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
+	fprintf(fp, "\t\tfaceType CONVEX\n");
+	fprintf(fp, "\t\tshapeType SOLID\n");
+	fprintf(fp, "\t\tcreaseAngle 0.0\n");
+	fprintf(fp, "\t}\n");
+	fprintf(fp, "\tDEF STLModel Separator {\n");
+	fprintf(fp, "\t\tDEF STLColor Material {\n");
+	fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
+	fprintf(fp, "\t\t}\n");
+	fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
+	fprintf(fp, "\t\t\tpoint [\n");
 
-  fprintf(fp, "#VRML V1.0 ascii\n\n");
-  fprintf(fp, "Separator {\n");
-  fprintf(fp, "\tDEF STLShape ShapeHints {\n");
-  fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
-  fprintf(fp, "\t\tfaceType CONVEX\n");
-  fprintf(fp, "\t\tshapeType SOLID\n");
-  fprintf(fp, "\t\tcreaseAngle 0.0\n");
-  fprintf(fp, "\t}\n");
-  fprintf(fp, "\tDEF STLModel Separator {\n");
-  fprintf(fp, "\t\tDEF STLColor Material {\n");
-  fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
-  fprintf(fp, "\t\t}\n");
-  fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
-  fprintf(fp, "\t\t\tpoint [\n");
+	int i = 0;
+	for (; i < (stl->stats.shared_vertices - 1); i++)
+		fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
+	fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
+	fprintf(fp, "\t\t}\n");
+	fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
+	fprintf(fp, "\t\t\tcoordIndex [\n");
 
-  for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
-    fprintf(fp, "\t\t\t\t%f %f %f,\n",
-            stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-  }
-  fprintf(fp, "\t\t\t\t%f %f %f]\n",
-          stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-  fprintf(fp, "\t\t}\n");
-  fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
-  fprintf(fp, "\t\t\tcoordIndex [\n");
-
-  for(i = 0; i < (stl->stats.number_of_facets - 1); i++) {
-    fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0],
-            stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
-  }
-  fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0],
-          stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
-  fprintf(fp, "\t\t}\n");
-  fprintf(fp, "\t}\n");
-  fprintf(fp, "}\n");
-  fclose(fp);
+	for (int i = 0; i + 1 < (int)stl->stats.number_of_facets; ++ i)
+		fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
+	fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
+	fprintf(fp, "\t\t}\n");
+	fprintf(fp, "\t}\n");
+	fprintf(fp, "}\n");
+	fclose(fp);
 }
 
-void stl_write_obj (stl_file *stl, const char *file) {
-  int i;
-  FILE* fp;
+void stl_write_obj (stl_file *stl, const char *file)
+{
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+  	FILE *fp = boost::nowide::fopen(file, "w");
+  	if (fp == nullptr) {
+    	char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
+    	sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
+    	perror(error_msg);
+    	free(error_msg);
+    	stl->error = 1;
+    	return;
+  	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if (fp == NULL) {
-    char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
-    perror(error_msg);
-    free(error_msg);
-    stl->error = 1;
-    return;
-  }
-
-  for (i = 0; i < stl->stats.shared_vertices; i++) {
-    fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-  }
-  for (i = 0; i < stl->stats.number_of_facets; i++) {
-    fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
-  }
-
-  fclose(fp);
+	for (int i = 0; i < stl->stats.shared_vertices; ++ i)
+    	fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
+  	fclose(fp);
 }
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index f867e197b..5ecd94bd1 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -277,5 +277,7 @@ extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
 extern void stl_clear_error(stl_file *stl);
 extern int stl_get_error(stl_file *stl);
 extern void stl_exit_on_error(stl_file *stl);
+// Validate the mesh, assert on error.
+extern bool stl_validate(stl_file *stl);
 
 #endif
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 305a58e22..c2d2c2726 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -457,3 +457,50 @@ All facets connected.  No further nearby check necessary.\n");
     stl_verify_neighbors(stl);
   }
 }
+
+// Check validity of the mesh, assert on error.
+bool stl_validate(stl_file *stl)
+{
+	assert(! stl->error);
+	assert(stl->fp == nullptr);
+	assert(stl->facet_start != nullptr);
+	assert(stl->heads == nullptr);
+	assert(stl->tail  == nullptr);
+	assert(stl->neighbors_start != nullptr);
+	assert((stl->v_indices == nullptr) == (stl->v_shared == nullptr));
+	assert(stl->stats.number_of_facets > 0);
+
+#ifdef _DEBUG
+    // Verify validity of neighborship data.
+    for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
+        const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
+        const int 			*vertices 	= (stl->v_indices == nullptr) ? nullptr : stl->v_indices[facet_idx].vertex;
+        for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
+            int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
+            assert(nbr_face < (int)stl->stats.number_of_facets);
+            if (nbr_face != -1) {
+            	int nbr_vnot = nbr.which_vertex_not[nbr_idx];
+				assert(nbr_vnot >= 0 && nbr_vnot < 6);
+				// Neighbor of the neighbor is the original face.
+				assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
+				int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
+				assert(vnot_back >= 0 && vnot_back < 6);
+				assert((nbr_vnot < 3) == (vnot_back < 3));
+				assert(vnot_back % 3 == (nbr_idx + 2) % 3);
+				if (vertices != nullptr) {
+					// Has shared vertices.
+	            	if (nbr_vnot < 3) {
+	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
+						assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
+					} else {
+	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
+						assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
+					}
+				}
+            }
+        }
+    }
+#endif /* _DEBUG */
+
+	return true;
+}
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 4d35cabca..b7c6c07a7 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -104,18 +104,21 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
 
 void TriangleMesh::repair()
 {
-    if (this->repaired) return;
+    if (this->repaired)
+    	return;
     
     // admesh fails when repairing empty meshes
-    if (this->stl.stats.number_of_facets == 0) return;
+    if (this->stl.stats.number_of_facets == 0)
+    	return;
 
     BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started";
-    
+
     // checking exact
 #ifdef SLIC3R_TRACE_REPAIR
 	BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact";
 #endif /* SLIC3R_TRACE_REPAIR */
 	stl_check_facets_exact(&stl);
+    assert(stl_validate(&this->stl));
     stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge);
     stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge);
     stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge);
@@ -141,6 +144,7 @@ void TriangleMesh::repair()
             }
         }
     }
+    assert(stl_validate(&this->stl));
     
     // remove_unconnected
     if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) {
@@ -148,6 +152,7 @@ void TriangleMesh::repair()
         BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets";
 #endif /* SLIC3R_TRACE_REPAIR */
         stl_remove_unconnected_facets(&stl);
+	    assert(stl_validate(&this->stl));
     }
     
     // fill_holes
@@ -168,24 +173,28 @@ void TriangleMesh::repair()
     BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_directions";
 #endif /* SLIC3R_TRACE_REPAIR */
     stl_fix_normal_directions(&stl);
+    assert(stl_validate(&this->stl));
 
     // normal_values
 #ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_fix_normal_values";
 #endif /* SLIC3R_TRACE_REPAIR */
     stl_fix_normal_values(&stl);
+    assert(stl_validate(&this->stl));
     
     // always calculate the volume and reverse all normals if volume is negative
 #ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_calculate_volume";
 #endif /* SLIC3R_TRACE_REPAIR */
     stl_calculate_volume(&stl);
+    assert(stl_validate(&this->stl));
     
     // neighbors
 #ifdef SLIC3R_TRACE_REPAIR
     BOOST_LOG_TRIVIAL(trace) << "\tstl_verify_neighbors";
 #endif /* SLIC3R_TRACE_REPAIR */
     stl_verify_neighbors(&stl);
+    assert(stl_validate(&this->stl));
 
     this->repaired = true;
 
@@ -594,27 +603,14 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
 void TriangleMesh::require_shared_vertices()
 {
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start";
-    if (!this->repaired) 
+    assert(stl_validate(&this->stl));
+    if (! this->repaired) 
         this->repair();
-    if (this->stl.v_shared == NULL) {
+    if (this->stl.v_shared == nullptr) {
         BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices";
         stl_generate_shared_vertices(&(this->stl));
     }
-#ifdef _DEBUG
-    // Verify validity of neighborship data.
-    for (int facet_idx = 0; facet_idx < stl.stats.number_of_facets; ++facet_idx) {
-        const stl_neighbors &nbr = stl.neighbors_start[facet_idx];
-        const int *vertices = stl.v_indices[facet_idx].vertex;
-        for (int nbr_idx = 0; nbr_idx < 3; ++nbr_idx) {
-            int nbr_face = this->stl.neighbors_start[facet_idx].neighbor[nbr_idx];
-            if (nbr_face != -1) {
-				assert(
-					(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[nbr_idx]) ||
-					(stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == vertices[nbr_idx]));
-            }
-        }
-    }
-#endif /* _DEBUG */
+    assert(stl_validate(&this->stl));
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
 }
 

From 8da54139c463a09ec899a9df6bccae16802dccdf Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 4 Jun 2019 22:06:42 +0200
Subject: [PATCH 02/22] WIP: Admesh - replacement of C memory allocation with
 std vectors

---
 CMakeLists.txt                               |   2 +-
 src/admesh/connect.cpp                       | 401 ++++++++-----------
 src/admesh/normals.cpp                       |  26 +-
 src/admesh/shared.cpp                        |  37 +-
 src/admesh/stl.h                             | 187 +++++----
 src/admesh/stl_io.cpp                        |  30 +-
 src/admesh/stlinit.cpp                       | 104 ++---
 src/admesh/util.cpp                          | 104 +++--
 src/libslic3r/Format/3mf.cpp                 |   2 +-
 src/libslic3r/Format/AMF.cpp                 |   2 +-
 src/libslic3r/Format/PRUS.cpp                |   6 +-
 src/libslic3r/Model.cpp                      |  18 +-
 src/libslic3r/SLA/SLASupportTreeIGL.cpp      |  17 +-
 src/libslic3r/SlicingAdaptive.cpp            |   4 +-
 src/libslic3r/TriangleMesh.cpp               |  83 ++--
 src/libslic3r/TriangleMesh.hpp               |   4 +-
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp |   8 +-
 17 files changed, 450 insertions(+), 585 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 719bdd04e..3d7157d5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,7 +60,7 @@ if (MSVC)
     # /bigobj (Increase Number of Sections in .Obj file)
     # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
     # Generate symbols at every build target, even for the release.
-    add_compile_options(-bigobj -Zm316 /Zi)
+    add_compile_options(-bigobj -Zm520 /Zi)
 endif ()
 
 # Display and check CMAKE_PREFIX_PATH
diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 3069251d3..b99f93f3d 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -97,18 +97,10 @@ void stl_check_facets_exact(stl_file *stl)
 	stl->stats.freed      = 0;
 	stl->stats.collisions = 0;
 	stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-		// initialize neighbors list to -1 to mark unconnected edges
-		stl->neighbors_start[i].neighbor[0] = -1;
-		stl->neighbors_start[i].neighbor[1] = -1;
-		stl->neighbors_start[i].neighbor[2] = -1;
-	}
-	stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
-	if (stl->heads == NULL)
-		perror("stl_initialize_facet_check_exact");
-	stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
-	if (stl->tail == NULL) 
-		perror("stl_initialize_facet_check_exact");
+	for (auto &neighbor : stl->neighbors_start)
+		neighbor.reset();
+	stl->heads.assign(stl->M, nullptr);
+	stl->tail = new stl_hash_edge;
 	stl->tail->next = stl->tail;
 	for (int i = 0; i < stl->M; ++ i)
 		stl->heads[i] = stl->tail;
@@ -180,7 +172,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
   stl_hash_edge *temp;
   if(link == stl->tail) {
     /* This list doesn't have any edges currently in it.  Add this one. */
-    new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
+    new_edge = new stl_hash_edge;
     if(new_edge == NULL) perror("insert_hash_edge");
     stl->stats.malloced++;
     *new_edge = edge;
@@ -192,7 +184,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
     match_neighbors(stl, &edge, link);
     /* Delete the matched edge from the list. */
     stl->heads[chain_number] = link->next;
-    free(link);
+    delete link;
     stl->stats.freed++;
     return;
   } else {
@@ -200,7 +192,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
     for(;;) {
       if(link->next == stl->tail) {
         /* This is the last item in the list. Insert a new edge. */
-        new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
+        new_edge = new stl_hash_edge;
         if(new_edge == NULL) perror("insert_hash_edge");
         stl->stats.malloced++;
         *new_edge = edge;
@@ -215,7 +207,7 @@ static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
         /* Delete the matched edge from the list. */
         temp = link->next;
         link->next = link->next->next;
-        free(temp);
+        delete temp;
         stl->stats.freed++;
         return;
       } else {
@@ -307,48 +299,38 @@ static void stl_free_edges(stl_file *stl)
     for (int i = 0; i < stl->M; i++) {
       for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) {
         stl->heads[i] = stl->heads[i]->next;
-        free(temp);
+        delete temp;
         ++ stl->stats.freed;
       }
     }
   }
-  free(stl->heads);
-  stl->heads = nullptr;
-  free(stl->tail);
+  stl->heads.clear();
+  delete stl->tail;
   stl->tail = nullptr;
 }
 
 static void stl_initialize_facet_check_nearby(stl_file *stl)
 {
-  int i;
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+	stl->stats.malloced   = 0;
+	stl->stats.freed 	  = 0;
+	stl->stats.collisions = 0;
 
-  stl->stats.malloced = 0;
-  stl->stats.freed = 0;
-  stl->stats.collisions = 0;
+	/*  tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/
+	/*  tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
+	/*  tolerance *= 0.5;*/
+	stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
 
-  /*  tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/
-  /*  tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
-  /*  tolerance *= 0.5;*/
+	stl->heads.assign(stl->M, nullptr);
+	stl->tail = new stl_hash_edge;
+	stl->tail->next = stl->tail;
 
-  stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
-
-  stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
-  if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby");
-
-  stl->tail = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
-  if(stl->tail == NULL) perror("stl_initialize_facet_check_nearby");
-
-  stl->tail->next = stl->tail;
-
-  for(i = 0; i < stl->M; i++) {
-    stl->heads[i] = stl->tail;
-  }
+	for (int i = 0; i < stl->M; ++ i)
+		stl->heads[i] = stl->tail;
 }
 
-
-
 static void
 stl_record_neighbors(stl_file *stl,
                      stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
@@ -358,29 +340,19 @@ stl_record_neighbors(stl_file *stl,
   if (stl->error) return;
 
   /* Facet a's neighbor is facet b */
-  stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] =
-    edge_b->facet_number;	/* sets the .neighbor part */
-
-  stl->neighbors_start[edge_a->facet_number].
-  which_vertex_not[edge_a->which_edge % 3] =
-    (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */
+  stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] = edge_b->facet_number;	/* sets the .neighbor part */
+  stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] = (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */
 
   /* Facet b's neighbor is facet a */
-  stl->neighbors_start[edge_b->facet_number].neighbor[edge_b->which_edge % 3] =
-    edge_a->facet_number;	/* sets the .neighbor part */
-
-  stl->neighbors_start[edge_b->facet_number].
-  which_vertex_not[edge_b->which_edge % 3] =
-    (edge_a->which_edge + 2) % 3; /* sets the .which_vertex_not part */
+  stl->neighbors_start[edge_b->facet_number].neighbor[edge_b->which_edge % 3] = edge_a->facet_number;	/* sets the .neighbor part */
+  stl->neighbors_start[edge_b->facet_number].which_vertex_not[edge_b->which_edge % 3] = (edge_a->which_edge + 2) % 3; /* sets the .which_vertex_not part */
 
   if(   ((edge_a->which_edge < 3) && (edge_b->which_edge < 3))
         || ((edge_a->which_edge > 2) && (edge_b->which_edge > 2))) {
     /* these facets are oriented in opposite directions.  */
     /*  their normals are probably messed up. */
-    stl->neighbors_start[edge_a->facet_number].
-    which_vertex_not[edge_a->which_edge % 3] += 3;
-    stl->neighbors_start[edge_b->facet_number].
-    which_vertex_not[edge_b->which_edge % 3] += 3;
+    stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] += 3;
+    stl->neighbors_start[edge_b->facet_number].which_vertex_not[edge_b->which_edge % 3] += 3;
   }
 
 
@@ -561,8 +533,7 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
     *facet1 = -1;
   } else {
     if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1)
-          && (stl->neighbors_start[edge_a->facet_number].
-              neighbor[(v1a + 2) % 3] == -1)) {
+          && (stl->neighbors_start[edge_a->facet_number].neighbor[(v1a + 2) % 3] == -1)) {
       /* This vertex has no neighbors.  This is a good one to change */
       *facet1 = edge_a->facet_number;
       *vertex1 = v1a;
@@ -581,8 +552,7 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
     *facet2 = -1;
   } else {
     if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1)
-          && (stl->neighbors_start[edge_a->facet_number].
-              neighbor[(v2a + 2) % 3] == -1)) {
+          && (stl->neighbors_start[edge_a->facet_number].neighbor[(v2a + 2) % 3] == -1)) {
       /* This vertex has no neighbors.  This is a good one to change */
       *facet2 = edge_a->facet_number;
       *vertex2 = v2a;
@@ -595,140 +565,6 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
   }
 }
 
-static void remove_facet(stl_file *stl, int facet_number)
-{
-	assert(! stl->error);
-	++ stl->stats.facets_removed;
-	/* Update list of connected edges */
-	stl_neighbors &neighbors = stl->neighbors_start[facet_number];
-	// Update statistics on unconnected triangle edges.
-	switch ((neighbors.neighbor[0] == -1) + (neighbors.neighbor[1] == -1) + (neighbors.neighbor[2] == -1)) {
-	case 0: // Facet has 3 neighbors
-		-- stl->stats.connected_facets_3_edge;
-		-- stl->stats.connected_facets_2_edge;
-		-- stl->stats.connected_facets_1_edge;
-		break;
-	case 1: // Facet has 2 neighbors
-		-- stl->stats.connected_facets_2_edge;
-		-- stl->stats.connected_facets_1_edge;
-		break;
-	case 2: // Facet has 1 neighbor
-		-- stl->stats.connected_facets_1_edge;
-	case 3: // Facet has 0 neighbors
-		break;
-	default:
-		assert(false);
-	}
-
-  	if (facet_number == -- stl->stats.number_of_facets)
-  		// Removing the last face is easy, just forget the last face.
-  		return;
-
-  	// Copy the face and neighborship from the last face to facet_number.
-  	stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
-  	neighbors = stl->neighbors_start[stl->stats.number_of_facets];
-  	// Update neighborship of faces, which used to point to the last face, now moved to facet_number.
-  	for (int i = 0; i < 3; ++ i)
-    	if (neighbors.neighbor[i] != -1) {
-	    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
-	  		if (other_face_idx != stl->stats.number_of_facets) {
-	    		printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets);
-	    		return;
-	  		}
-	  		other_face_idx = facet_number;
-  		}
-}
-
-static void remove_degenerate(stl_file *stl, int facet) 
-{
-	assert(! stl->error);
-
-	// Update statistics on face connectivity.
-	auto stl_update_connects_remove_1 = [stl](int facet_num) {
-		assert(! stl->error);
-		//FIXME when decreasing 3_edge, should I increase 2_edge etc?
-		switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
-		case 0: // Facet has 3 neighbors
-			-- stl->stats.connected_facets_3_edge; break;
-		case 1: // Facet has 2 neighbors
-			-- stl->stats.connected_facets_2_edge; break;
-		case 2: // Facet has 1 neighbor
-			-- stl->stats.connected_facets_1_edge; break;
-		case 3: // Facet has 0 neighbors
-			break;
-		default:
-			assert(false);
-	  	}
-	};
-
-	int edge_to_collapse = 0;
-   	if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
-		if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
-			// All 3 vertices are equal. Collapse the edge with no neighbor if it exists.
-			const int *nbr = stl->neighbors_start[facet].neighbor;
-			edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2;
-		} else {
-			edge_to_collapse = 0;
-		}
-  	} else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
-		edge_to_collapse = 1;
-  	} else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
-		edge_to_collapse = 2;
-  	} else {
-    	// No degenerate. Function shouldn't have been called.
-    	return;
-  	}
-
-	int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse };
-	int neighbor[] = {
-		stl->neighbors_start[facet].neighbor[edge[0]],
-		stl->neighbors_start[facet].neighbor[edge[1]],
-		stl->neighbors_start[facet].neighbor[edge[2]]
-	};
-	int vnot[] = {
-		stl->neighbors_start[facet].which_vertex_not[edge[0]],
-		stl->neighbors_start[facet].which_vertex_not[edge[1]],
-		stl->neighbors_start[facet].which_vertex_not[edge[2]]
-	};
-	// Update statistics on edge connectivity.
-  	if (neighbor[0] == -1)
-    	stl_update_connects_remove_1(neighbor[1]);
-  	if (neighbor[1] == -1)
-    	stl_update_connects_remove_1(neighbor[0]);
-
-  	if (neighbor[0] >= 0) {
-		if (neighbor[1] >= 0) {
-			// Adjust the "flip" flag for the which_vertex_not values.
-			if (vnot[0] > 2) {
-				if (vnot[1] > 2) {
-					// The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face
-					// the two remaining neighbors will be oriented correctly.
-					vnot[0] -= 3;
-					vnot[1] -= 3;
-				} else
-					// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
-					// After removal, the two neighbors will have their normals flipped.
-					vnot[1] += 3;
-			} else if (vnot[1] > 2)
-				// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
-				// After removal, the two neighbors will have their normals flipped.
-				vnot[0] += 3;
-		}
-		stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1];
-    	stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1];
-  	}
-  	if (neighbor[1] >= 0) {
-		stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0];
-    	stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
-  	}
-	if (neighbor[2] >= 0) {
-		stl_update_connects_remove_1(neighbor[2]);
-		stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
-	}
-
-  	remove_facet(stl, facet);
-}
-
 void stl_remove_unconnected_facets(stl_file *stl)
 {
 	// A couple of things need to be done here.  One is to remove any completely unconnected facets (0 edges connected) since these are
@@ -737,12 +573,143 @@ void stl_remove_unconnected_facets(stl_file *stl)
 	if (stl->error)
 		return;
 
+	auto remove_facet = [stl](int facet_number)
+	{
+		++ stl->stats.facets_removed;
+		/* Update list of connected edges */
+		stl_neighbors &neighbors = stl->neighbors_start[facet_number];
+		// Update statistics on unconnected triangle edges.
+		switch ((neighbors.neighbor[0] == -1) + (neighbors.neighbor[1] == -1) + (neighbors.neighbor[2] == -1)) {
+		case 0: // Facet has 3 neighbors
+			-- stl->stats.connected_facets_3_edge;
+			-- stl->stats.connected_facets_2_edge;
+			-- stl->stats.connected_facets_1_edge;
+			break;
+		case 1: // Facet has 2 neighbors
+			-- stl->stats.connected_facets_2_edge;
+			-- stl->stats.connected_facets_1_edge;
+			break;
+		case 2: // Facet has 1 neighbor
+			-- stl->stats.connected_facets_1_edge;
+		case 3: // Facet has 0 neighbors
+			break;
+		default:
+			assert(false);
+		}
+
+	  	if (facet_number == -- stl->stats.number_of_facets)
+	  		// Removing the last face is easy, just forget the last face.
+	  		return;
+
+	  	// Copy the face and neighborship from the last face to facet_number.
+	  	stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
+	  	neighbors = stl->neighbors_start[stl->stats.number_of_facets];
+	  	// Update neighborship of faces, which used to point to the last face, now moved to facet_number.
+	  	for (int i = 0; i < 3; ++ i)
+	    	if (neighbors.neighbor[i] != -1) {
+		    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
+		  		if (other_face_idx != stl->stats.number_of_facets) {
+		    		printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets);
+		    		return;
+		  		}
+		  		other_face_idx = facet_number;
+	  		}
+	};
+
+	auto remove_degenerate = [stl, remove_facet](int facet)
+	{
+		// Update statistics on face connectivity.
+		auto stl_update_connects_remove_1 = [stl](int facet_num) {
+			assert(! stl->error);
+			//FIXME when decreasing 3_edge, should I increase 2_edge etc?
+			switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
+			case 0: // Facet has 3 neighbors
+				-- stl->stats.connected_facets_3_edge; break;
+			case 1: // Facet has 2 neighbors
+				-- stl->stats.connected_facets_2_edge; break;
+			case 2: // Facet has 1 neighbor
+				-- stl->stats.connected_facets_1_edge; break;
+			case 3: // Facet has 0 neighbors
+				break;
+			default:
+				assert(false);
+		  	}
+		};
+
+		int edge_to_collapse = 0;
+	   	if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
+			if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
+				// All 3 vertices are equal. Collapse the edge with no neighbor if it exists.
+				const int *nbr = stl->neighbors_start[facet].neighbor;
+				edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2;
+			} else {
+				edge_to_collapse = 0;
+			}
+	  	} else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
+			edge_to_collapse = 1;
+	  	} else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
+			edge_to_collapse = 2;
+	  	} else {
+	    	// No degenerate. Function shouldn't have been called.
+	    	return;
+	  	}
+
+		int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse };
+		int neighbor[] = {
+			stl->neighbors_start[facet].neighbor[edge[0]],
+			stl->neighbors_start[facet].neighbor[edge[1]],
+			stl->neighbors_start[facet].neighbor[edge[2]]
+		};
+		int vnot[] = {
+			stl->neighbors_start[facet].which_vertex_not[edge[0]],
+			stl->neighbors_start[facet].which_vertex_not[edge[1]],
+			stl->neighbors_start[facet].which_vertex_not[edge[2]]
+		};
+		// Update statistics on edge connectivity.
+	  	if (neighbor[0] == -1)
+	    	stl_update_connects_remove_1(neighbor[1]);
+	  	if (neighbor[1] == -1)
+	    	stl_update_connects_remove_1(neighbor[0]);
+
+	  	if (neighbor[0] >= 0) {
+			if (neighbor[1] >= 0) {
+				// Adjust the "flip" flag for the which_vertex_not values.
+				if (vnot[0] > 2) {
+					if (vnot[1] > 2) {
+						// The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face
+						// the two remaining neighbors will be oriented correctly.
+						vnot[0] -= 3;
+						vnot[1] -= 3;
+					} else
+						// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
+						// After removal, the two neighbors will have their normals flipped.
+						vnot[1] += 3;
+				} else if (vnot[1] > 2)
+					// One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
+					// After removal, the two neighbors will have their normals flipped.
+					vnot[0] += 3;
+			}
+			stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1];
+	    	stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1];
+	  	}
+	  	if (neighbor[1] >= 0) {
+			stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0];
+	    	stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
+	  	}
+		if (neighbor[2] >= 0) {
+			stl_update_connects_remove_1(neighbor[2]);
+			stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
+		}
+
+	  	remove_facet(facet);
+	};
+
 	// remove degenerate facets
 	for (uint32_t i = 0; i < stl->stats.number_of_facets;)
 		if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
 			stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
 			stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
-			remove_degenerate(stl, i);
+			remove_degenerate(i);
 //			assert(stl_validate(stl));
 		} else
 			++ i;
@@ -754,7 +721,7 @@ void stl_remove_unconnected_facets(stl_file *stl)
 				stl->neighbors_start[i].neighbor[1] == -1 &&
 				stl->neighbors_start[i].neighbor[2] == -1) {
 				// This facet is completely unconnected.  Remove it.
-				remove_facet(stl, i);
+				remove_facet(i);
 				assert(stl_validate(stl));
 			} else
 				++ i;
@@ -850,8 +817,7 @@ stl_fill_holes(stl_file *stl) {
           }
           break;
         } else {
-          vnot = stl->neighbors_start[facet_num].
-                 which_vertex_not[next_edge];
+          vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
           facet_num = next_facet;
         }
 
@@ -867,27 +833,14 @@ Try using a smaller tolerance or don't do a nearby check\n");
   }
 }
 
-void
-stl_add_facet(stl_file *stl, stl_facet *new_facet) {
-  if (stl->error) return;
-
-  stl->stats.facets_added += 1;
-  if(stl->stats.facets_malloced < (int)stl->stats.number_of_facets + 1) {
-    stl->facet_start = (stl_facet*)realloc(stl->facet_start,
-                                           (sizeof(stl_facet) * (stl->stats.facets_malloced + 256)));
-    if(stl->facet_start == NULL) perror("stl_add_facet");
-    stl->neighbors_start = (stl_neighbors*)realloc(stl->neighbors_start,
-                           (sizeof(stl_neighbors) * (stl->stats.facets_malloced + 256)));
-    if(stl->neighbors_start == NULL) perror("stl_add_facet");
-    stl->stats.facets_malloced += 256;
-  }
-  stl->facet_start[stl->stats.number_of_facets] = *new_facet;
-
-  /* note that the normal vector is not set here, just initialized to 0 */
-  stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
-
-  stl->neighbors_start[stl->stats.number_of_facets].neighbor[0] = -1;
-  stl->neighbors_start[stl->stats.number_of_facets].neighbor[1] = -1;
-  stl->neighbors_start[stl->stats.number_of_facets].neighbor[2] = -1;
-  stl->stats.number_of_facets += 1;
+void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
+{
+	if (stl->error)
+		return;
+  	++ stl->stats.facets_added;
+  	++ stl->stats.number_of_facets;
+  	stl->facet_start.emplace_back(*new_facet);
+  	// note that the normal vector is not set here, just initialized to 0.
+  	stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
+  	stl->neighbors_start.emplace_back();
 }
diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp
index ecf08b59c..e11f1a3c1 100644
--- a/src/admesh/normals.cpp
+++ b/src/admesh/normals.cpp
@@ -84,7 +84,6 @@ stl_reverse_facet(stl_file *stl, int facet_num) {
 
 void
 stl_fix_normal_directions(stl_file *stl) {
-  char *norm_sw;
   /*  int edge_num;*/
   /*  int vnot;*/
   int checked = 0;
@@ -101,7 +100,6 @@ stl_fix_normal_directions(stl_file *stl) {
   struct stl_normal *newn;
   struct stl_normal *temp;
 
-  int* reversed_ids;
   int reversed_count = 0;
   int id;
   int force_exit = 0;
@@ -112,20 +110,15 @@ stl_fix_normal_directions(stl_file *stl) {
   if (stl->stats.number_of_facets == 0) return;
 
   /* Initialize linked list. */
-  head = (struct stl_normal*)malloc(sizeof(struct stl_normal));
-  if(head == NULL) perror("stl_fix_normal_directions");
-  tail = (struct stl_normal*)malloc(sizeof(struct stl_normal));
-  if(tail == NULL) perror("stl_fix_normal_directions");
+  head = new stl_normal;
+  tail = new stl_normal;
   head->next = tail;
   tail->next = tail;
 
   /* Initialize list that keeps track of already fixed facets. */
-  norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char));
-  if(norm_sw == NULL) perror("stl_fix_normal_directions");
-
+  std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
   /* Initialize list that keeps track of reversed facets. */
-  reversed_ids = (int*)calloc(stl->stats.number_of_facets, sizeof(int));
-  if (reversed_ids == NULL) perror("stl_fix_normal_directions reversed_ids");
+  std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
 
   facet_num = 0;
   /* If normal vector is not within tolerance and backwards:
@@ -166,8 +159,7 @@ stl_fix_normal_directions(stl_file *stl) {
         /* If we haven't fixed this facet yet, add it to the list: */
         if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
           /* Add node to beginning of list. */
-          newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
-          if(newn == NULL) perror("stl_fix_normal_directions");
+          newn = new stl_normal;
           newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
           newn->next = head->next;
           head->next = newn;
@@ -187,7 +179,7 @@ stl_fix_normal_directions(stl_file *stl) {
       }
       temp = head->next;	/* Delete this facet from the list. */
       head->next = head->next->next;
-      free(temp);
+      delete temp;
     } else { /* if we ran out of facets to fix: */
       /* All of the facets in this part have been fixed. */
       stl->stats.number_of_parts += 1;
@@ -213,10 +205,8 @@ stl_fix_normal_directions(stl_file *stl) {
       }
     }
   }
-  free(head);
-  free(tail);
-  free(reversed_ids);
-  free(norm_sw);
+  delete head;
+  delete tail;
 }
 
 static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) {
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index 2ad270903..8162c6a8d 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -31,17 +31,8 @@
 
 void stl_invalidate_shared_vertices(stl_file *stl)
 {
- 	if (stl->error) 
-    	return;
-
-  	if (stl->v_indices != nullptr) {
-    	free(stl->v_indices);
-    	stl->v_indices = nullptr;
-  	}
-  	if (stl->v_shared != nullptr) {
-    	free(stl->v_shared);
-    	stl->v_shared = nullptr;
-	}
+  	stl->v_indices.clear();
+  	stl->v_shared.clear();
 }
 
 void stl_generate_shared_vertices(stl_file *stl)
@@ -53,23 +44,11 @@ void stl_generate_shared_vertices(stl_file *stl)
 	stl_invalidate_shared_vertices(stl);
 
 	// 3 indices to vertex per face
-	stl->v_indices = (v_indices_struct*)calloc(stl->stats.number_of_facets, sizeof(v_indices_struct));
-	if (stl->v_indices == nullptr) 
-		perror("stl_generate_shared_vertices");
+	stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct());
 	// Shared vertices (3D coordinates)
-	stl->v_shared = (stl_vertex*)calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex));
-	if (stl->v_shared == nullptr) 
-		perror("stl_generate_shared_vertices");
-	stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
+	stl->v_shared.assign(stl->stats.number_of_facets / 2, stl_vertex());
 	stl->stats.shared_vertices = 0;
 
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-		// vertex index -1 means no shared vertex was assigned yet.
-		stl->v_indices[i].vertex[0] = -1;
-		stl->v_indices[i].vertex[1] = -1;
-		stl->v_indices[i].vertex[2] = -1;
-	}
-
 	// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
 	// while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
 	// are marked with a unique fan_traversal_stamp.
@@ -82,13 +61,7 @@ void stl_generate_shared_vertices(stl_file *stl)
 				// Shared vertex was already assigned.
 				continue;
 			// Create a new shared vertex.
-			if (stl->stats.shared_vertices == stl->stats.shared_malloced) {
-				stl->stats.shared_malloced += 1024;
-				stl->v_shared = (stl_vertex*)realloc(stl->v_shared, stl->stats.shared_malloced * sizeof(stl_vertex));
-				if(stl->v_shared == nullptr) 
-					perror("stl_generate_shared_vertices");
-			}
-			stl->v_shared[stl->stats.shared_vertices] = stl->facet_start[facet_idx].vertex[j];
+			stl->v_shared.emplace_back(stl->facet_start[facet_idx].vertex[j]);
 			// Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
 			int  facet_in_fan_idx 	= facet_idx;
 			bool edge_direction 	= false;
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 5ecd94bd1..345951121 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -27,6 +27,7 @@
 #include <stdint.h>
 #include <stddef.h>
 
+#include <vector>
 #include <Eigen/Geometry> 
 
 // Size of the binary STL header, free form.
@@ -44,18 +45,18 @@ static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
 static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
 
 struct stl_facet {
-  stl_normal normal;
-  stl_vertex vertex[3];
-  char       extra[2];
+	stl_normal normal;
+	stl_vertex vertex[3];
+	char       extra[2];
 
-  stl_facet  rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) {
-    stl_facet out;
-    out.normal    = rot * this->normal;
-    out.vertex[0] = rot * this->vertex[0];
-    out.vertex[1] = rot * this->vertex[1];
-    out.vertex[2] = rot * this->vertex[2];
-    return out;
-  }
+	stl_facet  rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) const {
+		stl_facet out;
+		out.normal    = rot * this->normal;
+		out.vertex[0] = rot * this->vertex[0];
+		out.vertex[1] = rot * this->vertex[1];
+		out.vertex[2] = rot * this->vertex[2];
+		return out;
+	}
 };
 
 #define SIZEOF_STL_FACET       50
@@ -67,86 +68,100 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec
 
 typedef enum {binary, ascii, inmemory} stl_type;
 
-typedef struct {
-  stl_vertex p1;
-  stl_vertex p2;
-  int        facet_number;
-} stl_edge;
+struct stl_edge {
+	stl_vertex p1;
+	stl_vertex p2;
+	int        facet_number;
+};
 
-typedef struct stl_hash_edge {
-  // Key of a hash edge: sorted vertices of the edge.
-  uint32_t       key[6];
-  // Compare two keys.
-  bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
-  bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
-  int  hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11  + key[4] / 7 + key[5] / 3)) % M; }
-  // Index of a facet owning this edge.
-  int            facet_number;
-  // Index of this edge inside the facet with an index of facet_number.
-  // If this edge is stored backwards, which_edge is increased by 3.
-  int            which_edge;
-  struct stl_hash_edge  *next;
-} stl_hash_edge;
+struct stl_hash_edge {
+	// Key of a hash edge: sorted vertices of the edge.
+	uint32_t       key[6];
+	// Compare two keys.
+	bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
+	bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
+	int  hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11  + key[4] / 7 + key[5] / 3)) % M; }
+	// Index of a facet owning this edge.
+	int            facet_number;
+	// Index of this edge inside the facet with an index of facet_number.
+	// If this edge is stored backwards, which_edge is increased by 3.
+	int            which_edge;
+	struct stl_hash_edge  *next;
+};
 
-typedef struct {
-  // Index of a neighbor facet.
-  int   neighbor[3];
-  // Index of an opposite vertex at the neighbor face.
-  char  which_vertex_not[3];
-} stl_neighbors;
+struct stl_neighbors {
+  	stl_neighbors() { reset(); }
+  	void reset() {
+  		neighbor[0] = -1;
+  		neighbor[1] = -1;
+  		neighbor[2] = -1;
+  		which_vertex_not[0] = -1;
+  		which_vertex_not[1] = -1;
+  		which_vertex_not[2] = -1;
+  	}
 
-typedef struct {
-  int   vertex[3];
-} v_indices_struct;
+	// Index of a neighbor facet.
+  	int   neighbor[3];
+  	// Index of an opposite vertex at the neighbor face.
+  	char  which_vertex_not[3];
+};
 
-typedef struct {
-  char          header[81];
-  stl_type      type;
-  uint32_t      number_of_facets;
-  stl_vertex    max;
-  stl_vertex    min;
-  stl_vertex    size;
-  float         bounding_diameter;
-  float         shortest_edge;
-  float         volume;
-  unsigned      number_of_blocks;
-  int           connected_edges;
-  int           connected_facets_1_edge;
-  int           connected_facets_2_edge;
-  int           connected_facets_3_edge;
-  int           facets_w_1_bad_edge;
-  int           facets_w_2_bad_edge;
-  int           facets_w_3_bad_edge;
-  int           original_num_facets;
-  int           edges_fixed;
-  int           degenerate_facets;
-  int           facets_removed;
-  int           facets_added;
-  int           facets_reversed;
-  int           backwards_edges;
-  int           normals_fixed;
-  int           number_of_parts;
-  int           malloced;
-  int           freed;
-  int           facets_malloced;
-  int           collisions;
-  int           shared_vertices;
-  int           shared_malloced;
-} stl_stats;
+struct v_indices_struct {
+	// -1 means no vertex index has been assigned yet
+	v_indices_struct() { vertex[0] = -1; vertex[1] = -1; vertex[2] = -1; }
+  	int   vertex[3];
+};
 
-typedef struct {
-  FILE          *fp;
-  stl_facet     *facet_start;
-  stl_hash_edge **heads;
-  stl_hash_edge *tail;
-  int           M;
-  stl_neighbors *neighbors_start;
-  v_indices_struct *v_indices;
-  stl_vertex    *v_shared;
-  stl_stats     stats;
-  char          error;
-} stl_file;
+struct stl_stats {
+	char          header[81];
+	stl_type      type;
+	uint32_t      number_of_facets;
+	stl_vertex    max;
+	stl_vertex    min;
+	stl_vertex    size;
+	float         bounding_diameter;
+	float         shortest_edge;
+	float         volume;
+	unsigned      number_of_blocks;
+	int           connected_edges;
+	int           connected_facets_1_edge;
+	int           connected_facets_2_edge;
+	int           connected_facets_3_edge;
+	int           facets_w_1_bad_edge;
+	int           facets_w_2_bad_edge;
+	int           facets_w_3_bad_edge;
+	int           original_num_facets;
+	int           edges_fixed;
+	int           degenerate_facets;
+	int           facets_removed;
+	int           facets_added;
+	int           facets_reversed;
+	int           backwards_edges;
+	int           normals_fixed;
+	int           number_of_parts;
+	int           shared_vertices;
 
+	// hash table statistics
+	int           malloced;
+	int           freed;
+	int           collisions;
+};
+
+struct stl_file {
+	FILE          			   	   *fp;
+	std::vector<stl_facet>     		facet_start;
+	std::vector<stl_neighbors> 		neighbors_start;
+	// Hash table on edges
+	std::vector<stl_hash_edge*> 	heads;
+	stl_hash_edge* 					tail;
+	int           					M;
+	// Indexed face set
+	std::vector<v_indices_struct> 	v_indices;
+	std::vector<stl_vertex>       	v_shared;
+	// Statistics
+	stl_stats     					stats;
+	char          					error;
+};
 
 extern void stl_open(stl_file *stl, const char *file);
 extern void stl_close(stl_file *stl);
@@ -272,7 +287,7 @@ extern void stl_allocate(stl_file *stl);
 extern void stl_read(stl_file *stl, int first_facet, bool first);
 extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
 extern void stl_reallocate(stl_file *stl);
-extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
+extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
 
 extern void stl_clear_error(stl_file *stl);
 extern int stl_get_error(stl_file *stl);
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index 85f66785b..81060c0a3 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -109,7 +109,6 @@ Normals fixed         : %5d\n", stl->stats.normals_fixed);
 
 void
 stl_write_ascii(stl_file *stl, const char *file, const char *label) {
-  int       i;
   char      *error_msg;
 
   if (stl->error) return;
@@ -129,7 +128,7 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
 
   fprintf(fp, "solid  %s\n", label);
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
     fprintf(fp, "  facet normal % .8E % .8E % .8E\n",
             stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
             stl->facet_start[i].normal(2));
@@ -154,7 +153,6 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
 
 void
 stl_print_neighbors(stl_file *stl, char *file) {
-  int i;
   FILE *fp;
   char *error_msg;
 
@@ -173,7 +171,7 @@ stl_print_neighbors(stl_file *stl, char *file) {
     return;
   }
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
             i,
             stl->neighbors_start[i].neighbor[0],
@@ -200,7 +198,6 @@ void stl_internal_reverse_quads(char *buf, size_t cnt)
 void
 stl_write_binary(stl_file *stl, const char *file, const char *label) {
   FILE      *fp;
-  int       i;
   char      *error_msg;
 
   if (stl->error) return;
@@ -219,13 +216,13 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) {
   }
 
   fprintf(fp, "%s", label);
-  for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
+  for(size_t i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
 
   fseek(fp, LABEL_SIZE, SEEK_SET);
 #ifdef BOOST_LITTLE_ENDIAN
   fwrite(&stl->stats.number_of_facets, 4, 1, fp);
-  for (i = 0; i < stl->stats.number_of_facets; ++ i)
-    fwrite(stl->facet_start + i, SIZEOF_STL_FACET, 1, fp);
+  for (const stl_facet &facet : stl->facet_start)
+	  fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
 #else /* BOOST_LITTLE_ENDIAN */
   char buffer[50];
   // Convert the number of facets to little endian.
@@ -288,8 +285,6 @@ stl_write_neighbor(stl_file *stl, int facet) {
 void
 stl_write_quad_object(stl_file *stl, char *file) {
   FILE      *fp;
-  int       i;
-  int       j;
   char      *error_msg;
   stl_vertex connect_color = stl_vertex::Zero();
   stl_vertex uncon_1_color = stl_vertex::Zero();
@@ -313,10 +308,10 @@ stl_write_quad_object(stl_file *stl, char *file) {
   }
 
   fprintf(fp, "CQUAD\n");
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    j = ((stl->neighbors_start[i].neighbor[0] == -1) +
-         (stl->neighbors_start[i].neighbor[1] == -1) +
-         (stl->neighbors_start[i].neighbor[2] == -1));
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+    int j = ((stl->neighbors_start[i].neighbor[0] == -1) +
+             (stl->neighbors_start[i].neighbor[1] == -1) +
+             (stl->neighbors_start[i].neighbor[2] == -1));
     if(j == 0) {
       color = connect_color;
     } else if(j == 1) {
@@ -346,9 +341,8 @@ stl_write_quad_object(stl_file *stl, char *file) {
   fclose(fp);
 }
 
-void
-stl_write_dxf(stl_file *stl, const char *file, char *label) {
-  int       i;
+void stl_write_dxf(stl_file *stl, const char *file, char *label) 
+{
   FILE      *fp;
   char      *error_msg;
 
@@ -375,7 +369,7 @@ stl_write_dxf(stl_file *stl, const char *file, char *label) {
 
   fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
 
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
+  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     fprintf(fp, "0\n3DFACE\n8\n0\n");
     fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
             stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 911f4f5e8..81b7914c3 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -35,22 +35,38 @@
 #error "SEEK_SET not defined"
 #endif
 
-void
-stl_open(stl_file *stl, const char *file) {
-  stl_initialize(stl);
-  stl_count_facets(stl, file);
-  stl_allocate(stl);
-  stl_read(stl, 0, true);
-  if (stl->fp != nullptr) {
-	  fclose(stl->fp);
-	  stl->fp = nullptr;
-  }
+void stl_open(stl_file *stl, const char *file)
+{
+	stl_initialize(stl);
+	stl_count_facets(stl, file);
+	stl_allocate(stl);
+	stl_read(stl, 0, true);
+	if (stl->fp != nullptr) {
+	  	fclose(stl->fp);
+	  	stl->fp = nullptr;
+	}
 }
 
-void
-stl_initialize(stl_file *stl) {
-  memset(stl, 0, sizeof(stl_file));
-  stl->stats.volume = -1.0;
+void stl_initialize(stl_file *stl)
+{
+	stl->fp = nullptr;
+	stl->tail = nullptr;
+	stl->M = 0;
+	stl->error = 0;
+	stl->facet_start.clear();
+	stl->neighbors_start.clear();
+	stl->v_indices.clear();
+	stl->v_shared.clear();
+  	memset(&stl->stats, 0, sizeof(stl_stats));
+  	stl->stats.volume = -1.0;
+}
+
+void stl_close(stl_file *stl)
+{
+	assert(stl->fp == nullptr);
+	assert(stl->heads.empty());
+	assert(stl->tail == nullptr);
+	stl_initialize(stl);
 }
 
 #ifndef BOOST_LITTLE_ENDIAN
@@ -175,20 +191,14 @@ stl_count_facets(stl_file *stl, const char *file) {
   stl->stats.original_num_facets = stl->stats.number_of_facets;
 }
 
-void
-stl_allocate(stl_file *stl) {
-  if (stl->error) return;
-
-  /*  Allocate memory for the entire .STL file */
-  stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
-                                        sizeof(stl_facet));
-  if(stl->facet_start == NULL) perror("stl_initialize");
-  stl->stats.facets_malloced = stl->stats.number_of_facets;
-
-  /* Allocate memory for the neighbors list */
-  stl->neighbors_start = (stl_neighbors*)
-                         calloc(stl->stats.number_of_facets, sizeof(stl_neighbors));
-  if(stl->facet_start == NULL) perror("stl_initialize");
+void stl_allocate(stl_file *stl) 
+{
+	if (stl->error) 
+		return;
+  	//  Allocate memory for the entire .STL file.
+  	stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
+  	// Allocate memory for the neighbors list.
+  	stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors());
 }
 
 void
@@ -237,23 +247,14 @@ stl_open_merge(stl_file *stl, char *file_to_merge) {
   stl->fp=origFp;
 }
 
-extern void
-stl_reallocate(stl_file *stl) {
-  if (stl->error) return;
-  /*  Reallocate more memory for the .STL file(s) */
-  stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets *
-                                         sizeof(stl_facet));
-  if(stl->facet_start == NULL) perror("stl_initialize");
-  stl->stats.facets_malloced = stl->stats.number_of_facets;
-
-  /* Reallocate more memory for the neighbors list */
-  stl->neighbors_start = (stl_neighbors*)
-                         realloc(stl->neighbors_start, stl->stats.number_of_facets *
-                                 sizeof(stl_neighbors));
-  if(stl->facet_start == NULL) perror("stl_initialize");
+void stl_reallocate(stl_file *stl) 
+{
+  	if (stl->error) 
+  		return;
+	stl->facet_start.resize(stl->stats.number_of_facets);
+	stl->neighbors_start.resize(stl->stats.number_of_facets);
 }
 
-
 /* Reads the contents of the file pointed to by stl->fp into the stl structure,
    starting at facet first_facet.  The second argument says if it's our first
    time running this for the stl and therefore we should reset our max and min stats. */
@@ -366,20 +367,3 @@ void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
   	stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
   }
 }
-
-void stl_close(stl_file *stl)
-{
-	assert(stl->fp == nullptr);
-	assert(stl->heads == nullptr);
-	assert(stl->tail == nullptr);
-
-	if (stl->facet_start != NULL)
-		free(stl->facet_start);
-	if (stl->neighbors_start != NULL)
-		free(stl->neighbors_start);
-	if (stl->v_indices != NULL)
-		free(stl->v_indices);
-	if (stl->v_shared != NULL)
-		free(stl->v_shared);
-	memset(stl, 0, sizeof(stl_file));
-}
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index c2d2c2726..61e0d11e7 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -32,45 +32,39 @@ static float get_area(stl_facet *facet);
 static float get_volume(stl_file *stl);
 
 
-void
-stl_verify_neighbors(stl_file *stl) {
-  int i;
-  int j;
-  stl_edge edge_a;
-  stl_edge edge_b;
-  int neighbor;
-  int vnot;
+void stl_verify_neighbors(stl_file *stl)
+{
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+	stl->stats.backwards_edges = 0;
 
-  stl->stats.backwards_edges = 0;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      edge_a.p1 = stl->facet_start[i].vertex[j];
-      edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
-      neighbor = stl->neighbors_start[i].neighbor[j];
-      vnot = stl->neighbors_start[i].which_vertex_not[j];
-
-      if(neighbor == -1)
-        continue;		/* this edge has no neighbor... Continue. */
-      if(vnot < 3) {
-        edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
-        edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
-      } else {
-        stl->stats.backwards_edges += 1;
-        edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
-        edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
-      }
-      if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
-        /* These edges should match but they don't.  Print results. */
-        printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
-               j, i, vnot + 1, neighbor);
-        stl_write_facet(stl, (char*)"first facet", i);
-        stl_write_facet(stl, (char*)"second facet", neighbor);
-      }
-    }
-  }
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+		for (int j = 0; j < 3; ++ j) {
+			stl_edge edge_a;
+			edge_a.p1 = stl->facet_start[i].vertex[j];
+			edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
+			int neighbor = stl->neighbors_start[i].neighbor[j];
+			if (neighbor == -1)
+				continue; // this edge has no neighbor... Continue.
+			int vnot = stl->neighbors_start[i].which_vertex_not[j];
+			stl_edge edge_b;
+			if (vnot < 3) {
+				edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
+				edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
+			} else {
+				stl->stats.backwards_edges += 1;
+				edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
+				edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
+			}
+			if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
+				// These edges should match but they don't.  Print results.
+				printf("edge %d of facet %d doesn't match edge %d of facet %d\n", j, i, vnot + 1, neighbor);
+				stl_write_facet(stl, (char*)"first facet", i);
+				stl_write_facet(stl, (char*)"second facet", neighbor);
+			}
+		}
+	}
 }
 
 void stl_translate(stl_file *stl, float x, float y, float z)
@@ -263,21 +257,19 @@ void stl_mirror_yz(stl_file *stl)
 
 void stl_mirror_xz(stl_file *stl)
 {
-  if (stl->error)
-  	return;
+	if (stl->error)
+		return;
 
-  for (int i = 0; i < stl->stats.number_of_facets; i++) {
-    for (int j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j](1) *= -1.0;
-    }
-  }
-  float temp_size = stl->stats.min(1);
-  stl->stats.min(1) = stl->stats.max(1);
-  stl->stats.max(1) = temp_size;
-  stl->stats.min(1) *= -1.0;
-  stl->stats.max(1) *= -1.0;
-  stl_reverse_all_facets(stl);
-  stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+		for (int j = 0; j < 3; ++ j)
+			stl->facet_start[i].vertex[j](1) *= -1.0;
+	float temp_size = stl->stats.min(1);
+	stl->stats.min(1) = stl->stats.max(1);
+	stl->stats.max(1) = temp_size;
+	stl->stats.min(1) *= -1.0;
+	stl->stats.max(1) *= -1.0;
+	stl_reverse_all_facets(stl);
+	stl->stats.facets_reversed -= stl->stats.number_of_facets;  // for not altering stats
 }
 
 static float get_volume(stl_file *stl)
@@ -463,18 +455,18 @@ bool stl_validate(stl_file *stl)
 {
 	assert(! stl->error);
 	assert(stl->fp == nullptr);
-	assert(stl->facet_start != nullptr);
-	assert(stl->heads == nullptr);
+	assert(! stl->facet_start.empty());
+	assert(stl->heads.empty());
 	assert(stl->tail  == nullptr);
-	assert(stl->neighbors_start != nullptr);
-	assert((stl->v_indices == nullptr) == (stl->v_shared == nullptr));
+	assert(! stl->neighbors_start.empty());
+	assert((stl->v_indices.empty()) == (stl->v_shared.empty()));
 	assert(stl->stats.number_of_facets > 0);
 
 #ifdef _DEBUG
     // Verify validity of neighborship data.
     for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
         const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
-        const int 			*vertices 	= (stl->v_indices == nullptr) ? nullptr : stl->v_indices[facet_idx].vertex;
+        const int 			*vertices 	= (stl->v_indices.empty()) ? nullptr : stl->v_indices[facet_idx].vertex;
         for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
             int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
             assert(nbr_face < (int)stl->stats.number_of_facets);
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 38b34c462..c3916a14e 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1885,7 +1885,7 @@ namespace Slic3r {
                 volume->mesh.repair();
 
             stl_file& stl = volume->mesh.stl;
-            if (stl.v_shared == nullptr)
+            if (stl.v_shared.empty())
                 stl_generate_shared_vertices(&stl);
 
             if (stl.stats.shared_vertices == 0)
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index d26b5f3ed..f48b5b58c 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -926,7 +926,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             if (! volume->mesh.repaired) 
                 throw std::runtime_error("store_amf() requires repair()");
             auto &stl = volume->mesh.stl;
-            if (stl.v_shared == nullptr)
+            if (stl.v_shared.empty())
                 stl_generate_shared_vertices(&stl);
             const Transform3d& matrix = volume->get_matrix();
             for (size_t i = 0; i < stl.stats.shared_vertices; ++i) {
diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
index 502cac6e9..d983b1098 100644
--- a/src/libslic3r/Format/PRUS.cpp
+++ b/src/libslic3r/Format/PRUS.cpp
@@ -167,10 +167,10 @@ static void extract_model_from_archive(
             stl.stats.original_num_facets = header.nTriangles;
             stl_allocate(&stl);
             if (header.nTriangles > 0 && data.size() == 50 * header.nTriangles + sizeof(StlHeader)) {
-                memcpy((char*)stl.facet_start, data.data() + sizeof(StlHeader), 50 * header.nTriangles);
+                memcpy((char*)stl.facet_start.data(), data.data() + sizeof(StlHeader), 50 * header.nTriangles);
                 if (sizeof(stl_facet) > SIZEOF_STL_FACET) {
                     // The stl.facet_start is not packed tightly. Unpack the array of stl_facets.
-                    unsigned char *data = (unsigned char*)stl.facet_start;
+                    unsigned char *data = (unsigned char*)stl.facet_start.data();
                     for (size_t i = header.nTriangles - 1; i > 0; -- i)
                         memmove(data + i * sizeof(stl_facet), data + i * SIZEOF_STL_FACET, SIZEOF_STL_FACET);
                 }
@@ -257,7 +257,7 @@ static void extract_model_from_archive(
             stl.stats.number_of_facets = (uint32_t)facets.size();
             stl.stats.original_num_facets = (int)facets.size();
             stl_allocate(&stl);
-            memcpy((void*)stl.facet_start, facets.data(), facets.size() * 50);
+            memcpy((void*)stl.facet_start.data(), facets.data(), facets.size() * 50);
             stl_get_size(&stl);
             mesh.repair();
             // Add a mesh to a model.
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 3b1bd5df2..64fbb9a2a 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -910,18 +910,16 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
         if (v->is_model_part()) {
             const stl_file &stl = v->mesh.stl;
             Transform3d trafo = trafo_instance * v->get_matrix();
-            if (stl.v_shared == nullptr) {
+            if (stl.v_shared.empty()) {
                 // Using the STL faces.
-                for (unsigned int i = 0; i < stl.stats.number_of_facets; ++ i) {
-                    const stl_facet &facet = stl.facet_start[i];
+				for (const stl_facet &facet : stl.facet_start)
                     for (size_t j = 0; j < 3; ++ j) {
                         Vec3d p = trafo * facet.vertex[j].cast<double>();
                         pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
                     }
-                }
             } else {
                 // Using the shared vertices should be a bit quicker than using the STL faces.
-                for (int i = 0; i < stl.stats.shared_vertices; ++ i) {           
+                for (int i = 0; i < stl.stats.shared_vertices; ++ i) {
                     Vec3d p = trafo * stl.v_shared[i].cast<double>();
                     pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
                 }
@@ -1347,13 +1345,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
 
         Transform3d mv = mi * v->get_matrix();
         const TriangleMesh& hull = v->get_convex_hull();
-        for (uint32_t f = 0; f < hull.stl.stats.number_of_facets; ++f)
-        {
-            const stl_facet* facet = hull.stl.facet_start + f;
-            min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[0].cast<double>()));
-            min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[1].cast<double>()));
-            min_z = std::min(min_z, Vec3d::UnitZ().dot(mv * facet->vertex[2].cast<double>()));
-        }
+		for (const stl_facet &facet : hull.stl.facet_start)
+			for (int i = 0; i < 3; ++ i)
+				min_z = std::min(min_z, (mv * facet.vertex[i].cast<double>()).z());
     }
 
     return min_z + inst->get_offset(Z);
diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
index c368b8604..1609b9ac4 100644
--- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp
+++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
@@ -121,19 +121,10 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
     V.resize(3*stl.stats.number_of_facets, 3);
     F.resize(stl.stats.number_of_facets, 3);
     for (unsigned int i = 0; i < stl.stats.number_of_facets; ++i) {
-        const stl_facet* facet = stl.facet_start+i;
-        V(3*i+0, 0) = double(facet->vertex[0](0));
-        V(3*i+0, 1) = double(facet->vertex[0](1));
-        V(3*i+0, 2) = double(facet->vertex[0](2));
-
-        V(3*i+1, 0) = double(facet->vertex[1](0));
-        V(3*i+1, 1) = double(facet->vertex[1](1));
-        V(3*i+1, 2) = double(facet->vertex[1](2));
-
-        V(3*i+2, 0) = double(facet->vertex[2](0));
-        V(3*i+2, 1) = double(facet->vertex[2](1));
-        V(3*i+2, 2) = double(facet->vertex[2](2));
-
+        const stl_facet &facet = stl.facet_start[i];
+		V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0].cast<double>();
+		V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1].cast<double>();
+		V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2].cast<double>();
         F(i, 0) = int(3*i+0);
         F(i, 1) = int(3*i+1);
         F(i, 2) = int(3*i+2);
diff --git a/src/libslic3r/SlicingAdaptive.cpp b/src/libslic3r/SlicingAdaptive.cpp
index 2ef4aec8c..ad03b550b 100644
--- a/src/libslic3r/SlicingAdaptive.cpp
+++ b/src/libslic3r/SlicingAdaptive.cpp
@@ -27,8 +27,8 @@ void SlicingAdaptive::prepare()
 		nfaces_total += (*it_mesh)->stl.stats.number_of_facets;
 	m_faces.reserve(nfaces_total);
 	for (std::vector<const TriangleMesh*>::const_iterator it_mesh = m_meshes.begin(); it_mesh != m_meshes.end(); ++ it_mesh)
-		for (int i = 0; i < (*it_mesh)->stl.stats.number_of_facets; ++ i)
-			m_faces.push_back((*it_mesh)->stl.facet_start + i);
+		for (const stl_facet &face : (*it_mesh)->stl.facet_start)
+			m_faces.emplace_back(&face);
 
 	// 2) Sort faces lexicographically by their Z span.
 	std::sort(m_faces.begin(), m_faces.end(), [](const stl_facet *f1, const stl_facet *f2) {
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index b7c6c07a7..ac23abd26 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -51,7 +51,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
     stl.stats.type = inmemory;
 
     // count facets and allocate memory
-    stl.stats.number_of_facets = facets.size();
+    stl.stats.number_of_facets = (uint32_t)facets.size();
     stl.stats.original_num_facets = stl.stats.number_of_facets;
     stl_allocate(&stl);
 
@@ -78,25 +78,14 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
     stl_close(&this->stl);
     this->stl       = other.stl;
     this->repaired  = other.repaired;
-    this->stl.heads = nullptr;
+	this->stl.heads.clear();
     this->stl.tail  = nullptr;
     this->stl.error = other.stl.error;
-    if (other.stl.facet_start != nullptr) {
-        this->stl.facet_start = (stl_facet*)calloc(other.stl.stats.number_of_facets, sizeof(stl_facet));
-        std::copy(other.stl.facet_start, other.stl.facet_start + other.stl.stats.number_of_facets, this->stl.facet_start);
-    }
-    if (other.stl.neighbors_start != nullptr) {
-        this->stl.neighbors_start = (stl_neighbors*)calloc(other.stl.stats.number_of_facets, sizeof(stl_neighbors));
-        std::copy(other.stl.neighbors_start, other.stl.neighbors_start + other.stl.stats.number_of_facets, this->stl.neighbors_start);
-    }
-    if (other.stl.v_indices != nullptr) {
-        this->stl.v_indices = (v_indices_struct*)calloc(other.stl.stats.number_of_facets, sizeof(v_indices_struct));
-        std::copy(other.stl.v_indices, other.stl.v_indices + other.stl.stats.number_of_facets, this->stl.v_indices);
-    }
-    if (other.stl.v_shared != nullptr) {
-        this->stl.v_shared = (stl_vertex*)calloc(other.stl.stats.shared_vertices, sizeof(stl_vertex));
-        std::copy(other.stl.v_shared, other.stl.v_shared + other.stl.stats.shared_vertices, this->stl.v_shared);
-    }
+    this->stl.facet_start = other.stl.facet_start;
+    this->stl.neighbors_start = other.stl.neighbors_start;
+    this->stl.v_indices = other.stl.v_indices;
+	this->stl.v_shared = other.stl.v_shared;
+	this->stl.stats = other.stl.stats;
     return *this;
 }
 
@@ -125,8 +114,8 @@ void TriangleMesh::repair()
     
     // checking nearby
     //int last_edges_fixed = 0;
-	float tolerance = stl.stats.shortest_edge;
-    float increment = stl.stats.bounding_diameter / 10000.0;
+	float tolerance = (float)stl.stats.shortest_edge;
+	float increment = (float)stl.stats.bounding_diameter / 10000.0f;
     int iterations = 2;
     if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) {
         for (int i = 0; i < iterations; i++) {
@@ -444,7 +433,7 @@ TriangleMeshPtrs TriangleMesh::split() const
         TriangleMesh* mesh = new TriangleMesh;
         meshes.emplace_back(mesh);
         mesh->stl.stats.type = inmemory;
-        mesh->stl.stats.number_of_facets = facets.size();
+        mesh->stl.stats.number_of_facets = (uint32_t)facets.size();
         mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
         stl_clear_error(&mesh->stl);
         stl_allocate(&mesh->stl);
@@ -486,13 +475,12 @@ ExPolygons TriangleMesh::horizontal_projection() const
 {
     Polygons pp;
     pp.reserve(this->stl.stats.number_of_facets);
-    for (uint32_t i = 0; i < this->stl.stats.number_of_facets; ++ i) {
-        stl_facet* facet = &this->stl.facet_start[i];
+	for (const stl_facet &facet : this->stl.facet_start) {
         Polygon p;
         p.points.resize(3);
-        p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1));
-        p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1));
-        p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1));
+        p.points[0] = Point::new_scale(facet.vertex[0](0), facet.vertex[0](1));
+        p.points[1] = Point::new_scale(facet.vertex[1](0), facet.vertex[1](1));
+        p.points[2] = Point::new_scale(facet.vertex[2](0), facet.vertex[2](1));
         p.make_counter_clockwise();  // do this after scaling, as winding order might change while doing that
         pp.emplace_back(p);
     }
@@ -526,17 +514,15 @@ BoundingBoxf3 TriangleMesh::bounding_box() const
 BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const
 {
     BoundingBoxf3 bbox;
-    if (stl.v_shared == nullptr) {
+    if (stl.v_shared.empty()) {
         // Using the STL faces.
-        for (size_t i = 0; i < this->facets_count(); ++ i) {
-            const stl_facet &facet = this->stl.facet_start[i];
+		for (const stl_facet &facet : this->stl.facet_start)
             for (size_t j = 0; j < 3; ++ j)
                 bbox.merge(trafo * facet.vertex[j].cast<double>());
-        }
     } else {
         // Using the shared vertices should be a bit quicker than using the STL faces.
-        for (int i = 0; i < stl.stats.shared_vertices; ++ i)            
-            bbox.merge(trafo * this->stl.v_shared[i].cast<double>());
+		for (const stl_vertex &v : this->stl.v_shared)
+            bbox.merge(trafo * v.cast<double>());
     }
     return bbox;
 }
@@ -551,18 +537,12 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
     std::vector<PointForQHull> src_vertices;
 
     // We will now fill the vector with input points for computation:
-    stl_facet* facet_ptr = stl.facet_start;
-    while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
-    {
-        for (int i = 0; i < 3; ++i)
-        {
-            const stl_vertex& v = facet_ptr->vertex[i];
+	for (const stl_facet &facet : stl.facet_start)
+        for (int i = 0; i < 3; ++ i) {
+            const stl_vertex& v = facet.vertex[i];
             src_vertices.emplace_back(v(0), v(1), v(2));
         }
 
-        facet_ptr += 1;
-    }
-
     // The qhull call:
     orgQhull::Qhull qhull;
     qhull.disableOutputStream(); // we want qhull to be quiet
@@ -606,7 +586,7 @@ void TriangleMesh::require_shared_vertices()
     assert(stl_validate(&this->stl));
     if (! this->repaired) 
         this->repair();
-    if (this->stl.v_shared == nullptr) {
+    if (this->stl.v_shared.empty()) {
         BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices";
         stl_generate_shared_vertices(&(this->stl));
     }
@@ -622,10 +602,9 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
 
     throw_on_cancel();
     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
-    v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
-    // Scale the copied vertices.
-    for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i)
-        this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR);
+	v_scaled_shared.assign(_mesh->stl.v_shared.size(), stl_vertex());
+	for (size_t i = 0; i < v_scaled_shared.size(); ++ i)
+        this->v_scaled_shared[i] = _mesh->stl.v_shared[i] / float(SCALING_FACTOR);
 
     // Create a mapping from triangle edge into face.
     struct EdgeToFace {
@@ -814,7 +793,7 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons
 void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, 
     const std::vector<float> &z) const
 {
-    const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx];
+    const stl_facet &facet = m_use_quaternion ? (this->mesh->stl.facet_start.data() + facet_idx)->rotated(m_quaternion) : *(this->mesh->stl.facet_start.data() + facet_idx);
     
     // find facet extents
     const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
@@ -1710,7 +1689,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object";
     float scaled_z = scale_(z);
     for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) {
-        stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
+        const stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
         
         // find facet extents
         float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2)));
@@ -1901,10 +1880,10 @@ TriangleMesh make_cylinder(double r, double h, double fa)
 //FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html
 TriangleMesh make_sphere(double radius, double fa)
 {
-	int   sectorCount = ceil(2. * M_PI / fa);
-	int   stackCount  = ceil(M_PI / fa);
-	float sectorStep  = 2. * M_PI / sectorCount;
-	float stackStep   = M_PI / stackCount;
+	int   sectorCount = int(ceil(2. * M_PI / fa));
+	int   stackCount  = int(ceil(M_PI / fa));
+	float sectorStep  = float(2. * M_PI / sectorCount);
+	float stackStep   = float(M_PI / stackCount);
 
 	Pointf3s vertices;
 	vertices.reserve((stackCount - 1) * sectorCount + 2);
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index c284f6482..4de1f5989 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -58,7 +58,7 @@ public:
     TriangleMeshPtrs split() const;
     void merge(const TriangleMesh &mesh);
     ExPolygons horizontal_projection() const;
-    const float* first_vertex() const { return this->stl.facet_start ? &this->stl.facet_start->vertex[0](0) : nullptr; }
+    const float* first_vertex() const { return this->stl.facet_start.empty() ? nullptr : &this->stl.facet_start.front().vertex[0](0); }
     // 2D convex hull of a 3D mesh projected into the Z=0 plane.
     Polygon convex_hull();
     BoundingBoxf3 bounding_box() const;
@@ -69,7 +69,7 @@ public:
     void reset_repair_stats();
     bool needed_repair() const;
     void require_shared_vertices();
-    bool   has_shared_vertices() const { return stl.v_shared != NULL; }
+    bool   has_shared_vertices() const { return ! stl.v_shared.empty(); }
     size_t facets_count() const { return this->stl.stats.number_of_facets; }
     bool   empty() const { return this->facets_count() == 0; }
     bool is_splittable() const;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index d118a6877..ae017f7d1 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -396,10 +396,10 @@ void GLGizmoSlaSupports::update_mesh()
     V.resize(3 * stl.stats.number_of_facets, 3);
     F.resize(stl.stats.number_of_facets, 3);
     for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
-        const stl_facet* facet = stl.facet_start+i;
-        V(3*i+0, 0) = facet->vertex[0](0); V(3*i+0, 1) = facet->vertex[0](1); V(3*i+0, 2) = facet->vertex[0](2);
-        V(3*i+1, 0) = facet->vertex[1](0); V(3*i+1, 1) = facet->vertex[1](1); V(3*i+1, 2) = facet->vertex[1](2);
-        V(3*i+2, 0) = facet->vertex[2](0); V(3*i+2, 1) = facet->vertex[2](1); V(3*i+2, 2) = facet->vertex[2](2);
+        const stl_facet &facet = stl.facet_start[i];
+		V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0];
+		V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1];
+		V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2];
         F(i, 0) = 3*i+0;
         F(i, 1) = 3*i+1;
         F(i, 2) = 3*i+2;

From c7ba48a4735cb2f6e98b56999a1b5d7476bde0fb Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Wed, 5 Jun 2019 09:54:52 +0200
Subject: [PATCH 03/22] Fix of perl bindings

---
 xs/xsp/TriangleMesh.xsp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index e519f9210..a188e0b8d 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -100,7 +100,7 @@ TriangleMesh::vertices()
     CODE:
         if (!THIS->repaired) CONFESS("vertices() requires repair()");
         
-        if (THIS->stl.v_shared == NULL)
+        if (THIS->stl.v_shared.empty())
             stl_generate_shared_vertices(&(THIS->stl));
         
         // vertices
@@ -124,7 +124,7 @@ TriangleMesh::facets()
     CODE:
         if (!THIS->repaired) CONFESS("facets() requires repair()");
         
-        if (THIS->stl.v_shared == NULL)
+        if (THIS->stl.v_shared.empty())
             stl_generate_shared_vertices(&(THIS->stl));
         
         // facets

From 025f86ca3f14e35d617ddb6c76dc5d463d5bf11e Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 11:04:09 +0200
Subject: [PATCH 04/22] Fix of the previous refactoring.

---
 src/admesh/connect.cpp         |  8 +++++---
 src/admesh/shared.cpp          |  3 ++-
 src/admesh/util.cpp            |  5 +++++
 src/libslic3r/TriangleMesh.cpp | 35 +++++++++++++++-------------------
 4 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index b99f93f3d..d35c48aba 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -837,10 +837,12 @@ void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
 {
 	if (stl->error)
 		return;
-  	++ stl->stats.facets_added;
-  	++ stl->stats.number_of_facets;
-  	stl->facet_start.emplace_back(*new_facet);
+	assert(stl->facet_start.size() == stl->stats.number_of_facets);
+	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
+	stl->facet_start.emplace_back(*new_facet);
   	// note that the normal vector is not set here, just initialized to 0.
   	stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
   	stl->neighbors_start.emplace_back();
+	++ stl->stats.facets_added;
+	++ stl->stats.number_of_facets;
 }
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index 8162c6a8d..bc264ee96 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -33,6 +33,7 @@ void stl_invalidate_shared_vertices(stl_file *stl)
 {
   	stl->v_indices.clear();
   	stl->v_shared.clear();
+  	stl->stats.shared_vertices = 0;
 }
 
 void stl_generate_shared_vertices(stl_file *stl)
@@ -46,7 +47,7 @@ void stl_generate_shared_vertices(stl_file *stl)
 	// 3 indices to vertex per face
 	stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct());
 	// Shared vertices (3D coordinates)
-	stl->v_shared.assign(stl->stats.number_of_facets / 2, stl_vertex());
+	stl->v_shared.reserve(stl->stats.number_of_facets / 2);
 	stl->stats.shared_vertices = 0;
 
 	// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 61e0d11e7..d8640e575 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -456,11 +456,16 @@ bool stl_validate(stl_file *stl)
 	assert(! stl->error);
 	assert(stl->fp == nullptr);
 	assert(! stl->facet_start.empty());
+	assert(stl->facet_start.size() == stl->stats.number_of_facets);
+	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
+	assert(stl->facet_start.size() == stl->neighbors_start.size());
 	assert(stl->heads.empty());
 	assert(stl->tail  == nullptr);
 	assert(! stl->neighbors_start.empty());
 	assert((stl->v_indices.empty()) == (stl->v_shared.empty()));
 	assert(stl->stats.number_of_facets > 0);
+	assert(stl->v_shared.size() == stl->stats.shared_vertices);
+	assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets);
 
 #ifdef _DEBUG
     // Verify validity of neighborship data.
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index a974f5af3..ad12047d2 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -47,7 +47,6 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
 {
     stl_initialize(&this->stl);
     stl_file &stl = this->stl;
-    stl.error = 0;
     stl.stats.type = inmemory;
 
     // count facets and allocate memory
@@ -55,7 +54,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
     stl.stats.original_num_facets = stl.stats.number_of_facets;
     stl_allocate(&stl);
 
-    for (uint32_t i = 0; i < stl.stats.number_of_facets; i++) {
+	for (uint32_t i = 0; i < stl.stats.number_of_facets; ++ i) {
         stl_facet facet;
         facet.vertex[0] = points[facets[i](0)].cast<float>();
         facet.vertex[1] = points[facets[i](1)].cast<float>();
@@ -76,16 +75,8 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
 TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
 {
     stl_close(&this->stl);
-    this->stl       = other.stl;
-    this->repaired  = other.repaired;
-	this->stl.heads.clear();
-    this->stl.tail  = nullptr;
-    this->stl.error = other.stl.error;
-    this->stl.facet_start = other.stl.facet_start;
-    this->stl.neighbors_start = other.stl.neighbors_start;
-    this->stl.v_indices = other.stl.v_indices;
-	this->stl.v_shared = other.stl.v_shared;
-	this->stl.stats = other.stl.stats;
+    this->stl = other.stl;
+	this->repaired = other.repaired;
     return *this;
 }
 
@@ -1711,10 +1702,12 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
         
         if (min_z > z || (min_z == z && max_z > z)) {
             // facet is above the cut plane and does not belong to it
-            if (upper != NULL) stl_add_facet(&upper->stl, facet);
+            if (upper != nullptr)
+				stl_add_facet(&upper->stl, facet);
         } else if (max_z < z || (max_z == z && min_z < z)) {
             // facet is below the cut plane and does not belong to it
-            if (lower != NULL) stl_add_facet(&lower->stl, facet);
+            if (lower != nullptr)
+				stl_add_facet(&lower->stl, facet);
         } else if (min_z < z && max_z > z) {
             // Facet is cut by the slicing plane.
 
@@ -1761,22 +1754,24 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
             quadrilateral[1].vertex[2] = v0v1;
             
             if (v0(2) > z) {
-                if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
-                if (lower != NULL) {
+                if (upper != nullptr) 
+					stl_add_facet(&upper->stl, &triangle);
+                if (lower != nullptr) {
                     stl_add_facet(&lower->stl, &quadrilateral[0]);
                     stl_add_facet(&lower->stl, &quadrilateral[1]);
                 }
             } else {
-                if (upper != NULL) {
+                if (upper != nullptr) {
                     stl_add_facet(&upper->stl, &quadrilateral[0]);
                     stl_add_facet(&upper->stl, &quadrilateral[1]);
                 }
-                if (lower != NULL) stl_add_facet(&lower->stl, &triangle);
+                if (lower != nullptr) 
+					stl_add_facet(&lower->stl, &triangle);
             }
         }
     }
     
-    if (upper != NULL) {
+    if (upper != nullptr) {
         BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating upper part";
         ExPolygons section;
         this->make_expolygons_simple(upper_lines, &section);
@@ -1790,7 +1785,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
         }
     }
     
-    if (lower != NULL) {
+    if (lower != nullptr) {
         BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - triangulating lower part";
         ExPolygons section;
         this->make_expolygons_simple(lower_lines, &section);

From 40b27e8332f5590d3998a2ef6c89bce65a48da27 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 16:53:08 +0200
Subject: [PATCH 05/22] admesh refactoring: Move the hashing structure out of
 stl_file

---
 src/admesh/connect.cpp                  | 1025 ++++++++++-------------
 src/admesh/stl.h                        |   24 +-
 src/admesh/stl_io.cpp                   |   13 -
 src/admesh/stlinit.cpp                  |    4 -
 src/admesh/util.cpp                     |    2 -
 src/libslic3r/Fill/FillRectilinear3.cpp |    2 +-
 6 files changed, 459 insertions(+), 611 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index d35c48aba..03b13343d 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -32,37 +32,363 @@
 
 #include "stl.h"
 
+struct HashEdge {
+	// Key of a hash edge: sorted vertices of the edge.
+	uint32_t       key[6];
+	// Compare two keys.
+	bool operator==(const HashEdge &rhs) const { return memcmp(key, rhs.key, sizeof(key)) == 0; }
+	bool operator!=(const HashEdge &rhs) const { return ! (*this == rhs); }
+	int  hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11  + key[4] / 7 + key[5] / 3)) % M; }
 
-static void stl_match_neighbors_nearby(stl_file *stl,
-                                       stl_hash_edge *edge_a, stl_hash_edge *edge_b);
-static void stl_record_neighbors(stl_file *stl,
-                                 stl_hash_edge *edge_a, stl_hash_edge *edge_b);
-static void stl_initialize_facet_check_nearby(stl_file *stl);
-static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b);
-static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
-                                stl_vertex *a, stl_vertex *b, float tolerance);
-static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
-                             void (*match_neighbors)(stl_file *stl,
-                                 stl_hash_edge *edge_a, stl_hash_edge *edge_b));
-static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b);
-static void stl_free_edges(stl_file *stl);
-static void stl_change_vertices(stl_file *stl, int facet_num, int vnot,
-                                stl_vertex new_vertex);
-static void stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
-    stl_hash_edge *edge_b, int *facet1, int *vertex1,
-    int *facet2, int *vertex2,
-    stl_vertex *new_vertex1, stl_vertex *new_vertex2);
-extern int stl_check_normal_vector(stl_file *stl,
-                                   int facet_num, int normal_fix_flag);
+	// Index of a facet owning this edge.
+	int            facet_number;
+	// Index of this edge inside the facet with an index of facet_number.
+	// If this edge is stored backwards, which_edge is increased by 3.
+	int            which_edge;
+	struct HashEdge  *next;
 
-static inline size_t hash_size_from_nr_faces(const size_t nr_faces)
+	void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b)
+	{
+		{
+	    	stl_vertex diff = (*a - *b).cwiseAbs();
+	    	float max_diff = std::max(diff(0), std::max(diff(1), diff(2)));
+	    	stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge);
+	  	}
+
+	  	// Ensure identical vertex ordering of equal edges.
+	  	// This method is numerically robust.
+	  	if (stl_vertex_lower(*a, *b)) {
+	  	} else {
+	  		// This edge is loaded backwards.
+		    std::swap(a, b);
+		    this->which_edge += 3;
+	  	}
+	  	memcpy(&this->key[0], a->data(), sizeof(stl_vertex));
+	  	memcpy(&this->key[3], b->data(), sizeof(stl_vertex));
+	  	// Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
+	  	for (size_t i = 0; i < 6; ++ i) {
+	    	unsigned char *p = (unsigned char*)(this->key + i);
+	#ifdef BOOST_LITTLE_ENDIAN
+	    	if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
+	      		// Negative zero, switch to positive zero.
+	      		p[3] = 0;
+	#else /* BOOST_LITTLE_ENDIAN */
+	    	if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0)
+	      		// Negative zero, switch to positive zero.
+	      		p[0] = 0;
+	#endif /* BOOST_LITTLE_ENDIAN */
+	  	}
+	}
+
+	bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance)
+	{
+		// Index of a grid cell spaced by tolerance.
+		typedef Eigen::Matrix<int32_t,  3, 1, Eigen::DontAlign> Vec3i;
+		Vec3i vertex1 = ((a - stl->stats.min) / tolerance).cast<int32_t>();
+		Vec3i vertex2 = ((b - stl->stats.min) / tolerance).cast<int32_t>();
+		static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect");
+
+		if (vertex1 == vertex2)
+			// Both vertices hash to the same value
+			return false;
+
+		// Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
+		// This method is numerically robust.
+		if ((vertex1[0] != vertex2[0]) ? 
+		    (vertex1[0] < vertex2[0]) : 
+		    ((vertex1[1] != vertex2[1]) ? 
+		        (vertex1[1] < vertex2[1]) : 
+		        (vertex1[2] < vertex2[2]))) {
+			memcpy(&this->key[0], vertex1.data(), sizeof(stl_vertex));
+			memcpy(&this->key[3], vertex2.data(), sizeof(stl_vertex));
+		} else {
+			memcpy(&this->key[0], vertex2.data(), sizeof(stl_vertex));
+			memcpy(&this->key[3], vertex1.data(), sizeof(stl_vertex));
+			this->which_edge += 3; /* this edge is loaded backwards */
+		}
+		return true;
+	}
+};
+
+struct HashTableEdges {
+	HashTableEdges(size_t number_of_faces) {
+		this->M = (int)hash_size_from_nr_faces(number_of_faces);
+		this->heads.assign(this->M, nullptr);
+		this->tail = new HashEdge;
+		this->tail->next = this->tail;
+		for (int i = 0; i < this->M; ++ i)
+			this->heads[i] = this->tail;
+	}
+	~HashTableEdges() {
+	    for (int i = 0; i < this->M; ++ i) {
+	    	for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) {
+	        	this->heads[i] = this->heads[i]->next;
+	        	delete temp;
+	        	++ this->freed;
+	      	}
+	    }
+		this->heads.clear();
+		delete this->tail;
+		this->tail = nullptr;
+	}
+
+	void insert_edge(stl_file *stl, const HashEdge &edge, void (*match_neighbors)(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b))
+	{
+		int       chain_number = edge.hash(this->M);
+		HashEdge *link         = this->heads[chain_number];
+		if (link == this->tail) {
+			// This list doesn't have any edges currently in it.  Add this one.
+			HashEdge *new_edge = new HashEdge(edge);
+			++ this->malloced;
+			new_edge->next = this->tail;
+			this->heads[chain_number] = new_edge;
+		} else if (edges_equal(edge, *link)) {
+			// This is a match.  Record result in neighbors list.
+			match_neighbors(stl, edge, *link);
+			// Delete the matched edge from the list.
+			this->heads[chain_number] = link->next;
+			delete link;
+			++ this->freed;
+		} else {
+			// Continue through the rest of the list.
+			for (;;) {
+				if (link->next == this->tail) {
+					// This is the last item in the list. Insert a new edge.
+					HashEdge *new_edge = new HashEdge;
+					++ this->malloced;
+					*new_edge = edge;
+					new_edge->next = this->tail;
+					link->next = new_edge;
+					++ this->collisions;
+					break;
+				}
+				if (edges_equal(edge, *link->next)) {
+					// This is a match.  Record result in neighbors list.
+					match_neighbors(stl, edge, *link->next);
+					// Delete the matched edge from the list.
+					HashEdge *temp = link->next;
+					link->next = link->next->next;
+					delete temp;
+					++ this->freed;
+					break;
+				}
+				// This is not a match.  Go to the next link.
+				link = link->next;
+				++ this->collisions;
+			}
+		}
+	}
+
+	// Hash table on edges
+	std::vector<HashEdge*> 	heads;
+	HashEdge* 					tail;
+	int           					M;
+
+	size_t 							malloced   	= 0;
+	size_t 							freed 	  	= 0;
+	size_t 							collisions 	= 0;
+
+private:
+	static inline size_t hash_size_from_nr_faces(const size_t nr_faces)
+	{
+		// Good primes for addressing a cca. 30 bit space.
+		// https://planetmath.org/goodhashtableprimes
+		static std::vector<uint32_t> primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
+		// Find a prime number for 50% filling of the shared triangle edges in the mesh.
+		auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1);
+		return (it == primes.end()) ? primes.back() : *it;
+	}
+
+	// Edges equal for hashing. Edgesof different facet are allowed to be matched.
+	static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b)
+	{
+	    return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b;
+	}
+};
+
+static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
 {
-	// Good primes for addressing a cca. 30 bit space.
-	// https://planetmath.org/goodhashtableprimes
-	static std::vector<uint32_t> primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
-	// Find a prime number for 50% filling of the shared triangle edges in the mesh.
-	auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1);
-	return (it == primes.end()) ? primes.back() : *it;
+	// Facet a's neighbor is facet b
+	stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number;	/* sets the .neighbor part */
+	stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */
+
+	// Facet b's neighbor is facet a
+	stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number;	/* sets the .neighbor part */
+	stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
+
+	if (((edge_a.which_edge < 3) && (edge_b.which_edge < 3)) || ((edge_a.which_edge > 2) && (edge_b.which_edge > 2))) {
+		// These facets are oriented in opposite directions, their normals are probably messed up.
+		stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
+		stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
+	}
+
+	// Count successful connects:
+	// Total connects:
+	stl->stats.connected_edges += 2;
+	// Count individual connects:
+	switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) {
+	case 1:	++ stl->stats.connected_facets_1_edge; break;
+	case 2: ++ stl->stats.connected_facets_2_edge; break;
+	case 3: ++ stl->stats.connected_facets_3_edge; break;
+	default: assert(false);
+	}
+	switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) {
+	case 1:	++ stl->stats.connected_facets_1_edge; break;
+	case 2: ++ stl->stats.connected_facets_2_edge; break;
+	case 3: ++ stl->stats.connected_facets_3_edge; break;
+	default: assert(false);
+	}
+}
+
+static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
+{
+	record_neighbors(stl, edge_a, edge_b);
+
+	// Which vertices to change
+	int facet1 = -1;
+	int facet2 = -1;
+	int vertex1, vertex2;
+	stl_vertex new_vertex1, new_vertex2;
+	{
+		int v1a; // pair 1, facet a
+		int v1b; // pair 1, facet b
+		int v2a; // pair 2, facet a
+		int v2b; // pair 2, facet b
+		// Find first pair.
+		if (edge_a.which_edge < 3) {
+			v1a = edge_a.which_edge;
+			v2a = (edge_a.which_edge + 1) % 3;
+		} else {
+			v2a = edge_a.which_edge % 3;
+			v1a = (edge_a.which_edge + 1) % 3;
+		}
+		if (edge_b.which_edge < 3) {
+			v1b = edge_b.which_edge;
+			v2b = (edge_b.which_edge + 1) % 3;
+		} else {
+			v2b = edge_b.which_edge % 3;
+			v1b = (edge_b.which_edge + 1) % 3;
+		}
+
+		// Of the first pair, which vertex, if any, should be changed
+		if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) {
+			// These facets are different.
+			if (   (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1)
+		        && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) {
+		  		// This vertex has no neighbors.  This is a good one to change.
+		  		facet1 = edge_a.facet_number;
+		  		vertex1 = v1a;
+		  		new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b];
+			} else {
+			  	facet1 = edge_b.facet_number;
+		  		vertex1 = v1b;
+		  		new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a];
+			}
+		}
+
+		// Of the second pair, which vertex, if any, should be changed.
+		if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) {
+			// These facets are different.
+			if (  (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1)
+		       && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) {
+		  		// This vertex has no neighbors.  This is a good one to change.
+		  		facet2 = edge_a.facet_number;
+		  		vertex2 = v2a;
+		  		new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b];
+			} else {
+		  		facet2 = edge_b.facet_number;
+		  		vertex2 = v2b;
+		  		new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a];
+			}
+		}
+	}
+
+	auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex)
+	{
+		int first_facet = facet_num;
+		bool direction = false;
+
+		for (;;) {
+			int pivot_vertex;
+			int next_edge;
+			if (vnot > 2) {
+				if (direction) {
+					pivot_vertex = (vnot + 1) % 3;
+					next_edge = vnot % 3;
+				}
+				else {
+					pivot_vertex = (vnot + 2) % 3;
+					next_edge = pivot_vertex;
+				}
+				direction = !direction;
+			}
+			else {
+				if (direction) {
+					pivot_vertex = (vnot + 2) % 3;
+					next_edge = pivot_vertex;
+				}
+				else {
+					pivot_vertex = (vnot + 1) % 3;
+					next_edge = vnot;
+				}
+			}
+#if 0
+			if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
+				stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
+				stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
+				printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2));
+			else {
+				if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
+					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+						stl->facet_start[facet_num].vertex[pivot_vertex](0),
+						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
+						new_vertex(0),
+						*reinterpret_cast<const int*>(&new_vertex(0)));
+				if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
+					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+						stl->facet_start[facet_num].vertex[pivot_vertex](1),
+						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
+						new_vertex(1),
+						*reinterpret_cast<const int*>(&new_vertex(1)));
+				if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
+					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+						stl->facet_start[facet_num].vertex[pivot_vertex](2),
+						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
+						new_vertex(2),
+						*reinterpret_cast<const int*>(&new_vertex(2)));
+			}
+#endif
+			stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
+			vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
+			facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
+			if (facet_num == -1)
+				break;
+
+			if (facet_num == first_facet) {
+				// back to the beginning
+				printf("Back to the first facet changing vertices: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n");
+				return;
+			}
+		}
+	};
+
+	if (facet1 != -1) {
+		int vnot1 = (facet1 == edge_a.facet_number) ? 
+	  		(edge_a.which_edge + 2) % 3 :
+			(edge_b.which_edge + 2) % 3;
+		if (((vnot1 + 2) % 3) == vertex1)
+	  		vnot1 += 3;
+		change_vertices(facet1, vnot1, new_vertex1);
+	}
+	if (facet2 != -1) {
+		int vnot2 = (facet2 == edge_a.facet_number) ?
+	  		(edge_a.which_edge + 2) % 3 :
+			(edge_b.which_edge + 2) % 3;
+		if (((vnot2 + 2) % 3) == vertex2)
+	  		vnot2 += 3;
+		change_vertices(facet2, vnot2, new_vertex2);
+	}
+	stl->stats.edges_fixed += 2;
 }
 
 // This function builds the neighbors list.  No modifications are made
@@ -93,30 +419,21 @@ void stl_check_facets_exact(stl_file *stl)
   	}
 
   	// Initialize hash table.
-	stl->stats.malloced   = 0;
-	stl->stats.freed      = 0;
-	stl->stats.collisions = 0;
-	stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
+  	HashTableEdges hash_table(stl->stats.number_of_facets);
 	for (auto &neighbor : stl->neighbors_start)
 		neighbor.reset();
-	stl->heads.assign(stl->M, nullptr);
-	stl->tail = new stl_hash_edge;
-	stl->tail->next = stl->tail;
-	for (int i = 0; i < stl->M; ++ i)
-		stl->heads[i] = stl->tail;
 
   	// Connect neighbor edges.
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		const stl_facet &facet = stl->facet_start[i];
 		for (int j = 0; j < 3; ++ j) {
-			stl_hash_edge  edge;
+			HashEdge edge;
 			edge.facet_number = i;
 			edge.which_edge = j;
-			stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
-			insert_hash_edge(stl, edge, stl_record_neighbors);
+			edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
+			hash_table.insert_edge(stl, edge, record_neighbors);
 		}
 	}
-	stl_free_edges(stl);
 
 #if 0
 	printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n", 
@@ -125,444 +442,33 @@ void stl_check_facets_exact(stl_file *stl)
 #endif
 }
 
-static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b) {
-
-  if (stl->error) return;
-
-  {
-    stl_vertex diff = (*a - *b).cwiseAbs();
-    float max_diff = std::max(diff(0), std::max(diff(1), diff(2)));
-    stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge);
-  }
-
-  // Ensure identical vertex ordering of equal edges.
-  // This method is numerically robust.
-  if (stl_vertex_lower(*a, *b)) {
-  } else {
-    std::swap(a, b);
-    edge->which_edge += 3; /* this edge is loaded backwards */
-  }
-  memcpy(&edge->key[0], a->data(), sizeof(stl_vertex));
-  memcpy(&edge->key[3], b->data(), sizeof(stl_vertex));
-  // Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
-  for (size_t i = 0; i < 6; ++ i) {
-    unsigned char *p = (unsigned char*)(edge->key + i);
-#ifdef BOOST_LITTLE_ENDIAN
-    if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
-      // Negative zero, switch to positive zero.
-      p[3] = 0;
-#else /* BOOST_LITTLE_ENDIAN */
-    if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0)
-      // Negative zero, switch to positive zero.
-      p[0] = 0;
-#endif /* BOOST_LITTLE_ENDIAN */
-  }
-}
-
-static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
-                 void (*match_neighbors)(stl_file *stl,
-                     stl_hash_edge *edge_a, stl_hash_edge *edge_b))
-{
-  if (stl->error) return;
-
-  int            chain_number = edge.hash(stl->M);
-  stl_hash_edge *link = stl->heads[chain_number];
-
-  stl_hash_edge *new_edge;
-  stl_hash_edge *temp;
-  if(link == stl->tail) {
-    /* This list doesn't have any edges currently in it.  Add this one. */
-    new_edge = new stl_hash_edge;
-    if(new_edge == NULL) perror("insert_hash_edge");
-    stl->stats.malloced++;
-    *new_edge = edge;
-    new_edge->next = stl->tail;
-    stl->heads[chain_number] = new_edge;
-    return;
-  } else  if(!stl_compare_function(&edge, link)) {
-    /* This is a match.  Record result in neighbors list. */
-    match_neighbors(stl, &edge, link);
-    /* Delete the matched edge from the list. */
-    stl->heads[chain_number] = link->next;
-    delete link;
-    stl->stats.freed++;
-    return;
-  } else {
-    /* Continue through the rest of the list */
-    for(;;) {
-      if(link->next == stl->tail) {
-        /* This is the last item in the list. Insert a new edge. */
-        new_edge = new stl_hash_edge;
-        if(new_edge == NULL) perror("insert_hash_edge");
-        stl->stats.malloced++;
-        *new_edge = edge;
-        new_edge->next = stl->tail;
-        link->next = new_edge;
-        stl->stats.collisions++;
-        return;
-      } else  if(!stl_compare_function(&edge, link->next)) {
-        /* This is a match.  Record result in neighbors list. */
-        match_neighbors(stl, &edge, link->next);
-
-        /* Delete the matched edge from the list. */
-        temp = link->next;
-        link->next = link->next->next;
-        delete temp;
-        stl->stats.freed++;
-        return;
-      } else {
-        /* This is not a match.  Go to the next link */
-        link = link->next;
-        stl->stats.collisions++;
-      }
-    }
-  }
-}
-
-// Return 1 if the edges are not matched.
-static inline int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b)
-{
-    // Don't match edges of the same facet
-    return (edge_a->facet_number == edge_b->facet_number) || (*edge_a != *edge_b);
-}
-
 void stl_check_facets_nearby(stl_file *stl, float tolerance)
-{
-  if (stl->error)
-    return;
-
-  if(   (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
-        && (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
-        && (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)) {
-    /* No need to check any further.  All facets are connected */
-    return;
-  }
-
-  stl_initialize_facet_check_nearby(stl);
-
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-    //FIXME is the copy necessary?
-    stl_facet facet = stl->facet_start[i];
-    for (int j = 0; j < 3; j++) {
-      if(stl->neighbors_start[i].neighbor[j] == -1) {
-        stl_hash_edge edge;
-        edge.facet_number = i;
-        edge.which_edge = j;
-        if(stl_load_edge_nearby(stl, &edge, &facet.vertex[j],
-                                &facet.vertex[(j + 1) % 3],
-                                tolerance)) {
-          /* only insert edges that have different keys */
-          insert_hash_edge(stl, edge, stl_match_neighbors_nearby);
-        }
-      }
-    }
-  }
-
-  stl_free_edges(stl);
-}
-
-static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, stl_vertex *a, stl_vertex *b, float tolerance)
-{
-  // Index of a grid cell spaced by tolerance.
-  typedef Eigen::Matrix<int32_t,  3, 1, Eigen::DontAlign> Vec3i;
-  Vec3i vertex1 = ((*a - stl->stats.min) / tolerance).cast<int32_t>();
-  Vec3i vertex2 = ((*b - stl->stats.min) / tolerance).cast<int32_t>();
-  static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect");
-
-  if (vertex1 == vertex2)
-    // Both vertices hash to the same value
-    return 0;
-
-  // Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
-  // This method is numerically robust.
-  if ((vertex1[0] != vertex2[0]) ? 
-        (vertex1[0] < vertex2[0]) : 
-        ((vertex1[1] != vertex2[1]) ? 
-            (vertex1[1] < vertex2[1]) : 
-            (vertex1[2] < vertex2[2]))) {
-    memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex));
-    memcpy(&edge->key[3], vertex2.data(), sizeof(stl_vertex));
-  } else {
-    memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex));
-    memcpy(&edge->key[3], vertex1.data(), sizeof(stl_vertex));
-    edge->which_edge += 3; /* this edge is loaded backwards */
-  }
-  return 1;
-}
-
-static void stl_free_edges(stl_file *stl)
-{
-  if (stl->error)
-    return;
-
-  if(stl->stats.malloced != stl->stats.freed) {
-    for (int i = 0; i < stl->M; i++) {
-      for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) {
-        stl->heads[i] = stl->heads[i]->next;
-        delete temp;
-        ++ stl->stats.freed;
-      }
-    }
-  }
-  stl->heads.clear();
-  delete stl->tail;
-  stl->tail = nullptr;
-}
-
-static void stl_initialize_facet_check_nearby(stl_file *stl)
 {
 	if (stl->error)
 		return;
 
-	stl->stats.malloced   = 0;
-	stl->stats.freed 	  = 0;
-	stl->stats.collisions = 0;
+  	if (  (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
+       && (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
+       && (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)) {
+    	// No need to check any further.  All facets are connected.
+    	return;
+  	}
 
-	/*  tolerance = STL_MAX(stl->stats.shortest_edge, tolerance);*/
-	/*  tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
-	/*  tolerance *= 0.5;*/
-	stl->M = (int)hash_size_from_nr_faces(stl->stats.number_of_facets);
-
-	stl->heads.assign(stl->M, nullptr);
-	stl->tail = new stl_hash_edge;
-	stl->tail->next = stl->tail;
-
-	for (int i = 0; i < stl->M; ++ i)
-		stl->heads[i] = stl->tail;
-}
-
-static void
-stl_record_neighbors(stl_file *stl,
-                     stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
-  int i;
-  int j;
-
-  if (stl->error) return;
-
-  /* Facet a's neighbor is facet b */
-  stl->neighbors_start[edge_a->facet_number].neighbor[edge_a->which_edge % 3] = edge_b->facet_number;	/* sets the .neighbor part */
-  stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] = (edge_b->which_edge + 2) % 3; /* sets the .which_vertex_not part */
-
-  /* Facet b's neighbor is facet a */
-  stl->neighbors_start[edge_b->facet_number].neighbor[edge_b->which_edge % 3] = edge_a->facet_number;	/* sets the .neighbor part */
-  stl->neighbors_start[edge_b->facet_number].which_vertex_not[edge_b->which_edge % 3] = (edge_a->which_edge + 2) % 3; /* sets the .which_vertex_not part */
-
-  if(   ((edge_a->which_edge < 3) && (edge_b->which_edge < 3))
-        || ((edge_a->which_edge > 2) && (edge_b->which_edge > 2))) {
-    /* these facets are oriented in opposite directions.  */
-    /*  their normals are probably messed up. */
-    stl->neighbors_start[edge_a->facet_number].which_vertex_not[edge_a->which_edge % 3] += 3;
-    stl->neighbors_start[edge_b->facet_number].which_vertex_not[edge_b->which_edge % 3] += 3;
-  }
-
-
-  /* Count successful connects */
-  /* Total connects */
-  stl->stats.connected_edges += 2;
-  /* Count individual connects */
-  i = ((stl->neighbors_start[edge_a->facet_number].neighbor[0] == -1) +
-       (stl->neighbors_start[edge_a->facet_number].neighbor[1] == -1) +
-       (stl->neighbors_start[edge_a->facet_number].neighbor[2] == -1));
-  j = ((stl->neighbors_start[edge_b->facet_number].neighbor[0] == -1) +
-       (stl->neighbors_start[edge_b->facet_number].neighbor[1] == -1) +
-       (stl->neighbors_start[edge_b->facet_number].neighbor[2] == -1));
-  if(i == 2) {
-    stl->stats.connected_facets_1_edge +=1;
-  } else if(i == 1) {
-    stl->stats.connected_facets_2_edge +=1;
-  } else {
-    stl->stats.connected_facets_3_edge +=1;
-  }
-  if(j == 2) {
-    stl->stats.connected_facets_1_edge +=1;
-  } else if(j == 1) {
-    stl->stats.connected_facets_2_edge +=1;
-  } else {
-    stl->stats.connected_facets_3_edge +=1;
-  }
-}
-
-static void stl_match_neighbors_nearby(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b)
-{
-  int facet1;
-  int facet2;
-  int vertex1;
-  int vertex2;
-  int vnot1;
-  int vnot2;
-  stl_vertex new_vertex1;
-  stl_vertex new_vertex2;
-
-  if (stl->error) return;
-
-  stl_record_neighbors(stl, edge_a, edge_b);
-  stl_which_vertices_to_change(stl, edge_a, edge_b, &facet1, &vertex1,
-                               &facet2, &vertex2, &new_vertex1, &new_vertex2);
-  if(facet1 != -1) {
-    if(facet1 == edge_a->facet_number) {
-      vnot1 = (edge_a->which_edge + 2) % 3;
-    } else {
-      vnot1 = (edge_b->which_edge + 2) % 3;
-    }
-    if(((vnot1 + 2) % 3) == vertex1) {
-      vnot1 += 3;
-    }
-    stl_change_vertices(stl, facet1, vnot1, new_vertex1);
-  }
-  if(facet2 != -1) {
-    if(facet2 == edge_a->facet_number) {
-      vnot2 = (edge_a->which_edge + 2) % 3;
-    } else {
-      vnot2 = (edge_b->which_edge + 2) % 3;
-    }
-    if(((vnot2 + 2) % 3) == vertex2) {
-      vnot2 += 3;
-    }
-    stl_change_vertices(stl, facet2, vnot2, new_vertex2);
-  }
-  stl->stats.edges_fixed += 2;
-}
-
-
-static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, stl_vertex new_vertex) {
-  int first_facet;
-  int direction;
-  int next_edge;
-  int pivot_vertex;
-
-  if (stl->error) return;
-
-  first_facet = facet_num;
-  direction = 0;
-
-  for(;;) {
-    if(vnot > 2) {
-      if(direction == 0) {
-        pivot_vertex = (vnot + 2) % 3;
-        next_edge = pivot_vertex;
-        direction = 1;
-      } else {
-        pivot_vertex = (vnot + 1) % 3;
-        next_edge = vnot % 3;
-        direction = 0;
-      }
-    } else {
-      if(direction == 0) {
-        pivot_vertex = (vnot + 1) % 3;
-        next_edge = vnot;
-      } else {
-        pivot_vertex = (vnot + 2) % 3;
-        next_edge = pivot_vertex;
-      }
-    }
-#if 0
-    if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
-        stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
-        stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
-      printf("Changing vertex %f,%f,%f: Same !!!\r\n", 
-        new_vertex(0), new_vertex(1), new_vertex(2));
-    else {
-      if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
-        printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex](0),
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
-          new_vertex(0),
-          *reinterpret_cast<const int*>(&new_vertex(0)));
-      if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
-        printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex](1),
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
-          new_vertex(1),
-          *reinterpret_cast<const int*>(&new_vertex(1)));
-      if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
-        printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n", 
-          stl->facet_start[facet_num].vertex[pivot_vertex](2),
-          *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
-          new_vertex(2),
-          *reinterpret_cast<const int*>(&new_vertex(2)));
-    }
-#endif
-    stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
-    vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
-    facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
-
-    if(facet_num == -1) {
-      break;
-    }
-
-    if(facet_num == first_facet) {
-      /* back to the beginning */
-      printf("\
-Back to the first facet changing vertices: probably a mobius part.\n\
-Try using a smaller tolerance or don't do a nearby check\n");
-      return;
-    }
-  }
-}
-
-static void
-stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
-                             stl_hash_edge *edge_b, int *facet1, int *vertex1,
-                             int *facet2, int *vertex2,
-                             stl_vertex *new_vertex1, stl_vertex *new_vertex2) {
-  int v1a;			/* pair 1, facet a */
-  int v1b;			/* pair 1, facet b */
-  int v2a;			/* pair 2, facet a */
-  int v2b;			/* pair 2, facet b */
-
-  /* Find first pair */
-  if(edge_a->which_edge < 3) {
-    v1a = edge_a->which_edge;
-    v2a = (edge_a->which_edge + 1) % 3;
-  } else {
-    v2a = edge_a->which_edge % 3;
-    v1a = (edge_a->which_edge + 1) % 3;
-  }
-  if(edge_b->which_edge < 3) {
-    v1b = edge_b->which_edge;
-    v2b = (edge_b->which_edge + 1) % 3;
-  } else {
-    v2b = edge_b->which_edge % 3;
-    v1b = (edge_b->which_edge + 1) % 3;
-  }
-
-  // Of the first pair, which vertex, if any, should be changed
-  if(stl->facet_start[edge_a->facet_number].vertex[v1a] == 
-     stl->facet_start[edge_b->facet_number].vertex[v1b]) {
-    // These facets are already equal.  No need to change.
-    *facet1 = -1;
-  } else {
-    if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1)
-          && (stl->neighbors_start[edge_a->facet_number].neighbor[(v1a + 2) % 3] == -1)) {
-      /* This vertex has no neighbors.  This is a good one to change */
-      *facet1 = edge_a->facet_number;
-      *vertex1 = v1a;
-      *new_vertex1 = stl->facet_start[edge_b->facet_number].vertex[v1b];
-    } else {
-      *facet1 = edge_b->facet_number;
-      *vertex1 = v1b;
-      *new_vertex1 = stl->facet_start[edge_a->facet_number].vertex[v1a];
-    }
-  }
-
-  /* Of the second pair, which vertex, if any, should be changed */
-  if(stl->facet_start[edge_a->facet_number].vertex[v2a] == 
-     stl->facet_start[edge_b->facet_number].vertex[v2b]) {
-    // These facets are already equal.  No need to change.
-    *facet2 = -1;
-  } else {
-    if(   (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1)
-          && (stl->neighbors_start[edge_a->facet_number].neighbor[(v2a + 2) % 3] == -1)) {
-      /* This vertex has no neighbors.  This is a good one to change */
-      *facet2 = edge_a->facet_number;
-      *vertex2 = v2a;
-      *new_vertex2 = stl->facet_start[edge_b->facet_number].vertex[v2b];
-    } else {
-      *facet2 = edge_b->facet_number;
-      *vertex2 = v2b;
-      *new_vertex2 = stl->facet_start[edge_a->facet_number].vertex[v2a];
-    }
-  }
+  	HashTableEdges hash_table(stl->stats.number_of_facets);
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+    	//FIXME is the copy necessary?
+    	stl_facet facet = stl->facet_start[i];
+    	for (int j = 0; j < 3; j++) {
+      		if (stl->neighbors_start[i].neighbor[j] == -1) {
+        		HashEdge edge;
+        		edge.facet_number = i;
+        		edge.which_edge = j;
+        		if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance))
+          			// Only insert edges that have different keys.
+          			hash_table.insert_edge(stl, edge, match_neighbors_nearby);
+      		}
+    	}
+  	}
 }
 
 void stl_remove_unconnected_facets(stl_file *stl)
@@ -728,109 +634,88 @@ void stl_remove_unconnected_facets(stl_file *stl)
 	}
 }
 
-void
-stl_fill_holes(stl_file *stl) {
-  stl_facet facet;
-  stl_facet new_facet;
-  int neighbors_initial[3];
-  stl_hash_edge edge;
-  int first_facet;
-  int direction;
-  int facet_num;
-  int vnot;
-  int next_edge;
-  int pivot_vertex;
-  int next_facet;
-  int j;
-  int k;
+void stl_fill_holes(stl_file *stl)
+{
+	if (stl->error)
+		return;
 
-  if (stl->error) return;
+	// Insert all unconnected edges into hash list.
+	HashTableEdges hash_table(stl->stats.number_of_facets);
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+  		stl_facet facet = stl->facet_start[i];
+		for (int j = 0; j < 3; ++ j) {
+	  		if(stl->neighbors_start[i].neighbor[j] != -1)
+	  			continue;
+			HashEdge edge;
+	  		edge.facet_number = i;
+	  		edge.which_edge = j;
+	  		edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
+	  		hash_table.insert_edge(stl, edge, record_neighbors);
+		}
+	}
 
-  /* Insert all unconnected edges into hash list */
-  stl_initialize_facet_check_nearby(stl);
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    facet = stl->facet_start[i];
-    for(j = 0; j < 3; j++) {
-      if(stl->neighbors_start[i].neighbor[j] != -1) continue;
-      edge.facet_number = i;
-      edge.which_edge = j;
-      stl_load_edge_exact(stl, &edge, &facet.vertex[j],
-                          &facet.vertex[(j + 1) % 3]);
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+		stl_facet facet = stl->facet_start[i];
+		int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] };
+		int first_facet = i;
+		for (int j = 0; j < 3; ++ j) {
+	  		if (stl->neighbors_start[i].neighbor[j] != -1)
+	  			continue;
 
-      insert_hash_edge(stl, edge, stl_record_neighbors);
-    }
-  }
+  			stl_facet new_facet;
+	  		new_facet.vertex[0] = facet.vertex[j];
+	  		new_facet.vertex[1] = facet.vertex[(j + 1) % 3];
+		  	bool direction = neighbors_initial[(j + 2) % 3] == -1;
+  			int facet_num = i;
+		  	int vnot = (j + 2) % 3;
 
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    facet = stl->facet_start[i];
-    neighbors_initial[0] = stl->neighbors_start[i].neighbor[0];
-    neighbors_initial[1] = stl->neighbors_start[i].neighbor[1];
-    neighbors_initial[2] = stl->neighbors_start[i].neighbor[2];
-    first_facet = i;
-    for(j = 0; j < 3; j++) {
-      if(stl->neighbors_start[i].neighbor[j] != -1) continue;
+	  		for (;;) {
+				int pivot_vertex = 0;
+				int next_edge = 0;
+	    		if (vnot > 2) {
+	      			if (direction) {
+	        			pivot_vertex = (vnot + 1) % 3;
+	        			next_edge = vnot % 3;
+	      			} else {
+	        			pivot_vertex = (vnot + 2) % 3;
+	        			next_edge = pivot_vertex;
+	      			}
+	      			direction = ! direction;
+	    		} else {
+	      			if(direction == 0) {
+	        			pivot_vertex = (vnot + 1) % 3;
+	        			next_edge = vnot;
+	      			} else {
+	        			pivot_vertex = (vnot + 2) % 3;
+	        			next_edge = pivot_vertex;
+	      			}
+	    		}
 
-      new_facet.vertex[0] = facet.vertex[j];
-      new_facet.vertex[1] = facet.vertex[(j + 1) % 3];
-      if(neighbors_initial[(j + 2) % 3] == -1) {
-        direction = 1;
-      } else {
-        direction = 0;
-      }
+	    		int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
+	    		if (next_facet == -1) {
+	      			new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3];
+				    stl_add_facet(stl, &new_facet);
+	      			for (int k = 0; k < 3; ++ k) {
+	      				HashEdge edge;
+	        			edge.facet_number = stl->stats.number_of_facets - 1;
+	        			edge.which_edge = k;
+	        			edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]);
+	        			hash_table.insert_edge(stl, edge, record_neighbors);
+	      			}
+	      			break;
+	    		}
 
-      facet_num = i;
-      vnot = (j + 2) % 3;
+	      		vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
+	      		facet_num = next_facet;
 
-      for(;;) {
-        if(vnot > 2) {
-          if(direction == 0) {
-            pivot_vertex = (vnot + 2) % 3;
-            next_edge = pivot_vertex;
-            direction = 1;
-          } else {
-            pivot_vertex = (vnot + 1) % 3;
-            next_edge = vnot % 3;
-            direction = 0;
-          }
-        } else {
-          if(direction == 0) {
-            pivot_vertex = (vnot + 1) % 3;
-            next_edge = vnot;
-          } else {
-            pivot_vertex = (vnot + 2) % 3;
-            next_edge = pivot_vertex;
-          }
-        }
-        next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
-
-        if(next_facet == -1) {
-          new_facet.vertex[2] = stl->facet_start[facet_num].
-                                vertex[vnot % 3];
-          stl_add_facet(stl, &new_facet);
-          for(k = 0; k < 3; k++) {
-            edge.facet_number = stl->stats.number_of_facets - 1;
-            edge.which_edge = k;
-            stl_load_edge_exact(stl, &edge, &new_facet.vertex[k],
-                                &new_facet.vertex[(k + 1) % 3]);
-
-            insert_hash_edge(stl, edge, stl_record_neighbors);
-          }
-          break;
-        } else {
-          vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
-          facet_num = next_facet;
-        }
-
-        if(facet_num == first_facet) {
-          /* back to the beginning */
-          printf("\
-Back to the first facet filling holes: probably a mobius part.\n\
-Try using a smaller tolerance or don't do a nearby check\n");
-          return;
-        }
-      }
-    }
-  }
+	    		if (facet_num == first_facet) {
+	      			// back to the beginning
+	      			printf("Back to the first facet filling holes: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n");
+	      			return;
+	    		}
+	  		}
+		}
+	}
 }
 
 void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 345951121..bd49ad59f 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -74,21 +74,6 @@ struct stl_edge {
 	int        facet_number;
 };
 
-struct stl_hash_edge {
-	// Key of a hash edge: sorted vertices of the edge.
-	uint32_t       key[6];
-	// Compare two keys.
-	bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
-	bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
-	int  hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11  + key[4] / 7 + key[5] / 3)) % M; }
-	// Index of a facet owning this edge.
-	int            facet_number;
-	// Index of this edge inside the facet with an index of facet_number.
-	// If this edge is stored backwards, which_edge is increased by 3.
-	int            which_edge;
-	struct stl_hash_edge  *next;
-};
-
 struct stl_neighbors {
   	stl_neighbors() { reset(); }
   	void reset() {
@@ -99,8 +84,10 @@ struct stl_neighbors {
   		which_vertex_not[1] = -1;
   		which_vertex_not[2] = -1;
   	}
+  	int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
+  	int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
 
-	// Index of a neighbor facet.
+  	// Index of a neighbor facet.
   	int   neighbor[3];
   	// Index of an opposite vertex at the neighbor face.
   	char  which_vertex_not[3];
@@ -151,10 +138,6 @@ struct stl_file {
 	FILE          			   	   *fp;
 	std::vector<stl_facet>     		facet_start;
 	std::vector<stl_neighbors> 		neighbors_start;
-	// Hash table on edges
-	std::vector<stl_hash_edge*> 	heads;
-	stl_hash_edge* 					tail;
-	int           					M;
 	// Indexed face set
 	std::vector<v_indices_struct> 	v_indices;
 	std::vector<stl_vertex>       	v_shared;
@@ -177,7 +160,6 @@ extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
 extern void stl_remove_unconnected_facets(stl_file *stl);
 extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
 extern void stl_write_facet(stl_file *stl, char *label, int facet);
-extern void stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge);
 extern void stl_write_neighbor(stl_file *stl, int facet);
 extern void stl_write_quad_object(stl_file *stl, char *file);
 extern void stl_verify_neighbors(stl_file *stl);
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index 81060c0a3..1e2e1479e 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -257,19 +257,6 @@ stl_write_facet(stl_file *stl, char *label, int facet) {
   stl_write_vertex(stl, facet, 2);
 }
 
-void
-stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) {
-  if (stl->error) return;
-  printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label);
-  if(edge.which_edge < 3) {
-    stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
-    stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
-  } else {
-    stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
-    stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
-  }
-}
-
 void
 stl_write_neighbor(stl_file *stl, int facet) {
   if (stl->error) return;
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 81b7914c3..b7ba21b77 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -50,8 +50,6 @@ void stl_open(stl_file *stl, const char *file)
 void stl_initialize(stl_file *stl)
 {
 	stl->fp = nullptr;
-	stl->tail = nullptr;
-	stl->M = 0;
 	stl->error = 0;
 	stl->facet_start.clear();
 	stl->neighbors_start.clear();
@@ -64,8 +62,6 @@ void stl_initialize(stl_file *stl)
 void stl_close(stl_file *stl)
 {
 	assert(stl->fp == nullptr);
-	assert(stl->heads.empty());
-	assert(stl->tail == nullptr);
 	stl_initialize(stl);
 }
 
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index d8640e575..91293d048 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -459,8 +459,6 @@ bool stl_validate(stl_file *stl)
 	assert(stl->facet_start.size() == stl->stats.number_of_facets);
 	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
 	assert(stl->facet_start.size() == stl->neighbors_start.size());
-	assert(stl->heads.empty());
-	assert(stl->tail  == nullptr);
 	assert(! stl->neighbors_start.empty());
 	assert((stl->v_indices.empty()) == (stl->v_shared.empty()));
 	assert(stl->stats.number_of_facets > 0);
diff --git a/src/libslic3r/Fill/FillRectilinear3.cpp b/src/libslic3r/Fill/FillRectilinear3.cpp
index 8a0b90ead..dab584298 100644
--- a/src/libslic3r/Fill/FillRectilinear3.cpp
+++ b/src/libslic3r/Fill/FillRectilinear3.cpp
@@ -15,7 +15,7 @@
 
 #include "FillRectilinear3.hpp"
 
- #define SLIC3R_DEBUG
+// #define SLIC3R_DEBUG
 
 // Make assert active if SLIC3R_DEBUG
 #ifdef SLIC3R_DEBUG

From a1c38794fbc12c0d88c59ac85230f058d0779b64 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 17:17:36 +0200
Subject: [PATCH 06/22] Refactored admesh to get rid of the error and fp
 members of stl_file.

---
 src/admesh/connect.cpp         |  15 ---
 src/admesh/normals.cpp         | 118 +++++++----------
 src/admesh/shared.cpp          |  33 ++---
 src/admesh/stl.h               |  74 ++++-------
 src/admesh/stl_io.cpp          | 111 ++++++----------
 src/admesh/stlinit.cpp         | 228 ++++++++++++---------------------
 src/admesh/util.cpp            |  39 +-----
 src/libslic3r/Format/PRUS.cpp  |   1 -
 src/libslic3r/Format/STL.cpp   |   3 +-
 src/libslic3r/TriangleMesh.cpp |   5 +-
 src/libslic3r/TriangleMesh.hpp |  14 +-
 xs/xsp/TriangleMesh.xsp        |   1 -
 12 files changed, 213 insertions(+), 429 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 03b13343d..9553e7c4d 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -396,9 +396,6 @@ static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const
 // floats of the first edge matches all six floats of the second edge.
 void stl_check_facets_exact(stl_file *stl)
 {
-	if (stl->error)
-		return;
-
   	stl->stats.connected_edges         = 0;
   	stl->stats.connected_facets_1_edge = 0;
   	stl->stats.connected_facets_2_edge = 0;
@@ -444,9 +441,6 @@ void stl_check_facets_exact(stl_file *stl)
 
 void stl_check_facets_nearby(stl_file *stl, float tolerance)
 {
-	if (stl->error)
-		return;
-
   	if (  (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
        && (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
        && (stl->stats.connected_facets_3_edge == stl->stats.number_of_facets)) {
@@ -476,9 +470,6 @@ void stl_remove_unconnected_facets(stl_file *stl)
 	// A couple of things need to be done here.  One is to remove any completely unconnected facets (0 edges connected) since these are
 	// useless and could be completely wrong.   The second thing that needs to be done is to remove any degenerate facets that were created during
 	// stl_check_facets_nearby().
-	if (stl->error)
-		return;
-
 	auto remove_facet = [stl](int facet_number)
 	{
 		++ stl->stats.facets_removed;
@@ -526,7 +517,6 @@ void stl_remove_unconnected_facets(stl_file *stl)
 	{
 		// Update statistics on face connectivity.
 		auto stl_update_connects_remove_1 = [stl](int facet_num) {
-			assert(! stl->error);
 			//FIXME when decreasing 3_edge, should I increase 2_edge etc?
 			switch ((stl->neighbors_start[facet_num].neighbor[0] == -1) + (stl->neighbors_start[facet_num].neighbor[1] == -1) + (stl->neighbors_start[facet_num].neighbor[2] == -1)) {
 			case 0: // Facet has 3 neighbors
@@ -636,9 +626,6 @@ void stl_remove_unconnected_facets(stl_file *stl)
 
 void stl_fill_holes(stl_file *stl)
 {
-	if (stl->error)
-		return;
-
 	// Insert all unconnected edges into hash list.
 	HashTableEdges hash_table(stl->stats.number_of_facets);
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
@@ -720,8 +707,6 @@ void stl_fill_holes(stl_file *stl)
 
 void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
 {
-	if (stl->error)
-		return;
 	assert(stl->facet_start.size() == stl->stats.number_of_facets);
 	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
 	stl->facet_start.emplace_back(*new_facet);
diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp
index e11f1a3c1..f20d9e68e 100644
--- a/src/admesh/normals.cpp
+++ b/src/admesh/normals.cpp
@@ -29,61 +29,43 @@
 
 static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
 
-static void
-stl_reverse_facet(stl_file *stl, int facet_num) {
-  stl_vertex tmp_vertex;
-  /*  int tmp_neighbor;*/
-  int neighbor[3];
-  int vnot[3];
+static void reverse_facet(stl_file *stl, int facet_num)
+{
+	stl->stats.facets_reversed += 1;
 
-  stl->stats.facets_reversed += 1;
+	int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] };
+	int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] };
 
-  neighbor[0] = stl->neighbors_start[facet_num].neighbor[0];
-  neighbor[1] = stl->neighbors_start[facet_num].neighbor[1];
-  neighbor[2] = stl->neighbors_start[facet_num].neighbor[2];
-  vnot[0] = stl->neighbors_start[facet_num].which_vertex_not[0];
-  vnot[1] = stl->neighbors_start[facet_num].which_vertex_not[1];
-  vnot[2] = stl->neighbors_start[facet_num].which_vertex_not[2];
+	// reverse the facet
+	stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0];
+	stl->facet_start[facet_num].vertex[0] =
+	stl->facet_start[facet_num].vertex[1];
+	stl->facet_start[facet_num].vertex[1] = tmp_vertex;
 
-  /* reverse the facet */
-  tmp_vertex = stl->facet_start[facet_num].vertex[0];
-  stl->facet_start[facet_num].vertex[0] =
-    stl->facet_start[facet_num].vertex[1];
-  stl->facet_start[facet_num].vertex[1] = tmp_vertex;
+	// fix the vnots of the neighboring facets
+	if (neighbor[0] != -1)
+		stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
+	if (neighbor[1] != -1)
+		stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
+	if (neighbor[2] != -1)
+		stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
 
-  /* fix the vnots of the neighboring facets */
-  if(neighbor[0] != -1)
-    stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] =
-      (stl->neighbors_start[neighbor[0]].
-       which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
-  if(neighbor[1] != -1)
-    stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] =
-      (stl->neighbors_start[neighbor[1]].
-       which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
-  if(neighbor[2] != -1)
-    stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] =
-      (stl->neighbors_start[neighbor[2]].
-       which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
+	// swap the neighbors of the facet that is being reversed
+	stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
+	stl->neighbors_start[facet_num].neighbor[2] = neighbor[1];
 
-  /* swap the neighbors of the facet that is being reversed */
-  stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
-  stl->neighbors_start[facet_num].neighbor[2] = neighbor[1];
+	// swap the vnots of the facet that is being reversed 
+	stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
+	stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
 
-  /* swap the vnots of the facet that is being reversed */
-  stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
-  stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
-
-  /* reverse the values of the vnots of the facet that is being reversed */
-  stl->neighbors_start[facet_num].which_vertex_not[0] =
-    (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
-  stl->neighbors_start[facet_num].which_vertex_not[1] =
-    (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
-  stl->neighbors_start[facet_num].which_vertex_not[2] =
-    (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
+	// reverse the values of the vnots of the facet that is being reversed
+	stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
+	stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
+	stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
 }
 
-void
-stl_fix_normal_directions(stl_file *stl) {
+void stl_fix_normal_directions(stl_file *stl)
+{
   /*  int edge_num;*/
   /*  int vnot;*/
   int checked = 0;
@@ -104,8 +86,6 @@ stl_fix_normal_directions(stl_file *stl) {
   int id;
   int force_exit = 0;
 
-  if (stl->error) return;
-
   // this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
   if (stl->stats.number_of_facets == 0) return;
 
@@ -125,7 +105,7 @@ stl_fix_normal_directions(stl_file *stl) {
      Arbitrarily starts at face 0.  If this one is wrong, we're screwed.  Thankfully, the chances
      of it being wrong randomly are low if most of the triangles are right: */
   if (stl_check_normal_vector(stl, 0, 0) == 2) {
-      stl_reverse_facet(stl, 0);
+      reverse_facet(stl, 0);
       reversed_ids[reversed_count++] = 0;
   }
 
@@ -144,12 +124,12 @@ stl_fix_normal_directions(stl_file *stl) {
             if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
                 /* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */
                 for (id = reversed_count - 1; id >= 0; --id) {
-                    stl_reverse_facet(stl, reversed_ids[id]);
+                    reverse_facet(stl, reversed_ids[id]);
                 }
                 force_exit = 1;
                 break;
             } else {
-                stl_reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
+                reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
                 reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j];
             }
         }
@@ -193,7 +173,7 @@ stl_fix_normal_directions(stl_file *stl) {
             /* This is the first facet of the next part. */
             facet_num = i;
             if(stl_check_normal_vector(stl, i, 0) == 2) {
-                stl_reverse_facet(stl, i);
+                reverse_facet(stl, i);
                 reversed_ids[reversed_count++] = i;
             }
 
@@ -209,7 +189,8 @@ stl_fix_normal_directions(stl_file *stl) {
   delete tail;
 }
 
-static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) {
+static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
+{
   /* Returns 0 if the normal is within tolerance */
   /* Returns 1 if the normal is not within tolerance, but direction is OK */
   /* Returns 2 if the normal is not within tolerance and backwards */
@@ -260,26 +241,19 @@ static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_
   return 4;
 }
 
-void stl_fix_normal_values(stl_file *stl) {
-  int i;
-
-  if (stl->error) return;
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    stl_check_normal_vector(stl, i, 1);
-  }
+void stl_fix_normal_values(stl_file *stl)
+{
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	stl_check_normal_vector(stl, i, 1);
 }
 
 void stl_reverse_all_facets(stl_file *stl)
 {
-  if (stl->error)
-  	return;
-
-  stl_normal normal;
-  for(int i = 0; i < stl->stats.number_of_facets; i++) {
-    stl_reverse_facet(stl, i);
-    stl_calculate_normal(normal, &stl->facet_start[i]);
-    stl_normalize_vector(normal);
-    stl->facet_start[i].normal = normal;
-  }
+	stl_normal normal;
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+    	reverse_facet(stl, i);
+    	stl_calculate_normal(normal, &stl->facet_start[i]);
+    	stl_normalize_vector(normal);
+    	stl->facet_start[i].normal = normal;
+  	}
 }
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index bc264ee96..a757d8816 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -38,15 +38,10 @@ void stl_invalidate_shared_vertices(stl_file *stl)
 
 void stl_generate_shared_vertices(stl_file *stl)
 {
-	if (stl->error)
-		return;
-
-	/* make sure this function is idempotent and does not leak memory */
-	stl_invalidate_shared_vertices(stl);
-
 	// 3 indices to vertex per face
 	stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct());
 	// Shared vertices (3D coordinates)
+	stl->v_shared.clear();
 	stl->v_shared.reserve(stl->stats.number_of_facets / 2);
 	stl->stats.shared_vertices = 0;
 
@@ -139,11 +134,8 @@ void stl_generate_shared_vertices(stl_file *stl)
 	}
 }
 
-void stl_write_off(stl_file *stl, const char *file)
+bool stl_write_off(stl_file *stl, const char *file)
 {
-	if (stl->error)
-		return;
-
 	/* Open the file */
 	FILE *fp = boost::nowide::fopen(file, "w");
 	if (fp == nullptr) {
@@ -151,8 +143,7 @@ void stl_write_off(stl_file *stl, const char *file)
 		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
 		perror(error_msg);
 		free(error_msg);
-		stl->error = 1;
-		return;
+		return false;
 	}
 
 	fprintf(fp, "OFF\n");
@@ -162,13 +153,11 @@ void stl_write_off(stl_file *stl, const char *file)
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
 		fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
 	fclose(fp);
+	return true;
 }
 
-void stl_write_vrml(stl_file *stl, const char *file)
+bool stl_write_vrml(stl_file *stl, const char *file)
 {
-  	if (stl->error) 
-  		return;
-
 	/* Open the file */
   	FILE *fp = boost::nowide::fopen(file, "w");
 	if (fp == nullptr) {
@@ -176,8 +165,7 @@ void stl_write_vrml(stl_file *stl, const char *file)
 		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
 		perror(error_msg);
 		free(error_msg);
-		stl->error = 1;
-		return;
+		return false;
 	}
 
 	fprintf(fp, "#VRML V1.0 ascii\n\n");
@@ -210,12 +198,11 @@ void stl_write_vrml(stl_file *stl, const char *file)
 	fprintf(fp, "\t}\n");
 	fprintf(fp, "}\n");
 	fclose(fp);
+	return true;
 }
 
-void stl_write_obj (stl_file *stl, const char *file)
+bool stl_write_obj(stl_file *stl, const char *file)
 {
-	if (stl->error)
-		return;
 
   	FILE *fp = boost::nowide::fopen(file, "w");
   	if (fp == nullptr) {
@@ -223,8 +210,7 @@ void stl_write_obj (stl_file *stl, const char *file)
     	sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
     	perror(error_msg);
     	free(error_msg);
-    	stl->error = 1;
-    	return;
+    	return false;
   	}
 
 	for (int i = 0; i < stl->stats.shared_vertices; ++ i)
@@ -232,4 +218,5 @@ void stl_write_obj (stl_file *stl, const char *file)
   	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
     	fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
   	fclose(fp);
+  	return true;
 }
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index bd49ad59f..51153ede7 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -127,15 +127,9 @@ struct stl_stats {
 	int           normals_fixed;
 	int           number_of_parts;
 	int           shared_vertices;
-
-	// hash table statistics
-	int           malloced;
-	int           freed;
-	int           collisions;
 };
 
 struct stl_file {
-	FILE          			   	   *fp;
 	std::vector<stl_facet>     		facet_start;
 	std::vector<stl_neighbors> 		neighbors_start;
 	// Indexed face set
@@ -143,17 +137,15 @@ struct stl_file {
 	std::vector<stl_vertex>       	v_shared;
 	// Statistics
 	stl_stats     					stats;
-	char          					error;
 };
 
-extern void stl_open(stl_file *stl, const char *file);
-extern void stl_close(stl_file *stl);
+extern bool stl_open(stl_file *stl, const char *file);
 extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
-extern void stl_print_neighbors(stl_file *stl, char *file);
+extern bool stl_print_neighbors(stl_file *stl, char *file);
 extern void stl_put_little_int(FILE *fp, int value_in);
 extern void stl_put_little_float(FILE *fp, float value_in);
-extern void stl_write_ascii(stl_file *stl, const char *file, const char *label);
-extern void stl_write_binary(stl_file *stl, const char *file, const char *label);
+extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label);
+extern bool stl_write_binary(stl_file *stl, const char *file, const char *label);
 extern void stl_write_binary_block(stl_file *stl, FILE *fp);
 extern void stl_check_facets_exact(stl_file *stl);
 extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
@@ -161,7 +153,7 @@ extern void stl_remove_unconnected_facets(stl_file *stl);
 extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
 extern void stl_write_facet(stl_file *stl, char *label, int facet);
 extern void stl_write_neighbor(stl_file *stl, int facet);
-extern void stl_write_quad_object(stl_file *stl, char *file);
+extern bool stl_write_quad_object(stl_file *stl, char *file);
 extern void stl_verify_neighbors(stl_file *stl);
 extern void stl_fill_holes(stl_file *stl);
 extern void stl_fix_normal_directions(stl_file *stl);
@@ -183,34 +175,28 @@ extern void stl_get_size(stl_file *stl);
 template<typename T>
 extern void stl_transform(stl_file *stl, T *trafo3x4)
 {
-  if (stl->error)
-    return;
+	for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
+		stl_facet &face = stl->facet_start[i_face];
+		for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
+			stl_vertex &v_dst = face.vertex[i_vertex];
+			stl_vertex  v_src = v_dst;
+			v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2) + trafo3x4[3]);
+			v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2) + trafo3x4[7]);
+			v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
+		}
+		stl_vertex &v_dst = face.normal;
+		stl_vertex  v_src = v_dst;
+		v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2));
+		v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2));
+		v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
+	}
 
-  for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
-    stl_facet &face = stl->facet_start[i_face];
-    for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
-      stl_vertex &v_dst = face.vertex[i_vertex];
-      stl_vertex  v_src = v_dst;
-      v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2) + trafo3x4[3]);
-      v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2) + trafo3x4[7]);
-      v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
-    }
-    stl_vertex &v_dst = face.normal;
-    stl_vertex  v_src = v_dst;
-    v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2));
-    v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2));
-    v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
-  }
-
-  stl_get_size(stl);
+	stl_get_size(stl);
 }
 
 template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
 {
-	if (stl->error)
-		return;
-
 	const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
 	for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
 		stl_facet &f = stl->facet_start[i];
@@ -225,9 +211,6 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
 template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
 {
-	if (stl->error)
-		return;
-
 	for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
 		stl_facet &f = stl->facet_start[i];
 		for (size_t j = 0; j < 3; ++j)
@@ -238,13 +221,12 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
 	stl_get_size(stl);
 }
 
-extern void stl_open_merge(stl_file *stl, char *file);
 extern void stl_invalidate_shared_vertices(stl_file *stl);
 extern void stl_generate_shared_vertices(stl_file *stl);
-extern void stl_write_obj(stl_file *stl, const char *file);
-extern void stl_write_off(stl_file *stl, const char *file);
-extern void stl_write_dxf(stl_file *stl, const char *file, char *label);
-extern void stl_write_vrml(stl_file *stl, const char *file);
+extern bool stl_write_obj(stl_file *stl, const char *file);
+extern bool stl_write_off(stl_file *stl, const char *file);
+extern bool stl_write_dxf(stl_file *stl, const char *file, char *label);
+extern bool stl_write_vrml(stl_file *stl, const char *file);
 inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
   normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
 }
@@ -263,17 +245,13 @@ extern void stl_calculate_volume(stl_file *stl);
 
 extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
 
-extern void stl_initialize(stl_file *stl);
-extern void stl_count_facets(stl_file *stl, const char *file);
+extern void stl_reset(stl_file *stl);
 extern void stl_allocate(stl_file *stl);
 extern void stl_read(stl_file *stl, int first_facet, bool first);
 extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
 extern void stl_reallocate(stl_file *stl);
 extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
 
-extern void stl_clear_error(stl_file *stl);
-extern int stl_get_error(stl_file *stl);
-extern void stl_exit_on_error(stl_file *stl);
 // Validate the mesh, assert on error.
 extern bool stl_validate(stl_file *stl);
 
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index 1e2e1479e..8f809d379 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -33,10 +33,8 @@
 #define SEEK_END 2
 #endif
 
-void
-stl_stats_out(stl_file *stl, FILE *file, char *input_file) {
-  if (stl->error) return;
-
+void stl_stats_out(stl_file *stl, FILE *file, char *input_file)
+{
   /* this is here for Slic3r, without our config.h
      it won't use this part of the code anyway */
 #ifndef VERSION
@@ -107,12 +105,10 @@ Backwards edges       : %5d\n", stl->stats.backwards_edges);
 Normals fixed         : %5d\n", stl->stats.normals_fixed);
 }
 
-void
-stl_write_ascii(stl_file *stl, const char *file, const char *label) {
+bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
+{
   char      *error_msg;
 
-  if (stl->error) return;
-
   /* Open the file */
   FILE *fp = boost::nowide::fopen(file, "w");
   if(fp == NULL) {
@@ -122,8 +118,7 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return false;
   }
 
   fprintf(fp, "solid  %s\n", label);
@@ -149,15 +144,14 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
   fprintf(fp, "endsolid  %s\n", label);
 
   fclose(fp);
+  return true;
 }
 
-void
-stl_print_neighbors(stl_file *stl, char *file) {
+bool stl_print_neighbors(stl_file *stl, char *file)
+{
   FILE *fp;
   char *error_msg;
 
-  if (stl->error) return;
-
   /* Open the file */
   fp = boost::nowide::fopen(file, "w");
   if(fp == NULL) {
@@ -167,8 +161,7 @@ stl_print_neighbors(stl_file *stl, char *file) {
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return false;
   }
 
   for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
@@ -182,6 +175,7 @@ stl_print_neighbors(stl_file *stl, char *file) {
             (int)stl->neighbors_start[i].which_vertex_not[2]);
   }
   fclose(fp);
+  return true;
 }
 
 #ifndef BOOST_LITTLE_ENDIAN
@@ -195,13 +189,11 @@ void stl_internal_reverse_quads(char *buf, size_t cnt)
 }
 #endif
 
-void
-stl_write_binary(stl_file *stl, const char *file, const char *label) {
+bool stl_write_binary(stl_file *stl, const char *file, const char *label)
+{
   FILE      *fp;
   char      *error_msg;
 
-  if (stl->error) return;
-
   /* Open the file */
   fp = boost::nowide::fopen(file, "wb");
   if(fp == NULL) {
@@ -211,8 +203,7 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) {
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return false;
   }
 
   fprintf(fp, "%s", label);
@@ -237,40 +228,38 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) {
   }
 #endif /* BOOST_LITTLE_ENDIAN */
   fclose(fp);
+  return true;
 }
 
-void
-stl_write_vertex(stl_file *stl, int facet, int vertex) {
-  if (stl->error) return;
-  printf("  vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
+void stl_write_vertex(stl_file *stl, int facet, int vertex)
+{
+  	printf("  vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
          stl->facet_start[facet].vertex[vertex](0),
          stl->facet_start[facet].vertex[vertex](1),
          stl->facet_start[facet].vertex[vertex](2));
 }
 
-void
-stl_write_facet(stl_file *stl, char *label, int facet) {
-  if (stl->error) return;
-  printf("facet (%d)/ %s\n", facet, label);
-  stl_write_vertex(stl, facet, 0);
-  stl_write_vertex(stl, facet, 1);
-  stl_write_vertex(stl, facet, 2);
+void stl_write_facet(stl_file *stl, char *label, int facet)
+{
+	printf("facet (%d)/ %s\n", facet, label);
+	stl_write_vertex(stl, facet, 0);
+	stl_write_vertex(stl, facet, 1);
+	stl_write_vertex(stl, facet, 2);
 }
 
-void
-stl_write_neighbor(stl_file *stl, int facet) {
-  if (stl->error) return;
-  printf("Neighbors %d: %d, %d, %d ;  %d, %d, %d\n", facet,
-         stl->neighbors_start[facet].neighbor[0],
-         stl->neighbors_start[facet].neighbor[1],
-         stl->neighbors_start[facet].neighbor[2],
-         stl->neighbors_start[facet].which_vertex_not[0],
-         stl->neighbors_start[facet].which_vertex_not[1],
-         stl->neighbors_start[facet].which_vertex_not[2]);
+void stl_write_neighbor(stl_file *stl, int facet)
+{
+	printf("Neighbors %d: %d, %d, %d ;  %d, %d, %d\n", facet,
+		stl->neighbors_start[facet].neighbor[0],
+		stl->neighbors_start[facet].neighbor[1],
+		stl->neighbors_start[facet].neighbor[2],
+		stl->neighbors_start[facet].which_vertex_not[0],
+		stl->neighbors_start[facet].which_vertex_not[1],
+		stl->neighbors_start[facet].which_vertex_not[2]);
 }
 
-void
-stl_write_quad_object(stl_file *stl, char *file) {
+bool stl_write_quad_object(stl_file *stl, char *file)
+{
   FILE      *fp;
   char      *error_msg;
   stl_vertex connect_color = stl_vertex::Zero();
@@ -279,8 +268,6 @@ stl_write_quad_object(stl_file *stl, char *file) {
   stl_vertex uncon_3_color = stl_vertex::Zero();
   stl_vertex color;
 
-  if (stl->error) return;
-
   /* Open the file */
   fp = boost::nowide::fopen(file, "w");
   if(fp == NULL) {
@@ -290,8 +277,7 @@ stl_write_quad_object(stl_file *stl, char *file) {
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return false;
   }
 
   fprintf(fp, "CQUAD\n");
@@ -326,15 +312,14 @@ stl_write_quad_object(stl_file *stl, char *file) {
             stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
   }
   fclose(fp);
+  return true;
 }
 
-void stl_write_dxf(stl_file *stl, const char *file, char *label) 
+bool stl_write_dxf(stl_file *stl, const char *file, char *label) 
 {
   FILE      *fp;
   char      *error_msg;
 
-  if (stl->error) return;
-
   /* Open the file */
   fp = boost::nowide::fopen(file, "w");
   if(fp == NULL) {
@@ -344,8 +329,7 @@ void stl_write_dxf(stl_file *stl, const char *file, char *label)
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return false;
   }
 
   fprintf(fp, "999\n%s\n", label);
@@ -375,22 +359,5 @@ void stl_write_dxf(stl_file *stl, const char *file, char *label)
   fprintf(fp, "0\nENDSEC\n0\nEOF\n");
 
   fclose(fp);
-}
-
-void
-stl_clear_error(stl_file *stl) {
-  stl->error = 0;
-}
-
-void
-stl_exit_on_error(stl_file *stl) {
-  if (!stl->error) return;
-  stl->error = 0;
-  stl_close(stl);
-  exit(1);
-}
-
-int
-stl_get_error(stl_file *stl) {
-  return stl->error;
+  return true;
 }
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index b7ba21b77..088842d51 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -35,42 +35,8 @@
 #error "SEEK_SET not defined"
 #endif
 
-void stl_open(stl_file *stl, const char *file)
+static FILE* stl_open_count_facets(stl_file *stl, const char *file) 
 {
-	stl_initialize(stl);
-	stl_count_facets(stl, file);
-	stl_allocate(stl);
-	stl_read(stl, 0, true);
-	if (stl->fp != nullptr) {
-	  	fclose(stl->fp);
-	  	stl->fp = nullptr;
-	}
-}
-
-void stl_initialize(stl_file *stl)
-{
-	stl->fp = nullptr;
-	stl->error = 0;
-	stl->facet_start.clear();
-	stl->neighbors_start.clear();
-	stl->v_indices.clear();
-	stl->v_shared.clear();
-  	memset(&stl->stats, 0, sizeof(stl_stats));
-  	stl->stats.volume = -1.0;
-}
-
-void stl_close(stl_file *stl)
-{
-	assert(stl->fp == nullptr);
-	stl_initialize(stl);
-}
-
-#ifndef BOOST_LITTLE_ENDIAN
-extern void stl_internal_reverse_quads(char *buf, size_t cnt);
-#endif /* BOOST_LITTLE_ENDIAN */
-
-void
-stl_count_facets(stl_file *stl, const char *file) {
   long           file_size;
   uint32_t       header_num_facets;
   uint32_t       num_facets;
@@ -80,30 +46,27 @@ stl_count_facets(stl_file *stl, const char *file) {
   int            num_lines = 1;
   char           *error_msg;
 
-  if (stl->error) return;
-
   /* Open the file in binary mode first */
-  stl->fp = boost::nowide::fopen(file, "rb");
-  if(stl->fp == NULL) {
+  FILE *fp = boost::nowide::fopen(file, "rb");
+  if (fp == nullptr) {
     error_msg = (char*)
                 malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
     sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
             file);
     perror(error_msg);
     free(error_msg);
-    stl->error = 1;
-    return;
+    return nullptr;
   }
   /* Find size of file */
-  fseek(stl->fp, 0, SEEK_END);
-  file_size = ftell(stl->fp);
+  fseek(fp, 0, SEEK_END);
+  file_size = ftell(fp);
 
   /* Check for binary or ASCII file */
-  fseek(stl->fp, HEADER_SIZE, SEEK_SET);
-  if (!fread(chtest, sizeof(chtest), 1, stl->fp)) {
+  fseek(fp, HEADER_SIZE, SEEK_SET);
+  if (!fread(chtest, sizeof(chtest), 1, fp)) {
     perror("The input is an empty file");
-    stl->error = 1;
-    return;
+    fclose(fp);
+    return nullptr;
   }
   stl->stats.type = ascii;
   for(s = 0; s < sizeof(chtest); s++) {
@@ -112,7 +75,7 @@ stl_count_facets(stl_file *stl, const char *file) {
       break;
     }
   }
-  rewind(stl->fp);
+  rewind(fp);
 
   /* Get the header and the number of facets in the .STL file */
   /* If the .STL file is binary, then do the following */
@@ -121,18 +84,18 @@ stl_count_facets(stl_file *stl, const char *file) {
     if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
         || (file_size < STL_MIN_FILE_SIZE)) {
       fprintf(stderr, "The file %s has the wrong size.\n", file);
-      stl->error = 1;
-      return;
+      fclose(fp);
+      return nullptr;
     }
     num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
 
     /* Read the header */
-    if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) {
+    if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) {
       stl->stats.header[80] = '\0';
     }
 
     /* Read the int following the header.  This should contain # of facets */
-    bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp) != 0;
+    bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
 #ifndef BOOST_LITTLE_ENDIAN
     // Convert from little endian to big endian.
     stl_internal_reverse_quads((char*)&header_num_facets, 4);
@@ -147,23 +110,23 @@ stl_count_facets(stl_file *stl, const char *file) {
     /* Reopen the file in text mode (for getting correct newlines on Windows) */
     // fix to silence a warning about unused return value.
     // obviously if it fails we have problems....
-    stl->fp = boost::nowide::freopen(file, "r", stl->fp);
+    fp = boost::nowide::freopen(file, "r", fp);
 
     // do another null check to be safe
-    if(stl->fp == NULL) {
+    if(fp == nullptr) {
       error_msg = (char*)
         malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
       sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
           file);
       perror(error_msg);
       free(error_msg);
-      stl->error = 1;
-      return;
+      fclose(fp);
+      return nullptr;
     }
     
     /* Find the number of facets */
     char linebuf[100];
-    while (fgets(linebuf, 100, stl->fp) != NULL) {
+    while (fgets(linebuf, 100, fp) != nullptr) {
         /* don't count short lines */
         if (strlen(linebuf) <= 4) continue;
         
@@ -173,11 +136,11 @@ stl_count_facets(stl_file *stl, const char *file) {
         ++num_lines;
     }
     
-    rewind(stl->fp);
+    rewind(fp);
     
     /* Get the header */
     for(i = 0;
-        (i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++);
+        (i < 80) && (stl->stats.header[i] = getc(fp)) != '\n'; i++);
     stl->stats.header[i] = '\0'; /* Lose the '\n' */
     stl->stats.header[80] = '\0';
 
@@ -185,84 +148,20 @@ stl_count_facets(stl_file *stl, const char *file) {
   }
   stl->stats.number_of_facets += num_facets;
   stl->stats.original_num_facets = stl->stats.number_of_facets;
+  return fp;
 }
 
-void stl_allocate(stl_file *stl) 
-{
-	if (stl->error) 
-		return;
-  	//  Allocate memory for the entire .STL file.
-  	stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
-  	// Allocate memory for the neighbors list.
-  	stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors());
-}
-
-void
-stl_open_merge(stl_file *stl, char *file_to_merge) {
-  int num_facets_so_far;
-  stl_type origStlType;
-  FILE *origFp;
-  stl_file stl_to_merge;
-
-  if (stl->error) return;
-
-  /* Record how many facets we have so far from the first file.  We will start putting
-     facets in the next position.  Since we're 0-indexed, it'l be the same position. */
-  num_facets_so_far = stl->stats.number_of_facets;
-
-  /* Record the file type we started with: */
-  origStlType=stl->stats.type;
-  /* Record the file pointer too: */
-  origFp=stl->fp;
-
-  /* Initialize the sturucture with zero stats, header info and sizes: */
-  stl_initialize(&stl_to_merge);
-  stl_count_facets(&stl_to_merge, file_to_merge);
-
-  /* Copy what we need to into stl so that we can read the file_to_merge directly into it
-     using stl_read:  Save the rest of the valuable info: */
-  stl->stats.type=stl_to_merge.stats.type;
-  stl->fp=stl_to_merge.fp;
-
-  /* Add the number of facets we already have in stl with what we we found in stl_to_merge but
-     haven't read yet. */
-  stl->stats.number_of_facets=num_facets_so_far+stl_to_merge.stats.number_of_facets;
-
-  /* Allocate enough room for stl->stats.number_of_facets facets and neighbors: */
-  stl_reallocate(stl);
-
-  /* Read the file to merge directly into stl, adding it to what we have already.
-     Start at num_facets_so_far, the index to the first unused facet.  Also say
-     that this isn't our first time so we should augment stats like min and max
-     instead of erasing them. */
-  stl_read(stl, num_facets_so_far, false);
-
-  /* Restore the stl information we overwrote (for stl_read) so that it still accurately
-     reflects the subject part: */
-  stl->stats.type=origStlType;
-  stl->fp=origFp;
-}
-
-void stl_reallocate(stl_file *stl) 
-{
-  	if (stl->error) 
-  		return;
-	stl->facet_start.resize(stl->stats.number_of_facets);
-	stl->neighbors_start.resize(stl->stats.number_of_facets);
-}
-
-/* Reads the contents of the file pointed to by stl->fp into the stl structure,
+/* Reads the contents of the file pointed to by fp into the stl structure,
    starting at facet first_facet.  The second argument says if it's our first
    time running this for the stl and therefore we should reset our max and min stats. */
-void stl_read(stl_file *stl, int first_facet, bool first) {
+static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
+{
   stl_facet facet;
 
-  if (stl->error) return;
-
   if(stl->stats.type == binary) {
-    fseek(stl->fp, HEADER_SIZE, SEEK_SET);
+    fseek(fp, HEADER_SIZE, SEEK_SET);
   } else {
-    rewind(stl->fp);
+    rewind(fp);
   }
 
   char normal_buf[3][32];
@@ -271,10 +170,8 @@ void stl_read(stl_file *stl, int first_facet, bool first) {
       /* Read a single facet from a binary .STL file */
     {
       /* we assume little-endian architecture! */
-      if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) {
-        stl->error = 1;
-        return;
-      }
+      if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
+      	return false;
 #ifndef BOOST_LITTLE_ENDIAN
       // Convert the loaded little endian data to big endian.
       stl_internal_reverse_quads((char*)&facet, 48);
@@ -284,27 +181,26 @@ void stl_read(stl_file *stl, int first_facet, bool first) {
     {
       // skip solid/endsolid
       // (in this order, otherwise it won't work when they are paired in the middle of a file)
-      fscanf(stl->fp, "endsolid%*[^\n]\n");
-      fscanf(stl->fp, "solid%*[^\n]\n");  // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
+      fscanf(fp, "endsolid%*[^\n]\n");
+      fscanf(fp, "solid%*[^\n]\n");  // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
       // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
-      int res_normal     = fscanf(stl->fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
+      int res_normal     = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
       assert(res_normal == 3);
-      int res_outer_loop = fscanf(stl->fp, " outer loop");
+      int res_outer_loop = fscanf(fp, " outer loop");
       assert(res_outer_loop == 0);
-      int res_vertex1    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
+      int res_vertex1    = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
       assert(res_vertex1 == 3);
-      int res_vertex2    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
+      int res_vertex2    = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
       assert(res_vertex2 == 3);
-      int res_vertex3    = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
+      int res_vertex3    = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
       assert(res_vertex3 == 3);
-      int res_endloop    = fscanf(stl->fp, " endloop");
+      int res_endloop    = fscanf(fp, " endloop");
       assert(res_endloop == 0);
       // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
-      int res_endfacet   = fscanf(stl->fp, " endfacet ");
+      int res_endfacet   = fscanf(fp, " endfacet ");
       if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
         perror("Something is syntactically very wrong with this ASCII STL!");
-        stl->error = 1;
-        return;
+        return false;
       }
 
       // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
@@ -338,13 +234,51 @@ void stl_read(stl_file *stl, int first_facet, bool first) {
   }
   stl->stats.size = stl->stats.max - stl->stats.min;
   stl->stats.bounding_diameter = stl->stats.size.norm();
+  return true;
+}
+
+bool stl_open(stl_file *stl, const char *file)
+{
+	stl_reset(stl);
+	FILE *fp = stl_open_count_facets(stl, file);
+	if (fp == nullptr)
+		return false;
+	stl_allocate(stl);
+	bool result = stl_read(stl, fp, 0, true);
+  	fclose(fp);
+  	return result;
+}
+
+void stl_reset(stl_file *stl)
+{
+	stl->facet_start.clear();
+	stl->neighbors_start.clear();
+	stl->v_indices.clear();
+	stl->v_shared.clear();
+  	memset(&stl->stats, 0, sizeof(stl_stats));
+  	stl->stats.volume = -1.0;
+}
+
+#ifndef BOOST_LITTLE_ENDIAN
+extern void stl_internal_reverse_quads(char *buf, size_t cnt);
+#endif /* BOOST_LITTLE_ENDIAN */
+
+void stl_allocate(stl_file *stl) 
+{
+  	//  Allocate memory for the entire .STL file.
+  	stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
+  	// Allocate memory for the neighbors list.
+  	stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors());
+}
+
+void stl_reallocate(stl_file *stl) 
+{
+	stl->facet_start.resize(stl->stats.number_of_facets);
+	stl->neighbors_start.resize(stl->stats.number_of_facets);
 }
 
 void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
 {
-  if (stl->error)
-  	return;
-
   // While we are going through all of the facets, let's find the
   // maximum and minimum values for x, y, and z
 
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 91293d048..db05cbc09 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -34,9 +34,6 @@ static float get_volume(stl_file *stl);
 
 void stl_verify_neighbors(stl_file *stl)
 {
-	if (stl->error)
-		return;
-
 	stl->stats.backwards_edges = 0;
 
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
@@ -69,9 +66,6 @@ void stl_verify_neighbors(stl_file *stl)
 
 void stl_translate(stl_file *stl, float x, float y, float z)
 {
-  if (stl->error)
-  	return;
-
   stl_vertex new_min(x, y, z);
   stl_vertex shift = new_min - stl->stats.min;
   for (int i = 0; i < stl->stats.number_of_facets; ++ i)
@@ -85,9 +79,6 @@ void stl_translate(stl_file *stl, float x, float y, float z)
 /* Translates the stl by x,y,z, relatively from wherever it is currently */
 void stl_translate_relative(stl_file *stl, float x, float y, float z)
 {
-  if (stl->error)
-  	return;
-
   stl_vertex shift(x, y, z);
   for (int i = 0; i < stl->stats.number_of_facets; ++ i)
     for (int j = 0; j < 3; ++ j)
@@ -99,9 +90,6 @@ void stl_translate_relative(stl_file *stl, float x, float y, float z)
 
 void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
 {
-  if (stl->error)
-  	return;
-
   // Scale extents.
   auto s = versor.array();
   stl->stats.min.array() *= s;
@@ -120,9 +108,6 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
 
 static void calculate_normals(stl_file *stl) 
 {
-  if (stl->error)
-  	return;
-
   stl_normal normal;
   for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
     stl_calculate_normal(normal, &stl->facet_start[i]);
@@ -139,8 +124,6 @@ stl_rotate_x(stl_file *stl, float angle) {
   double c = cos(radian_angle);
   double s = sin(radian_angle);
 
-  if (stl->error) return;
-
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
       stl_rotate(&stl->facet_start[i].vertex[j](1),
@@ -159,8 +142,6 @@ stl_rotate_y(stl_file *stl, float angle) {
   double c = cos(radian_angle);
   double s = sin(radian_angle);
 
-  if (stl->error) return;
-
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
       stl_rotate(&stl->facet_start[i].vertex[j](2),
@@ -179,8 +160,6 @@ stl_rotate_z(stl_file *stl, float angle) {
   double c = cos(radian_angle);
   double s = sin(radian_angle);
 
-  if (stl->error) return;
-
   for(i = 0; i < stl->stats.number_of_facets; i++) {
     for(j = 0; j < 3; j++) {
       stl_rotate(&stl->facet_start[i].vertex[j](0),
@@ -203,7 +182,7 @@ stl_rotate(float *x, float *y, const double c, const double s) {
 
 void stl_get_size(stl_file *stl)
 {
-  if (stl->error || stl->stats.number_of_facets == 0)
+  if (stl->stats.number_of_facets == 0)
   	return;
   stl->stats.min = stl->facet_start[0].vertex[0];
   stl->stats.max = stl->stats.min;
@@ -220,9 +199,6 @@ void stl_get_size(stl_file *stl)
 
 void stl_mirror_xy(stl_file *stl)
 {
-  if (stl->error) 
-  	return;
-
   for(int i = 0; i < stl->stats.number_of_facets; i++) {
     for(int j = 0; j < 3; j++) {
       stl->facet_start[i].vertex[j](2) *= -1.0;
@@ -239,8 +215,6 @@ void stl_mirror_xy(stl_file *stl)
 
 void stl_mirror_yz(stl_file *stl)
 {
-  if (stl->error) return;
-
   for (int i = 0; i < stl->stats.number_of_facets; i++) {
     for (int j = 0; j < 3; j++) {
       stl->facet_start[i].vertex[j](0) *= -1.0;
@@ -257,9 +231,6 @@ void stl_mirror_yz(stl_file *stl)
 
 void stl_mirror_xz(stl_file *stl)
 {
-	if (stl->error)
-		return;
-
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
 		for (int j = 0; j < 3; ++ j)
 			stl->facet_start[i].vertex[j](1) *= -1.0;
@@ -274,9 +245,6 @@ void stl_mirror_xz(stl_file *stl)
 
 static float get_volume(stl_file *stl)
 {
-  if (stl->error)
-  	return 0;
-
   // Choose a point, any point as the reference.
   stl_vertex p0 = stl->facet_start[0].vertex[0];
   float volume = 0.f;
@@ -291,7 +259,6 @@ static float get_volume(stl_file *stl)
 
 void stl_calculate_volume(stl_file *stl)
 {
-  if (stl->error) return;
   stl->stats.volume = get_volume(stl);
   if(stl->stats.volume < 0.0) {
     stl_reverse_all_facets(stl);
@@ -346,8 +313,6 @@ void stl_repair(stl_file *stl,
   int i;
   int last_edges_fixed = 0;
 
-  if (stl->error) return;
-
   if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag
       || fill_holes_flag || normal_directions_flag) {
     if (verbose_flag)
@@ -453,8 +418,6 @@ All facets connected.  No further nearby check necessary.\n");
 // Check validity of the mesh, assert on error.
 bool stl_validate(stl_file *stl)
 {
-	assert(! stl->error);
-	assert(stl->fp == nullptr);
 	assert(! stl->facet_start.empty());
 	assert(stl->facet_start.size() == stl->stats.number_of_facets);
 	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
diff --git a/src/libslic3r/Format/PRUS.cpp b/src/libslic3r/Format/PRUS.cpp
index d983b1098..03ea71a83 100644
--- a/src/libslic3r/Format/PRUS.cpp
+++ b/src/libslic3r/Format/PRUS.cpp
@@ -161,7 +161,6 @@ static void extract_model_from_archive(
         else {
             // Header has been extracted. Now read the faces.
             stl_file &stl = mesh.stl;
-            stl.error = 0;
             stl.stats.type = inmemory;
             stl.stats.number_of_facets = header.nTriangles;
             stl.stats.original_num_facets = header.nTriangles;
diff --git a/src/libslic3r/Format/STL.cpp b/src/libslic3r/Format/STL.cpp
index b00623d1d..932906fe0 100644
--- a/src/libslic3r/Format/STL.cpp
+++ b/src/libslic3r/Format/STL.cpp
@@ -17,8 +17,7 @@ namespace Slic3r {
 bool load_stl(const char *path, Model *model, const char *object_name_in)
 {
     TriangleMesh mesh;
-    mesh.ReadSTLFile(path);
-    if (mesh.stl.error) {
+    if (! mesh.ReadSTLFile(path)) {
 //    die "Failed to open $file\n" if !-e $path;
         return false;
     }
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index ad12047d2..27163eb57 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -45,7 +45,7 @@ namespace Slic3r {
 TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets)
     : repaired(false)
 {
-    stl_initialize(&this->stl);
+    stl_reset(&this->stl);
     stl_file &stl = this->stl;
     stl.stats.type = inmemory;
 
@@ -74,7 +74,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
 
 TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
 {
-    stl_close(&this->stl);
+    stl_reset(&this->stl);
     this->stl = other.stl;
 	this->repaired = other.repaired;
     return *this;
@@ -426,7 +426,6 @@ TriangleMeshPtrs TriangleMesh::split() const
         mesh->stl.stats.type = inmemory;
         mesh->stl.stats.number_of_facets = (uint32_t)facets.size();
         mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets;
-        stl_clear_error(&mesh->stl);
         stl_allocate(&mesh->stl);
 
         // Assign the facets to the new mesh.
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index 4de1f5989..c16f4a664 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -21,18 +21,18 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
 class TriangleMesh
 {
 public:
-    TriangleMesh() : repaired(false) { stl_initialize(&this->stl); }
+    TriangleMesh() : repaired(false) { stl_reset(&this->stl); }
     TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
-    TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
-    TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
+    TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_reset(&this->stl); *this = other; }
+    TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_reset(&this->stl); this->swap(other); }
     ~TriangleMesh() { clear(); }
     TriangleMesh& operator=(const TriangleMesh &other);
     TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
-    void clear() { stl_close(&this->stl); this->repaired = false; }
+    void clear() { stl_reset(&this->stl); this->repaired = false; }
     void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
-    void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
-    void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
-    void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); }
+    bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
+    bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); }
+    bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); }
     void repair();
     float volume();
     void check_topology();
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index a188e0b8d..3cfbaa54d 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -46,7 +46,6 @@ TriangleMesh::ReadFromPerl(vertices, facets)
     SV* facets
     CODE:
         stl_file &stl = THIS->stl;
-        stl.error = 0;
         stl.stats.type = inmemory;
     
         // count facets and allocate memory

From 65238a89b10fb18e7f9b647f5026da9276d32d58 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 17:36:15 +0200
Subject: [PATCH 07/22] admesh refactoring: Removed the shared_vertices counter
 as it is now contained inside v_shared std::vector

---
 src/admesh/shared.cpp          | 14 +++++---------
 src/admesh/stl.h               |  2 --
 src/admesh/util.cpp            |  1 -
 src/libslic3r/Format/3mf.cpp   |  6 +++---
 src/libslic3r/Format/AMF.cpp   |  4 ++--
 src/libslic3r/Model.cpp        |  2 +-
 src/libslic3r/TriangleMesh.cpp |  4 ++--
 xs/xsp/TriangleMesh.xsp        |  4 ++--
 8 files changed, 15 insertions(+), 22 deletions(-)

diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index a757d8816..e9f075498 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -33,7 +33,6 @@ void stl_invalidate_shared_vertices(stl_file *stl)
 {
   	stl->v_indices.clear();
   	stl->v_shared.clear();
-  	stl->stats.shared_vertices = 0;
 }
 
 void stl_generate_shared_vertices(stl_file *stl)
@@ -43,7 +42,6 @@ void stl_generate_shared_vertices(stl_file *stl)
 	// Shared vertices (3D coordinates)
 	stl->v_shared.clear();
 	stl->v_shared.reserve(stl->stats.number_of_facets / 2);
-	stl->stats.shared_vertices = 0;
 
 	// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
 	// while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
@@ -91,7 +89,7 @@ void stl_generate_shared_vertices(stl_file *stl)
 			    		next_edge    = pivot_vertex;
 			  		}
 				}
-				stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->stats.shared_vertices;
+				stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->v_shared.size() - 1;
 				fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
 
 				// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
@@ -128,8 +126,6 @@ void stl_generate_shared_vertices(stl_file *stl)
 					facet_in_fan_idx = next_facet;
 				}
 			}
-
-			++ stl->stats.shared_vertices;
 		}
 	}
 }
@@ -147,8 +143,8 @@ bool stl_write_off(stl_file *stl, const char *file)
 	}
 
 	fprintf(fp, "OFF\n");
-	fprintf(fp, "%d %d 0\n", stl->stats.shared_vertices, stl->stats.number_of_facets);
-	for (int i = 0; i < stl->stats.shared_vertices; ++ i)
+	fprintf(fp, "%d %d 0\n", stl->v_shared.size(), stl->stats.number_of_facets);
+	for (int i = 0; i < stl->v_shared.size(); ++ i)
 		fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
 		fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
@@ -184,7 +180,7 @@ bool stl_write_vrml(stl_file *stl, const char *file)
 	fprintf(fp, "\t\t\tpoint [\n");
 
 	int i = 0;
-	for (; i < (stl->stats.shared_vertices - 1); i++)
+	for (; i + 1 < stl->v_shared.size(); ++ i)
 		fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
 	fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
 	fprintf(fp, "\t\t}\n");
@@ -213,7 +209,7 @@ bool stl_write_obj(stl_file *stl, const char *file)
     	return false;
   	}
 
-	for (int i = 0; i < stl->stats.shared_vertices; ++ i)
+	for (size_t i = 0; i < stl->v_shared.size(); ++ i)
     	fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
   	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
     	fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 51153ede7..4aee6048f 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -109,7 +109,6 @@ struct stl_stats {
 	float         bounding_diameter;
 	float         shortest_edge;
 	float         volume;
-	unsigned      number_of_blocks;
 	int           connected_edges;
 	int           connected_facets_1_edge;
 	int           connected_facets_2_edge;
@@ -126,7 +125,6 @@ struct stl_stats {
 	int           backwards_edges;
 	int           normals_fixed;
 	int           number_of_parts;
-	int           shared_vertices;
 };
 
 struct stl_file {
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index db05cbc09..685b641b4 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -425,7 +425,6 @@ bool stl_validate(stl_file *stl)
 	assert(! stl->neighbors_start.empty());
 	assert((stl->v_indices.empty()) == (stl->v_shared.empty()));
 	assert(stl->stats.number_of_facets > 0);
-	assert(stl->v_shared.size() == stl->stats.shared_vertices);
 	assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets);
 
 #ifdef _DEBUG
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index c3916a14e..d67106656 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1888,17 +1888,17 @@ namespace Slic3r {
             if (stl.v_shared.empty())
                 stl_generate_shared_vertices(&stl);
 
-            if (stl.stats.shared_vertices == 0)
+            if (stl.v_shared.empty())
             {
                 add_error("Found invalid mesh");
                 return false;
             }
 
-            vertices_count += stl.stats.shared_vertices;
+            vertices_count += stl.v_shared.size();
 
             const Transform3d& matrix = volume->get_matrix();
 
-            for (int i = 0; i < stl.stats.shared_vertices; ++i)
+            for (size_t i = 0; i < stl.v_shared.size(); ++i)
             {
                 stream << "     <" << VERTEX_TAG << " ";
                 Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index f48b5b58c..e81ced3ad 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -929,7 +929,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             if (stl.v_shared.empty())
                 stl_generate_shared_vertices(&stl);
             const Transform3d& matrix = volume->get_matrix();
-            for (size_t i = 0; i < stl.stats.shared_vertices; ++i) {
+            for (size_t i = 0; i < stl.v_shared.size(); ++i) {
                 stream << "         <vertex>\n";
                 stream << "           <coordinates>\n";
                 Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
@@ -939,7 +939,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
                 stream << "           </coordinates>\n";
                 stream << "         </vertex>\n";
             }
-            num_vertices += stl.stats.shared_vertices;
+            num_vertices += stl.v_shared.size();
         }
         stream << "      </vertices>\n";
         for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 64fbb9a2a..6da7fc0c3 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -919,7 +919,7 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
                     }
             } else {
                 // Using the shared vertices should be a bit quicker than using the STL faces.
-                for (int i = 0; i < stl.stats.shared_vertices; ++ i) {
+                for (size_t i = 0; i < stl.v_shared.size(); ++ i) {
                     Vec3d p = trafo * stl.v_shared[i].cast<double>();
                     pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
                 }
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 27163eb57..003affc27 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -484,8 +484,8 @@ Polygon TriangleMesh::convex_hull()
 {
     this->require_shared_vertices();
     Points pp;
-    pp.reserve(this->stl.stats.shared_vertices);
-    for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) {
+    pp.reserve(this->stl.v_shared.size());
+    for (size_t i = 0; i < this->stl.v_shared.size(); ++ i) {
         const stl_vertex &v = this->stl.v_shared[i];
         pp.emplace_back(Point::new_scale(v(0), v(1)));
     }
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index 3cfbaa54d..53b052027 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -104,8 +104,8 @@ TriangleMesh::vertices()
         
         // vertices
         AV* vertices = newAV();
-        av_extend(vertices, THIS->stl.stats.shared_vertices);
-        for (int i = 0; i < THIS->stl.stats.shared_vertices; i++) {
+        av_extend(vertices, THIS->stl.v_shared.size());
+        for (size_t i = 0; i < THIS->stl.v_shared.size(); i++) {
             AV* vertex = newAV();
             av_store(vertices, i, newRV_noinc((SV*)vertex));
             av_extend(vertex, 2);

From 6defabea537ba871070fc405a14c2173cb92fc89 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 18:30:54 +0200
Subject: [PATCH 08/22] admesh refactoring: separation of the shared vertices /
 indices into an indexed_triangle_set structure

---
 src/admesh/shared.cpp           | 111 +++++++++++++++++++++++---------
 src/admesh/stl.h                |  26 ++++----
 src/admesh/stlinit.cpp          |   2 -
 src/admesh/util.cpp             |  50 --------------
 src/libslic3r/Format/3mf.cpp    |  24 +++----
 src/libslic3r/Format/AMF.cpp    |  17 +++--
 src/libslic3r/Model.cpp         |   9 +--
 src/libslic3r/TriangleMesh.cpp  |  46 ++++++-------
 src/libslic3r/TriangleMesh.hpp  |   3 +-
 src/slic3r/GUI/PresetBundle.cpp |   4 +-
 xs/xsp/TriangleMesh.xsp         |  24 +++----
 11 files changed, 154 insertions(+), 162 deletions(-)

diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index e9f075498..7da2841b0 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -29,19 +29,13 @@
 
 #include "stl.h"
 
-void stl_invalidate_shared_vertices(stl_file *stl)
-{
-  	stl->v_indices.clear();
-  	stl->v_shared.clear();
-}
-
-void stl_generate_shared_vertices(stl_file *stl)
+void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
 {
 	// 3 indices to vertex per face
-	stl->v_indices.assign(stl->stats.number_of_facets, v_indices_struct());
+	its.indices.assign(stl->stats.number_of_facets, v_indices_struct());
 	// Shared vertices (3D coordinates)
-	stl->v_shared.clear();
-	stl->v_shared.reserve(stl->stats.number_of_facets / 2);
+	its.vertices.clear();
+	its.vertices.reserve(stl->stats.number_of_facets / 2);
 
 	// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
 	// while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
@@ -51,11 +45,11 @@ void stl_generate_shared_vertices(stl_file *stl)
 
 	for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
 		for (int j = 0; j < 3; ++ j) {
-			if (stl->v_indices[facet_idx].vertex[j] != -1)
+			if (its.indices[facet_idx].vertex[j] != -1)
 				// Shared vertex was already assigned.
 				continue;
 			// Create a new shared vertex.
-			stl->v_shared.emplace_back(stl->facet_start[facet_idx].vertex[j]);
+			its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]);
 			// Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
 			int  facet_in_fan_idx 	= facet_idx;
 			bool edge_direction 	= false;
@@ -89,7 +83,7 @@ void stl_generate_shared_vertices(stl_file *stl)
 			    		next_edge    = pivot_vertex;
 			  		}
 				}
-				stl->v_indices[facet_in_fan_idx].vertex[pivot_vertex] = stl->v_shared.size() - 1;
+				its.indices[facet_in_fan_idx].vertex[pivot_vertex] = its.vertices.size() - 1;
 				fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
 
 				// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
@@ -130,7 +124,7 @@ void stl_generate_shared_vertices(stl_file *stl)
 	}
 }
 
-bool stl_write_off(stl_file *stl, const char *file)
+bool its_write_off(const indexed_triangle_set &its, const char *file)
 {
 	/* Open the file */
 	FILE *fp = boost::nowide::fopen(file, "w");
@@ -143,16 +137,16 @@ bool stl_write_off(stl_file *stl, const char *file)
 	}
 
 	fprintf(fp, "OFF\n");
-	fprintf(fp, "%d %d 0\n", stl->v_shared.size(), stl->stats.number_of_facets);
-	for (int i = 0; i < stl->v_shared.size(); ++ i)
-		fprintf(fp, "\t%f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
-		fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
+	fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size());
+	for (int i = 0; i < its.vertices.size(); ++ i)
+		fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
+	for (uint32_t i = 0; i < its.indices.size(); ++ i)
+		fprintf(fp, "\t3 %d %d %d\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
 	fclose(fp);
 	return true;
 }
 
-bool stl_write_vrml(stl_file *stl, const char *file)
+bool its_write_vrml(const indexed_triangle_set &its, const char *file)
 {
 	/* Open the file */
   	FILE *fp = boost::nowide::fopen(file, "w");
@@ -180,16 +174,16 @@ bool stl_write_vrml(stl_file *stl, const char *file)
 	fprintf(fp, "\t\t\tpoint [\n");
 
 	int i = 0;
-	for (; i + 1 < stl->v_shared.size(); ++ i)
-		fprintf(fp, "\t\t\t\t%f %f %f,\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-	fprintf(fp, "\t\t\t\t%f %f %f]\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
+	for (; i + 1 < its.vertices.size(); ++ i)
+		fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
+	fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
 	fprintf(fp, "\t\t}\n");
 	fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
 	fprintf(fp, "\t\t\tcoordIndex [\n");
 
-	for (int i = 0; i + 1 < (int)stl->stats.number_of_facets; ++ i)
-		fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
-	fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0], stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
+	for (size_t i = 0; i + 1 < its.indices.size(); ++ i)
+		fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
+	fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
 	fprintf(fp, "\t\t}\n");
 	fprintf(fp, "\t}\n");
 	fprintf(fp, "}\n");
@@ -197,7 +191,7 @@ bool stl_write_vrml(stl_file *stl, const char *file)
 	return true;
 }
 
-bool stl_write_obj(stl_file *stl, const char *file)
+bool its_write_obj(const indexed_triangle_set &its, const char *file)
 {
 
   	FILE *fp = boost::nowide::fopen(file, "w");
@@ -209,10 +203,65 @@ bool stl_write_obj(stl_file *stl, const char *file)
     	return false;
   	}
 
-	for (size_t i = 0; i < stl->v_shared.size(); ++ i)
-    	fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
-  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
-    	fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
+	for (size_t i = 0; i < its.vertices.size(); ++ i)
+    	fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
+  	for (size_t i = 0; i < its.indices.size(); ++ i)
+    	fprintf(fp, "f %d %d %d\n", its.indices[i].vertex[0]+1, its.indices[i].vertex[1]+1, its.indices[i].vertex[2]+1);
   	fclose(fp);
   	return true;
 }
+
+
+// Check validity of the mesh, assert on error.
+bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
+{
+	assert(! stl->facet_start.empty());
+	assert(stl->facet_start.size() == stl->stats.number_of_facets);
+	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
+	assert(stl->facet_start.size() == stl->neighbors_start.size());
+	assert(! stl->neighbors_start.empty());
+	assert((its.indices.empty()) == (its.vertices.empty()));
+	assert(stl->stats.number_of_facets > 0);
+	assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets);
+
+#ifdef _DEBUG
+    // Verify validity of neighborship data.
+    for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
+        const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
+        const int 			*vertices 	= (its.indices.empty()) ? nullptr : its.indices[facet_idx].vertex;
+        for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
+            int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
+            assert(nbr_face < (int)stl->stats.number_of_facets);
+            if (nbr_face != -1) {
+            	int nbr_vnot = nbr.which_vertex_not[nbr_idx];
+				assert(nbr_vnot >= 0 && nbr_vnot < 6);
+				// Neighbor of the neighbor is the original face.
+				assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
+				int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
+				assert(vnot_back >= 0 && vnot_back < 6);
+				assert((nbr_vnot < 3) == (vnot_back < 3));
+				assert(vnot_back % 3 == (nbr_idx + 2) % 3);
+				if (vertices != nullptr) {
+					// Has shared vertices.
+	            	if (nbr_vnot < 3) {
+	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
+						assert((its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
+					} else {
+	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
+						assert((its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
+					}
+				}
+            }
+        }
+    }
+#endif /* _DEBUG */
+
+	return true;
+}
+
+// Check validity of the mesh, assert on error.
+bool stl_validate(const stl_file *stl)
+{
+	indexed_triangle_set its;
+	return stl_validate(stl, its);
+}
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 4aee6048f..bb5d25296 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -130,21 +130,22 @@ struct stl_stats {
 struct stl_file {
 	std::vector<stl_facet>     		facet_start;
 	std::vector<stl_neighbors> 		neighbors_start;
-	// Indexed face set
-	std::vector<v_indices_struct> 	v_indices;
-	std::vector<stl_vertex>       	v_shared;
 	// Statistics
 	stl_stats     					stats;
 };
 
+struct indexed_triangle_set
+{
+	void clear() { indices.clear(); vertices.clear(); }
+	std::vector<v_indices_struct> 	indices;
+	std::vector<stl_vertex>       	vertices;
+};
+
 extern bool stl_open(stl_file *stl, const char *file);
 extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
 extern bool stl_print_neighbors(stl_file *stl, char *file);
-extern void stl_put_little_int(FILE *fp, int value_in);
-extern void stl_put_little_float(FILE *fp, float value_in);
 extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label);
 extern bool stl_write_binary(stl_file *stl, const char *file, const char *label);
-extern void stl_write_binary_block(stl_file *stl, FILE *fp);
 extern void stl_check_facets_exact(stl_file *stl);
 extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
 extern void stl_remove_unconnected_facets(stl_file *stl);
@@ -219,12 +220,12 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
 	stl_get_size(stl);
 }
 
-extern void stl_invalidate_shared_vertices(stl_file *stl);
-extern void stl_generate_shared_vertices(stl_file *stl);
-extern bool stl_write_obj(stl_file *stl, const char *file);
-extern bool stl_write_off(stl_file *stl, const char *file);
+extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
+extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
+extern bool its_write_off(const indexed_triangle_set &its, const char *file);
+extern bool its_write_vrml(const indexed_triangle_set &its, const char *file);
+
 extern bool stl_write_dxf(stl_file *stl, const char *file, char *label);
-extern bool stl_write_vrml(stl_file *stl, const char *file);
 inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
   normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
 }
@@ -251,6 +252,7 @@ extern void stl_reallocate(stl_file *stl);
 extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
 
 // Validate the mesh, assert on error.
-extern bool stl_validate(stl_file *stl);
+extern bool stl_validate(const stl_file *stl);
+extern bool stl_validate(const stl_file *stl, const indexed_triangle_set &its);
 
 #endif
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 088842d51..44477511f 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -253,8 +253,6 @@ void stl_reset(stl_file *stl)
 {
 	stl->facet_start.clear();
 	stl->neighbors_start.clear();
-	stl->v_indices.clear();
-	stl->v_shared.clear();
   	memset(&stl->stats, 0, sizeof(stl_stats));
   	stl->stats.volume = -1.0;
 }
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 685b641b4..f4e4dbf0a 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -73,7 +73,6 @@ void stl_translate(stl_file *stl, float x, float y, float z)
       stl->facet_start[i].vertex[j] += shift;
   stl->stats.min = new_min;
   stl->stats.max += shift;
-  stl_invalidate_shared_vertices(stl);
 }
 
 /* Translates the stl by x,y,z, relatively from wherever it is currently */
@@ -85,7 +84,6 @@ void stl_translate_relative(stl_file *stl, float x, float y, float z)
       stl->facet_start[i].vertex[j] += shift;
   stl->stats.min += shift;
   stl->stats.max += shift;
-  stl_invalidate_shared_vertices(stl);
 }
 
 void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
@@ -103,7 +101,6 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
   for (int i = 0; i < stl->stats.number_of_facets; ++ i)
     for (int j = 0; j < 3; ++ j)
       stl->facet_start[i].vertex[j].array() *= s;
-  stl_invalidate_shared_vertices(stl);
 }
 
 static void calculate_normals(stl_file *stl) 
@@ -414,50 +411,3 @@ All facets connected.  No further nearby check necessary.\n");
     stl_verify_neighbors(stl);
   }
 }
-
-// Check validity of the mesh, assert on error.
-bool stl_validate(stl_file *stl)
-{
-	assert(! stl->facet_start.empty());
-	assert(stl->facet_start.size() == stl->stats.number_of_facets);
-	assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
-	assert(stl->facet_start.size() == stl->neighbors_start.size());
-	assert(! stl->neighbors_start.empty());
-	assert((stl->v_indices.empty()) == (stl->v_shared.empty()));
-	assert(stl->stats.number_of_facets > 0);
-	assert(stl->v_shared.empty() || stl->v_indices.size() == stl->stats.number_of_facets);
-
-#ifdef _DEBUG
-    // Verify validity of neighborship data.
-    for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
-        const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
-        const int 			*vertices 	= (stl->v_indices.empty()) ? nullptr : stl->v_indices[facet_idx].vertex;
-        for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
-            int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
-            assert(nbr_face < (int)stl->stats.number_of_facets);
-            if (nbr_face != -1) {
-            	int nbr_vnot = nbr.which_vertex_not[nbr_idx];
-				assert(nbr_vnot >= 0 && nbr_vnot < 6);
-				// Neighbor of the neighbor is the original face.
-				assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
-				int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
-				assert(vnot_back >= 0 && vnot_back < 6);
-				assert((nbr_vnot < 3) == (vnot_back < 3));
-				assert(vnot_back % 3 == (nbr_idx + 2) % 3);
-				if (vertices != nullptr) {
-					// Has shared vertices.
-	            	if (nbr_vnot < 3) {
-	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
-						assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
-					} else {
-	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
-						assert((stl->v_indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && stl->v_indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
-					}
-				}
-            }
-        }
-    }
-#endif /* _DEBUG */
-
-	return true;
-}
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index d67106656..8298fe222 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1881,27 +1881,23 @@ namespace Slic3r {
 
             volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
 
-            if (!volume->mesh.repaired)
-                volume->mesh.repair();
+			volume->mesh.require_shared_vertices();
 
-            stl_file& stl = volume->mesh.stl;
-            if (stl.v_shared.empty())
-                stl_generate_shared_vertices(&stl);
-
-            if (stl.v_shared.empty())
+            const indexed_triangle_set &its = volume->mesh.its;
+            if (its.vertices.empty())
             {
                 add_error("Found invalid mesh");
                 return false;
             }
 
-            vertices_count += stl.v_shared.size();
+            vertices_count += its.vertices.size();
 
             const Transform3d& matrix = volume->get_matrix();
 
-            for (size_t i = 0; i < stl.v_shared.size(); ++i)
+            for (size_t i = 0; i < its.vertices.size(); ++i)
             {
                 stream << "     <" << VERTEX_TAG << " ";
-                Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
+                Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
                 stream << "x=\"" << v(0) << "\" ";
                 stream << "y=\"" << v(1) << "\" ";
                 stream << "z=\"" << v(2) << "\" />\n";
@@ -1920,19 +1916,19 @@ namespace Slic3r {
             VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume);
             assert(volume_it != volumes_offsets.end());
 
-            stl_file& stl = volume->mesh.stl;
+            const indexed_triangle_set &its = volume->mesh.its;
 
             // updates triangle offsets
             volume_it->second.first_triangle_id = triangles_count;
-            triangles_count += stl.stats.number_of_facets;
+            triangles_count += its.indices.size();
             volume_it->second.last_triangle_id = triangles_count - 1;
 
-            for (uint32_t i = 0; i < stl.stats.number_of_facets; ++i)
+            for (size_t i = 0; i < its.indices.size(); ++ i)
             {
                 stream << "     <" << TRIANGLE_TAG << " ";
                 for (int j = 0; j < 3; ++j)
                 {
-                    stream << "v" << j + 1 << "=\"" << stl.v_indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" ";
+                    stream << "v" << j + 1 << "=\"" << its.indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" ";
                 }
                 stream << "/>\n";
             }
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index e81ced3ad..dcd913864 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -923,23 +923,22 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
         int              num_vertices = 0;
         for (ModelVolume *volume : object->volumes) {
             vertices_offsets.push_back(num_vertices);
-            if (! volume->mesh.repaired) 
+            if (! volume->mesh.repaired)
                 throw std::runtime_error("store_amf() requires repair()");
-            auto &stl = volume->mesh.stl;
-            if (stl.v_shared.empty())
-                stl_generate_shared_vertices(&stl);
+			volume->mesh.require_shared_vertices();
+            const indexed_triangle_set &its = volume->mesh.its;
             const Transform3d& matrix = volume->get_matrix();
-            for (size_t i = 0; i < stl.v_shared.size(); ++i) {
+            for (size_t i = 0; i < its.vertices.size(); ++i) {
                 stream << "         <vertex>\n";
                 stream << "           <coordinates>\n";
-                Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
+                Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
                 stream << "             <x>" << v(0) << "</x>\n";
                 stream << "             <y>" << v(1) << "</y>\n";
                 stream << "             <z>" << v(2) << "</z>\n";
                 stream << "           </coordinates>\n";
                 stream << "         </vertex>\n";
             }
-            num_vertices += stl.v_shared.size();
+            num_vertices += its.vertices.size();
         }
         stream << "      </vertices>\n";
         for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
@@ -956,10 +955,10 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             if (volume->is_modifier())
                 stream << "        <metadata type=\"slic3r.modifier\">1</metadata>\n";
             stream << "        <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
-            for (int i = 0; i < (int)volume->mesh.stl.stats.number_of_facets; ++i) {
+            for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) {
                 stream << "        <triangle>\n";
                 for (int j = 0; j < 3; ++j)
-                stream << "          <v" << j + 1 << ">" << volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset << "</v" << j + 1 << ">\n";
+                stream << "          <v" << j + 1 << ">" << volume->mesh.its.indices[i].vertex[j] + vertices_offset << "</v" << j + 1 << ">\n";
                 stream << "        </triangle>\n";
             }
             stream << "      </volume>\n";
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 6da7fc0c3..770581c03 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -908,10 +908,11 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
     Points pts;
     for (const ModelVolume *v : this->volumes)
         if (v->is_model_part()) {
-            const stl_file &stl = v->mesh.stl;
             Transform3d trafo = trafo_instance * v->get_matrix();
-            if (stl.v_shared.empty()) {
+			const indexed_triangle_set &its = v->mesh.its;
+			if (its.vertices.empty()) {
                 // Using the STL faces.
+				const stl_file& stl = v->mesh.stl;
 				for (const stl_facet &facet : stl.facet_start)
                     for (size_t j = 0; j < 3; ++ j) {
                         Vec3d p = trafo * facet.vertex[j].cast<double>();
@@ -919,8 +920,8 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
                     }
             } else {
                 // Using the shared vertices should be a bit quicker than using the STL faces.
-                for (size_t i = 0; i < stl.v_shared.size(); ++ i) {
-                    Vec3d p = trafo * stl.v_shared[i].cast<double>();
+                for (size_t i = 0; i < its.vertices.size(); ++ i) {
+                    Vec3d p = trafo * its.vertices[i].cast<double>();
                     pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
                 }
             }
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 003affc27..ae35c8a5b 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -238,20 +238,20 @@ bool TriangleMesh::needed_repair() const
 
 void TriangleMesh::WriteOBJFile(const char* output_file)
 {
-    stl_generate_shared_vertices(&stl);
-    stl_write_obj(&stl, output_file);
+    stl_generate_shared_vertices(&stl, its);
+    its_write_obj(its, output_file);
 }
 
 void TriangleMesh::scale(float factor)
 {
     stl_scale(&(this->stl), factor);
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
 }
 
 void TriangleMesh::scale(const Vec3d &versor)
 {
     stl_scale_versor(&this->stl, versor.cast<float>());
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
 }
 
 void TriangleMesh::translate(float x, float y, float z)
@@ -259,7 +259,7 @@ void TriangleMesh::translate(float x, float y, float z)
     if (x == 0.f && y == 0.f && z == 0.f)
         return;
     stl_translate_relative(&(this->stl), x, y, z);
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
 }
 
 void TriangleMesh::translate(const Vec3f &displacement)
@@ -282,7 +282,7 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
     } else if (axis == Z) {
         stl_rotate_z(&(this->stl), angle);
     }
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
 }
 
 void TriangleMesh::rotate(float angle, const Vec3d& axis)
@@ -305,13 +305,13 @@ void TriangleMesh::mirror(const Axis &axis)
     } else if (axis == Z) {
         stl_mirror_xy(&this->stl);
     }
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
 }
 
 void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
 {
     stl_transform(&stl, t);
-    stl_invalidate_shared_vertices(&stl);
+    this->its.clear();
 	if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
 		// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
 		this->repair();
@@ -322,7 +322,7 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
 void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
 {
     stl_transform(&stl, m);
-    stl_invalidate_shared_vertices(&stl);
+    this->its.clear();
     if (fix_left_handed && m.determinant() < 0.) {
         // Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
         this->repair();
@@ -443,7 +443,7 @@ void TriangleMesh::merge(const TriangleMesh &mesh)
 {
     // reset stats and metadata
     int number_of_facets = this->stl.stats.number_of_facets;
-    stl_invalidate_shared_vertices(&this->stl);
+    this->its.clear();
     this->repaired = false;
     
     // update facet count and allocate more memory
@@ -484,9 +484,9 @@ Polygon TriangleMesh::convex_hull()
 {
     this->require_shared_vertices();
     Points pp;
-    pp.reserve(this->stl.v_shared.size());
-    for (size_t i = 0; i < this->stl.v_shared.size(); ++ i) {
-        const stl_vertex &v = this->stl.v_shared[i];
+    pp.reserve(this->its.vertices.size());
+    for (size_t i = 0; i < this->its.vertices.size(); ++ i) {
+        const stl_vertex &v = this->its.vertices[i];
         pp.emplace_back(Point::new_scale(v(0), v(1)));
     }
     return Slic3r::Geometry::convex_hull(pp);
@@ -504,14 +504,14 @@ BoundingBoxf3 TriangleMesh::bounding_box() const
 BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const
 {
     BoundingBoxf3 bbox;
-    if (stl.v_shared.empty()) {
+    if (this->its.vertices.empty()) {
         // Using the STL faces.
 		for (const stl_facet &facet : this->stl.facet_start)
             for (size_t j = 0; j < 3; ++ j)
                 bbox.merge(trafo * facet.vertex[j].cast<double>());
     } else {
         // Using the shared vertices should be a bit quicker than using the STL faces.
-		for (const stl_vertex &v : this->stl.v_shared)
+		for (const stl_vertex &v : this->its.vertices)
             bbox.merge(trafo * v.cast<double>());
     }
     return bbox;
@@ -576,11 +576,11 @@ void TriangleMesh::require_shared_vertices()
     assert(stl_validate(&this->stl));
     if (! this->repaired) 
         this->repair();
-    if (this->stl.v_shared.empty()) {
+    if (this->its.vertices.empty()) {
         BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - stl_generate_shared_vertices";
-        stl_generate_shared_vertices(&(this->stl));
+        stl_generate_shared_vertices(&this->stl, this->its);
     }
-    assert(stl_validate(&this->stl));
+    assert(stl_validate(&this->stl, this->its));
     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - end";
 }
 
@@ -592,9 +592,9 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
 
     throw_on_cancel();
     facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
-	v_scaled_shared.assign(_mesh->stl.v_shared.size(), stl_vertex());
+	v_scaled_shared.assign(_mesh->its.vertices.size(), stl_vertex());
 	for (size_t i = 0; i < v_scaled_shared.size(); ++ i)
-        this->v_scaled_shared[i] = _mesh->stl.v_shared[i] / float(SCALING_FACTOR);
+        this->v_scaled_shared[i] = _mesh->its.vertices[i] / float(SCALING_FACTOR);
 
     // Create a mapping from triangle edge into face.
     struct EdgeToFace {
@@ -614,8 +614,8 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
     for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx)
         for (int i = 0; i < 3; ++ i) {
             EdgeToFace &e2f = edges_map[facet_idx*3+i];
-            e2f.vertex_low  = this->mesh->stl.v_indices[facet_idx].vertex[i];
-            e2f.vertex_high = this->mesh->stl.v_indices[facet_idx].vertex[(i + 1) % 3];
+            e2f.vertex_low  = this->mesh->its.indices[facet_idx].vertex[i];
+            e2f.vertex_high = this->mesh->its.indices[facet_idx].vertex[(i + 1) % 3];
             e2f.face        = facet_idx;
             // 1 based indexing, to be always strictly positive.
             e2f.face_edge   = i + 1;
@@ -852,7 +852,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
     // Reorder vertices so that the first one is the one with lowest Z.
     // This is needed to get all intersection lines in a consistent order
     // (external on the right of the line)
-    const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
+    const int *vertices = this->mesh->its.indices[facet_idx].vertex;
     int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0);
 
     // These are used only if the cut plane is tilted:
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index c16f4a664..75082cfdb 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -69,12 +69,13 @@ public:
     void reset_repair_stats();
     bool needed_repair() const;
     void require_shared_vertices();
-    bool   has_shared_vertices() const { return ! stl.v_shared.empty(); }
+    bool   has_shared_vertices() const { return ! this->its.vertices.empty(); }
     size_t facets_count() const { return this->stl.stats.number_of_facets; }
     bool   empty() const { return this->facets_count() == 0; }
     bool is_splittable() const;
 
     stl_file stl;
+    indexed_triangle_set its;
     bool repaired;
 
 private:
diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp
index fb3b6f7a4..45092f257 100644
--- a/src/slic3r/GUI/PresetBundle.cpp
+++ b/src/slic3r/GUI/PresetBundle.cpp
@@ -781,7 +781,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
                     if (i == 0)
                         suffix[0] = 0;
                     else
-                        sprintf(suffix, "%d", i);
+                        sprintf(suffix, "%d", (int)i);
                     std::string new_name = name + suffix;
                     loaded = &this->filaments.load_preset(this->filaments.path_from_name(new_name),
                         new_name, std::move(cfg), i == 0);
@@ -1379,7 +1379,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
     for (size_t i = 0; i < this->filament_presets.size(); ++ i) {
         char suffix[64];
         if (i > 0)
-            sprintf(suffix, "_%d", i);
+            sprintf(suffix, "_%d", (int)i);
         else
             suffix[0] = 0;
         c << "filament" << suffix << " = " << this->filament_presets[i] << std::endl;
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index 53b052027..3e90bfefd 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -98,20 +98,18 @@ SV*
 TriangleMesh::vertices()
     CODE:
         if (!THIS->repaired) CONFESS("vertices() requires repair()");
-        
-        if (THIS->stl.v_shared.empty())
-            stl_generate_shared_vertices(&(THIS->stl));
+        THIS->require_shared_vertices();
         
         // vertices
         AV* vertices = newAV();
-        av_extend(vertices, THIS->stl.v_shared.size());
-        for (size_t i = 0; i < THIS->stl.v_shared.size(); i++) {
+        av_extend(vertices, THIS->its.vertices.size());
+        for (size_t i = 0; i < THIS->its.vertices.size(); i++) {
             AV* vertex = newAV();
             av_store(vertices, i, newRV_noinc((SV*)vertex));
             av_extend(vertex, 2);
-            av_store(vertex, 0, newSVnv(THIS->stl.v_shared[i](0)));
-            av_store(vertex, 1, newSVnv(THIS->stl.v_shared[i](1)));
-            av_store(vertex, 2, newSVnv(THIS->stl.v_shared[i](2)));
+            av_store(vertex, 0, newSVnv(THIS->its.vertices[i](0)));
+            av_store(vertex, 1, newSVnv(THIS->its.vertices[i](1)));
+            av_store(vertex, 2, newSVnv(THIS->its.vertices[i](2)));
         }
         
         RETVAL = newRV_noinc((SV*)vertices);
@@ -122,9 +120,7 @@ SV*
 TriangleMesh::facets()
     CODE:
         if (!THIS->repaired) CONFESS("facets() requires repair()");
-        
-        if (THIS->stl.v_shared.empty())
-            stl_generate_shared_vertices(&(THIS->stl));
+        THIS->require_shared_vertices();
         
         // facets
         AV* facets = newAV();
@@ -133,9 +129,9 @@ TriangleMesh::facets()
             AV* facet = newAV();
             av_store(facets, i, newRV_noinc((SV*)facet));
             av_extend(facet, 2);
-            av_store(facet, 0, newSVnv(THIS->stl.v_indices[i].vertex[0]));
-            av_store(facet, 1, newSVnv(THIS->stl.v_indices[i].vertex[1]));
-            av_store(facet, 2, newSVnv(THIS->stl.v_indices[i].vertex[2]));
+            av_store(facet, 0, newSVnv(THIS->its.indices[i].vertex[0]));
+            av_store(facet, 1, newSVnv(THIS->its.indices[i].vertex[1]));
+            av_store(facet, 2, newSVnv(THIS->its.indices[i].vertex[2]));
         }
         
         RETVAL = newRV_noinc((SV*)facets);

From 313ec7424a9714ba6de64a94b7d4b89ebae05f91 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 19:45:38 +0200
Subject: [PATCH 09/22] admesh refactoring: replaced various diagnostics
 outputs with boost::log

---
 src/admesh/connect.cpp          |  23 ++-
 src/admesh/shared.cpp           |  16 +-
 src/admesh/stl.h                |   2 +-
 src/admesh/stl_io.cpp           | 283 +++++++++++--------------
 src/admesh/stlinit.cpp          | 356 +++++++++++++++-----------------
 src/admesh/util.cpp             | 204 +++++++++---------
 src/slic3r/GUI/PresetBundle.cpp |   2 +-
 7 files changed, 405 insertions(+), 481 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 9553e7c4d..5ae03597e 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -28,6 +28,7 @@
 #include <algorithm>
 #include <vector>
 
+#include <boost/log/trivial.hpp>
 #include <boost/detail/endian.hpp>
 
 #include "stl.h"
@@ -124,7 +125,9 @@ struct HashTableEdges {
 	    	for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) {
 	        	this->heads[i] = this->heads[i]->next;
 	        	delete temp;
+#ifndef NDEBUG
 	        	++ this->freed;
+#endif /* NDEBUG */
 	      	}
 	    }
 		this->heads.clear();
@@ -139,7 +142,9 @@ struct HashTableEdges {
 		if (link == this->tail) {
 			// This list doesn't have any edges currently in it.  Add this one.
 			HashEdge *new_edge = new HashEdge(edge);
+#ifndef NDEBUG
 			++ this->malloced;
+#endif /* NDEBUG */
 			new_edge->next = this->tail;
 			this->heads[chain_number] = new_edge;
 		} else if (edges_equal(edge, *link)) {
@@ -148,18 +153,24 @@ struct HashTableEdges {
 			// Delete the matched edge from the list.
 			this->heads[chain_number] = link->next;
 			delete link;
+#ifndef NDEBUG
 			++ this->freed;
+#endif /* NDEBUG */
 		} else {
 			// Continue through the rest of the list.
 			for (;;) {
 				if (link->next == this->tail) {
 					// This is the last item in the list. Insert a new edge.
 					HashEdge *new_edge = new HashEdge;
+#ifndef NDEBUG
 					++ this->malloced;
+#endif /* NDEBUG */
 					*new_edge = edge;
 					new_edge->next = this->tail;
 					link->next = new_edge;
+#ifndef NDEBUG
 					++ this->collisions;
+#endif /* NDEBUG */
 					break;
 				}
 				if (edges_equal(edge, *link->next)) {
@@ -169,12 +180,16 @@ struct HashTableEdges {
 					HashEdge *temp = link->next;
 					link->next = link->next->next;
 					delete temp;
+#ifndef NDEBUG
 					++ this->freed;
+#endif /* NDEBUG */
 					break;
 				}
 				// This is not a match.  Go to the next link.
 				link = link->next;
+#ifndef NDEBUG
 				++ this->collisions;
+#endif /* NDEBUG */
 			}
 		}
 	}
@@ -184,9 +199,11 @@ struct HashTableEdges {
 	HashEdge* 					tail;
 	int           					M;
 
+#ifndef NDEBUG
 	size_t 							malloced   	= 0;
 	size_t 							freed 	  	= 0;
 	size_t 							collisions 	= 0;
+#endif /* NDEBUG */
 
 private:
 	static inline size_t hash_size_from_nr_faces(const size_t nr_faces)
@@ -366,7 +383,7 @@ static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const
 
 			if (facet_num == first_facet) {
 				// back to the beginning
-				printf("Back to the first facet changing vertices: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n");
+				BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
 				return;
 			}
 		}
@@ -506,7 +523,7 @@ void stl_remove_unconnected_facets(stl_file *stl)
 	    	if (neighbors.neighbor[i] != -1) {
 		    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
 		  		if (other_face_idx != stl->stats.number_of_facets) {
-		    		printf("in remove_facet: neighbor = %d numfacets = %d this is wrong\n", other_face_idx, stl->stats.number_of_facets);
+		  			BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong";
 		    		return;
 		  		}
 		  		other_face_idx = facet_number;
@@ -697,7 +714,7 @@ void stl_fill_holes(stl_file *stl)
 
 	    		if (facet_num == first_facet) {
 	      			// back to the beginning
-	      			printf("Back to the first facet filling holes: probably a mobius part.\nTry using a smaller tolerance or don't do a nearby check\n");
+		  			BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
 	      			return;
 	    		}
 	  		}
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index 7da2841b0..fe6d5e656 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -25,6 +25,7 @@
 
 #include <vector>
 
+#include <boost/log/trivial.hpp>
 #include <boost/nowide/cstdio.hpp>
 
 #include "stl.h"
@@ -129,10 +130,7 @@ bool its_write_off(const indexed_triangle_set &its, const char *file)
 	/* Open the file */
 	FILE *fp = boost::nowide::fopen(file, "w");
 	if (fp == nullptr) {
-		char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
-		perror(error_msg);
-		free(error_msg);
+		BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
 		return false;
 	}
 
@@ -151,10 +149,7 @@ bool its_write_vrml(const indexed_triangle_set &its, const char *file)
 	/* Open the file */
   	FILE *fp = boost::nowide::fopen(file, "w");
 	if (fp == nullptr) {
-  		char *error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-		sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
-		perror(error_msg);
-		free(error_msg);
+		BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing";
 		return false;
 	}
 
@@ -196,10 +191,7 @@ bool its_write_obj(const indexed_triangle_set &its, const char *file)
 
   	FILE *fp = boost::nowide::fopen(file, "w");
   	if (fp == nullptr) {
-    	char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    	sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
-    	perror(error_msg);
-    	free(error_msg);
+		BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
     	return false;
   	}
 
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index bb5d25296..500d6bfdb 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -242,7 +242,7 @@ inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
 }
 extern void stl_calculate_volume(stl_file *stl);
 
-extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
+extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
 
 extern void stl_reset(stl_file *stl);
 extern void stl_allocate(stl_file *stl);
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index 8f809d379..dc4e4a7db 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -24,6 +24,7 @@
 #include <string.h>
 #include "stl.h"
 
+#include <boost/log/trivial.hpp>
 #include <boost/nowide/cstdio.hpp>
 #include <boost/detail/endian.hpp>
 
@@ -107,65 +108,47 @@ Normals fixed         : %5d\n", stl->stats.normals_fixed);
 
 bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
 {
-  char      *error_msg;
+	FILE *fp = boost::nowide::fopen(file, "w");
+  	if (fp == NULL) {
+		BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
+    	return false;
+  	}
 
-  /* Open the file */
-  FILE *fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return false;
-  }
+	fprintf(fp, "solid  %s\n", label);
 
-  fprintf(fp, "solid  %s\n", label);
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+		fprintf(fp, "  facet normal % .8E % .8E % .8E\n",
+	        stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
+	        stl->facet_start[i].normal(2));
+		fprintf(fp, "    outer loop\n");
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
+	        stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
+	        stl->facet_start[i].vertex[0](2));
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
+	        stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
+	        stl->facet_start[i].vertex[1](2));
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
+	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+	        stl->facet_start[i].vertex[2](2));
+		fprintf(fp, "    endloop\n");
+		fprintf(fp, "  endfacet\n");
+	}
 
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-    fprintf(fp, "  facet normal % .8E % .8E % .8E\n",
-            stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
-            stl->facet_start[i].normal(2));
-    fprintf(fp, "    outer loop\n");
-    fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
-            stl->facet_start[i].vertex[0](2));
-    fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
-            stl->facet_start[i].vertex[1](2));
-    fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-            stl->facet_start[i].vertex[2](2));
-    fprintf(fp, "    endloop\n");
-    fprintf(fp, "  endfacet\n");
-  }
-
-  fprintf(fp, "endsolid  %s\n", label);
-
-  fclose(fp);
-  return true;
+  	fprintf(fp, "endsolid  %s\n", label);
+  	fclose(fp);
+  	return true;
 }
 
 bool stl_print_neighbors(stl_file *stl, char *file)
 {
-  FILE *fp;
-  char *error_msg;
+	FILE *fp = boost::nowide::fopen(file, "w");
+	if (fp == NULL) {
+		BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing";
+    	return false;
+  	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return false;
-  }
-
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+    	fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
             i,
             stl->neighbors_start[i].neighbor[0],
             (int)stl->neighbors_start[i].which_vertex_not[0],
@@ -173,62 +156,54 @@ bool stl_print_neighbors(stl_file *stl, char *file)
             (int)stl->neighbors_start[i].which_vertex_not[1],
             stl->neighbors_start[i].neighbor[2],
             (int)stl->neighbors_start[i].which_vertex_not[2]);
-  }
-  fclose(fp);
-  return true;
+  	}
+  	fclose(fp);
+  	return true;
 }
 
 #ifndef BOOST_LITTLE_ENDIAN
 // Swap a buffer of 32bit data from little endian to big endian and vice versa.
 void stl_internal_reverse_quads(char *buf, size_t cnt)
 {
-  for (size_t i = 0; i < cnt; i += 4) {
-    std::swap(buf[i], buf[i+3]);
-    std::swap(buf[i+1], buf[i+2]);
-  }
+	for (size_t i = 0; i < cnt; i += 4) {
+		std::swap(buf[i], buf[i+3]);
+		std::swap(buf[i+1], buf[i+2]);
+	}
 }
 #endif
 
 bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 {
-  FILE      *fp;
-  char      *error_msg;
+	FILE *fp = boost::nowide::fopen(file, "wb");
+	if (fp == NULL) {
+		BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing";
+    	return false;
+  	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "wb");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return false;
-  }
+	fprintf(fp, "%s", label);
+	for (size_t i = strlen(label); i < LABEL_SIZE; ++ i)
+		putc(0, fp);
 
-  fprintf(fp, "%s", label);
-  for(size_t i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
-
-  fseek(fp, LABEL_SIZE, SEEK_SET);
+	fseek(fp, LABEL_SIZE, SEEK_SET);
 #ifdef BOOST_LITTLE_ENDIAN
-  fwrite(&stl->stats.number_of_facets, 4, 1, fp);
-  for (const stl_facet &facet : stl->facet_start)
-	  fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
+	fwrite(&stl->stats.number_of_facets, 4, 1, fp);
+	for (const stl_facet &facet : stl->facet_start)
+	  	fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
 #else /* BOOST_LITTLE_ENDIAN */
-  char buffer[50];
-  // Convert the number of facets to little endian.
-  memcpy(buffer, &stl->stats.number_of_facets, 4);
-  stl_internal_reverse_quads(buffer, 4);
-  fwrite(buffer, 4, 1, fp);
-  for (i = 0; i < stl->stats.number_of_facets; ++ i) {
-    memcpy(buffer, stl->facet_start + i, 50);
-    // Convert to little endian.
-    stl_internal_reverse_quads(buffer, 48);
-    fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
-  }
+	char buffer[50];
+	// Convert the number of facets to little endian.
+	memcpy(buffer, &stl->stats.number_of_facets, 4);
+	stl_internal_reverse_quads(buffer, 4);
+	fwrite(buffer, 4, 1, fp);
+	for (i = 0; i < stl->stats.number_of_facets; ++ i) {
+		memcpy(buffer, stl->facet_start + i, 50);
+		// Convert to little endian.
+		stl_internal_reverse_quads(buffer, 48);
+		fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
+	}
 #endif /* BOOST_LITTLE_ENDIAN */
-  fclose(fp);
-  return true;
+	fclose(fp);
+	return true;
 }
 
 void stl_write_vertex(stl_file *stl, int facet, int vertex)
@@ -260,53 +235,39 @@ void stl_write_neighbor(stl_file *stl, int facet)
 
 bool stl_write_quad_object(stl_file *stl, char *file)
 {
-  FILE      *fp;
-  char      *error_msg;
-  stl_vertex connect_color = stl_vertex::Zero();
-  stl_vertex uncon_1_color = stl_vertex::Zero();
-  stl_vertex uncon_2_color = stl_vertex::Zero();
-  stl_vertex uncon_3_color = stl_vertex::Zero();
-  stl_vertex color;
+	stl_vertex connect_color = stl_vertex::Zero();
+	stl_vertex uncon_1_color = stl_vertex::Zero();
+	stl_vertex uncon_2_color = stl_vertex::Zero();
+	stl_vertex uncon_3_color = stl_vertex::Zero();
+	stl_vertex color;
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return false;
-  }
+	FILE *fp = boost::nowide::fopen(file, "w");
+	if (fp == NULL) {
+		BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
+		return false;
+	}
 
-  fprintf(fp, "CQUAD\n");
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    int j = ((stl->neighbors_start[i].neighbor[0] == -1) +
-             (stl->neighbors_start[i].neighbor[1] == -1) +
-             (stl->neighbors_start[i].neighbor[2] == -1));
-    if(j == 0) {
-      color = connect_color;
-    } else if(j == 1) {
-      color = uncon_1_color;
-    } else if(j == 2) {
-      color = uncon_2_color;
-    } else {
-      color = uncon_3_color;
-    }
-    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
+  	fprintf(fp, "CQUAD\n");
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+  		switch (stl->neighbors_start[i].num_neighbors_missing()) {
+  		case 0: color = connect_color; break;
+    	case 1: color = uncon_1_color; break;
+    	case 2: color = uncon_2_color; break;
+    	default: color = uncon_3_color;
+	    }
+	    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
             stl->facet_start[i].vertex[0](0),
             stl->facet_start[i].vertex[0](1),
             stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
-    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
             stl->facet_start[i].vertex[1](0),
             stl->facet_start[i].vertex[1](1),
             stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
-    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
             stl->facet_start[i].vertex[2](0),
             stl->facet_start[i].vertex[2](1),
             stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
-    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
             stl->facet_start[i].vertex[2](0),
             stl->facet_start[i].vertex[2](1),
             stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
@@ -317,47 +278,37 @@ bool stl_write_quad_object(stl_file *stl, char *file)
 
 bool stl_write_dxf(stl_file *stl, const char *file, char *label) 
 {
-  FILE      *fp;
-  char      *error_msg;
+	FILE *fp = boost::nowide::fopen(file, "w");
+	if (fp == NULL) {
+		BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
+    	return false;
+  	}
 
-  /* Open the file */
-  fp = boost::nowide::fopen(file, "w");
-  if(fp == NULL) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return false;
-  }
+	fprintf(fp, "999\n%s\n", label);
+	fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
+	fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
+	0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
+	fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
 
-  fprintf(fp, "999\n%s\n", label);
-  fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
-  fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
-0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
-  fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
+	fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
 
-  fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+		fprintf(fp, "0\n3DFACE\n8\n0\n");
+		fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
+	        stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
+	        stl->facet_start[i].vertex[0](2));
+		fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
+	        stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
+	        stl->facet_start[i].vertex[1](2));
+		fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
+	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+	        stl->facet_start[i].vertex[2](2));
+		fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
+	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
+	        stl->facet_start[i].vertex[2](2));
+	}
 
-  for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    fprintf(fp, "0\n3DFACE\n8\n0\n");
-    fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
-            stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
-            stl->facet_start[i].vertex[0](2));
-    fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
-            stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
-            stl->facet_start[i].vertex[1](2));
-    fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
-            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-            stl->facet_start[i].vertex[2](2));
-    fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
-            stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-            stl->facet_start[i].vertex[2](2));
-  }
-
-  fprintf(fp, "0\nENDSEC\n0\nEOF\n");
-
-  fclose(fp);
-  return true;
+  	fprintf(fp, "0\nENDSEC\n0\nEOF\n");
+  	fclose(fp);
+  	return true;
 }
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 44477511f..24fbe9edc 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -26,6 +26,7 @@
 #include <math.h>
 #include <assert.h>
 
+#include <boost/log/trivial.hpp>
 #include <boost/nowide/cstdio.hpp>
 #include <boost/detail/endian.hpp>
 
@@ -37,118 +38,102 @@
 
 static FILE* stl_open_count_facets(stl_file *stl, const char *file) 
 {
-  long           file_size;
-  uint32_t       header_num_facets;
-  uint32_t       num_facets;
-  int            i;
-  size_t         s;
-  unsigned char  chtest[128];
-  int            num_lines = 1;
-  char           *error_msg;
+  	// Open the file in binary mode first.
+  	FILE *fp = boost::nowide::fopen(file, "rb");
+  	if (fp == nullptr) {
+		BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
+    	return nullptr;
+  	}
+  	// Find size of file.
+  	fseek(fp, 0, SEEK_END);
+  	long file_size = ftell(fp);
 
-  /* Open the file in binary mode first */
-  FILE *fp = boost::nowide::fopen(file, "rb");
-  if (fp == nullptr) {
-    error_msg = (char*)
-                malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-    sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
-            file);
-    perror(error_msg);
-    free(error_msg);
-    return nullptr;
-  }
-  /* Find size of file */
-  fseek(fp, 0, SEEK_END);
-  file_size = ftell(fp);
+  	// Check for binary or ASCII file.
+  	fseek(fp, HEADER_SIZE, SEEK_SET);
+	unsigned char chtest[128];
+  	if (! fread(chtest, sizeof(chtest), 1, fp)) {
+		BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file;
+    	fclose(fp);
+    	return nullptr;
+  	}
+  	stl->stats.type = ascii;
+  	for (size_t s = 0; s < sizeof(chtest); s++) {
+    	if (chtest[s] > 127) {
+      		stl->stats.type = binary;
+      		break;
+    	}
+  	}
+  	rewind(fp);
 
-  /* Check for binary or ASCII file */
-  fseek(fp, HEADER_SIZE, SEEK_SET);
-  if (!fread(chtest, sizeof(chtest), 1, fp)) {
-    perror("The input is an empty file");
-    fclose(fp);
-    return nullptr;
-  }
-  stl->stats.type = ascii;
-  for(s = 0; s < sizeof(chtest); s++) {
-    if(chtest[s] > 127) {
-      stl->stats.type = binary;
-      break;
-    }
-  }
-  rewind(fp);
+  	uint32_t num_facets = 0;
 
-  /* Get the header and the number of facets in the .STL file */
-  /* If the .STL file is binary, then do the following */
-  if(stl->stats.type == binary) {
-    /* Test if the STL file has the right size  */
-    if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
-        || (file_size < STL_MIN_FILE_SIZE)) {
-      fprintf(stderr, "The file %s has the wrong size.\n", file);
-      fclose(fp);
-      return nullptr;
-    }
-    num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
+  	// Get the header and the number of facets in the .STL file.
+  	// If the .STL file is binary, then do the following:
+  	if (stl->stats.type == binary) {
+    	// Test if the STL file has the right size.
+    	if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) {
+			BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size.";
+      		fclose(fp);
+      		return nullptr;
+    	}
+    	num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
 
-    /* Read the header */
-    if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79) {
-      stl->stats.header[80] = '\0';
-    }
+    	// Read the header.
+    	if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79)
+      		stl->stats.header[80] = '\0';
 
-    /* Read the int following the header.  This should contain # of facets */
-    bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
+    	// Read the int following the header.  This should contain # of facets.
+	  	uint32_t header_num_facets;
+    	bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
 #ifndef BOOST_LITTLE_ENDIAN
-    // Convert from little endian to big endian.
-    stl_internal_reverse_quads((char*)&header_num_facets, 4);
+    	// Convert from little endian to big endian.
+    	stl_internal_reverse_quads((char*)&header_num_facets, 4);
 #endif /* BOOST_LITTLE_ENDIAN */
-    if (! header_num_faces_read || num_facets != header_num_facets) {
-      fprintf(stderr,
-              "Warning: File size doesn't match number of facets in the header\n");
-    }
-  }
-  /* Otherwise, if the .STL file is ASCII, then do the following */
-  else {
-    /* Reopen the file in text mode (for getting correct newlines on Windows) */
-    // fix to silence a warning about unused return value.
-    // obviously if it fails we have problems....
-    fp = boost::nowide::freopen(file, "r", fp);
+    	if (! header_num_faces_read || num_facets != header_num_facets)
+			BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file;
+  	}
+  	// Otherwise, if the .STL file is ASCII, then do the following:
+  	else
+  	{
+    	// Reopen the file in text mode (for getting correct newlines on Windows)
+    	// fix to silence a warning about unused return value.
+    	// obviously if it fails we have problems....
+    	fp = boost::nowide::freopen(file, "r", fp);
 
-    // do another null check to be safe
-    if(fp == nullptr) {
-      error_msg = (char*)
-        malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
-      sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
-          file);
-      perror(error_msg);
-      free(error_msg);
-      fclose(fp);
-      return nullptr;
-    }
+		// do another null check to be safe
+    	if (fp == nullptr) {
+			BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
+      		fclose(fp);
+      		return nullptr;
+    	}
     
-    /* Find the number of facets */
-    char linebuf[100];
-    while (fgets(linebuf, 100, fp) != nullptr) {
-        /* don't count short lines */
-        if (strlen(linebuf) <= 4) continue;
-        
-        /* skip solid/endsolid lines as broken STL file generators may put several of them */
-        if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) continue;
-        
-        ++num_lines;
-    }
-    
-    rewind(fp);
-    
-    /* Get the header */
-    for(i = 0;
-        (i < 80) && (stl->stats.header[i] = getc(fp)) != '\n'; i++);
-    stl->stats.header[i] = '\0'; /* Lose the '\n' */
-    stl->stats.header[80] = '\0';
+    	// Find the number of facets.
+		char linebuf[100];
+		int num_lines = 1;
+		while (fgets(linebuf, 100, fp) != nullptr) {
+		    // Don't count short lines.
+		    if (strlen(linebuf) <= 4)
+		    	continue;
+		    // Skip solid/endsolid lines as broken STL file generators may put several of them.
+		    if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0)
+		    	continue;
+		    ++ num_lines;
+		}
 
-    num_facets = num_lines / ASCII_LINES_PER_FACET;
-  }
-  stl->stats.number_of_facets += num_facets;
-  stl->stats.original_num_facets = stl->stats.number_of_facets;
-  return fp;
+    	rewind(fp);
+    
+    	// Get the header.
+		int i = 0;
+    	for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ;
+    	stl->stats.header[i] = '\0'; // Lose the '\n'
+    	stl->stats.header[80] = '\0';
+
+    	num_facets = num_lines / ASCII_LINES_PER_FACET;
+  	}
+
+  	stl->stats.number_of_facets += num_facets;
+  	stl->stats.original_num_facets = stl->stats.number_of_facets;
+  	return fp;
 }
 
 /* Reads the contents of the file pointed to by fp into the stl structure,
@@ -156,85 +141,82 @@ static FILE* stl_open_count_facets(stl_file *stl, const char *file)
    time running this for the stl and therefore we should reset our max and min stats. */
 static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
 {
-  stl_facet facet;
+	if (stl->stats.type == binary)
+    	fseek(fp, HEADER_SIZE, SEEK_SET);
+  	else
+    	rewind(fp);
 
-  if(stl->stats.type == binary) {
-    fseek(fp, HEADER_SIZE, SEEK_SET);
-  } else {
-    rewind(fp);
-  }
+  	char normal_buf[3][32];
+  	for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++i) {
+  	  	stl_facet facet;
 
-  char normal_buf[3][32];
-  for(uint32_t i = first_facet; i < stl->stats.number_of_facets; i++) {
-    if(stl->stats.type == binary)
-      /* Read a single facet from a binary .STL file */
-    {
-      /* we assume little-endian architecture! */
-      if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
-      	return false;
+    	if (stl->stats.type == binary) {
+      		// Read a single facet from a binary .STL file. We assume little-endian architecture!
+      		if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
+      			return false;
 #ifndef BOOST_LITTLE_ENDIAN
-      // Convert the loaded little endian data to big endian.
-      stl_internal_reverse_quads((char*)&facet, 48);
+      		// Convert the loaded little endian data to big endian.
+      		stl_internal_reverse_quads((char*)&facet, 48);
 #endif /* BOOST_LITTLE_ENDIAN */
-    } else
-      /* Read a single facet from an ASCII .STL file */
-    {
-      // skip solid/endsolid
-      // (in this order, otherwise it won't work when they are paired in the middle of a file)
-      fscanf(fp, "endsolid%*[^\n]\n");
-      fscanf(fp, "solid%*[^\n]\n");  // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
-      // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
-      int res_normal     = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
-      assert(res_normal == 3);
-      int res_outer_loop = fscanf(fp, " outer loop");
-      assert(res_outer_loop == 0);
-      int res_vertex1    = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
-      assert(res_vertex1 == 3);
-      int res_vertex2    = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
-      assert(res_vertex2 == 3);
-      int res_vertex3    = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
-      assert(res_vertex3 == 3);
-      int res_endloop    = fscanf(fp, " endloop");
-      assert(res_endloop == 0);
-      // There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
-      int res_endfacet   = fscanf(fp, " endfacet ");
-      if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
-        perror("Something is syntactically very wrong with this ASCII STL!");
-        return false;
-      }
+    	} else {
+			// Read a single facet from an ASCII .STL file
+			// skip solid/endsolid
+			// (in this order, otherwise it won't work when they are paired in the middle of a file)
+			fscanf(fp, "endsolid%*[^\n]\n");
+			fscanf(fp, "solid%*[^\n]\n");  // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
+			// Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
+			int res_normal     = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
+			assert(res_normal == 3);
+			int res_outer_loop = fscanf(fp, " outer loop");
+			assert(res_outer_loop == 0);
+			int res_vertex1    = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
+			assert(res_vertex1 == 3);
+			int res_vertex2    = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
+			assert(res_vertex2 == 3);
+			int res_vertex3    = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
+			assert(res_vertex3 == 3);
+			int res_endloop    = fscanf(fp, " endloop");
+			assert(res_endloop == 0);
+			// There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
+			int res_endfacet   = fscanf(fp, " endfacet ");
+			if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
+				BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! ";
+				return false;
+			}
 
-      // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
-	  if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
-		  sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
-		  sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
-		  // Normal was mangled. Maybe denormals or "not a number" were stored?
-		  // Just reset the normal and silently ignore it.
-		  memset(&facet.normal, 0, sizeof(facet.normal));
-	  }
-    }
+			// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
+			if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
+			    sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
+			    sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
+			    // Normal was mangled. Maybe denormals or "not a number" were stored?
+			  	// Just reset the normal and silently ignore it.
+			  	memset(&facet.normal, 0, sizeof(facet.normal));
+			}
+		}
 
 #if 0
-      // Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
-      // close to zero values may be represented with singificantly higher precision than the rest of the vertices.
-      // It may be worth to round these numbers to zero during loading to reduce the number of errors reported
-      // during the STL import.
-      for (size_t j = 0; j < 3; ++ j) {
-        if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
-            printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
-        if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
-            printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
-        if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
-            printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
-      }
+		// Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
+		// close to zero values may be represented with singificantly higher precision than the rest of the vertices.
+		// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
+		// during the STL import.
+		for (size_t j = 0; j < 3; ++ j) {
+		if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
+		    printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
+		if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
+		    printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
+		if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
+		    printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
+		}
 #endif
 
-    /* Write the facet into memory. */
-    stl->facet_start[i] = facet;
-    stl_facet_stats(stl, facet, first);
-  }
-  stl->stats.size = stl->stats.max - stl->stats.min;
-  stl->stats.bounding_diameter = stl->stats.size.norm();
-  return true;
+		// Write the facet into memory.
+		stl->facet_start[i] = facet;
+		stl_facet_stats(stl, facet, first);
+  	}
+  
+  	stl->stats.size = stl->stats.max - stl->stats.min;
+  	stl->stats.bounding_diameter = stl->stats.size.norm();
+  	return true;
 }
 
 bool stl_open(stl_file *stl, const char *file)
@@ -277,21 +259,21 @@ void stl_reallocate(stl_file *stl)
 
 void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
 {
-  // While we are going through all of the facets, let's find the
-  // maximum and minimum values for x, y, and z
+	// While we are going through all of the facets, let's find the
+	// maximum and minimum values for x, y, and z
 
-  if (first) {
-	// Initialize the max and min values the first time through
-    stl->stats.min = facet.vertex[0];
-    stl->stats.max = facet.vertex[0];
-    stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
-    stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
-    first = false;
-  }
+	if (first) {
+		// Initialize the max and min values the first time through
+		stl->stats.min = facet.vertex[0];
+		stl->stats.max = facet.vertex[0];
+		stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
+		stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
+		first = false;
+	}
 
-  // Now find the max and min values.
-  for (size_t i = 0; i < 3; ++ i) {
-  	stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
-  	stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
-  }
+	// Now find the max and min values.
+	for (size_t i = 0; i < 3; ++ i) {
+		stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
+		stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
+	}
 }
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index f4e4dbf0a..bb135db95 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -25,13 +25,14 @@
 #include <string.h>
 #include <math.h>
 
+#include <boost/log/trivial.hpp>
+
 #include "stl.h"
 
 static void stl_rotate(float *x, float *y, const double c, const double s);
 static float get_area(stl_facet *facet);
 static float get_volume(stl_file *stl);
 
-
 void stl_verify_neighbors(stl_file *stl)
 {
 	stl->stats.backwards_edges = 0;
@@ -56,7 +57,7 @@ void stl_verify_neighbors(stl_file *stl)
 			}
 			if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
 				// These edges should match but they don't.  Print results.
-				printf("edge %d of facet %d doesn't match edge %d of facet %d\n", j, i, vnot + 1, neighbor);
+				BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor;
 				stl_write_facet(stl, (char*)"first facet", i);
 				stl_write_facet(stl, (char*)"second facet", neighbor);
 			}
@@ -291,123 +292,104 @@ static float get_area(stl_facet *facet)
   return 0.5f * n.dot(sum);
 }
 
-void stl_repair(stl_file *stl,
-                int fixall_flag,
-                int exact_flag,
-                int tolerance_flag,
-                float tolerance,
-                int increment_flag,
-                float increment,
-                int nearby_flag,
-                int iterations,
-                int remove_unconnected_flag,
-                int fill_holes_flag,
-                int normal_directions_flag,
-                int normal_values_flag,
-                int reverse_all_flag,
-                int verbose_flag) {
-  
-  int i;
-  int last_edges_fixed = 0;
+void stl_repair(
+	stl_file *stl,
+	bool fixall_flag,
+	bool exact_flag,
+	bool tolerance_flag,
+	float tolerance,
+	bool increment_flag,
+	float increment,
+	bool nearby_flag,
+	int iterations,
+	bool remove_unconnected_flag,
+	bool fill_holes_flag,
+	bool normal_directions_flag,
+	bool normal_values_flag,
+	bool reverse_all_flag,
+	bool verbose_flag)
+{
+	if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) {
+		if (verbose_flag)
+		  	printf("Checking exact...\n");
+		exact_flag = true;
+		stl_check_facets_exact(stl);
+		stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
+		stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
+		stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
+	}
 
-  if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag
-      || fill_holes_flag || normal_directions_flag) {
-    if (verbose_flag)
-      printf("Checking exact...\n");
-    exact_flag = 1;
-    stl_check_facets_exact(stl);
-    stl->stats.facets_w_1_bad_edge =
-      (stl->stats.connected_facets_2_edge -
-       stl->stats.connected_facets_3_edge);
-    stl->stats.facets_w_2_bad_edge =
-      (stl->stats.connected_facets_1_edge -
-       stl->stats.connected_facets_2_edge);
-    stl->stats.facets_w_3_bad_edge =
-      (stl->stats.number_of_facets -
-       stl->stats.connected_facets_1_edge);
-  }
-
-  if(nearby_flag || fixall_flag) {
-    if(!tolerance_flag) {
-      tolerance = stl->stats.shortest_edge;
-    }
-    if(!increment_flag) {
-      increment = stl->stats.bounding_diameter / 10000.0;
+  	if (nearby_flag || fixall_flag) {
+    	if (! tolerance_flag)
+      		tolerance = stl->stats.shortest_edge;
+ 	   	if (! increment_flag)
+      		increment = stl->stats.bounding_diameter / 10000.0;
     }
 
-    if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
-      for(i = 0; i < iterations; i++) {
-        if(stl->stats.connected_facets_3_edge <
-            stl->stats.number_of_facets) {
-          if (verbose_flag)
-            printf("\
-Checking nearby. Tolerance= %f Iteration=%d of %d...",
-                 tolerance, i + 1, iterations);
-          stl_check_facets_nearby(stl, tolerance);
-          if (verbose_flag)
-            printf("  Fixed %d edges.\n",
-                 stl->stats.edges_fixed - last_edges_fixed);
-          last_edges_fixed = stl->stats.edges_fixed;
-          tolerance += increment;
-        } else {
-          if (verbose_flag)
-            printf("\
-All facets connected.  No further nearby check necessary.\n");
-          break;
-        }
-      }
-    } else {
-      if (verbose_flag)
-        printf("All facets connected.  No nearby check necessary.\n");
-    }
-  }
+	if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
+	  	int last_edges_fixed = 0;
+	  	for (int i = 0; i < iterations; ++ i) {
+	    	if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
+	      		if (verbose_flag)
+	        		printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
+	      		stl_check_facets_nearby(stl, tolerance);
+	      		if (verbose_flag)
+	        		printf("  Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed);
+	      		last_edges_fixed = stl->stats.edges_fixed;
+	      		tolerance += increment;
+	    	} else {
+	    		if (verbose_flag)
+	        		printf("All facets connected.  No further nearby check necessary.\n");
+		      	break;
+		    }
+	  	}
+	} else if (verbose_flag)
+	    printf("All facets connected.  No nearby check necessary.\n");
 
-  if(remove_unconnected_flag || fixall_flag || fill_holes_flag) {
-    if(stl->stats.connected_facets_3_edge <  stl->stats.number_of_facets) {
-      if (verbose_flag)
-        printf("Removing unconnected facets...\n");
-      stl_remove_unconnected_facets(stl);
-    } else
-      if (verbose_flag)
-        printf("No unconnected need to be removed.\n");
-  }
+	if (remove_unconnected_flag || fixall_flag || fill_holes_flag) {
+		if (stl->stats.connected_facets_3_edge <  stl->stats.number_of_facets) {
+	  		if (verbose_flag)
+	    		printf("Removing unconnected facets...\n");
+	  		stl_remove_unconnected_facets(stl);
+		} else if (verbose_flag)
+	    	printf("No unconnected need to be removed.\n");
+	}
 
-  if(fill_holes_flag || fixall_flag) {
-    if(stl->stats.connected_facets_3_edge <  stl->stats.number_of_facets) {
-      if (verbose_flag)
-        printf("Filling holes...\n");
-      stl_fill_holes(stl);
-    } else
-      if (verbose_flag)
-        printf("No holes need to be filled.\n");
-  }
+	if (fill_holes_flag || fixall_flag) {
+		if (stl->stats.connected_facets_3_edge <  stl->stats.number_of_facets) {
+	  		if (verbose_flag)
+	    		printf("Filling holes...\n");
+	  		stl_fill_holes(stl);
+		} else if (verbose_flag)
+	    	printf("No holes need to be filled.\n");
+	}
 
-  if(reverse_all_flag) {
-    if (verbose_flag)
-      printf("Reversing all facets...\n");
-    stl_reverse_all_facets(stl);
-  }
+	if (reverse_all_flag) {
+		if (verbose_flag)
+	  		printf("Reversing all facets...\n");
+		stl_reverse_all_facets(stl);
+	}
 
-  if(normal_directions_flag || fixall_flag) {
-    if (verbose_flag)
-      printf("Checking normal directions...\n");
-    stl_fix_normal_directions(stl);
-  }
+	if (normal_directions_flag || fixall_flag) {
+		if (verbose_flag)
+	  		printf("Checking normal directions...\n");
+		stl_fix_normal_directions(stl);
+	}
 
-  if(normal_values_flag || fixall_flag) {
-    if (verbose_flag)
-      printf("Checking normal values...\n");
-    stl_fix_normal_values(stl);
-  }
+	if (normal_values_flag || fixall_flag) {
+		if (verbose_flag)
+	  		printf("Checking normal values...\n");
+		stl_fix_normal_values(stl);
+	}
 
-  /* Always calculate the volume.  It shouldn't take too long */
-  if (verbose_flag)
-    printf("Calculating volume...\n");
-  stl_calculate_volume(stl);
+  	// Always calculate the volume.  It shouldn't take too long.
+	if (verbose_flag)
+		printf("Calculating volume...\n");
+	stl_calculate_volume(stl);
 
-  if(exact_flag) {
-    if (verbose_flag)
-      printf("Verifying neighbors...\n");
-    stl_verify_neighbors(stl);
-  }
+	if (exact_flag) {
+		if (verbose_flag)
+	  		printf("Verifying neighbors...\n");
+		stl_verify_neighbors(stl);
+	}
 }
diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp
index 45092f257..b28cb2eda 100644
--- a/src/slic3r/GUI/PresetBundle.cpp
+++ b/src/slic3r/GUI/PresetBundle.cpp
@@ -837,7 +837,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const
                     return preset_name_dst;
                 // Try to generate another name.
                 char buf[64];
-                sprintf(buf, " (%d)", i);
+                sprintf(buf, " (%d)", (int)i);
                 preset_name_dst = preset_name_src + buf + bundle_name;
             }
         }

From af5017c46c42305553e42f95c4f62c2cbe27d607 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 21:14:58 +0200
Subject: [PATCH 10/22] admesh refactoring: Use Eigen vec3i for indexed
 triangles.

---
 src/admesh/connect.cpp         |  10 +-
 src/admesh/normals.cpp         | 308 +++++++++++++++----------------
 src/admesh/shared.cpp          |  20 +-
 src/admesh/stl.h               |  17 +-
 src/admesh/stl_io.cpp          | 170 ++++++-----------
 src/admesh/util.cpp            | 321 +++++++++++++++------------------
 src/libslic3r/Format/3mf.cpp   |   2 +-
 src/libslic3r/Format/AMF.cpp   |   2 +-
 src/libslic3r/TriangleMesh.cpp |   6 +-
 xs/xsp/TriangleMesh.xsp        |   6 +-
 10 files changed, 369 insertions(+), 493 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 5ae03597e..cbd4f1d33 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -196,13 +196,13 @@ struct HashTableEdges {
 
 	// Hash table on edges
 	std::vector<HashEdge*> 	heads;
-	HashEdge* 					tail;
-	int           					M;
+	HashEdge* 				tail;
+	int           			M;
 
 #ifndef NDEBUG
-	size_t 							malloced   	= 0;
-	size_t 							freed 	  	= 0;
-	size_t 							collisions 	= 0;
+	size_t 					malloced   	= 0;
+	size_t 					freed 	  	= 0;
+	size_t 					collisions 	= 0;
 #endif /* NDEBUG */
 
 private:
diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp
index f20d9e68e..464f9e6d8 100644
--- a/src/admesh/normals.cpp
+++ b/src/admesh/normals.cpp
@@ -27,19 +27,16 @@
 
 #include "stl.h"
 
-static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
-
 static void reverse_facet(stl_file *stl, int facet_num)
 {
-	stl->stats.facets_reversed += 1;
+	++ stl->stats.facets_reversed;
 
 	int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] };
 	int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] };
 
 	// reverse the facet
 	stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0];
-	stl->facet_start[facet_num].vertex[0] =
-	stl->facet_start[facet_num].vertex[1];
+	stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1];
 	stl->facet_start[facet_num].vertex[1] = tmp_vertex;
 
 	// fix the vnots of the neighboring facets
@@ -64,187 +61,164 @@ static void reverse_facet(stl_file *stl, int facet_num)
 	stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
 }
 
-void stl_fix_normal_directions(stl_file *stl)
+// Returns true if the normal was flipped.
+static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
 {
-  /*  int edge_num;*/
-  /*  int vnot;*/
-  int checked = 0;
-  int facet_num;
-  /*  int next_facet;*/
-  int i;
-  int j;
-  struct stl_normal {
-    int               facet_num;
-    struct stl_normal *next;
-  };
-  struct stl_normal *head;
-  struct stl_normal *tail;
-  struct stl_normal *newn;
-  struct stl_normal *temp;
+	stl_facet *facet = &stl->facet_start[facet_num];
 
-  int reversed_count = 0;
-  int id;
-  int force_exit = 0;
+	stl_normal normal;
+	stl_calculate_normal(normal, facet);
+	stl_normalize_vector(normal);
+	stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
 
-  // this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
-  if (stl->stats.number_of_facets == 0) return;
+	const float eps = 0.001f;
+	if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
+		// Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will.
+		facet->normal = normal;
+		return false;
+	}
 
-  /* Initialize linked list. */
-  head = new stl_normal;
-  tail = new stl_normal;
-  head->next = tail;
-  tail->next = tail;
+	stl_normal test_norm = facet->normal;
+	stl_normalize_vector(test_norm);
+	normal_dif = (normal - test_norm).cwiseAbs();
+	if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
+		// The normal is not within tolerance, but direction is OK.
+		if (normal_fix_flag) {
+	  		facet->normal = normal;
+	  		++ stl->stats.normals_fixed;
+		}
+		return false;
+	}
 
-  /* Initialize list that keeps track of already fixed facets. */
-  std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
-  /* Initialize list that keeps track of reversed facets. */
-  std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
-
-  facet_num = 0;
-  /* If normal vector is not within tolerance and backwards:
-     Arbitrarily starts at face 0.  If this one is wrong, we're screwed.  Thankfully, the chances
-     of it being wrong randomly are low if most of the triangles are right: */
-  if (stl_check_normal_vector(stl, 0, 0) == 2) {
-      reverse_facet(stl, 0);
-      reversed_ids[reversed_count++] = 0;
-  }
-
-  /* Say that we've fixed this facet: */
-  norm_sw[facet_num] = 1;
-  checked++;
-
-  for(;;) {
-    /* Add neighbors_to_list.
-       Add unconnected neighbors to the list:a  */
-    for(j = 0; j < 3; j++) {
-      /* Reverse the neighboring facets if necessary. */
-      if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
-        /* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
-        if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
-            if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
-                /* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */
-                for (id = reversed_count - 1; id >= 0; --id) {
-                    reverse_facet(stl, reversed_ids[id]);
-                }
-                force_exit = 1;
-                break;
-            } else {
-                reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
-                reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j];
-            }
-        }
-      }
-      /* If this edge of the facet is connected: */
-      if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
-        /* If we haven't fixed this facet yet, add it to the list: */
-        if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
-          /* Add node to beginning of list. */
-          newn = new stl_normal;
-          newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
-          newn->next = head->next;
-          head->next = newn;
-        }
-      }
-    }
-
-    /* an error occourred, quit the for loop and exit */
-    if (force_exit) break;
-
-    /* Get next facet to fix from top of list. */
-    if(head->next != tail) {
-      facet_num = head->next->facet_num;
-      if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */
-        norm_sw[facet_num] = 1; /* Record this one as being fixed. */
-        checked++;
-      }
-      temp = head->next;	/* Delete this facet from the list. */
-      head->next = head->next->next;
-      delete temp;
-    } else { /* if we ran out of facets to fix: */
-      /* All of the facets in this part have been fixed. */
-      stl->stats.number_of_parts += 1;
-      if(checked >= stl->stats.number_of_facets) {
-        /* All of the facets have been checked.  Bail out. */
-        break;
-      } else {
-        /* There is another part here.  Find it and continue. */
-        for(i = 0; i < stl->stats.number_of_facets; i++) {
-          if(norm_sw[i] == 0) {
-            /* This is the first facet of the next part. */
-            facet_num = i;
-            if(stl_check_normal_vector(stl, i, 0) == 2) {
-                reverse_facet(stl, i);
-                reversed_ids[reversed_count++] = i;
-            }
-
-            norm_sw[facet_num] = 1;
-            checked++;
-            break;
-          }
-        }
-      }
-    }
-  }
-  delete head;
-  delete tail;
+	test_norm *= -1.f;
+	normal_dif = (normal - test_norm).cwiseAbs();
+	if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
+		// The normal is not within tolerance and backwards.
+		if (normal_fix_flag) {
+	  		facet->normal = normal;
+	  		++ stl->stats.normals_fixed;
+		}
+		return true;
+	}
+	if (normal_fix_flag) {
+		facet->normal = normal;
+		++ stl->stats.normals_fixed;
+	}
+	// Status is unknown.
+	return false;
 }
 
-static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
+void stl_fix_normal_directions(stl_file *stl)
 {
-  /* Returns 0 if the normal is within tolerance */
-  /* Returns 1 if the normal is not within tolerance, but direction is OK */
-  /* Returns 2 if the normal is not within tolerance and backwards */
-  /* Returns 4 if the status is unknown. */
+ 	// This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
+  	if (stl->stats.number_of_facets == 0)
+  		return;
 
-  stl_facet *facet;
+	struct stl_normal {
+    	int         facet_num;
+    	stl_normal *next;
+  	};
 
-  facet = &stl->facet_start[facet_num];
+  	// Initialize linked list.
+   	stl_normal *head = new stl_normal;
+  	stl_normal *tail = new stl_normal;
+	head->next = tail;
+	tail->next = tail;
 
-  stl_normal normal;
-  stl_calculate_normal(normal, facet);
-  stl_normalize_vector(normal);
-  stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
+	// Initialize list that keeps track of already fixed facets.
+	std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
+	// Initialize list that keeps track of reversed facets.
+	std::vector<int>  reversed_ids(stl->stats.number_of_facets, 0);
 
-  const float eps = 0.001f;
-  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
-    /* It is not really necessary to change the values here */
-    /* but just for consistency, I will. */
-    facet->normal = normal;
-    return 0;
-  }
+  	int facet_num = 0;
+  	int reversed_count = 0;
+  	// If normal vector is not within tolerance and backwards:
+    // Arbitrarily starts at face 0.  If this one is wrong, we're screwed. Thankfully, the chances
+    // of it being wrong randomly are low if most of the triangles are right:
+  	if (check_normal_vector(stl, 0, 0)) {
+    	reverse_facet(stl, 0);
+      	reversed_ids[reversed_count ++] = 0;
+  	}
 
-  stl_normal test_norm = facet->normal;
-  stl_normalize_vector(test_norm);
-  normal_dif = (normal - test_norm).cwiseAbs();
-  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
-    if(normal_fix_flag) {
-      facet->normal = normal;
-      stl->stats.normals_fixed += 1;
-    }
-    return 1;
-  }
+  	// Say that we've fixed this facet:
+  	norm_sw[facet_num] = 1;
+	int checked = 1;
 
-  test_norm *= -1.f;
-  normal_dif = (normal - test_norm).cwiseAbs();
-  if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
-    // Facet is backwards.
-    if(normal_fix_flag) {
-      facet->normal = normal;
-      stl->stats.normals_fixed += 1;
-    }
-    return 2;
-  }
-  if(normal_fix_flag) {
-    facet->normal = normal;
-    stl->stats.normals_fixed += 1;
-  }
-  return 4;
+  	for (;;) {
+    	// Add neighbors_to_list. Add unconnected neighbors to the list.
+    	bool force_exit = false;
+    	for (int j = 0; j < 3; ++ j) {
+      		// Reverse the neighboring facets if necessary.
+      		if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
+        		// If the facet has a neighbor that is -1, it means that edge isn't shared by another facet
+        		if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
+            		if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
+                		// trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
+                		for (int id = reversed_count - 1; id >= 0; -- id)
+                    		reverse_facet(stl, reversed_ids[id]);
+                		force_exit = true;
+                		break;
+            		}
+            		reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
+            		reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j];
+        		}
+      		}
+      		// If this edge of the facet is connected:
+      		if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
+        		// If we haven't fixed this facet yet, add it to the list:
+        		if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
+	          		// Add node to beginning of list.
+	          		stl_normal *newn = new stl_normal;
+	          		newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
+	          		newn->next = head->next;
+	          		head->next = newn;
+	        	}
+	      	}
+	    }
+
+    	// an error occourred, quit the for loop and exit
+    	if (force_exit)
+    		break;
+
+    	// Get next facet to fix from top of list.
+    	if (head->next != tail) {
+      		facet_num = head->next->facet_num;
+      		if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
+        		norm_sw[facet_num] = 1; // Record this one as being fixed.
+        		++ checked;
+      		}
+      		stl_normal *temp = head->next;	// Delete this facet from the list.
+      		head->next = head->next->next;
+      		delete temp;
+    	} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
+      		++ stl->stats.number_of_parts;
+      		if (checked >= stl->stats.number_of_facets)
+        		// All of the facets have been checked.  Bail out.
+        		break;
+    		// There is another part here.  Find it and continue.
+    		for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+      			if (norm_sw[i] == 0) {
+        			// This is the first facet of the next part.
+        			facet_num = i;
+        			if (check_normal_vector(stl, i, 0)) {
+            			reverse_facet(stl, i);
+            			reversed_ids[reversed_count++] = i;
+        			}
+        			norm_sw[facet_num] = 1;
+        			++ checked;
+        			break;
+      			}
+    	}
+  	}
+
+	delete head;
+	delete tail;
 }
 
 void stl_fix_normal_values(stl_file *stl)
 {
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
-    	stl_check_normal_vector(stl, i, 1);
+    	check_normal_vector(stl, i, 1);
 }
 
 void stl_reverse_all_facets(stl_file *stl)
diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index fe6d5e656..78179e863 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -33,7 +33,7 @@
 void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
 {
 	// 3 indices to vertex per face
-	its.indices.assign(stl->stats.number_of_facets, v_indices_struct());
+	its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1));
 	// Shared vertices (3D coordinates)
 	its.vertices.clear();
 	its.vertices.reserve(stl->stats.number_of_facets / 2);
@@ -46,7 +46,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
 
 	for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
 		for (int j = 0; j < 3; ++ j) {
-			if (its.indices[facet_idx].vertex[j] != -1)
+			if (its.indices[facet_idx][j] != -1)
 				// Shared vertex was already assigned.
 				continue;
 			// Create a new shared vertex.
@@ -84,7 +84,7 @@ void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
 			    		next_edge    = pivot_vertex;
 			  		}
 				}
-				its.indices[facet_in_fan_idx].vertex[pivot_vertex] = its.vertices.size() - 1;
+				its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1;
 				fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
 
 				// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
@@ -139,7 +139,7 @@ bool its_write_off(const indexed_triangle_set &its, const char *file)
 	for (int i = 0; i < its.vertices.size(); ++ i)
 		fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
 	for (uint32_t i = 0; i < its.indices.size(); ++ i)
-		fprintf(fp, "\t3 %d %d %d\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
+		fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
 	fclose(fp);
 	return true;
 }
@@ -177,8 +177,8 @@ bool its_write_vrml(const indexed_triangle_set &its, const char *file)
 	fprintf(fp, "\t\t\tcoordIndex [\n");
 
 	for (size_t i = 0; i + 1 < its.indices.size(); ++ i)
-		fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
-	fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i].vertex[0], its.indices[i].vertex[1], its.indices[i].vertex[2]);
+		fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
+	fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
 	fprintf(fp, "\t\t}\n");
 	fprintf(fp, "\t}\n");
 	fprintf(fp, "}\n");
@@ -198,7 +198,7 @@ bool its_write_obj(const indexed_triangle_set &its, const char *file)
 	for (size_t i = 0; i < its.vertices.size(); ++ i)
     	fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
   	for (size_t i = 0; i < its.indices.size(); ++ i)
-    	fprintf(fp, "f %d %d %d\n", its.indices[i].vertex[0]+1, its.indices[i].vertex[1]+1, its.indices[i].vertex[2]+1);
+    	fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1);
   	fclose(fp);
   	return true;
 }
@@ -220,7 +220,7 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
     // Verify validity of neighborship data.
     for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
         const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
-        const int 			*vertices 	= (its.indices.empty()) ? nullptr : its.indices[facet_idx].vertex;
+        const int 			*vertices 	= (its.indices.empty()) ? nullptr : its.indices[facet_idx];
         for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
             int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
             assert(nbr_face < (int)stl->stats.number_of_facets);
@@ -237,10 +237,10 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
 					// Has shared vertices.
 	            	if (nbr_vnot < 3) {
 	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
-						assert((its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
+						assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
 					} else {
 	            		// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
-						assert((its.indices[nbr_face].vertex[(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face].vertex[(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
+						assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
 					}
 				}
             }
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 500d6bfdb..fce23eb3f 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -41,6 +41,7 @@
 
 typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
 typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
+typedef Eigen::Matrix<int,   3, 1, Eigen::DontAlign> stl_triangle_vertex_indices;
 static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
 static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
 
@@ -68,12 +69,6 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec
 
 typedef enum {binary, ascii, inmemory} stl_type;
 
-struct stl_edge {
-	stl_vertex p1;
-	stl_vertex p2;
-	int        facet_number;
-};
-
 struct stl_neighbors {
   	stl_neighbors() { reset(); }
   	void reset() {
@@ -93,12 +88,6 @@ struct stl_neighbors {
   	char  which_vertex_not[3];
 };
 
-struct v_indices_struct {
-	// -1 means no vertex index has been assigned yet
-	v_indices_struct() { vertex[0] = -1; vertex[1] = -1; vertex[2] = -1; }
-  	int   vertex[3];
-};
-
 struct stl_stats {
 	char          header[81];
 	stl_type      type;
@@ -137,8 +126,8 @@ struct stl_file {
 struct indexed_triangle_set
 {
 	void clear() { indices.clear(); vertices.clear(); }
-	std::vector<v_indices_struct> 	indices;
-	std::vector<stl_vertex>       	vertices;
+	std::vector<stl_triangle_vertex_indices> 	indices;
+	std::vector<stl_vertex>       				vertices;
 };
 
 extern bool stl_open(stl_file *stl, const char *file);
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index dc4e4a7db..7e181716c 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -22,94 +22,55 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include "stl.h"
 
 #include <boost/log/trivial.hpp>
 #include <boost/nowide/cstdio.hpp>
 #include <boost/detail/endian.hpp>
 
-#if !defined(SEEK_SET)
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-#endif
+#include "stl.h"
 
 void stl_stats_out(stl_file *stl, FILE *file, char *input_file)
 {
-  /* this is here for Slic3r, without our config.h
-     it won't use this part of the code anyway */
+  	// This is here for Slic3r, without our config.h it won't use this part of the code anyway.
 #ifndef VERSION
 #define VERSION "unknown"
 #endif
-  fprintf(file, "\n\
-================= Results produced by ADMesh version " VERSION " ================\n");
-  fprintf(file, "\
-Input file         : %s\n", input_file);
-  if(stl->stats.type == binary) {
-    fprintf(file, "\
-File type          : Binary STL file\n");
-  } else {
-    fprintf(file, "\
-File type          : ASCII STL file\n");
-  }
-  fprintf(file, "\
-Header             : %s\n", stl->stats.header);
-  fprintf(file, "============== Size ==============\n");
-  fprintf(file, "Min X = % f, Max X = % f\n",
-          stl->stats.min(0), stl->stats.max(0));
-  fprintf(file, "Min Y = % f, Max Y = % f\n",
-          stl->stats.min(1), stl->stats.max(1));
-  fprintf(file, "Min Z = % f, Max Z = % f\n",
-          stl->stats.min(2), stl->stats.max(2));
-
-  fprintf(file, "\
-========= Facet Status ========== Original ============ Final ====\n");
-  fprintf(file, "\
-Number of facets                 : %5d               %5d\n",
-          stl->stats.original_num_facets, stl->stats.number_of_facets);
-  fprintf(file, "\
-Facets with 1 disconnected edge  : %5d               %5d\n",
-          stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge -
-          stl->stats.connected_facets_3_edge);
-  fprintf(file, "\
-Facets with 2 disconnected edges : %5d               %5d\n",
-          stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge -
-          stl->stats.connected_facets_2_edge);
-  fprintf(file, "\
-Facets with 3 disconnected edges : %5d               %5d\n",
-          stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
-          stl->stats.connected_facets_1_edge);
-  fprintf(file, "\
-Total disconnected facets        : %5d               %5d\n",
-          stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge +
-          stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
-          stl->stats.connected_facets_3_edge);
-
-  fprintf(file,
-          "=== Processing Statistics ===     ===== Other Statistics =====\n");
-  fprintf(file, "\
-Number of parts       : %5d        Volume   : % f\n",
-          stl->stats.number_of_parts, stl->stats.volume);
-  fprintf(file, "\
-Degenerate facets     : %5d\n", stl->stats.degenerate_facets);
-  fprintf(file, "\
-Edges fixed           : %5d\n", stl->stats.edges_fixed);
-  fprintf(file, "\
-Facets removed        : %5d\n", stl->stats.facets_removed);
-  fprintf(file, "\
-Facets added          : %5d\n", stl->stats.facets_added);
-  fprintf(file, "\
-Facets reversed       : %5d\n", stl->stats.facets_reversed);
-  fprintf(file, "\
-Backwards edges       : %5d\n", stl->stats.backwards_edges);
-  fprintf(file, "\
-Normals fixed         : %5d\n", stl->stats.normals_fixed);
+  	fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n");
+  	fprintf(file, "Input file         : %s\n", input_file);
+  	if (stl->stats.type == binary)
+    	fprintf(file, "File type          : Binary STL file\n");
+  	else
+    	fprintf(file, "File type          : ASCII STL file\n");
+  	fprintf(file, "Header             : %s\n", stl->stats.header);
+  	fprintf(file, "============== Size ==============\n");
+  	fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0));
+  	fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1));
+  	fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2));
+  	fprintf(file, "========= Facet Status ========== Original ============ Final ====\n");
+  	fprintf(file, "Number of facets                 : %5d               %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets);
+  	fprintf(file, "Facets with 1 disconnected edge  : %5d               %5d\n", 
+  		stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
+  	fprintf(file, "Facets with 2 disconnected edges : %5d               %5d\n",
+    	stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
+  	fprintf(file, "Facets with 3 disconnected edges : %5d               %5d\n",
+        stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
+  	fprintf(file, "Total disconnected facets        : %5d               %5d\n",
+		stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge);
+  	fprintf(file, "=== Processing Statistics ===     ===== Other Statistics =====\n");
+  	fprintf(file, "Number of parts       : %5d        Volume   : %f\n", stl->stats.number_of_parts, stl->stats.volume);
+  	fprintf(file, "Degenerate facets     : %5d\n", stl->stats.degenerate_facets);
+  	fprintf(file, "Edges fixed           : %5d\n", stl->stats.edges_fixed);
+  	fprintf(file, "Facets removed        : %5d\n", stl->stats.facets_removed);
+  	fprintf(file, "Facets added          : %5d\n", stl->stats.facets_added);
+  	fprintf(file, "Facets reversed       : %5d\n", stl->stats.facets_reversed);
+  	fprintf(file, "Backwards edges       : %5d\n", stl->stats.backwards_edges);
+  	fprintf(file, "Normals fixed         : %5d\n", stl->stats.normals_fixed);
 }
 
 bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
 {
 	FILE *fp = boost::nowide::fopen(file, "w");
-  	if (fp == NULL) {
+  	if (fp == nullptr) {
 		BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
     	return false;
   	}
@@ -117,19 +78,11 @@ bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
 	fprintf(fp, "solid  %s\n", label);
 
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-		fprintf(fp, "  facet normal % .8E % .8E % .8E\n",
-	        stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
-	        stl->facet_start[i].normal(2));
+		fprintf(fp, "  facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2));
 		fprintf(fp, "    outer loop\n");
-		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-	        stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
-	        stl->facet_start[i].vertex[0](2));
-		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-	        stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
-	        stl->facet_start[i].vertex[1](2));
-		fprintf(fp, "      vertex % .8E % .8E % .8E\n",
-	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-	        stl->facet_start[i].vertex[2](2));
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
+		fprintf(fp, "      vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
 		fprintf(fp, "    endloop\n");
 		fprintf(fp, "  endfacet\n");
 	}
@@ -142,7 +95,7 @@ bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
 bool stl_print_neighbors(stl_file *stl, char *file)
 {
 	FILE *fp = boost::nowide::fopen(file, "w");
-	if (fp == NULL) {
+	if (fp == nullptr) {
 		BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing";
     	return false;
   	}
@@ -175,7 +128,7 @@ void stl_internal_reverse_quads(char *buf, size_t cnt)
 bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 {
 	FILE *fp = boost::nowide::fopen(file, "wb");
-	if (fp == NULL) {
+	if (fp == nullptr) {
 		BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing";
     	return false;
   	}
@@ -184,6 +137,9 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 	for (size_t i = strlen(label); i < LABEL_SIZE; ++ i)
 		putc(0, fp);
 
+#if !defined(SEEK_SET)
+	#define SEEK_SET 0
+#endif
 	fseek(fp, LABEL_SIZE, SEEK_SET);
 #ifdef BOOST_LITTLE_ENDIAN
 	fwrite(&stl->stats.number_of_facets, 4, 1, fp);
@@ -242,7 +198,7 @@ bool stl_write_quad_object(stl_file *stl, char *file)
 	stl_vertex color;
 
 	FILE *fp = boost::nowide::fopen(file, "w");
-	if (fp == NULL) {
+	if (fp == nullptr) {
 		BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
 		return false;
 	}
@@ -255,22 +211,10 @@ bool stl_write_quad_object(stl_file *stl, char *file)
     	case 2: color = uncon_2_color; break;
     	default: color = uncon_3_color;
 	    }
-	    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[0](0),
-            stl->facet_start[i].vertex[0](1),
-            stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
-    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[1](0),
-            stl->facet_start[i].vertex[1](1),
-            stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
-    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[2](0),
-            stl->facet_start[i].vertex[2](1),
-            stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
-    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n",
-            stl->facet_start[i].vertex[2](0),
-            stl->facet_start[i].vertex[2](1),
-            stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
+	    fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
+    	fprintf(fp, "%f %f %f    %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
   }
   fclose(fp);
   return true;
@@ -279,7 +223,7 @@ bool stl_write_quad_object(stl_file *stl, char *file)
 bool stl_write_dxf(stl_file *stl, const char *file, char *label) 
 {
 	FILE *fp = boost::nowide::fopen(file, "w");
-	if (fp == NULL) {
+	if (fp == nullptr) {
 		BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
     	return false;
   	}
@@ -292,20 +236,12 @@ bool stl_write_dxf(stl_file *stl, const char *file, char *label)
 
 	fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
 
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		fprintf(fp, "0\n3DFACE\n8\n0\n");
-		fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
-	        stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
-	        stl->facet_start[i].vertex[0](2));
-		fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
-	        stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
-	        stl->facet_start[i].vertex[1](2));
-		fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
-	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-	        stl->facet_start[i].vertex[2](2));
-		fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
-	        stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
-	        stl->facet_start[i].vertex[2](2));
+		fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
+		fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
+		fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
+		fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
 	}
 
   	fprintf(fp, "0\nENDSEC\n0\nEOF\n");
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index bb135db95..6fff8a8ed 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -29,16 +29,17 @@
 
 #include "stl.h"
 
-static void stl_rotate(float *x, float *y, const double c, const double s);
-static float get_area(stl_facet *facet);
-static float get_volume(stl_file *stl);
-
 void stl_verify_neighbors(stl_file *stl)
 {
 	stl->stats.backwards_edges = 0;
 
 	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		for (int j = 0; j < 3; ++ j) {
+			struct stl_edge {
+				stl_vertex p1;
+				stl_vertex p2;
+				int        facet_number;
+			};
 			stl_edge edge_a;
 			edge_a.p1 = stl->facet_start[i].vertex[j];
 			edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
@@ -67,164 +68,140 @@ void stl_verify_neighbors(stl_file *stl)
 
 void stl_translate(stl_file *stl, float x, float y, float z)
 {
-  stl_vertex new_min(x, y, z);
-  stl_vertex shift = new_min - stl->stats.min;
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
-    for (int j = 0; j < 3; ++ j)
-      stl->facet_start[i].vertex[j] += shift;
-  stl->stats.min = new_min;
-  stl->stats.max += shift;
+	stl_vertex new_min(x, y, z);
+	stl_vertex shift = new_min - stl->stats.min;
+	for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+		for (int j = 0; j < 3; ++ j)
+	  		stl->facet_start[i].vertex[j] += shift;
+	stl->stats.min = new_min;
+	stl->stats.max += shift;
 }
 
 /* Translates the stl by x,y,z, relatively from wherever it is currently */
 void stl_translate_relative(stl_file *stl, float x, float y, float z)
 {
-  stl_vertex shift(x, y, z);
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
-    for (int j = 0; j < 3; ++ j)
-      stl->facet_start[i].vertex[j] += shift;
-  stl->stats.min += shift;
-  stl->stats.max += shift;
+	stl_vertex shift(x, y, z);
+	for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+		for (int j = 0; j < 3; ++ j)
+	  		stl->facet_start[i].vertex[j] += shift;
+	stl->stats.min += shift;
+	stl->stats.max += shift;
 }
 
 void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
 {
-  // Scale extents.
-  auto s = versor.array();
-  stl->stats.min.array() *= s;
-  stl->stats.max.array() *= s;
-  // Scale size.
-  stl->stats.size.array() *= s;
-  // Scale volume.
-  if (stl->stats.volume > 0.0)
-    stl->stats.volume *= versor(0) * versor(1) * versor(2);
-  // Scale the mesh.
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i)
-    for (int j = 0; j < 3; ++ j)
-      stl->facet_start[i].vertex[j].array() *= s;
+	// Scale extents.
+	auto s = versor.array();
+	stl->stats.min.array() *= s;
+	stl->stats.max.array() *= s;
+	// Scale size.
+	stl->stats.size.array() *= s;
+	// Scale volume.
+	if (stl->stats.volume > 0.0)
+		stl->stats.volume *= versor(0) * versor(1) * versor(2);
+	// Scale the mesh.
+	for (int i = 0; i < stl->stats.number_of_facets; ++ i)
+		for (int j = 0; j < 3; ++ j)
+	  		stl->facet_start[i].vertex[j].array() *= s;
 }
 
 static void calculate_normals(stl_file *stl) 
 {
-  stl_normal normal;
-  for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
-    stl_calculate_normal(normal, &stl->facet_start[i]);
-    stl_normalize_vector(normal);
-    stl->facet_start[i].normal = normal;
-  }
+	stl_normal normal;
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+		stl_calculate_normal(normal, &stl->facet_start[i]);
+		stl_normalize_vector(normal);
+		stl->facet_start[i].normal = normal;
+	}
 }
 
-void
-stl_rotate_x(stl_file *stl, float angle) {
-  int i;
-  int j;
-  double radian_angle = (angle / 180.0) * M_PI;
-  double c = cos(radian_angle);
-  double s = sin(radian_angle);
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j](1),
-                 &stl->facet_start[i].vertex[j](2), c, s);
-    }
-  }
-  stl_get_size(stl);
-  calculate_normals(stl);
+static void rotate_point_2d(float *x, float *y, const double c, const double s)
+{
+	double xold = *x;
+	double yold = *y;
+	*x = float(c * xold - s * yold);
+	*y = float(s * xold + c * yold);
 }
 
-void
-stl_rotate_y(stl_file *stl, float angle) {
-  int i;
-  int j;
-  double radian_angle = (angle / 180.0) * M_PI;
-  double c = cos(radian_angle);
-  double s = sin(radian_angle);
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j](2),
-                 &stl->facet_start[i].vertex[j](0), c, s);
-    }
-  }
-  stl_get_size(stl);
-  calculate_normals(stl);
+void stl_rotate_x(stl_file *stl, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	for (int j = 0; j < 3; ++ j)
+      		rotate_point_2d(&stl->facet_start[i].vertex[j](1), &stl->facet_start[i].vertex[j](2), c, s);
+  	stl_get_size(stl);
+  	calculate_normals(stl);
 }
 
-void
-stl_rotate_z(stl_file *stl, float angle) {
-  int i;
-  int j;
-  double radian_angle = (angle / 180.0) * M_PI;
-  double c = cos(radian_angle);
-  double s = sin(radian_angle);
-
-  for(i = 0; i < stl->stats.number_of_facets; i++) {
-    for(j = 0; j < 3; j++) {
-      stl_rotate(&stl->facet_start[i].vertex[j](0),
-                 &stl->facet_start[i].vertex[j](1), c, s);
-    }
-  }
-  stl_get_size(stl);
-  calculate_normals(stl);
+void stl_rotate_y(stl_file *stl, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	for (int j = 0; j < 3; ++ j)
+			rotate_point_2d(&stl->facet_start[i].vertex[j](2), &stl->facet_start[i].vertex[j](0), c, s);
+  	stl_get_size(stl);
+  	calculate_normals(stl);
 }
 
-
-
-static void
-stl_rotate(float *x, float *y, const double c, const double s) {
-  double xold = *x;
-  double yold = *y;
-  *x = float(c * xold - s * yold);
-  *y = float(s * xold + c * yold);
+void stl_rotate_z(stl_file *stl, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	for (int j = 0; j < 3; ++ j)
+      		rotate_point_2d(&stl->facet_start[i].vertex[j](0), &stl->facet_start[i].vertex[j](1), c, s);
+  	stl_get_size(stl);
+  	calculate_normals(stl);
 }
 
 void stl_get_size(stl_file *stl)
 {
-  if (stl->stats.number_of_facets == 0)
-  	return;
-  stl->stats.min = stl->facet_start[0].vertex[0];
-  stl->stats.max = stl->stats.min;
-  for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
-  	const stl_facet &face = stl->facet_start[i];
-    for (int j = 0; j < 3; ++ j) {
-      stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
-      stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
-    }
-  }
-  stl->stats.size = stl->stats.max - stl->stats.min;
-  stl->stats.bounding_diameter = stl->stats.size.norm();
+  	if (stl->stats.number_of_facets == 0)
+  		return;
+  	stl->stats.min = stl->facet_start[0].vertex[0];
+  	stl->stats.max = stl->stats.min;
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+  		const stl_facet &face = stl->facet_start[i];
+    	for (int j = 0; j < 3; ++ j) {
+      		stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
+      		stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
+    	}
+  	}
+  	stl->stats.size = stl->stats.max - stl->stats.min;
+  	stl->stats.bounding_diameter = stl->stats.size.norm();
 }
 
 void stl_mirror_xy(stl_file *stl)
 {
-  for(int i = 0; i < stl->stats.number_of_facets; i++) {
-    for(int j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j](2) *= -1.0;
-    }
-  }
-  float temp_size = stl->stats.min(2);
-  stl->stats.min(2) = stl->stats.max(2);
-  stl->stats.max(2) = temp_size;
-  stl->stats.min(2) *= -1.0;
-  stl->stats.max(2) *= -1.0;
-  stl_reverse_all_facets(stl);
-  stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	for (int j = 0; j < 3; ++ j)
+      		stl->facet_start[i].vertex[j](2) *= -1.0;
+	float temp_size = stl->stats.min(2);
+	stl->stats.min(2) = stl->stats.max(2);
+	stl->stats.max(2) = temp_size;
+	stl->stats.min(2) *= -1.0;
+	stl->stats.max(2) *= -1.0;
+	stl_reverse_all_facets(stl);
+	stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
 }
 
 void stl_mirror_yz(stl_file *stl)
 {
-  for (int i = 0; i < stl->stats.number_of_facets; i++) {
-    for (int j = 0; j < 3; j++) {
-      stl->facet_start[i].vertex[j](0) *= -1.0;
-    }
-  }
-  float temp_size = stl->stats.min(0);
-  stl->stats.min(0) = stl->stats.max(0);
-  stl->stats.max(0) = temp_size;
-  stl->stats.min(0) *= -1.0;
-  stl->stats.max(0) *= -1.0;
-  stl_reverse_all_facets(stl);
-  stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
+    	for (int j = 0; j < 3; j++)
+      		stl->facet_start[i].vertex[j](0) *= -1.0;
+	float temp_size = stl->stats.min(0);
+	stl->stats.min(0) = stl->stats.max(0);
+	stl->stats.max(0) = temp_size;
+	stl->stats.min(0) *= -1.0;
+	stl->stats.max(0) *= -1.0;
+	stl_reverse_all_facets(stl);
+	stl->stats.facets_reversed -= stl->stats.number_of_facets;  /* for not altering stats */
 }
 
 void stl_mirror_xz(stl_file *stl)
@@ -241,55 +218,55 @@ void stl_mirror_xz(stl_file *stl)
 	stl->stats.facets_reversed -= stl->stats.number_of_facets;  // for not altering stats
 }
 
+static float get_area(stl_facet *facet)
+{
+	/* cast to double before calculating cross product because large coordinates
+	 can result in overflowing product
+	(bad area is responsible for bad volume and bad facets reversal) */
+	double cross[3][3];
+	for (int i = 0; i < 3; i++) {
+		cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
+	             	 ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
+		cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
+	             	 ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
+		cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
+	             	 ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
+	}
+
+	stl_normal sum;
+	sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
+	sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
+	sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
+
+	// This should already be done.  But just in case, let's do it again.
+	//FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
+	stl_normal n;
+	stl_calculate_normal(n, facet);
+	stl_normalize_vector(n);
+	return 0.5f * n.dot(sum);
+}
+
 static float get_volume(stl_file *stl)
 {
-  // Choose a point, any point as the reference.
-  stl_vertex p0 = stl->facet_start[0].vertex[0];
-  float volume = 0.f;
-  for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
-    // Do dot product to get distance from point to plane.
-    float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
-    float area   = get_area(&stl->facet_start[i]);
-    volume += (area * height) / 3.0f;
-  }
-  return volume;
+  	// Choose a point, any point as the reference.
+  	stl_vertex p0 = stl->facet_start[0].vertex[0];
+  	float volume = 0.f;
+  	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
+    	// Do dot product to get distance from point to plane.
+    	float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
+    	float area   = get_area(&stl->facet_start[i]);
+    	volume += (area * height) / 3.0f;
+  	}
+  	return volume;
 }
 
 void stl_calculate_volume(stl_file *stl)
 {
-  stl->stats.volume = get_volume(stl);
-  if(stl->stats.volume < 0.0) {
-    stl_reverse_all_facets(stl);
-    stl->stats.volume = -stl->stats.volume;
-  }
-}
-
-static float get_area(stl_facet *facet)
-{
-  /* cast to double before calculating cross product because large coordinates
-     can result in overflowing product
-    (bad area is responsible for bad volume and bad facets reversal) */
-  double cross[3][3];
-  for (int i = 0; i < 3; i++) {
-    cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
-                 ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
-    cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
-                 ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
-    cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
-                 ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
-  }
-
-  stl_normal sum;
-  sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
-  sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
-  sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
-
-  // This should already be done.  But just in case, let's do it again.
-  //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
-  stl_normal n;
-  stl_calculate_normal(n, facet);
-  stl_normalize_vector(n);
-  return 0.5f * n.dot(sum);
+  	stl->stats.volume = get_volume(stl);
+  	if (stl->stats.volume < 0.0) {
+    	stl_reverse_all_facets(stl);
+    	stl->stats.volume = -stl->stats.volume;
+  	}
 }
 
 void stl_repair(
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 8298fe222..654426528 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1928,7 +1928,7 @@ namespace Slic3r {
                 stream << "     <" << TRIANGLE_TAG << " ";
                 for (int j = 0; j < 3; ++j)
                 {
-                    stream << "v" << j + 1 << "=\"" << its.indices[i].vertex[j] + volume_it->second.first_vertex_id << "\" ";
+                    stream << "v" << j + 1 << "=\"" << its.indices[i][j] + volume_it->second.first_vertex_id << "\" ";
                 }
                 stream << "/>\n";
             }
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index dcd913864..48887bc78 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -958,7 +958,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) {
                 stream << "        <triangle>\n";
                 for (int j = 0; j < 3; ++j)
-                stream << "          <v" << j + 1 << ">" << volume->mesh.its.indices[i].vertex[j] + vertices_offset << "</v" << j + 1 << ">\n";
+                stream << "          <v" << j + 1 << ">" << volume->mesh.its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
                 stream << "        </triangle>\n";
             }
             stream << "      </volume>\n";
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index ae35c8a5b..5b0ecbd00 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -614,8 +614,8 @@ void TriangleMeshSlicer::init(const TriangleMesh *_mesh, throw_on_cancel_callbac
     for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx)
         for (int i = 0; i < 3; ++ i) {
             EdgeToFace &e2f = edges_map[facet_idx*3+i];
-            e2f.vertex_low  = this->mesh->its.indices[facet_idx].vertex[i];
-            e2f.vertex_high = this->mesh->its.indices[facet_idx].vertex[(i + 1) % 3];
+            e2f.vertex_low  = this->mesh->its.indices[facet_idx][i];
+            e2f.vertex_high = this->mesh->its.indices[facet_idx][(i + 1) % 3];
             e2f.face        = facet_idx;
             // 1 based indexing, to be always strictly positive.
             e2f.face_edge   = i + 1;
@@ -852,7 +852,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet(
     // Reorder vertices so that the first one is the one with lowest Z.
     // This is needed to get all intersection lines in a consistent order
     // (external on the right of the line)
-    const int *vertices = this->mesh->its.indices[facet_idx].vertex;
+    const stl_triangle_vertex_indices &vertices = this->mesh->its.indices[facet_idx];
     int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0);
 
     // These are used only if the cut plane is tilted:
diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp
index 3e90bfefd..f3153665c 100644
--- a/xs/xsp/TriangleMesh.xsp
+++ b/xs/xsp/TriangleMesh.xsp
@@ -129,9 +129,9 @@ TriangleMesh::facets()
             AV* facet = newAV();
             av_store(facets, i, newRV_noinc((SV*)facet));
             av_extend(facet, 2);
-            av_store(facet, 0, newSVnv(THIS->its.indices[i].vertex[0]));
-            av_store(facet, 1, newSVnv(THIS->its.indices[i].vertex[1]));
-            av_store(facet, 2, newSVnv(THIS->its.indices[i].vertex[2]));
+            av_store(facet, 0, newSVnv(THIS->its.indices[i][0]));
+            av_store(facet, 1, newSVnv(THIS->its.indices[i][1]));
+            av_store(facet, 2, newSVnv(THIS->its.indices[i][2]));
         }
         
         RETVAL = newRV_noinc((SV*)facets);

From 0cb5b57c5cf6661f20ab0b3fca3a85ce3b9c790d Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 22:43:21 +0200
Subject: [PATCH 11/22] SLA gimzmo: Sharing the Mesh's indexed triangle set
 with IGL AABB structure directly, without having to make a copy.

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 61 ++++++++++----------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  7 ++-
 2 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index ae017f7d1..89475a058 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -27,6 +27,7 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_i
     : GLGizmoBase(parent, sprite_id)
 #endif // ENABLE_SVG_ICONS
     , m_quadric(nullptr)
+    , m_its(nullptr)
 {
     m_quadric = ::gluNewQuadric();
     if (m_quadric != nullptr)
@@ -379,36 +380,24 @@ bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
 bool GLGizmoSlaSupports::is_mesh_update_necessary() const
 {
     return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty())
-        && ((m_model_object->id() != m_current_mesh_model_id) || m_V.size()==0);
+        && ((m_model_object->id() != m_current_mesh_model_id) || m_its == nullptr);
 }
 
 void GLGizmoSlaSupports::update_mesh()
 {
     wxBusyCursor wait;
-    Eigen::MatrixXf& V = m_V;
-    Eigen::MatrixXi& F = m_F;
-    // We rely on SLA model object having a single volume,
     // this way we can use that mesh directly.
     // This mesh does not account for the possible Z up SLA offset.
     m_mesh = &m_model_object->volumes.front()->mesh;
     const_cast<TriangleMesh*>(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this
-    const stl_file& stl = m_mesh->stl;
-    V.resize(3 * stl.stats.number_of_facets, 3);
-    F.resize(stl.stats.number_of_facets, 3);
-    for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
-        const stl_facet &facet = stl.facet_start[i];
-		V.block<1, 3>(3 * i + 0, 0) = facet.vertex[0];
-		V.block<1, 3>(3 * i + 1, 0) = facet.vertex[1];
-		V.block<1, 3>(3 * i + 2, 0) = facet.vertex[2];
-        F(i, 0) = 3*i+0;
-        F(i, 1) = 3*i+1;
-        F(i, 2) = 3*i+2;
-    }
+    m_its = &m_mesh->its;
     m_current_mesh_model_id = m_model_object->id();
     m_editing_mode = false;
 
-    m_AABB = igl::AABB<Eigen::MatrixXf,3>();
-    m_AABB.init(m_V, m_F);
+	m_AABB.deinit();
+    m_AABB.init(
+        MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
+        MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3));
 }
 
 // Unprojects the mouse position on the mesh and return the hit point and normal of the facet.
@@ -416,7 +405,7 @@ void GLGizmoSlaSupports::update_mesh()
 std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
 {
     // if the gizmo doesn't have the V, F structures for igl, calculate them first:
-    if (m_V.size() == 0)
+    if (m_its == nullptr)
         update_mesh();
 
     const Camera& camera = m_parent.get_camera();
@@ -442,7 +431,10 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
     point1 = inv * point1;
     point2 = inv * point2;
 
-    if (!m_AABB.intersect_ray(m_V, m_F, point1.cast<float>(), (point2-point1).cast<float>(), hits))
+    if (!m_AABB.intersect_ray(
+        MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
+        MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
+        point1.cast<float>(), (point2-point1).cast<float>(), hits))
         throw std::invalid_argument("unproject_on_mesh(): No intersection found.");
 
     std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
@@ -457,9 +449,9 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
         igl::Hit& hit = hits[i];
         int fid = hit.id;   // facet id
         bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
-        a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0)));
-        b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0)));
-        result = bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2));
+        a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]);
+        b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]);
+        result = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)];
         if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast<double>()))
             break;
     }
@@ -564,15 +556,18 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
                     // Cast a ray in the direction of the camera and look for intersection with the mesh:
                     std::vector<igl::Hit> hits;
                     // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
-                    if (m_AABB.intersect_ray(m_V, m_F, support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) {
+                    if (m_AABB.intersect_ray(
+                            MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
+                            MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
+                            support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) {
                         std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; });
 
                         if (m_clipping_plane_distance != 0.f) {
                             // If the closest hit facet normal points in the same direction as the ray,
                             // we are looking through the mesh and should therefore discard the point:
                             int fid = hits.front().id;   // facet id
-                            Vec3f a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0)));
-                            Vec3f b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0)));
+                            Vec3f a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]);
+                            Vec3f b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]);
                             if ((a.cross(b)).dot(direction_to_camera_mesh) > 0.f)
                                 is_obscured = true;
 
@@ -582,7 +577,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
                                 int fid = hit.id;   // facet id
 
                                 Vec3f bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
-                                Vec3f hit_pos = bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2));
+                                Vec3f hit_pos = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)];
                                 if (is_point_clipped(hit_pos.cast<double>())) {
                                     hits.erase(hits.begin()+j);
                                     --j;
@@ -759,9 +754,12 @@ void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const
     int idx = 0;
     Eigen::Matrix<float, 1, 3> pp = m_editing_mode_cache[i].support_point.pos;
     Eigen::Matrix<float, 1, 3> cc;
-    m_AABB.squared_distance(m_V, m_F, pp, idx, cc);
-    Vec3f a = (m_V.row(m_F(idx, 1)) - m_V.row(m_F(idx, 0)));
-    Vec3f b = (m_V.row(m_F(idx, 2)) - m_V.row(m_F(idx, 0)));
+    m_AABB.squared_distance(
+        MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
+        MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
+        pp, idx, cc);
+    Vec3f a = (m_its->vertices[m_its->indices[idx](1)] - m_its->vertices[m_its->indices[idx](0)]);
+    Vec3f b = (m_its->vertices[m_its->indices[idx](2)] - m_its->vertices[m_its->indices[idx](0)]);
     m_editing_mode_cache[i].normal = a.cross(b);
 }
 
@@ -1067,8 +1065,7 @@ void GLGizmoSlaSupports::on_set_state()
                 m_clipping_plane_distance = 0.f;
                 // Release triangle mesh slicer and the AABB spatial search structure.
                 m_AABB.deinit();
-				m_V = Eigen::MatrixXf();
-				m_F = Eigen::MatrixXi();
+                m_its = nullptr;
                 m_tms.reset();
                 m_supports_tms.reset();
             });
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index fb758d240..4946db12d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -35,10 +35,11 @@ private:
     const float RenderPointScale = 1.f;
 
     GLUquadricObj* m_quadric;
-    Eigen::MatrixXf m_V; // vertices
-    Eigen::MatrixXi m_F; // facets indices
-    igl::AABB<Eigen::MatrixXf,3> m_AABB;
+    typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned;
+    typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned;
+    igl::AABB<MapMatrixXfUnaligned, 3> m_AABB;
     const TriangleMesh* m_mesh;
+    const indexed_triangle_set* m_its;
     mutable const TriangleMesh* m_supports_mesh;
     mutable std::vector<Vec2f> m_triangles;
     mutable std::vector<Vec2f> m_supports_triangles;

From 590c290ede9ed9da7e608614fbe170d489d1aa06 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Mon, 10 Jun 2019 22:43:42 +0200
Subject: [PATCH 12/22] Fix of a typo.

---
 src/admesh/shared.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/admesh/shared.cpp b/src/admesh/shared.cpp
index 78179e863..902bbfc9b 100644
--- a/src/admesh/shared.cpp
+++ b/src/admesh/shared.cpp
@@ -220,7 +220,7 @@ bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
     // Verify validity of neighborship data.
     for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
         const stl_neighbors &nbr 		= stl->neighbors_start[facet_idx];
-        const int 			*vertices 	= (its.indices.empty()) ? nullptr : its.indices[facet_idx];
+        const int 			*vertices 	= its.indices.empty() ? nullptr : its.indices[facet_idx].data();
         for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
             int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
             assert(nbr_face < (int)stl->stats.number_of_facets);

From 5fc465b7e8e5398771e4b6db6043bc84770e5923 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 11 Jun 2019 09:29:32 +0200
Subject: [PATCH 13/22] admesh refactoring: Using boost::object_pool for linked
 list memory allocation.

---
 src/admesh/connect.cpp | 525 +++++++++++++++++++++--------------------
 src/admesh/normals.cpp |  15 +-
 src/admesh/stl_io.cpp  |  10 +-
 3 files changed, 284 insertions(+), 266 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index cbd4f1d33..be782b1b7 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -28,8 +28,9 @@
 #include <algorithm>
 #include <vector>
 
+#include <boost/predef/other/endian.h>
 #include <boost/log/trivial.hpp>
-#include <boost/detail/endian.hpp>
+#include <boost/pool/object_pool.hpp>
 
 #include "stl.h"
 
@@ -42,11 +43,11 @@ struct HashEdge {
 	int  hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11  + key[4] / 7 + key[5] / 3)) % M; }
 
 	// Index of a facet owning this edge.
-	int            facet_number;
+	int        facet_number;
 	// Index of this edge inside the facet with an index of facet_number.
 	// If this edge is stored backwards, which_edge is increased by 3.
-	int            which_edge;
-	struct HashEdge  *next;
+	int        which_edge;
+	HashEdge  *next;
 
 	void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b)
 	{
@@ -69,15 +70,15 @@ struct HashEdge {
 	  	// Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
 	  	for (size_t i = 0; i < 6; ++ i) {
 	    	unsigned char *p = (unsigned char*)(this->key + i);
-	#ifdef BOOST_LITTLE_ENDIAN
+	#if BOOST_ENDIAN_LITTLE_BYTE
 	    	if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
 	      		// Negative zero, switch to positive zero.
 	      		p[3] = 0;
-	#else /* BOOST_LITTLE_ENDIAN */
+	#else /* BOOST_ENDIAN_LITTLE_BYTE */
 	    	if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0)
 	      		// Negative zero, switch to positive zero.
 	      		p[0] = 0;
-	#endif /* BOOST_LITTLE_ENDIAN */
+	#endif /* BOOST_ENDIAN_LITTLE_BYTE */
 	  	}
 	}
 
@@ -115,7 +116,7 @@ struct HashTableEdges {
 	HashTableEdges(size_t number_of_faces) {
 		this->M = (int)hash_size_from_nr_faces(number_of_faces);
 		this->heads.assign(this->M, nullptr);
-		this->tail = new HashEdge;
+		this->tail = pool.construct();
 		this->tail->next = this->tail;
 		for (int i = 0; i < this->M; ++ i)
 			this->heads[i] = this->tail;
@@ -124,80 +125,32 @@ struct HashTableEdges {
 	    for (int i = 0; i < this->M; ++ i) {
 	    	for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) {
 	        	this->heads[i] = this->heads[i]->next;
-	        	delete temp;
+	        	pool.destroy(temp);
 #ifndef NDEBUG
 	        	++ this->freed;
 #endif /* NDEBUG */
 	      	}
 	    }
 		this->heads.clear();
-		delete this->tail;
+		pool.destroy(this->tail);
 		this->tail = nullptr;
 	}
 
-	void insert_edge(stl_file *stl, const HashEdge &edge, void (*match_neighbors)(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b))
+	void insert_edge_exact(stl_file *stl, const HashEdge &edge)
 	{
-		int       chain_number = edge.hash(this->M);
-		HashEdge *link         = this->heads[chain_number];
-		if (link == this->tail) {
-			// This list doesn't have any edges currently in it.  Add this one.
-			HashEdge *new_edge = new HashEdge(edge);
-#ifndef NDEBUG
-			++ this->malloced;
-#endif /* NDEBUG */
-			new_edge->next = this->tail;
-			this->heads[chain_number] = new_edge;
-		} else if (edges_equal(edge, *link)) {
-			// This is a match.  Record result in neighbors list.
-			match_neighbors(stl, edge, *link);
-			// Delete the matched edge from the list.
-			this->heads[chain_number] = link->next;
-			delete link;
-#ifndef NDEBUG
-			++ this->freed;
-#endif /* NDEBUG */
-		} else {
-			// Continue through the rest of the list.
-			for (;;) {
-				if (link->next == this->tail) {
-					// This is the last item in the list. Insert a new edge.
-					HashEdge *new_edge = new HashEdge;
-#ifndef NDEBUG
-					++ this->malloced;
-#endif /* NDEBUG */
-					*new_edge = edge;
-					new_edge->next = this->tail;
-					link->next = new_edge;
-#ifndef NDEBUG
-					++ this->collisions;
-#endif /* NDEBUG */
-					break;
-				}
-				if (edges_equal(edge, *link->next)) {
-					// This is a match.  Record result in neighbors list.
-					match_neighbors(stl, edge, *link->next);
-					// Delete the matched edge from the list.
-					HashEdge *temp = link->next;
-					link->next = link->next->next;
-					delete temp;
-#ifndef NDEBUG
-					++ this->freed;
-#endif /* NDEBUG */
-					break;
-				}
-				// This is not a match.  Go to the next link.
-				link = link->next;
-#ifndef NDEBUG
-				++ this->collisions;
-#endif /* NDEBUG */
-			}
-		}
+		this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { record_neighbors(stl, edge1, edge2); });
+	}
+
+	void insert_edge_nearby(stl_file *stl, const HashEdge &edge)
+	{
+		this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { match_neighbors_nearby(stl, edge1, edge2); });
 	}
 
 	// Hash table on edges
 	std::vector<HashEdge*> 	heads;
 	HashEdge* 				tail;
 	int           			M;
+	boost::object_pool<HashEdge> pool;
 
 #ifndef NDEBUG
 	size_t 					malloced   	= 0;
@@ -216,198 +169,260 @@ private:
 		return (it == primes.end()) ? primes.back() : *it;
 	}
 
+
+	// MatchNeighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
+	template<typename MatchNeighbors>
+	void insert_edge(stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors)
+	{
+		int       chain_number = edge.hash(this->M);
+		HashEdge *link         = this->heads[chain_number];
+		if (link == this->tail) {
+			// This list doesn't have any edges currently in it.  Add this one.
+			HashEdge *new_edge = pool.construct(edge);
+#ifndef NDEBUG
+			++ this->malloced;
+#endif /* NDEBUG */
+			new_edge->next = this->tail;
+			this->heads[chain_number] = new_edge;
+		} else if (edges_equal(edge, *link)) {
+			// This is a match.  Record result in neighbors list.
+			match_neighbors(edge, *link);
+			// Delete the matched edge from the list.
+			this->heads[chain_number] = link->next;
+			pool.destroy(link);
+#ifndef NDEBUG
+			++ this->freed;
+#endif /* NDEBUG */
+		} else {
+			// Continue through the rest of the list.
+			for (;;) {
+				if (link->next == this->tail) {
+					// This is the last item in the list. Insert a new edge.
+					HashEdge *new_edge = pool.construct();
+#ifndef NDEBUG
+					++ this->malloced;
+#endif /* NDEBUG */
+					*new_edge = edge;
+					new_edge->next = this->tail;
+					link->next = new_edge;
+#ifndef NDEBUG
+					++ this->collisions;
+#endif /* NDEBUG */
+					break;
+				}
+				if (edges_equal(edge, *link->next)) {
+					// This is a match.  Record result in neighbors list.
+					match_neighbors(edge, *link->next);
+					// Delete the matched edge from the list.
+					HashEdge *temp = link->next;
+					link->next = link->next->next;
+					pool.destroy(temp);
+#ifndef NDEBUG
+					++ this->freed;
+#endif /* NDEBUG */
+					break;
+				}
+				// This is not a match.  Go to the next link.
+				link = link->next;
+#ifndef NDEBUG
+				++ this->collisions;
+#endif /* NDEBUG */
+			}
+		}
+	}
+
 	// Edges equal for hashing. Edgesof different facet are allowed to be matched.
 	static inline bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b)
 	{
 	    return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b;
 	}
+
+	static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
+	{
+		// Facet a's neighbor is facet b
+		stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number;	/* sets the .neighbor part */
+		stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */
+
+		// Facet b's neighbor is facet a
+		stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number;	/* sets the .neighbor part */
+		stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
+
+		if (((edge_a.which_edge < 3) && (edge_b.which_edge < 3)) || ((edge_a.which_edge > 2) && (edge_b.which_edge > 2))) {
+			// These facets are oriented in opposite directions, their normals are probably messed up.
+			stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
+			stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
+		}
+
+		// Count successful connects:
+		// Total connects:
+		stl->stats.connected_edges += 2;
+		// Count individual connects:
+		switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) {
+		case 1:	++ stl->stats.connected_facets_1_edge; break;
+		case 2: ++ stl->stats.connected_facets_2_edge; break;
+		case 3: ++ stl->stats.connected_facets_3_edge; break;
+		default: assert(false);
+		}
+		switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) {
+		case 1:	++ stl->stats.connected_facets_1_edge; break;
+		case 2: ++ stl->stats.connected_facets_2_edge; break;
+		case 3: ++ stl->stats.connected_facets_3_edge; break;
+		default: assert(false);
+		}
+	}
+
+	static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
+	{
+		record_neighbors(stl, edge_a, edge_b);
+
+		// Which vertices to change
+		int facet1 = -1;
+		int facet2 = -1;
+		int vertex1, vertex2;
+		stl_vertex new_vertex1, new_vertex2;
+		{
+			int v1a; // pair 1, facet a
+			int v1b; // pair 1, facet b
+			int v2a; // pair 2, facet a
+			int v2b; // pair 2, facet b
+			// Find first pair.
+			if (edge_a.which_edge < 3) {
+				v1a = edge_a.which_edge;
+				v2a = (edge_a.which_edge + 1) % 3;
+			} else {
+				v2a = edge_a.which_edge % 3;
+				v1a = (edge_a.which_edge + 1) % 3;
+			}
+			if (edge_b.which_edge < 3) {
+				v1b = edge_b.which_edge;
+				v2b = (edge_b.which_edge + 1) % 3;
+			} else {
+				v2b = edge_b.which_edge % 3;
+				v1b = (edge_b.which_edge + 1) % 3;
+			}
+
+			// Of the first pair, which vertex, if any, should be changed
+			if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) {
+				// These facets are different.
+				if (   (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1)
+			        && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) {
+			  		// This vertex has no neighbors.  This is a good one to change.
+			  		facet1 = edge_a.facet_number;
+			  		vertex1 = v1a;
+			  		new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b];
+				} else {
+				  	facet1 = edge_b.facet_number;
+			  		vertex1 = v1b;
+			  		new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a];
+				}
+			}
+
+			// Of the second pair, which vertex, if any, should be changed.
+			if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) {
+				// These facets are different.
+				if (  (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1)
+			       && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) {
+			  		// This vertex has no neighbors.  This is a good one to change.
+			  		facet2 = edge_a.facet_number;
+			  		vertex2 = v2a;
+			  		new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b];
+				} else {
+			  		facet2 = edge_b.facet_number;
+			  		vertex2 = v2b;
+			  		new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a];
+				}
+			}
+		}
+
+		auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex)
+		{
+			int first_facet = facet_num;
+			bool direction = false;
+
+			for (;;) {
+				int pivot_vertex;
+				int next_edge;
+				if (vnot > 2) {
+					if (direction) {
+						pivot_vertex = (vnot + 1) % 3;
+						next_edge = vnot % 3;
+					}
+					else {
+						pivot_vertex = (vnot + 2) % 3;
+						next_edge = pivot_vertex;
+					}
+					direction = !direction;
+				}
+				else {
+					if (direction) {
+						pivot_vertex = (vnot + 2) % 3;
+						next_edge = pivot_vertex;
+					}
+					else {
+						pivot_vertex = (vnot + 1) % 3;
+						next_edge = vnot;
+					}
+				}
+	#if 0
+				if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
+					stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
+					stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
+					printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2));
+				else {
+					if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
+						printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+							stl->facet_start[facet_num].vertex[pivot_vertex](0),
+							*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
+							new_vertex(0),
+							*reinterpret_cast<const int*>(&new_vertex(0)));
+					if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
+						printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+							stl->facet_start[facet_num].vertex[pivot_vertex](1),
+							*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
+							new_vertex(1),
+							*reinterpret_cast<const int*>(&new_vertex(1)));
+					if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
+						printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
+							stl->facet_start[facet_num].vertex[pivot_vertex](2),
+							*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
+							new_vertex(2),
+							*reinterpret_cast<const int*>(&new_vertex(2)));
+				}
+	#endif
+				stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
+				vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
+				facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
+				if (facet_num == -1)
+					break;
+
+				if (facet_num == first_facet) {
+					// back to the beginning
+					BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
+					return;
+				}
+			}
+		};
+
+		if (facet1 != -1) {
+			int vnot1 = (facet1 == edge_a.facet_number) ? 
+		  		(edge_a.which_edge + 2) % 3 :
+				(edge_b.which_edge + 2) % 3;
+			if (((vnot1 + 2) % 3) == vertex1)
+		  		vnot1 += 3;
+			change_vertices(facet1, vnot1, new_vertex1);
+		}
+		if (facet2 != -1) {
+			int vnot2 = (facet2 == edge_a.facet_number) ?
+		  		(edge_a.which_edge + 2) % 3 :
+				(edge_b.which_edge + 2) % 3;
+			if (((vnot2 + 2) % 3) == vertex2)
+		  		vnot2 += 3;
+			change_vertices(facet2, vnot2, new_vertex2);
+		}
+		stl->stats.edges_fixed += 2;
+	}
 };
 
-static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
-{
-	// Facet a's neighbor is facet b
-	stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number;	/* sets the .neighbor part */
-	stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */
-
-	// Facet b's neighbor is facet a
-	stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number;	/* sets the .neighbor part */
-	stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
-
-	if (((edge_a.which_edge < 3) && (edge_b.which_edge < 3)) || ((edge_a.which_edge > 2) && (edge_b.which_edge > 2))) {
-		// These facets are oriented in opposite directions, their normals are probably messed up.
-		stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
-		stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
-	}
-
-	// Count successful connects:
-	// Total connects:
-	stl->stats.connected_edges += 2;
-	// Count individual connects:
-	switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) {
-	case 1:	++ stl->stats.connected_facets_1_edge; break;
-	case 2: ++ stl->stats.connected_facets_2_edge; break;
-	case 3: ++ stl->stats.connected_facets_3_edge; break;
-	default: assert(false);
-	}
-	switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) {
-	case 1:	++ stl->stats.connected_facets_1_edge; break;
-	case 2: ++ stl->stats.connected_facets_2_edge; break;
-	case 3: ++ stl->stats.connected_facets_3_edge; break;
-	default: assert(false);
-	}
-}
-
-static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
-{
-	record_neighbors(stl, edge_a, edge_b);
-
-	// Which vertices to change
-	int facet1 = -1;
-	int facet2 = -1;
-	int vertex1, vertex2;
-	stl_vertex new_vertex1, new_vertex2;
-	{
-		int v1a; // pair 1, facet a
-		int v1b; // pair 1, facet b
-		int v2a; // pair 2, facet a
-		int v2b; // pair 2, facet b
-		// Find first pair.
-		if (edge_a.which_edge < 3) {
-			v1a = edge_a.which_edge;
-			v2a = (edge_a.which_edge + 1) % 3;
-		} else {
-			v2a = edge_a.which_edge % 3;
-			v1a = (edge_a.which_edge + 1) % 3;
-		}
-		if (edge_b.which_edge < 3) {
-			v1b = edge_b.which_edge;
-			v2b = (edge_b.which_edge + 1) % 3;
-		} else {
-			v2b = edge_b.which_edge % 3;
-			v1b = (edge_b.which_edge + 1) % 3;
-		}
-
-		// Of the first pair, which vertex, if any, should be changed
-		if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) {
-			// These facets are different.
-			if (   (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1)
-		        && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) {
-		  		// This vertex has no neighbors.  This is a good one to change.
-		  		facet1 = edge_a.facet_number;
-		  		vertex1 = v1a;
-		  		new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b];
-			} else {
-			  	facet1 = edge_b.facet_number;
-		  		vertex1 = v1b;
-		  		new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a];
-			}
-		}
-
-		// Of the second pair, which vertex, if any, should be changed.
-		if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) {
-			// These facets are different.
-			if (  (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1)
-		       && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) {
-		  		// This vertex has no neighbors.  This is a good one to change.
-		  		facet2 = edge_a.facet_number;
-		  		vertex2 = v2a;
-		  		new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b];
-			} else {
-		  		facet2 = edge_b.facet_number;
-		  		vertex2 = v2b;
-		  		new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a];
-			}
-		}
-	}
-
-	auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex)
-	{
-		int first_facet = facet_num;
-		bool direction = false;
-
-		for (;;) {
-			int pivot_vertex;
-			int next_edge;
-			if (vnot > 2) {
-				if (direction) {
-					pivot_vertex = (vnot + 1) % 3;
-					next_edge = vnot % 3;
-				}
-				else {
-					pivot_vertex = (vnot + 2) % 3;
-					next_edge = pivot_vertex;
-				}
-				direction = !direction;
-			}
-			else {
-				if (direction) {
-					pivot_vertex = (vnot + 2) % 3;
-					next_edge = pivot_vertex;
-				}
-				else {
-					pivot_vertex = (vnot + 1) % 3;
-					next_edge = vnot;
-				}
-			}
-#if 0
-			if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
-				stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
-				stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
-				printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2));
-			else {
-				if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
-					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
-						stl->facet_start[facet_num].vertex[pivot_vertex](0),
-						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
-						new_vertex(0),
-						*reinterpret_cast<const int*>(&new_vertex(0)));
-				if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
-					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
-						stl->facet_start[facet_num].vertex[pivot_vertex](1),
-						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
-						new_vertex(1),
-						*reinterpret_cast<const int*>(&new_vertex(1)));
-				if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
-					printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
-						stl->facet_start[facet_num].vertex[pivot_vertex](2),
-						*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
-						new_vertex(2),
-						*reinterpret_cast<const int*>(&new_vertex(2)));
-			}
-#endif
-			stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
-			vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
-			facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
-			if (facet_num == -1)
-				break;
-
-			if (facet_num == first_facet) {
-				// back to the beginning
-				BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
-				return;
-			}
-		}
-	};
-
-	if (facet1 != -1) {
-		int vnot1 = (facet1 == edge_a.facet_number) ? 
-	  		(edge_a.which_edge + 2) % 3 :
-			(edge_b.which_edge + 2) % 3;
-		if (((vnot1 + 2) % 3) == vertex1)
-	  		vnot1 += 3;
-		change_vertices(facet1, vnot1, new_vertex1);
-	}
-	if (facet2 != -1) {
-		int vnot2 = (facet2 == edge_a.facet_number) ?
-	  		(edge_a.which_edge + 2) % 3 :
-			(edge_b.which_edge + 2) % 3;
-		if (((vnot2 + 2) % 3) == vertex2)
-	  		vnot2 += 3;
-		change_vertices(facet2, vnot2, new_vertex2);
-	}
-	stl->stats.edges_fixed += 2;
-}
-
 // This function builds the neighbors list.  No modifications are made
 // to any of the facets.  The edges are said to match only if all six
 // floats of the first edge matches all six floats of the second edge.
@@ -445,7 +460,7 @@ void stl_check_facets_exact(stl_file *stl)
 			edge.facet_number = i;
 			edge.which_edge = j;
 			edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
-			hash_table.insert_edge(stl, edge, record_neighbors);
+			hash_table.insert_edge_exact(stl, edge);
 		}
 	}
 
@@ -476,7 +491,7 @@ void stl_check_facets_nearby(stl_file *stl, float tolerance)
         		edge.which_edge = j;
         		if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance))
           			// Only insert edges that have different keys.
-          			hash_table.insert_edge(stl, edge, match_neighbors_nearby);
+          			hash_table.insert_edge_nearby(stl, edge);
       		}
     	}
   	}
@@ -654,7 +669,7 @@ void stl_fill_holes(stl_file *stl)
 	  		edge.facet_number = i;
 	  		edge.which_edge = j;
 	  		edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
-	  		hash_table.insert_edge(stl, edge, record_neighbors);
+	  		hash_table.insert_edge_exact(stl, edge);
 		}
 	}
 
@@ -704,7 +719,7 @@ void stl_fill_holes(stl_file *stl)
 	        			edge.facet_number = stl->stats.number_of_facets - 1;
 	        			edge.which_edge = k;
 	        			edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]);
-	        			hash_table.insert_edge(stl, edge, record_neighbors);
+	        			hash_table.insert_edge_exact(stl, edge);
 	      			}
 	      			break;
 	    		}
diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp
index 464f9e6d8..4d47573f6 100644
--- a/src/admesh/normals.cpp
+++ b/src/admesh/normals.cpp
@@ -25,6 +25,8 @@
 #include <string.h>
 #include <math.h>
 
+#include <boost/pool/object_pool.hpp>
+
 #include "stl.h"
 
 static void reverse_facet(stl_file *stl, int facet_num)
@@ -120,8 +122,9 @@ void stl_fix_normal_directions(stl_file *stl)
   	};
 
   	// Initialize linked list.
-   	stl_normal *head = new stl_normal;
-  	stl_normal *tail = new stl_normal;
+  	boost::object_pool<stl_normal> pool;
+   	stl_normal *head = pool.construct();
+  	stl_normal *tail = pool.construct();
 	head->next = tail;
 	tail->next = tail;
 
@@ -168,7 +171,7 @@ void stl_fix_normal_directions(stl_file *stl)
         		// If we haven't fixed this facet yet, add it to the list:
         		if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
 	          		// Add node to beginning of list.
-	          		stl_normal *newn = new stl_normal;
+	          		stl_normal *newn = pool.construct();
 	          		newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
 	          		newn->next = head->next;
 	          		head->next = newn;
@@ -189,7 +192,7 @@ void stl_fix_normal_directions(stl_file *stl)
       		}
       		stl_normal *temp = head->next;	// Delete this facet from the list.
       		head->next = head->next->next;
-      		delete temp;
+      		pool.destroy(temp);
     	} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
       		++ stl->stats.number_of_parts;
       		if (checked >= stl->stats.number_of_facets)
@@ -211,8 +214,8 @@ void stl_fix_normal_directions(stl_file *stl)
     	}
   	}
 
-	delete head;
-	delete tail;
+	pool.destroy(head);
+	pool.destroy(tail);
 }
 
 void stl_fix_normal_values(stl_file *stl)
diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp
index 7e181716c..464c98907 100644
--- a/src/admesh/stl_io.cpp
+++ b/src/admesh/stl_io.cpp
@@ -25,7 +25,7 @@
 
 #include <boost/log/trivial.hpp>
 #include <boost/nowide/cstdio.hpp>
-#include <boost/detail/endian.hpp>
+#include <boost/predef/other/endian.h>
 
 #include "stl.h"
 
@@ -114,7 +114,7 @@ bool stl_print_neighbors(stl_file *stl, char *file)
   	return true;
 }
 
-#ifndef BOOST_LITTLE_ENDIAN
+#if BOOST_ENDIAN_BIG_BYTE
 // Swap a buffer of 32bit data from little endian to big endian and vice versa.
 void stl_internal_reverse_quads(char *buf, size_t cnt)
 {
@@ -141,11 +141,11 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 	#define SEEK_SET 0
 #endif
 	fseek(fp, LABEL_SIZE, SEEK_SET);
-#ifdef BOOST_LITTLE_ENDIAN
+#if BOOST_ENDIAN_LITTLE_BYTE
 	fwrite(&stl->stats.number_of_facets, 4, 1, fp);
 	for (const stl_facet &facet : stl->facet_start)
 	  	fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
-#else /* BOOST_LITTLE_ENDIAN */
+#else /* BOOST_ENDIAN_LITTLE_BYTE */
 	char buffer[50];
 	// Convert the number of facets to little endian.
 	memcpy(buffer, &stl->stats.number_of_facets, 4);
@@ -157,7 +157,7 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label)
 		stl_internal_reverse_quads(buffer, 48);
 		fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
 	}
-#endif /* BOOST_LITTLE_ENDIAN */
+#endif /* BOOST_ENDIAN_LITTLE_BYTE */
 	fclose(fp);
 	return true;
 }

From 0bb8ee149e8702fb644a70ab1f3924ff8e6f3d71 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 11 Jun 2019 17:08:47 +0200
Subject: [PATCH 14/22] Sharing TriangleMesh objects between the front end (UI)
 and back end (background processing)

---
 src/PrusaSlicer.cpp                          |   8 +-
 src/admesh/connect.cpp                       |  46 +++++---
 src/admesh/stl.h                             |  38 +++++-
 src/admesh/stlinit.cpp                       |   2 +-
 src/admesh/util.cpp                          |   2 +-
 src/libslic3r/Format/3mf.cpp                 |  27 +++--
 src/libslic3r/Format/AMF.cpp                 |  20 ++--
 src/libslic3r/Model.cpp                      | 118 +++++++++----------
 src/libslic3r/Model.hpp                      |  46 +++++---
 src/libslic3r/PrintObject.cpp                |  14 ++-
 src/libslic3r/Slicing.cpp                    |   2 +-
 src/libslic3r/TriangleMesh.cpp               |  72 ++++++-----
 src/libslic3r/TriangleMesh.hpp               |   2 +-
 src/slic3r/GUI/3DScene.cpp                   |  25 ++--
 src/slic3r/GUI/3DScene.hpp                   |  12 +-
 src/slic3r/GUI/GLCanvas3D.cpp                |   2 +-
 src/slic3r/GUI/GUI_ObjectList.cpp            |   4 +-
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp |   3 +-
 src/slic3r/GUI/Plater.cpp                    |   2 +-
 xs/xsp/Model.xsp                             |   2 +-
 20 files changed, 254 insertions(+), 193 deletions(-)

diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index fef1f6e7f..a3247b929 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -241,8 +241,7 @@ int CLI::run(int argc, char **argv)
         } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
             std::vector<Model> new_models;
             for (auto &model : m_models) {
-                model.repair();
-                model.translate(0, 0, -model.bounding_box().min.z());  // align to z = 0                
+                model.translate(0, 0, -model.bounding_box().min.z());  // align to z = 0
 				size_t num_objects = model.objects.size();
 				for (size_t i = 0; i < num_objects; ++ i) {
 
@@ -301,8 +300,9 @@ int CLI::run(int argc, char **argv)
                 }
             }
         } else if (opt_key == "repair") {
-            for (auto &model : m_models)
-                model.repair();
+			// Models are repaired by default.
+            //for (auto &model : m_models)
+            //    model.repair();
         } else {
             boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
             return 1;
diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index be782b1b7..1a7b7965d 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -59,7 +59,7 @@ struct HashEdge {
 
 	  	// Ensure identical vertex ordering of equal edges.
 	  	// This method is numerically robust.
-	  	if (stl_vertex_lower(*a, *b)) {
+	  	if (vertex_lower(*a, *b)) {
 	  	} else {
 	  		// This edge is loaded backwards.
 		    std::swap(a, b);
@@ -110,6 +110,12 @@ struct HashEdge {
 		}
 		return true;
 	}
+
+private:
+	inline bool vertex_lower(const stl_vertex &a, const stl_vertex &b) {
+	  	return (a(0) != b(0)) ? (a(0) < b(0)) :
+	           ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
+	}
 };
 
 struct HashTableEdges {
@@ -440,7 +446,9 @@ void stl_check_facets_exact(stl_file *stl)
 		stl_facet &facet = stl->facet_start[i];
 	  	if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
 		  	// Remove the degenerate facet.
-		  	facet = stl->facet_start[--stl->stats.number_of_facets];
+		  	facet = stl->facet_start[-- stl->stats.number_of_facets];
+			stl->facet_start.pop_back();
+			stl->neighbors_start.pop_back();
 		  	stl->stats.facets_removed += 1;
 		  	stl->stats.degenerate_facets += 1;
 	  	} else
@@ -526,23 +534,25 @@ void stl_remove_unconnected_facets(stl_file *stl)
 			assert(false);
 		}
 
-	  	if (facet_number == -- stl->stats.number_of_facets)
-	  		// Removing the last face is easy, just forget the last face.
-	  		return;
-
-	  	// Copy the face and neighborship from the last face to facet_number.
-	  	stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
-	  	neighbors = stl->neighbors_start[stl->stats.number_of_facets];
-	  	// Update neighborship of faces, which used to point to the last face, now moved to facet_number.
-	  	for (int i = 0; i < 3; ++ i)
-	    	if (neighbors.neighbor[i] != -1) {
-		    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
-		  		if (other_face_idx != stl->stats.number_of_facets) {
-		  			BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong";
-		    		return;
+	  	if (facet_number < -- stl->stats.number_of_facets) {
+	  		// Removing a face, which was not the last one.
+		  	// Copy the face and neighborship from the last face to facet_number.
+		  	stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
+		  	neighbors = stl->neighbors_start[stl->stats.number_of_facets];
+		  	// Update neighborship of faces, which used to point to the last face, now moved to facet_number.
+		  	for (int i = 0; i < 3; ++ i)
+		    	if (neighbors.neighbor[i] != -1) {
+			    	int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
+			  		if (other_face_idx != stl->stats.number_of_facets) {
+			  			BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong";
+			    		return;
+			  		}
+			  		other_face_idx = facet_number;
 		  		}
-		  		other_face_idx = facet_number;
-	  		}
+		}
+
+	  	stl->facet_start.pop_back();
+	  	stl->neighbors_start.pop_back();
 	};
 
 	auto remove_degenerate = [stl, remove_facet](int facet)
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index fce23eb3f..c419c567b 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -128,6 +128,8 @@ struct indexed_triangle_set
 	void clear() { indices.clear(); vertices.clear(); }
 	std::vector<stl_triangle_vertex_indices> 	indices;
 	std::vector<stl_vertex>       				vertices;
+	//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
+	//std::vector<stl_normal> 					normals
 };
 
 extern bool stl_open(stl_file *stl, const char *file);
@@ -186,7 +188,7 @@ template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
 {
 	const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
-	for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
+	for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		stl_facet &f = stl->facet_start[i];
 		for (size_t j = 0; j < 3; ++j)
 			f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
@@ -199,7 +201,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
 template<typename T>
 inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
 {
-	for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
+	for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		stl_facet &f = stl->facet_start[i];
 		for (size_t j = 0; j < 3; ++j)
 			f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
@@ -209,6 +211,34 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
 	stl_get_size(stl);
 }
 
+
+template<typename T>
+extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
+{
+	for (stl_vertex &v_dst : its.vertices) {
+		stl_vertex &v_dst = face.vertex[i_vertex];
+		stl_vertex  v_src = v_dst;
+		v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2) + trafo3x4[3]);
+		v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2) + trafo3x4[7]);
+		v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
+	}
+}
+
+template<typename T>
+inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
+{
+	const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
+	for (stl_vertex &v : its.vertices)
+		v = (t * v.template cast<T>()).template cast<float>().eval();
+}
+
+template<typename T>
+inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
+{
+	for (stl_vertex &v : its.vertices)
+		v = (m * v.template cast<T>()).template cast<float>().eval();
+}
+
 extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
 extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
 extern bool its_write_off(const indexed_triangle_set &its, const char *file);
@@ -225,10 +255,6 @@ inline void stl_normalize_vector(stl_normal &normal) {
   else
     normal *= float(1.0 / length);
 }
-inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
-  return (a(0) != b(0)) ? (a(0) < b(0)) :
-        ((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
-}
 extern void stl_calculate_volume(stl_file *stl);
 
 extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 24fbe9edc..0cc6e50c7 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -147,7 +147,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
     	rewind(fp);
 
   	char normal_buf[3][32];
-  	for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++i) {
+  	for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) {
   	  	stl_facet facet;
 
     	if (stl->stats.type == binary) {
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 6fff8a8ed..70f4ffc27 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -108,7 +108,7 @@ void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
 static void calculate_normals(stl_file *stl) 
 {
 	stl_normal normal;
-	for (uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
+	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
 		stl_calculate_normal(normal, &stl->facet_start[i]);
 		stl_normalize_vector(normal);
 		stl->facet_start[i].normal = normal;
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 654426528..4793586e3 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1489,10 +1489,10 @@ namespace Slic3r {
             }
 
             // splits volume out of imported geometry
-            unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1;
-            ModelVolume* volume = object.add_volume(TriangleMesh());
-            stl_file& stl = volume->mesh.stl;
-            stl.stats.type = inmemory;
+			TriangleMesh triangle_mesh;
+            stl_file    &stl             = triangle_mesh.stl;
+			unsigned int triangles_count = volume_data.last_triangle_id - volume_data.first_triangle_id + 1;
+			stl.stats.type = inmemory;
             stl.stats.number_of_facets = (uint32_t)triangles_count;
             stl.stats.original_num_facets = (int)stl.stats.number_of_facets;
             stl_allocate(&stl);
@@ -1509,9 +1509,11 @@ namespace Slic3r {
                 }
             }
 
-            stl_get_size(&stl);
-            volume->mesh.repair();
-            volume->center_geometry();
+			stl_get_size(&stl);
+			triangle_mesh.repair();
+
+			ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
+            volume->center_geometry_after_creation();
             volume->calculate_convex_hull();
 
             // apply volume's name and config data
@@ -1879,11 +1881,14 @@ namespace Slic3r {
             if (volume == nullptr)
                 continue;
 
+			if (!volume->mesh().repaired)
+				throw std::runtime_error("store_3mf() requires repair()");
+			if (!volume->mesh().has_shared_vertices())
+				throw std::runtime_error("store_3mf() requires shared vertices");
+
             volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
 
-			volume->mesh.require_shared_vertices();
-
-            const indexed_triangle_set &its = volume->mesh.its;
+            const indexed_triangle_set &its = volume->mesh().its;
             if (its.vertices.empty())
             {
                 add_error("Found invalid mesh");
@@ -1916,7 +1921,7 @@ namespace Slic3r {
             VolumeToOffsetsMap::iterator volume_it = volumes_offsets.find(volume);
             assert(volume_it != volumes_offsets.end());
 
-            const indexed_triangle_set &its = volume->mesh.its;
+            const indexed_triangle_set &its = volume->mesh().its;
 
             // updates triangle offsets
             volume_it->second.first_triangle_id = triangles_count;
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 48887bc78..a33d21c9f 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -522,7 +522,8 @@ void AMFParserContext::endElement(const char * /* name */)
     case NODE_TYPE_VOLUME:
     {
 		assert(m_object && m_volume);
-        stl_file &stl = m_volume->mesh.stl;
+		TriangleMesh  mesh;
+        stl_file	 &stl = mesh.stl;
         stl.stats.type = inmemory;
         stl.stats.number_of_facets = int(m_volume_facets.size() / 3);
         stl.stats.original_num_facets = stl.stats.number_of_facets;
@@ -533,8 +534,9 @@ void AMFParserContext::endElement(const char * /* name */)
                 memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
         }
         stl_get_size(&stl);
-        m_volume->mesh.repair();
-        m_volume->center_geometry();
+        mesh.repair();
+		m_volume->set_mesh(std::move(mesh));
+        m_volume->center_geometry_after_creation();
         m_volume->calculate_convex_hull();
         m_volume_facets.clear();
         m_volume = nullptr;
@@ -923,10 +925,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
         int              num_vertices = 0;
         for (ModelVolume *volume : object->volumes) {
             vertices_offsets.push_back(num_vertices);
-            if (! volume->mesh.repaired)
+            if (! volume->mesh().repaired)
                 throw std::runtime_error("store_amf() requires repair()");
-			volume->mesh.require_shared_vertices();
-            const indexed_triangle_set &its = volume->mesh.its;
+			if (! volume->mesh().has_shared_vertices())
+				throw std::runtime_error("store_amf() requires shared vertices");
+            const indexed_triangle_set &its = volume->mesh().its;
             const Transform3d& matrix = volume->get_matrix();
             for (size_t i = 0; i < its.vertices.size(); ++i) {
                 stream << "         <vertex>\n";
@@ -955,10 +958,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
             if (volume->is_modifier())
                 stream << "        <metadata type=\"slic3r.modifier\">1</metadata>\n";
             stream << "        <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
-            for (size_t i = 0; i < (int)volume->mesh.its.indices.size(); ++i) {
+			const indexed_triangle_set &its = volume->mesh().its;
+            for (size_t i = 0; i < (int)its.indices.size(); ++i) {
                 stream << "        <triangle>\n";
                 for (int j = 0; j < 3; ++j)
-                stream << "          <v" << j + 1 << ">" << volume->mesh.its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
+                stream << "          <v" << j + 1 << ">" << its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
                 stream << "        </triangle>\n";
             }
             stream << "      </volume>\n";
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 770581c03..113b21503 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -160,12 +160,6 @@ Model Model::read_from_archive(const std::string &input_file, DynamicPrintConfig
     return model;
 }
 
-void Model::repair()
-{
-    for (ModelObject *o : this->objects)
-        o->repair();
-}
-
 ModelObject* Model::add_object()
 {
     this->objects.emplace_back(new ModelObject(this));
@@ -472,7 +466,7 @@ bool Model::looks_like_multipart_object() const
         if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
             return false;
         for (const ModelVolume *vol : obj->volumes) {
-            double zmin_this = vol->mesh.bounding_box().min(2);
+            double zmin_this = vol->mesh().bounding_box().min(2);
             if (zmin == std::numeric_limits<double>::max())
                 zmin = zmin_this;
             else if (std::abs(zmin - zmin_this) > EPSILON)
@@ -679,7 +673,7 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
 {
     ModelVolume* v = new ModelVolume(this, mesh);
     this->volumes.push_back(v);
-    v->center_geometry();
+    v->center_geometry_after_creation();
     this->invalidate_bounding_box();
     return v;
 }
@@ -688,7 +682,7 @@ ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh)
 {
     ModelVolume* v = new ModelVolume(this, std::move(mesh));
     this->volumes.push_back(v);
-    v->center_geometry();
+    v->center_geometry_after_creation();
     this->invalidate_bounding_box();
     return v;
 }
@@ -697,7 +691,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other)
 {
     ModelVolume* v = new ModelVolume(this, other);
     this->volumes.push_back(v);
-    v->center_geometry();
+    v->center_geometry_after_creation();
     this->invalidate_bounding_box();
     return v;
 }
@@ -706,7 +700,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, TriangleMesh &&me
 {
     ModelVolume* v = new ModelVolume(this, other, std::move(mesh));
     this->volumes.push_back(v);
-    v->center_geometry();
+    v->center_geometry_after_creation();
     this->invalidate_bounding_box();
     return v;
 }
@@ -827,7 +821,7 @@ TriangleMesh ModelObject::raw_mesh() const
     for (const ModelVolume *v : this->volumes)
         if (v->is_model_part())
         {
-            TriangleMesh vol_mesh(v->mesh);
+            TriangleMesh vol_mesh(v->mesh());
             vol_mesh.transform(v->get_matrix());
             mesh.merge(vol_mesh);
         }
@@ -840,7 +834,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
     TriangleMesh mesh;
     for (const ModelVolume *v : this->volumes)
     {
-        TriangleMesh vol_mesh(v->mesh);
+        TriangleMesh vol_mesh(v->mesh());
         vol_mesh.transform(v->get_matrix());
         mesh.merge(vol_mesh);
     }
@@ -854,7 +848,7 @@ const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
         m_raw_mesh_bounding_box.reset();
         for (const ModelVolume *v : this->volumes)
             if (v->is_model_part())
-                m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
+                m_raw_mesh_bounding_box.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
     }
     return m_raw_mesh_bounding_box;
 }
@@ -863,7 +857,7 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
 {
 	BoundingBoxf3 bb;
 	for (const ModelVolume *v : this->volumes)
-		bb.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
+		bb.merge(v->mesh().transformed_bounding_box(v->get_matrix()));
 	return bb;
 }
 
@@ -881,7 +875,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
         for (const ModelVolume *v : this->volumes)
         {
             if (v->is_model_part())
-                m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
+                m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
         }
     }
 	return m_raw_bounding_box;
@@ -895,7 +889,7 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
     for (ModelVolume *v : this->volumes)
     {
         if (v->is_model_part())
-            bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
+            bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
     }
     return bb;
 }
@@ -909,10 +903,10 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const
     for (const ModelVolume *v : this->volumes)
         if (v->is_model_part()) {
             Transform3d trafo = trafo_instance * v->get_matrix();
-			const indexed_triangle_set &its = v->mesh.its;
+			const indexed_triangle_set &its = v->mesh().its;
 			if (its.vertices.empty()) {
                 // Using the STL faces.
-				const stl_file& stl = v->mesh.stl;
+				const stl_file& stl = v->mesh().stl;
 				for (const stl_facet &facet : stl.facet_start)
                     for (size_t j = 0; j < 3; ++ j) {
                         Vec3d p = trafo * facet.vertex[j].cast<double>();
@@ -1038,6 +1032,7 @@ void ModelObject::mirror(Axis axis)
     this->invalidate_bounding_box();
 }
 
+// This method could only be called before the meshes of this ModelVolumes are not shared!
 void ModelObject::scale_mesh(const Vec3d &versor)
 {
     for (ModelVolume *v : this->volumes)
@@ -1061,14 +1056,14 @@ size_t ModelObject::facets_count() const
     size_t num = 0;
     for (const ModelVolume *v : this->volumes)
         if (v->is_model_part())
-            num += v->mesh.stl.stats.number_of_facets;
+            num += v->mesh().stl.stats.number_of_facets;
     return num;
 }
 
 bool ModelObject::needed_repair() const
 {
     for (const ModelVolume *v : this->volumes)
-        if (v->is_model_part() && v->mesh.needed_repair())
+        if (v->is_model_part() && v->mesh().needed_repair())
             return true;
     return false;
 }
@@ -1134,11 +1129,12 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
 
             // Transform the mesh by the combined transformation matrix.
             // Flip the triangles in case the composite transformation is left handed.
-            volume->mesh.transform(instance_matrix * volume_matrix, true);
+			TriangleMesh mesh(volume->mesh());
+			mesh.transform(instance_matrix * volume_matrix, true);
+			volume->reset_mesh();
 
             // Perform cut
-            volume->mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
-            TriangleMeshSlicer tms(&volume->mesh);
+            TriangleMeshSlicer tms(&mesh);
             tms.cut(float(z), &upper_mesh, &lower_mesh);
 
             // Reset volume transformation except for offset
@@ -1157,14 +1153,14 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
 
             if (keep_upper && upper_mesh.facets_count() > 0) {
                 ModelVolume* vol = upper->add_volume(upper_mesh);
-                vol->name = volume->name;
-                vol->config         = volume->config;
+                vol->name	= volume->name;
+                vol->config = volume->config;
                 vol->set_material(volume->material_id(), *volume->material());
             }
             if (keep_lower && lower_mesh.facets_count() > 0) {
                 ModelVolume* vol = lower->add_volume(lower_mesh);
-                vol->name = volume->name;
-                vol->config         = volume->config;
+                vol->name	= volume->name;
+                vol->config = volume->config;
                 vol->set_material(volume->material_id(), *volume->material());
 
                 // Compute the lower part instances' bounding boxes to figure out where to place
@@ -1232,7 +1228,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
     }
     
     ModelVolume* volume = this->volumes.front();
-    TriangleMeshPtrs meshptrs = volume->mesh.split();
+    TriangleMeshPtrs meshptrs = volume->mesh().split();
     for (TriangleMesh *mesh : meshptrs) {
         mesh->repair();
         
@@ -1259,12 +1255,6 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
     return;
 }
 
-void ModelObject::repair()
-{
-    for (ModelVolume *v : this->volumes)
-        v->mesh.repair();
-}
-
 // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees,
 // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure.
 // This situation is solved by baking in the instance transformation into the mesh vertices.
@@ -1294,8 +1284,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
 
     // Adjust the meshes.
     // Transformation to be applied to the meshes.
-    Eigen::Matrix3d    mesh_trafo_3x3           = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
-	Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
+    Eigen::Matrix3d mesh_trafo_3x3           = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
+	Transform3d     volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
     for (ModelVolume *model_volume : this->volumes) {
         const Geometry::Transformation volume_trafo = model_volume->get_transformation();
         bool   volume_left_handed        = volume_trafo.is_left_handed();
@@ -1305,7 +1295,8 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
         double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
         // Transform the mesh.
 		Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
-		model_volume->transform_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
+        // Following method creates a new shared_ptr<TriangleMesh>
+		model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
         // Reset the rotation, scaling and mirroring.
         model_volume->set_rotation(Vec3d(0., 0., 0.));
         model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor));
@@ -1447,7 +1438,7 @@ std::string ModelObject::get_export_filename() const
 stl_stats ModelObject::get_object_stl_stats() const
 {
     if (this->volumes.size() == 1)
-        return this->volumes[0]->mesh.stl.stats;
+        return this->volumes[0]->mesh().stl.stats;
 
     stl_stats full_stats;
     memset(&full_stats, 0, sizeof(stl_stats));
@@ -1458,7 +1449,7 @@ stl_stats ModelObject::get_object_stl_stats() const
         if (volume->id() == this->volumes[0]->id())
             continue;
 
-        const stl_stats& stats = volume->mesh.stl.stats;
+        const stl_stats& stats = volume->mesh().stl.stats;
 
         // initialize full_stats (for repaired errors)
         full_stats.degenerate_facets    += stats.degenerate_facets;
@@ -1526,30 +1517,30 @@ bool ModelVolume::is_splittable() const
 {
     // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once
     if (m_is_splittable == -1)
-        m_is_splittable = (int)mesh.is_splittable();
+        m_is_splittable = (int)this->mesh().is_splittable();
 
     return m_is_splittable == 1;
 }
 
-void ModelVolume::center_geometry()
+void ModelVolume::center_geometry_after_creation()
 {
-    Vec3d shift = mesh.bounding_box().center();
+    Vec3d shift = this->mesh().bounding_box().center();
     if (!shift.isApprox(Vec3d::Zero()))
     {
-        mesh.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
-        m_convex_hull.translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
+        m_mesh->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
+        m_convex_hull->translate(-(float)shift(0), -(float)shift(1), -(float)shift(2));
         translate(shift);
     }
 }
 
 void ModelVolume::calculate_convex_hull()
 {
-    m_convex_hull = mesh.convex_hull_3d();
+    m_convex_hull = std::make_shared<TriangleMesh>(this->mesh().convex_hull_3d());
 }
 
 int ModelVolume::get_mesh_errors_count() const
 {
-    const stl_stats& stats = this->mesh.stl.stats;
+    const stl_stats& stats = this->mesh().stl.stats;
 
     return  stats.degenerate_facets + stats.edges_fixed     + stats.facets_removed +
             stats.facets_added      + stats.facets_reversed + stats.backwards_edges;
@@ -1557,7 +1548,7 @@ int ModelVolume::get_mesh_errors_count() const
 
 const TriangleMesh& ModelVolume::get_convex_hull() const
 {
-    return m_convex_hull;
+    return *m_convex_hull.get();
 }
 
 ModelVolumeType ModelVolume::type_from_string(const std::string &s)
@@ -1597,7 +1588,7 @@ std::string ModelVolume::type_to_string(const ModelVolumeType t)
 // This is useful to assign different materials to different volumes of an object.
 size_t ModelVolume::split(unsigned int max_extruders)
 {
-    TriangleMeshPtrs meshptrs = this->mesh.split();
+    TriangleMeshPtrs meshptrs = this->mesh().split();
     if (meshptrs.size() <= 1) {
         delete meshptrs.front();
         return 1;
@@ -1614,7 +1605,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
         mesh->repair();
         if (idx == 0)
         {
-            this->mesh = std::move(*mesh);
+            this->set_mesh(std::move(*mesh));
             this->calculate_convex_hull();
             // Assign a new unique ID, so that a new GLVolume will be generated.
             this->set_new_unique_id();
@@ -1623,7 +1614,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
             this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
 
         this->object->volumes[ivolume]->set_offset(Vec3d::Zero());
-        this->object->volumes[ivolume]->center_geometry();
+        this->object->volumes[ivolume]->center_geometry_after_creation();
         this->object->volumes[ivolume]->translate(offset);
         this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
         this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders));
@@ -1689,24 +1680,33 @@ void ModelVolume::mirror(Axis axis)
     set_mirror(mirror);
 }
 
+// This method could only be called before the meshes of this ModelVolumes are not shared!
 void ModelVolume::scale_geometry(const Vec3d& versor)
 {
-    mesh.scale(versor);
-    m_convex_hull.scale(versor);
+    m_mesh->scale(versor);
+    m_convex_hull->scale(versor);
 }
 
-void ModelVolume::transform_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
+void ModelVolume::transform_this_mesh(const Transform3d &mesh_trafo, bool fix_left_handed)
 {
-    this->mesh.transform(mesh_trafo, fix_left_handed);
-    this->m_convex_hull.transform(mesh_trafo, fix_left_handed);
+	TriangleMesh mesh = this->mesh();
+	mesh.transform(mesh_trafo, fix_left_handed);
+	this->set_mesh(std::move(mesh));
+    TriangleMesh convex_hull = this->get_convex_hull();
+    convex_hull.transform(mesh_trafo, fix_left_handed);
+    this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
     // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
     this->set_new_unique_id();
 }
 
-void ModelVolume::transform_mesh(const Matrix3d &matrix, bool fix_left_handed)
+void ModelVolume::transform_this_mesh(const Matrix3d &matrix, bool fix_left_handed)
 {
-	this->mesh.transform(matrix, fix_left_handed);
-	this->m_convex_hull.transform(matrix, fix_left_handed);
+	TriangleMesh mesh = this->mesh();
+	mesh.transform(matrix, fix_left_handed);
+	this->set_mesh(std::move(mesh));
+    TriangleMesh convex_hull = this->get_convex_hull();
+    convex_hull.transform(matrix, fix_left_handed);
+    this->m_convex_hull = std::make_shared<TriangleMesh>(std::move(convex_hull));
     // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded.
     this->set_new_unique_id();
 }
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 41bf5bd4b..0fd1140f0 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -7,7 +7,9 @@
 #include "Point.hpp"
 #include "TriangleMesh.hpp"
 #include "Slicing.hpp"
+
 #include <map>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -261,6 +263,7 @@ public:
     void rotate(double angle, const Vec3d& axis);
     void mirror(Axis axis);
 
+    // This method could only be called before the meshes of this ModelVolumes are not shared!
     void scale_mesh(const Vec3d& versor);
 
     size_t materials_count() const;
@@ -268,7 +271,6 @@ public:
     bool needed_repair() const;
     ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);    // Note: z is in world coordinates
     void split(ModelObjectPtrs* new_objects);
-    void repair();
     // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees,
     // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure.
     // This situation is solved by baking in the instance transformation into the mesh vertices.
@@ -340,7 +342,12 @@ class ModelVolume : public ModelBase
 public:
     std::string         name;
     // The triangular model.
-    TriangleMesh        mesh;
+    const TriangleMesh& mesh() const { return *m_mesh.get(); }
+    void                set_mesh(const TriangleMesh &mesh) { m_mesh = std::make_shared<TriangleMesh>(mesh); }
+    void                set_mesh(TriangleMesh &&mesh) { m_mesh = std::make_shared<TriangleMesh>(std::move(mesh)); }
+    void                set_mesh(std::shared_ptr<TriangleMesh> &mesh) { m_mesh = mesh; }
+    void                set_mesh(std::unique_ptr<TriangleMesh> &&mesh) { m_mesh = std::move(mesh); }
+	void				reset_mesh() { m_mesh = std::make_shared<TriangleMesh>(); }
     // Configuration parameters specific to an object model geometry or a modifier volume, 
     // overriding the global Slic3r settings and the ModelObject settings.
     DynamicPrintConfig  config;
@@ -377,13 +384,16 @@ public:
     void                rotate(double angle, const Vec3d& axis);
     void                mirror(Axis axis);
 
+    // This method could only be called before the meshes of this ModelVolumes are not shared!
     void                scale_geometry(const Vec3d& versor);
 
-    // translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box
-    void                center_geometry();
+    // Translates the mesh and the convex hull so that the origin of their vertices is in the center of this volume's bounding box.
+    // Attention! This method may only be called just after ModelVolume creation! It must not be called once the TriangleMesh of this ModelVolume is shared!
+    void                center_geometry_after_creation();
 
     void                calculate_convex_hull();
     const TriangleMesh& get_convex_hull() const;
+    std::shared_ptr<const TriangleMesh> get_convex_hull_shared_ptr() const { return m_convex_hull; }
     // Get count of errors in the mesh
     int                 get_mesh_errors_count() const;
 
@@ -430,18 +440,20 @@ protected:
 
 	explicit ModelVolume(const ModelVolume &rhs) = default;
     void     set_model_object(ModelObject *model_object) { object = model_object; }
-    void     transform_mesh(const Transform3d& t, bool fix_left_handed);
-    void     transform_mesh(const Matrix3d& m, bool fix_left_handed);
+    void     transform_this_mesh(const Transform3d& t, bool fix_left_handed);
+    void     transform_this_mesh(const Matrix3d& m, bool fix_left_handed);
 
 private:
     // Parent object owning this ModelVolume.
-    ModelObject*            object;
+    ModelObject*                    object;
+    // The triangular model.
+    std::shared_ptr<TriangleMesh>   m_mesh;
     // Is it an object to be printed, or a modifier volume?
-    ModelVolumeType         m_type;
-    t_model_material_id     m_material_id;
+    ModelVolumeType                 m_type;
+    t_model_material_id             m_material_id;
     // The convex hull of this model's mesh.
-    TriangleMesh             m_convex_hull;
-    Geometry::Transformation m_transformation;
+    std::shared_ptr<TriangleMesh>   m_convex_hull;
+    Geometry::Transformation        m_transformation;
 
     // flag to optimize the checking if the volume is splittable
     //     -1   ->   is unknown value (before first cheking)
@@ -449,24 +461,24 @@ private:
     //      1   ->   is splittable
     mutable int               m_is_splittable{ -1 };
 
-	ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object)
+	ModelVolume(ModelObject *object, const TriangleMesh &mesh) : m_mesh(new TriangleMesh(mesh)), m_type(ModelVolumeType::MODEL_PART), object(object)
     {
         if (mesh.stl.stats.number_of_facets > 1)
             calculate_convex_hull();
     }
     ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
-		mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {}
+		m_mesh(new TriangleMesh(std::move(mesh))), m_convex_hull(new TriangleMesh(std::move(convex_hull))), m_type(ModelVolumeType::MODEL_PART), object(object) {}
 
     // Copying an existing volume, therefore this volume will get a copy of the ID assigned.
     ModelVolume(ModelObject *object, const ModelVolume &other) :
         ModelBase(other), // copy the ID
-        name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
+        name(other.name), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
     {
         this->set_material_id(other.material_id());
     }
     // Providing a new mesh, therefore this volume will get a new unique ID assigned.
     ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
-        name(other.name), mesh(std::move(mesh)), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
+        name(other.name), m_mesh(new TriangleMesh(std::move(mesh))), config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation)
     {
         this->set_material_id(other.material_id());
         if (mesh.stl.stats.number_of_facets > 1)
@@ -597,10 +609,6 @@ public:
     static Model read_from_file(const std::string &input_file, DynamicPrintConfig *config = nullptr, bool add_default_instances = true);
     static Model read_from_archive(const std::string &input_file, DynamicPrintConfig *config, bool add_default_instances = true);
 
-    /// Repair the ModelObjects of the current Model.
-    /// This function calls repair function on each TriangleMesh of each model object volume
-    void         repair();
-
     // Add a new ModelObject to this Model, generate a new ID for this ModelObject.
     ModelObject* add_object();
     ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 660a2d939..d99aceabf 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1797,7 +1797,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
     if (! volumes.empty()) {
         // Compose mesh.
         //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
-		TriangleMesh mesh(volumes.front()->mesh);
+		TriangleMesh mesh(volumes.front()->mesh());
         mesh.transform(volumes.front()->get_matrix(), true);
 		assert(mesh.repaired);
 		if (volumes.size() == 1 && mesh.repaired) {
@@ -1806,7 +1806,7 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
 		}
         for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) {
             const ModelVolume &model_volume = *volumes[idx_volume];
-            TriangleMesh vol_mesh(model_volume.mesh);
+            TriangleMesh vol_mesh(model_volume.mesh());
             vol_mesh.transform(model_volume.get_matrix(), true);
             mesh.merge(vol_mesh);
         }
@@ -1815,10 +1815,11 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
             // apply XY shift
             mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
             // perform actual slicing
-            TriangleMeshSlicer mslicer;
             const Print *print = this->print();
             auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
-            mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
+            // TriangleMeshSlicer needs shared vertices, also this calls the repair() function.
+            mesh.require_shared_vertices();
+            TriangleMeshSlicer mslicer;
             mslicer.init(&mesh, callback);
 			mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
             m_print->throw_if_canceled();
@@ -1832,7 +1833,7 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
     std::vector<ExPolygons> layers;
     // Compose mesh.
     //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
-    TriangleMesh mesh(volume.mesh);
+    TriangleMesh mesh(volume.mesh());
     mesh.transform(volume.get_matrix(), true);
 	if (mesh.repaired) {
 		//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
@@ -1846,7 +1847,8 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z,
         TriangleMeshSlicer mslicer;
         const Print *print = this->print();
         auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
-        mesh.require_shared_vertices(); // TriangleMeshSlicer needs this
+        // TriangleMeshSlicer needs the shared vertices.
+        mesh.require_shared_vertices();
         mslicer.init(&mesh, callback);
         mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
         m_print->throw_if_canceled();
diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp
index 3a05e9d8a..e1bb4b313 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -227,7 +227,7 @@ std::vector<coordf_t> layer_height_profile_adaptive(
     as.set_slicing_parameters(slicing_params);
     for (const ModelVolume *volume : volumes)
         if (volume->is_model_part())
-            as.add_mesh(&volume->mesh);
+            as.add_mesh(&volume->mesh());
     as.prepare();
 
     // 2) Generate layers using the algorithm of @platsch 
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 5b0ecbd00..11f45147c 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -82,11 +82,14 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
 
 // #define SLIC3R_TRACE_REPAIR
 
-void TriangleMesh::repair()
+void TriangleMesh::repair(bool update_shared_vertices)
 {
-    if (this->repaired)
+    if (this->repaired) {
+    	if (update_shared_vertices)
+    		this->require_shared_vertices();
     	return;
-    
+    }
+
     // admesh fails when repairing empty meshes
     if (this->stl.stats.number_of_facets == 0)
     	return;
@@ -97,6 +100,7 @@ void TriangleMesh::repair()
 #ifdef SLIC3R_TRACE_REPAIR
 	BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact";
 #endif /* SLIC3R_TRACE_REPAIR */
+	assert(stl_validate(&this->stl));
 	stl_check_facets_exact(&stl);
     assert(stl_validate(&this->stl));
     stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge);
@@ -179,6 +183,12 @@ void TriangleMesh::repair()
     this->repaired = true;
 
     BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() finished";
+
+    // This call should be quite cheap, a lot of code requires the indexed_triangle_set data structure,
+    // and it is risky to generate such a structure once the meshes are shared. Do it now.
+    this->its.clear();
+    if (update_shared_vertices)
+    	this->require_shared_vertices();
 }
 
 float TriangleMesh::volume()
@@ -238,8 +248,7 @@ bool TriangleMesh::needed_repair() const
 
 void TriangleMesh::WriteOBJFile(const char* output_file)
 {
-    stl_generate_shared_vertices(&stl, its);
-    its_write_obj(its, output_file);
+    its_write_obj(this->its, output_file);
 }
 
 void TriangleMesh::scale(float factor)
@@ -294,6 +303,7 @@ void TriangleMesh::rotate(float angle, const Vec3d& axis)
     Transform3d m = Transform3d::Identity();
     m.rotate(Eigen::AngleAxisd(angle, axis_norm));
     stl_transform(&stl, m);
+    its_transform(its, m);
 }
 
 void TriangleMesh::mirror(const Axis &axis)
@@ -311,22 +321,26 @@ void TriangleMesh::mirror(const Axis &axis)
 void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
 {
     stl_transform(&stl, t);
-    this->its.clear();
+    its_transform(its, t);
 	if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
 		// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
-		this->repair();
+		this->repair(false);
 		stl_reverse_all_facets(&stl);
+		this->its.clear();
+		this->require_shared_vertices();
 	}
 }
 
 void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
 {
     stl_transform(&stl, m);
-    this->its.clear();
+    its_transform(its, m);
     if (fix_left_handed && m.determinant() < 0.) {
         // Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
-        this->repair();
+        this->repair(false);
         stl_reverse_all_facets(&stl);
+		this->its.clear();
+		this->require_shared_vertices();
     }
 }
 
@@ -482,7 +496,6 @@ ExPolygons TriangleMesh::horizontal_projection() const
 // 2D convex hull of a 3D mesh projected into the Z=0 plane.
 Polygon TriangleMesh::convex_hull()
 {
-    this->require_shared_vertices();
     Points pp;
     pp.reserve(this->its.vertices.size());
     for (size_t i = 0; i < this->its.vertices.size(); ++ i) {
@@ -519,26 +532,32 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c
 
 TriangleMesh TriangleMesh::convex_hull_3d() const
 {
-    // Helper struct for qhull:
-    struct PointForQHull{
-        PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {}
-        realT x, y, z;
-    };
-    std::vector<PointForQHull> src_vertices;
-
-    // We will now fill the vector with input points for computation:
-	for (const stl_facet &facet : stl.facet_start)
-        for (int i = 0; i < 3; ++ i) {
-            const stl_vertex& v = facet.vertex[i];
-            src_vertices.emplace_back(v(0), v(1), v(2));
-        }
-
     // The qhull call:
     orgQhull::Qhull qhull;
     qhull.disableOutputStream(); // we want qhull to be quiet
-    try
+	std::vector<realT> src_vertices;
+	try
     {
-        qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt");
+    	if (this->has_shared_vertices()) {
+#if REALfloat
+	    	qhull.runQhull("", 3, (int)this->its.vertices.size() / 3, (const realT*)(this->its.vertices.front().data()), "Qt");
+#else
+	    	src_vertices.reserve(this->its.vertices() * 3);
+	    	// We will now fill the vector with input points for computation:
+			for (const stl_vertex &v : ths->its.vertices.size())
+				for (int i = 0; i < 3; ++ i)
+		        	src_vertices.emplace_back(v(i));
+	        qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
+#endif
+	    } else {
+	    	src_vertices.reserve(this->stl.facet_start.size() * 9);
+	    	// We will now fill the vector with input points for computation:
+			for (const stl_facet &f : this->stl.facet_start)
+				for (int i = 0; i < 3; ++ i)
+					for (int j = 0; j < 3; ++ j)
+		        		src_vertices.emplace_back(f.vertex[i](j));
+	        qhull.runQhull("", 3, (int)src_vertices.size() / 3, src_vertices.data(), "Qt");
+	    }
     }
     catch (...)
     {
@@ -566,7 +585,6 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
 
     TriangleMesh output_mesh(dst_vertices, facets);
     output_mesh.repair();
-    output_mesh.require_shared_vertices();
     return output_mesh;
 }
 
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index 75082cfdb..ffd9b7e62 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -33,7 +33,7 @@ public:
     bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
     bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); }
     bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); }
-    void repair();
+    void repair(bool update_shared_vertices = true);
     float volume();
     void check_topology();
     bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == (int)this->stl.stats.number_of_facets; }
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 59480de1c..33ab1f5d1 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -241,8 +241,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
     : m_transformed_bounding_box_dirty(true)
     , m_sla_shift_z(0.0)
     , m_transformed_convex_hull_bounding_box_dirty(true)
-    , m_convex_hull(nullptr)
-    , m_convex_hull_owned(false)
     // geometry_id == 0 -> invalid
     , geometry_id(std::pair<size_t, size_t>(0, 0))
     , extruder_id(0)
@@ -268,12 +266,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
     set_render_color(r, g, b, a);
 }
 
-GLVolume::~GLVolume()
-{
-    if (m_convex_hull_owned)
-        delete m_convex_hull;
-}
-
 void GLVolume::set_render_color(float r, float g, float b, float a)
 {
     render_color[0] = r;
@@ -335,12 +327,6 @@ void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume)
     color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
 }
 
-void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned)
-{
-    m_convex_hull = convex_hull;
-    m_convex_hull_owned = owned;
-}
-
 Transform3d GLVolume::world_matrix() const
 {
     Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix();
@@ -377,7 +363,7 @@ const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
 
 BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const
 {
-	return (m_convex_hull != nullptr && m_convex_hull->stl.stats.number_of_facets > 0) ? 
+	return (m_convex_hull && m_convex_hull->stl.stats.number_of_facets > 0) ? 
 		m_convex_hull->transformed_bounding_box(trafo) :
 		bounding_box.transformed(trafo);
 }
@@ -587,7 +573,7 @@ int GLVolumeCollection::load_object_volume(
     const ModelVolume   *model_volume = model_object->volumes[volume_idx];
     const int            extruder_id  = model_volume->extruder_id();
     const ModelInstance *instance     = model_object->instances[instance_idx];
-    const TriangleMesh& mesh = model_volume->mesh;
+    const TriangleMesh& mesh = model_volume->mesh();
     float color[4];
     memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
 /*    if (model_volume->is_support_blocker()) {
@@ -613,7 +599,7 @@ int GLVolumeCollection::load_object_volume(
     if (model_volume->is_model_part())
     {
 		// GLVolume will reference a convex hull from model_volume!
-        v.set_convex_hull(&model_volume->get_convex_hull(), false);
+        v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
         if (extruder_id != -1)
             v.extruder_id = extruder_id;
     }
@@ -656,7 +642,10 @@ void GLVolumeCollection::load_object_auxiliary(
         v.composite_id = GLVolume::CompositeID(obj_idx, - int(milestone), (int)instance_idx.first);
         v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
 		// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
-		v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true);
+        if (&instance_idx == &instances.back())
+            v.set_convex_hull(std::move(convex_hull));
+        else
+            v.set_convex_hull(convex_hull);
         v.is_modifier  = false;
         v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree);
         v.set_instance_transformation(model_instance.get_transformation());
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 2ca11073b..b9ac668e0 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -10,6 +10,7 @@
 #include "slic3r/GUI/GLCanvas3DManager.hpp"
 
 #include <functional>
+#include <memory>
 
 #ifndef NDEBUG
 #define HAS_GLSAFE
@@ -243,7 +244,6 @@ public:
 
     GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
     GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
-    ~GLVolume();
 
 private:
     Geometry::Transformation m_instance_transformation;
@@ -255,10 +255,8 @@ private:
     mutable BoundingBoxf3 m_transformed_bounding_box;
     // Whether or not is needed to recalculate the transformed bounding box.
     mutable bool          m_transformed_bounding_box_dirty;
-    // Pointer to convex hull of the original mesh, if any.
-    // This object may or may not own the convex hull instance based on m_convex_hull_owned
-    const TriangleMesh*   m_convex_hull;
-    bool                  m_convex_hull_owned;
+    // Convex hull of the volume, if any.
+    std::shared_ptr<const TriangleMesh> m_convex_hull;
     // Bounding box of this volume, in unscaled coordinates.
     mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
     // Whether or not is needed to recalculate the transformed convex hull bounding box.
@@ -395,7 +393,9 @@ public:
     double get_sla_shift_z() const { return m_sla_shift_z; }
     void set_sla_shift_z(double z) { m_sla_shift_z = z; }
 
-    void set_convex_hull(const TriangleMesh *convex_hull, bool owned);
+    void set_convex_hull(std::shared_ptr<const TriangleMesh> &convex_hull) { m_convex_hull = convex_hull; }
+    void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(convex_hull); }
+    void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(std::move(convex_hull)); }
 
     int                 object_idx() const { return this->composite_id.object_id; }
     int                 volume_idx() const { return this->composite_id.volume_id; }
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index b8ca905d2..f0a40950d 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -5498,7 +5498,7 @@ void GLCanvas3D::_load_sla_shells()
         v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0));
         v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation));
         v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.);
-        v.set_convex_hull(new TriangleMesh(std::move(mesh.convex_hull_3d())), true);
+        v.set_convex_hull(mesh.convex_hull_3d());
     };
 
     // adds objects' volumes 
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index dffa02e95..cbf7a5ef5 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -261,7 +261,7 @@ wxString ObjectList::get_mesh_errors_list(const int obj_idx, const int vol_idx /
 
     const stl_stats& stats = vol_idx == -1 ?
                             (*m_objects)[obj_idx]->get_object_stl_stats() :
-                            (*m_objects)[obj_idx]->volumes[vol_idx]->mesh.stl.stats;
+                            (*m_objects)[obj_idx]->volumes[vol_idx]->mesh().stl.stats;
 
     std::map<std::string, int> error_msg = {
         { L("degenerate facets"),   stats.degenerate_facets },
@@ -1592,7 +1592,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
         // First (any) GLVolume of the selected instance. They all share the same instance matrix.
         const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
         // Transform the new modifier to be aligned with the print bed.
-		const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box();
+		const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
 		new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
         // Set the modifier position.
         auto offset = (type_name == "Slab") ?
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 89475a058..2a2adcae9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -388,8 +388,7 @@ void GLGizmoSlaSupports::update_mesh()
     wxBusyCursor wait;
     // this way we can use that mesh directly.
     // This mesh does not account for the possible Z up SLA offset.
-    m_mesh = &m_model_object->volumes.front()->mesh;
-    const_cast<TriangleMesh*>(m_mesh)->require_shared_vertices(); // TriangleMeshSlicer needs this
+    m_mesh = &m_model_object->volumes.front()->mesh();
     m_its = &m_mesh->its;
     m_current_mesh_model_id = m_model_object->id();
     m_editing_mode = false;
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 44f77b3f7..18b3078bb 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3565,7 +3565,7 @@ void Plater::export_stl(bool extended, bool selection_only)
         else
         {
             const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
-            mesh = model_object->volumes[volume->volume_idx()]->mesh;
+            mesh = model_object->volumes[volume->volume_idx()]->mesh();
             mesh.transform(volume->get_volume_transformation().get_matrix());
             mesh.translate(-model_object->origin_translation.cast<float>());
         }
diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp
index a1c8890ef..6a2cc6080 100644
--- a/xs/xsp/Model.xsp
+++ b/xs/xsp/Model.xsp
@@ -253,7 +253,7 @@ ModelMaterial::attributes()
     Ref<DynamicPrintConfig> config()
         %code%{ RETVAL = &THIS->config; %};
     Ref<TriangleMesh> mesh()
-        %code%{ RETVAL = &THIS->mesh; %};
+        %code%{ RETVAL = &THIS->mesh(); %};
     
     bool modifier()
         %code%{ RETVAL = THIS->is_modifier(); %};

From 3872b939e440421dec0fc2cee8fad40fba6f1c0c Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 11 Jun 2019 17:15:07 +0200
Subject: [PATCH 15/22] Fix of previous commit

---
 src/admesh/stl.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index c419c567b..40bced2f4 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -216,7 +216,6 @@ template<typename T>
 extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
 {
 	for (stl_vertex &v_dst : its.vertices) {
-		stl_vertex &v_dst = face.vertex[i_vertex];
 		stl_vertex  v_src = v_dst;
 		v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2]  * v_src(2) + trafo3x4[3]);
 		v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6]  * v_src(2) + trafo3x4[7]);

From 9379fedd439826846d97eb02c7d88455aa50c47e Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 13 Jun 2019 16:33:50 +0200
Subject: [PATCH 16/22] Further C++isation of the admesh library & TriangleMesh
 (copy & move constructors / operators)

---
 src/admesh/connect.cpp               |  2 ++
 src/admesh/stl.h                     | 26 ++++++++++++++-
 src/admesh/stlinit.cpp               | 10 +-----
 src/admesh/util.cpp                  | 43 ++++++++++++++++++++-----
 src/libslic3r/TriangleMesh.cpp       | 47 +++++++++++++++-------------
 src/libslic3r/TriangleMesh.hpp       | 14 ++++-----
 src/slic3r/Config/Version.cpp        |  5 +++
 src/slic3r/Utils/FixModelByWin10.cpp |  4 +--
 8 files changed, 102 insertions(+), 49 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 1a7b7965d..5afb85d2c 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -30,6 +30,8 @@
 
 #include <boost/predef/other/endian.h>
 #include <boost/log/trivial.hpp>
+// Boost pool: Don't use mutexes to synchronize memory allocation.
+#define BOOST_POOL_NO_MT
 #include <boost/pool/object_pool.hpp>
 
 #include "stl.h"
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 40bced2f4..87210b3c9 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -89,6 +89,8 @@ struct stl_neighbors {
 };
 
 struct stl_stats {
+	stl_stats() { this->reset(); }
+	void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; }
 	char          header[81];
 	stl_type      type;
 	uint32_t      number_of_facets;
@@ -117,6 +119,18 @@ struct stl_stats {
 };
 
 struct stl_file {
+	stl_file() {}
+	stl_file(const stl_file &rhs) : facet_start(rhs.facet_start), neighbors_start(rhs.neighbors_start), stats(rhs.stats) {}
+	stl_file(stl_file &&rhs) : facet_start(std::move(rhs.facet_start)), neighbors_start(std::move(rhs.neighbors_start)), stats(rhs.stats) {}
+	stl_file& operator=(const stl_file &rhs) { this->facet_start = rhs.facet_start; this->neighbors_start = rhs.neighbors_start; this->stats = rhs.stats; return *this; }
+	stl_file& operator=(stl_file &&rhs) { this->facet_start = std::move(rhs.facet_start); this->neighbors_start = std::move(rhs.neighbors_start); this->stats = rhs.stats; return *this; }
+
+	void clear() {
+		this->facet_start.clear();
+		this->neighbors_start.clear();
+		this->stats.reset();
+	}
+
 	std::vector<stl_facet>     		facet_start;
 	std::vector<stl_neighbors> 		neighbors_start;
 	// Statistics
@@ -125,7 +139,14 @@ struct stl_file {
 
 struct indexed_triangle_set
 {
+	indexed_triangle_set() {}
+	indexed_triangle_set(const indexed_triangle_set &rhs) : indices(rhs.indices), vertices(rhs.vertices) {}
+	indexed_triangle_set(indexed_triangle_set &&rhs) : indices(std::move(rhs.indices)), vertices(std::move(rhs.vertices)) {}
+	indexed_triangle_set& operator=(const indexed_triangle_set &rhs) { this->indices = rhs.indices; this->vertices = rhs.vertices; return *this; }
+	indexed_triangle_set& operator=(indexed_triangle_set &&rhs) { this->indices = std::move(rhs.indices); this->vertices = std::move(rhs.vertices); return *this; }
+
 	void clear() { indices.clear(); vertices.clear(); }
+
 	std::vector<stl_triangle_vertex_indices> 	indices;
 	std::vector<stl_vertex>       				vertices;
 	//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
@@ -238,6 +259,10 @@ inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3
 		v = (m * v.template cast<T>()).template cast<float>().eval();
 }
 
+extern void its_rotate_x(indexed_triangle_set &its, float angle);
+extern void its_rotate_y(indexed_triangle_set &its, float angle);
+extern void its_rotate_z(indexed_triangle_set &its, float angle);
+
 extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
 extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
 extern bool its_write_off(const indexed_triangle_set &its, const char *file);
@@ -258,7 +283,6 @@ extern void stl_calculate_volume(stl_file *stl);
 
 extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
 
-extern void stl_reset(stl_file *stl);
 extern void stl_allocate(stl_file *stl);
 extern void stl_read(stl_file *stl, int first_facet, bool first);
 extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp
index 0cc6e50c7..a328baa75 100644
--- a/src/admesh/stlinit.cpp
+++ b/src/admesh/stlinit.cpp
@@ -221,7 +221,7 @@ static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
 
 bool stl_open(stl_file *stl, const char *file)
 {
-	stl_reset(stl);
+	stl->clear();
 	FILE *fp = stl_open_count_facets(stl, file);
 	if (fp == nullptr)
 		return false;
@@ -231,14 +231,6 @@ bool stl_open(stl_file *stl, const char *file)
   	return result;
 }
 
-void stl_reset(stl_file *stl)
-{
-	stl->facet_start.clear();
-	stl->neighbors_start.clear();
-  	memset(&stl->stats, 0, sizeof(stl_stats));
-  	stl->stats.volume = -1.0;
-}
-
 #ifndef BOOST_LITTLE_ENDIAN
 extern void stl_internal_reverse_quads(char *buf, size_t cnt);
 #endif /* BOOST_LITTLE_ENDIAN */
diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp
index 70f4ffc27..029e44a28 100644
--- a/src/admesh/util.cpp
+++ b/src/admesh/util.cpp
@@ -115,12 +115,12 @@ static void calculate_normals(stl_file *stl)
 	}
 }
 
-static void rotate_point_2d(float *x, float *y, const double c, const double s)
+static inline void rotate_point_2d(float &x, float &y, const double c, const double s)
 {
-	double xold = *x;
-	double yold = *y;
-	*x = float(c * xold - s * yold);
-	*y = float(s * xold + c * yold);
+	double xold = x;
+	double yold = y;
+	x = float(c * xold - s * yold);
+	y = float(s * xold + c * yold);
 }
 
 void stl_rotate_x(stl_file *stl, float angle)
@@ -130,7 +130,7 @@ void stl_rotate_x(stl_file *stl, float angle)
 	double s = sin(radian_angle);
   	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
     	for (int j = 0; j < 3; ++ j)
-      		rotate_point_2d(&stl->facet_start[i].vertex[j](1), &stl->facet_start[i].vertex[j](2), c, s);
+      		rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s);
   	stl_get_size(stl);
   	calculate_normals(stl);
 }
@@ -142,7 +142,7 @@ void stl_rotate_y(stl_file *stl, float angle)
 	double s = sin(radian_angle);
   	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
     	for (int j = 0; j < 3; ++ j)
-			rotate_point_2d(&stl->facet_start[i].vertex[j](2), &stl->facet_start[i].vertex[j](0), c, s);
+			rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s);
   	stl_get_size(stl);
   	calculate_normals(stl);
 }
@@ -154,11 +154,38 @@ void stl_rotate_z(stl_file *stl, float angle)
 	double s = sin(radian_angle);
   	for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
     	for (int j = 0; j < 3; ++ j)
-      		rotate_point_2d(&stl->facet_start[i].vertex[j](0), &stl->facet_start[i].vertex[j](1), c, s);
+      		rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s);
   	stl_get_size(stl);
   	calculate_normals(stl);
 }
 
+void its_rotate_x(indexed_triangle_set &its, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+	for (stl_vertex &v : its.vertices)
+		rotate_point_2d(v(1), v(2), c, s);
+}
+
+void its_rotate_y(indexed_triangle_set& its, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+	for (stl_vertex& v : its.vertices)
+		rotate_point_2d(v(2), v(0), c, s);
+}
+
+void its_rotate_z(indexed_triangle_set& its, float angle)
+{
+	double radian_angle = (angle / 180.0) * M_PI;
+	double c = cos(radian_angle);
+	double s = sin(radian_angle);
+	for (stl_vertex& v : its.vertices)
+		rotate_point_2d(v(0), v(1), c, s);
+}
+
 void stl_get_size(stl_file *stl)
 {
   	if (stl->stats.number_of_facets == 0)
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 11f45147c..56accfefa 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -42,10 +42,8 @@
 
 namespace Slic3r {
 
-TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets)
-    : repaired(false)
+TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets) : repaired(false)
 {
-    stl_reset(&this->stl);
     stl_file &stl = this->stl;
     stl.stats.type = inmemory;
 
@@ -72,14 +70,6 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f
     stl_get_size(&stl);
 }
 
-TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
-{
-    stl_reset(&this->stl);
-    this->stl = other.stl;
-	this->repaired = other.repaired;
-    return *this;
-}
-
 // #define SLIC3R_TRACE_REPAIR
 
 void TriangleMesh::repair(bool update_shared_vertices)
@@ -254,13 +244,18 @@ void TriangleMesh::WriteOBJFile(const char* output_file)
 void TriangleMesh::scale(float factor)
 {
     stl_scale(&(this->stl), factor);
-    this->its.clear();
+	for (stl_vertex& v : this->its.vertices)
+		v *= factor;
 }
 
 void TriangleMesh::scale(const Vec3d &versor)
 {
     stl_scale_versor(&this->stl, versor.cast<float>());
-    this->its.clear();
+	for (stl_vertex& v : this->its.vertices) {
+		v.x() *= versor.x();
+		v.y() *= versor.y();
+		v.z() *= versor.z();
+	}
 }
 
 void TriangleMesh::translate(float x, float y, float z)
@@ -268,7 +263,9 @@ void TriangleMesh::translate(float x, float y, float z)
     if (x == 0.f && y == 0.f && z == 0.f)
         return;
     stl_translate_relative(&(this->stl), x, y, z);
-    this->its.clear();
+	stl_vertex shift(x, y, z);
+	for (stl_vertex& v : this->its.vertices)
+		v += shift;
 }
 
 void TriangleMesh::translate(const Vec3f &displacement)
@@ -285,13 +282,15 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
     angle = Slic3r::Geometry::rad2deg(angle);
     
     if (axis == X) {
-        stl_rotate_x(&(this->stl), angle);
+        stl_rotate_x(&this->stl, angle);
+        its_rotate_x(this->its, angle);
     } else if (axis == Y) {
-        stl_rotate_y(&(this->stl), angle);
+        stl_rotate_y(&this->stl, angle);
+        its_rotate_y(this->its, angle);
     } else if (axis == Z) {
-        stl_rotate_z(&(this->stl), angle);
+        stl_rotate_z(&this->stl, angle);
+        its_rotate_z(this->its, angle);
     }
-    this->its.clear();
 }
 
 void TriangleMesh::rotate(float angle, const Vec3d& axis)
@@ -310,12 +309,17 @@ void TriangleMesh::mirror(const Axis &axis)
 {
     if (axis == X) {
         stl_mirror_yz(&this->stl);
+        for (stl_vertex &v : this->its.vertices)
+      		v(0) *= -1.0;
     } else if (axis == Y) {
         stl_mirror_xz(&this->stl);
+        for (stl_vertex &v : this->its.vertices)
+      		v(1) *= -1.0;
     } else if (axis == Z) {
         stl_mirror_xy(&this->stl);
+        for (stl_vertex &v : this->its.vertices)
+      		v(2) *= -1.0;
     }
-    this->its.clear();
 }
 
 void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
@@ -358,7 +362,8 @@ void TriangleMesh::rotate(double angle, Point* center)
         return;
     Vec2f c = center->cast<float>();
     this->translate(-c(0), -c(1), 0);
-    stl_rotate_z(&(this->stl), (float)angle);
+    stl_rotate_z(&this->stl, (float)angle);
+    its_rotate_z(this->its, (float)angle);
     this->translate(c(0), c(1), 0);
 }
 
@@ -540,7 +545,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
     {
     	if (this->has_shared_vertices()) {
 #if REALfloat
-	    	qhull.runQhull("", 3, (int)this->its.vertices.size() / 3, (const realT*)(this->its.vertices.front().data()), "Qt");
+	    	qhull.runQhull("", 3, (int)this->its.vertices.size(), (const realT*)(this->its.vertices.front().data()), "Qt");
 #else
 	    	src_vertices.reserve(this->its.vertices() * 3);
 	    	// We will now fill the vector with input points for computation:
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index ffd9b7e62..54c6dc5d0 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -21,15 +21,13 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
 class TriangleMesh
 {
 public:
-    TriangleMesh() : repaired(false) { stl_reset(&this->stl); }
+    TriangleMesh() : repaired(false) {}
     TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
-    TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_reset(&this->stl); *this = other; }
-    TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_reset(&this->stl); this->swap(other); }
-    ~TriangleMesh() { clear(); }
-    TriangleMesh& operator=(const TriangleMesh &other);
-    TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
-    void clear() { stl_reset(&this->stl); this->repaired = false; }
-    void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
+	TriangleMesh(const TriangleMesh& rhs) : stl(rhs.stl), its(rhs.its), repaired(rhs.repaired) {}
+	TriangleMesh(TriangleMesh&& rhs) : stl(std::move(rhs.stl)), its(std::move(rhs.its)), repaired(rhs.repaired) {}
+	TriangleMesh& operator=(const TriangleMesh& rhs) { this->stl = rhs.stl; this->its = rhs.its; this->repaired = rhs.repaired; return *this; }
+	TriangleMesh& operator=(TriangleMesh &&rhs) { this->stl = std::move(rhs.stl); this->its = std::move(rhs.its); this->repaired = rhs.repaired; return *this; }
+	void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; }
     bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
     bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); }
     bool write_binary(const char* output_file) { return stl_write_binary(&this->stl, output_file, ""); }
diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp
index 2eda135d6..fe3adfd7f 100644
--- a/src/slic3r/Config/Version.cpp
+++ b/src/slic3r/Config/Version.cpp
@@ -198,6 +198,11 @@ size_t Index::load(const boost::filesystem::path &path)
     size_t idx_line = 0;
     Version ver;
     while (std::getline(ifs, line)) {
+#ifndef _MSVCVER
+		// On a Unix system, getline does not remove the trailing carriage returns, if the index is shared over a Windows filesystem. Remove them manually.
+		while (! line.empty() && line.back() == '\r')
+			line.pop_back();
+#endif
     	++ idx_line;
     	// Skip the initial white spaces.
     	char *key = left_trim(const_cast<char*>(line.data()));
diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp
index 1daeaff26..710f19090 100644
--- a/src/slic3r/Utils/FixModelByWin10.cpp
+++ b/src/slic3r/Utils/FixModelByWin10.cpp
@@ -389,10 +389,10 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx)
 	 				throw std::runtime_error(L("Repaired 3MF file does not contain any volume"));
 				if (model.objects.front()->volumes.size() > 1)
 	 				throw std::runtime_error(L("Repaired 3MF file contains more than one volume"));
-	 			meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh));
+	 			meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
 			}
 			for (size_t i = 0; i < volumes.size(); ++ i) {
-				volumes[i]->mesh = std::move(meshes_repaired[i]);
+				volumes[i]->set_mesh(std::move(meshes_repaired[i]));
 				volumes[i]->set_new_unique_id();
 			}
 			model_object.invalidate_bounding_box();

From dbfa4e6c838eda34fd059ca2f6ce71f2130c5180 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 13 Jun 2019 16:55:12 +0200
Subject: [PATCH 17/22] Fix of a smart pointer gymnastics from previous commit

---
 src/slic3r/GUI/3DScene.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index b9ac668e0..0414a1ed3 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -393,7 +393,7 @@ public:
     double get_sla_shift_z() const { return m_sla_shift_z; }
     void set_sla_shift_z(double z) { m_sla_shift_z = z; }
 
-    void set_convex_hull(std::shared_ptr<const TriangleMesh> &convex_hull) { m_convex_hull = convex_hull; }
+    void set_convex_hull(std::shared_ptr<const TriangleMesh> convex_hull) { m_convex_hull = std::move(convex_hull); }
     void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(convex_hull); }
     void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(std::move(convex_hull)); }
 

From 9b7bb41db5b949285d28206a4ff44078bce37ecf Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 13 Jun 2019 17:24:37 +0200
Subject: [PATCH 18/22] ModelObject::add_volume(const ModelVolume &other) shall
 not re-center the volume as it will share meshes (object mesh, convex hull
 mesh) of the source, which may be in use by the background processing.

---
 src/libslic3r/Model.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 113b21503..8e879a3e6 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -691,8 +691,9 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other)
 {
     ModelVolume* v = new ModelVolume(this, other);
     this->volumes.push_back(v);
-    v->center_geometry_after_creation();
-    this->invalidate_bounding_box();
+	// The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull.
+//	v->center_geometry_after_creation();
+//    this->invalidate_bounding_box();
     return v;
 }
 

From d750d4f9255bfb388ba7b53d3a366ac16d84a7d0 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 13 Jun 2019 17:42:55 +0200
Subject: [PATCH 19/22] Re-enable high power graphics card on Windows. This is
 a regression issue against 1.41.3

---
 src/PrusaSlicer.cpp          | 3 +++
 src/PrusaSlicer_app_msvc.cpp | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index a3247b929..2becb8071 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -7,10 +7,13 @@
     #include <Windows.h>
     #include <wchar.h>
     #ifdef SLIC3R_GUI
+    extern "C" 
+    { 
         // Let the NVIDIA and AMD know we want to use their graphics card
         // on a dual graphics card system.
         __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
         __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+    }
     #endif /* SLIC3R_GUI */
 #endif /* WIN32 */
 
diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp
index 5b01751b9..ee8cdf696 100644
--- a/src/PrusaSlicer_app_msvc.cpp
+++ b/src/PrusaSlicer_app_msvc.cpp
@@ -8,10 +8,14 @@
 #include <wchar.h>
 
 #ifdef SLIC3R_GUI
+//Turn on high power graphics for NVidia cards on laptops (with built in graphics cards + Nvidia cards)
+extern "C" 
+{ 
 	// Let the NVIDIA and AMD know we want to use their graphics card
 	// on a dual graphics card system.
 	__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
 	__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+}
 #endif /* SLIC3R_GUI */
 
 #include <stdlib.h>

From 77954a13b9c34c74a46ac652ef58118b3b9c6977 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Jun 2019 11:07:07 +0200
Subject: [PATCH 20/22] Fix of admesh import due to boost::pool::destroy taking
 O(n). Why on earth?!

---
 src/admesh/connect.cpp | 16 +++++-----------
 src/admesh/normals.cpp |  8 +++++---
 2 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp
index 5afb85d2c..e729c8922 100644
--- a/src/admesh/connect.cpp
+++ b/src/admesh/connect.cpp
@@ -130,18 +130,12 @@ struct HashTableEdges {
 			this->heads[i] = this->tail;
 	}
 	~HashTableEdges() {
-	    for (int i = 0; i < this->M; ++ i) {
-	    	for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i]) {
-	        	this->heads[i] = this->heads[i]->next;
-	        	pool.destroy(temp);
 #ifndef NDEBUG
+		for (int i = 0; i < this->M; ++ i)
+	    	for (HashEdge *temp = this->heads[i]; this->heads[i] != this->tail; temp = this->heads[i])
 	        	++ this->freed;
-#endif /* NDEBUG */
-	      	}
-	    }
-		this->heads.clear();
-		pool.destroy(this->tail);
 		this->tail = nullptr;
+#endif /* NDEBUG */
 	}
 
 	void insert_edge_exact(stl_file *stl, const HashEdge &edge)
@@ -197,7 +191,7 @@ private:
 			match_neighbors(edge, *link);
 			// Delete the matched edge from the list.
 			this->heads[chain_number] = link->next;
-			pool.destroy(link);
+			// pool.destroy(link);
 #ifndef NDEBUG
 			++ this->freed;
 #endif /* NDEBUG */
@@ -224,7 +218,7 @@ private:
 					// Delete the matched edge from the list.
 					HashEdge *temp = link->next;
 					link->next = link->next->next;
-					pool.destroy(temp);
+					// pool.destroy(temp);
 #ifndef NDEBUG
 					++ this->freed;
 #endif /* NDEBUG */
diff --git a/src/admesh/normals.cpp b/src/admesh/normals.cpp
index 4d47573f6..16bb3daab 100644
--- a/src/admesh/normals.cpp
+++ b/src/admesh/normals.cpp
@@ -25,6 +25,8 @@
 #include <string.h>
 #include <math.h>
 
+// Boost pool: Don't use mutexes to synchronize memory allocation.
+#define BOOST_POOL_NO_MT
 #include <boost/pool/object_pool.hpp>
 
 #include "stl.h"
@@ -192,7 +194,7 @@ void stl_fix_normal_directions(stl_file *stl)
       		}
       		stl_normal *temp = head->next;	// Delete this facet from the list.
       		head->next = head->next->next;
-      		pool.destroy(temp);
+      		// pool.destroy(temp);
     	} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
       		++ stl->stats.number_of_parts;
       		if (checked >= stl->stats.number_of_facets)
@@ -214,8 +216,8 @@ void stl_fix_normal_directions(stl_file *stl)
     	}
   	}
 
-	pool.destroy(head);
-	pool.destroy(tail);
+	// pool.destroy(head);
+	// pool.destroy(tail);
 }
 
 void stl_fix_normal_values(stl_file *stl)

From f8c5570155e9a36a28c2147a95c1404d1c7a9f75 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Jun 2019 15:47:40 +0200
Subject: [PATCH 21/22] Removed unnecessary copy / move constructors /
 assignment operators.

---
 src/PrusaSlicer_app_msvc.cpp   | 1 -
 src/admesh/stl.h               | 8 --------
 src/libslic3r/TriangleMesh.hpp | 4 ----
 3 files changed, 13 deletions(-)

diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp
index ee8cdf696..95dd4fb07 100644
--- a/src/PrusaSlicer_app_msvc.cpp
+++ b/src/PrusaSlicer_app_msvc.cpp
@@ -8,7 +8,6 @@
 #include <wchar.h>
 
 #ifdef SLIC3R_GUI
-//Turn on high power graphics for NVidia cards on laptops (with built in graphics cards + Nvidia cards)
 extern "C" 
 { 
 	// Let the NVIDIA and AMD know we want to use their graphics card
diff --git a/src/admesh/stl.h b/src/admesh/stl.h
index 87210b3c9..2ac6c7fd2 100644
--- a/src/admesh/stl.h
+++ b/src/admesh/stl.h
@@ -120,10 +120,6 @@ struct stl_stats {
 
 struct stl_file {
 	stl_file() {}
-	stl_file(const stl_file &rhs) : facet_start(rhs.facet_start), neighbors_start(rhs.neighbors_start), stats(rhs.stats) {}
-	stl_file(stl_file &&rhs) : facet_start(std::move(rhs.facet_start)), neighbors_start(std::move(rhs.neighbors_start)), stats(rhs.stats) {}
-	stl_file& operator=(const stl_file &rhs) { this->facet_start = rhs.facet_start; this->neighbors_start = rhs.neighbors_start; this->stats = rhs.stats; return *this; }
-	stl_file& operator=(stl_file &&rhs) { this->facet_start = std::move(rhs.facet_start); this->neighbors_start = std::move(rhs.neighbors_start); this->stats = rhs.stats; return *this; }
 
 	void clear() {
 		this->facet_start.clear();
@@ -140,10 +136,6 @@ struct stl_file {
 struct indexed_triangle_set
 {
 	indexed_triangle_set() {}
-	indexed_triangle_set(const indexed_triangle_set &rhs) : indices(rhs.indices), vertices(rhs.vertices) {}
-	indexed_triangle_set(indexed_triangle_set &&rhs) : indices(std::move(rhs.indices)), vertices(std::move(rhs.vertices)) {}
-	indexed_triangle_set& operator=(const indexed_triangle_set &rhs) { this->indices = rhs.indices; this->vertices = rhs.vertices; return *this; }
-	indexed_triangle_set& operator=(indexed_triangle_set &&rhs) { this->indices = std::move(rhs.indices); this->vertices = std::move(rhs.vertices); return *this; }
 
 	void clear() { indices.clear(); vertices.clear(); }
 
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index 54c6dc5d0..054a98935 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -23,10 +23,6 @@ class TriangleMesh
 public:
     TriangleMesh() : repaired(false) {}
     TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
-	TriangleMesh(const TriangleMesh& rhs) : stl(rhs.stl), its(rhs.its), repaired(rhs.repaired) {}
-	TriangleMesh(TriangleMesh&& rhs) : stl(std::move(rhs.stl)), its(std::move(rhs.its)), repaired(rhs.repaired) {}
-	TriangleMesh& operator=(const TriangleMesh& rhs) { this->stl = rhs.stl; this->its = rhs.its; this->repaired = rhs.repaired; return *this; }
-	TriangleMesh& operator=(TriangleMesh &&rhs) { this->stl = std::move(rhs.stl); this->its = std::move(rhs.its); this->repaired = rhs.repaired; return *this; }
 	void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; }
     bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
     bool write_ascii(const char* output_file) { return stl_write_ascii(&this->stl, output_file, ""); }

From 630883ad0f4d7f602e06773a8f333e65c1385e77 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Tue, 18 Jun 2019 08:54:28 +0200
Subject: [PATCH 22/22] Extended the error message when the G-code cannot be
 copied to the SD card

---
 src/slic3r/GUI/BackgroundSlicingProcess.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 94fb6481b..b77a272e2 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -89,7 +89,7 @@ void BackgroundSlicingProcess::process_fff()
 	    	// Perform the final post-processing of the export path by applying the print statistics over the file name.
 	    	std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
 		    if (copy_file(m_temp_output_path, export_path) != 0)
-	    		throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
+	    		throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
 	    	m_print->set_status(95, _utf8(L("Running post-processing scripts")));
 	    	run_post_process_scripts(export_path, m_fff_print->config());
 	    	m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());