/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Converts the contents of the isoPlotSegment to an appropriate GCodeCmd object /// </summary> /// <returns>list of GCodeCmd objects or null for fail</returns> public override List <GCodeCmd> GetGCodeCmds(GCodeFileStateMachine stateMachine) { int adjustedNumTabs; GCodeCmd_Line lineObj = null; GCodeCmd_Line lineObjSegment = null; List <GCodeCmd> retList = new List <GCodeCmd>(); float fX0; float fY0; float fX1; float fY1; List <PointF> ptListMidCenters = new List <PointF>(); // build the line now if (ReverseOnConversionToGCode == true) { // NOTE we use the chainedStart_X as point x1,y1 here. lineObj = new GCodeCmd_Line(x0, y0, ChainedStart_X, ChainedStart_Y, this.PointsAddedCount, this.DebugID); fX0 = (float)x0; fY0 = (float)y0; fX1 = (float)ChainedStart_X; fY1 = (float)ChainedStart_Y; lineObj.ReverseOnConversionToGCode = true; } else { // NOTE we use the chainedStart_X as point x0,y0 here. lineObj = new GCodeCmd_Line(ChainedStart_X, ChainedStart_Y, x1, y1, this.PointsAddedCount, this.DebugID); fX0 = (float)ChainedStart_X; fY0 = (float)ChainedStart_Y; fX1 = (float)x1; fY1 = (float)y1; lineObj.ReverseOnConversionToGCode = false; } lineObj.DoNotEmitToGCode = DoNotEmitToGCode; //DebugMessage("IsoSegmentLength=" + IsoSegmentLength(stateMachine).ToString()); // figure out our adjusted number of tabs adjustedNumTabs = 0; if (NumberOfTabs <= 0) { adjustedNumTabs = 0; } else { adjustedNumTabs = CalcAdjustedNumberOfTabs(stateMachine); } //DebugMessage("NumberOfTabs=" + NumberOfTabs.ToString()); //DebugMessage("adjustedNumTabs=" + adjustedNumTabs.ToString()); //DebugMessage("TabLength=" + TabLength.ToString()); // do we need to break the line to add tabs? if ((NumberOfTabs <= 0) || (adjustedNumTabs <= 0) || (TabLength <= 0)) { // no we do not, add it and return it as a single line in a list retList.Add(lineObj); return(retList); } // calc the length of a tab in isoplot units float TabLenInIsoPlotUnits = TabLength * stateMachine.IsoPlotPointsPerAppUnit; // we use half of half of the Isolation width to compensate for the width of the bit float millRadiusCompensatedTabLenInIsoPlotUnits = TabLenInIsoPlotUnits + ((stateMachine.IsolationWidth * stateMachine.IsoPlotPointsPerAppUnit) / 2); // this is the amount of a segment repressented by a tab float pctOfSegmentInASingleTab = millRadiusCompensatedTabLenInIsoPlotUnits / IsoSegmentLength; // we deduct half a tab width from the midpoint to calc the new start and end points float pctOfSegmentInASingleHalfTab = pctOfSegmentInASingleTab / 2; // set this now int numSegments = adjustedNumTabs + 1; // figure out the set of points starting and ending each line segment // add the original line start point ptListMidCenters.Add(new PointF(fX0, fY0)); // this is based on the line partitioning algorythm courtesy of Tom Sirgedas // https://stackoverflow.com/questions/3542402/partition-line-into-equal-parts for (float i = 1; i < numSegments; i++) { float weightedAverage = (i / numSegments); float workingNearSidePct = pctOfSegmentInASingleHalfTab; float workingFarSidePct = pctOfSegmentInASingleHalfTab; // calc the start of the segment float startX = fX0 * (1 - (weightedAverage - workingNearSidePct)) + fX1 * (weightedAverage - workingNearSidePct); float startY = fY0 * (1 - (weightedAverage - workingNearSidePct)) + fY1 * (weightedAverage - workingNearSidePct); // calc the end of the segment float endX = fX0 * (1 - (weightedAverage + workingFarSidePct)) + fX1 * (weightedAverage + workingFarSidePct); float endY = fY0 * (1 - (weightedAverage + workingFarSidePct)) + fY1 * (weightedAverage + workingFarSidePct); // add the point about this center ptListMidCenters.Add(new PointF(startX, startY)); ptListMidCenters.Add(new PointF(endX, endY)); } // add the original line end point ptListMidCenters.Add(new PointF(fX1, fY1)); // by this point we have a list of points, each pair represents a line we should draw // now we go through the points list and build our lines from them for (int i = 0; i < ptListMidCenters.Count; i += 2) { float startX = ptListMidCenters[i].X; float startY = ptListMidCenters[i].Y; float endX = ptListMidCenters[i + 1].X; float endY = ptListMidCenters[i + 1].Y; // convert to ints int startXInt = (int)Math.Round(startX, 0); int startYInt = (int)Math.Round(startY, 0); int endXInt = (int)Math.Round(endX, 0); int endYInt = (int)Math.Round(endY, 0); // create a new line, give it a debugID based off the original full length one, and copy other info in as well lineObjSegment = new GCodeCmd_Line(startXInt, startYInt, endXInt, endYInt, this.PointsAddedCount, (int)((this.DebugID * DEFAULT_NEW_DEBUG_ID_MULTIPLIER) + i)); lineObjSegment.ReverseOnConversionToGCode = this.ReverseOnConversionToGCode; // add it retList.Add(lineObjSegment); } // was the original line object reversed? If so we have to reverse the order of the segments if (this.ReverseOnConversionToGCode == true) { retList.Reverse(); } // return this return(retList); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Generates the gcode to mill a pocket in the surface. We use this for /// BedFlattening /// </summary> /// <remarks>the gcode file is assumed to have been populated with the standard headers. /// We just add our lines onto the end.</remarks> /// <param name="lX">low x coord</param> /// <param name="lY">low y coord</param> /// <param name="hX">high x coord</param> /// <param name="hY">high y coord</param> /// <param name="millWidth">the diameter of the mill doing the pocketing</param> /// <param name="overlapScaleFactor">the amount of overlap we require. Expressed as decimal fraction. 0.25 =25%</param> /// <param name="errStr">the error string</param> public int GeneratePocketGCode(float isoPlotPointsPerAppUnit, float lX, float lY, float hX, float hY, float millWidth, float overlapScaleFactor, ref string errStr) { int i = 0; GCodeCmd_ZMove zLine = null; GCodeCmd_RapidMove rmLine = null; GCodeCmd_Line gcLine = null; GCodeCmd_Comment coLine = null; errStr = ""; float centerX; float centerY; float lXCutCoord; float lYCutCoord; float hXCutCoord; float hYCutCoord; float lastXCoord; float lastYCoord; // test these if (isoPlotPointsPerAppUnit <= 0) { LogMessage("GeneratePocketGCode: isoPlotPointsPerAppUnit<=0"); errStr = "isoPlotPointsPerAppUnit is invalid."; return(1023); } if ((lX == float.MaxValue) || (lY == float.MaxValue) || (hX == float.MinValue) || (hY == float.MinValue)) { LogMessage("GeneratePocketGCode: One or more of the lX,lY,hXor hY coordinates are invalid."); errStr = "The X and Y coordinates of the pocket rectangle are invalid."; return(1024); } // do we enclose an area? if ((lX == hX) || (lY == hY)) { LogMessage("GeneratePocketGCode: The lX,lY,hXor hY coordinates do not enclose an area."); errStr = "The X and Y coordinates of the pocket rectangle do not enclose an area."; return(1025); } // are we inverted if ((lX > hX) || (lY > hY)) { LogMessage("GeneratePocketGCode: The lX,lY,hXor hY coordinates are inverted."); errStr = "The X and Y coordinates of the pocket rectangle are inverted."; return(1026); } // more checks if (millWidth < 0) { LogMessage("GeneratePocketGCode: The millWidth is invalid."); errStr = "The millWidth is invalid."; return(1027); } // more checks if ((overlapScaleFactor > 1) || (overlapScaleFactor < 0)) { LogMessage("GeneratePocketGCode: The overlapScaleFactor is invalid."); errStr = "The overlapScaleFactor is invalid."; return(1028); } if (StateMachine.CurrentZFeedrate <= 0) { LogMessage("GeneratePocketGCode: The zFeedRate is invalid."); errStr = "The zFeedRate is invalid."; return(1029); } if (StateMachine.CurrentXYFeedrate <= 0) { LogMessage("GeneratePocketGCode: The xyFeedRate is invalid."); errStr = "The xyFeedRate is invalid."; return(1030); } if (StateMachine.ZCoordForCut > StateMachine.ZCoordForClear) { LogMessage("GeneratePocketGCode: The zCutLevel > zClearLevel. This cannot be correct."); errStr = "The zCutLevel > zClearLevel. This cannot be correct."; return(1031); } // test to see if the pocket can be cut with this mill if ((millWidth >= (hX - lX)) || (millWidth >= (hY - lY))) { LogMessage("GeneratePocketGCode: The mill diameter is bigger than the pocket area."); errStr = "The mill diameter is bigger than the pocket area. Pocket cannot be cut with this mill."; return(1031); } // calculate the center point centerX = (((hX - lX) / 2f) + lX) * isoPlotPointsPerAppUnit; centerY = (((hY - lY) / 2f) + lY) * isoPlotPointsPerAppUnit; // the first offset distance is the millWidth, after that we adjust by float incrementalDistance = (millWidth * overlapScaleFactor) * isoPlotPointsPerAppUnit; coLine = new GCodeCmd_Comment("... start ..."); this.AddLine(coLine); // figure out the new corner coordinates - compensating for milling // bit diameter lXCutCoord = (lX + (millWidth / 2)) * isoPlotPointsPerAppUnit; lYCutCoord = (lY + (millWidth / 2)) * isoPlotPointsPerAppUnit; hXCutCoord = (hX - (millWidth / 2)) * isoPlotPointsPerAppUnit; hYCutCoord = (hY - (millWidth / 2)) * isoPlotPointsPerAppUnit; // G00 rapid move tool head to the destX,destY rmLine = new GCodeCmd_RapidMove((int)hXCutCoord, (int)hYCutCoord); this.AddLine(rmLine); // G01 - put the bit into the work piece zLine = new GCodeCmd_ZMove(GCodeCmd_ZMove.GCodeZMoveHeightEnum.GCodeZMoveHeight_ZCoordForCut); zLine.WantLinearMove = true; this.AddLine(zLine); // do the vertical down leg gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)hYCutCoord, (int)hXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); // do the low horizontal leg gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)lYCutCoord, (int)lXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); // do the vertical up leg gcLine = new GCodeCmd_Line((int)lXCutCoord, (int)lYCutCoord, (int)lXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); // do the high horizontal leg gcLine = new GCodeCmd_Line((int)lXCutCoord, (int)hYCutCoord, (int)hXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); lastXCoord = hXCutCoord; lastYCoord = hYCutCoord; // now do the rest of the pocket passes. This is encoded as a for loop // because I do not like endless loops. MAX_POCKETING_PASSES should be // pretty high so that it is not reached unless the finish tests fail for (i = 0; i < MAX_POCKETING_PASSES; i++) { // figure out the new corner coordinates - compensating for milling // bit diameter lXCutCoord = lXCutCoord + incrementalDistance; lYCutCoord = lYCutCoord + incrementalDistance; hXCutCoord = hXCutCoord - incrementalDistance; hYCutCoord = hYCutCoord - incrementalDistance; // perform tests if ((lXCutCoord >= centerX) || (lYCutCoord >= centerY) || (hXCutCoord <= centerX) || (hYCutCoord <= centerY)) { // we are on the last cut - just figure out which is the longer dimension // and run a single cut down that if ((lX - lY) > (hX - hY)) { // we have to move to the new start position gcLine = new GCodeCmd_Line((int)lastXCoord, (int)lastYCoord, (int)hXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); // vertical is the longer dimension, hold X constant, run down Y gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)hYCutCoord, (int)hXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); lastXCoord = hXCutCoord; lastYCoord = hYCutCoord; } else { // we have to move to the new start position gcLine = new GCodeCmd_Line((int)lastXCoord, (int)lastYCoord, (int)hXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); // horizontal is the longer dimension, hold Y constant, run down X gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)hYCutCoord, (int)lXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); lastXCoord = hXCutCoord; lastYCoord = hYCutCoord; } // leave now break; } coLine = new GCodeCmd_Comment("... pass ..."); this.AddLine(coLine); // we have to move to the new start position gcLine = new GCodeCmd_Line((int)lastXCoord, (int)lastYCoord, (int)hXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); // do the vertical down leg, this will also move it to (hXCutCoord, hYCutCoord) gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)hYCutCoord, (int)hXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); // do the low horizontal leg gcLine = new GCodeCmd_Line((int)hXCutCoord, (int)lYCutCoord, (int)lXCutCoord, (int)lYCutCoord); this.AddLine(gcLine); // do the vertical up leg gcLine = new GCodeCmd_Line((int)lXCutCoord, (int)lYCutCoord, (int)lXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); // do the high horizontal leg gcLine = new GCodeCmd_Line((int)lXCutCoord, (int)hYCutCoord, (int)hXCutCoord, (int)hYCutCoord); this.AddLine(gcLine); lastXCoord = hXCutCoord; lastYCoord = hYCutCoord; } // one last test if (i >= MAX_POCKETING_PASSES) { LogMessage("GeneratePocketGCode: The the maximum number of pocketing passes was reached."); errStr = "The the maximum number of pocketing passes was reached. The gcode file is not correct. Please see the logs."; return(1036); } coLine = new GCodeCmd_Comment("... end ..."); this.AddLine(coLine); return(0); }