/// <summary> /// Record the parameters from a Set Axis command. /// </summary> /// <param name="axisName"></param> /// <param name="maxSpeed"></param> /// <param name="acceleration"></param> public void RecordSetAxis(char axisID, string axisName, double maxSpeed, double acceleration) { AxisModel axisModel = _printerModel.FindAxis(axisName); double mmPerStep = axisModel.MmPerStep; //Max speed is read as steps / s and acceleration is read as steps / s2. //These parameters are converted to this program's convention of mm / s and mm / s2. double convertedMaxSpeed = maxSpeed * mmPerStep; double convertedAcceleration = acceleration * mmPerStep; //Record new data. switch (axisID) { case 'X': _xRealTimeStatusAxisModel = new RealTimeStatusAxisModel(axisName, _xRealTimeStatusAxisModel.Position, convertedMaxSpeed, convertedAcceleration); break; case 'Y': _yRealTimeStatusAxisModel = new RealTimeStatusAxisModel(axisName, _yRealTimeStatusAxisModel.Position, convertedMaxSpeed, convertedAcceleration); break; case 'Z': //If the Z Axis does not need to be changed, then keep the same position. Otherwise, create new positions assuming the Z actuator was retracted before becoming active. double zPosition = (axisName == _zRealTimeStatusAxisModel.Name) ? _zRealTimeStatusAxisModel.Position : _printerModel.FindAxis(axisName).MaxPosition - GlobalValues.LimitBuffer - _printerModel.FindAxis(axisName).MinPosition; _zRealTimeStatusAxisModel = new RealTimeStatusAxisModel(axisName, zPosition, convertedMaxSpeed, convertedAcceleration); break; default: //Should never reach this point. break; } //Notify other classes. OnRecordSetAxisExecuted(axisName); }
/// <summary> /// Set the new center as the origin (position 0) and adjust the max and min range around such. /// </summary> /// <param name="commandSet"></param> /// <returns></returns> private List <string> InterpretSetOrigin(string commandSet) { //Remove "*Origin" from the beginning of the string. commandSet = commandSet.Substring(6); if (commandSet.Contains("E")) { if (_realTimeStatusDataModel.ActivePrintheadType == PrintheadType.Motorized) { RealTimeStatusMotorizedPrintheadModel realTimeStatusMotorizedPrintheadModel = (RealTimeStatusMotorizedPrintheadModel)_realTimeStatusDataModel.ActivePrintheadModel; MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)_printerModel.FindPrinthead(realTimeStatusMotorizedPrintheadModel.Name).PrintheadTypeModel; double previousEPosition = realTimeStatusMotorizedPrintheadModel.Position; motorizedPrintheadTypeModel.MaxPosition -= previousEPosition; motorizedPrintheadTypeModel.MinPosition -= previousEPosition; realTimeStatusMotorizedPrintheadModel.Position = 0; } } if (commandSet.Contains("X")) { AxisModel xAxisModel = _printerModel.AxisModelList[0]; double previousXPosition = _realTimeStatusDataModel.XRealTimeStatusAxisModel.Position; xAxisModel.MaxPosition -= previousXPosition; xAxisModel.MinPosition -= previousXPosition; _realTimeStatusDataModel.XRealTimeStatusAxisModel.Position = 0; } if (commandSet.Contains("Y")) { AxisModel yAxisModel = _printerModel.AxisModelList[1]; double previousYPosition = _realTimeStatusDataModel.YRealTimeStatusAxisModel.Position; yAxisModel.MaxPosition -= previousYPosition; yAxisModel.MinPosition -= previousYPosition; _realTimeStatusDataModel.YRealTimeStatusAxisModel.Position = 0; } if (commandSet.Contains("Z")) { AxisModel zAxisModel = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name); double previousZPosition = _realTimeStatusDataModel.ZRealTimeStatusAxisModel.Position; zAxisModel.MaxPosition -= previousZPosition; zAxisModel.MinPosition -= previousZPosition; _realTimeStatusDataModel.ZRealTimeStatusAxisModel.Position = 0; } OnCommandSetMinMaxPositionChanged(); OnCommandSetMinMaxPositionChanged(); //No commands to return. return(null); }
/// <summary> /// Reads the coordinate values in a movement or print command. /// </summary> /// <param name="convertedGCodeLine"></param> /// <param name="gCodeIndex"></param> /// <param name="materialModel"></param> /// <returns></returns> private MovementModel ReadCoord(string convertedGCodeLine, int gCodeIndex, MaterialModel materialModel) { //G Commands from Converted GCode are in relative positions. string[] gCodePhrases = GCodeStringParsing.GCodeTo2DArr(convertedGCodeLine)[0]; double xDistance = 0; double yDistance = 0; double zDistance = 0; double eDistance = 0; //Read the coordinates from the GCode. for (int phrase = 1; phrase < gCodePhrases.Length; phrase++) { switch (gCodePhrases[phrase][0]) { case 'X': int xSteps = (int)GCodeStringParsing.ParseDouble(gCodePhrases[phrase]); AxisModel xAxisModel = _printerModel.AxisModelList[0]; xDistance = G00Calculator.StepsToDistance(xSteps, xAxisModel.MmPerStep, xAxisModel.IsDirectionInverted); break; case 'Y': int ySteps = (int)GCodeStringParsing.ParseDouble(gCodePhrases[phrase]); AxisModel yAxisModel = _printerModel.AxisModelList[1]; yDistance = G00Calculator.StepsToDistance(ySteps, yAxisModel.MmPerStep, yAxisModel.IsDirectionInverted); break; case 'Z': int zSteps = (int)GCodeStringParsing.ParseDouble(gCodePhrases[phrase]); AxisModel zAxisModel = _printerModel.FindAxis(materialModel.PrintheadModel.AttachedZAxisModel.Name); zDistance = G00Calculator.StepsToDistance(zSteps, zAxisModel.MmPerStep, zAxisModel.IsDirectionInverted); break; case 'E': int eSteps = (int)GCodeStringParsing.ParseDouble(gCodePhrases[phrase]); MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)materialModel.PrintheadModel.PrintheadTypeModel; eDistance = G00Calculator.StepsToDistance(eSteps, motorizedPrintheadTypeModel.MmPerStep, motorizedPrintheadTypeModel.IsDirectionInverted); break; default: //Do nothing. break; } } MovementModel movementModel = new MovementModel(xDistance, yDistance, zDistance, eDistance, gCodeIndex, materialModel, _printerModel); return(movementModel); }
/// <summary> /// Translates task queued message when a Set Axis task is complete. /// Sets parameters for the Real Time Status. /// </summary> /// <param name="taskQueuedMessage"></param> public void InterpretSetAxisComplete(string taskQueuedMessage) { char axisID = 'A'; //X, Y, or Z. A is just a temporary placeholder. string axisName = taskQueuedMessage.Substring(12, taskQueuedMessage.IndexOf(" S") - 12); //Name of the Axis. Labelled as unknown if Axis cannot be found. double[] parameterValues = ParseDoubleArray(taskQueuedMessage.Substring(taskQueuedMessage.IndexOf(" S"))); //Array of numerical values in incomingMessage. axisName = (_printerModel.FindAxis(axisName) != null) ? axisName : "Unknown Axis"; int maxSpeed = (int)parameterValues[0]; int acceleration = (int)parameterValues[1]; //The old Axis is used to revert the active status of the old Axis. AxisViewModel oldAxisViewModel = null; switch (taskQueuedMessage.Substring(4, 1)) //Axis Name. { case "X": axisID = 'X'; break; case "Y": axisID = 'Y'; break; case "Z": axisID = 'Z'; oldAxisViewModel = _printerViewModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name); break; default: //If Axis was not found. axisName = "Unknown Axis"; break; } //Set Real Time Status parameters based on this incomingMessage. if ((axisID != 'A') && (axisName != "Unknown Axis")) { if (oldAxisViewModel != null) { oldAxisViewModel.AxisStatus = AxisStatus.Idle; } _realTimeStatusDataModel.RecordSetAxis(axisID, axisName, maxSpeed, acceleration); _printerViewModel.FindAxis(axisName).AxisStatus = AxisStatus.Active; } }
/// <summary> /// Takes manual input parameters for a movement command and outputs the command to the serial port. /// </summary> /// <param name="xDistance"></param> /// <param name="yDistance"></param> /// <param name="zDistance"></param> public void ProcessManualMovementCommand(double xDistance, double yDistance, double zDistance) { double xmmPerStep = (xDistance != 0) ? _printerModel.AxisModelList[0].MmPerStep : double.MaxValue; double ymmPerStep = (yDistance != 0) ? _printerModel.AxisModelList[1].MmPerStep : double.MaxValue; AxisModel zAxisModel = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name); double zmmPerStep = (zDistance != 0) ? _printerModel.FindAxis(zAxisModel.Name).MmPerStep : double.MaxValue; bool zDirectionInverted = (zAxisModel != null) ? zAxisModel.IsDirectionInverted : false; double unused = 0; string axesMovementString = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement(xmmPerStep, ymmPerStep, zmmPerStep, xDistance, yDistance, zDistance, _printerModel.AxisModelList[0].IsDirectionInverted, _printerModel.AxisModelList[1].IsDirectionInverted, zDirectionInverted, ref unused, ref unused, ref unused)); _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(axesMovementString); }
/// <summary> /// Sends outgoing commands that retracts all Z Axes and moves X and Y Axes to the limit switches. /// </summary> public void Home(double xCalibrationSpeed, double yCalibrationSpeed, double zCalibrationSpeed, double xDistanceFromCenter, double yDistanceFromCenter) { try { //Retract Z Axes. RetractAllZ(zCalibrationSpeed); //Z Axes should be in default positions. AxisModel zAxisModel = _printerModel.ZAxisModelList[_printerModel.ZAxisModelList.Count - 1]; double zPosition = zAxisModel.MaxPosition - GlobalValues.LimitBuffer; _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "SetMinMaxPos " + "Z" + zPosition); //Set X Axis to calibration speeds. AxisModel xAxis = _printerModel.AxisModelList[0]; int xLimitPinID = (xAxis.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : xAxis.AttachedLimitSwitchGPIOPinModel.PinID; string switchX = _writeSetAxisModel.WriteSetAxis(xAxis.AxisID, xAxis.AttachedMotorStepGPIOPinModel.PinID, xAxis.AttachedMotorDirectionGPIOPinModel.PinID, xAxis.StepPulseTime, xLimitPinID, xCalibrationSpeed, xAxis.MaxAcceleration, xAxis.MmPerStep); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchX); //Set Y Axis to max speeds. AxisModel yAxis = _printerModel.AxisModelList[1]; int yLimitPinID = (yAxis.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : yAxis.AttachedLimitSwitchGPIOPinModel.PinID; string switchY = _writeSetAxisModel.WriteSetAxis(yAxis.AxisID, yAxis.AttachedMotorStepGPIOPinModel.PinID, yAxis.AttachedMotorDirectionGPIOPinModel.PinID, yAxis.StepPulseTime, yLimitPinID, yCalibrationSpeed, yAxis.MaxAcceleration, yAxis.MmPerStep); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchY); //Hit the min and max limit switches on X. double unused = 0; string xPositive = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( xAxis.MmPerStep, 0, 0, 5000, 0, 0, xAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); string xNegative = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( xAxis.MmPerStep, 0, 0, -5000, 0, 0, xAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xPositive); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xNegative); //Move away from the limit switch. string xMoveAwayFromLimit = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( xAxis.MmPerStep, 0, 0, GlobalValues.LimitBuffer, 0, 0, xAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xMoveAwayFromLimit); //Hit the min and max limit switches on Y. string yPositive = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( 0, yAxis.MmPerStep, 0, 0, 5000, 0, yAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); string yNegative = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( 0, yAxis.MmPerStep, 0, 0, -5000, 0, yAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yPositive); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yNegative); //Move away from the limit switch. string yMoveAwayFromLimit = GCodeLinesConverter.GCodeLinesListToString( WriteG00.WriteAxesMovement( 0, yAxis.MmPerStep, 0, 0, GlobalValues.LimitBuffer, 0, yAxis.IsDirectionInverted, false, false, ref unused, ref unused, ref unused)); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yMoveAwayFromLimit); //Set X Axis to max speeds. string switchXMax = _writeSetAxisModel.WriteSetAxis(xAxis); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchXMax); //Set Y Axis to max speeds. string switchYMax = _writeSetAxisModel.WriteSetAxis(yAxis); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchYMax); //Center the X and Y actuators. _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "Center X" + xDistanceFromCenter + " Y" + yDistanceFromCenter); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "OriginXY"); //At the end, switch the Z actuator to the Printhead used at the beginning of the print. if (_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name != "Unset") { AxisModel zAxisFinalModel = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name); int zFinalLimitPinID = (zAxisFinalModel.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : zAxisFinalModel.AttachedLimitSwitchGPIOPinModel.PinID; string switchZFinal = _writeSetAxisModel.WriteSetAxis(zAxisFinalModel.AxisID, zAxisFinalModel.AttachedMotorStepGPIOPinModel.PinID, zAxisFinalModel.AttachedMotorDirectionGPIOPinModel.PinID, zAxisFinalModel.StepPulseTime, zFinalLimitPinID, zCalibrationSpeed, zAxisFinalModel.MaxAcceleration, zAxisFinalModel.MmPerStep); _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchZFinal); } OnCalibrationBegun(); } catch { _errorListViewModel.AddError("", "Unkown error when homing"); } }
/// <summary> /// Processes the command of setting a printhead. /// </summary> public List <ConvertedGCodeLine> ProcessTCommand(string[] repRapLine, ref MaterialModel currentMaterial) { AxisModel xAxis = _printerModel.AxisModelList[0]; AxisModel yAxis = _printerModel.AxisModelList[1]; AxisModel zAxisCurrent = _printerModel.FindAxis(currentMaterial.PrintheadModel.AttachedZAxisModel.Name); //The return GCode. List <ConvertedGCodeLine> convertedGCodeLinesList = new List <ConvertedGCodeLine>(); //Finds the material that matches the TCommand. string repRapTCommand = repRapLine[0]; MaterialModel matchingMaterial = _printModel.FindMaterial(repRapTCommand); //Appends the converted GCode line with a command that sets the Printhead. //Also appends the converted GCode line with a command that sets the new Z Axis associated with the new Printhead. //Also appends the converted GCode line with commands that compensate for the new Printhead's offsets. try { //If the current Material is using a Motorized Printhead, retract it before switching Printheads. if (((currentMaterial.Name != "Unset") && //If this is not the first Material (currentMaterial.PrintheadModel.PrintheadType == PrintheadType.Motorized) && (currentMaterial.PrintheadModel.Name != matchingMaterial.PrintheadModel.Name) && //Do not execute retraction-related actions if no Printhead change occurs (_parametersModel.IsRetracted == false))) { MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)currentMaterial.PrintheadModel.PrintheadTypeModel; ContinuousPrintStyleModel continuousPrintheadStyleModel = (ContinuousPrintStyleModel)currentMaterial.PrintStyleModel; int eModiPrintCoordIndex = _parametersModel.FindEModiPrintCoordIndex(currentMaterial.PrintheadModel); convertedGCodeLinesList = WriteG00.WriteMotorizedPrintWithoutMovement(-1 * continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance, motorizedPrintheadTypeModel.MmPerStep, motorizedPrintheadTypeModel.IsDirectionInverted, ref _parametersModel.ERepRapCoord.DeltaCoordRemainder, _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex]); _parametersModel.IsRetracted = true; } //If a new Motorized Printhead is being set... //Finds the EModiPrintCoord corresponding to the given Printhead and sets the Minimum and Maximum Position values of the EModiPrintCoord. if (matchingMaterial.PrintheadModel.PrintheadType == PrintheadType.Motorized) { int eModiPrintCoordIndex = _parametersModel.FindEModiPrintCoordIndex(matchingMaterial.PrintheadModel); MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)matchingMaterial.PrintheadModel.PrintheadTypeModel; ContinuousPrintStyleModel continuousPrintheadStyleModel = (ContinuousPrintStyleModel)matchingMaterial.PrintStyleModel; //Sets new Min and Max Positions. _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex].MinPosition = motorizedPrintheadTypeModel.MinPosition; _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex].MaxPosition = motorizedPrintheadTypeModel.MaxPosition; //Sets the starting position of the new Motorized Printhead. //The starting position is the retracted state. //If this is the first Material, then retraction needs to occur to reach the starting retracted state. if (currentMaterial.Name == "Unset") //If this is the first Material. { //Retraction needs to occur to reach the starting retracted state. List <ConvertedGCodeLine> retractE = WriteG00.WriteMotorizedPrintWithoutMovement(-1 * continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance, motorizedPrintheadTypeModel.MmPerStep, motorizedPrintheadTypeModel.IsDirectionInverted, ref _parametersModel.ERepRapCoord.DeltaCoordRemainder, _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex]); if (retractE != null) { convertedGCodeLinesList.AddRange(retractE); } _parametersModel.ERepRapCoord.SetInitialCoord(continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance); _parametersModel.IsRetracted = true; } //If this is a new Motorized Printhead, then it is by default, retracted. if (currentMaterial.PrintheadModel.Name != matchingMaterial.PrintheadModel.Name) { _parametersModel.ERepRapCoord.SetInitialCoord(continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance); _parametersModel.IsRetracted = true; } } else { _parametersModel.IsRetracted = false; } //Set new Min and Max Positions for the X and Y Axes. //This is only relevant when the first Material is set. _parametersModel.SetNewXYZCoord('X', _parametersModel.XCoord.CurrentCoord, _printerModel.AxisModelList[0].MinPosition, _printerModel.AxisModelList[0].MaxPosition); _parametersModel.SetNewXYZCoord('Y', _parametersModel.YCoord.CurrentCoord, _printerModel.AxisModelList[1].MinPosition, _printerModel.AxisModelList[1].MaxPosition); //If the Z Axis does not need to be changed, then keep the same Min and Max Positions in the ZCoord. //If the Z Axis was switched, then set a new ZCoord Position assuming the Z Axis started from a retracted position and traversed its Offset. if (matchingMaterial.PrintheadModel.AttachedZAxisModel.Name != matchingMaterial.PrintheadModel.AttachedZAxisModel.Name) { AxisModel zAxisModel = _printerModel.FindAxis(matchingMaterial.PrintheadModel.AttachedZAxisModel.Name); double newZPosition = zAxisModel.MaxPosition - GlobalValues.LimitBuffer; _parametersModel.SetNewXYZCoord('Z', newZPosition, zAxisModel.MinPosition, zAxisModel.MaxPosition); } //Set new Droplet parameters if applicable. if (!((currentMaterial.Name == "Unset") || (currentMaterial == null)) && //If the current Material is set to Droplet... (currentMaterial.PrintStyle == PrintStyle.Droplet)) { //Execute movement for the remaining movement left in droplet movements. MaterialModel newMaterialParameter = (matchingMaterial.PrintStyle == PrintStyle.Droplet) ? matchingMaterial : null; double[] remainingDropletMovementArr = _parametersModel.ResetDropletPrintParameters(currentMaterial, newMaterialParameter); double unused = 0; List <ConvertedGCodeLine> remainingDropletMovement = WriteG00.WriteAxesMovement( xAxis.MmPerStep, yAxis.MmPerStep, zAxisCurrent.MmPerStep, remainingDropletMovementArr[0], remainingDropletMovementArr[1], remainingDropletMovementArr[2], xAxis.IsDirectionInverted, yAxis.IsDirectionInverted, zAxisCurrent.IsDirectionInverted, ref unused, ref unused, ref unused); if (remainingDropletMovement != null) { convertedGCodeLinesList.AddRange(remainingDropletMovement); } } else if (matchingMaterial.PrintStyle == PrintStyle.Droplet) //If the current Material is irrelevant and the new Material is set to Droplet... { _parametersModel.ResetDropletPrintParameters(null, matchingMaterial); } //Set the new Material. currentMaterial = matchingMaterial; //Command Set for switching Materials. //This Command Set will convert to the commands for retracting the Z Axis, switching Printheads, moving Offsets, and setting new movement speeds. string convertedGCodeLine = SerialMessageCharacters.SerialCommandSetCharacter + "SwitchMaterial "; //If applicable, pause the print sequence before switching to the next Material. if ((currentMaterial.Name != "Unset") && (currentMaterial.PauseBeforeDeactivating == true)) { convertedGCodeLine += "D"; } //If applicable pause the print sequence after switching printheads. if (matchingMaterial.PauseAfterActivating == true) { convertedGCodeLine += "A"; } if (convertedGCodeLine[convertedGCodeLine.Length - 1] != ' ') { convertedGCodeLine += " "; } convertedGCodeLine += '"' + matchingMaterial.Name + '"'; convertedGCodeLinesList.Add(new ConvertedGCodeLine(convertedGCodeLine)); } catch when((matchingMaterial == null) || (currentMaterial == null)) //Catch unset Material. { //Catching and error reporting should have happened earlier. _parametersModel.ErrorReporterViewModel.ReportError("G-Code Conversion Failed: Print Settings Incorrectly Set, Should Not Happen", "Material Null"); return(null); }