Пример #1
0
        public void saveDebugSTL(string filename)
        {
#if true
            OptimizedVolume vol = volumes[0];

            using (StreamWriter stream = new StreamWriter(filename))
            {
                BinaryWriter f      = new BinaryWriter(stream.BaseStream);
                Byte[]       header = new Byte[80];

                f.Write(header);

                int n = vol.facesTriangle.Count;

                f.Write(n);

                for (int i = 0; i < vol.facesTriangle.Count; i++)
                {
                    // stl expects a normal (we don't care about it's data)
                    f.Write((float)1);
                    f.Write((float)1);
                    f.Write((float)1);

                    for (int vert = 0; vert < 3; vert++)
                    {
                        f.Write((float)(vol.vertices[vol.facesTriangle[i].vertexIndex[vert]].position.x / 1000.0));
                        f.Write((float)(vol.vertices[vol.facesTriangle[i].vertexIndex[vert]].position.y / 1000.0));
                        f.Write((float)(vol.vertices[vol.facesTriangle[i].vertexIndex[vert]].position.z / 1000.0));
                    }

                    f.Write((short)0);
                }
            }
#else
            char             buffer[80] = "MatterSlice_STL_export";
Пример #2
0
        public void GenerateSupportGrid(OptimizedModel model, ConfigSettings config)
        {
            this.generated = false;
            if (config.supportEndAngle < 0)
            {
                return;
            }

            this.generated = true;

            this.gridOffset.X = model.minXYZ_um.x;
            this.gridOffset.Y = model.minXYZ_um.y;
            this.gridScale    = 200;
            this.gridWidth    = (model.size_um.x / this.gridScale) + 1;
            this.gridHeight   = (model.size_um.y / this.gridScale) + 1;
            int gridSize = this.gridWidth * this.gridHeight;

            this.xYGridOfSupportPoints = new List <List <SupportPoint> >(gridSize);
            for (int i = 0; i < gridSize; i++)
            {
                this.xYGridOfSupportPoints.Add(new List <SupportPoint>());
            }

            this.endAngleDegrees         = config.supportEndAngle;
            this.generateInternalSupport = config.generateInternalSupport;
            this.supportXYDistance_um    = config.supportXYDistance_um;
            this.supportLayerHeight_um   = config.layerThickness_um;
            this.supportZGapLayers       = config.supportNumberOfLayersToSkipInZ;
            this.supportInterfaceLayers  = config.supportInterfaceLayers;

            // This should really be a ray intersection as later code is going to count on it being an even odd list of bottoms and tops.
            // As it is we are finding the hit on the plane but not checking for good intersection with the triangle.
            for (int volumeIndex = 0; volumeIndex < model.volumes.Count; volumeIndex++)
            {
                OptimizedVolume vol = model.volumes[volumeIndex];
                for (int faceIndex = 0; faceIndex < vol.facesTriangle.Count; faceIndex++)
                {
                    OptimizedFace faceTriangle = vol.facesTriangle[faceIndex];
                    Point3        v0           = vol.vertices[faceTriangle.vertexIndex[0]].position;
                    Point3        v1           = vol.vertices[faceTriangle.vertexIndex[1]].position;
                    Point3        v2           = vol.vertices[faceTriangle.vertexIndex[2]].position;

                    // get the angle of this polygon
                    double angleFromHorizon;
                    {
                        FPoint3 v0f    = new FPoint3(v0);
                        FPoint3 v1f    = new FPoint3(v1);
                        FPoint3 v2f    = new FPoint3(v2);
                        FPoint3 normal = (v1f - v0f).Cross(v2f - v0f);
                        normal.z = Math.Abs(normal.z);

                        angleFromHorizon = (Math.PI / 2) - FPoint3.CalculateAngle(normal, FPoint3.Up);
                    }

                    v0.x = (int)((v0.x - this.gridOffset.X) / (double)this.gridScale + .5);
                    v0.y = (int)((v0.y - this.gridOffset.Y) / (double)this.gridScale + .5);
                    v1.x = (int)((v1.x - this.gridOffset.X) / (double)this.gridScale + .5);
                    v1.y = (int)((v1.y - this.gridOffset.Y) / (double)this.gridScale + .5);
                    v2.x = (int)((v2.x - this.gridOffset.X) / (double)this.gridScale + .5);
                    v2.y = (int)((v2.y - this.gridOffset.Y) / (double)this.gridScale + .5);

                    if (v0.x > v1.x)
                    {
                        swap(ref v0, ref v1);
                    }
                    if (v1.x > v2.x)
                    {
                        swap(ref v1, ref v2);
                    }
                    if (v0.x > v1.x)
                    {
                        swap(ref v0, ref v1);
                    }
                    for (long x = v0.x; x < v1.x; x++)
                    {
                        long y0 = (long)(v0.y + (v1.y - v0.y) * (x - v0.x) / (double)(v1.x - v0.x) + .5);
                        long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5);
                        long z0 = (long)(v0.z + (v1.z - v0.z) * (x - v0.x) / (double)(v1.x - v0.x) + .5);
                        long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5);

                        if (y0 > y1)
                        {
                            swap(ref y0, ref y1);
                            swap(ref z0, ref z1);
                        }

                        for (long y = y0; y < y1; y++)
                        {
                            SupportPoint newSupportPoint = new SupportPoint((int)(z0 + (z1 - z0) * (y - y0) / (double)(y1 - y0) + .5), angleFromHorizon);
                            this.xYGridOfSupportPoints[(int)(x + y * this.gridWidth)].Add(newSupportPoint);
                        }
                    }

                    for (int x = v1.x; x < v2.x; x++)
                    {
                        long y0 = (long)(v1.y + (v2.y - v1.y) * (x - v1.x) / (double)(v2.x - v1.x) + .5);
                        long y1 = (long)(v0.y + (v2.y - v0.y) * (x - v0.x) / (double)(v2.x - v0.x) + .5);
                        long z0 = (long)(v1.z + (v2.z - v1.z) * (x - v1.x) / (double)(v2.x - v1.x) + .5);
                        long z1 = (long)(v0.z + (v2.z - v0.z) * (x - v0.x) / (double)(v2.x - v0.x) + .5);

                        if (y0 > y1)
                        {
                            swap(ref y0, ref y1);
                            swap(ref z0, ref z1);
                        }

                        for (int y = (int)y0; y < y1; y++)
                        {
                            this.xYGridOfSupportPoints[x + y * this.gridWidth].Add(new SupportPoint((int)(z0 + (z1 - z0) * (double)(y - y0) / (double)(y1 - y0) + .5), angleFromHorizon));
                        }
                    }
                }
            }

            for (int x = 0; x < this.gridWidth; x++)
            {
                for (int y = 0; y < this.gridHeight; y++)
                {
                    int gridIndex = x + y * this.gridWidth;
                    List <SupportPoint> currentList = this.xYGridOfSupportPoints[gridIndex];
                    currentList.Sort(SortSupportsOnZ);

                    if (currentList.Count > 1)
                    {
                        // now remove duplicates (try to make it a better bottom and top list)
                        for (int i = currentList.Count - 1; i >= 1; i--)
                        {
                            if (currentList[i].z == currentList[i - 1].z)
                            {
                                currentList.RemoveAt(i);
                            }
                        }
                    }
                }
            }
            this.gridOffset.X += this.gridScale / 2;
            this.gridOffset.Y += this.gridScale / 2;
        }
