Пример #1
0
        public static bool loadModelSTL_ascii(SimpleModel simpleModel, string filename, FMatrix3x3 matrix)
        {
            SimpleVolume vol = new SimpleVolume();
            using (StreamReader f = new StreamReader(filename))
            {
                // check for "SOLID"

                FPoint3 vertex = new FPoint3();
                int n = 0;
                Point3 v0 = new Point3(0, 0, 0);
                Point3 v1 = new Point3(0, 0, 0);
                Point3 v2 = new Point3(0, 0, 0);
                string line = f.ReadLine();
                Regex onlySingleSpaces = new Regex("\\s+", RegexOptions.Compiled);
                while (line != null)
                {
                    line = onlySingleSpaces.Replace(line, " ");
                    var parts = line.Trim().Split(' ');
                    if (parts[0].Trim() == "vertex")
                    {
                        vertex.x = Convert.ToDouble(parts[1]);
                        vertex.y = Convert.ToDouble(parts[2]);
                        vertex.z = Convert.ToDouble(parts[3]);

                        // change the scale from mm to micrometers
                        vertex *= 1000.0;

                        n++;
                        switch (n)
                        {
                            case 1:
                                v0 = matrix.apply(vertex);
                                break;

                            case 2:
                                v1 = matrix.apply(vertex);
                                break;

                            case 3:
                                v2 = matrix.apply(vertex);
                                vol.addFaceTriangle(v0, v1, v2);
                                n = 0;
                                break;
                        }
                    }
                    line = f.ReadLine();
                }
            }

            if (vol.faceTriangles.Count > 3)
            {
                simpleModel.volumes.Add(vol);
                return true;
            }

            return false;
        }
Пример #2
0
        public static List<Segment> ConvertPathToSegments(IList<IntPoint> path, long zHeight, bool isPerimeter = true)
        {
            List<Segment> polySegments = new List<Segment>(path.Count);
            int endIndex = isPerimeter ? path.Count : path.Count - 1;
            for (int i = 0; i < endIndex; i++)
            {
                Point3 point = new Point3(path[i].X, path[i].Y, zHeight);
                int nextIndex = (i + 1) % path.Count;
                Point3 nextPoint = new Point3(path[nextIndex].X, path[nextIndex].Y, zHeight);

                polySegments.Add(new Segment()
                {
                    Start = point,
                    End = nextPoint,
                });
            }

            return polySegments;
        }
Пример #3
0
 public FPoint3(Point3 v0)
 {
     this.x = v0.x;
     this.y = v0.y;
     this.z = v0.z;
 }
Пример #4
0
        public void ForceMinimumLayerTime(double minTime, int minimumPrintingSpeed)
        {
            Point3 lastPosition = gcodeExport.GetPosition();
            double travelTime   = 0.0;
            double extrudeTime  = 0.0;

            for (int n = 0; n < paths.Count; n++)
            {
                GCodePath path = paths[n];
                for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++)
                {
                    Point3 currentPosition = path.points[pointIndex];
                    double thisTime        = (lastPosition - currentPosition).LengthMm() / (double)(path.config.speed);
                    if (path.config.lineWidth_um != 0)
                    {
                        extrudeTime += thisTime;
                    }
                    else
                    {
                        travelTime += thisTime;
                    }

                    lastPosition = currentPosition;
                }
            }

            double totalTime = extrudeTime + travelTime;

            if (totalTime < minTime && extrudeTime > 0.0)
            {
                double minExtrudeTime = minTime - travelTime;
                if (minExtrudeTime < 1)
                {
                    minExtrudeTime = 1;
                }

                double factor = extrudeTime / minExtrudeTime;
                for (int n = 0; n < paths.Count; n++)
                {
                    GCodePath path = paths[n];
                    if (path.config.lineWidth_um == 0)
                    {
                        continue;
                    }

                    int speed = (int)(path.config.speed * factor);
                    if (speed < minimumPrintingSpeed)
                    {
                        factor = (double)(minimumPrintingSpeed) / (double)(path.config.speed);
                    }
                }

                //Only slow down with the minimum time if that will be slower then a factor already set. First layer slowdown also sets the speed factor.
                if (factor * 100 < getExtrudeSpeedFactor())
                {
                    SetExtrudeSpeedFactor((int)(factor * 100));
                }
                else
                {
                    factor = getExtrudeSpeedFactor() / 100.0;
                }

                if (minTime - (extrudeTime / factor) - travelTime > 0.1)
                {
                    //TODO: Use up this extra time (circle around the print?)
                    this.extraTime = minTime - (extrudeTime / factor) - travelTime;
                }
                this.totalPrintTime = (extrudeTime / factor) + travelTime;
            }
            else
            {
                this.totalPrintTime = totalTime;
            }
        }
