/// <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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        /// <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);
            }