Пример #3
0
        public Slicer(OptimizedVolume ov, int initialLayerThickness, int layerThickness, ConfigConstants.REPAIR_OUTLINES outlineRepairTypes)
        {
            modelSize = ov.model.size;
            modelMin  = ov.model.minXYZ;

            int heightWithoutFirstLayer      = modelSize.z - initialLayerThickness;
            int countOfNormalThicknessLayers = heightWithoutFirstLayer / layerThickness;

            int layerCount = countOfNormalThicknessLayers + 1; // we have to add in the first layer (that is a differnt size)

            LogOutput.log(string.Format("Layer count: {0}\n", layerCount));
            layers.Capacity = layerCount;
            for (int i = 0; i < layerCount; i++)
            {
                layers.Add(new SlicerLayer());
            }

            for (int layerIndex = 0; layerIndex < layerCount; layerIndex++)
            {
                if (layerIndex == 0)
                {
                    layers[layerIndex].z = initialLayerThickness / 2;
                }
                else
                {
                    layers[layerIndex].z = initialLayerThickness + layerThickness / 2 + layerThickness * (layerIndex - 1);
                }
            }

            for (int faceIndex = 0; faceIndex < ov.facesTriangle.Count; faceIndex++)
            {
                Point3 p0   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[0]].position;
                Point3 p1   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[1]].position;
                Point3 p2   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[2]].position;
                int    minZ = p0.z;
                int    maxZ = p0.z;
                if (p1.z < minZ)
                {
                    minZ = p1.z;
                }
                if (p2.z < minZ)
                {
                    minZ = p2.z;
                }
                if (p1.z > maxZ)
                {
                    maxZ = p1.z;
                }
                if (p2.z > maxZ)
                {
                    maxZ = p2.z;
                }

                for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++)
                {
                    int z = layers[layerIndex].z;
                    if (z < minZ || layerIndex < 0)
                    {
                        continue;
                    }

                    SlicerSegment polyCrossingAtThisZ;
                    if (p0.z < z && p1.z >= z && p2.z >= z)
                    {
                        // p1   p2
                        // --------
                        //   p0
                        polyCrossingAtThisZ = GetCrossingAtZ(p0, p2, p1, z);
                    }
                    else if (p0.z >= z && p1.z < z && p2.z < z)
                    {
                        //   p0
                        // --------
                        // p1  p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p0, p1, p2, z);
                    }
                    else if (p1.z < z && p0.z >= z && p2.z >= z)
                    {
                        // p0   p2
                        // --------
                        //   p1
                        polyCrossingAtThisZ = GetCrossingAtZ(p1, p0, p2, z);
                    }
                    else if (p1.z >= z && p0.z < z && p2.z < z)
                    {
                        //   p1
                        // --------
                        // p0  p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p1, p2, p0, z);
                    }
                    else if (p2.z < z && p1.z >= z && p0.z >= z)
                    {
                        // p1   p0
                        // --------
                        //   p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p2, p1, p0, z);
                    }
                    else if (p2.z >= z && p1.z < z && p0.z < z)
                    {
                        //   p2
                        // --------
                        // p1  p0
                        polyCrossingAtThisZ = GetCrossingAtZ(p2, p0, p1, z);
                    }
                    else
                    {
                        //Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
                        //  on the slice would create two segments
                        continue;
                    }
                    layers[layerIndex].faceTo2DSegmentIndex[faceIndex] = layers[layerIndex].segmentList.Count;
                    polyCrossingAtThisZ.faceIndex             = faceIndex;
                    polyCrossingAtThisZ.hasBeenAddedToPolygon = false;
                    layers[layerIndex].segmentList.Add(polyCrossingAtThisZ);
                }
            }

            for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++)
            {
                layers[layerIndex].MakePolygons(ov, outlineRepairTypes);
            }
        }