Пример #5
0
 public FPoint3(Point3 v0)
 {
     this.x = v0.x;
     this.y = v0.y;
     this.z = v0.z;
 }
Пример #6
0
		public Point3 Cross(Point3 p)
		{
			return new Point3(
				y * p.z - z * p.y,
				z * p.x - x * p.z,
				x * p.y - y * p.x);
		}
Пример #7
0
 public SimpleFace(Point3 v0, Point3 v1, Point3 v2)
 {
     vertices[0] = v0; vertices[1] = v1; vertices[2] = v2;
 }
Пример #8
0
        private static bool loadModelSTL_binary(SimpleModel simpleModel, string filename, FMatrix3x3 matrix)
        {
            SimpleVolume vol = new SimpleVolume();
            using (FileStream stlStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                // load it as a binary stl
                // skip the first 80 bytes
                // read in the number of triangles
                stlStream.Position = 0;
                BinaryReader br = new BinaryReader(stlStream);
                byte[] fileContents = br.ReadBytes((int)stlStream.Length);
                int currentPosition = 80;
                uint numTriangles = System.BitConverter.ToUInt32(fileContents, currentPosition);
                long bytesForNormals = numTriangles * 3 * 4;
                long bytesForVertices = numTriangles * 3 * 4;
                long bytesForAttributs = numTriangles * 2;
                currentPosition += 4;
                long numBytesRequiredForVertexData = currentPosition + bytesForNormals + bytesForVertices + bytesForAttributs;
                if (fileContents.Length < numBytesRequiredForVertexData || numTriangles < 4)
                {
                    stlStream.Close();
                    return false;
                }

                Point3[] vector = new Point3[3];
                for (int i = 0; i < numTriangles; i++)
                {
                    // skip the normal
                    currentPosition += 3 * 4;
                    for (int j = 0; j < 3; j++)
                    {
                        vector[j] = new Point3(
                            System.BitConverter.ToSingle(fileContents, currentPosition + 0 * 4) * 1000,
                            System.BitConverter.ToSingle(fileContents, currentPosition + 1 * 4) * 1000,
                            System.BitConverter.ToSingle(fileContents, currentPosition + 2 * 4) * 1000);
                        currentPosition += 3 * 4;
                    }
                    currentPosition += 2; // skip the attribute

                    vol.addFaceTriangle(vector[2], vector[1], vector[0]);
                }
            }

            if (vol.faceTriangles.Count > 3)
            {
                simpleModel.volumes.Add(vol);
                return true;
            }

            return false;
        }
Пример #9
0
        public Slicer(OptimizedMesh ov, ConfigSettings config)
        {
            int initialLayerThickness_um = config.FirstLayerThickness_um;
            int layerThickness_um        = config.LayerThickness_um;

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

            long 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 different size)
                layerCount++;
            }
            if (config.outputOnlyFirstLayer)
            {
                layerCount = 1;
            }

            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 MeshProcessingLayer(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;
                long   minZ = p0.z;
                long   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;
                    }

                    SlicePerimeterSegment 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();
            }
        }
