/**
Copyright (C) 2012-2025 by Autodesk, Inc.
All rights reserved.
Fadal post processor configuration.
$Revision: 44198 6a42ca17e0263a1a46e2952ee0514914e541d222 $
$Date: 2025-10-10 14:37:38 $
FORKID {D3B70418-781B-4cfb-8CD2-98E9C897515A}
*/
description = "Fadal";
vendor = "Fadal";
vendorUrl = "http://www.fadal.com";
legal = "Copyright (C) 2012-2025 by Autodesk, Inc.";
certificationLevel = 2;
minimumRevision = 45917;
longDescription = "Generic milling post for Fadal.";
extension = "nc";
programNameIsInteger = true;
setCodePage("ascii");
capabilities = CAPABILITY_MILLING | CAPABILITY_MACHINE_SIMULATION;
tolerance = spatial(0.002, MM);
minimumChordLength = spatial(0.25, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(180);
allowHelicalMoves = true;
allowedCircularPlanes = undefined; // allow any circular motion
highFeedrate = (unit == MM) ? 5000 : 100;
highFeedMapping = HIGH_FEED_MAP_MULTI;
// user-defined properties
properties = {
preloadTool: {
title : "Preload tool",
description: "Preloads the next tool at a tool change (if any).",
group : "preferences",
type : "boolean",
value : false,
scope : "post"
},
showSequenceNumbers: {
title : "Use sequence numbers",
description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.",
group : "formats",
type : "enum",
values : [
{title:"Yes", id:"true"},
{title:"No", id:"false"},
{title:"Only on tool change", id:"toolChange"}
],
value: "true",
scope: "post"
},
sequenceNumberStart: {
title : "Start sequence number",
description: "The number at which to start the sequence numbers.",
group : "formats",
type : "integer",
value : 10,
scope : "post"
},
sequenceNumberIncrement: {
title : "Sequence number increment",
description: "The amount by which the sequence number is incremented by in each block.",
group : "formats",
type : "integer",
value : 5,
scope : "post"
},
optionalStop: {
title : "Optional stop",
description: "Outputs optional stop code during when necessary in the code.",
group : "preferences",
type : "boolean",
value : true,
scope : "post"
},
onlyENumbers: {
title : "Output E-code for WCS offset",
description: "Enable to output E-codes or disable to output G54-G59 for WCS offsets.",
group : "preferences",
type : "boolean",
value : true,
scope : "post"
},
separateWordsWithSpace: {
title : "Separate words with space",
description: "Adds spaces between words if enabled.",
group : "formats",
type : "boolean",
value : true,
scope : "post"
},
format: {
title : "Format style output",
description: "Select either Fadal or Fanuc style formatting.",
group : "formats",
type : "enum",
values : [
{title:"Fadal", id:"fadal"},
{title:"Fanuc", id:"fanuc"}
],
value: "fanuc",
scope: "post"
},
useRigidTapping: {
title : "Use rigid tapping",
description: "Enable to use rigid tapping (G84.1), disable to use standard tapping (G84).",
group : "preferences",
type : "boolean",
value : true,
scope : "post"
},
hasAAxis: {
title : "Has rotary table",
description: "Enable or disable the A-axis rotary table.",
group : "configuration",
type : "boolean",
value : false,
scope : "post"
},
useInverseTime: {
title : "Use inverse time feedrates",
description: "Enable to use inverse time feedrates, disable to use DPM feedrates.",
group : "multiAxis",
type : "boolean",
value : true,
scope : "post"
},
rotaryScale: {
title : "Rotary table scale",
description: "Select either Rotary (0-360) with sign determining direction or Linear (continuous).",
group : "multiAxis",
type : "enum",
values : [
{title:"Rotary", id:"rotary"},
{title:"Linear", id:"linear"}
],
value: "rotary",
scope: "post"
},
safePositionMethod: {
title : "Safe Retracts",
description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.",
group : "homePositions",
type : "enum",
values : [
{title:"Clearance Height", id:"clearanceHeight"},
{title:"Machine Home", id:"machineHome"}
],
value: "machineHome",
scope: "post"
},
useRadius: {
title : "Radius arcs",
description: "Enable to output arcs using radius values rather than IJK.",
group : "preferences",
type : "boolean",
value : false,
scope : "post"
},
disableFeedRamps: {
title : "Use G8",
description: "Enable to disable feed ramps using G8 for all operations. This property is only valid when the 'Format style output' property is set to Fadal.",
group : "preferences",
type : "boolean",
value : false,
scope : "post"
}
};
var gFormat = createFormat({prefix:"G", decimals:1});
var mFormat = createFormat({prefix:"M", decimals:0});
var hFormat = createFormat({prefix:"H", decimals:0});
var diameterOffsetFormat = createFormat({prefix:"D", decimals:0});
var eFormat = createFormat({prefix:"E", decimals:0});
var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL});
var abcFormat = createFormat({decimals:3, type:FORMAT_REAL, scale:DEG});
var feedFormat = createFormat({decimals:(unit == MM ? 1 : 2), type:FORMAT_REAL});
var inverseTimeFormat = createFormat({decimals:3, type:FORMAT_REAL});
var tapFeedFormat = createFormat({decimals:3, type:FORMAT_REAL});
var toolFormat = createFormat({decimals:0});
var rpmFormat = createFormat({decimals:1, forceDecimal:false});
var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999
var rFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL, forceSign:true});
var taperFormat = createFormat({decimals:1, scale:DEG});
var oFormat = createFormat({minDigitsLeft:4, decimals:0});
var xOutput = createOutputVariable({onchange:function() {state.retractedX = false;}, prefix:"X"}, xyzFormat);
var yOutput = createOutputVariable({onchange:function() {state.retractedY = false;}, prefix:"Y"}, xyzFormat);
var zOutput = createOutputVariable({onchange:function() {state.retractedZ = false;}, prefix:"Z"}, xyzFormat);
var aOutput = createOutputVariable({prefix:"A"}, abcFormat);
var bOutput = createOutputVariable({prefix:"B"}, abcFormat);
var cOutput = createOutputVariable({prefix:"C"}, abcFormat);
var feedOutput = createOutputVariable({prefix:"F"}, feedFormat);
var inverseTimeOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, inverseTimeFormat);
var tapFeedOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, tapFeedFormat);
var sOutput = createOutputVariable({prefix:"S", control:CONTROL_FORCE}, rpmFormat);
// circular output
var iOutput = createOutputVariable({prefix:"I", control:CONTROL_NONZERO}, xyzFormat);
var jOutput = createOutputVariable({prefix:"J", control:CONTROL_NONZERO}, xyzFormat);
var kOutput = createOutputVariable({prefix:"K", control:CONTROL_NONZERO}, xyzFormat);
var gMotionModal = createOutputVariable({}, gFormat); // modal group 1 // G0-G3, ...
var gPlaneModal = createOutputVariable({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19
var gAbsIncModal = createOutputVariable({}, gFormat); // modal group 3 // G90-91
var gFeedModeModal = createOutputVariable({}, gFormat); // modal group 5 // G93-94
var gUnitModal = createOutputVariable({}, gFormat); // modal group 6 // G20-21
var gCycleModal = createOutputVariable({}, gFormat); // modal group 9 // G81, ...
var gRetractModal = createOutputVariable({}, gFormat); // modal group 10 // G98-99
var gAccDecModal = createOutputVariable({}, gFormat); // modal group D // G8-G9
var fourthAxisClamp = createOutputVariable({}, mFormat);
var fifthAxisClamp = createOutputVariable({}, mFormat);
var WARNING_WORK_OFFSET = 0;
// fixed settings
var maxTappingRPM = 3000; // s/b 3000 for 10k spindle, 1500 for 7.5k spindle
// collected state
var tapping = false;
var leftTapping = false;
var settings = {
coolant: {
// samples:
// {id: COOLANT_THROUGH_TOOL, on: 88, off: 89}
// {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]}
// {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"}
coolants: [
{id:COOLANT_FLOOD, on:8},
{id:COOLANT_MIST, on:7},
{id:COOLANT_THROUGH_TOOL},
{id:COOLANT_AIR},
{id:COOLANT_AIR_THROUGH_TOOL},
{id:COOLANT_SUCTION},
{id:COOLANT_FLOOD_MIST},
{id:COOLANT_FLOOD_THROUGH_TOOL},
{id:COOLANT_OFF, off:9}
],
singleLineCoolant: false, // specifies to output multiple coolant codes in one line rather than in separate lines
},
retract: {
cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting
methodXY : undefined, // special condition, overwrite retract behavior per axis
methodZ : undefined, // special condition, overwrite retract behavior per axis
useZeroValues : ["G28", "G30"], // enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0)
homeXY : {onIndexing:false, onToolChange:false, onProgramEnd:{axes:[X, Y]}} // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false}
},
machineAngles: { // refer to https://cam.autodesk.com/posts/reference/classMachineConfiguration.html#a14bcc7550639c482492b4ad05b1580c8
controllingAxis: ABC,
type : PREFER_PREFERENCE,
options : ENABLE_ALL
},
workPlaneMethod: {
useTiltedWorkplane : false, // specifies that tilted workplanes should be used (ie. G68.2, G254, PLANE SPATIAL, CYCLE800), can be overwritten by property
eulerConvention : EULER_ZXZ_R, // specifies the euler convention (ie EULER_XYZ_R), set to undefined to use machine angles for TWP commands ('undefined' requires machine configuration)
eulerCalculationMethod: "standard", // ('standard' / 'machine') 'machine' adjusts euler angles to match the machines ABC orientation, machine configuration required
cancelTiltFirst : false, // cancel tilted workplane prior to WCS (G54-G59) blocks
forceMultiAxisIndexing: false, // force multi-axis indexing for 3D programs
optimizeType : OPTIMIZE_AXIS // can be set to OPTIMIZE_NONE, OPTIMIZE_BOTH, OPTIMIZE_TABLES, OPTIMIZE_HEADS, OPTIMIZE_AXIS. 'undefined' uses legacy rotations
},
comments: {
permittedCommentChars: " abcdefghijklmnopqrstuvwxyz0123456789.,=_-", // letters are not case sensitive, use option 'outputFormat' below. Set to 'undefined' to allow any character
prefix : "(", // specifies the prefix for the comment
suffix : ")", // specifies the suffix for the comment
outputFormat : "upperCase", // can be set to "upperCase", "lowerCase" and "ignoreCase". Set to "ignoreCase" to write comments without upper/lower case formatting
maximumLineLength : 80 // the maximum number of characters allowed in a line, set to 0 to disable comment output
},
maximumSequenceNumber: undefined, // the maximum sequence number (Nxxx), use 'undefined' for unlimited
polarCycleExpandMode : 1, // 0=EXPAND_NONE: Does not expand any cycles. 1=EXPAND_TCP: Expands drilling cycles, when TCP is on. 2=EXPAND_NON_TCP: Expands drilling cycles, when TCP is off. 3=EXPAND_ALL: Expands all drilling cycles
// fixed settings below, do not modify
supportsTCP : false // this postprocessor does not support TCP
};
function defineMachine() {
if (getProperty("hasAAxis")) { // note: setup your machine here
var useTCP = false;
var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], tcp:useTCP});
machineConfiguration = new MachineConfiguration(aAxis);
setMachineConfiguration(machineConfiguration);
if (receivedMachineConfiguration) {
warning(localize("The provided CAM machine configuration is overwritten by the postprocessor."));
receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten
}
}
if (getProperty("rotaryScale") == "rotary") {
var axis = -1;
if (machineConfiguration.getAxisV().isEnabled()) {
axis = machineConfiguration.getAxisV().getCoordinate();
} else if (machineConfiguration.getAxisU().isEnabled()) {
axis = machineConfiguration.getAxisU().getCoordinate();
}
if (axis != -1) {
var output = axis == 0 ? aOutput : (axis == 1 ? bOutput : cOutput);
output.setType(TYPE_DIRECTIONAL);
output.setCyclicLimit(360);
output.setCyclicSign(1);
}
}
if (!receivedMachineConfiguration) {
// multiaxis settings
if (machineConfiguration.isHeadConfiguration()) {
machineConfiguration.setVirtualTooltip(false); // translate the pivot point to the virtual tool tip for nonTCP rotary heads
}
// retract / reconfigure
var performRewinds = false; // set to true to enable the rewind/reconfigure logic
if (performRewinds) {
machineConfiguration.enableMachineRewinds(); // enables the retract/reconfigure logic
safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock, can be overridden with a property
safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate
safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate
machineConfiguration.setSafeRetractDistance(safeRetractDistance);
machineConfiguration.setSafeRetractFeedrate(safeRetractFeed);
machineConfiguration.setSafePlungeFeedrate(safePlungeFeed);
var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values
machineConfiguration.setRewindStockExpansion(stockExpansion);
}
// multi-axis feedrates
if (machineConfiguration.isMultiAxisConfiguration()) {
machineConfiguration.setMultiAxisFeedrate(
useTCP ? FEED_FPM : getProperty("useInverseTime") ? FEED_INVERSE_TIME : FEED_DPM,
9999.99, // maximum output value for inverse time feed rates
getProperty("useInverseTime") ? INVERSE_MINUTES : DPM_COMBINATION, // INVERSE_MINUTES/INVERSE_SECONDS or DPM_COMBINATION/DPM_STANDARD
0.5, // tolerance to determine when the DPM feed has changed
1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations
);
setMachineConfiguration(machineConfiguration);
}
/* home positions */
// machineConfiguration.setHomePositionX(toPreciseUnit(0, IN));
// machineConfiguration.setHomePositionY(toPreciseUnit(0, IN));
// machineConfiguration.setRetractPlane(toPreciseUnit(0, IN));
}
}
function onOpen() {
// define and enable machine configuration
receivedMachineConfiguration = machineConfiguration.isReceived();
if (typeof defineMachine == "function") {
defineMachine(); // hardcoded machine configuration
}
activateMachine(); // enable the machine optimizations and settings
if (getProperty("useRadius")) {
maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC
}
if (getProperty("format") == "fadal") {
diameterOffsetFormat.setPrefix("H");
}
if (highFeedrate <= 0) {
error(localize("You must set 'highFeedrate' because axes are not synchronized for rapid traversal."));
return;
}
if (!getProperty("separateWordsWithSpace")) {
setWordSeparator("");
}
settings.supportsInverseTimeFeed = getProperty("useInverseTime");
writeln("%");
writeln("O" + oFormat.format(getProgramNumber()) + conditional(programComment, " " + formatComment(programComment)));
writeProgramHeader();
// absolute coordinates and feed per min
writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(94), gPlaneModal.format(17),
(getProperty("format") == "fadal" ? formatWords(hFormat.format(0), eFormat.format(0)) : ""));
writeBlock(gUnitModal.format(unit == MM ? 21 : 20));
validateCommonParameters();
if (settings.workPlaneMethod.useTiltedWorkplane) {
error(localize("The 'useTiltedWorkplane' setting is enabled which is not supported by this postprocessor."));
}
}
function onParameter(name, value) {
}
function writeInitialPositioning(position, insertToolCall, wcsCode) {
var motionCode = {single:0, multi:0};
switch (highFeedMapping) {
case HIGH_FEED_MAP_ANY:
motionCode = {single:1, multi:1}; // map all rapid traversals to high feed
break;
case HIGH_FEED_MAP_MULTI:
motionCode = {single:0, multi:1}; // map rapid traversal along more than one axis to high feed
break;
}
var feed = (highFeedMapping != HIGH_FEED_NO_MAPPING) ? getFeed(highFeedrate) : "";
forceModals(gMotionModal);
if (!state.retractedZ && !insertToolCall) {
if (xyzFormat.getResultingValue(getCurrentPosition().z) < xyzFormat.getResultingValue(position.z)) {
writeBlock(gMotionModal.format(motionCode.single), wcsCode, zOutput.format(position.z), feed);
wcsCode = "";
machineSimulation({z:position.z});
}
}
if (state.retractedZ || insertToolCall) {
var lengthOffset = tool.lengthOffset;
gMotionModal.reset();
if ((tapping || getProperty("disableFeedRamps")) && (getProperty("format") == "fadal")) {
writeBlock(gAccDecModal.format(8));
}
if (!machineConfiguration.isHeadConfiguration()) {
writeBlock(
gAbsIncModal.format(90),
gMotionModal.format(motionCode.multi), wcsCode, xOutput.format(position.x), yOutput.format(position.y), feed
);
machineSimulation({x:position.x, y:position.y});
if (getProperty("format") == "fadal") {
writeBlock(gMotionModal.format(motionCode.single), hFormat.format(lengthOffset), zOutput.format(position.z));
} else {
writeBlock(gMotionModal.format(motionCode.single), gFormat.format(43), zOutput.format(position.z), hFormat.format(lengthOffset));
}
machineSimulation({z:position.z});
} else {
if (getProperty("format") == "fadal") {
writeBlock(
gAbsIncModal.format(90),
gMotionModal.format(motionCode.multi),
wcsCode,
hFormat.format(lengthOffset),
xOutput.format(position.x),
yOutput.format(position.y),
zOutput.format(position.z),
feed
);
} else {
writeBlock(
gAbsIncModal.format(90),
gMotionModal.format(motionCode.multi),
wcsCode,
gFormat.format(43), xOutput.format(position.x),
yOutput.format(position.y),
zOutput.format(position.z), hFormat.format(lengthOffset), feed
);
}
machineSimulation({x:position.x, y:position.y, z:position.z});
}
forceModals(gMotionModal);
} else {
writeBlock(gAbsIncModal.format(90), gMotionModal.format(motionCode.multi), wcsCode, xOutput.format(position.x), yOutput.format(position.y), feed);
machineSimulation({x:position.x, y:position.y});
}
}
function onSection() {
var forceSectionRestart = optionalSection && !currentSection.isOptional();
optionalSection = currentSection.isOptional();
var insertToolCall = isToolChangeNeeded("number") || forceSectionRestart;
var newWorkOffset = isNewWorkOffset() || forceSectionRestart;
var newWorkPlane = isNewWorkPlane() || forceSectionRestart || (typeof defineWorkPlane == "function" &&
Vector.diff(defineWorkPlane(getPreviousSection(), false), defineWorkPlane(currentSection, false)).length > 1e-4);
// Define Machining modes
tapping = isTappingCycle();
leftTapping = tapping && ((getParameter("operation:cycleType") == "left-tapping") || (tool.type == TOOL_TAP_LEFT_HAND));
if (insertToolCall || newWorkOffset || newWorkPlane || state.tcpIsActive || currentSection.isMultiAxis()) {
if (insertToolCall && !isFirstSection()) {
onCommand(COMMAND_COOLANT_OFF); // turn off coolant before retract during tool change
onCommand(COMMAND_STOP_SPINDLE); // stop spindle before retract during tool change
}
if ((tapping || getProperty("disableFeedRamps")) && (getProperty("format") == "fadal") && !isFirstSection()) {
writeBlock(gAccDecModal.format(9));
}
writeRetract(Z); // retract
}
writeln("");
writeComment(getParameter("operation-comment", ""));
// tool change
writeToolCall(tool, insertToolCall);
startSpindle(tool, insertToolCall);
// Output modal commands here
writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(94), gPlaneModal.format(17));
// wcs
if (insertToolCall) { // force work offset when changing tool
currentWorkOffset = undefined;
}
var workOffset = currentSection.workOffset;
var wcsCode = "";
if (workOffset == 0) {
if (getProperty("onlyENumbers")) {
warningOnce(localize("Work offset has not been specified. Using E1 as WCS."), WARNING_WORK_OFFSET);
} else {
warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET);
}
workOffset = 1;
}
if (workOffset > 0) {
if (getProperty("format") == "fadal") {
if (workOffset != currentWorkOffset) {
wcsCode = eFormat.format(workOffset);
currentWorkOffset = workOffset;
}
} else {
if (getProperty("onlyENumbers") || (workOffset > 6)) {
if (workOffset > 24) {
error(localize("Work offset out of range."));
}
if (workOffset != currentWorkOffset) {
wcsCode = eFormat.format(workOffset);
currentWorkOffset = workOffset;
}
} else {
if (workOffset != currentWorkOffset) {
wcsCode = gFormat.format(53 + workOffset); // G54->G59
currentWorkOffset = workOffset;
}
}
}
}
forceXYZ();
var abc = defineWorkPlane(currentSection, true);
setCoolant(tool.coolant); // writes the required coolant codes
forceAny();
if (tapping && getProperty("useRigidTapping")) {
writeBlock(gFormat.format(leftTapping ? 74.2 : 84.2));
}
var initialPosition = getFramePosition(currentSection.getInitialPosition());
writeInitialPositioning(initialPosition, insertToolCall, wcsCode);
}
function onDwell(seconds) {
var maxValue = 99999.999;
if (seconds > maxValue) {
warning(subst(localize("Dwelling time of '%1' exceeds the maximum value of '%2' in operation '%3'"), seconds, maxValue, getParameter("operation-comment", "")));
}
seconds = clamp(0.001, seconds, 99999.999);
var saveFeedMode = gFeedModeModal.getCurrent();
writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(seconds * 1000));
writeBlock(gFeedModeModal.format(saveFeedMode));
}
function onSpindleSpeed(spindleSpeed) {
writeBlock(sOutput.format(spindleSpeed));
}
function onCycle() {
writeBlock(gPlaneModal.format(17));
}
function getCommonCycle(x, y, z, r) {
forceXYZ(); // force xyz on first drill hole of any cycle
if ((currentSection.getPolarMode && currentSection.getPolarMode() != POLAR_MODE_OFF) && currentSection.isMultiAxis()) {
var polarPosition = getPolarPosition(x, y, z);
return [xOutput.format(polarPosition.first.x), yOutput.format(polarPosition.first.y), zOutput.format(polarPosition.first.z),
aOutput.format(polarPosition.second.x), bOutput.format(polarPosition.second.y), cOutput.format(polarPosition.second.z),
"R0" + rFormat.format(r)];
} else {
return [xOutput.format(x), yOutput.format(y), zOutput.format(z), "R0" + rFormat.format(r)];
}
}
function onCyclePoint(x, y, z) {
if (!isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(currentSection))) {
expandCyclePoint(x, y, z);
return;
}
if (isFirstCyclePoint()) {
gRetractModal.reset(); // force G98 to avoid slow feed issue between canned cycles reported for some CNCs
repositionToCycleClearance(cycle, x, y, z);
writeBlock(gFeedModeModal.format(94));
writeBlock(gMotionModal.format(0)); // G01 can cause slow feeds between canned cycles
// return to initial Z which is clearance plane and set absolute mode
var F = cycle.feedrate;
var dwell = (cycle.dwell == 0) ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds
var leftTappingCode = getProperty("useRigidTapping") ? 74.1 : 74;
var rightTappingCode = getProperty("useRigidTapping") ? 84.1 : 84;
var tappingRPM = (spindleSpeed > 750) ? spindleSpeed + 0.2 : spindleSpeed;
if (tapping && ((cycle.clearance - cycle.stock) < toPreciseUnit(0.39999, IN))) {
warning(localize("The retract plane should be greater than ") + xyzFormat.format(toPreciseUnit(0.4, IN)) + localize(" when tapping."));
}
switch (cycleType) {
case "drilling":
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(81),
getCommonCycle(x, y, z, cycle.retract),
feedOutput.format(F)
);
break;
case "counter-boring":
if (dwell > 0) {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(82),
getCommonCycle(x, y, z, cycle.retract),
"P" + milliFormat.format(dwell),
feedOutput.format(F)
);
} else {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(81),
getCommonCycle(x, y, z, cycle.retract),
feedOutput.format(F)
);
}
break;
case "chip-breaking":
if ((cycle.accumulatedDepth < cycle.depth) || (dwell > 0)) {
expandCyclePoint(x, y, z);
} else {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(73),
getCommonCycle(x, y, z, cycle.retract),
(((cycle.incrementalDepthReduction > 0) ? "I" : "Q") + xyzFormat.format(cycle.incrementalDepth)),
conditional(cycle.incrementalDepthReduction > 0, "J" + xyzFormat.format(cycle.incrementalDepthReduction)),
conditional(cycle.incrementalDepthReduction > 0, "K" + xyzFormat.format(cycle.minimumIncrementalDepth)),
conditional(cycle.chipBreakDistance > 0, "P" + xyzFormat.format(cycle.chipBreakDistance)), // optional P value
feedOutput.format(F)
);
}
break;
case "deep-drilling":
if (dwell > 0) {
expandCyclePoint(x, y, z);
} else {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(83),
getCommonCycle(x, y, z, cycle.retract),
(((cycle.incrementalDepthReduction > 0) ? "I" : "Q") + xyzFormat.format(cycle.incrementalDepth)),
conditional(cycle.incrementalDepthReduction > 0, "J" + xyzFormat.format(cycle.incrementalDepthReduction)),
conditional(cycle.incrementalDepthReduction > 0, "K" + xyzFormat.format(cycle.minimumIncrementalDepth)),
feedOutput.format(F)
);
}
break;
case "tapping":
if (getProperty("format") == "fadal") {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? leftTappingCode : rightTappingCode),
getCommonCycle(x, y, z, cycle.retract),
"Q" + xyzFormat.format(tool.threadPitch),
"F" + feedFormat.format(tappingRPM)
);
feedOutput.reset();
} else {
if (!F) {
F = tool.getTappingFeedrate();
}
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? leftTappingCode : rightTappingCode),
getCommonCycle(x, y, z, cycle.retract),
conditional(getProperty("useRigidTapping"), sOutput.format(tappingRPM)),
tapFeedOutput.format(F)
);
feedOutput.reset();
}
break;
case "left-tapping":
if (getProperty("format") == "fadal") {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format(leftTappingCode),
getCommonCycle(x, y, z, cycle.retract),
"Q" + xyzFormat.format(tool.threadPitch),
"F" + feedFormat.format(tappingRPM)
);
feedOutput.reset();
} else {
if (!F) {
F = tool.getTappingFeedrate();
}
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format(leftTappingCode),
getCommonCycle(x, y, z, cycle.retract),
conditional(getProperty("useRigidTapping"), sOutput.format(tappingRPM)),
tapFeedOutput.format(F)
);
feedOutput.reset();
}
break;
case "right-tapping":
if (getProperty("format") == "fadal") {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format(rightTappingCode),
getCommonCycle(x, y, z, cycle.retract),
"Q" + xyzFormat.format(tool.threadPitch),
"F" + feedFormat.format(tappingRPM)
);
feedOutput.reset();
} else {
if (!F) {
F = tool.getTappingFeedrate();
}
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90),
gCycleModal.format(rightTappingCode),
getCommonCycle(x, y, z, cycle.retract),
conditional(getProperty("useRigidTapping"), sOutput.format(tappingRPM)),
tapFeedOutput.format(F)
);
feedOutput.reset();
}
break;
case "fine-boring":
// shift along Y+
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(76),
getCommonCycle(x, y, z, cycle.retract),
"P" + milliFormat.format(dwell),
"Q" + xyzFormat.format(cycle.shift),
feedOutput.format(F)
);
break;
case "back-boring":
expandCyclePoint(x, y, z);
break;
case "reaming":
if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) {
expandCyclePoint(x, y, z);
break;
}
if (dwell > 0) {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(89),
getCommonCycle(x, y, z, cycle.retract),
"P" + milliFormat.format(dwell),
feedOutput.format(F)
);
} else {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(85),
getCommonCycle(x, y, z, cycle.retract),
feedOutput.format(F)
);
}
break;
case "stop-boring":
if (dwell > 0) {
expandCyclePoint(x, y, z);
} else {
// no stop orientation
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(86),
getCommonCycle(x, y, z, cycle.retract),
feedOutput.format(F)
);
}
break;
case "manual-boring":
expandCyclePoint(x, y, z);
break;
case "boring":
if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) {
expandCyclePoint(x, y, z);
break;
}
if (dwell > 0) {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(89),
getCommonCycle(x, y, z, cycle.retract),
"P" + milliFormat.format(dwell),
feedOutput.format(F)
);
} else {
writeBlock(
gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(86),
getCommonCycle(x, y, z, cycle.retract),
feedOutput.format(F)
);
}
break;
default:
expandCyclePoint(x, y, z);
}
} else {
if (cycleExpanded) {
expandCyclePoint(x, y, z);
} else {
if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && !xyzFormat.areDifferent(y, yOutput.getCurrent())) {
xOutput.reset(); // at least one axis is required
}
if ((currentSection.getPolarMode && currentSection.getPolarMode() != POLAR_MODE_OFF) && currentSection.isMultiAxis()) {
var polarPosition = getPolarPosition(x, y, z);
setCurrentPositionAndDirection(polarPosition);
writeBlock(xOutput.format(polarPosition.first.x), yOutput.format(polarPosition.first.y),
aOutput.format(polarPosition.second.x), bOutput.format(polarPosition.second.y), cOutput.format(polarPosition.second.z));
} else {
writeBlock(xOutput.format(x), yOutput.format(y));
}
}
}
}
function onCycleEnd() {
if (!cycleExpanded) {
writeBlock(gCycleModal.format(80));
zOutput.reset();
}
}
function onRapid(_x, _y, _z) {
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
if (x || y || z) {
if (pendingRadiusCompensation >= 0) {
error(localize("Radius compensation mode cannot be changed at rapid traversal."));
}
if (((x ? 1 : 0) + (y ? 1 : 0) + (z ? 1 : 0)) > 1) {
// axes are not synchronized
writeBlock(gMotionModal.format(1), x, y, z, feedOutput.format(highFeedrate));
} else {
writeBlock(gMotionModal.format(0), x, y, z);
feedOutput.reset();
}
}
}
function onRapid5D(_x, _y, _z, _a, _b, _c) {
if (pendingRadiusCompensation >= 0) {
error(localize("Radius compensation mode cannot be changed at rapid traversal."));
return;
}
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
var a = aOutput.format(_a);
var b = bOutput.format(_b);
var c = cOutput.format(_c);
if (x || y || z || a || b || c) {
if (true) {
writeBlock(gMotionModal.format(1), x, y, z, a, b, c, getFeed(highFeedrate));
} else {
writeBlock(gMotionModal.format(0), x, y, z, a, b, c);
}
forceFeed();
}
}
/** Adjust final point to lie exactly on circle. */
function CircularData(_plane, _center, _end) {
// use Output variables, since last point could have been adjusted if previous move was circular
var start = new Vector(xOutput.getCurrent(), yOutput.getCurrent(), zOutput.getCurrent());
var saveStart = new Vector(start.x, start.y, start.z);
var center = new Vector(
xyzFormat.getResultingValue(_center.x),
xyzFormat.getResultingValue(_center.y),
xyzFormat.getResultingValue(_center.z)
);
var end = new Vector(_end.x, _end.y, _end.z);
switch (_plane) {
case PLANE_XY:
start.setZ(center.z);
end.setZ(center.z);
break;
case PLANE_ZX:
start.setY(center.y);
end.setY(center.y);
break;
case PLANE_YZ:
start.setX(center.x);
end.setX(center.x);
break;
default:
this.center = new Vector(_center.x, _center.y, _center.z);
this.start = new Vector(start.x, start.y, start.z);
this.end = new Vector(_end.x, _end.y, _end.z);
this.offset = Vector.diff(center, start);
this.radius = this.offset.length;
}
this.start = new Vector(
xyzFormat.getResultingValue(start.x),
xyzFormat.getResultingValue(start.y),
xyzFormat.getResultingValue(start.z)
);
var temp = Vector.diff(center, start);
this.offset = new Vector(
xyzFormat.getResultingValue(temp.x),
xyzFormat.getResultingValue(temp.y),
xyzFormat.getResultingValue(temp.z)
);
this.center = Vector.sum(this.start, this.offset);
this.radius = this.offset.length;
temp = Vector.diff(end, center).normalized;
this.end = new Vector(
xyzFormat.getResultingValue(this.center.x + temp.x * this.radius),
xyzFormat.getResultingValue(this.center.y + temp.y * this.radius),
xyzFormat.getResultingValue(this.center.z + temp.z * this.radius)
);
switch (_plane) {
case PLANE_XY:
this.start.setZ(saveStart.z);
this.end.setZ(_end.z);
this.offset.setZ(0);
break;
case PLANE_ZX:
this.start.setY(saveStart.y);
this.end.setY(_end.y);
this.offset.setY(0);
break;
case PLANE_YZ:
this.start.setX(saveStart.x);
this.end.setX(_end.x);
this.offset.setX(0);
break;
}
}
function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {
if (pendingRadiusCompensation >= 0) {
if (getCircularPlane() != PLANE_XY) {
error(localize("Radius compensation cannot be activated/deactivated for circular move in other plane than the XY-plane."));
return;
}
}
var circle = new CircularData(getCircularPlane(), new Vector(cx, cy, cz), new Vector(x, y, z));
var crc = [];
if (pendingRadiusCompensation >= 0) {
validate(getCircularPlane() == PLANE_XY, "Circular moves must be in the XY plane when using radius compensation.");
// ensure that we end at desired position when compensation is turned off
xOutput.reset();
yOutput.reset();
pendingRadiusCompensation = -1;
var d = getSetting("outputToolDiameterOffset", true) ? diameterOffsetFormat.format(tool.diameterOffset) : "";
switch (radiusCompensation) {
case RADIUS_COMPENSATION_LEFT:
crc = [gFormat.format(41), d];
break;
case RADIUS_COMPENSATION_RIGHT:
crc = [gFormat.format(42), d];
break;
default:
crc = [gFormat.format(40)];
}
}
if (isFullCircle()) {
if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs
linearize(tolerance);
return;
}
switch (getCircularPlane()) {
case PLANE_XY:
writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), crc,
iOutput.format(circle.offset.x, 0), jOutput.format(circle.offset.y, 0), feedOutput.format(feed));
break;
case PLANE_ZX:
writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
iOutput.format(circle.offset.x, 0), kOutput.format(circle.offset.z, 0), feedOutput.format(feed));
break;
case PLANE_YZ:
writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
jOutput.format(circle.offset.y, 0), kOutput.format(circle.offset.z, 0), feedOutput.format(feed));
break;
default:
linearize(tolerance);
}
} else if (!getProperty("useRadius")) {
switch (getCircularPlane()) {
case PLANE_XY:
writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), crc,
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
iOutput.format(circle.offset.x), jOutput.format(circle.offset.y), feedOutput.format(feed));
break;
case PLANE_ZX:
writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
iOutput.format(circle.offset.x), kOutput.format(circle.offset.z), feedOutput.format(feed));
break;
case PLANE_YZ:
writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
jOutput.format(circle.offset.y), kOutput.format(circle.offset.z), feedOutput.format(feed));
break;
default:
linearize(tolerance);
}
} else { // use radius mode
var r = getCircularRadius();
if (toDeg(getCircularSweep()) > (180 + 1e-9)) {
r = -r; // allow up to <360 deg arcs
}
switch (getCircularPlane()) {
case PLANE_XY:
writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), crc,
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
"R" + xyzFormat.format(circle.radius), feedOutput.format(feed));
break;
case PLANE_ZX:
writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
"R" + xyzFormat.format(circle.radius), feedOutput.format(feed));
break;
case PLANE_YZ:
writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3),
xOutput.format(circle.end.x), yOutput.format(circle.end.y), zOutput.format(circle.end.z),
"R" + xyzFormat.format(circle.radius), feedOutput.format(feed));
break;
default:
linearize(tolerance);
}
}
}
var mapCommand = {
COMMAND_END : 2,
COMMAND_STOP_SPINDLE : 5,
COMMAND_ORIENTATE_SPINDLE: 19
};
function onCommand(command) {
switch (command) {
case COMMAND_COOLANT_OFF:
setCoolant(COOLANT_OFF);
return;
case COMMAND_COOLANT_ON:
setCoolant(tool.coolant);
return;
case COMMAND_STOP:
writeBlock(mFormat.format(0));
forceSpindleSpeed = true;
forceCoolant = true;
return;
case COMMAND_OPTIONAL_STOP:
writeBlock(mFormat.format(1));
forceSpindleSpeed = true;
forceCoolant = true;
return;
case COMMAND_START_SPINDLE:
forceSpindleSpeed = false;
if (tapping && (spindleSpeed > maxTappingRPM)) {
warning(localize("Spindle speed exceeds maximum tapping speed of " + maxTappingRPM + " RPM"));
}
var sCode = spindleSpeed;
if (tapping && sCode > 750) {
sCode += 0.2; // use high gear for tapping
}
if (tapping && getProperty("useRigidTapping")) {
writeBlock(sOutput.format(sCode), mFormat.format(5));
} else {
writeBlock(sOutput.format(sCode), mFormat.format(tool.clockwise ? 3 : 4));
if (isFirstSection()) { // TAG: if RPM changes
var seconds = 3 * 60 / spindleSpeed; // wait for 3 revolutions
writeBlock(gFormat.format(4), "P" + milliFormat.format(seconds * 1000));
}
}
return;
case COMMAND_LOAD_TOOL:
writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6));
writeComment(tool.comment);
var preloadTool = getNextTool(tool.number != getFirstTool().number);
if (getProperty("preloadTool") && preloadTool) {
writeBlock("T" + toolFormat.format(preloadTool.number)); // preload next/first tool
}
return;
case COMMAND_LOCK_MULTI_AXIS:
if (machineConfiguration.isMultiAxisConfiguration()) {
// writeBlock(fourthAxisClamp.format(25)); // lock 4th axis
if (machineConfiguration.getNumberOfAxes() > 4) {
// writeBlock(fifthAxisClamp.format(35)); // lock 5th axis
}
}
return;
case COMMAND_UNLOCK_MULTI_AXIS:
if (machineConfiguration.isMultiAxisConfiguration()) {
// writeBlock(fourthAxisClamp.format(26)); // unlock 4th axis
if (machineConfiguration.getNumberOfAxes() > 4) {
// writeBlock(fifthAxisClamp.format(36)); // unlock 5th axis
}
}
return;
case COMMAND_BREAK_CONTROL:
return;
case COMMAND_TOOL_MEASURE:
return;
}
var stringId = getCommandStringId(command);
var mcode = mapCommand[stringId];
if (mcode != undefined) {
writeBlock(mFormat.format(mcode));
} else {
onUnsupportedCommand(command);
}
}
function onSectionEnd() {
writeBlock(gPlaneModal.format(17));
if (!isLastSection()) {
if (getNextSection().getTool().coolant != tool.coolant) {
setCoolant(COOLANT_OFF);
}
if (tool.breakControl && isToolChangeNeeded(getNextSection(), getProperty("toolAsName") ? "description" : "number")) {
onCommand(COMMAND_BREAK_CONTROL);
}
}
forceAny();
if (currentSection.isMultiAxis()) {
writeBlock(gFeedModeModal.format(94)); // inverse time feed off
}
}
function writeRetract() {
var retract = getRetractParameters.apply(this, arguments);
if (retract && retract.words.length > 0) {
if (typeof cancelWCSRotation == "function" && getSetting("retract.cancelRotationOnRetracting", false)) { // cancel rotation before retracting
cancelWCSRotation();
}
for (var i in retract.words) {
var words = retract.singleLine ? retract.words : retract.words[i];
switch (retract.method) {
case "machineHome":
// 90/91 mode is don't care
if (getProperty("format") == "fadal") {
if (retract.retractAxes[2]) { // Z axis retract
writeBlock(gAbsIncModal.format(90), gMotionModal.format(0), hFormat.format(0), words);
} else {
writeBlock(gAbsIncModal.format(90), eFormat.format(0), gMotionModal.format(0), words);
}
} else {
if (retract.retractAxes[2]) { // Z axis retract
writeBlock(gFormat.format(28), gAbsIncModal.format(91), words);
writeBlock(gAbsIncModal.format(90));
} else {
writeBlock(gAbsIncModal.format(90), gMotionModal.format(0));
writeBlock(gFormat.format(53), words);
}
}
break;
default:
error(subst(localize("Unsupported safe position method '%1'"), retract.method));
}
machineSimulation({
x : retract.singleLine || words.indexOf("X") != -1 ? retract.positions.x : undefined,
y : retract.singleLine || words.indexOf("Y") != -1 ? retract.positions.y : undefined,
z : retract.singleLine || words.indexOf("Z") != -1 ? retract.positions.z : undefined,
coordinates: MACHINE
});
if (retract.singleLine) {
break;
}
}
}
}
function onClose() {
optionalSection = false;
writeln("");
setCoolant(COOLANT_OFF);
writeRetract(Z);
setWorkPlane(new Vector(0, 0, 0)); // reset working plane
if (getSetting("retract.homeXY.onProgramEnd", false)) {
writeRetract(settings.retract.homeXY.onProgramEnd);
}
writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off
writeln("%");
}
// >>>>> INCLUDED FROM include_files/commonFunctions.cpi
// internal variables, do not change
var receivedMachineConfiguration;
var tcp = {isSupportedByControl:getSetting("supportsTCP", true), isSupportedByMachine:false, isSupportedByOperation:false};
var state = {
retractedX : false, // specifies that the machine has been retracted in X
retractedY : false, // specifies that the machine has been retracted in Y
retractedZ : false, // specifies that the machine has been retracted in Z
tcpIsActive : false, // specifies that TCP is currently active
twpIsActive : false, // specifies that TWP is currently active
lengthCompensationActive: !getSetting("outputToolLengthCompensation", true), // specifies that tool length compensation is active
mainState : true // specifies the current context of the state (true = main, false = optional)
};
var validateLengthCompensation = getSetting("outputToolLengthCompensation", true); // disable validation when outputToolLengthCompensation is disabled
var multiAxisFeedrate;
var sequenceNumber;
var optionalSection = false;
var currentWorkOffset;
var forceSpindleSpeed = false;
var operationNeedsSafeStart = false; // used to convert blocks to optional for safeStartAllOperations
function activateMachine() {
// disable unsupported rotary axes output
if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) {
aOutput.disable();
}
if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) {
bOutput.disable();
}
if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) {
cOutput.disable();
}
// setup usage of useTiltedWorkplane
settings.workPlaneMethod.useTiltedWorkplane = getProperty("useTiltedWorkplane") != undefined ? getProperty("useTiltedWorkplane") :
getSetting("workPlaneMethod.useTiltedWorkplane", false);
settings.workPlaneMethod.useABCPrepositioning = getSetting("workPlaneMethod.useABCPrepositioning", true);
if (!machineConfiguration.isMultiAxisConfiguration()) {
return; // don't need to modify any settings for 3-axis machines
}
// identify if any of the rotary axes has TCP enabled
var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()];
tcp.isSupportedByMachine = axes.some(function(axis) {return axis.isEnabled() && axis.isTCPEnabled();}); // true if TCP is enabled on any rotary axis
// save multi-axis feedrate settings from machine configuration
var mode = machineConfiguration.getMultiAxisFeedrateMode();
var type = mode == FEED_INVERSE_TIME ? machineConfiguration.getMultiAxisFeedrateInverseTimeUnits() :
(mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateDPMType() : DPM_STANDARD);
multiAxisFeedrate = {
mode : mode,
maximum : machineConfiguration.getMultiAxisFeedrateMaximum(),
type : type,
tolerance: mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateOutputTolerance() : 0,
bpwRatio : mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateBpwRatio() : 1
};
// setup of retract/reconfigure TAG: Only needed until post kernel supports these machine config settings
if (receivedMachineConfiguration && machineConfiguration.performRewinds()) {
safeRetractDistance = machineConfiguration.getSafeRetractDistance();
safePlungeFeed = machineConfiguration.getSafePlungeFeedrate();
safeRetractFeed = machineConfiguration.getSafeRetractFeedrate();
}
if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) {
safeRetractDistance = getProperty("safeRetractDistance");
}
if (revision >= 50294) {
activateAutoPolarMode({tolerance:tolerance / 2, optimizeType:OPTIMIZE_AXIS, expandCycles:getSetting("polarCycleExpandMode", EXPAND_ALL)});
}
if (machineConfiguration.isHeadConfiguration() && getSetting("workPlaneMethod.compensateToolLength", false)) {
for (var i = 0; i < getNumberOfSections(); ++i) {
var section = getSection(i);
if (section.isMultiAxis()) {
machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments
section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS);
}
}
} else {
optimizeMachineAngles2(OPTIMIZE_AXIS);
}
}
function getBodyLength(tool) {
for (var i = 0; i < getNumberOfSections(); ++i) {
var section = getSection(i);
if (tool.number == section.getTool().number) {
if (section.hasParameter("operation:tool_assemblyGaugeLength")) { // For Fusion
return section.getParameter("operation:tool_assemblyGaugeLength", tool.bodyLength + tool.holderLength);
} else { // Legacy products
return section.getParameter("operation:tool_overallLength", tool.bodyLength + tool.holderLength);
}
}
}
return tool.bodyLength + tool.holderLength;
}
function getFeed(f) {
if (getProperty("useG95")) {
return feedOutput.format(f / spindleSpeed); // use feed value
}
if (typeof activeMovements != "undefined" && activeMovements) {
var feedContext = activeMovements[movement];
if (feedContext != undefined) {
if (!feedFormat.areDifferent(feedContext.feed, f)) {
if (feedContext.id == currentFeedId) {
return ""; // nothing has changed
}
forceFeed();
currentFeedId = feedContext.id;
return settings.parametricFeeds.feedOutputVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id);
}
}
currentFeedId = undefined; // force parametric feed next time
}
return feedOutput.format(f); // use feed value
}
function validateCommonParameters() {
validateToolData();
for (var i = 0; i < getNumberOfSections(); ++i) {
var section = getSection(i);
if (getSection(0).workOffset == 0 && section.workOffset > 0) {
if (!(typeof wcsDefinitions != "undefined" && wcsDefinitions.useZeroOffset)) {
error(localize("Using multiple work offsets is not possible if the initial work offset is 0."));
}
}
if (section.isMultiAxis()) {
if (!section.isOptimizedForMachine() &&
(!getSetting("workPlaneMethod.useTiltedWorkplane", false) || !getSetting("supportsToolVectorOutput", false))) {
error(localize("This postprocessor requires a machine configuration for 5-axis simultaneous toolpath."));
}
if (machineConfiguration.getMultiAxisFeedrateMode() == FEED_INVERSE_TIME && !getSetting("supportsInverseTimeFeed", true)) {
error(localize("This postprocessor does not support inverse time feedrates."));
}
if (getSetting("supportsToolVectorOutput", false) && !tcp.isSupportedByControl) {
error(localize("Incompatible postprocessor settings detected." + EOL +
"Setting 'supportsToolVectorOutput' requires setting 'supportsTCP' to be enabled as well."));
}
}
}
if (!tcp.isSupportedByControl && tcp.isSupportedByMachine) {
error(localize("The machine configuration has TCP enabled which is not supported by this postprocessor."));
}
if (getProperty("safePositionMethod") == "clearanceHeight") {
var msg = "-Attention- Property 'Safe Retracts' is set to 'Clearance Height'." + EOL +
"Ensure the clearance height will clear the part and or fixtures." + EOL +
"Raise the Z-axis to a safe height before starting the program.";
warning(msg);
writeComment(msg);
}
}
function validateToolData() {
var _default = 99999;
var _maximumSpindleRPM = machineConfiguration.getMaximumSpindleSpeed() > 0 ? machineConfiguration.getMaximumSpindleSpeed() :
settings.maximumSpindleRPM == undefined ? _default : settings.maximumSpindleRPM;
var _maximumToolNumber = machineConfiguration.isReceived() && machineConfiguration.getNumberOfTools() > 0 ? machineConfiguration.getNumberOfTools() :
settings.maximumToolNumber == undefined ? _default : settings.maximumToolNumber;
var _maximumToolLengthOffset = settings.maximumToolLengthOffset == undefined ? _default : settings.maximumToolLengthOffset;
var _maximumToolDiameterOffset = settings.maximumToolDiameterOffset == undefined ? _default : settings.maximumToolDiameterOffset;
var header = ["Detected maximum values are out of range.", "Maximum values:"];
var warnings = {
toolNumber : {msg:"Tool number value exceeds the maximum value for tool: " + EOL, max:" Tool number: " + _maximumToolNumber, values:[]},
lengthOffset : {msg:"Tool length offset value exceeds the maximum value for tool: " + EOL, max:" Tool length offset: " + _maximumToolLengthOffset, values:[]},
diameterOffset: {msg:"Tool diameter offset value exceeds the maximum value for tool: " + EOL, max:" Tool diameter offset: " + _maximumToolDiameterOffset, values:[]},
spindleSpeed : {msg:"Spindle speed exceeds the maximum value for operation: " + EOL, max:" Spindle speed: " + _maximumSpindleRPM, values:[]}
};
var toolIds = [];
for (var i = 0; i < getNumberOfSections(); ++i) {
var section = getSection(i);
if (toolIds.indexOf(section.getTool().getToolId()) === -1) { // loops only through sections which have a different tool ID
var toolNumber = section.getTool().number;
var lengthOffset = section.getTool().lengthOffset;
var diameterOffset = section.getTool().diameterOffset;
var comment = section.getParameter("operation-comment", "");
if (toolNumber > _maximumToolNumber && !getProperty("toolAsName")) {
warnings.toolNumber.values.push(SP + toolNumber + EOL);
}
if (lengthOffset > _maximumToolLengthOffset) {
warnings.lengthOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Length offset: " + lengthOffset + ")" + EOL);
}
if (diameterOffset > _maximumToolDiameterOffset) {
warnings.diameterOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Diameter offset: " + diameterOffset + ")" + EOL);
}
toolIds.push(section.getTool().getToolId());
}
// loop through all sections regardless of tool id for idenitfying spindle speeds
// identify if movement ramp is used in current toolpath, use ramp spindle speed for comparisons
var ramp = section.getMovements() & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_ZIG_ZAG) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_HELIX));
var _sectionSpindleSpeed = Math.max(section.getTool().spindleRPM, ramp ? section.getTool().rampingSpindleRPM : 0, 0);
if (_sectionSpindleSpeed > _maximumSpindleRPM) {
warnings.spindleSpeed.values.push(SP + section.getParameter("operation-comment", "") + " (" + _sectionSpindleSpeed + " RPM" + ")" + EOL);
}
}
// sort lists by tool number
warnings.toolNumber.values.sort(function(a, b) {return a - b;});
warnings.lengthOffset.values.sort(function(a, b) {return a.localeCompare(b);});
warnings.diameterOffset.values.sort(function(a, b) {return a.localeCompare(b);});
var warningMessages = [];
for (var key in warnings) {
if (warnings[key].values != "") {
header.push(warnings[key].max); // add affected max values to the header
warningMessages.push(warnings[key].msg + warnings[key].values.join(""));
}
}
if (warningMessages.length != 0) {
warningMessages.unshift(header.join(EOL) + EOL);
warning(warningMessages.join(EOL));
}
}
function forceFeed() {
currentFeedId = undefined;
feedOutput.reset();
}
/** Force output of X, Y, and Z. */
function forceXYZ() {
xOutput.reset();
yOutput.reset();
zOutput.reset();
}
/** Force output of A, B, and C. */
function forceABC() {
aOutput.reset();
bOutput.reset();
cOutput.reset();
}
/** Force output of X, Y, Z, A, B, C, and F on next output. */
function forceAny() {
forceXYZ();
forceABC();
forceFeed();
}
/**
Writes the specified block.
*/
function writeBlock() {
var text = formatWords(arguments);
if (!text) {
return;
}
var prefix = getSetting("sequenceNumberPrefix", "N");
var suffix = getSetting("writeBlockSuffix", "");
if ((optionalSection || skipBlocks) && !getSetting("supportsOptionalBlocks", true)) {
error(localize("Optional blocks are not supported by this post."));
}
if (getProperty("showSequenceNumbers") == "true") {
if (sequenceNumber == undefined || sequenceNumber >= settings.maximumSequenceNumber) {
sequenceNumber = getProperty("sequenceNumberStart");
}
if (optionalSection || skipBlocks) {
writeWords2("/", prefix + sequenceNumber, text + suffix);
} else {
writeWords2(prefix + sequenceNumber, text + suffix);
}
sequenceNumber += getProperty("sequenceNumberIncrement");
} else {
if (optionalSection || skipBlocks) {
writeWords2("/", text + suffix);
} else {
writeWords(text + suffix);
}
}
}
validate(settings.comments, "Setting 'comments' is required but not defined.");
function formatComment(text) {
var prefix = settings.comments.prefix;
var suffix = settings.comments.suffix;
var _permittedCommentChars = settings.comments.permittedCommentChars == undefined ? "" : settings.comments.permittedCommentChars;
switch (settings.comments.outputFormat) {
case "upperCase":
text = text.toUpperCase();
_permittedCommentChars = _permittedCommentChars.toUpperCase();
break;
case "lowerCase":
text = text.toLowerCase();
_permittedCommentChars = _permittedCommentChars.toLowerCase();
break;
case "ignoreCase":
_permittedCommentChars = _permittedCommentChars.toUpperCase() + _permittedCommentChars.toLowerCase();
break;
default:
error(localize("Unsupported option specified for setting 'comments.outputFormat'."));
}
if (_permittedCommentChars != "") {
text = filterText(String(text), _permittedCommentChars);
}
text = String(text).substring(0, settings.comments.maximumLineLength - prefix.length - suffix.length);
return text != "" ? prefix + text + suffix : "";
}
/**
Output a comment.
*/
function writeComment(text) {
if (!text) {
return;
}
var comments = String(text).split(EOL);
for (comment in comments) {
var _comment = formatComment(comments[comment]);
if (_comment) {
if (getSetting("comments.showSequenceNumbers", false)) {
writeBlock(_comment);
} else {
writeln(_comment);
}
}
}
}
function onComment(text) {
writeComment(text);
}
/**
Writes the specified block - used for tool changes only.
*/
function writeToolBlock() {
var show = getProperty("showSequenceNumbers");
setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false");
writeBlock(arguments);
setProperty("showSequenceNumbers", show);
machineSimulation({/*x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE,*/ mode:TOOLCHANGE}); // move machineSimulation to a tool change position
}
var skipBlocks = false;
var initialState = JSON.parse(JSON.stringify(state)); // save initial state
var optionalState = JSON.parse(JSON.stringify(state));
var saveCurrentSectionId = undefined;
function writeStartBlocks(isRequired, code) {
var saveSkipBlocks = skipBlocks;
var saveMainState = state; // save main state
if (!isRequired) {
if (!getProperty("safeStartAllOperations", false)) {
return; // when safeStartAllOperations is disabled, dont output code and return
}
if (saveCurrentSectionId != getCurrentSectionId()) {
saveCurrentSectionId = getCurrentSectionId();
forceModals(); // force all modal variables when entering a new section
optionalState = Object.create(initialState); // reset optionalState to initialState when entering a new section
}
skipBlocks = true; // if values are not required, but safeStartAllOperations is enabled - write following blocks as optional
state = optionalState; // set state to optionalState if skipBlocks is true
state.mainState = false;
}
code(); // writes out the code which is passed to this function as an argument
state = saveMainState; // restore main state
skipBlocks = saveSkipBlocks; // restore skipBlocks value
}
var pendingRadiusCompensation = -1;
function onRadiusCompensation() {
pendingRadiusCompensation = radiusCompensation;
if (pendingRadiusCompensation >= 0 && !getSetting("supportsRadiusCompensation", true)) {
error(localize("Radius compensation mode is not supported."));
return;
}
}
function onPassThrough(text) {
var commands = String(text).split(",");
for (text in commands) {
writeBlock(commands[text]);
}
}
function forceModals() {
if (arguments.length == 0) { // reset all modal variables listed below
var modals = [
"gMotionModal",
"gPlaneModal",
"gAbsIncModal",
"gFeedModeModal",
"feedOutput"
];
if (operationNeedsSafeStart && (typeof currentSection != "undefined" && currentSection.isMultiAxis())) {
modals.push("fourthAxisClamp", "fifthAxisClamp", "sixthAxisClamp");
}
for (var i = 0; i < modals.length; ++i) {
if (typeof this[modals[i]] != "undefined") {
this[modals[i]].reset();
}
}
} else {
for (var i in arguments) {
arguments[i].reset(); // only reset the modal variable passed to this function
}
}
}
/** Helper function to be able to use a default value for settings which do not exist. */
function getSetting(setting, defaultValue) {
var result = defaultValue;
var keys = setting.split(".");
var obj = settings;
for (var i in keys) {
if (obj[keys[i]] != undefined) { // setting does exist
result = obj[keys[i]];
if (typeof [keys[i]] === "object") {
obj = obj[keys[i]];
continue;
}
} else { // setting does not exist, use default value
if (defaultValue != undefined) {
result = defaultValue;
} else {
error("Setting '" + keys[i] + "' has no default value and/or does not exist.");
return undefined;
}
}
}
return result;
}
function getForwardDirection(_section) {
var forward = undefined;
var _optimizeType = settings.workPlaneMethod && settings.workPlaneMethod.optimizeType;
if (_section.isMultiAxis()) {
forward = _section.workPlane.forward;
} else if (!getSetting("workPlaneMethod.useTiltedWorkplane", false) && machineConfiguration.isMultiAxisConfiguration()) {
if (_optimizeType == undefined) {
var saveRotation = getRotation();
getWorkPlaneMachineABC(_section, true);
forward = getRotation().forward;
setRotation(saveRotation); // reset rotation
} else {
var abc = getWorkPlaneMachineABC(_section, false);
var forceAdjustment = settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH;
forward = machineConfiguration.getOptimizedDirection(_section.workPlane.forward, abc, false, forceAdjustment);
}
} else {
forward = getRotation().forward;
}
return forward;
}
function getRetractParameters() {
var _arguments = typeof arguments[0] === "object" ? arguments[0].axes : arguments;
var singleLine = arguments[0].singleLine == undefined ? true : arguments[0].singleLine;
var words = []; // store all retracted axes in an array
var retractAxes = new Array(false, false, false);
var method = getProperty("safePositionMethod", "undefined");
if (method == "clearanceHeight") {
if (!is3D()) {
error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis."));
}
return undefined;
}
validate(settings.retract, "Setting 'retract' is required but not defined.");
validate(_arguments.length != 0, "No axis specified for getRetractParameters().");
for (i in _arguments) {
retractAxes[_arguments[i]] = true;
}
if ((retractAxes[0] || retractAxes[1]) && !state.retractedZ) { // retract Z first before moving to X/Y home
error(localize("Retracting in X/Y is not possible without being retracted in Z."));
return undefined;
}
// special conditions
if (retractAxes[0] || retractAxes[1]) {
method = getSetting("retract.methodXY", method);
}
if (retractAxes[2]) {
method = getSetting("retract.methodZ", method);
}
// define home positions
var useZeroValues = (settings.retract.useZeroValues && settings.retract.useZeroValues.indexOf(method) != -1);
var _xHome = machineConfiguration.hasHomePositionX() && !useZeroValues ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM);
var _yHome = machineConfiguration.hasHomePositionY() && !useZeroValues ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM);
var _zHome = machineConfiguration.getRetractPlane() != 0 && !useZeroValues ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM);
for (var i = 0; i < _arguments.length; ++i) {
switch (_arguments[i]) {
case X:
if (!state.retractedX) {
words.push("X" + xyzFormat.format(_xHome));
xOutput.reset();
state.retractedX = true;
}
break;
case Y:
if (!state.retractedY) {
words.push("Y" + xyzFormat.format(_yHome));
yOutput.reset();
state.retractedY = true;
}
break;
case Z:
if (!state.retractedZ) {
words.push("Z" + xyzFormat.format(_zHome));
zOutput.reset();
state.retractedZ = true;
}
break;
default:
error(localize("Unsupported axis specified for getRetractParameters()."));
return undefined;
}
}
return {
method : method,
retractAxes: retractAxes,
words : words,
positions : {
x: retractAxes[0] ? _xHome : undefined,
y: retractAxes[1] ? _yHome : undefined,
z: retractAxes[2] ? _zHome : undefined},
singleLine: singleLine};
}
/** Returns true when subprogram logic does exist into the post. */
function subprogramsAreSupported() {
return typeof subprogramState != "undefined";
}
// Start of machine simulation connection move support
var debugSimulation = false; // enable to output debug information for connection move support in the NC program
var TCPON = "TCP ON";
var TCPOFF = "TCP OFF";
var TWPON = "TWP ON";
var TWPOFF = "TWP OFF";
var TOOLCHANGE = "TOOL CHANGE";
var RETRACTTOOLAXIS = "RETRACT TOOLAXIS";
var WORK = "WORK CS";
var MACHINE = "MACHINE CS";
var MIN = "MIN";
var MAX = "MAX";
var WARNING_NON_RANGE = [0, 1, 2];
var isTwpOn;
var isTcpOn;
/**
* Helper function for connection moves in machine simulation.
* @param {Object} parameters An object containing the desired options for machine simulation.
* @note Available properties are:
* @param {Number} x X axis position, alternatively use MIN or MAX to move to the axis limit
* @param {Number} y Y axis position, alternatively use MIN or MAX to move to the axis limit
* @param {Number} z Z axis position, alternatively use MIN or MAX to move to the axis limit
* @param {Number} a A axis position (in radians)
* @param {Number} b B axis position (in radians)
* @param {Number} c C axis position (in radians)
* @param {Number} feed desired feedrate, automatically set to high/current feedrate if not specified
* @param {String} mode mode TCPON | TCPOFF | TWPON | TWPOFF | TOOLCHANGE | RETRACTTOOLAXIS
* @param {String} coordinates WORK | MACHINE - if undefined, work coordinates will be used by default
* @param {Number} eulerAngles the calculated Euler angles for the workplane
* @example
machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE});
machineSimulation({x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE, mode:TOOLCHANGE});
*/
function machineSimulation(parameters) {
if (revision < 50198 || skipBlocks) {
return; // return when post kernel revision is lower than 50198 or when skipBlocks is enabled
}
getAxisLimit = function(axis, limit) {
validate(limit == MIN || limit == MAX, subst(localize("Invalid argument \"%1\" passed to the machineSimulation function."), limit));
var range = axis.getRange();
if (range.isNonRange()) {
var axisLetters = ["X", "Y", "Z"];
var warningMessage = subst(localize("An attempt was made to move the \"%1\" axis to its MIN/MAX limits during machine simulation, but its range is set to \"unlimited\"." + EOL +
"A limited range must be set for the \"%1\" axis in the machine definition, or these motions will not be shown in machine simulation."), axisLetters[axis.getCoordinate()]);
warningOnce(warningMessage, WARNING_NON_RANGE[axis.getCoordinate()]);
return undefined;
}
return limit == MIN ? range.minimum : range.maximum;
};
var x = (isNaN(parameters.x) && parameters.x) ? getAxisLimit(machineConfiguration.getAxisX(), parameters.x) : parameters.x;
var y = (isNaN(parameters.y) && parameters.y) ? getAxisLimit(machineConfiguration.getAxisY(), parameters.y) : parameters.y;
var z = (isNaN(parameters.z) && parameters.z) ? getAxisLimit(machineConfiguration.getAxisZ(), parameters.z) : parameters.z;
var rotaryAxesErrorMessage = localize("Invalid argument for rotary axes passed to the machineSimulation function. Only numerical values are supported.");
var a = (isNaN(parameters.a) && parameters.a) ? error(rotaryAxesErrorMessage) : parameters.a;
var b = (isNaN(parameters.b) && parameters.b) ? error(rotaryAxesErrorMessage) : parameters.b;
var c = (isNaN(parameters.c) && parameters.c) ? error(rotaryAxesErrorMessage) : parameters.c;
var coordinates = parameters.coordinates;
var eulerAngles = parameters.eulerAngles;
var feed = parameters.feed;
if (feed === undefined && typeof gMotionModal !== "undefined") {
feed = gMotionModal.getCurrent() !== 0;
}
var mode = parameters.mode;
var performToolChange = mode == TOOLCHANGE;
if (mode !== undefined && ![TCPON, TCPOFF, TWPON, TWPOFF, TOOLCHANGE, RETRACTTOOLAXIS].includes(mode)) {
error(subst("Mode '%1' is not supported.", mode));
}
// mode takes precedence over TCP/TWP states
var enableTCP = isTcpOn;
var enableTWP = isTwpOn;
if (mode === TCPON || mode === TCPOFF) {
enableTCP = mode === TCPON;
} else if (mode === TWPON || mode === TWPOFF) {
enableTWP = mode === TWPON;
} else {
enableTCP = typeof state !== "undefined" && state.tcpIsActive;
enableTWP = typeof state !== "undefined" && state.twpIsActive;
}
var disableTCP = !enableTCP;
var disableTWP = !enableTWP;
if (disableTWP) {
simulation.setTWPModeOff();
isTwpOn = false;
}
if (disableTCP) {
simulation.setTCPModeOff();
isTcpOn = false;
}
if (enableTCP) {
simulation.setTCPModeOn();
isTcpOn = true;
}
if (enableTWP) {
if (settings.workPlaneMethod.eulerConvention == undefined) {
simulation.setTWPModeAlignToCurrentPose();
} else if (eulerAngles) {
simulation.setTWPModeByEulerAngles(settings.workPlaneMethod.eulerConvention, eulerAngles.x, eulerAngles.y, eulerAngles.z);
}
isTwpOn = true;
}
if (mode == RETRACTTOOLAXIS) {
simulation.retractAlongToolAxisToLimit();
}
if (debugSimulation) {
writeln(" DEBUG" + JSON.stringify(parameters));
writeln(" DEBUG" + JSON.stringify({isTwpOn:isTwpOn, isTcpOn:isTcpOn, feed:feed}));
}
if (x !== undefined || y !== undefined || z !== undefined || a !== undefined || b !== undefined || c !== undefined) {
if (x !== undefined) {simulation.setTargetX(x);}
if (y !== undefined) {simulation.setTargetY(y);}
if (z !== undefined) {simulation.setTargetZ(z);}
if (a !== undefined) {simulation.setTargetA(a);}
if (b !== undefined) {simulation.setTargetB(b);}
if (c !== undefined) {simulation.setTargetC(c);}
if (feed != undefined && feed) {
simulation.setMotionToLinear();
simulation.setFeedrate(typeof feed == "number" ? feed : feedOutput.getCurrent() == 0 ? highFeedrate : feedOutput.getCurrent());
} else {
simulation.setMotionToRapid();
}
if (coordinates != undefined && coordinates == MACHINE) {
simulation.moveToTargetInMachineCoords();
} else {
simulation.moveToTargetInWorkCoords();
}
}
if (performToolChange) {
simulation.performToolChangeCycle();
simulation.moveToTargetInMachineCoords();
}
}
// <<<<< INCLUDED FROM include_files/commonFunctions.cpi
// >>>>> INCLUDED FROM include_files/defineWorkPlane.cpi
validate(settings.workPlaneMethod, "Setting 'workPlaneMethod' is required but not defined.");
function defineWorkPlane(_section, _setWorkPlane) {
var abc = new Vector(0, 0, 0);
if (settings.workPlaneMethod.forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) {
if (isPolarModeActive()) {
abc = getCurrentDirection();
} else if (_section.isMultiAxis()) {
forceWorkPlane();
cancelTransformation();
abc = _section.isOptimizedForMachine() ? _section.getInitialToolAxisABC() : _section.getGlobalInitialToolAxis();
} else if (settings.workPlaneMethod.useTiltedWorkplane && settings.workPlaneMethod.eulerConvention != undefined) {
if (settings.workPlaneMethod.eulerCalculationMethod == "machine" && machineConfiguration.isMultiAxisConfiguration()) {
abc = machineConfiguration.getOrientation(getWorkPlaneMachineABC(_section, true)).getEuler2(settings.workPlaneMethod.eulerConvention);
} else {
abc = _section.workPlane.getEuler2(settings.workPlaneMethod.eulerConvention);
}
} else {
abc = getWorkPlaneMachineABC(_section, true);
}
if (_setWorkPlane) {
if (_section.isMultiAxis() || isPolarModeActive()) { // 4-5x simultaneous operations
cancelWorkPlane();
if (_section.isOptimizedForMachine()) {
positionABC(abc, true);
} else {
setCurrentDirection(abc);
}
} else { // 3x and/or 3+2x operations
setWorkPlane(abc);
}
}
} else {
var remaining = _section.workPlane;
if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) {
error(localize("Tool orientation is not supported."));
return abc;
}
setRotation(remaining);
}
tcp.isSupportedByOperation = isTCPSupportedByOperation(_section);
return abc;
}
function isTCPSupportedByOperation(_section) {
var _tcp = _section.getOptimizedTCPMode() == OPTIMIZE_NONE;
if (!_section.isMultiAxis() && (settings.workPlaneMethod.useTiltedWorkplane ||
(machineConfiguration.isMultiAxisConfiguration() && settings.workPlaneMethod.optimizeType != undefined ?
getWorkPlaneMachineABC(_section, false).isZero() : isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(_section))) ||
settings.workPlaneMethod.optimizeType == OPTIMIZE_HEADS ||
settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES ||
settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH)) {
_tcp = false;
}
return _tcp;
}
// <<<<< INCLUDED FROM include_files/defineWorkPlane.cpi
// >>>>> INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi
validate(settings.machineAngles, "Setting 'machineAngles' is required but not defined.");
function getWorkPlaneMachineABC(_section, rotate) {
var currentABC = isFirstSection() ? new Vector(0, 0, 0) : getCurrentABC();
var abc = _section.getABCByPreference(machineConfiguration, _section.workPlane, currentABC, settings.machineAngles.controllingAxis, settings.machineAngles.type, settings.machineAngles.options);
if (!isSameDirection(machineConfiguration.getDirection(abc), _section.workPlane.forward)) {
error(localize("Orientation not supported."));
}
if (rotate) {
if (settings.workPlaneMethod.optimizeType == undefined || settings.workPlaneMethod.useTiltedWorkplane) { // legacy
var useTCP = false;
var R = machineConfiguration.getRemainingOrientation(abc, _section.workPlane);
setRotation(useTCP ? _section.workPlane : R);
} else {
if (!_section.isOptimizedForMachine()) {
machineConfiguration.setToolLength(getSetting("workPlaneMethod.compensateToolLength", false) ? getBodyLength(_section.getTool()) : 0); // define the tool length for head adjustments
_section.optimize3DPositionsByMachine(machineConfiguration, abc, settings.workPlaneMethod.optimizeType);
}
}
}
return abc;
}
// <<<<< INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi
// >>>>> INCLUDED FROM include_files/positionABC.cpi
function positionABC(abc, force) {
if (!machineConfiguration.isMultiAxisConfiguration()) {
error("Function 'positionABC' can only be used with multi-axis machine configurations.");
}
if (typeof unwindABC == "function") {
unwindABC(abc);
}
if (force) {
forceABC();
}
var a = aOutput.format(abc.x);
var b = bOutput.format(abc.y);
var c = cOutput.format(abc.z);
if (a || b || c) {
writeRetract(Z);
if (getSetting("retract.homeXY.onIndexing", false)) {
writeRetract(settings.retract.homeXY.onIndexing);
}
onCommand(COMMAND_UNLOCK_MULTI_AXIS);
gMotionModal.reset();
writeBlock(gMotionModal.format(0), a, b, c);
setCurrentABC(abc); // required for machine simulation
machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE});
}
}
// <<<<< INCLUDED FROM include_files/positionABC.cpi
// >>>>> INCLUDED FROM include_files/writeToolCall.cpi
function writeToolCall(tool, insertToolCall) {
if (!isFirstSection()) {
writeStartBlocks(!getProperty("safeStartAllOperations") && insertToolCall, function () {
writeRetract(Z); // write optional Z retract before tool change if safeStartAllOperations is enabled
});
}
writeStartBlocks(insertToolCall, function () {
writeRetract(Z);
if (getSetting("retract.homeXY.onToolChange", false)) {
writeRetract(settings.retract.homeXY.onToolChange);
}
if (!isFirstSection() && insertToolCall) {
if (typeof forceWorkPlane == "function") {
forceWorkPlane();
}
onCommand(COMMAND_COOLANT_OFF); // turn off coolant on tool change
if (typeof disableLengthCompensation == "function") {
disableLengthCompensation(false);
}
}
if (tool.manualToolChange) {
onCommand(COMMAND_STOP);
writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number));
} else {
if (!isFirstSection() && getProperty("optionalStop") && insertToolCall) {
onCommand(COMMAND_OPTIONAL_STOP);
}
onCommand(COMMAND_LOAD_TOOL);
}
});
if (typeof forceModals == "function" && (insertToolCall || getProperty("safeStartAllOperations"))) {
forceModals();
}
}
// <<<<< INCLUDED FROM include_files/writeToolCall.cpi
// >>>>> INCLUDED FROM include_files/startSpindle.cpi
function startSpindle(tool, insertToolCall) {
if (tool.type != TOOL_PROBE) {
var spindleSpeedIsRequired = insertToolCall || forceSpindleSpeed || isFirstSection() ||
rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent()) ||
(tool.clockwise != getPreviousSection().getTool().clockwise);
writeStartBlocks(spindleSpeedIsRequired, function () {
if (spindleSpeedIsRequired || operationNeedsSafeStart) {
onCommand(COMMAND_START_SPINDLE);
}
});
}
}
// <<<<< INCLUDED FROM include_files/startSpindle.cpi
// >>>>> INCLUDED FROM include_files/coolant.cpi
var currentCoolantMode = COOLANT_OFF;
var coolantOff = undefined;
var isOptionalCoolant = false;
var forceCoolant = false;
function setCoolant(coolant) {
var coolantCodes = getCoolantCodes(coolant);
if (Array.isArray(coolantCodes)) {
writeStartBlocks(!isOptionalCoolant, function () {
if (settings.coolant.singleLineCoolant) {
writeBlock(coolantCodes.join(getWordSeparator()));
} else {
for (var c in coolantCodes) {
writeBlock(coolantCodes[c]);
}
}
});
return undefined;
}
return coolantCodes;
}
function getCoolantCodes(coolant, format) {
if (!getProperty("useCoolant", true)) {
return undefined; // coolant output is disabled by property if it exists
}
isOptionalCoolant = false;
if (typeof operationNeedsSafeStart == "undefined") {
operationNeedsSafeStart = false;
}
var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line
var coolants = settings.coolant.coolants;
if (!coolants) {
error(localize("Coolants have not been defined."));
}
if (tool.type && tool.type == TOOL_PROBE) { // avoid coolant output for probing
coolant = COOLANT_OFF;
}
if (coolant == currentCoolantMode) {
if (operationNeedsSafeStart && coolant != COOLANT_OFF) {
isOptionalCoolant = true;
} else if (!forceCoolant || coolant == COOLANT_OFF) {
return undefined; // coolant is already active
}
}
if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant && !isOptionalCoolant) {
if (Array.isArray(coolantOff)) {
for (var i in coolantOff) {
multipleCoolantBlocks.push(coolantOff[i]);
}
} else {
multipleCoolantBlocks.push(coolantOff);
}
}
forceCoolant = false;
var m;
var coolantCodes = {};
for (var c in coolants) { // find required coolant codes into the coolants array
if (coolants[c].id == coolant) {
coolantCodes.on = coolants[c].on;
if (coolants[c].off != undefined) {
coolantCodes.off = coolants[c].off;
break;
} else {
for (var i in coolants) {
if (coolants[i].id == COOLANT_OFF) {
coolantCodes.off = coolants[i].off;
break;
}
}
}
}
}
if (coolant == COOLANT_OFF) {
m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified
} else {
coolantOff = coolantCodes.off;
m = coolantCodes.on;
}
if (!m) {
onUnsupportedCoolant(coolant);
m = 9;
} else {
if (Array.isArray(m)) {
for (var i in m) {
multipleCoolantBlocks.push(m[i]);
}
} else {
multipleCoolantBlocks.push(m);
}
currentCoolantMode = coolant;
for (var i in multipleCoolantBlocks) {
if (typeof multipleCoolantBlocks[i] == "number") {
multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]);
}
}
if (format == undefined || format) {
return multipleCoolantBlocks; // return the single formatted coolant value
} else {
return m; // return unformatted coolant value
}
}
return undefined;
}
// <<<<< INCLUDED FROM include_files/coolant.cpi
// >>>>> INCLUDED FROM include_files/writeProgramHeader.cpi
properties.writeMachine = {
title : "Write machine",
description: "Output the machine settings in the header of the program.",
group : "formats",
type : "boolean",
value : true,
scope : "post"
};
properties.writeTools = {
title : "Write tool list",
description: "Output a tool list in the header of the program.",
group : "formats",
type : "boolean",
value : true,
scope : "post"
};
function writeProgramHeader() {
// dump machine configuration
var vendor = machineConfiguration.getVendor();
var model = machineConfiguration.getModel();
var mDescription = machineConfiguration.getDescription();
if (getProperty("writeMachine") && (vendor || model || mDescription)) {
writeComment(localize("Machine"));
if (vendor) {
writeComment(" " + localize("vendor") + ": " + vendor);
}
if (model) {
writeComment(" " + localize("model") + ": " + model);
}
if (mDescription) {
writeComment(" " + localize("description") + ": " + mDescription);
}
}
// dump tool information
if (getProperty("writeTools")) {
if (false) { // set to true to use the post kernel version of the tool list
writeToolTable(TOOL_NUMBER_COL);
} else {
var zRanges = {};
if (is3D()) {
var numberOfSections = getNumberOfSections();
for (var i = 0; i < numberOfSections; ++i) {
var section = getSection(i);
var zRange = section.getGlobalZRange();
var tool = section.getTool();
if (zRanges[tool.number]) {
zRanges[tool.number].expandToRange(zRange);
} else {
zRanges[tool.number] = zRange;
}
}
}
var tools = getToolTable();
if (tools.getNumberOfTools() > 0) {
for (var i = 0; i < tools.getNumberOfTools(); ++i) {
var tool = tools.getTool(i);
var comment = (getProperty("toolAsName") ? "\"" + tool.description.toUpperCase() + "\"" : "T" + toolFormat.format(tool.number)) + " " +
"D=" + xyzFormat.format(tool.diameter) + " " +
localize("CR") + "=" + xyzFormat.format(tool.cornerRadius);
if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) {
comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg");
}
if (zRanges[tool.number]) {
comment += " - " + localize("ZMIN") + "=" + xyzFormat.format(zRanges[tool.number].getMinimum());
}
comment += " - " + getToolTypeName(tool.type);
writeComment(comment);
}
}
}
}
}
// <<<<< INCLUDED FROM include_files/writeProgramHeader.cpi
// >>>>> INCLUDED FROM include_files/onLinear_fanuc.cpi
function onLinear(_x, _y, _z, feed) {
if (pendingRadiusCompensation >= 0) {
xOutput.reset();
yOutput.reset();
}
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
var f = getFeed(feed);
if (x || y || z) {
if (pendingRadiusCompensation >= 0) {
pendingRadiusCompensation = -1;
var d = getSetting("outputToolDiameterOffset", true) ? diameterOffsetFormat.format(tool.diameterOffset) : "";
writeBlock(gPlaneModal.format(17));
switch (radiusCompensation) {
case RADIUS_COMPENSATION_LEFT:
writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, d, f);
break;
case RADIUS_COMPENSATION_RIGHT:
writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, d, f);
break;
default:
writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f);
}
} else {
writeBlock(gMotionModal.format(1), x, y, z, f);
}
} else if (f) {
if (getNextRecord().isMotion()) { // try not to output feed without motion
forceFeed(); // force feed on next line
} else {
writeBlock(gMotionModal.format(1), f);
}
}
}
// <<<<< INCLUDED FROM include_files/onLinear_fanuc.cpi
// >>>>> INCLUDED FROM include_files/onLinear5D_fanuc.cpi
function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) {
if (pendingRadiusCompensation >= 0) {
error(localize("Radius compensation cannot be activated/deactivated for 5-axis move."));
return;
}
if (!currentSection.isOptimizedForMachine()) {
forceXYZ();
}
var x = xOutput.format(_x);
var y = yOutput.format(_y);
var z = zOutput.format(_z);
var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a);
var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b);
var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c);
if (feedMode == FEED_INVERSE_TIME) {
forceFeed();
}
var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : getFeed(feed);
var fMode = feedMode == FEED_INVERSE_TIME ? 93 : getProperty("useG95") ? 95 : 94;
if (x || y || z || a || b || c) {
writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), x, y, z, a, b, c, f);
} else if (f) {
if (getNextRecord().isMotion()) { // try not to output feed without motion
forceFeed(); // force feed on next line
} else {
writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f);
}
}
}
// <<<<< INCLUDED FROM include_files/onLinear5D_fanuc.cpi
// >>>>> INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi
var gRotationModal = createOutputVariable({current : 69,
onchange: function () {
state.twpIsActive = gRotationModal.getCurrent() != 69;
if (typeof probeVariables != "undefined") {
probeVariables.outputRotationCodes = probeVariables.probeAngleMethod == "G68";
}
machineSimulation({}); // update machine simulation TWP state
}}, gFormat);
var currentWorkPlaneABC = undefined;
function forceWorkPlane() {
currentWorkPlaneABC = undefined;
}
function cancelWCSRotation() {
if (typeof gRotationModal != "undefined" && gRotationModal.getCurrent() == 68) {
cancelWorkPlane(true);
}
}
function cancelWorkPlane(force) {
if (typeof gRotationModal != "undefined") {
if (force) {
gRotationModal.reset();
}
var command = gRotationModal.format(69);
if (command) {
writeBlock(command); // cancel frame
forceWorkPlane();
}
}
}
function setWorkPlane(abc) {
if (!settings.workPlaneMethod.forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) {
return; // ignore
}
var workplaneIsRequired = (currentWorkPlaneABC == undefined) ||
abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) ||
abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) ||
abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z);
writeStartBlocks(workplaneIsRequired, function () {
writeRetract(Z);
if (getSetting("retract.homeXY.onIndexing", false)) {
writeRetract(settings.retract.homeXY.onIndexing);
}
if ((state.lengthCompensationActive || state.tcpIsActive) && typeof disableLengthCompensation == "function") {
disableLengthCompensation(); // cancel tool lenght compensation / TCP prior to output TWP
}
if (settings.workPlaneMethod.useTiltedWorkplane) {
onCommand(COMMAND_UNLOCK_MULTI_AXIS);
cancelWorkPlane();
if (machineConfiguration.isMultiAxisConfiguration()) {
var machineABC = abc.isNonZero() ? (currentSection.isMultiAxis() ? getCurrentDirection() : getWorkPlaneMachineABC(currentSection, false)) : abc;
if (settings.workPlaneMethod.useABCPrepositioning || machineABC.isZero()) {
positionABC(machineABC);
} else {
setCurrentABC(machineABC);
}
}
if (abc.isNonZero() || !machineConfiguration.isMultiAxisConfiguration()) {
gRotationModal.reset();
writeBlock(
gRotationModal.format(68.2), "X" + xyzFormat.format(currentSection.workOrigin.x), "Y" + xyzFormat.format(currentSection.workOrigin.y), "Z" + xyzFormat.format(currentSection.workOrigin.z),
"I" + abcFormat.format(abc.x), "J" + abcFormat.format(abc.y), "K" + abcFormat.format(abc.z)
); // set frame
writeBlock(gFormat.format(53.1)); // turn machine
machineSimulation({a:getCurrentABC().x, b:getCurrentABC().y, c:getCurrentABC().z, coordinates:MACHINE, eulerAngles:abc});
}
} else {
positionABC(abc, true);
}
if (!currentSection.isMultiAxis()) {
onCommand(COMMAND_LOCK_MULTI_AXIS);
}
currentWorkPlaneABC = abc;
});
}
// <<<<< INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi
// >>>>> INCLUDED FROM include_files/getProgramNumber_fanuc.cpi
function getProgramNumber() {
if (typeof oFormat != "undefined" && getProperty("o8")) {
oFormat.setMinDigitsLeft(8);
}
var minimumProgramNumber = getSetting("programNumber.min", 1);
var maximumProgramNumber = getSetting("programNumber.max", getProperty("o8") ? 99999999 : 9999);
var reservedProgramNumbers = getSetting("programNumber.reserved", [8000, 9999]);
if (programName) {
var _programNumber;
try {
_programNumber = getAsInt(programName);
} catch (e) {
error(localize("Program name must be a number."));
}
if (!((_programNumber >= minimumProgramNumber) && (_programNumber <= maximumProgramNumber))) {
error(subst(localize("Program number '%1' is out of range. Please enter a program number between '%2' and '%3'."), _programNumber, minimumProgramNumber, maximumProgramNumber));
}
if ((_programNumber >= reservedProgramNumbers[0]) && (_programNumber <= reservedProgramNumbers[1])) {
warning(subst(localize("Program number '%1' is potentially reserved by the machine tool builder. Reserved range is '%2' to '%3'."), _programNumber, reservedProgramNumbers[0], reservedProgramNumbers[1]));
}
} else {
error(localize("Program name has not been specified."));
}
return _programNumber;
}
// <<<<< INCLUDED FROM include_files/getProgramNumber_fanuc.cpi