Пример #4
0
        public void MakePolygons(OptimizedVolume optomizedMesh, ConfigConstants.REPAIR_OUTLINES outlineRepairTypes)
        {
            for (int startingSegmentIndex = 0; startingSegmentIndex < segmentList.Count; startingSegmentIndex++)
            {
                if (segmentList[startingSegmentIndex].hasBeenAddedToPolygon)
                {
                    continue;
                }

                Polygon poly = new Polygon();
                // We start by adding the start, as we will add ends from now on.
                IntPoint polygonStartPosition = segmentList[startingSegmentIndex].start;
                poly.Add(polygonStartPosition);


                int  segmentIndexBeingAdded = startingSegmentIndex;
                bool canClose;

                bool lastAddWasAStart = true;

                while (true)
                {
                    canClose = false;
                    segmentList[segmentIndexBeingAdded].hasBeenAddedToPolygon = true;
                    IntPoint addedSegmentEndPoint = segmentList[segmentIndexBeingAdded].end;
                    if (!lastAddWasAStart)
                    {
                        // the last added point was an end so add the start as the text end point
                        addedSegmentEndPoint = segmentList[segmentIndexBeingAdded].start;
                    }

                    poly.Add(addedSegmentEndPoint);
                    int           nextSegmentToCheckIndex = -1;
                    OptimizedFace face = optomizedMesh.facesTriangle[segmentList[segmentIndexBeingAdded].faceIndex];
                    for (int connectedFaceIndex = 0; connectedFaceIndex < 3; connectedFaceIndex++)
                    {
                        int testFaceIndex = face.touchingFaces[connectedFaceIndex];
                        if (testFaceIndex > -1)
                        {
                            // If the connected face has an edge that is in the segment list
                            if (faceTo2DSegmentIndex.ContainsKey(testFaceIndex))
                            {
                                int      touchingSegmentIndex = faceTo2DSegmentIndex[testFaceIndex];
                                IntPoint foundSegmentStart    = segmentList[touchingSegmentIndex].start;
                                if (addedSegmentEndPoint == foundSegmentStart)
                                {
                                    // if we have looped back around to where we started
                                    if (addedSegmentEndPoint == polygonStartPosition)
                                    {
                                        canClose = true;
                                    }

                                    // If this segment has already been added
                                    if (segmentList[touchingSegmentIndex].hasBeenAddedToPolygon)
                                    {
                                        continue;
                                    }

                                    nextSegmentToCheckIndex = touchingSegmentIndex;
                                    lastAddWasAStart        = true;
                                }
                                else // let's check if the other side of this segment can hook up (the normal is facing the wrong way)
                                {
                                    IntPoint foundSegmentEnd = segmentList[touchingSegmentIndex].end;
                                    if (addedSegmentEndPoint == foundSegmentEnd)
                                    {
                                        // if we have looped back around to where we started
                                        if (addedSegmentEndPoint == polygonStartPosition)
                                        {
                                            canClose = true;
                                        }

                                        // If this segment has already been added
                                        if (segmentList[touchingSegmentIndex].hasBeenAddedToPolygon)
                                        {
                                            continue;
                                        }

                                        nextSegmentToCheckIndex = touchingSegmentIndex;
                                        lastAddWasAStart        = false;
                                    }
                                }
                            }
                        }
                    }

                    if (nextSegmentToCheckIndex == -1)
                    {
                        break;
                    }

                    segmentIndexBeingAdded = nextSegmentToCheckIndex;
                }

                if (canClose)
                {
                    polygonList.Add(poly);
                }
                else
                {
                    openPolygonList.Add(poly);
                }
            }

            // Link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time.
            while (true)
            {
                long bestScore = 10000 * 10000;
                int  bestA     = -1;
                int  bestB     = -1;
                bool reversed  = false;
                for (int polygonAIndex = 0; polygonAIndex < openPolygonList.Count; polygonAIndex++)
                {
                    if (openPolygonList[polygonAIndex].Count < 1)
                    {
                        continue;
                    }

                    for (int polygonBIndex = 0; polygonBIndex < openPolygonList.Count; polygonBIndex++)
                    {
                        if (openPolygonList[polygonBIndex].Count < 1)
                        {
                            continue;
                        }

                        IntPoint diff1        = openPolygonList[polygonAIndex][openPolygonList[polygonAIndex].Count - 1] - openPolygonList[polygonBIndex][0];
                        long     distSquared1 = (diff1).LengthSquared();
                        if (distSquared1 < bestScore)
                        {
                            bestScore = distSquared1;
                            bestA     = polygonAIndex;
                            bestB     = polygonBIndex;
                            reversed  = false;

                            if (bestScore == 0)
                            {
                                // found a perfect match stop looking
                                break;
                            }
                        }

                        if (polygonAIndex != polygonBIndex)
                        {
                            IntPoint diff2        = openPolygonList[polygonAIndex][openPolygonList[polygonAIndex].Count - 1] - openPolygonList[polygonBIndex][openPolygonList[polygonBIndex].Count - 1];
                            long     distSquared2 = (diff2).LengthSquared();
                            if (distSquared2 < bestScore)
                            {
                                bestScore = distSquared2;
                                bestA     = polygonAIndex;
                                bestB     = polygonBIndex;
                                reversed  = true;

                                if (bestScore == 0)
                                {
                                    // found a perfect match stop looking
                                    break;
                                }
                            }
                        }
                    }

                    if (bestScore == 0)
                    {
                        // found a perfect match stop looking
                        break;
                    }
                }

                if (bestScore >= 10000 * 10000)
                {
                    break;
                }

                if (bestA == bestB)
                {
                    polygonList.Add(new Polygon(openPolygonList[bestA]));
                    openPolygonList[bestA].Clear();
                }
                else
                {
                    if (reversed)
                    {
                        if (openPolygonList[bestA].PolygonLength() > openPolygonList[bestB].PolygonLength())
                        {
                            if (openPolygonList[bestA].PolygonLength() > openPolygonList[bestB].PolygonLength())
                            {
                                openPolygonList[bestA].AddRange(openPolygonList[bestB]);
                                openPolygonList[bestB].Clear();
                            }
                            else
                            {
                                openPolygonList[bestB].AddRange(openPolygonList[bestA]);
                                openPolygonList[bestA].Clear();
                            }
                        }
                        else
                        {
                            openPolygonList[bestB].AddRange(openPolygonList[bestA]);
                            openPolygonList[bestB].Clear();
                        }
                    }
                    else
                    {
                        openPolygonList[bestA].AddRange(openPolygonList[bestB]);
                        openPolygonList[bestB].Clear();
                    }
                }
            }


            if ((outlineRepairTypes & ConfigConstants.REPAIR_OUTLINES.EXTENSIVE_STITCHING) == ConfigConstants.REPAIR_OUTLINES.EXTENSIVE_STITCHING)
            {
                //For extensive stitching find 2 open polygons that are touching 2 closed polygons.
                // Then find the sortest path over this polygon that can be used to connect the open polygons,
                // And generate a path over this shortest bit to link up the 2 open polygons.
                // (If these 2 open polygons are the same polygon, then the final result is a closed polyon)

                while (true)
                {
                    int             bestA      = -1;
                    int             bestB      = -1;
                    GapCloserResult bestResult = new GapCloserResult();
                    bestResult.len          = long.MaxValue;
                    bestResult.polygonIndex = -1;
                    bestResult.pointIndexA  = -1;
                    bestResult.pointIndexB  = -1;

                    for (int i = 0; i < openPolygonList.Count; i++)
                    {
                        if (openPolygonList[i].Count < 1)
                        {
                            continue;
                        }

                        {
                            GapCloserResult res = FindPolygonGapCloser(openPolygonList[i][0], openPolygonList[i][openPolygonList[i].Count - 1]);
                            if (res.len > 0 && res.len < bestResult.len)
                            {
                                bestA      = i;
                                bestB      = i;
                                bestResult = res;
                            }
                        }

                        for (int j = 0; j < openPolygonList.Count; j++)
                        {
                            if (openPolygonList[j].Count < 1 || i == j)
                            {
                                continue;
                            }

                            GapCloserResult res = FindPolygonGapCloser(openPolygonList[i][0], openPolygonList[j][openPolygonList[j].Count - 1]);
                            if (res.len > 0 && res.len < bestResult.len)
                            {
                                bestA      = i;
                                bestB      = j;
                                bestResult = res;
                            }
                        }
                    }

                    if (bestResult.len < long.MaxValue)
                    {
                        if (bestA == bestB)
                        {
                            if (bestResult.pointIndexA == bestResult.pointIndexB)
                            {
                                polygonList.Add(new Polygon(openPolygonList[bestA]));
                                openPolygonList[bestA].Clear();
                            }
                            else if (bestResult.AtoB)
                            {
                                Polygon poly = new Polygon();
                                polygonList.Add(poly);
                                for (int j = bestResult.pointIndexA; j != bestResult.pointIndexB; j = (j + 1) % polygonList[bestResult.polygonIndex].Count)
                                {
                                    poly.Add(polygonList[bestResult.polygonIndex][j]);
                                }

                                poly.AddRange(openPolygonList[bestA]);
                                openPolygonList[bestA].Clear();
                            }
                            else
                            {
                                int n = polygonList.Count;
                                polygonList.Add(new Polygon(openPolygonList[bestA]));
                                for (int j = bestResult.pointIndexB; j != bestResult.pointIndexA; j = (j + 1) % polygonList[bestResult.polygonIndex].Count)
                                {
                                    polygonList[n].Add(polygonList[bestResult.polygonIndex][j]);
                                }
                                openPolygonList[bestA].Clear();
                            }
                        }
                        else
                        {
                            if (bestResult.pointIndexA == bestResult.pointIndexB)
                            {
                                openPolygonList[bestB].AddRange(openPolygonList[bestA]);
                                openPolygonList[bestA].Clear();
                            }
                            else if (bestResult.AtoB)
                            {
                                Polygon poly = new Polygon();
                                for (int n = bestResult.pointIndexA; n != bestResult.pointIndexB; n = (n + 1) % polygonList[bestResult.polygonIndex].Count)
                                {
                                    poly.Add(polygonList[bestResult.polygonIndex][n]);
                                }

                                for (int n = poly.Count - 1; (int)(n) >= 0; n--)
                                {
                                    openPolygonList[bestB].Add(poly[n]);
                                }

                                for (int n = 0; n < openPolygonList[bestA].Count; n++)
                                {
                                    openPolygonList[bestB].Add(openPolygonList[bestA][n]);
                                }

                                openPolygonList[bestA].Clear();
                            }
                            else
                            {
                                for (int n = bestResult.pointIndexB; n != bestResult.pointIndexA; n = (n + 1) % polygonList[bestResult.polygonIndex].Count)
                                {
                                    openPolygonList[bestB].Add(polygonList[bestResult.polygonIndex][n]);
                                }

                                for (int n = openPolygonList[bestA].Count - 1; n >= 0; n--)
                                {
                                    openPolygonList[bestB].Add(openPolygonList[bestA][n]);
                                }

                                openPolygonList[bestA].Clear();
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            if ((outlineRepairTypes & ConfigConstants.REPAIR_OUTLINES.KEEP_OPEN) == ConfigConstants.REPAIR_OUTLINES.KEEP_OPEN)
            {
                for (int n = 0; n < openPolygonList.Count; n++)
                {
                    if (openPolygonList[n].Count > 0)
                    {
                        polygonList.Add(new Polygon(openPolygonList[n]));
                    }
                }
            }

            //Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print.
            int snapDistance = 1000;

            for (int polygonIndex = 0; polygonIndex < polygonList.Count; polygonIndex++)
            {
                int length = 0;

                for (int intPointIndex = 1; intPointIndex < polygonList[polygonIndex].Count; intPointIndex++)
                {
                    length += (polygonList[polygonIndex][intPointIndex] - polygonList[polygonIndex][intPointIndex - 1]).vSize();
                    if (length > snapDistance)
                    {
                        break;
                    }
                }
                if (length < snapDistance)
                {
                    polygonList.RemoveAt(polygonIndex);
                    polygonIndex--;
                }
            }

            //Finally optimize all the polygons. Every point removed saves time in the long run.
            double minimumDistanceToCreateNewPosition = 1.415;

            polygonList = Clipper.CleanPolygons(polygonList, minimumDistanceToCreateNewPosition);
        }
Пример #5
0
        public Slicer(OptimizedVolume ov, ConfigSettings config)
        {
            int initialLayerThickness_um = config.firstLayerThickness_um;
            int layerThickness_um        = config.layerThickness_um;

            ConfigConstants.REPAIR_OUTLINES outlineRepairTypes = config.repairOutlines;

            modelSize = ov.parentModel.size_um;
            modelMin  = ov.parentModel.minXYZ_um;

            int heightWithoutFirstLayer      = modelSize.z - initialLayerThickness_um - config.bottomClipAmount_um;
            int countOfNormalThicknessLayers = Math.Max(0, (int)((heightWithoutFirstLayer / (double)layerThickness_um) + .5));

            int layerCount = countOfNormalThicknessLayers;

            if (initialLayerThickness_um > 0)
            {
                // we have to add in the first layer (that is a differnt size)
                layerCount++;
            }

            LogOutput.Log(string.Format("Layer count: {0}\n", layerCount));
            layers.Capacity = layerCount;
            for (int layerIndex = 0; layerIndex < layerCount; layerIndex++)
            {
                int z;
                if (layerIndex == 0)
                {
                    z = initialLayerThickness_um / 2;
                }
                else
                {
                    z = initialLayerThickness_um + layerThickness_um / 2 + layerThickness_um * (layerIndex - 1);
                }
                layers.Add(new SlicerLayer(z));
            }

            for (int faceIndex = 0; faceIndex < ov.facesTriangle.Count; faceIndex++)
            {
                Point3 p0   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[0]].position;
                Point3 p1   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[1]].position;
                Point3 p2   = ov.vertices[ov.facesTriangle[faceIndex].vertexIndex[2]].position;
                int    minZ = p0.z;
                int    maxZ = p0.z;
                if (p1.z < minZ)
                {
                    minZ = p1.z;
                }
                if (p2.z < minZ)
                {
                    minZ = p2.z;
                }
                if (p1.z > maxZ)
                {
                    maxZ = p1.z;
                }
                if (p2.z > maxZ)
                {
                    maxZ = p2.z;
                }

                for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++)
                {
                    int z = layers[layerIndex].Z;
                    if (z < minZ || z > maxZ)
                    {
                        continue;
                    }

                    SlicerSegment polyCrossingAtThisZ;
                    if (p0.z < z && p1.z >= z && p2.z >= z)
                    {
                        // p1   p2
                        // --------
                        //   p0
                        polyCrossingAtThisZ = GetCrossingAtZ(p0, p2, p1, z);
                    }
                    else if (p0.z >= z && p1.z < z && p2.z < z)
                    {
                        //   p0
                        // --------
                        // p1  p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p0, p1, p2, z);
                    }
                    else if (p1.z < z && p0.z >= z && p2.z >= z)
                    {
                        // p0   p2
                        // --------
                        //   p1
                        polyCrossingAtThisZ = GetCrossingAtZ(p1, p0, p2, z);
                    }
                    else if (p1.z >= z && p0.z < z && p2.z < z)
                    {
                        //   p1
                        // --------
                        // p0  p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p1, p2, p0, z);
                    }
                    else if (p2.z < z && p1.z >= z && p0.z >= z)
                    {
                        // p1   p0
                        // --------
                        //   p2
                        polyCrossingAtThisZ = GetCrossingAtZ(p2, p1, p0, z);
                    }
                    else if (p2.z >= z && p1.z < z && p0.z < z)
                    {
                        //   p2
                        // --------
                        // p1  p0
                        polyCrossingAtThisZ = GetCrossingAtZ(p2, p0, p1, z);
                    }
                    else
                    {
                        //Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
                        //  on the slice would create two segments
                        continue;
                    }

                    polyCrossingAtThisZ.hasBeenAddedToPolygon = false;
                    layers[layerIndex].SegmentList.Add(polyCrossingAtThisZ);
                }
            }

            for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++)
            {
                layers[layerIndex].MakePolygons(outlineRepairTypes);
            }
        }