Пример #10
0
        public SlicePerimeterSegment GetCrossingAtZ(Point3 singlePointOnSide, Point3 otherSide1, Point3 otherSide2, int z)
        {
            SlicePerimeterSegment seg = new SlicePerimeterSegment();

            seg.start.X = (long)(singlePointOnSide.x + (double)(otherSide1.x - singlePointOnSide.x) * (double)(z - singlePointOnSide.z) / (double)(otherSide1.z - singlePointOnSide.z) + .5);
            seg.start.Y = (long)(singlePointOnSide.y + (double)(otherSide1.y - singlePointOnSide.y) * (double)(z - singlePointOnSide.z) / (double)(otherSide1.z - singlePointOnSide.z) + .5);
            seg.end.X   = (long)(singlePointOnSide.x + (double)(otherSide2.x - singlePointOnSide.x) * (double)(z - singlePointOnSide.z) / (double)(otherSide2.z - singlePointOnSide.z) + .5);
            seg.end.Y   = (long)(singlePointOnSide.y + (double)(otherSide2.y - singlePointOnSide.y) * (double)(z - singlePointOnSide.z) / (double)(otherSide2.z - singlePointOnSide.z) + .5);
            return(seg);
        }
Пример #11
0
		public long Dot(Point3 p)
		{
			return this.x * p.x + this.y * p.y + this.z * p.z;
		}
Пример #12
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;
        }
Пример #13
0
 private static void swap(ref Point3 p0, ref Point3 p1)
 {
     Point3 tmp = p0;
     p0 = p1;
     p1 = tmp;
 }
Пример #14
0
		public OptimizedPoint3(Point3 position)
		{
			this.position = position;
		}
Пример #15
0
		public void SetPositionAndSize(SimpleMeshCollection simpleMeshCollection, long xCenter_um, long yCenter_um, long zClip_um, bool centerObjectInXy)
		{
			minXYZ_um = simpleMeshCollection.minXYZ_um();
			maxXYZ_um = simpleMeshCollection.maxXYZ_um();

			if (centerObjectInXy)
			{
				Point3 modelXYCenterZBottom_um = new Point3((minXYZ_um.x + maxXYZ_um.x) / 2, (minXYZ_um.y + maxXYZ_um.y) / 2, minXYZ_um.z);
				modelXYCenterZBottom_um -= new Point3(xCenter_um, yCenter_um, zClip_um);
				for (int optimizedMeshIndex = 0; optimizedMeshIndex < OptimizedMeshes.Count; optimizedMeshIndex++)
				{
					for (int n = 0; n < OptimizedMeshes[optimizedMeshIndex].vertices.Count; n++)
					{
						OptimizedMeshes[optimizedMeshIndex].vertices[n].position -= modelXYCenterZBottom_um;
					}
				}

				minXYZ_um -= modelXYCenterZBottom_um;
				maxXYZ_um -= modelXYCenterZBottom_um;
			}
			else // we still need to put in the bottom clip
			{
				// Ofset by bed center and correctly position in z
				Point3 modelZBottom_um = new Point3(0, 0, minXYZ_um.z - zClip_um);
				for (int optimizedMeshIndex = 0; optimizedMeshIndex < OptimizedMeshes.Count; optimizedMeshIndex++)
				{
					for (int vertexIndex = 0; vertexIndex < OptimizedMeshes[optimizedMeshIndex].vertices.Count; vertexIndex++)
					{
						OptimizedMeshes[optimizedMeshIndex].vertices[vertexIndex].position -= modelZBottom_um;
					}
				}

				minXYZ_um -= modelZBottom_um;
				maxXYZ_um -= modelZBottom_um;
			}

			size_um = maxXYZ_um - minXYZ_um;
		}
Пример #16
0
 public SlicerSegment GetCrossingAtZ(Point3 singlePointOnSide, Point3 otherSide1, Point3 otherSide2, int z)
 {
     SlicerSegment seg = new SlicerSegment();
     seg.start.X = (long)(singlePointOnSide.x + (double)(otherSide1.x - singlePointOnSide.x) * (double)(z - singlePointOnSide.z) / (double)(otherSide1.z - singlePointOnSide.z) + .5);
     seg.start.Y = (long)(singlePointOnSide.y + (double)(otherSide1.y - singlePointOnSide.y) * (double)(z - singlePointOnSide.z) / (double)(otherSide1.z - singlePointOnSide.z) + .5);
     seg.end.X = (long)(singlePointOnSide.x + (double)(otherSide2.x - singlePointOnSide.x) * (double)(z - singlePointOnSide.z) / (double)(otherSide2.z - singlePointOnSide.z) + .5);
     seg.end.Y = (long)(singlePointOnSide.y + (double)(otherSide2.y - singlePointOnSide.y) * (double)(z - singlePointOnSide.z) / (double)(otherSide2.z - singlePointOnSide.z) + .5);
     return seg;
 }
