/** Copyright (C) 2012-2024 by Autodesk, Inc. All rights reserved. woodWOP post processor configuration. $Revision: 44142 0ad4064c4baac60c7a457beaa12f1e745ba6bf42 $ $Date: 2024-08-28 03:28:56 $ FORKID {2A265A9B-0B98-43a0-A447-177302864E1E} */ /////////////////////////////////////////////////////////////////////////////// // MANUAL NC COMMANDS // // The following ACTION commands are supported by this post. // // GrooveWidth:width - The groove width for sawing operations (NB). // ApproachMode:mode - Contour/saw approach mode (MDA), can be 'tangent', 'lateral', 'vertical' // ExitMode:mode - Contour/saw exit mode (MDE), can be 'tangent', 'lateral', 'vertical' // InsertDowel:Off, depth - Outputs a dowel insertion command after drilling a hole. // Can be 'Off' to disable dowel insertion or the 'depth' to insert a dowel after each drilled hole. // /////////////////////////////////////////////////////////////////////////////// description = "woodWOP"; vendor = "HOMAG"; vendorUrl = "http://www.homag.com"; legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45892; longDescription = "Generic woodWOP post with support for multi-axis machines. By default any drilling will be executed before all milling. You can turn off the 'doAllDrillingFirst' property to use the programmed order."; extension = "mpr"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.3, MM); // avoid errors with smaller radii maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(90); // limit to 180deg for now to work around issues with 360deg arcs // limit to 90deg to avoid potential center calculation errors for CNC allowHelicalMoves = true; allowedCircularPlanes = (1 << PLANE_XY); // allow XY circular motion mapWorkOrigin = false; // user-defined properties properties = { doAllDrillingFirst: { title : "Do all drilling first", description: "Enable to reorder toolpath to do all drilling first.", group : "preferences", type : "boolean", value : true, scope : "post" }, useDrillThrough: { title : "Use Drill Tip Through Bottom", description: "Enable to treat the Drill Tip Through Bottom checkbox as drilling through the part (LSL).", group : "preferences", type : "boolean", value : true, scope : "post" }, useBoreToolNumber: { title : "Output tool number for drilling", description: "Enable to output tool numbers with drilling operations, disable to output the hole diameter.", group : "preferences", type : "boolean", value : true, scope : "post" }, useBoreFeeds: { title : "Output feedrates for drilling", description: "Enable to output the programmed feedrate with drilling operations, disable to output the hole diameter.", group : "preferences", type : "boolean", value : true, scope : "post" }, machineModel: { title : "Machine type", description: "Select the machine type to output in the MAT command.", group : "configuration", type : "enum", values : [ {title:"HOMAG", id:"HOMAG"}, {title:"CF-HOMAG", id:"CF-HOMAG"}, {title:"FK-HOMAG", id:"FK-HOMAG"}, {title:"WEEKE", id:"WEEKE"} ], value: "WEEKE", scope: "post" }, shiftOrigin: { title : "Shift origin to part origin", description: "Enable to shift the WCS origin to the selected origin of the part as specifed by the 'Part origin' property.", group : "preferences", type : "boolean", value : true, scope : "post" }, wcsOrigin: { title : "Part origin", description: "The origin of the part can be on any corner of the part, select Lower left, Lower right, Upper right, or Upper left.", group : "preferences", type : "enum", values : [ {title:"Lower left", id:"F0"}, {title:"Lower right", id:"01"}, {title:"Upper right", id:"02"}, {title:"Upper left", id:"03"} ], value: "F0", scope: "post" }, stockDefinition: { title : "Stock definition", description: "The stock definition can either be defined as the 'Size' of the stock or the 'Offset' of the stock from the finished part.", group : "preferences", type : "enum", values : [ {title:"Stock size", id:"size"}, {title:"Stock offset", id:"offset"} ], value: "size", scope: "post" }, freeMotionParkPosition: { title : "Free motion park position", description: "Specifies where the machine should park after cutting.", group : "homePositions", type : "integer", values : [ 0, 1, 2, 3, 4, 5 ], value: 1, scope: "post" }, freeMotionAdditional: { title : "Free motion additional", description: "Specifies how much to add to the free motion park position (in mm).", group : "homePositions", type : "number", value : 0, scope : "post" }, isoOnly: { title : "Output NC code in ISO format", description: "Enable to output all operations in ISO format using the Universal Makro.", group : "formats", type : "boolean", value : false, scope : "post" }, showSequenceNumbers: { title : "Use sequence numbers", description: "Use sequence numbers for each ISO block.", group : "formats", type : "boolean", value : true, scope : "post" }, sequenceNumberStart: { title : "Start sequence number", description: "The number at which to start the sequence numbers.", group : "formats", type : "integer", value : 1, 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 : 1, scope : "post" }, showNotes: { title : "Show notes", description: "Writes operation notes as comments in the ISO output code.", group : "formats", type : "boolean", value : false, scope : "post" }, useComments: { title : "Show comments", description: "Enable to write out standard commments using the '\\ comment' syntax.", group : "formats", type : "boolean", value : true, scope : "post" }, homePositionZ: { title : "Z home position", description: "Z home position between multi-axis operations.", group : "homePositions", type : "spatial", value : 100, scope : "post" }, useSmoothing: { title : "Use smoothing", description: "Enables BSPLINE style smoothing for contours and multi-axis operations.", group : "preferences", type : "boolean", value : true, scope : "post" }, smoothingPathDev: { title : "Path deviation", description: "Allowed linear path deviation for smoothing.", group : "preferences", type : "number", value : 0.02, scope : "post" }, smoothingTrackDev: { title : "Angular deviation", description: "Allowed rotary angle deviation for smoothing.", group : "preferences", type : "number", value : 1, scope : "post" }, useRadius: { title : "Radius arcs", description: "If yes is selected, arcs are output using radius values rather than IJK in ISO mode.", group : "preferences", type : "boolean", value : false, scope : "post" }, useMultiAxisFeatures: { title : "Use ISO work planes", description: "Enable to output work planes for 3+2 operations in ISO mode. Disable to output 3+2 operations using TCP in ISO mode.", group : "multiAxis", type : "boolean", value : false, scope : "post" }, abcToler: { title : "A-axis tolerance", description: "The tolerance used to determine the output of the A-axis.", group : "multiAxis", type : "spatial", value : 0.001, scope : "post" }, sawMode: { title : "Saw mode", description: "Defines the macro to use when a saw blade is used. 'Contour' outputs the 193 Sawing_contour macro, 'Groove' outputs the '109 Sawing_vertical' and '124 Sawing_with_A_angle' macros.", group : "saw", type : "enum", values : [ {title:"Contour", id:"contour"}, {title:"Groove", id:"groove"} ], value: "groove", scope: "post" }, verticalContourMode: { title : "Vertical contour mode", description: "Defines the macro to use for a vertical contour. 'Contour' outputs the 105 Trimming_vertical macro, 'Polygon' outputs the '119 Trimming_polygon' macro.", group : "preferences", type : "enum", values : [ {title:"Contour", id:"contour"}, {title:"Polygon", id:"polygon"} ], value: "contour", scope: "post" }, startRoutine: { title : "Start subroutine", description: "Select the start subroutine to output in ISO mode.", group : "formats", type : "enum", values : [ {title:"UNCVK40", id:"UNCVK40"}, {title:"OUNCVK40", id:"OUNCVK40"} ], value: "UNCVK40", scope: "post" } }; groupDefinitions = { saw: {title:"Saw Aggregate", collapsed:true, description:"Settings related to an aggregate saw attachment", order:25}, }; var nFormat = createFormat({prefix:"N", decimals:0, minDigitsLeft:4}); var gFormat = createFormat({prefix:"G", decimals:0}); var xFormat = createFormat({decimals:4}); var yFormat = createFormat({decimals:4}); var zFormat = createFormat({decimals:4}); var xyzFormat = createFormat({decimals:4}); var eulerFormat = createFormat({decimals:3, scale:DEG}); var abcFormat = createFormat({decimals:3, type:FORMAT_REAL, minDigitsRight:3, scale:DEG}); var radianFormat = createFormat({decimals:3, type:FORMAT_REAL}); var rFormat = createFormat({decimals:4}); var spatialFormat = createFormat({decimals:4}); var feedFormat = createFormat({decimals:3, scale:0.001}); var isoFeedFormat = createFormat({decimals:3, type:FORMAT_REAL, minDigitsRight:3, scale:0.001}); var integerFormat = createFormat({decimals:0}); var wcsFormat = createFormat({decimals:2, minDigitsLeft:2}); var xOutput = createOutputVariable({prefix:"X"}, xyzFormat); 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"}, isoFeedFormat); // 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", control:CONTROL_FORCE}, xyzFormat); var gMotionModal = createOutputVariable({}, gFormat); // modal group 1 // G0-G3, ... // fixed settings var useMultiAxisFeatures = true; // use #CS work planes var useABCPrepositioning = true; // position ABC axes prior to #CS work plane var retracted = false; // specifies that the tool has been retracted to the safe plane var REDIRECT_ID = 99999; var SAW_OFF = 0; var SAW_CONTOUR = 1; var SAW_GROOVE = 2; // collected state var inContour = false; var contourId = 0; var entityId = 0; var currentFeed = -1; var machining = []; var definedWorkPlanes = []; var virtualConfiguration = {}; var sequenceNumber; var redirectBuffer = []; var redirectIndex = 0; var previousABC = new Vector(0, 0, 0); var useISO; var tcpActive; var workOrigin; var sawIsActive = SAW_OFF; var workpiece; var workpieceDelta; var workpieceOffset; var part; var partDelta; var grooveWidth = 0; var approachMode = "SEN"; // vertical entry to contour var exitMode = "SEN_AB"; // vertical exit from contour var insertDowel = false; var dowelDepth = 0; var translation; var identityWCS; var isPolygon = false; var polygonStart = 0; var polygonBuffer = new Array(); /** Writes the specified block. */ function writeSimpleBlock() { writeWords(arguments); } /** Writes the specified ISO block */ function writeBlock() { var text = formatWords(arguments); if (!text) { return; } if (getProperty("showSequenceNumbers")) { if (sequenceNumber > 9999) { sequenceNumber = getProperty("sequenceNumberStart"); } writeWords2(nFormat.format(sequenceNumber), arguments); sequenceNumber += getProperty("sequenceNumberIncrement"); } else { writeWords(arguments); } } /** Output a woodWOP comment. */ function writeSimpleComment(text) { if (getProperty("useComments")) { writeSimpleBlock("\\ " + text); } } /** Output an ISO comment. */ function writeComment(text) { writeBlock("(" + text + ")"); } /** Output a KM comment. */ function writeKMComment(text) { writeVar("KM", text); } function writeVal(name, value) { writeln(name + "=" + value); } function writeVar(name, value) { writeln(formatVar(name, value)); } function formatVar(name, value) { return name + "=\"" + value + "\""; } var SMOOTH_DEFINE = 0; var SMOOTH_RESET = 1; var SMOOTH_ENABLE = 2; var SMOOTH_DISABLE = 3; var currentSmoothing = SMOOTH_DISABLE; var smoothing = {enabled:false, pathDev:0.02, trackDev:1}; function setSmoothing(type) { if (!smoothing.enabled || type == currentSmoothing || (hasParameter("operation-strategy") && (getParameter("operation-strategy") == "drill"))) { return; } switch (type) { case SMOOTH_DEFINE: writeln( "#HSC[BSPLINE PATH_DEV=" + spatialFormat.format(smoothing.pathDev) + " TRACK_DEV=" + spatialFormat.format(smoothing.trackDev) + "]" ); writeln("#SET SLOPE PROFIL[3]"); currentSmoothing = SMOOTH_DISABLE; break; case SMOOTH_RESET: writeln("#SET SLOPE PROFIL"); currentSmoothing = SMOOTH_DISABLE; break; case SMOOTH_ENABLE: writeln("#HSC ON"); currentSmoothing = SMOOTH_ENABLE; break; case SMOOTH_DISABLE: writeln("#HSC OFF"); currentSmoothing = SMOOTH_DISABLE; break; } } function coordinatesAreSame(xyz1, xyz2) { if (xyzFormat.getResultingValue(xyz1.x) != xyzFormat.getResultingValue(xyz2.x) || xyzFormat.getResultingValue(xyz1.y) != xyzFormat.getResultingValue(xyz2.y) || xyzFormat.getResultingValue(xyz1.z) != xyzFormat.getResultingValue(xyz2.z)) { return false; } return true; } function anglesAreSame(abc1, abc2) { if (eulerFormat.getResultingValue(abc1.x) != eulerFormat.getResultingValue(abc2.x) || eulerFormat.getResultingValue(abc1.y) != eulerFormat.getResultingValue(abc2.y) || eulerFormat.getResultingValue(abc1.z) != eulerFormat.getResultingValue(abc2.z)) { return false; } return true; } function getDefinedWorkPlane(sectionId) { for (var i = 0; i < definedWorkPlanes.length; i++) { if (definedWorkPlanes[i].section == sectionId) { return definedWorkPlanes[i]; } } return definedWorkPlanes[0]; } function onOpen() { unit = MM; // output units are always in MM sequenceNumber = getProperty("sequenceNumberStart"); useMultiAxisFeatures = getProperty("useMultiAxisFeatures"); identityWCS = getProperty("wcsOrigin"); aOutput.setTolerance(getProperty("abcToler")); // smoothing variables smoothing.enabled = getProperty("useSmoothing"); smoothing.pathDev = getProperty("smoothingPathDev"); smoothing.trackDev = getProperty("smoothingTrackDev"); // Define machine configuration if program has multi-axis operation(s) if (isMultiAxis() || getProperty("isoOnly")) { // physical machine configuration var headAngle = -39.18; var aAxis = createAxis({coordinate:0, table:false, axis:[0, -Math.cos(toRad(headAngle)), -Math.sin(toRad(headAngle))], range:[-189, 189]}); var cAxis = createAxis({coordinate:2, table:false, axis:[0, 0, -1], range:[-365, 365], cyclic:false, reset:1}); machineConfiguration = new MachineConfiguration(aAxis, cAxis); // virtual machine configuration expected by controller var virtualAAxis = createAxis({coordinate:0, table:false, axis:[-1, 0, 0], range:[-99.99, 99.99]}); var virtualCAxis = createAxis({coordinate:2, table:false, axis:[0, 0, -1], cyclic:true}); // range: [-365, 365], cyclic: false}); virtualConfiguration = new MachineConfiguration(virtualAAxis, virtualCAxis); setMachineConfiguration(machineConfiguration); optimizeMachineAngles2(0); // TCP mode } if (!machineConfiguration.isMachineCoordinate(0)) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1)) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2)) { cOutput.disable(); } if (programName) { writeSimpleComment(programName); } if (programComment) { writeSimpleComment(programComment); } writeln("[H"); writeVar("VERSION", "4.0"); writeVar("INCH", 0 /*(unit == IN) ? 1 : 0*/); // 0 mm, 1 inch // we map inches to mm writeVar("MAT", getProperty("machineModel")); // HOMAG, CF-HOMAG, FK-HOMAG, WEEKE writeVar("OP", getProperty("doAllDrillingFirst") ? 1 : 0); writeVar("FM", getProperty("freeMotionParkPosition")); // free motion part posisiton 0-4 writeVar("FW", spatialFormat.format(getProperty("freeMotionAdditional"))); // in mm workpiece = getWorkpiece(); workpieceDelta = Vector.diff(workpiece.upper, workpiece.lower); part = new BoundingBox(new Vector(getGlobalParameter("part-lower-x", 0), getGlobalParameter("part-lower-y", 0), getGlobalParameter("part-lower-z", 0)), new Vector(getGlobalParameter("part-upper-x", 0), getGlobalParameter("part-upper-y", 0), getGlobalParameter("part-upper-z", 0))); partDelta = Vector.diff(part.upper, part.lower); workpieceOffset = getWorkpieceOffset(); // variables writeln(""); writeln("[001"); /* writeVar("L", 0); writeVar("KM", ""); writeVar("B", 0); writeVar("KM", ""); writeVar("D", 0); writeVar("KM", ""); */ writeVar("i", 25.4); writeKMComment("Inch conversion"); if (partDelta.isNonZero()) { writeVar("L", spatialFormat.format(partDelta.x)); writeKMComment("Part Length"); writeVar("W", spatialFormat.format(partDelta.y)); writeKMComment("Part Width"); } if (workpieceDelta.isNonZero()) { if (getProperty("stockDefinition") == "offset") { writeVar("SOX", spatialFormat.format(workpieceDelta.x - partDelta.x)); writeKMComment("Stock Offset X"); writeVar("SOY", spatialFormat.format(workpieceDelta.y - partDelta.y)); writeKMComment("Stock Offset Y"); } else { writeVar("SL", spatialFormat.format(workpieceDelta.x)); writeKMComment("Stock Length"); writeVar("SW", spatialFormat.format(workpieceDelta.y)); writeKMComment("Stock Width"); } writeVar("T", spatialFormat.format(workpieceDelta.z)); writeKMComment("Stock Height"); writeVar("POX", spatialFormat.format(part.lower.x - workpiece.lower.x)); writeKMComment("Part Offset X"); writeVar("POY", spatialFormat.format(part.lower.y - workpiece.lower.y)); writeKMComment("Part Offset Y"); } writeVar("X", 0); writeKMComment(""); writeVar("Y", 0); writeKMComment(""); // workpiece if (workpieceDelta.isNonZero()) { writeln(""); writeln("<100 \\WerkStck\\"); writeVar("LA", "L"); // length of finished part writeVar("BR", "W"); // width of finished part writeVar("DI", "T"); // thickness of stock writeVar("FNX", "POX"); // finished part origin in X writeVar("FNY", "POY"); // finished part origin in Y if (getProperty("stockDefinition") == "size") { writeVar("RL", "SL"); // length of raw piece writeVar("RB", "SW"); // width of raw piece } else { writeVar("AX", "SOX"); // offset in X of finished part writeVar("AY", "SOY"); // offset in Y of finished part } } if (!getProperty("isoOnly")) { var workPlaneID = 4; var id; setFormats(identityWCS); var numberOfSections = getNumberOfSections(); for (var i = 0; i < numberOfSections; ++i) { section = getSection(i); var euler = new Vector(0, 0, 0); var abc = new Vector(0, 0, 0); var origin = new Vector(0, 0, 0); var horizontalDrilling = isDrillingCycle(section) && isPerpto(section.workPlane.forward, new Vector(0, 0, 1)); if (!section.isMultiAxis()) { if (getSawMode(section.getTool()) != SAW_GROOVE) { // saw cuts/horizontal drilling use F0 coordinate system origin = getWorkOrigin(section); euler = section.workPlane.getEuler2(EULER_ZXZ_R); // used for contours abc = getWorkPlaneMachineABC(section.workPlane, false); // used for drilling } } var found = false; for (var j = 0; j < definedWorkPlanes.length; ++j) { if (anglesAreSame(euler, definedWorkPlanes[j].euler) && (euler.isZero() || coordinatesAreSame(origin, definedWorkPlanes[j].origin))) { id = definedWorkPlanes[j].id; found = true; break; } } if (!found) { id = euler.isZero() ? identityWCS : wcsFormat.format(workPlaneID++); if ((id != identityWCS || id == "F0")) { var origin = id == identityWCS ? new Vector(0, 0, 0) : origin; writeln(""); writeln("[K"); writeln("<00 \\Koordinatensystem\\"); writeVar("NR", id); writeVar("XP", xFormat.format(origin.x)); // X-origin writeVar("XF", 1); // X-scale writeVar("YP", yFormat.format(origin.y)); // Y-origin writeVar("YF", 1); // Y-scale writeVar("ZP", zFormat.format(origin.z)); // Z-origin writeVar("ZF", 1); // Z-scale writeVar("D1", eulerFormat.format(euler.x)); // rotation about Z writeVar("KI", eulerFormat.format(euler.y)); // rotation about X' writeVar("D2", eulerFormat.format(euler.z)); // rotation about Z" writeVar("MI", 0); // mirrored } } definedWorkPlanes.push({section:i, id:id, origin:origin, euler:euler, abc:abc, workPlane:section.workPlane}); } } } function onComment(message) { var section = typeof currentSection == "undefined" ? getSection(0) : currentSection; if (section.isMultiAxis() || getProperty("isoOnly")) { writeComment(message); } else { writeSimpleComment(message); } } function parseNumbers(_text, _max) { // extract values between commas var sText1 = _text; var sText2 = new Array(); var retCoord = new Array(); sText2 = sText1.split(","); // too many values, return 0 if (sText2.length > _max) { return retCoord; } // parse numbers for (i = 0; i < sText2.length; i++) { retCoord[i] = parseFloat(sText2[i]); if (isNaN(retCoord[i])) { return new Array(); } } // return number of values return retCoord; } function onParameter(name, value) { if (name == "action") { var sText1 = String(value).toUpperCase(); var sText2 = new Array(); sText2 = sText1.split(":"); if (sText2.length != 2) { error(localize("Invalid action command") + ": " + value); return; } if (sText2[0] == "GROOVEWIDTH") { var num = parseNumbers(sText2[1], 1); if (num.length != 1) { error(localize("Invalid GROOVEWIDTH command" + ": " + value)); return; } grooveWidth = num[0]; } else if (sText2[0] == "APPROACHMODE") { switch (sText2[1]) { case "TANGENT": approachMode = "TAN"; break; case "LATERAL": approachMode = "SEI"; break; case "VERTICAL": approachMode = "SEN"; break; default: error(localize("The APPROACHMODE value must be 'TANGENT', 'LATERAL', or 'VERTICAL'")); return; } } else if (sText2[0] == "EXITMODE") { switch (sText2[1]) { case "TANGENT": exitMode = "TAN_AB"; break; case "LATERAL": exitMode = "SEI_AB"; break; case "VERTICAL": exitMode = "SEN_AB"; break; default: error(localize("The EXITMODE value must be 'TANGENT', 'LATERAL', or 'VERTICAL'")); return; } } else if (sText2[0] == "INSERTDOWEL") { if (sText2[1] == "OFF") { insertDowel = false; } else { var num = parseNumbers(sText2[1], 1); if (num.length != 1) { error(localize("Invalid INSERTDOWEL command" + ": " + value)); return; } dowelDepth = num[0]; insertDowel = true; } } else { error(localize("Unknown Action command") + ": " + value); } } } /** 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(); } function forceFeed() { currentFeedId = undefined; feedOutput.reset(); } /** Force output of X, Y, Z, A, B, C, and F on next output. */ function forceAny() { forceXYZ(); forceABC(); forceFeed(); } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } function cancelWorkPlane() { writeln("#CS OFF"); // cancel frame forceWorkPlane(); } function setWorkPlane(abc, euler) { if (currentSection.isMultiAxis()) { return; // ignore } if (!((currentWorkPlaneABC == undefined) || abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { return; // no change } onCommand(COMMAND_UNLOCK_MULTI_AXIS); /* if (!retracted) { writeRetract(Z); }*/ if (useMultiAxisFeatures) { if (machineConfiguration.isMultiAxisConfiguration() && useABCPrepositioning) { if (euler.isNonZero()) { var origin = getWorkOrigin(currentSection); writeln( "#CS ON[" + xyzFormat.format(origin.x) + "," + xyzFormat.format(origin.y) + "," + xyzFormat.format(origin.z) + "," + eulerFormat.format(euler.z) + "," + eulerFormat.format(euler.y) + "," + eulerFormat.format(euler.x) + "]" ); // set frame } gMotionModal.reset(); var abc1 = getABC(abc); writeBlock( gMotionModal.format(0), conditional(machineConfiguration.isMachineCoordinate(0), "A" + abcFormat.format(abc1.x)), conditional(machineConfiguration.isMachineCoordinate(1), "B" + abcFormat.format(abc1.y)), conditional(machineConfiguration.isMachineCoordinate(2), "C" + abcFormat.format(abc1.z)) ); } } else { var abc1 = getABC(abc); writeBlock( gMotionModal.format(0), conditional(machineConfiguration.isMachineCoordinate(0), "A" + abcFormat.format(abc1.x)), conditional(machineConfiguration.isMachineCoordinate(1), "B" + abcFormat.format(abc1.y)), conditional(machineConfiguration.isMachineCoordinate(2), "C" + abcFormat.format(abc1.z)) ); } onCommand(COMMAND_LOCK_MULTI_AXIS); currentWorkPlaneABC = abc; } var closestABC = false; // choose closest machine angles var currentMachineABC; function getWorkPlaneMachineABC(workPlane, rotate) { // calculate ISO plane if (useISO) { return getWorkPlaneMachineISO(workPlane, rotate); } var W = workPlane; // map to global frame // Workplane angles are between -360 - 360 : Beta=A, Alpha=C var abc = W.getTurnAndTilt(Y, Z); if (abc.y != 0) { abc.setZ(Math.PI + abc.z); // axis rotates in opposite direction, can't specify direction with Turn and Tilt } 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 (eulerFormat.format(abc.z) > 360) { abc.setZ(abc.z - (Math.PI * 2)); } return abc; } function getWorkPlaneMachineISO(workPlane, rotate) { var W = workPlane; // map to global frame var abc = machineConfiguration.getABC(W); if (closestABC) { if (currentMachineABC) { abc = machineConfiguration.remapToABC(abc, currentMachineABC); } else { abc = machineConfiguration.getPreferredABC(abc); } } else { abc = machineConfiguration.getPreferredABC(abc); } try { abc = machineConfiguration.remapABC(abc); currentMachineABC = abc; } catch (e) { error( localize("Machine angles not supported") + ":" + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) ); } var direction = machineConfiguration.getDirection(abc); if (!isSameDirection(direction, W.forward)) { error(localize("Orientation not supported.")); } if (!machineConfiguration.isABCSupported(abc)) { error( localize("Work plane is not supported") + ":" + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) ); } 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; } /** calculates the virtual ABC position from the physical ABC position */ function getABC(_abc) { var axis = machineConfiguration.getDirection(_abc); var both = virtualConfiguration.getABCByDirectionBoth(axis); var abc1 = remapABC(both.first, _abc); var abc2 = remapABC(both.second, _abc); var abc = new Vector(abc1.x, abc1.y, abc1.z); if (Math.abs(abc2.x - _abc.x) < Math.abs(abc1.x - _abc.x)) { abc = new Vector(abc2.x, abc2.y, abc2.z); } if (abcFormat.format(abc.x) == 0) { // protect against C0 when tool is vertical abc.setZ(previousABC.z); } if (!virtualConfiguration.getAxisV().isCyclic()) { if ((radianFormat.getResultingValue(abc.x) < virtualConfiguration.getAxisU().getRange().getMinimum()) || (radianFormat.getResultingValue(abc.x) > virtualConfiguration.getAxisU().getRange().getMaximum())) { error(subst(localize("A%1 is outside of the virtual limits of the machine"), abcFormat.format(abc.x))); return abc; } if ((radianFormat.getResultingValue(abc.z) < virtualConfiguration.getAxisV().getRange().getMinimum()) || (radianFormat.getResultingValue(abc.z) > virtualConfiguration.getAxisV().getRange().getMaximum())) { error(subst(localize("C%1 is outside of the virtual limits of the machine"), abcFormat.format(abc.z))); return abc; } } return abc; } /** calculate the closest virtual C-axis to the physical C-axis position */ function remapABC(_abc, _currentABC) { var abc = new Vector(_abc.x, _abc.y, _abc.z); if (abcFormat.getResultingValue(_abc.x) == 0 && abcFormat.getResultingValue(_abc.z) == 0) { abc.setZ(cOutput.getCurrent()); } var dist = Math.abs(abc.z - _currentABC.z); if (virtualConfiguration.getAxisV().isCyclic() || ((_abc.z + Math.PI * 2) <= virtualConfiguration.getAxisV().getRange().getMaximum())) { var dist1 = Math.abs((_abc.z + Math.PI * 2) - _currentABC.z); if (dist1 < dist) { dist = dist1; abc.setZ(_abc.z + Math.PI * 2); } } if (virtualConfiguration.getAxisV().isCyclic() || ((_abc.z - Math.PI * 2) >= virtualConfiguration.getAxisV().getRange().getMinimum())) { var dist1 = Math.abs((_abc.z - Math.PI * 2) - _currentABC.z); if (dist1 < dist) { dist = dist1; abc.setZ(_abc.z - Math.PI * 2); } } return abc; } function getWorkpieceOffset() { switch (getProperty("wcsOrigin")) { case "F0": partOrigin = part.lower; workpieceOrigin = workpiece.lower; break; case "01": partOrigin = new Vector(part.upper.x, part.lower.y, part.lower.z); workpieceOrigin = new Vector(workpiece.upper.x, workpiece.lower.y, workpiece.lower.z); break; case "02": partOrigin = new Vector(part.upper.x, part.upper.y, part.lower.z); workpieceOrigin = new Vector(workpiece.upper.x, workpiece.upper.y, workpiece.lower.z); break; case "03": partOrigin = new Vector(part.lower.x, part.upper.y, part.lower.z); workpieceOrigin = new Vector(workpiece.lower.x, workpiece.upper.y, workpiece.lower.z); break; } return Vector.diff(partOrigin, workpieceOrigin); } function getWorkOrigin(section) { workpiece = getWorkpiece(); switch (getProperty("wcsOrigin")) { case "F0": // lower left shift = workpiece.lower; break; case "01": // lower right var shift = new Vector(workpiece.upper.x, workpiece.lower.y, workpiece.lower.z); break; case "02": // upper right var shift = new Vector(workpiece.upper.x, workpiece.upper.y, workpiece.lower.z); break; case "03": // upper left var shift = new Vector(workpiece.lower.x, workpiece.upper.y, workpiece.lower.z); break; } var origin = Vector.diff(Vector.diff(section.workOrigin, shift), workpieceOffset); return origin; } function wcsMirrored(wcs) { return { x : (wcs == "01" || wcs == "02") ? -1 : 1, y : (wcs == "02" || wcs == "03") ? -1 : 1, z : 1, mirrored: wcs == "01" || wcs == "03" }; } function setFormats(wcs) { xFormat.setScale(wcsMirrored(wcs).x); yFormat.setScale(wcsMirrored(wcs).y); zFormat.setScale(wcsMirrored(wcs).z); } function isPerpto(a, b) { return Math.abs(Vector.dot(a, b)) < (1e-7); } function onSection() { sawIsActive = getSawMode(tool); compensatedMove = RADIUS_COMPENSATION_OFF; // origin is always at lower left of part, except for 3+2 operations, which use the operation origin workOrigin = getWorkOrigin(currentSection); var forward = currentSection.workPlane.forward; workpiece = getWorkpiece(); var horizontalDrilling = !getProperty("isoOnly") && (getParameter("operation-strategy", "") == "drill") && isPerpto(forward, new Vector(0, 0, 1)); cancelTransformation(); translation = getTranslation(); if (horizontalDrilling) { // horizontal drilling uses TCP coordinates setRotation(currentSection.workPlane); } if (getProperty("shiftOrigin")) { if (horizontalDrilling) { translation = Vector.sum(translation, workOrigin); } else if ((currentSection.isMultiAxis() || getProperty("isoOnly") || sawIsActive == SAW_GROOVE)) { translation = Vector.sum(translation, workOrigin); setRotation(currentSection.workPlane); // TCP mode setTranslation(translation); } else if (isSameDirection(forward, new Vector(0, 0, 1))) { if (getDefinedWorkPlane(getCurrentSectionId()).id == identityWCS) { // F0 coordinate system does not define origin, so a translation must be added translation = Vector.sum(translation, workOrigin); setTranslation(translation); } } else if (getDefinedWorkPlane(getCurrentSectionId()).id != identityWCS) { translation = Vector.sum(translation, Vector.diff(part.lower, partOrigin)); } } useISO = currentSection.isMultiAxis() || getProperty("isoOnly"); tcpActive = true; if (!useISO) { setFormats(getDefinedWorkPlane(currentSection.getId()).id); } var abc = new Vector(0, 0, 0); var abcPlane = new Vector(0, 0, 0); if (useISO) { if (currentSection.isMultiAxis()) { abc = currentSection.getInitialToolAxisABC(); } else { // pure 3D abc = getWorkPlaneMachineABC(currentSection.workPlane, !useMultiAxisFeatures); if (useMultiAxisFeatures) { var euler = currentSection.workPlane.getEuler2(EULER_ZYX_R); abcPlane = new Vector(euler.x, euler.y, euler.z); tcpActive = abc.isZero(); } } redirectToBuffer(); // ISO operations output in onClose along with all other operations var comment = hasParameter("operation-comment") ? getParameter("operation-comment") : ""; var notes = (getProperty("showNotes") && hasParameter("notes")) ? getParameter("notes") : ""; if (comment || notes) { writeln(""); writeln("<101 \\Kommentar\\"); if (comment) { writeKMComment(comment); if (notes) { writeKMComment(""); } } if (notes) { var lines = String(notes).split("\n"); var r1 = new RegExp("^[\\s]+", "g"); var r2 = new RegExp("[\\s]+$", "g"); for (line in lines) { var comment = lines[line].replace(r1, "").replace(r2, ""); if (comment) { writeKMComment(comment); } } } } var initialPosition = getFramePosition(currentSection.getInitialPosition()); var tcpPosition = tcpActive ? initialPosition : currentSection.workPlane.multiply(initialPosition); writeln(""); writeln("<153\\Universal Makro\\"); writeVar("LOCAL", 1); writeVar("XA", xyzFormat.format(tcpPosition.x)); // initial XYZ position writeVar("YA", xyzFormat.format(tcpPosition.y)); writeVar("ZA", xyzFormat.format(tcpPosition.z)); writeVar("WI", abcFormat.format(abc.z)); // initial C-axis rotation writeVar("WZ", tool.number); writeVar("SM", 1); // rpm mode writeVar("S_", integerFormat.format(spindleSpeed)); if (hasParameter("operation:tool_feedCutting")) { writeVar("F_", isoFeedFormat.format(getParameter("operation:tool_feedCutting"))); } writeVar("WWP", 0); // 1 = evaluate woodWOP parameters writeVar("BBA", 0); // 1 = evaluate processing range writeVar("KRI", 0); // 1 = spindle is not orientated perpendicular writeVar("P1", 0); // parameters writeVar("P2", 0); writeVar("P3", 0); writeVar("P4", 0); writeVar("PX1", 0); // operation range writeVar("PY1", 0); writeVar("PX2", 0); writeVar("PY2", 0); writeln(""); writeln("STARTLOCAL"); writeln("L " + getProperty("startRoutine")); if (spindleSpeed != 0) { writeln("\"STRSPINDEL\""); } setSmoothing(SMOOTH_DEFINE); if (tcpActive) { writeln("#RTCP ON"); forceAny(); } else { writeln("#RTCP ON"); // required with #CS plane forceWorkPlane(); setWorkPlane(abc, abcPlane); forceXYZ(); } gMotionModal.reset(); if (tcpActive) { // multi-axis var abc1 = getABC(abc); writeBlock(gMotionModal.format(0), cOutput.format(abc1.z)); writeBlock(gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), aOutput.format(abc1.x)); writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); previousABC = new Vector(abc1.x, abc1.y, abc1.z); } else { // 3 + 2 writeBlock(gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z)); } } else { if (section.getParameter("operation:compensationType") == "wear") { error(localize("Wear compensation is not allowed.")); return; } if (!sawIsActive && !isDrillingCycle()) { if (getProperty("verticalContourMode") == "polygon" && getDefinedWorkPlane(getCurrentSectionId()).id == identityWCS) { isPolygon = true; polygonStart = polygonBuffer.length; } } } } function onSpindleSpeed(spindleSpeed) { if (useISO) { // cannot output spindle speed in the middle of a tpaCAD contour writeVar("S_A", integerFormat.format(spindleSpeed)); } } function onDwell(seconds) { } function onCycle() { } function onCyclePoint(x, y, z) { if (useISO) { expandCyclePoint(x, y, z); } else { cycle.dwell = getParameter("operation:dwellBeforeRetract", 1) ? cycle.dwell : 0; var through = (getProperty("useDrillThrough") && getParameter("operation:drillTipThroughBottom", 0)) || ((cycle.depth + 0.001) >= (workpiece.upper.z - workpiece.lower.z)); machining.push({ id : -1, sectionId : getCurrentSectionId(), p : new Vector(x, y, z), cycle : cycle, type : cycleType, through : through, translation: translation, dowel : insertDowel, dowelDepth : dowelDepth}); } } function onCycleEnd() { if (!cycleExpanded) { zOutput.reset(); } } var pendingRadiusCompensation = -1; var compensatedMove; var firstCompensatedMove; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; compensatedMove = radiusCompensation; firstCompensatedMove = true; } // buffer straight line moves to reduce profile size var linearMove; var linearFeed; var linearDirection; var linearIsBuffered = false; function pushLinear(x, y, z, feed) { // don't output duplicate points var currentPosition = getCurrentPosition(); if ((xyzFormat.getResultingValue(x) == xyzFormat.getResultingValue(currentPosition.x)) && (xyzFormat.getResultingValue(y) == xyzFormat.getResultingValue(currentPosition.y)) && (xyzFormat.getResultingValue(z) == xyzFormat.getResultingValue(currentPosition.z))) { // ignore zero length lines return; } // buffer moves in same direction var dir = Vector.diff(new Vector(x, y, z), getCurrentPosition()).getNormalized(); if (linearIsBuffered) { if (isSameDirection(dir, linearDirection) && feed == linearFeed) { linearMove = new Vector(x, y, z); return; } flushLinear(linearMove.x, linearMove.y, linearMove.z, linearFeed); } // buffer move if next record is linear if (getNextRecord().getType() == RECORD_LINEAR) { linearMove = new Vector(x, y, z); linearFeed = feed; linearDirection = dir; linearIsBuffered = true; } else { flushLinear(x, y, z, feed); } } function flushLinear(x, y, z, feed) { writeln(""); writeln("$E" + entityId); writeln("KL"); writeVal("X", xFormat.format(x)); writeVal("Y", yFormat.format(y)); writeVal("Z", zFormat.format(z)); entityId += 1; linearIsBuffered = false; } function compensationEntryMove() { if (getParameter("operation:compensationType", "computer") != "computer") { if (compensatedMove == RADIUS_COMPENSATION_OFF) { return true; } // ignore first compensation move, it is not part of the lead-in and causes problems with the profile if (firstCompensatedMove) { firstCompensatedMove = false; return true; } } return false; } function onRapid(_x, _y, _z) { if (useISO) { 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.")); return; } setSmoothing(SMOOTH_DISABLE); writeBlock(gMotionModal.format(0), x, y, z); forceFeed(); } return; } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation is not supported.")); return; } if (sawIsActive == SAW_GROOVE) { bufferSawMove(_x, _y, _z, 0); return; } if (isPolygon) { polygonBuffer.push({xyz:new Vector(_x, _y, _z), state:"U"}); return; } if (linearIsBuffered) { flushLinear(linearMove.x, linearMove.y, linearMove.z, linearFeed); } if (inContour) { machining.push({ id : contourId, sectionId: getCurrentSectionId(), entities : entityId, feed : currentFeed, saw : sawIsActive, mda : approachMode, mde : exitMode }); inContour = false; } } function onLinear(_x, _y, _z, feed) { if (useISO) { setSmoothing(SMOOTH_ENABLE); var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(feed); if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: writeBlock(gMotionModal.format(1), x, y, z, f, gFormat.format(41)); break; case RADIUS_COMPENSATION_RIGHT: writeBlock(gMotionModal.format(1), x, y, z, f, gFormat.format(42)); break; default: writeBlock(gMotionModal.format(1), x, y, z, f, gFormat.format(40)); } } 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); } } return; } // ignore all uncompensated moves since compensation is active for the entire operation pendingRadiusCompensation = -1; if (compensationEntryMove()) { return; } if (sawIsActive == SAW_GROOVE) { bufferSawMove(_x, _y, _z, feed); return; } if (isPolygon) { currentFeed = getParameter("operation:tool_feedCutting"); polygonBuffer.push({xyz:new Vector(_x, _y, _z), state:"D"}); entityId += 1; return; } if (!inContour) { writeln(""); contourId += 1; writeln("]" + contourId); entityId = 0; var start = getCurrentPosition(); writeln(""); writeln("$E" + entityId); writeln("KP"); writeVal("X", xFormat.format(start.x)); writeVal("Y", yFormat.format(start.y)); writeVal("Z", zFormat.format(start.z)); writeVal("KO", getDefinedWorkPlane(getCurrentSectionId()).id); entityId += 1; currentFeed = feed; inContour = true; } if ((movement == MOVEMENT_CUTTING) || (movement == MOVEMENT_FINISH_CUTTING)) { currentFeed = feed; } // currentFeed = Math.min(currentFeed, feed); pushLinear(_x, _y, _z, feed); } var sawPositions = new Array(); function getSawMode(tool) { return tool.type == TOOL_MILLING_SLOT ? (getProperty("sawMode") == "contour" ? SAW_CONTOUR : SAW_GROOVE) : SAW_OFF; } function bufferSawMove(x, y, z, feed) { if (sawPositions.length == 0 || xyzFormat.getResultingValue(Vector.diff(new Vector(x, y, z), sawPositions[sawPositions.length - 1].xyz).length)) { sawPositions.push({xyz:new Vector(x, y, z), feed:feed, movement:movement}); } } function flushSawMove() { // break out saw moves var currentPosition = undefined; var sawMoves = new Array(); for (var i = 0; i < sawPositions.length; ++i) { switch (sawPositions[i].movement) { case MOVEMENT_RAPID: currentPosition = sawPositions[i].xyz; break; case MOVEMENT_LEAD_IN: case MOVEMENT_LEAD_OUT: currentPosition = sawPositions[i].xyz; break; case MOVEMENT_CUTTING: case MOVEMENT_FINISH_CUTTING: case MOVEMENT_REDUCED: if (currentPosition == undefined) { currentPosition = sawPositions[i].xyz; } else { sawMoves.push({start:currentPosition, end:sawPositions[i].xyz, feed:sawPositions[i].feed, used:true}); currentPosition = sawPositions[i].xyz; } break; default: currentPosition = sawPositions[i].xyz; break; } } if (false) { // DEBUG for (var i = 0; i < sawMoves.length; ++i) { if (sawMoves.used) { writeDebug(""); writeDebug("start = " + sawMoves[i].start); writeDebug("end = " + sawMoves[i].end); } } } // validate saw moves if (sawMoves.length > 1) { var sawDirection = Vector.diff(sawMoves[0].end, sawMoves[0].start).getNormalized(); for (var i = 1; i < sawMoves.length; ++i) { var moveDirection = Vector.diff(sawMoves[i].end, sawMoves[i].start).getNormalized(); if (xyzFormat.getResultingValue(Vector.diff(sawMoves[i - 1].end, sawMoves[i].start).length) <= toPreciseUnit(0.001, IN)) { if (Vector.diff(moveDirection, sawDirection).length > toPreciseUnit(0.001, IN)) { // saw direction changes error(localize("Saw move changes direction during cut.")); return; } else { // remove saw cuts in same direction sawMoves[i - 1].used = false; sawMoves[i].start = sawMoves[i - 1].start; } } } } // output saw moves writeSawMoves(sawMoves); } function writeSawMoves(sawMoves) { for (var i = 0; i < sawMoves.length; ++i) { if (sawMoves[i].used) { var start = new Vector(sawMoves[i].start.x, sawMoves[i].start.y, sawMoves[i].start.z); var end = new Vector(sawMoves[i].end.x, sawMoves[i].end.y, sawMoves[i].end.z); var forward = currentSection.workPlane.forward; // getRotation().multiply(new Vector(0, 0, 1)); // output points are along edge of cutter var dir = "left"; if (hasParameter("operation:compensationType") && hasParameter("operation:compensation")) { if (getParameter("operation:compensationType") != "control") { var offsetVector = new Vector(0, 0, 0); dir = getParameter("operation:compensation"); var sawDirection = Vector.diff(end, start).getNormalized(); if (dir == "right") { offsetVector = Vector.product(Vector.cross(forward, sawDirection).getNormalized(), (tool.diameter / 2)); } else if (dir == "left") { offsetVector = Vector.product(Vector.cross(sawDirection, forward).getNormalized(), (tool.diameter / 2)); } start = Vector.sum(start, offsetVector); end = Vector.sum(end, offsetVector); } } // output points are at center of blade start = Vector.sum(start, Vector.product(forward, (tool.fluteLength / 2))); end = Vector.sum(end, Vector.product(forward, (tool.fluteLength / 2))); // write out saw operation machining.push({ id : contourId, sectionId : getCurrentSectionId(), entities : entityId, feed : sawMoves[i].feed, saw : sawIsActive, start : start, end : end, cutSide : dir, grooveWidth: (grooveWidth == 0 ? tool.getFluteLength() : grooveWidth), mda : approachMode, mde : exitMode }); } } sawPositions = new Array(); // zero out saw moves } function onRapid5D(_x, _y, _z, _a, _b, _c) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } var abc = getABC(new Vector(_a, _b, _c)); var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(abc.x); var b = bOutput.format(abc.y); var c = cOutput.format(abc.z); if (x || y || z || a || b || c) { setSmoothing(SMOOTH_DISABLE); writeBlock(gMotionModal.format(0), x, y, z, a, b, c); forceFeed(); } previousABC = new Vector(abc.x, abc.y, abc.z); } function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); return; } setSmoothing(SMOOTH_ENABLE); var abc = getABC(new Vector(_a, _b, _c)); var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(abc.x); var b = bOutput.format(abc.y); var c = cOutput.format(abc.z); var f = feedOutput.format(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 forceFeed(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } previousABC = new Vector(abc.x, abc.y, abc.z); } // Start of onRewindMachine logic /***** Be sure to add 'safeRetractDistance' to post getProperty(" ")*****/ var performRewinds = true; // enables the onRewindMachine logic var safeRetractFeed = (unit == IN) ? 20 : 500; var safePlungeFeed = (unit == IN) ? 10 : 250; 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; } /** Retract to safe position before indexing rotaries. */ function moveToSafeRetractPosition(isRetracted) { if (getProperty("homePositionZ") <= getCurrentPosition().z) { error(localize("Z-Home position must be higher than current Z position during a retract and reconfigure.")); return; } writeRetract(Z); } /** Return from safe position after indexing rotaries. */ function returnFromSafeRetractPosition(position, abc) { forceXYZ(); xOutput.reset(); yOutput.reset(); zOutput.reset(); onRapid5D(position.x, position.y, position.z, abc.x, abc.y, abc.z); //zOutput.enable(); //onExpandedRapid(position.x, position.y, position.z); } /** Intersect the point-vector with the stock box. */ function intersectStock(point, direction) { var stock = getWorkpiece(); stock.expandTo(Vector.sum(stock.lower, getTranslation())); stock.expandTo(Vector.sum(stock.upper, getTranslation())); var intersection = stock.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) || (Vector.diff(currentPosition, retractPos).length > tool.getBodyLength())) { 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) { var abc = getABC(new Vector(_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(abc.x) + ", " + abcFormat.format(abc.y) + ", " + abcFormat.format(abc.z) ); 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); writeComment(text); } // Move to retract position var position; if (currentSection.getOptimizedTCPMode() == 0) { position = retractPosition; } else { position = machineConfiguration.getOrientation(getCurrentDirection()).getTransposed().multiply(retractPosition); } onLinear5D(position.x, position.y, position.z, currentABC.x, currentABC.y, currentABC.z, safeRetractFeed); // Cancel so that tool doesn't follow tables //writeBlock(gFormat.format(49), formatComment("TCPC OFF")); // Position to safe machine position for rewinding axes moveToSafeRetractPosition(false); // 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(); // Reinstate // writeBlock(gFormat.format(234), //hFormat.format(tool.lengthOffset), formatComment("TCPC ON")); // Move back to position above part if (currentSection.getOptimizedTCPMode() != 0) { position = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(retractPosition); } returnFromSafeRetractPosition(position, new Vector(_a, _b, _c)); // Plunge tool back to original position if (currentSection.getOptimizedTCPMode() != 0) { currentTool = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(currentTool); } onLinear5D(currentTool.x, currentTool.y, currentTool.z, _a, _b, _c, safePlungeFeed); } // End of onRewindMachine logic function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { if (useISO) { isoCircular(clockwise, cx, cy, cz, x, y, z, feed); return; } if (isPolygon) { linearize(tolerance); return; } // ignore all uncompensated moves since compensation is active for the entire operation if (compensationEntryMove()) { return; } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); return; } if (sawIsActive == SAW_GROOVE) { bufferSawMove(x, y, z, feed); return; } if (linearIsBuffered) { flushLinear(linearMove.x, linearMove.y, linearMove.z, linearFeed); } /* if ((movement != MOVEMENT_CUTTING) && (movement != MOVEMENT_FINISH_CUTTING)) { if (inContour) { machining.push({id:contourId, sectionId:getCurrentSectionId(), entities:entityId, feed:currentFeed}); inContour = false; } return; } */ var KO = getDefinedWorkPlane(getCurrentSectionId()).id; if (!inContour) { writeln(""); writeln("]" + contourId); contourId += 1; entityId = 0; var start = getCurrentPosition(); writeln(""); writeln("$E" + entityId); writeln("KP"); writeVal("X", xFormat.format(start.x)); writeVal("Y", yFormat.format(start.y)); writeVal("Z", zFormat.format(start.z)); writeVal("KO", KO); entityId += 1; currentFeed = feed; inContour = true; } if ((movement == MOVEMENT_CUTTING) || (movement == MOVEMENT_FINISH_CUTTING)) { currentFeed = feed; } // currentFeed = Math.min(currentFeed, feed); switch (getCircularPlane()) { case PLANE_XY: writeln(""); writeln("$E" + entityId); writeln("KA"); writeVal("X", xFormat.format(x)); writeVal("Y", yFormat.format(y)); writeVal("Z", zFormat.format(z)); // var ip = getPositionU(0.5); // writeVal("I", xyzFormat.format(ip.x)); // writeVal("J", xyzFormat.format(ip.y)); // writeVal("K", xyzFormat.format(ip.z)); writeVal("R", rFormat.format(getCircularRadius() + toPreciseUnit(0.002, MM))); // around rounding issue var small = Math.abs(getCircularSweep()) <= Math.PI; clockwise = wcsMirrored(KO).mirrored ? !clockwise : clockwise; if (small) { writeVal("DS", clockwise ? 0 : 1); } else { writeVal("DS", clockwise ? 2 : 3); } entityId += 1; break; default: linearize(tolerance); } } function isoCircular(clockwise, cx, cy, cz, x, y, z, feed) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); return; } var start = getCurrentPosition(); if (isFullCircle()) { if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs linearize(tolerance); return; } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), jOutput.format(cy - start.y), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), kOutput.format(cz - start.z), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y), kOutput.format(cz - start.z), feedOutput.format(feed)); break; default: linearize(tolerance); } } else if (!getProperty("useRadius")) { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y), kOutput.format(cz - start.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(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; default: linearize(tolerance); } } } function onCommand(command) { } function onSectionEnd() { if (useISO) { writeRetract(Z); if (aOutput.getCurrent() != 0) { writeBlock(gMotionModal.format(0), aOutput.format(0)); } if (cOutput.getCurrent() != 0) { writeBlock(gMotionModal.format(0), cOutput.format(0)); } if (tcpActive) { writeln("#RTCP OFF"); } else { cancelWorkPlane(); writeln("#RTCP OFF"); } setSmoothing(SMOOTH_DISABLE); setSmoothing(SMOOTH_RESET); writeln("L " + (getProperty("startRoutine") == "UNCVK40" ? "UNCHK40" : "OUNCHK40")); writeln("ENDLOCAL"); } if (isRedirecting()) { redirectBuffer[redirectIndex] = getRedirectionBuffer(); closeRedirection(); machining.push({id:REDIRECT_ID, index:redirectIndex++}); } else if (sawIsActive == SAW_GROOVE) { flushSawMove(); } else if (inContour) { machining.push({ id : contourId, sectionId: getCurrentSectionId(), entities : entityId, feed : currentFeed, saw : sawIsActive, mda : approachMode, mde : exitMode }); inContour = false; } else if (isPolygon) { machining.push({ id : polygonStart, sectionId: getCurrentSectionId(), entities : polygonBuffer.length - 1, feed : currentFeed, saw : sawIsActive, mda : approachMode, mde : exitMode }); isPolygon = false; } grooveWidth = 0; } /** Output block to do safe retract and/or move to home position. */ function writeRetract() { if (arguments.length == 0) { error(localize("No axis specified for writeRetract().")); return; } var words = []; // store all retracted axes in an array for (var i = 0; i < arguments.length; ++i) { let instances = 0; // checks for duplicate retract calls for (var j = 0; j < arguments.length; ++j) { if (arguments[i] == arguments[j]) { ++instances; } } if (instances > 1) { // error if there are multiple retract calls for the same axis error(localize("Cannot retract the same axis twice in one line")); return; } switch (arguments[i]) { case X: if (!machineConfiguration.hasHomePositionX()) { error(localize("A home position has not been defined in X.")); return; } words.push(xOutput.format(machineConfiguration.getHomePositionX())); break; case Y: if (!machineConfiguration.hasHomePositionY()) { error(localize("A home position has not been defined in Y.")); return; } words.push(yOutput.format(machineConfiguration.getHomePositionY())); break; case Z: if (getProperty("homePositionZ") > getCurrentPosition().z) { words.push(zOutput.format(getProperty("homePositionZ"))); retracted = true; // specifies that the tool has been retracted to the safe plane } break; default: error(localize("Bad axis specified for writeRetract().")); return; } } if (words.length > 0) { writeBlock(gMotionModal.format(0), words); // retract } } function writeDrillBlock(m, wpData, tool) { var forward = wpData.workPlane.forward; var horizontalDrilling = isPerpto(forward, new Vector(0, 0, 1)); var KO = horizontalDrilling ? identityWCS : wpData.id; setFormats(KO); if (isSameDirection(forward, new Vector(0, 0, 1)) || isSameDirection(forward, new Vector(0, 0, -1))) { // XY drilling operation var BM = (m.type == "chip-breaking" || m.type == "deep-drilling") ? "BMR" : (m.through ? "LSL" : "LS"); if (isSameDirection(forward, new Vector(0, 0, -1))) { m.p = wpData.workPlane.multiply(m.p); BM += "U"; } writeln("<102 \\BohrVert\\"); writeVar("XA", xFormat.format(m.p.x)); writeVar("YA", yFormat.format(m.p.y)); if (xyzFormat.getResultingValue(m.cycle.stock - part.upper.z) != 0 || xyzFormat.getResultingValue(part.upper.z - workpiece.upper.z)) { writeVar("ZA", zFormat.format(m.cycle.stock + m.translation.z)); // requires absolute value } if (m.type == "chip-breaking" || m.type == "deep-drilling") { writeVar("ZT", xyzFormat.format(m.cycle.incrementalDepth)); writeVar("RM", m.type == "chip-breaking" ? "@" + xyzFormat.format(m.cycle.chipBreakDistance) : xyzFormat.format(m.cycle.retract - m.cycle.stock)); } if (m.cycle.dwell > 0 || (m.type == "chip-breaking" || m.type == "deep-drilling")) { writeVar("VW", m.cycle.dwell); } writeVar("BM", BM); writeVar("TI", xyzFormat.format(m.cycle.depth)); if (getProperty("useBoreToolNumber")) { writeVar("TNO", tool.number); } else { writeVar("DU", spatialFormat.format(tool.diameter)); } writeVar("F_", getProperty("useBoreFeeds") ? feedFormat.format(m.cycle.feedrate) : "STANDARD"); if (KO != "F0") { writeVar("KO", KO); } } else if (isPerpto(forward, new Vector(0, 0, 1))) { // horizontal drilling var BM; var WI = ""; if (isSameDirection(forward, new Vector(1, 0, 0))) { BM = wcsMirrored(KO).x > 0 ? "XM" : "XP"; } else if (isSameDirection(forward, new Vector(-1, 0, 0))) { BM = wcsMirrored(KO).x > 0 ? "XP" : "XM"; } else if (isSameDirection(forward, new Vector(0, 1, 0))) { BM = wcsMirrored(KO).y > 0 ? "YM" : "YP"; } else if (isSameDirection(forward, new Vector(0, -1, 0))) { BM = wcsMirrored(KO).y > 0 ? "YP" : "YM"; } else { BM = "C"; var angle = wpData.abc.z; var mirrored = wcsMirrored(KO); if (mirrored.x == -1) { angle = mirrored.y == 1 ? angle = toRad(180) - angle : toRad(180) + angle; } else if (mirrored.y == -1) { angle = -angle; } var WI = eulerFormat.format(angle); } var BM2 = (m.type == "chip-breaking" || m.type == "deep-drilling") ? "BMR" : "STD"; m.p = Vector.sum(m.p, Vector.product(forward, m.cycle.depth)); var xyz = Vector.sum(m.p, m.translation); writeln("<103 \\BohrHoriz\\"); writeVar("XA", xFormat.format(xyz.x)); writeVar("YA", yFormat.format(xyz.y)); writeVar("ZA", zFormat.format(xyz.z)); writeVar("BM", BM); writeVar("BM2", BM2); if (WI) { writeVar("WI", WI); } if (m.type == "chip-breaking" || m.type == "deep-drilling") { writeVar("ZT", xyzFormat.format(m.cycle.incrementalDepth)); writeVar("RM", m.type == "chip-breaking" ? "@" + xyzFormat.format(m.cycle.chipBreakDistance) : xyzFormat.format(m.cycle.retract - m.cycle.stock)); } if (m.cycle.dwell > 0 || (m.type == "chip-breaking" || m.type == "deep-drilling")) { writeVar("VW", m.cycle.dwell); } writeVar("TI", xyzFormat.format(m.cycle.depth)); if (getProperty("useBoreToolNumber")) { writeVar("TNO", tool.number); } else { writeVar("DU", spatialFormat.format(tool.diameter)); } writeVar("F_", getProperty("useBoreFeeds") ? feedFormat.format(m.cycle.feedrate) : "STANDARD"); if (KO != "F0") { writeVar("KO", KO); } } else { // 3+2 drilling operation var BM = (m.type == "chip-breaking" || m.type == "deep-drilling") ? "BMR" : "STD"; m.p.setZ(m.p.z + m.cycle.depth); var xyz = m.p; // wpData.workPlane.multiply(m.p); writeln("<104 \\BohrUniv\\"); writeVar("XA", xyzFormat.format(xyz.x)); writeVar("YA", xyzFormat.format(xyz.y)); writeVar("ZA", xyzFormat.format(xyz.z)); writeVar("BM", BM); // writeVar("CA", eulerFormat.format(wpData.abc.z)); // writeVar("WI", eulerFormat.format(wpData.abc.y)); if (m.type == "chip-breaking" || m.type == "deep-drilling") { writeVar("ZT", xyzFormat.format(m.cycle.incrementalDepth)); writeVar("RM", m.type == "chip-breaking" ? "@" + xyzFormat.format(m.cycle.chipBreakDistance) : xyzFormat.format(m.cycle.retract - m.cycle.stock)); } if (m.cycle.dwell > 0 || (m.type == "chip-breaking" || m.type == "deep-drilling")) { writeVar("VW", m.cycle.dwell); } writeVar("TI", xyzFormat.format(m.cycle.depth)); if (getProperty("useBoreToolNumber")) { writeVar("TNO", tool.number); } else { writeVar("DU", spatialFormat.format(tool.diameter)); } writeVar("F_", getProperty("useBoreFeeds") ? feedFormat.format(m.cycle.feedrate) : "STANDARD"); writeVar("KO", KO); } // insert dowel if (m.dowel) { if (xyzFormat.getResultingValue(m.dowelDepth) > xyzFormat.getResultingValue(m.cycle.depth)) { error(subst(localize("The dowel depth of %1 is greater than the drilling depth of %2"), xyzFormat.getResultingValue(m.dowelDepth), xyzFormat.getResultingValue(m.cycle.depth))); } writeln(""); writeln("<139 \\Komponente\\"); writeVar("IN", "ABD_ENU.MPR"); writeVar("XA", "0.0"); writeVar("YA", "0.0"); writeVar("ZA", "0.0"); writeVar("EM", "0.0"); writeVar("VA", "Edge 2"); writeVar("VA", "Pos " + xyzFormat.format(m.dowelDepth)); writeVar("VA", "ZPos " + xyzFormat.format(xyz.z)); writeVar("VA", "Diameter " + spatialFormat.format(tool.diameter)); writeVar("VA", "depth " + xyzFormat.format(m.cycle.depth)); writeVar("VA", "dowel 1"); writeVar("VA", "glue 1"); writeVar("VA", "number 1"); writeVar("VA", "grid 0"); writeVar("VA", "center 0"); writeVar("VA", "inch 0"); writeVar("VA", "KAT=Komponentenmakro"); writeVar("MNM", "ABD_ENU"); writeVar("ORI", ""); writeVar("KO", KO); } } function writeContourBlock(m, wpData, tool) { var forward = wpData.workPlane.forward; var section = getSection(wpData.section); var wrk = "NOWRK"; if (section.getParameter("operation:compensationType") == "control") { wrk = section.getParameter("operation:compensation") == "left" ? "WRKL" : "WRKR"; } if (wpData.id == identityWCS) { // vertical contour writeln("<105 \\Konturfraesen\\"); writeVar("EA", m.id + ":" + 0); writeVar("MDA", m.mda); writeVar("EE", m.id + ":" + (m.entities - 1)); writeVar("MDE", m.mde); writeVar("RK", wrk); writeVar("TNO", tool.number); writeVar("ZA", "@0"); // ignore all Z in program writeVar("F_", feedFormat.format(m.feed)); writeVar("SM", 1); // rpm if (getProperty("useSmoothing")) { writeVar("KG", 2); // 0 = off, 1 = Contour mode, 2 = Bspline Mode writeVar("MBA", spatialFormat.format(getProperty("smoothingPathDev"))); writeVar("MWA", spatialFormat.format(getProperty("smoothingTrackDev"))); } writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour } else if (Math.abs(Vector.dot(forward, new Vector(0, 0, 1))) < 1e-7) { // horizontal contour writeln("<133 \\Horizontal Konturfraesen\\"); writeVar("EA", m.id + ":" + 0); writeVar("MDA", m.mda); writeVar("RK", wrk); writeVar("EE", m.id + ":" + (m.entities - 1)); writeVar("MDE", m.mde); writeVar("EM", 0); writeVar("RI", 1); writeVar("TNO", tool.number); writeVar("SM", 1); // rpm writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour writeVar("F_", feedFormat.format(m.feed)); writeVar("AB", 0); // distance to programmed contour writeVar("ZM", "@0"); // Z-mass if (getProperty("useSmoothing")) { writeVar("KG", 2); // 0 = off, 1 = Contour mode, 2 = Bspline Mode writeVar("MBA", spatialFormat.format(getProperty("smoothingPathDev"))); writeVar("MWA", spatialFormat.format(getProperty("smoothingTrackDev"))); } } else { // 3+2 contour writeln("<140 \\Vektor Konturfraesen\\"); writeVar("EA", m.id + ":" + 0); writeVar("MDA", m.mda); writeVar("RK", wrk); writeVar("EE", m.id + ":" + (m.entities - 1)); writeVar("MDE", m.mde); writeVar("EM", 0); writeVar("RI", 1); writeVar("TNO", tool.number); writeVar("SM", 1); // rpm writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour writeVar("F_", feedFormat.format(m.feed)); writeVar("AB", 0); // distance to programmed contour writeVar("ZM", "@0"); // Z-mass if (getProperty("useSmoothing")) { writeVar("KG", 2); // 0 = off, 1 = Contour mode, 2 = Bspline Mode writeVar("MBA", spatialFormat.format(getProperty("smoothingPathDev"))); writeVar("MWA", spatialFormat.format(getProperty("smoothingTrackDev"))); } } } function writePolygonBlock(m, wpData, tool) { var section = getSection(wpData.section); var range = section.getBoundingBox(); var wrk = "NOWRK"; if (section.getParameter("operation:compensationType") == "control") { wrk = section.getParameter("operation:compensation") == "left" ? "WRKL" : "WRKR"; } writeln("<119 \\Polygonzug\\"); writeVar("NM", polygonStart++); writeVar("LOCAL", 1); writeVar("MT", 0); writeVar("XA", ((range.upper.x - range.lower.x) / 2)); writeVar("YA", ((range.upper.y - range.lower.y) / 2)); writeVar("BR", xFormat.format(range.upper.x - range.lower.x)); writeVar("HE", yFormat.format(range.upper.y - range.lower.y)); writeVar("ZA", "0"); // ignore all Z in program writeVar("WI", 0); writeVar("TI", 0); // z-values are contained in xyz moves writeVar("RK", wrk); writeVar("WZ", tool.number); writeVar("F_", feedFormat.format(m.feed)); writeVar("SM", 1); // rpm writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour writeln("STARTLOCAL"); writeln("SIZE" + " X" + xFormat.format(range.upper.x - range.lower.x) + " Y" + yFormat.format(range.upper.y - range.lower.y)); var state = undefined; var saveShowSequenceNumbers = getProperty("showSequenceNumbers"); setProperty("showSequenceNumbers", false); for (var i = m.id; i <= m.entities; ++i) { if (polygonBuffer[i].state != state) { writeln(polygonBuffer[i].state); state = polygonBuffer[i].state; } writeBlock(xOutput.format(polygonBuffer[i].xyz.x), yOutput.format(polygonBuffer[i].xyz.y), zOutput.format(polygonBuffer[i].xyz.z)); } setProperty("showSequenceNumbers", saveShowSequenceNumbers); } function writeSawContour(m, wpData, tool) { writeln("<193 \\Kontursaegen\\"); writeVar("EA", m.id + ":" + (m.entities > 2 ? 1 : 0)); writeVar("MDA", m.mda); writeVar("EE", m.id + ":" + (m.entities - 1)); writeVar("MDE", m.mde); writeVar("RK", "NOWRK"); writeVar("TNO", tool.number); writeVar("ZM", spatialFormat.format(tool.getFluteLength())); writeVar("Z_", "0"); writeVar("ZA", "0"); // ignore all Z in program writeVar("BL", tool.coolant == "COOLANT_AIR" ? "1" : "0"); // blow-off sprayer control writeVar("RI", "1"); // forward along contour writeVar("F_", feedFormat.format(m.feed)); writeVar("SM", 1); // rpm writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour writeVar("F_Z", "0"); writeVar("AB", "0"); writeVar("VLS", "0"); writeVar("VLE", "0"); writeVar("HP", "0"); writeVar("SP", "0"); writeVar("YVE", "0"); writeVar("ASG", "0"); writeVar("RP", "STANDARD"); } function writeSawGroove(m, wpData, tool) { setFormats(wpData.id); var abc = getWorkPlaneMachineABC(wpData.workPlane, false); if (abcFormat.format(abc.y) == 0) { error(localize("Horizontal saw cuts are not supported when using Grooving macros.")); return; } var angled = abcFormat.format(abc.y) != 90; writeln(angled ? "<124 \\groove_R\\" : "<109 \\grooveen\\"); writeVar("XA", xFormat.format(m.start.x)); writeVar("YA", yFormat.format(m.start.y)); writeVar("XE", xFormat.format(m.end.x)); writeVar("YE", yFormat.format(m.end.y)); writeVar("AN", 0); writeVar("NB", xyzFormat.format(m.grooveWidth)); // groove width writeVar("RK", "NOWRK"); if (angled) { writeVar("WI", abcFormat.format(abc.y)); } writeVar("EM", "MOD1"); // writeVar("VZ", Math.min(m.start.z, m.end.z)); // scoring Z-level // writeVar("MV", m.cutSide == "right" ? "GGL" : "GL"); var z = Math.min(m.start.z, m.end.z); if (angled) { writeVar("Z_", zFormat.format(z)); } else { writeVar("TI", zFormat.format(partDelta.z - z + (workpiece.upper.z - part.upper.z))); } writeVar("MN", m.cutSide == "right" ? "GGL" : "GL"); writeVar("OP", 0); writeVar("T_", tool.number); writeVar("F_", feedFormat.format(m.feed)); writeVar("SM", 1); // rpm writeVar("S_A", integerFormat.format(tool.spindleRPM)); // use cutting speed, cannot output spindle speed in the middle of a contour writeVar("KO", wpData.id); } function onClose() { polygonStart = 0; for (var i = 0; i < machining.length; ++i) { var m = machining[i]; var tool = 0; var wpData; if (m.id != REDIRECT_ID) { wpData = getDefinedWorkPlane(m.sectionId); tool = getSection(m.sectionId).getTool(); } writeln(""); if (m.id == REDIRECT_ID) { write(redirectBuffer[m.index]); } else if (m.id < 0) { writeDrillBlock(m, wpData, tool); } else if (m.saw == SAW_CONTOUR) { writeSawContour(m, wpData, tool); } else if (m.saw == SAW_GROOVE) { writeSawGroove(m, wpData, tool); } else if (getProperty("verticalContourMode") == "polygon" && wpData.id == identityWCS) { writePolygonBlock(m, wpData, tool); } else { writeContourBlock(m, wpData, tool); } } writeln(""); writeln("<101 \\Kommentar\\"); if (programName) { writeKMComment(programName); } if (programComment) { writeKMComment(programComment); } writeVar("KAT", "Kommentar"); writeVar("MNM", "Kommentar"); writeln("!"); }