/** Copyright (C) 2012-2024 by Autodesk, Inc. All rights reserved. Felder post processor configuration. $Revision:$ $Date:$ FORKID {B8E29875-2F66-48C2-8304-2D098C415DD5} */ description = "Felder F4 Integrate"; vendor = "Felder"; vendorUrl = "https://www.felder-group.com"; legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45892; longDescription = "Generic post for Felder F4 Integrate machines. Define a Slot Mill cutter to use as a Saw Blade. " + "The Manual NC Action commands M21 (Nesting geometry) and M22 (Nest left over areas) are supported."; extension = "f4g"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING; tolerance = spatial(0.002, MM); highFeedrate = (unit == IN) ? 200 : 5000; minimumChordLength = spatial(0.01, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(180); allowHelicalMoves = true; allowedCircularPlanes = 1 << PLANE_XY; // allow XY plane only // user-defined properties properties = { xRapidRate: { title : "X-axis rapid rate", description: "The rapid rate for the X-axis in Meters per Minute.", group : "preferences", type : "number", value : 60, scope : "post" }, yRapidRate: { title : "Y-axis rapid rate", description: "The rapid rate for the Y-axis in Meters per Minute.", group : "preferences", type : "number", value : 75, scope : "post" }, zRapidRate: { title : "Z-axis rapid rate", description: "The rapid rate for the Z-axis in Meters per Minute.", group : "preferences", type : "number", value : 23, scope : "post" }, safeRetractDistance: { title : "Safe retract distance", description: "The safe Z value used when rewinding rotary axes.", group : "multiAxis", type : "number", value : 0, scope : "post" }, ignoreSawLeadIn: { title : "Ignore saw lead-in/out moves", description: "Enable to ignore lead-in/out moves on saw cuts so simulation is consistent with machine movement. If disabled, the lead-in/out moves must be tangent to the saw cut.", group : "preferences", type : "boolean", value : true, scope : "post" }, shiftOrigin: { title : "Shift origin to lower left corner", description: "Enable to shift the WCS origin to the lower left hand corner of the part.", group : "preferences", type : "boolean", value : true, scope : "post" }, workingArea: { title : "Working area", description: "Define the used working area on machine.", group : "preferences", type : "string", value : "AD1", scope : "post" }, outfit: { title : "Tool outfit", description: "Set the used tool outfit for machining.", group : "preferences", type : "string", value : "Default", scope : "post" }, isoOnly: { title : "Output NC code in ISO format", description: "Enable to output all operations in ISO format using, disable to output only multi-axis operations in ISO mode.", group : "formats", type : "boolean", value : false, scope : "post" }, isoCircular: { title : "Enable circular output in ISO format", description: "Enable to allow circular interpolation in ISO mode, disable to linearize circular moves.", group : "formats", type : "boolean", value : false, scope : "post" }, useFilesForSubprograms: { title : "Create external ISO subprograms", description: "Create subprogram files for ISO operations.", group : "formats", type : "boolean", value : true, scope : "post" }, subprogramPath: { title : "Output path for subprogram files", description: "Specifies the desired output path for subprogram files. 'Default' is the current output folder.", group : "formats", type : "string", value : "Default", scope : "post" }, minSubfileLength: { title : "Minimum line count of ISO subprogram file", description: "Enter the minimum line count to consider for creating a tool path ISO subprogram file. Setting the value to 0 will create an external subprogram for all ISO operations.", group : "formats", type : "number", value : 10000, scope : "post" }, maxFileLength: { title : "Maximum line count for a single file", description: "Enter the maximum line count allowed for a single file. NC files longer than this setting will be output into multiple files. Setting the value to 0 will create a single file.", group : "formats", type : "number", value : 0, range : [0, 99999999], scope : "post" } }; var numberOfToolSlots = 9999; var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-"; var gFormat = createFormat({prefix:"G", decimals:0}); var mFormat = createFormat({prefix:"M", decimals:0}); var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4)}); var xFormat = createFormat({decimals:(unit == MM ? 3 : 4)}); var abcFormat = createFormat({decimals:3, scale:DEG}); var feedFormat = createFormat({decimals:(unit == MM ? 4 : 4)}); var rpmFormat = createFormat({decimals:0}); var secFormat = createFormat({decimals:3, type:FORMAT_REAL}); // seconds - range 0.001-1000 var taperFormat = createFormat({decimals:1, scale:DEG}); var toolFormat = createFormat({decimals:0}); var feedFormat = createFormat({decimals:(unit == MM ? 0 : 0)}); var subFormat = createFormat({decimals:2, minDigitsLeft:2}); var xOutput = createOutputVariable({prefix:"X"}, xFormat); var yOutput = createOutputVariable({prefix:"Y"}, xyzFormat); var zOutput = createOutputVariable({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 sOutput = createOutputVariable({prefix:"S", control:CONTROL_FORCE}, rpmFormat); var tOutput = createOutputVariable({prefix:" T", control:CONTROL_FORCE}, toolFormat); // circular output var iOutput = createOutputVariable({prefix:"I", control:CONTROL_FORCE}, xyzFormat); var jOutput = createOutputVariable({prefix:"J", control:CONTROL_FORCE}, xyzFormat); var kOutput = createOutputVariable({prefix:"K"}, xyzFormat); var gMotionModal = createOutputVariable({control:CONTROL_FORCE}, 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({control:CONTROL_FORCE}, gFormat); // modal group 9 // G81, ... var gRetractModal = createOutputVariable({}, gFormat); // modal group 10 // G98-99 var WARNING_WORK_OFFSET = 0; // collected state var currentWorkOffset; var subProgramNumber = 0; var strictFace = false; var invertX = false; var isWorkingPlane = false; var virtualPlaneCounter = 0; var useIso; var nestingCode = ""; var sawIsActive = false; var sideZero = false; var sideOne = false; var sideThree = false; var sideFour = false; var sideFive = false; var sideSix = false; var previousFaceName = ""; /** Writes the specified block. */ function writeBlock() { bufferedLinesLength++; writeWords(arguments); } function formatComment(text) { return "# " + filterText(String(text).toUpperCase(), permittedCommentChars).replace(/[()]/g, ""); } function formatVirtualPlaneName(text, counter) { return " T\"" + filterText(String(text).toUpperCase(), permittedCommentChars).replace(/ /g, "_") + "_" + counter + "\""; } /** Output a comment. */ function writeComment(text) { writeln(formatComment(text)); } function onOpen() { if (true) { // note: setup your machine here var aAxis = createAxis({coordinate:0, table:false, axis:[-0.766044, 0, 0.642788], range:[-181, 181], preference:1}); var cAxis = createAxis({coordinate:2, table:false, axis:[0, 0, -1], range:[-270, 270], preference:1}); machineConfiguration = new MachineConfiguration(aAxis, cAxis); setMachineConfiguration(machineConfiguration); optimizeMachineAngles2(0); // TCP mode } if (!machineConfiguration.isMachineCoordinate(0)) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1)) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2)) { cOutput.disable(); } writeHeader(); fileLinesLength = 0; bufferedLinesLength = 0; } function writeHeader() { writeln("[header]"); // all programs must start like this workpiece = getWorkpiece(); var xStock = (workpiece.upper.x - workpiece.lower.x); var yStock = (workpiece.upper.y - workpiece.lower.y); var zStock = (workpiece.upper.z - workpiece.lower.z); writeBlock("l=" + xyzFormat.format(xStock)); writeBlock("h=" + xyzFormat.format(yStock)); writeBlock("t=" + xyzFormat.format(zStock)); switch (unit) { case IN: writeBlock("isinch=1"); break; case MM: writeBlock("isinch=0"); break; } writeBlock("area=" + getProperty("workingArea")); writeBlock("offsetx=0"); writeBlock("offsety=0"); writeBlock("offsetz=0"); writeBlock("rawxm=0"); writeBlock("rawym=0"); writeBlock("rawzm=0"); writeBlock("rawxp=0"); writeBlock("rawyp=0"); writeBlock("rawzp=0"); writeBlock("outfit='" + getProperty("outfit") + "'"); if (programName) { // writeBlock("comment='" + programName + "'"); } if (programComment) { writeBlock("comment='" + programComment + "'"); } writeBlock("[/header]"); } function onComment(message) { writeComment(message); } /** 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(); feedOutput.reset(); } // calculate output feed rate in Meters per Minute, ISO feeds are in MM per Minute function getFeed(feed) { // if (unit == IN) { // return (feed * 25.4) / (currentSection.isMultiAxis() ? 1 : 1000); // } else { // return feed / (currentSection.isMultiAxis() ? 1 : 1000); // } return feed; } // calculate output rapid rate in Meters per Minute function getRapidRate(_x, _y, _z) { var xyz = getCurrentPosition(); var x = xFormat.areDifferent(_x, xyz.x); var y = xyzFormat.areDifferent(_y, xyz.y); var z = xyzFormat.areDifferent(_z, xyz.z); var feed = 100000; feed = x ? ((getProperty("xRapidRate") < feed) ? getProperty("xRapidRate") : feed) : feed; feed = y ? ((getProperty("yRapidRate") < feed) ? getProperty("yRapidRate") : feed) : feed; feed = z ? ((getProperty("zRapidRate") < feed) ? getProperty("zRapidRate") : feed) : feed; feed = (feed == 100000) ? getProperty("zRapidRate") : feed; return feed; } function getWorkPlaneMachineABC(workPlane, rotate) { var W = workPlane; // map to global frame // Workplane angles are between 0-360 : Beta=B, Alpha=C var abc = W.getTurnAndTilt(Y, Z); if (abc.y < 0) { abc.setY(-abc.y); abc.setZ(abc.z + Math.PI); } if (abc.z < 0) { abc.setZ(abc.z + (Math.PI * 2)); } if (abcFormat.format(abc.z) > 270) { abc.setZ(abc.z - (Math.PI * 2)); } // TCP mode is supported if (rotate) { var tcp = true; if (tcp) { setRotation(W); // TCP mode } else { var O = machineConfiguration.getOrientation(abc); var R = machineConfiguration.getRemainingOrientation(abc, W); setRotation(R); } } return abc; } function getSpindleSpeed(speed) { return speed <= 1 ? 0 : speed; } var currentFaceNumber = 0; var currentFaceName = "TOP"; function calculateWorkpiece(section) { var workpiece = getWorkpiece(); // don't shift origin, expand stock to include workplane origin if (!getProperty("shiftOrigin")) { var xStock = (workpiece.upper.x - workpiece.lower.x); var yStock = (workpiece.upper.y - workpiece.lower.y); var expansion = new Vector(section.workOrigin.x, section.workOrigin.y, workpiece.lower.z); workpiece.expandTo(expansion); var upperZ = workpiece.lower.z; workpiece = new BoundingBox( new Vector(0, 0, -workpiece.upper.z), new Vector(workpiece.upper.x, workpiece.upper.y, upperZ) ); // make sure stock does not shrink if workplane origin is positive of the stock origin var length = (workpiece.upper.x - workpiece.lower.x); var width = (workpiece.upper.y - workpiece.lower.y); if (length < xStock || width < yStock) { workpiece = new BoundingBox( new Vector(workpiece.lower.x, workpiece.lower.y, workpiece.lower.z), new Vector(workpiece.lower.x + (length < xStock ? xStock : 0), workpiece.lower.y + (width < yStock ? yStock : 0), workpiece.upper.z) ); } } return workpiece; } function setWorkingSide(forward) { var zAxis = forward; isWorkingPlane = false; var workpiece = calculateWorkpiece(currentSection); var W = currentSection.workPlane; var zAxis = forward; var xAxis = new Vector(1, 0, 0); invertX = false; var origin; if (isSameDirection(zAxis, new Vector(0, 0, 1)) || useIso || sawIsActive) { currentFaceName = useIso ? "BASE" : "TOP"; currentFaceNumber = 1; isWorkingPlane = (sawIsActive && !isSameDirection(zAxis, new Vector(0, 0, 1))); xAxis = new Vector(1, 0, 0); zAxis = new Vector(0, 0, 1); origin = new Vector(-workpiece.lower.x, -workpiece.lower.y, useIso ? -workpiece.lower.z : -workpiece.upper.z); } else if (isSameDirection(zAxis, new Vector(-1, 0, 0))) { xAxis = new Vector(0, -1, 0); zAxis = new Vector(-1, 0, 0); invertX = true; currentFaceNumber = 6; currentFaceName = "LEFT"; origin = new Vector(workpiece.lower.y, -workpiece.lower.z, workpiece.lower.x); } else if (isSameDirection(zAxis, new Vector(1, 0, 0))) { xAxis = new Vector(0, 1, 0); zAxis = new Vector(1, 0, 0); currentFaceNumber = 4; currentFaceName = "RIGHT"; origin = new Vector(-workpiece.lower.y, -workpiece.lower.z, -workpiece.upper.x); } else if (isSameDirection(zAxis, new Vector(0, -1, 0))) { xAxis = new Vector(1, 0, 0); zAxis = new Vector(0, -1, 0); currentFaceNumber = 3; currentFaceName = "FRONT"; origin = new Vector(-workpiece.lower.x, -workpiece.lower.z, workpiece.lower.y); } else if (isSameDirection(zAxis, new Vector(0, 1, 0))) { xAxis = new Vector(-1, 0, 0); zAxis = new Vector(0, 1, 0); invertX = true; currentFaceNumber = 5; currentFaceName = "BACK"; origin = new Vector(workpiece.lower.x, -workpiece.lower.z, -workpiece.upper.y); } else { // 3+2 operation outside of a predefined face if (!isDrillingCycle()) { xAxis = new Vector(1, 0, 0); zAxis = new Vector(0, 0, 1); currentFaceNumber = 1; currentFaceName = "TOP"; origin = new Vector(-workpiece.lower.x, -workpiece.lower.y, -workpiece.upper.z); isWorkingPlane = true; } else { currentFaceName = "G500"; return; } } setTranslation(origin); var yAxis = Vector.cross(zAxis, xAxis); var O = new Matrix(xAxis, yAxis, zAxis); var R = O.getTransposed().multiply(W); setRotation(R); } function onSection() { cancelTransformation(); var insertToolCall = isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); useIso = getProperty("isoOnly") || currentSection.isMultiAxis(); sawIsActive = tool.type == TOOL_MILLING_SLOT && !useIso; redirectOperation = !isFirstSection() && getProperty("maxFileLength") > 0 && (!useIso || !getProperty("useFilesForSubprograms")); if (redirectOperation && !isRedirecting()) { redirectToBuffer(); } workPlaneABC = new Vector(0, 0, 0); // define working side and transformations setWorkingSide(currentSection.workPlane.forward, false); if (insertToolCall) { if (tool.number > numberOfToolSlots) { warning(localize("Tool number exceeds maximum value.")); } var showToolZMin = false; if (showToolZMin) { if (is3D()) { var numberOfSections = getNumberOfSections(); var zRange = currentSection.getGlobalZRange(); var number = tool.number; for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { var section = getSection(i); if (section.getTool().number != number) { break; } zRange.expandToRange(section.getGlobalZRange()); } writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); } } } if (insertToolCall || isFirstSection() || (rpmFormat.areDifferent(tool.spindleRPM, sOutput.getCurrent())) || (tool.clockwise != getPreviousSection().getTool().clockwise)) { if (tool.spindleRPM < 0) { error(localize("Spindle speed out of range.")); } if (tool.spindleRPM > 99999) { warning(localize("Spindle speed exceeds maximum value.")); } } forceXYZ(); if (machineConfiguration.isMultiAxisConfiguration() && (useIso || isWorkingPlane || sawIsActive)) { if (!useIso) { workPlaneABC = getWorkPlaneMachineABC(currentSection.workPlane, true); } } forceAny(); var initialPosition = getFramePosition(currentSection.getInitialPosition()); if (hasParameter("operation:tool_feedCutting")) { feed = feedOutput.format(getFeed(getParameter("operation:tool_feedCutting"))); } setFormats(useIso); if (nestingCode && (useIso || sawIsActive)) { error(subst(localize("%1 is not allowed for nesting geometry"), useIso ? "ISO" : "Saw")); } if (useIso) { writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); // Sub program ISO call if (getProperty("useFilesForSubprograms")) { redirectToBuffer(); } writeWords("G61"); var abc = currentSection.isOptimizedForMachine() ? currentSection.getInitialToolAxisABC() : getWorkPlaneMachineABC(currentSection.workPlane, false); writeBlock("G90 G40 G101", "T" + tool.number, xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z), aOutput.format(abc.x), cOutput.format(abc.z), "S" + getSpindleSpeed(tool.spindleRPM) + " " + mFormat.format(tool.clockwise ? 3 : 4)); forceAny(); writeBlock(gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z)); sideZero = true; } else if (!sawIsActive) { var z = initialPosition.z; if (nestingCode) { var zRange = currentSection.getZRange(); z = zRange.getMinimum(); } if (isWorkingPlane) { writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); if (!isDrillingCycle()) { writeBlock(nestingCode, "G90 G101 T" + tool.number, xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(z), "B" + abcFormat.format(workPlaneABC.y) + " C" + abcFormat.format(workPlaneABC.z), conditional(!nestingCode, "S" + getSpindleSpeed(tool.spindleRPM) + "U0"), conditional(nestingCode, "U0")); } else { if (nestingCode) { error(localize("Drilling cycle is not allowed for nesting geometry")); } } sideZero = true; } else { if (!isCannedCycle() && !sawIsActive) { writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); writeBlock(nestingCode, "G90 G40 G100 T" + toolFormat.format(tool.number), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(z), conditional(!nestingCode, "S" + getSpindleSpeed(tool.spindleRPM)), conditional(nestingCode, "U0")); sideZero = true; } else if (isCannedCycle() && !sawIsActive) { if (nestingCode) { error(localize("Drilling cycle is not allowed for nesting geometry")); } if (currentFaceName == "G500") { writeComment(getParameter("operation-comment")); } else { // drilling with cycle in faces writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); // writeBlock("G90 G40 G100 T" + toolFormat.format(tool.number), // xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z), // "S" + getSpindleSpeed(tool.spindleRPM)); // "U0Q0;0;0;0;0;0;0W0;0;0;0;0;0;0"); sideZero = true; } } } } if (nestingCode) { var finalPosition = getFramePosition(currentSection.getFinalPosition()); if (xFormat.getResultingValue(initialPosition.x) != xFormat.getResultingValue(finalPosition.x) || xyzFormat.getResultingValue(initialPosition.y) != xyzFormat.getResultingValue(finalPosition.y)) { error(localize("Nesting geometry must be closed.")); } zOutput.disable(); feedOutput.disable(); } } function moveWCS(x, y, z) { xOutput.offset = x; yOutput.offset = y; zOutput.offset = z; if (x != 0 && y != 0 && z != 0) { strictFace = true; } else { strictFace = false; } } function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); } seconds = clamp(0.001, seconds, 99999.999); writeBlock(gFormat.format(4), "P" + secFormat.format(seconds)); } function onCycle() { if (sawIsActive) { error(localize("Cycles are not allowed when using a saw blade.")); return; } if (currentFaceName == "G500") { // drilling with cycle using virtual plane var workpiece = getWorkpiece(); var cyclePoint = getCyclePoint(0); cyclePoint.setZ(cycle.stock); var cyclePointWorld = currentSection.workPlane.multiply(cyclePoint); var origin = Vector.diff(cyclePointWorld, workpiece.lower); var abc = getWorkPlaneMachineABC(currentSection.workPlane, false); virtualPlaneCounter += 1; writeBlock(currentFaceName + formatVirtualPlaneName(getParameter("operation-comment"), virtualPlaneCounter) + " X" + xyzFormat.format(origin.x) + " Y" + xyzFormat.format(origin.y) + " Z" + xyzFormat.format(origin.z) + " A" + abcFormat.format(0) + " B" + abcFormat.format(abc.y) + " C" + abcFormat.format(abc.z)); setTranslation(cyclePoint.getNegated()); } } function isCannedCycle() { if (!isDrillingCycle()) { return false; } var cycleType = getParameter("operation:cycleType"); var isCanned = false; if (!isWorkingPlane) { switch (cycleType) { case "drilling": case "chip-breaking": case "deep-drilling": case "tapping": case "right-tapping": case "left-tapping": isCanned = true; break; default: isCanned = false; } } else { isCanned = true; } return isCanned; } function onCyclePoint(x, y, z) { if (currentFaceName == "G500" && isFirstCyclePoint()) { // TAG: setTranslation in onCycle does not affect the first point x += getTranslation().x; y += getTranslation().y; z += getTranslation().z; } if (isWorkingPlane || !isDrillingCycle() || useIso) { expandCyclePoint(x, y, z); return; } var F = getFeed(cycle.feedrate); var P = (cycle.dwell == 0) ? 0 : clamp(0.001, cycle.dwell, 99999.999); // in seconds switch (cycleType) { case "back-boring": error(localize("Back boring is not supported")); return; case "drilling": case "counter-boring": writeBlock(gCycleModal.format(81), xOutput.format(x), yOutput.format(y), zOutput.format(z), "T" + toolFormat.format(tool.number), feedOutput.format(F), sOutput.format(getSpindleSpeed(tool.spindleRPM)), conditional(P > 0, "H" + secFormat.format(P)) ); break; case "deep-drilling": case "chip-breaking": feedOutput.reset(); writeBlock(gCycleModal.format(81), xOutput.format(x), yOutput.format(y), zOutput.format(z), "T" + toolFormat.format(tool.number), feedOutput.format(F), sOutput.format(getSpindleSpeed(tool.spindleRPM)), conditional(P > 0, "H" + secFormat.format(P)), "K" + xyzFormat.format(cycle.incrementalDepth), "R" + xyzFormat.format(cycle.retract) // TAG: 'R' is an absolute position ); break; case "tapping": case "left-tapping": case "right-tapping": writeBlock(gCycleModal.format(84), xOutput.format(x), yOutput.format(y), zOutput.format(z), "T" + toolFormat.format(tool.number), sOutput.format(getSpindleSpeed(tool.spindleRPM)) ); break; default: expandCyclePoint(x, y, z); } } function onCycleEnd() { if (!cycleExpanded) { zOutput.reset(); } } function onParameter(name, value) { switch (name) { case "action": if (String(value).toUpperCase() == "M21") { nestingCode = mFormat.format(21); // Nesting geometry } else if (String(value).toUpperCase() == "M22") { nestingCode = "M22"; // Nest left over areas } else { error(subst(localize("Invalid Action command: %1"), value)); } break; } } var pendingRadiusCompensation = -1; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; } function onMovement(movement) { if (nestingCode && (movement == MOVEMENT_LEAD_IN || movement == MOVEMENT_LEAD_OUT)) { error(localize("Lead-in/Lead-out moves are not allowed while creating nesting geometry.")); } } function onRapid(_x, _y, _z) { if (sawIsActive) { flushSawMove(getCurrentPosition(), sawCuttingFeed); return; } if (nestingCode && (movement != MOVEMENT_CUTTING && movement != MOVEMENT_FINISH_CUTTING)) { return; } var current = getCurrentPosition(); if ((xFormat.areDifferent(current.x, _x) || xyzFormat.areDifferent(current.y, _y) || xyzFormat.areDifferent(current.z, _z)) && (!isCannedCycle() || cycleExpanded)) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); if (x || y || z) { writeBlock(gMotionModal.format(0), x, y, z); } } } function onLinear(_x, _y, _z, feed) { if (sawIsActive) { linearSawMove(_x, _y, _z, feed); return; } if (nestingCode && (movement != MOVEMENT_CUTTING && movement != MOVEMENT_FINISH_CUTTING)) { return; } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(getFeed(feed)); var current = getCurrentPosition(); if ((xFormat.areDifferent(current.x, _x) || xyzFormat.areDifferent(current.y, _y) || xyzFormat.areDifferent(current.z, _z))) { if (pendingRadiusCompensation >= 0) { var invert = false; if (currentFaceName == "LEFT" || currentFaceName == "BACK") {invert = true;} pendingRadiusCompensation = -1; var d = tool.diameterOffset; if (d > 99) { warning(localize("The diameter offset exceeds the maximum value.")); } switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: if (invert) { writeBlock(gFormat.format(42), gMotionModal.format(1), x, y, z, f); } else { writeBlock(gFormat.format(41), gMotionModal.format(1), x, y, z, f); } break; case RADIUS_COMPENSATION_RIGHT: if (invert) { writeBlock(gFormat.format(41), gMotionModal.format(1), x, y, z, f); } else { writeBlock(gFormat.format(42), gMotionModal.format(1), x, y, z, f); } break; default: writeBlock(gFormat.format(40), gMotionModal.format(1), 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 feedOutput.reset(); // force feed on next line } else { feedOutput.reset(); // force feed on next line } } } var sawMoveType = MOVEMENT_RAPID; var sawDirection; var sawPreviousPosition; var sawCuttingFeed; function linearSawMove(_x, _y, _z, feed) { var moveDirection = Vector.diff(new Vector(_x, _y, _z), getCurrentPosition()).getNormalized(); if (movement == MOVEMENT_LEAD_IN) { // buffer lead-in move and save direction if (getProperty("ignoreSawLeadIn")) { sawPreviousPosition = new Vector(_x, _y, _z); return; } sawPreviousPosition = getCurrentPosition(); sawMoveType = MOVEMENT_LEAD_IN; sawDirection = moveDirection; return; } else if (movement == MOVEMENT_LEAD_OUT) { // check lead-out direction and flush motion if (getProperty("ignoreSawLeadIn") && sawMoveType != MOVEMENT_CUTTING) { return; } sawMoveType = MOVEMENT_LEAD_OUT; if (getProperty("ignoreSawLeadIn")) { flushSawMove(getCurrentPosition(), sawCuttingFeed); return; } else if (Vector.diff(moveDirection, sawDirection).length > toPreciseUnit(0.001, IN)) { error(localize("Lead-out direction does not match cut direction.")); } else { flushSawMove(new Vector(_x, _y, _z), sawCuttingFeed); } return; } else if ((movement != MOVEMENT_CUTTING) && (movement != MOVEMENT_FINISH_CUTTING) && (movement != MOVEMENT_REDUCED)) { // ignore non-cutting moves sawPreviousPosition = new Vector(_x, _y, _z); return; } // cutting move if (sawMoveType == MOVEMENT_LEAD_IN) { // check lead-in direction if (Vector.diff(moveDirection, sawDirection).length > toPreciseUnit(0.001, IN)) { error(localize("Lead-in direction does not match cut direction.")); return; } } else if (sawMoveType == MOVEMENT_CUTTING) { // flush consecutive cutting motions // buffer moves in same direction if (Vector.diff(moveDirection, sawDirection).length > toPreciseUnit(0.001, IN)) { flushSawMove(getCurrentPosition(), sawCuttingFeed); sawMoveType = MOVEMENT_CUTTING; } } // buffer cutting move in case of lead-out move sawPreviousPosition = sawPreviousPosition == undefined ? getCurrentPosition() : sawPreviousPosition; sawDirection = Vector.diff(new Vector(_x, _y, _z), sawPreviousPosition).getNormalized(); sawCuttingFeed = feed; sawMoveType = MOVEMENT_CUTTING; } var sawOffset = 1; // -1 = offset from saw to line, 0 = no offset, 1 = offset from line to saw function flushSawMove(_xyz, feed) { if (sawMoveType == MOVEMENT_RAPID) { // nothing to output return; } // saw cuts require that the tool be on the profile line var start = new Vector(sawPreviousPosition.x, sawPreviousPosition.y, sawPreviousPosition.z); var end = new Vector(_xyz.x, _xyz.y, _xyz.z); var offsetVector = new Vector(0, 0, 0); var compDir = 0; var entryFeed = hasParameter("operation:tool_feedEntry") ? getParameter("operation:tool_feedEntry") : feed; var dir = getParameter("operation:compensation") == "left" ? -1 : 1; // horizontal saw cut if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { var workpiece = calculateWorkpiece(currentSection); if (dir == -1) { zAxis = Vector.cross(currentSection.workPlane.forward, sawDirection); } else { zAxis = Vector.cross(sawDirection, currentSection.workPlane.forward); } var x; var y; var z; var endX; var face; var toolRadius = tool.diameter / 2; if (getParameter("operation:compensationType") == "control") { error(localize("Cannot calculate workplane for horizontal saw cut.")); return; } if (isSameDirection(zAxis, new Vector(-1, 0, 0))) { // face 6 face = 6; currentFaceName = "LEFT"; x = start.y; endX = end.y; y = -(start.x + toolRadius); z = start.z + (workpiece.upper.z - workpiece.lower.z); } else if (isSameDirection(zAxis, new Vector(1, 0, 0))) { // face 4 face = 4; currentFaceName = "RIGHT"; x = start.y; endX = end.y; y = start.x - toolRadius - (workpiece.upper.x - workpiece.lower.x); z = start.z + (workpiece.upper.z - workpiece.lower.z); } else if (isSameDirection(zAxis, new Vector(0, -1, 0))) { // face 3 face = 3; currentFaceName = "FRONT"; x = start.x; endX = end.x; y = -(start.y + toolRadius); z = start.z + (workpiece.upper.z - workpiece.lower.z); } else if (isSameDirection(zAxis, new Vector(0, 1, 0))) { // face 5 face = 5; currentFaceName = "BACK"; x = start.x; endX = end.x; y = start.y - toolRadius - (workpiece.upper.y - workpiece.lower.y); z = start.z + (workpiece.upper.z - workpiece.lower.z); } else { var debug = false; var leadIn = getParameter("operation:entry_distance", toUnit(0.1, IN)); leadIn = leadIn == 0 ? toUnit(0.1, IN) : leadIn; // leadin not in radius direction if (dir == -1) { offsetVector = Vector.cross(currentSection.workPlane.forward, sawDirection).getNormalized(); } else { offsetVector = Vector.cross(sawDirection, currentSection.workPlane.forward).getNormalized(); } // calculate plane rotation var angle = Math.atan2(offsetVector.y, offsetVector.x); var mx = Matrix.getZRotation(angle).getTransposed(); // calculate start/end moves at outer edge of saw, adjust for the lead-in move var offset = toolRadius - leadIn; var xyzStart = Vector.sum(start, Vector.product(offsetVector.negated, offset)); var xyzEnd = Vector.sum(end, Vector.product(offsetVector.negated, offset)); // calculate origin in TOP wcs var origin = new Vector(xyzStart.x, xyzStart.y, 0); if (false) { writeln("offsetVector = " + offsetVector.getNormalized()); writeln("offset = " + offset); writeln("start = " + start); writeln("end = " + end); writeln("shiftedStart = " + xyzStart); writeln("shiftedEnd = " + xyzEnd); } // move start and end points based on new origin xyzStart = Vector.diff(xyzStart, origin); xyzEnd = Vector.diff(xyzEnd, origin); // rotate saw move to plane of cut var xyzStart = mx.multiply(xyzStart); var xyzEnd = mx.multiply(xyzEnd); if (debug) { writeln("rotatedStart = " + xyzStart); writeln("rotatedEnd = " + xyzEnd); } writeBlock("TOP"); virtualPlaneCounter += 1; currentFaceName = gFormat.format(500) + formatVirtualPlaneName(getParameter("operation-comment"), virtualPlaneCounter) + " X" + xyzFormat.format(origin.x) + " Y" + xyzFormat.format(origin.y) + " Z" + xyzFormat.format(0) + " A" + abcFormat.format(toRad(0)) + " B" + abcFormat.format(toRad(90)) + " C" + abcFormat.format(angle); x = Math.abs(xyzStart.x) * dir; endX = Math.abs(xyzEnd.x) * dir; y = -leadIn; // xyzStart.y; z = start.z + (workpiece.upper.z - workpiece.lower.z); } // horizontal saw cuts must be in postive direction var reverseX = 0; if (x < endX) { var temp = x; x = endX; endX = temp; reverseX = 1; } // Z-depth is a center of groove // flip cutting direction for left and back face when comp right is used var reverseComp; if (currentFaceName == "LEFT" || currentFaceName == "BACK") { reverseComp = dir == -1 ? "L1" : "L0"; } else { reverseComp = dir == -1 ? "L0" : "L1"; } writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); writeBlock("G111" + tOutput.format(tool.number), "X" + xOutput.format(x) + ";" + xyzFormat.format(endX), // starting X, ending X "Y" + yOutput.format(z) + ";" + xyzFormat.format(z), // center of cut along Z-axis of Face 1 "Z" + zOutput.format(y), // depth of cut reverseComp, // cutting direction "D40", "S" + getSpindleSpeed(tool.spindleRPM) + " F" + feedFormat.format(feed) + " H" + feedFormat.format(entryFeed) ); sawPreviousPosition = new Vector(_xyz.x, _xyz.y, _xyz.z); sawMoveType = MOVEMENT_RAPID; return; } if (hasParameter("operation:compensationType") && hasParameter("operation:compensation")) { // for saw cuts, conventional (left) cutting must be used // reverse direction of cut if (right) cutting is specified if (getParameter("operation:compensationType") != "control") { if (getParameter("operation:compensation") == "right") { var temp = new Vector(start.x, start.y, start.z); start = new Vector(end.x, end.y, end.z); end = new Vector(temp.x, temp.y, temp.z); sawDirection.negate(); } offsetVector = Vector.product(Vector.cross(sawDirection, currentSection.workPlane.forward).getNormalized(), (tool.diameter / 2)); start = Vector.sum(start, offsetVector); end = Vector.sum(end, offsetVector); } } var beta = workPlaneABC.y < 0 ? Math.PI + workPlaneABC.y : workPlaneABC.y; beta -= toRad(90); var xyVector = new Vector(offsetVector.x, offsetVector.y, 0).normalized; var startX = start.x + (Math.tan(beta) * (Math.abs(start.z) * xyVector.x)); var endX = end.x + (Math.tan(beta) * (Math.abs(end.z) * xyVector.x)); var startY = start.y + (Math.tan(beta) * (Math.abs(start.z) * xyVector.y)); var endY = end.y + (Math.tan(beta) * (Math.abs(end.z) * xyVector.y)); var x = xOutput.format(endX); var y = yOutput.format(endY); if (x || y) { var xyMove = true; var yMove = xyzFormat.areDifferent(sawPreviousPosition.y, _xyz.y) && !xyMove; var entryFeed = hasParameter("operation:tool_feedEntry") ? getParameter("operation:tool_feedEntry") : feed; if (abcFormat.getResultingValue(workPlaneABC.z) >= 180) { workPlaneABC.setZ(workPlaneABC.z - Math.PI); workPlaneABC.setY(workPlaneABC.y - Math.PI); } writeBlock(currentFaceName); writeComment(getParameter("operation-comment")); writeBlock("G111" + tOutput.format(tool.number), "X" + xOutput.format(startX) + ";" + conditional(!yMove, x), "Y" + yOutput.format(startY) + ";" + conditional((xyMove || yMove), y), "Z" + zOutput.format(start.z), conditional(xyMove, "B" + abcFormat.format(-beta)), // beta angle (B-axis) ((getParameter("operation:compensation")) != "left" ? "L1" : "L0"), "D40", "S" + getSpindleSpeed(tool.spindleRPM) + " F" + feedFormat.format(feed) + " H" + feedFormat.format(entryFeed) ); } sawPreviousPosition = new Vector(_xyz.x, _xyz.y, _xyz.z); sawMoveType = MOVEMENT_RAPID; } function onRapid5D(_x, _y, _z, _a, _b, _c) { 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); writeBlock(gMotionModal.format(0), x, y, z, a, b, c); feedOutput.reset(); } function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { 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); var f = feedOutput.format(getFeed(feed)); if (x || y || z || a || b || c) { writeBlock(gMotionModal.format(1), x, y, z, a, b, c, f); } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } function setFormats(isoMode) { var xyzDecimals = currentSection.isMultiAxis() ? (unit == MM ? 5 : 6) : (unit == MM ? 3 : 4); var abcDecimals = currentSection.isMultiAxis() ? 6 : 3; xFormat.setNumberOfDecimals(xyzDecimals); xFormat.setScale(invertX ? -1 : 1); xyzFormat.setNumberOfDecimals(xyzDecimals); abcFormat.setNumberOfDecimals(abcDecimals); xOutput.setFormat(xFormat); yOutput.setFormat(xyzFormat); zOutput.setFormat(xyzFormat); aOutput.setFormat(abcFormat); bOutput.setFormat(abcFormat); cOutput.setFormat(abcFormat); iOutput.setFormat(xFormat); if (isoMode) { xOutput.setPrefix("X"); yOutput.setPrefix("Y"); zOutput.setPrefix("Z"); xOutput.setControl(CONTROL_CHANGED); yOutput.setControl(CONTROL_CHANGED); zOutput.setControl(CONTROL_CHANGED); } else if (sawIsActive) { xOutput.setPrefix(""); yOutput.setPrefix(""); zOutput.setPrefix(""); xOutput.setControl(CONTROL_FORCE); yOutput.setControl(CONTROL_FORCE); zOutput.setControl(CONTROL_FORCE); } else { xOutput.setPrefix("X"); yOutput.setPrefix("Y"); zOutput.setPrefix("Z"); xOutput.setControl(CONTROL_FORCE); yOutput.setControl(CONTROL_FORCE); zOutput.setControl(CONTROL_FORCE); } } // Start of onRewindMachine logic /***** Be sure to add 'safeRetractDistance' to post getProperty(" ")*****/ var performRewinds = true; // enables the onRewindMachine logic var safeRetractFeed = (unit == IN) ? 20 : 1500; var safePlungeFeed = (unit == IN) ? 10 : 1000; var stockAllowance = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); /** Allow user to override the onRewind logic. */ function onRewindMachineEntry(_a, _b, _c) { return false; } /** Return from safe position after indexing rotaries. */ function returnFromSafeRetractPosition(position) { forceXYZ(); xOutput.reset(); yOutput.reset(); zOutput.disable(); onExpandedRapid(position.x, position.y, position.z); zOutput.enable(); onExpandedRapid(position.x, position.y, position.z); } /** Intersect the point-vector with the stock box. */ function intersectStock(point, direction) { var intersection = getWorkpiece().getRayIntersection(point, direction, stockAllowance); return intersection === null ? undefined : intersection.second; } /** Calculates the retract point using the stock box and safe retract distance. */ function getRetractPosition(currentPosition, currentDirection) { var retractPos = intersectStock(currentPosition, currentDirection); if (retractPos == undefined) { if (tool.getFluteLength() != 0) { retractPos = Vector.sum(currentPosition, Vector.product(currentDirection, tool.getFluteLength())); } } if ((retractPos != undefined) && getProperty("safeRetractDistance")) { retractPos = Vector.sum(retractPos, Vector.product(currentDirection, getProperty("safeRetractDistance"))); } return retractPos; } /** Determines if the angle passed to onRewindMachine is a valid starting position. */ function isRewindAngleValid(_a, _b, _c) { // make sure the angles are different from the last output angles if (!abcFormat.areDifferent(getCurrentDirection().x, _a) && !abcFormat.areDifferent(getCurrentDirection().y, _b) && !abcFormat.areDifferent(getCurrentDirection().z, _c)) { error( localize("REWIND: Rewind angles are the same as the previous angles: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } // make sure angles are within the limits of the machine var abc = new Array(_a, _b, _c); var ix = machineConfiguration.getAxisU().getCoordinate(); var failed = false; if ((ix != -1) && !machineConfiguration.getAxisU().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisV().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisV().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisW().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisW().isSupported(abc[ix])) { failed = true; } if (failed) { error( localize("REWIND: Rewind angles are outside the limits of the machine: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } return true; } function onRewindMachine(_a, _b, _c) { if (!performRewinds) { error(localize("REWIND: Rewind of machine is required for simultaneous multi-axis toolpath and has been disabled.")); return; } // Allow user to override rewind logic if (onRewindMachineEntry(_a, _b, _c)) { return; } // Determine if input angles are valid or will cause a crash if (!isRewindAngleValid(_a, _b, _c)) { error( localize("REWIND: Rewind angles are invalid:") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return; } // Work with the tool end point if (currentSection.getOptimizedTCPMode() == 0) { currentTool = getCurrentPosition(); } else { currentTool = machineConfiguration.getOrientation(getCurrentDirection()).multiply(getCurrentPosition()); } var currentABC = getCurrentDirection(); var currentDirection = machineConfiguration.getDirection(currentABC); // Calculate the retract position var retractPosition = getRetractPosition(currentTool, currentDirection); // Output warning that axes take longest route if (retractPosition == undefined) { error(localize("REWIND: Cannot calculate retract position.")); return; } else { var text = localize("REWIND: Tool is retracting due to rotary axes limits."); warning(text); } // Move to retract position var position; if (currentSection.getOptimizedTCPMode() == 0) { position = retractPosition; } else { position = machineConfiguration.getOrientation(getCurrentDirection()).getTransposed().multiply(retractPosition); } onExpandedLinear(position.x, position.y, position.z, safeRetractFeed); // Rotate axes to new position above reentry position xOutput.disable(); yOutput.disable(); zOutput.disable(); onRapid5D(position.x, position.y, position.z, _a, _b, _c); xOutput.enable(); yOutput.enable(); zOutput.enable(); // Move back to position above part if (currentSection.getOptimizedTCPMode() != 0) { position = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(retractPosition); } returnFromSafeRetractPosition(position); // Plunge tool back to original position if (currentSection.getOptimizedTCPMode() != 0) { currentTool = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(currentTool); } onExpandedLinear(currentTool.x, currentTool.y, currentTool.z, safePlungeFeed); } // End of onRewindMachine logic function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { if (sawIsActive || (useIso && !getProperty("isoCircular"))) { linearize(tolerance); return; } var start = getCurrentPosition(); var dir = clockwise ? (invertX ? 3 : 2) : (invertX ? 2 : 3); var invert = false; if (currentFaceName == "LEFT" || currentFaceName == "BACK") {invert = true;} if (isFullCircle()) { if (isHelical()) { linearize(tolerance); return; } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gMotionModal.format(dir), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), feedOutput.format(getFeed(feed))); break; default: linearize(tolerance); } } else { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gMotionModal.format(dir), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), feedOutput.format(getFeed(feed))); break; default: linearize(tolerance); } } } function onSectionEnd() { if (sawIsActive) { // Saw blade redirection flushSawMove(getCurrentPosition(), sawCuttingFeed); } else if (redirectOperation) { writeRedirectedOperation(); } else if (isRedirecting()) { writeIsoFile(); } nestingCode = ""; if (nestingCode) { zOutput.enable(); feedOutput.enable(); } forceAny(); } var redirectOperation = false; var writeToMainFile = true; var fileLinesLength = 0; var bufferedLinesLength = 0; var fileNumber = 1; var fileBuffer = ""; function writeRedirectedOperation() { if (isRedirecting()) { // first operation is not redirected var redirectedLines = getRedirectionBuffer(); closeRedirection(); if ((fileLinesLength + bufferedLinesLength) >= getProperty("maxFileLength")) { writeToRedirectedFile(); fileBuffer = ""; fileLinesLength = 0; } fileBuffer += redirectedLines; fileLinesLength += bufferedLinesLength; } else { fileLinesLength = bufferedLinesLength; } bufferedLinesLength = 0; } function writeToRedirectedFile() { if (fileBuffer.length > 0) { if (writeToMainFile) { write(fileBuffer); } else { var fileName = FileSystem.getFilename(FileSystem.replaceExtension(getOutputPath(), "xxx").split(".xxx", 1)); var subName = fileName + "_" + fileNumber + "." + extension; var path = FileSystem.getFolderPath(getOutputPath()); path = FileSystem.getCombinedPath(path, subName); redirectToFile(path); writeHeader(); write(fileBuffer); closeRedirection(); fileNumber++; } } writeToMainFile = false; } function writeIsoFile() { var redirectedLines = (String(getRedirectionBuffer()).split(EOL)); closeRedirection(); if (redirectedLines.length > getProperty("minSubfileLength")) { var fileName = FileSystem.getFilename(FileSystem.replaceExtension(getOutputPath(), "xxx").split(".xxx", 1)); var subName = fileName + subFormat.format(subProgramNumber) + ".iso"; var path = FileSystem.getFolderPath(getOutputPath()); if (getProperty("subprogramPath").toUpperCase() != "DEFAULT") { path = FileSystem.getCombinedPath(path, getProperty("subprogramPath")); if (!FileSystem.isFolder(path)) { FileSystem.makeFolder(path); } } path = FileSystem.getCombinedPath(path, subName); subProgramNumber += 1; // subprogram ISO call writeBlock(gFormat.format(105), xOutput.format(0), yOutput.format(0), zOutput.format(0) + " P\"" + path + "\"" + "T" + tool.number); setFormats(true); redirectToFile(path); for (line in redirectedLines) { if (redirectedLines[line].indexOf("G61") == -1 && redirectedLines[line].indexOf("G101") == -1) { writeBlock(redirectedLines[line]); } } // writeBlock(gFormat.format(60)); writeBlock(mFormat.format(2)); closeRedirection(); } else { for (line in redirectedLines) { writeBlock(redirectedLines[line]); } // writeBlock(gFormat.format(60)); } } function onClose() { writeToRedirectedFile(); }