Пример #17
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 = (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);
            }
        }
Пример #18
0
		public Vector3(Point3 v0)
		{
			this.x = v0.x;
			this.y = v0.y;
			this.z = v0.z;
		}
Пример #19
0
 public void addFaceTriangle(Point3 v0, Point3 v1, Point3 v2)
 {
     faceTriangles.Add(new SimpleFace(v0, v1, v2));
 }
Пример #20
0
        public void WriteMove(Point3 movePosition_um, double speed, long lineWidth_um)
        {
            StringBuilder lineToWrite = new StringBuilder();

            //Normal E handling.
            if (lineWidth_um != 0)
            {
                Point3 diff = movePosition_um - GetPosition();
                if (isRetracted)
                {
                    if (retractionZHop_mm > 0)
                    {
                        double zWritePosition = (double)(currentPosition_um.z - extruderOffset_um[extruderIndex].z) / 1000;
                        lineToWrite.Append("G1 Z{0:0.###}\n".FormatWith(zWritePosition));
                    }

                    if (extrusionAmount_mm > 10000.0)
                    {
                        //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure.
                        ResetExtrusionValue(retractionAmount_mm);
                    }

                    lineToWrite.Append("G1 F{0} E{1:0.#####}\n".FormatWith(retractionSpeed * 60, extrusionAmount_mm));

                    currentSpeed = retractionSpeed;
                    estimateCalculator.plan(new TimeEstimateCalculator.Position(
                                                currentPosition_um.x / 1000.0,
                                                currentPosition_um.y / 1000.0,
                                                currentPosition_um.z / 1000.0,
                                                extrusionAmount_mm),
                                            currentSpeed);

                    isRetracted = false;
                }

                extrusionAmount_mm += extrusionPerMm * lineWidth_um / 1000.0 * diff.LengthMm();
                lineToWrite.Append("G1");
            }
            else
            {
                lineToWrite.Append("G0");
            }

            if (currentSpeed != speed)
            {
                lineToWrite.Append(" F{0}".FormatWith(speed * 60));
                currentSpeed = speed;
            }

            double xWritePosition = (double)(movePosition_um.x - extruderOffset_um[extruderIndex].x) / 1000.0;
            double yWritePosition = (double)(movePosition_um.y - extruderOffset_um[extruderIndex].y) / 1000.0;

            lineToWrite.Append(" X{0:0.###} Y{1:0.###}".FormatWith(xWritePosition, yWritePosition));

            if (movePosition_um.z != currentPosition_um.z)
            {
                double zWritePosition = (double)(movePosition_um.z - extruderOffset_um[extruderIndex].z) / 1000.0;
                if (lineWidth_um == 0 &&
                    isRetracted)
                {
                    zWritePosition += retractionZHop_mm;
                }
                lineToWrite.Append(" Z{0:0.###}".FormatWith(zWritePosition));
            }

            if (lineWidth_um != 0)
            {
                lineToWrite.Append(" E{0:0.#####}".FormatWith(extrusionAmount_mm));
            }

            lineToWrite.Append("\n");

            if (lineToWrite.Length > 0)
            {
                string lineAsString = lineToWrite.ToString();
                gcodeFileStream.Write(lineAsString);
            }

            //If wipe enabled remember path, but stop at 100 moves to keep memory usage low
            if (wipeAfterRetraction)
            {
                retractionWipePath.Add(movePosition_um);
                if (retractionWipePath.Count > 100)
                {
                    retractionWipePath.RemoveAt(0);
                }
            }

            currentPosition_um = movePosition_um;
            estimateCalculator.plan(new TimeEstimateCalculator.Position(currentPosition_um.x / 1000.0, currentPosition_um.y / 1000.0, currentPosition_um.z / 1000.0, extrusionAmount_mm), speed);
        }
