/** Copyright (C) 2012-2021 by Autodesk, Inc. All rights reserved. Flow waterjet post processor configuration. $Revision: 44117 463fd7c2dd9948f82fbd288395b22f549b778dc5 $ $Date: 2023-05-17 14:08:01 $ FORKID {F61954EF-5A29-4B93-93E7-870BC2786880} */ description = "Flow Waterjet ORD"; vendor = "Flow"; vendorUrl = "http://www.flowwaterjet.com"; legal = "Copyright (C) 2012-2021 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45702; longDescription = "Post for Flow Waterjets using software Version 5 or 6. V5=2-axis, V6=3-axis. " + "V5: Manually set nozzle height. V6: Nozzle height in NC program set by Top Height attribute. " + EOL + "Feed percentage set by Cutting Mode quality in tool dialog (auto=60, high=20, medium=40, low=100)"; extension = "ORD"; setCodePage("ascii"); capabilities = CAPABILITY_JET; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(90); allowHelicalMoves = false; allowedCircularPlanes = 1 << PLANE_XY; // allow only XY circular motion // formatVersion: // version 6 should be user selectable, but now use version 5 // version 5 does not have z moves, so it will be safer for inexperienced users // version 5 does not have the mysterious parameter after the cutter comp value properties = { useHSMFeedrates: { title : "Use HSM feedrates", description: "Specifies whether to output the feedrates from HSM.", group : "preferences", type : "boolean", value : false, scope : "post" }, maximumFeedrateIPM: { title : "Maximum feedrate (IPM)", description: "Sets the maximum feedrate in IPM.", group : "preferences", type : "integer", value : 700, scope : "post" }, formatVersion: { title : "Flow control software version", description: "V5 outputs XY, V6 outputs XYZ", group : "configuration", type : "enum", values : [ {title:"V5", id:"5"}, {title:"V6", id:"6"} ], value: "5", scope: "post" } }; // use fixed width instead var xyzFormat = createFormat({decimals:4, trim:false}); var integerFormat = createFormat({decimals:0}); // fixed settings var thickness = 0; var arcCounter = 0; var lineCounter = -1; // collected state var useVersion6 = false; var arcFinish = undefined; // center compensation var _compensationOffset = 0; var etchOperation = false; // though-cut unless set to true var forceOutput = false; /** Writes the specified block. */ function writeBlock() { writeWords(arguments); } var FIELD = " "; /** Make sure fields are aligned. */ function f(text) { var length = text.length; if (length > 10) { return text; } return FIELD.substr(0, 10 - length) + text; } /** Make sure fields are aligned. */ function fi(text, size) { var length = text.length; if (length > size) { return text; } return FIELD.substr(0, size - length) + text; } function onOpen() { useVersion6 = getProperty("formatVersion") == "6"; unit = IN; // only inch mode is supported redirectToBuffer(); // buffer the entire program to be able to count the linear and circular moves setWordSeparator(""); { // stock - workpiece var workpiece = getWorkpiece(); var delta = Vector.diff(workpiece.upper, workpiece.lower); if (delta.isNonZero()) { // thickness = (workpiece.upper.z - workpiece.lower.z); } } if (getNumberOfSections() > 0) { var firstSection = getSection(0); var remaining = firstSection.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); return; } setRotation(remaining); if (!useVersion6) { var originZ = firstSection.getGlobalZRange().getMinimum(); // the cutting depth of the first section for (var i = 0; i < getNumberOfSections(); ++i) { var section = getSection(i); var z = section.getGlobalZRange().getMinimum(); // contour Z of the each section if (xyzFormat.getResultingValue(z) != xyzFormat.getResultingValue(originZ)) { error(localize("You are trying to machine at multiple depths which is not allowed.")); return; } } } } forceOutput = true;// force out first line } function onSection() { var remaining = currentSection.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); return; } setRotation(remaining); etchOperation = false; if (currentSection.getType() == TYPE_JET) { switch (tool.type) { case TOOL_WATER_JET: break; default: error(localize("The CNC does not support the required tool.")); return; } switch (currentSection.jetMode) { case JET_MODE_THROUGH: break; case JET_MODE_ETCHING: etchOperation = true; break; case JET_MODE_VAPORIZE: error(localize("Vaporize is not supported by the CNC.")); return; default: error(localize("Unsupported cutting mode.")); return; } } else if (currentSection.getType() == TYPE_MILLING) { warning(localize("Milling toolpath will be used as waterjet through-cutting toolpath.")); } else { error(localize("CNC doesn't support the toolpath.")); return; } var initialPosition = getFramePosition(currentSection.getInitialPosition()); onExpandedRapid(initialPosition.x, initialPosition.y, initialPosition.z); } function onParameter(name, value) { } function writeLinear(x, y, z, feed, column7) { var flag = false; if (useVersion6) { flag = xyzFormat.areDifferent(x, getCurrentPosition().x) || xyzFormat.areDifferent(y, getCurrentPosition().y) || xyzFormat.areDifferent(z, getCurrentPosition().z); } else { flag = xyzFormat.areDifferent(x, getCurrentPosition().x) || xyzFormat.areDifferent(y, getCurrentPosition().y); } if (flag || forceOutput) { if (useVersion6) { writeBlock( f(xyzFormat.format(x)), ",", f(xyzFormat.format(y)), ",", f(xyzFormat.format(z)), ",", fi(integerFormat.format(0), 2), ",", // linear fi(integerFormat.format(feed), 5), ",", fi(integerFormat.format(_compensationOffset), 2), ",", // left, center, right fi(integerFormat.format(column7), 2) // TAG: seen -2..2 - unknown ); } else { writeBlock( f(xyzFormat.format(x)), ",", f(xyzFormat.format(y)), ",", fi(integerFormat.format(0), 2), ",", fi(integerFormat.format(feed), 5), ",", fi(integerFormat.format(_compensationOffset), 2) ); } ++lineCounter; forceOutput = false; } } function finishArcs() { if (arcFinish) { // complete circular motion with output of destination values forceOutput = true; writeLinear(arcFinish.x, arcFinish.y, arcFinish.z, arcFinish.feed, 2); arcFinish = undefined; } } function onRapid(x, y, z) { finishArcs(); writeLinear(x, y, z, 0, 0); // non-cutting } function onLinear(x, y, z, feed) { finishArcs(); // skip output if next move is an arc. OnCircular record has this move destination XY if (getNextRecord().getType() != RECORD_CIRCULAR) { writeLinear(x, y, z, power ? getFeedInPercent(feed) : 0, 2); } } function onPower(power) { } function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { // spirals are not allowed - arcs must be < 360deg // fail if radius compensation is changed for circular move // syntax is; start X, start y, arc direction, feed, comp, cx, cy // end X, end Y, if following move is an arc, is the start x, start y, of the line // end X, end Y, if following move is a line, is output in OnLinear // using the arcFinish flag circularICode = (clockwise ? 1 : -1); if ((getCircularPlane() != PLANE_XY) || isHelical()) { linearize(tolerance); } var p = getCurrentPosition(); if (useVersion6) { writeBlock( f(xyzFormat.format(p.x)), ",", f(xyzFormat.format(p.y)), ",", f(xyzFormat.format(p.z)), ",", fi(integerFormat.format(circularICode), 2), ",", // arc cw/ccw fi(integerFormat.format(power ? getFeedInPercent(feed) : 0), 5), ",", fi(integerFormat.format(_compensationOffset), 2), ",", // left, center, right fi(integerFormat.format(2), 2), ",", // TAG: seen -2..2 - unknown f(xyzFormat.format(cx)), ",", f(xyzFormat.format(cy)), ",", f(xyzFormat.format(0)) // PLANE_XY only ); } else { writeBlock( f(xyzFormat.format(p.x)), ",", f(xyzFormat.format(p.y)), ",", fi(integerFormat.format(circularICode), 2), ",", // arc cw/ccw fi(integerFormat.format(power ? getFeedInPercent(feed) : 0), 5), ",", fi(integerFormat.format(_compensationOffset), 2), ",", // left, center, right f(xyzFormat.format(cx)), ",", f(xyzFormat.format(cy)) ); } ++arcCounter; // save destination values to complete arc move arcFinish = {x:x, y:y, z:z, feed:(power ? getFeedInPercent(feed) : 0)}; } function getFeedInPercent(feed) { var feedPercent; if ((getProperty("maximumFeedrateIPM") > 0) && getProperty("useHSMFeedrates")) { // use HSM feedrates // 1 - 99 % feedPercent = Math.min(Math.ceil(Math.min(getProperty("maximumFeedrateIPM"), feed) / getProperty("maximumFeedrateIPM") * 100), 99); } else { // use fixed feedrates per quality selection switch (currentSection.quality) { case 1: // high quality feedPercent = 20; // very slow, cut surface excellent break; case 2: feedPercent = 40; // slow, cut surface good break; case 3: feedPercent = 100; // fast, cut surface slightly rough break; default: // medium quality feedPercent = 60; // moderate, cut surface moderate } } return feedPercent; } function onRadiusCompensation() { switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: _compensationOffset = -1; break; case RADIUS_COMPENSATION_RIGHT: _compensationOffset = 1; break; default: _compensationOffset = 0; // center compensation } } function onCycle() { error(localize("Canned cycles are not supported.")); } function onSectionEnd() { finishArcs(); _compensationOffset = 0; // center compensation } function onClose() { if (isRedirecting()) { var mainProgram = getRedirectionBuffer(); // TAG: no need for redirection closeRedirection(); writeln("// This file was created by FlowMaster(R), which is proprietary to Flow International Corporation. " + lineCounter + " " + arcCounter); if (useVersion6) { writeln("VER 6.00"); } writeln("// Created by Autodesk HSM"); if (programComment) { writeln("// " + programComment); } write(mainProgram); } } function setProperty(property, value) { properties[property].current = value; }