Пример #21
0
        public List <List <Point3> > GetPathsWithOverlapsRemoved(List <Point3> perimeter, int overlapMergeAmount_um)
        {
            // make a copy that has every point duplicated (so that we have them as segments).
            List <Point3> polySegments = new List <Point3>(perimeter.Count * 2);

            for (int i = 0; i < perimeter.Count - 1; i++)
            {
                Point3 point     = perimeter[i];
                Point3 nextPoint = perimeter[i + 1];

                polySegments.Add(point);
                polySegments.Add(nextPoint);
            }

            Altered[] markedAltered = new Altered[polySegments.Count / 2];

            int segmentCount = polySegments.Count / 2;

            // now walk every segment and check if there is another segment that is similar enough to merge them together
            for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
            {
                int firstPointIndex = firstSegmentIndex * 2;
                for (int checkSegmentIndex = firstSegmentIndex + 1; checkSegmentIndex < segmentCount; checkSegmentIndex++)
                {
                    int checkPointIndex = checkSegmentIndex * 2;
                    // The first point of start and the last point of check (the path will be coming back on itself).
                    long startDelta = (polySegments[firstPointIndex] - polySegments[checkPointIndex + 1]).Length();
                    // if the segments are similar enough
                    if (startDelta < overlapMergeAmount_um)
                    {
                        // The last point of start and the first point of check (the path will be coming back on itself).
                        long endDelta = (polySegments[firstPointIndex + 1] - polySegments[checkPointIndex]).Length();
                        if (endDelta < overlapMergeAmount_um)
                        {
                            // move the first segments points to the average of the merge positions
                            polySegments[firstPointIndex]     = (polySegments[firstPointIndex] + polySegments[checkPointIndex + 1]) / 2;                         // the start
                            polySegments[firstPointIndex + 1] = (polySegments[firstPointIndex + 1] + polySegments[checkPointIndex]) / 2;                         // the end

                            markedAltered[firstSegmentIndex] = Altered.merged;
                            // mark this segment for removal
                            markedAltered[checkSegmentIndex] = Altered.remove;
                            // We only expect to find one match for each segment, so move on to the next segment
                            break;
                        }
                    }
                }
            }

            // Check for perimeter edges that need to be removed that are the u turns of sections that go back on themselves.
            //  __________
            // |__________|	->  |--------|  the 2 vertical sections should be removed
            for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
            {
                int prevSegmentIndex = (int)((uint)(segmentIndex - 1) % (uint)segmentCount);
                int nextSegmentIndex = (segmentIndex + 1) % segmentCount;
                if ((markedAltered[nextSegmentIndex] == Altered.merged && markedAltered[prevSegmentIndex] == Altered.remove) ||
                    (markedAltered[nextSegmentIndex] == Altered.remove && markedAltered[prevSegmentIndex] == Altered.merged))
                {
                    markedAltered[segmentIndex] = Altered.remove;
                }
            }

            // remove the marked segments
            for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
            {
                int pointIndex = segmentIndex * 2;
                if (markedAltered[segmentIndex] == Altered.remove)
                {
                    polySegments.RemoveRange(pointIndex, 2);
                }
            }

            // go through the polySegments and create a new polygon for every connected set of segments
            List <List <Point3> > separatedPolygons = new List <List <Point3> >();
            List <Point3>         currentPolygon    = new List <Point3>();

            separatedPolygons.Add(currentPolygon);
            // put in the first point
            for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex += 2)
            {
                // add the start point
                currentPolygon.Add(polySegments[segmentIndex]);

                // if the next segment is not connected to this one
                if (segmentIndex < polySegments.Count - 2 &&
                    polySegments[segmentIndex + 1] != polySegments[segmentIndex + 2])
                {
                    // add the end point
                    currentPolygon.Add(polySegments[segmentIndex + 1]);

                    // create a new polygon
                    currentPolygon = new List <Point3>();
                    separatedPolygons.Add(currentPolygon);
                }
            }

            // add the end point
            currentPolygon.Add(polySegments[polySegments.Count - 1]);

            return(separatedPolygons);
        }
Пример #22
0
        public void WriteQueuedGCode(int layerThickness)
        {
            GCodePathConfig lastConfig    = null;
            int             extruderIndex = gcodeExport.GetExtruderIndex();

            for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++)
            {
                GCodePath path = paths[pathIndex];
                if (extruderIndex != path.extruderIndex)
                {
                    extruderIndex = path.extruderIndex;
                    gcodeExport.SwitchExtruder(extruderIndex);
                }
                else if (path.Retract)
                {
                    gcodeExport.WriteRetraction();
                }
                if (path.config != travelConfig && lastConfig != path.config)
                {
                    gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment));
                    lastConfig = path.config;
                }

                double speed = path.config.speed;
                if (path.config.lineWidth_um != 0)
                {
                    // Only apply the extrudeSpeedFactor to extrusion moves
                    speed = speed * extrudeSpeedFactor / 100;
                }
                else
                {
                    speed = speed * travelSpeedFactor / 100;
                }

                if (path.points.Count == 1 &&
                    path.config != travelConfig &&
                    (gcodeExport.GetPositionXY() - path.points[0].XYPoint).ShorterThen(path.config.lineWidth_um * 2))
                {
                    //Check for lots of small moves and combine them into one large line
                    Point3 nextPosition = path.points[0];
                    int    i            = pathIndex + 1;
                    while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth_um * 2))
                    {
                        nextPosition = paths[i].points[0];
                        i++;
                    }
                    if (paths[i - 1].config == travelConfig)
                    {
                        i--;
                    }

                    if (i > pathIndex + 2)
                    {
                        nextPosition = gcodeExport.GetPosition();
                        for (int x = pathIndex; x < i - 1; x += 2)
                        {
                            long   oldLen   = (nextPosition - paths[x].points[0]).Length();
                            Point3 newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2;
                            long   newLen   = (gcodeExport.GetPosition() - newPoint).Length();
                            if (newLen > 0)
                            {
                                gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen));
                            }

                            nextPosition = paths[x + 1].points[0];
                        }

                        gcodeExport.WriteMove(paths[i - 1].points[0], speed, path.config.lineWidth_um);
                        pathIndex = i - 1;
                        continue;
                    }
                }


                bool spiralize = path.config.spiralize;
                if (spiralize)
                {
                    //Check if we are the last spiralize path in the list, if not, do not spiralize.
                    for (int m = pathIndex + 1; m < paths.Count; m++)
                    {
                        if (paths[m].config.spiralize)
                        {
                            spiralize = false;
                        }
                    }
                }

                if (spiralize)                 // if we are still in spiralize mode
                {
                    //If we need to spiralize then raise the head slowly by 1 layer as this path progresses.
                    double   totalLength     = 0;
                    long     z               = gcodeExport.GetPositionZ();
                    IntPoint currentPosition = gcodeExport.GetPositionXY();
                    for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++)
                    {
                        IntPoint nextPosition = path.points[pointIndex].XYPoint;
                        totalLength    += (currentPosition - nextPosition).LengthMm();
                        currentPosition = nextPosition;
                    }

                    double length = 0.0;
                    currentPosition = gcodeExport.GetPositionXY();
                    for (int i = 0; i < path.points.Count; i++)
                    {
                        IntPoint nextPosition = path.points[i].XYPoint;
                        length         += (currentPosition - nextPosition).LengthMm();
                        currentPosition = nextPosition;
                        Point3 nextExtrusion = path.points[i];
                        nextExtrusion.z = (int)(z + layerThickness * length / totalLength + .5);
                        gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um);
                    }
                }
                else
                {
                    // This is test code to remove double drawn small perimeter lines.
                    if (RemoveDoubleDrawPerimeterLines(path, speed))
                    {
                        return;
                    }
                    else
                    {
                        //TrimPerimeterIfNeeded(path);

                        for (int i = 0; i < path.points.Count; i++)
                        {
                            gcodeExport.WriteMove(path.points[i], speed, path.config.lineWidth_um);
                        }
                    }
                }
            }

            gcodeExport.UpdateTotalPrintTime();
        }
Пример #23
0
        public void WriteMove(Point3 movePosition_um, double speed, int lineWidth_um)
        {
            StringBuilder lineToWrite = new StringBuilder();
            //Normal E handling.
            if (lineWidth_um != 0)
            {
                Point3 diff = movePosition_um - GetPosition();
                if (isRetracted)
                {
                    if (retractionZHop_mm > 0)
                    {
                        double zWritePosition = (double)(currentPosition_um.z - extruderOffset_um[extruderIndex].z) / 1000;
                        lineToWrite.Append("G1 Z{0:0.###}\n".FormatWith(zWritePosition));
                    }

                    if (extrusionAmount_mm > 10000.0)
                    {
                        //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure.
                        ResetExtrusionValue(retractionAmount_mm);
                    }

                    if (outputType == ConfigConstants.OUTPUT_TYPE.ULTIGCODE)
                    {
                        lineToWrite.Append("G11\n");
                    }
                    else
                    {
                        lineToWrite.Append("G1 F{0} {1}{2:0.#####}\n".FormatWith(retractionSpeed * 60, extruderCharacter[extruderIndex], extrusionAmount_mm));

                        currentSpeed = retractionSpeed;
                        estimateCalculator.plan(new TimeEstimateCalculator.Position(
                            currentPosition_um.x / 1000.0,
                            currentPosition_um.y / 1000.0,
                            currentPosition_um.z / 1000.0,
                            extrusionAmount_mm),
                            currentSpeed);
                    }

                    isRetracted = false;
                }

                extrusionAmount_mm += extrusionPerMm * lineWidth_um / 1000.0 * diff.LengthMm();
                lineToWrite.Append("G1");
            }
            else
            {
                lineToWrite.Append("G0");
            }

            if (currentSpeed != speed)
            {
                lineToWrite.Append(" F{0}".FormatWith(speed * 60));
                currentSpeed = speed;
            }

            double xWritePosition = (double)(movePosition_um.x - extruderOffset_um[extruderIndex].x) / 1000.0;
            double yWritePosition = (double)(movePosition_um.y - extruderOffset_um[extruderIndex].y) / 1000.0;
            lineToWrite.Append(" X{0:0.###} Y{1:0.###}".FormatWith(xWritePosition, yWritePosition));

            if (movePosition_um.z != currentPosition_um.z)
            {
                double zWritePosition = (double)(movePosition_um.z - extruderOffset_um[extruderIndex].z) / 1000.0;
                lineToWrite.Append(" Z{0:0.###}".FormatWith(zWritePosition));
            }

            if (lineWidth_um != 0)
            {
                lineToWrite.Append(" {0}{1:0.#####}".FormatWith(extruderCharacter[extruderIndex], extrusionAmount_mm));
            }

            lineToWrite.Append("\n");

            if (lineToWrite.Length > 0)
            {
                string lineAsString = lineToWrite.ToString();
                gcodeFileStream.Write(lineAsString);
            }

            //If wipe enabled remember path, but stop at 100 moves to keep memory usage low
            if (wipeAfterRetraction)
            {
                retractionWipePath.Add(movePosition_um);
                if (retractionWipePath.Count > 100)
                {
                    retractionWipePath.RemoveAt(0);
                }
            }

            currentPosition_um = movePosition_um;
            estimateCalculator.plan(new TimeEstimateCalculator.Position(currentPosition_um.x / 1000.0, currentPosition_um.y / 1000.0, currentPosition_um.z / 1000.0, extrusionAmount_mm), speed);
        }
Пример #24
0
        public void writeMove(IntPoint movePosition_um, int speed, int lineWidth_um)
        {
            if (outputType == ConfigConstants.OUTPUT_TYPE.BFB)
            {
                //For Bits From Bytes machines, we need to handle this completely differently. As they do not use E values, they use RPM values
                double fspeed = speed * 60;
                double rpm    = (extrusionPerMm * (double)(lineWidth_um) / 1000.0) * speed * 60;

                //All BFB machines have 4mm per RPM extrusion.
                const double mm_per_rpm = 4.0;
                rpm /= mm_per_rpm;
                if (rpm > 0)
                {
                    if (isRetracted)
                    {
                        if (currentSpeed != (int)(rpm * 10))
                        {
                            //f.Write("; %f e-per-mm %d mm-width %d mm/s\n", extrusionPerMM, lineWidth, speed);
                            f.Write("M108 S{0:0.0}\n".FormatWith(rpm * 10));
                            currentSpeed = (int)(rpm * 10);
                        }
                        f.Write("M101\n");
                        isRetracted = false;
                    }
                    // Fix the speed by the actual RPM we are asking, because of rounding errors we cannot get all RPM values, but we have a lot more resolution in the feedrate value.
                    // (Trick copied from KISSlicer, thanks Jonathan)
                    fspeed *= (rpm / (Round(rpm * 100) / 100));

                    //Increase the extrusion amount to calculate the amount of filament used.
                    IntPoint diff = movePosition_um - getPositionXY();
                    extrusionAmount_mm += extrusionPerMm * lineWidth_um / 1000.0 * diff.LengthMm();
                }
                else
                {
                    //If we are not extruding, check if we still need to disable the extruder. This causes a retraction due to auto-retraction.
                    if (!isRetracted)
                    {
                        f.Write("M103\n");
                        isRetracted = true;
                    }
                }
                f.Write("G1 X{0:0.00} Y{1:0.00} Z{2:0.00} F{3:0.0}\n".FormatWith((double)(movePosition_um.X - extruderOffset_um[extruderIndex].X) / 1000, (double)(movePosition_um.Y - extruderOffset_um[extruderIndex].Y) / 1000, (double)(zPos_um) / 1000, fspeed));
            }
            else
            {
                //Normal E handling.
                if (lineWidth_um != 0)
                {
                    IntPoint diff = movePosition_um - getPositionXY();
                    if (isRetracted)
                    {
                        if (retractionZHop_mm > 0)
                        {
                            f.Write("G1 Z{0:0.00}\n".FormatWith(currentPosition_um.z / 1000.0));
                        }

                        if (outputType == ConfigConstants.OUTPUT_TYPE.ULTIGCODE)
                        {
                            f.Write("G11\n");
                        }
                        else
                        {
                            f.Write("G1 F{0} {1}{2:0.00000}\n".FormatWith(retractionSpeed * 60, extruderCharacter[extruderIndex], extrusionAmount_mm));

                            currentSpeed = retractionSpeed;
                            estimateCalculator.plan(new TimeEstimateCalculator.Position(
                                                        currentPosition_um.x / 1000.0,
                                                        currentPosition_um.y / 1000.0,
                                                        currentPosition_um.z / 1000.0,
                                                        extrusionAmount_mm),
                                                    currentSpeed);
                        }

                        if (extrusionAmount_mm > 10000.0)
                        {
                            //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure.
                            resetExtrusionValue();
                        }
                        isRetracted = false;
                    }
                    extrusionAmount_mm += extrusionPerMm * lineWidth_um / 1000.0 * diff.LengthMm();
                    f.Write("G1");
                }
                else
                {
                    f.Write("G0");
                }

                if (currentSpeed != speed)
                {
                    f.Write(" F{0}".FormatWith(speed * 60));
                    currentSpeed = speed;
                }
                f.Write(" X{0:0.00} Y{1:0.00}".FormatWith((movePosition_um.X - extruderOffset_um[extruderIndex].X) / 1000.0, (movePosition_um.Y - extruderOffset_um[extruderIndex].Y) / 1000.0));
                if (zPos_um != currentPosition_um.z)
                {
                    f.Write(" Z{0:0.00}".FormatWith((zPos_um) / 1000.0));
                }
                if (lineWidth_um != 0)
                {
                    f.Write(" {0}{1:0.00000}".FormatWith(extruderCharacter[extruderIndex], extrusionAmount_mm));
                }
                f.Write("\n");
            }

            currentPosition_um = new Point3(movePosition_um.X, movePosition_um.Y, zPos_um);
            estimateCalculator.plan(new TimeEstimateCalculator.Position(currentPosition_um.x / 1000.0, currentPosition_um.y / 1000.0, currentPosition_um.z / 1000.0, extrusionAmount_mm), speed);
        }