Перейти к публикации

Вопрос по CAM обработке в инвентор


Elenaa

Рекомендованные сообщения

Вопрос такой. Делаю в Инвентор Кам обработку для станка с ЧПУ. Станок гравировальный. Обработкой пользуюсь в основном: Карман и HSM и Контурная. Начались смещения в работе станка одной программы. В Симуляции управляющей программы просматриваю все хорошо по центрам. Но со станка выходит смещение. Скажите на какие параметры обратить внимание при обработке в Инвентор?

Ссылка на сообщение
Поделиться на других сайтах
  • 7 месяцев спустя...


UnPinned posts

Здравствуйте! Имеется станок DMC DL6 TMH но постпроцессор не выводит нужную "шапку" для работы программы на станке.

выводит вот так

Скрытый текст

%
O1001
G98 G18
G21
G50 S3500
G53 G0 Y0.
G28 U0.
G0 Z200.


N8
(???????10 2)
T808
G50 S3500
G99
G96 S140 M3 P11
G54
M8
G0 Z5.4
X40.
Z-5.675
X11.819
G1 X8.748 F1.
X5.919 Z-7.089
X2.829 Z-13.979 F0.1
G18 G2 X2.8 Z-14.111 R0.6
G1 Z-23.667
G2 X3.04 Z-24.027 R0.6
G1 X5.74 Z-25.827
G3 X6.1 Z-26.367 R0.9
G1 Z-26.6
X8.928 Z-25.186 F1.
X9.595
G0 X40.
Z5.4

M9
M5 P11
M5 P12
M34
G53 Y0.
G28 U0.
G0 Z200.
G53 G0 Y0.

M30
%
 

 

 

а нужно вот так 

Скрытый текст

%
O0001
M52
(-------------------)
(STROKA BEZOPASNOSTI)
G40G97G21G80G18G90G99
(VIHOD V TOCHKU SMENI INSTRUMENTA) 
G28U0
G28W0
(OTMENA V CONST+UST SIST KOORD+INSTR)
G50S3000
G59T0202 
G96S100M3
G0 Z5.
M8

G0 Z5.4
X40.
Z-5.675
X11.819
G1 X8.748 F1.
X5.919 Z-7.089
X2.829 Z-13.979 F0.1
G18 G2 X2.8 Z-14.111 R0.6
G1 Z-23.667
G2 X3.04 Z-24.027 R0.6
G1 X5.74 Z-25.827
G3 X6.1 Z-26.367 R0.9
G1 Z-26.6
X8.928 Z-25.186 F1.
X9.595
G0 X40.
Z5.4

G28U0M09 
G28W0
(OTMENA KORREKCII INSTR) 
G97
M99
%

 

 

при нажатии "открыть конфиг" в инвенторе - выдает такой код постпроцессора

Скрытый текст

/**
  Copyright (C) 2012-2013 by Autodesk, Inc.
  All rights reserved.

  FANUC Mill Lathe post processor configuration.

  $Revision: 34065 $
  $Date: 2013-04-03 12:35:41 +0200 (on, 03 apr 2013) $

  FORKID {14D60AD3-4366-49dc-939C-4DB5EA48FF68}
*/

//setWriteStack(true); // tells which functions are called for each NC block
//setWriteInvocations(true); // tells which entry functions are called  

description = "Fanuc Mill-Turn";
vendor = "Autodesk, Inc.";
vendorUrl = "http://www.autodesk.com";
legal = "Copyright (C) 2012-2014 by Autodesk, Inc.";
certificationLevel = 2;
minimumRevision = 24000;

extension = "nc";
programNameIsInteger = true;
setCodePage("ascii");

capabilities = CAPABILITY_MILLING | CAPABILITY_TURNING;
tolerance = spatial(0.002, MM);

minimumChordLength = spatial(0.01, MM);
minimumCircularRadius = spatial(0.01, MM);
maximumCircularRadius = spatial(1000, MM);
minimumCircularSweep = toRad(0.01);
maximumCircularSweep = toRad(120);
allowHelicalMoves = false;
allowedCircularPlanes = undefined; // allow any circular motion
allowSpiralMoves = true;
highFeedrate = (unit == IN) ? 100 : 8000;

// user-defined properties
properties = {
  writeMachine: false, // write machine
  writeTools: false, // writes the tools
  preloadTool: false, // preloads next tool on tool change if any
  showSequenceNumbers: false, // show sequence numbers
  sequenceNumberStart: 10, // first sequence number
  sequenceNumberIncrement: 1, // increment for sequence numbers
  optionalStop: true, // optional stop
  separateWordsWithSpace: true, // specifies that the words should be separated with a white space
  useRadius: true, // specifies that arcs should be output using the radius (R word) instead of the I, J, and K words.
  maximumSpindleSpeed: 3500, // specifies the maximum spindle speed
  useParametricFeed: false, // specifies that feed should be output using Q values
  showNotes: false, // specifies that operation notes should be output.
  useCycles: true, // specifies that drilling cycles should be used.
  G53HomePosition_X: 0, // Home position for X-axis
  G53HomePosition_Y: 0, // Home position for Y-axis
  G53HomePosition_Z: 200, // Home position for Z-axis
  G53HomePositionSub_Z: 0, //Home Position for Z when the operation uses the Secondary Spindle 
  gotPartCatcher: false,  // specifies if the machine has a part catcher
  useTailStock: false,  // specifies to use the tailstock or not
  gotChipConveyor: false // specifies to use a chip conveyor Y/N
  //transBClearance: -5, // Stock Transfer B clearance plane - First Position relative to B offset 
  //transBPosition: -7, //Stock Transfer B position plane - Position on Part relative to B offset 
  //transFeedrate: 75 //Stock Transfer Feedrate 
  //synchronousStockTransfer: false // G199/G198, cannot create proper synchronous transfer data with current UI
};

var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-";

var gFormat = createFormat({prefix:"G", decimals:0});
var mFormat = createFormat({prefix:"M", decimals:0});

var spatialFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:2}); // diameter mode & IS SCALING POLAR COORDINATES
var yFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var zFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var rFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); // radius
var qFormat = createFormat({forceDecimal:false,decimals:0, scale:1000});
var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG});
var cFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG, cyclicLimit:Math.PI*2});
var feedFormat = createFormat({decimals:(unit == MM ? 2 : 3), forceDecimal:true});
var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true});
var toolFormat = createFormat({decimals:0,width:2, zeropad:true});
var rpmFormat = createFormat({decimals:0});
var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999
var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999
var taperFormat = createFormat({decimals:1, scale:DEG});

var xOutput = createVariable({prefix:"X"}, xFormat);
var yOutput = createVariable({prefix:"Y"}, yFormat);
var zOutput = createVariable({prefix:"Z"}, zFormat);
var aOutput = createVariable({prefix:"A"}, abcFormat);
var bOutput = createVariable({prefix:"B"}, abcFormat);
var cOutput = createVariable({prefix:"C"}, cFormat);
var feedOutput = createVariable({prefix:"F"}, feedFormat);
var pitchOutput = createVariable({prefix:"F", force:true}, pitchFormat);
var sOutput = createVariable({prefix:"S", force:true}, rpmFormat);
var pOutput = createVariable({prefix:"P", force:true}, rpmFormat);

// circular output
var iOutput = createReferenceVariable({prefix:"I", force:true}, spatialFormat);
var jOutput = createReferenceVariable({prefix:"J", force:true}, spatialFormat);
var kOutput = createReferenceVariable({prefix:"K", force:true}, spatialFormat);

var g92IOutput = createVariable({prefix:"I"}, zFormat); // no scaling

var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ...
var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19
var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G98-99
var gSpindleModeModal = createModal({}, gFormat); // modal group 5 // G96-97
var gSpindleModal = createModal({}, gFormat); // G14/G15 SPINDLE MODE
var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21
var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ...
var gPolarModal = createModal({}, gFormat); // G112, G113
var mModalFormat = createModal({}, mFormat); 

// fixed settings
var firstFeedParameter = 1;
var gotYAxis = true;  // specifies if the machine has a Y-axis
var yAxisMinimum = toPreciseUnit(-1, MM);  // specifies the mimimum range for the Y-axis
var yAxisMaximum = toPreciseUnit(1, MM);  // specifies the maximum range for the Y-axis
var gotLiveTooling = true;  // specifies if the machine is able to do live tooling
var gotCAxis = true; 
var gotSecondarySpindle = false;
var gotDoorControl = false;
var gotBarFeeder = false;
var gotMultiTurret = false;  // specifies if the machine has several turrets

var WARNING_WORK_OFFSET = 0;

// collected state
var sequenceNumber;
var currentWorkOffset;
var optionalSection = false;
var forceSpindleSpeed = false;
var activeMovements; // do not use by default
var currentFeedId;
var toolNumberArray = new Array();
var blockNumberArray = new Array();

/** Returns the modulus. */
function getModulus(x, y) {
  return Math.sqrt(x * x + y * y);
}

/** Returns the required number of segments for linearization of the corresponding arc segment. */
function getNumberOfSegments(radius, sweep, error) {
  if (radius > error) {
    var stepAngle = 2 * Math.acos(1 - error/radius);
    return Math.max(Math.ceil(sweep/stepAngle), 1);
  }
  return 1;
}

/**
  Returns the C rotation for the given X and Y coordinates.
*/
function getC(x, y) {
  return Math.atan2(y, x);
}

/**
  Returns the C rotation for the given X and Y coordinates in the desired rotary direction.
*/
function getCClosest(x, y, _c, clockwise) {
  if (_c == Number.POSITIVE_INFINITY) {
    _c = 0; // undefined
  }
  var c = getC(x, y);
  if (clockwise != undefined) {
    if (clockwise) {
      while (c < _c) {
        c += Math.PI * 2;
      }
    } else {
      while (c > _c) {
        c -= Math.PI * 2;
      }
    }
  } else {
    min = _c - Math.PI;
    max = _c + Math.PI;
    while (c < min) {
      c += Math.PI * 2;
    }
    while (c > max) {
      c -= Math.PI * 2;
    }
  }
  return c;
}

/**
  Returns the desired tolerance for the given section.
*/
function getTolerance() {
  var t = tolerance;
  if (hasParameter("operation:tolerance")) {
    if (t > 0) {
      t = Math.min(t, getParameter("operation:tolerance"));
    } else {
      t = getParameter("operation:tolerance");
    }
  }
  return t;
}

/**
  Writes the specified block.
*/
function writeBlock() {
  if (properties.showSequenceNumbers) {
    if (optionalSection) {
      var text = formatWords(arguments);
      if (text) {
        writeWords("N" + sequenceNumber, "/", text);
      }
    } else {
      writeWords2("N" + sequenceNumber, arguments);
    }
    sequenceNumber += properties.sequenceNumberIncrement;
  } else {
    writeWords(arguments);
  }
}

/**
  Writes the specified optional block.
*/
function writeOptionalBlock() {
  if (properties.showSequenceNumbers) {
    var words = formatWords(arguments);
    if (words) {
      writeWords("/", "N" + sequenceNumber, words);
      sequenceNumber += properties.sequenceNumberIncrement;
    }
  } else {
    writeWords("/", arguments);
  }
}

function formatComment(text) {
  return "(" + String(text).replace(/[\(\)]/g, "") + ")";
}

/**
  Output a comment.
*/
function writeComment(text) {
  writeln(formatComment(text));
}

var machineConfigurationZ;
var machineConfigurationXC;
var machineConfigurationXB;

function onOpen() {

  if (true) {
    machineConfigurationZ = new MachineConfiguration();

    if (gotCAxis) {
      var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:1}); //C axis is modal between primary and secondary spindle 
      machineConfigurationXC = new MachineConfiguration(cAxis);
      machineConfigurationXC.setSpindleAxis(new Vector(1, 0, 0));
    }
  }
  
  aOutput.disable();
  if (!machineConfigurationXB) {
    bOutput.disable();
  }
  if (!machineConfigurationXC) {
    cOutput.disable();
  }

  if (highFeedrate <= 0) {
    error(localize("You must set 'highFeedrate' because axes are not synchronized for rapid traversal."));
    return;
  }
  
  if (!properties.separateWordsWithSpace) {
    setWordSeparator("");
  }

  sequenceNumber = properties.sequenceNumberStart;
  writeln("%");

  if (programName) {
    var programId;
    try {
      programId = getAsInt(programName);
    } catch(e) {
      error(localize("Program name must be a number."));
      return;
    }
    if (!((programId >= 1) && (programId <= 9999))) {
      error(localize("Program number is out of range."));
      return;
    }
    var oFormat = createFormat({width:4, zeropad:true, decimals:0});
    if (programComment) {
      writeln("O" + oFormat.format(programId) + " (" + filterText(String(programComment).toUpperCase(), permittedCommentChars) + ")");
    } else {
      writeln("O" + oFormat.format(programId));
    }
  } else {
    error(localize("Program name has not been specified."));
    return;
  }

  // dump machine configuration
  var vendor = machineConfiguration.getVendor();
  var model = machineConfiguration.getModel();
  var description = machineConfiguration.getDescription();

  if (properties.writeMachine && (vendor || model || description)) {
    writeComment(localize("Machine"));
    if (vendor) {
      writeComment("  " + localize("vendor") + ": " + vendor);
    }
    if (model) {
      writeComment("  " + localize("model") + ": " + model);
    }
    if (description) {
      writeComment("  " + localize("description") + ": "  + description);
    }
  }

  // dump tool information
  if (properties.writeTools) {
    var zRanges = {};
    if (is3D()) {
      var numberOfSections = getNumberOfSections();
      for (var i = 0; i < numberOfSections; ++i) {
        var section = getSection(i);
        var zRange = section.getGlobalZRange();
        var tool = section.getTool();
        if (zRanges[tool.number]) {
          zRanges[tool.number].expandToRange(zRange);
        } else {
          zRanges[tool.number] = zRange;
        }
      }
    }

    var tools = getToolTable();
    if (tools.getNumberOfTools() > 0) {
      for (var i = 0; i < tools.getNumberOfTools(); ++i) {
        var tool = tools.getTool(i);
        var compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset;
        var comment = "T" + toolFormat.format(tool.number) + toolFormat.format(compensationOffset) + " " +
           (!tool.isTurningTool() ? "D=" + spatialFormat.format(tool.diameter) : "" )+ " " +
           (!tool.isTurningTool() ? localize("CR") + "=" + spatialFormat.format(tool.cornerRadius) : "")
        if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) {
          comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg");
        }
        if (zRanges[tool.number]) {
           (!tool.isTurningTool() ? comment += " - " + localize("ZMIN") + "=" + spatialFormat.format(zRanges[tool.number].getMinimum()) : "") ;
        }
        comment += " - " + getToolTypeName(tool.type);
        writeComment(comment);
      }
    }
  }
  
  var tools = getToolTable();
  if (tools.getNumberOfTools() > 0) {
      for (var i = 0; i < tools.getNumberOfTools(); ++i) {
        var tool = tools.getTool(i);
        toolNumberArray[tool.number] = tool.number;
        blockNumberArray[tool.number] = tool.number;
      }
  }  
  
  if (false) {
    // check for duplicate tool number
    for (var i = 0; i < getNumberOfSections(); ++i) {
      var sectioni = getSection(i);
      var tooli = sectioni.getTool();
      for (var j = i + 1; j < getNumberOfSections(); ++j) {
        var sectionj = getSection(j);
        var toolj = sectionj.getTool();
        if (tooli.number == toolj.number) {
          if (spatialFormat.areDifferent(tooli.diameter, toolj.diameter) ||
              spatialFormat.areDifferent(tooli.cornerRadius, toolj.cornerRadius) ||
              abcFormat.areDifferent(tooli.taperAngle, toolj.taperAngle) ||
              (tooli.numberOfFlutes != toolj.numberOfFlutes)) {
            error(
              subst(
                localize("Using the same tool number for different cutter geometry for operation '%1' and '%2'."),
                sectioni.hasParameter("operation-comment") ? sectioni.getParameter("operation-comment") : ("#" + (i + 1)),
                sectionj.hasParameter("operation-comment") ? sectionj.getParameter("operation-comment") : ("#" + (j + 1))
              )
            );
            return;
          }
        }
      }
    }
  }
  
  // absolute coordinates and feed per min
  writeBlock(gFeedModeModal.format(98), gPlaneModal.format(18));

  switch (unit) {
  case IN:
    writeBlock(gUnitModal.format(20));
    break;
  case MM:
    writeBlock(gUnitModal.format(21));
    break;
  }

  //writeBlock("#" + (firstFeedParameter - 1) + "=" + currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z, formatComment("G53HomePosition_Z"));
  
  var usesPrimarySpindle = false;
  var usesSecondarySpindle = false;
  for (var i = 0; i < getNumberOfSections(); ++i) {
    var section = getSection(i);
    if (section.getType() != TYPE_TURNING) {
      continue;
    }
    switch (section.spindle) {
    case SPINDLE_PRIMARY:
      usesPrimarySpindle = true;
      break;
    case SPINDLE_SECONDARY:
      usesSecondarySpindle = true;
      break;
    }
  }
  
  writeBlock(gFormat.format(50), sOutput.format(properties.maximumSpindleSpeed));
  sOutput.reset();

  if (properties.gotChipConveyor) {
    onCommand(COMMAND_START_CHIP_TRANSPORT);
  }
  if (gotYAxis) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.G53HomePosition_Y)); // retract
  }
  writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X)); // retract
  if (gotSecondarySpindle) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "B" + zFormat.format(0)); // retract Sub Spindle if applicable 
    }
  writeBlock(gFormat.format(0), "Z" + zFormat.format(properties.G53HomePosition_Z))
  forceXYZ();
}


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();
  forceFeed();
}

function forceFeed() {
  currentFeedId = undefined;
  feedOutput.reset();
}

function FeedContext(id, description, feed) {
  this.id = id;
  this.description = description;
  this.feed = feed;
}

function getFeed(f) {
  if (activeMovements) {
    var feedContext = activeMovements[movement];
    if (feedContext != undefined) {
      if (!feedFormat.areDifferent(feedContext.feed, f)) {
        if (feedContext.id == currentFeedId) {
          return ""; // nothing has changed
        }
        currentFeedId = feedContext.id;
        forceFeed();
        return "F#" + (firstFeedParameter + feedContext.id);
      }
    }
    currentFeedId = undefined; // force Q feed next time
  }
  return feedOutput.format(f); // use feed value
}

function initializeActiveFeeds() {
  activeMovements = new Array();
  var movements = currentSection.getMovements();

  var id = 0;
  var activeFeeds = new Array();
  if (hasParameter("operation:tool_feedCutting")) {
    if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) {
      var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_CUTTING] = feedContext;
      activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext;
      activeMovements[MOVEMENT_EXTENDED] = feedContext;
    }
    ++id;
    if (movements & (1 << MOVEMENT_PREDRILL)) {
      feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting"));
      activeMovements[MOVEMENT_PREDRILL] = feedContext;
      activeFeeds.push(feedContext);
    }
    ++id;
  }
  
  if (hasParameter("operation:finishFeedrate")) {
    if (movements & (1 << MOVEMENT_FINISH_CUTTING)) {
      var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext;
    }
    ++id;
  } else if (hasParameter("operation:tool_feedCutting")) {
    if (movements & (1 << MOVEMENT_FINISH_CUTTING)) {
      var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext;
    }
    ++id;
  }
  
  if (hasParameter("operation:tool_feedEntry")) {
    if (movements & (1 << MOVEMENT_LEAD_IN)) {
      var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LEAD_IN] = feedContext;
    }
    ++id;
  }

  if (hasParameter("operation:tool_feedExit")) {
    if (movements & (1 << MOVEMENT_LEAD_OUT)) {
      var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LEAD_OUT] = feedContext;
    }
    ++id;
  }

  if (hasParameter("operation:noEngagementFeedrate")) {
    if (movements & (1 << MOVEMENT_LINK_DIRECT)) {
      var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LINK_DIRECT] = feedContext;
    }
    ++id;
  } else if (hasParameter("operation:tool_feedCutting") &&
             hasParameter("operation:tool_feedEntry") &&
             hasParameter("operation:tool_feedExit")) {
    if (movements & (1 << MOVEMENT_LINK_DIRECT)) {
      var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit")));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_LINK_DIRECT] = feedContext;
    }
    ++id;
  }
  
/*
  if (hasParameter("operation:reducedFeedrate")) {
    if (movements & (1 << MOVEMENT_REDUCED)) {
      var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_REDUCED] = feedContext;
    }
    ++id;
  }
*/

  if (hasParameter("operation:tool_feedRamp")) {
    if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) {
      var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_RAMP] = feedContext;
      activeMovements[MOVEMENT_RAMP_HELIX] = feedContext;
      activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext;
      activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext;
    }
    ++id;
  }
  if (hasParameter("operation:tool_feedPlunge")) {
    if (movements & (1 << MOVEMENT_PLUNGE)) {
      var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge"));
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_PLUNGE] = feedContext;
    }
    ++id;
  }
  if (true) { // high feed
    if (movements & (1 << MOVEMENT_HIGH_FEED)) {
      var feedContext = new FeedContext(id, localize("High Feed"), this.highFeedrate);
      activeFeeds.push(feedContext);
      activeMovements[MOVEMENT_HIGH_FEED] = feedContext;
    }
    ++id;
  }
  
  for (var i = 0; i < activeFeeds.length; ++i) {
    var feedContext = activeFeeds[i];
    writeBlock("#" + (firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed), formatComment(feedContext.description));
  }
}

var currentWorkPlaneABC = undefined;

function forceWorkPlane() {
  currentWorkPlaneABC = undefined;
}

function setWorkPlane(abc) {
  // milling only

  if (!machineConfiguration.isMultiAxisConfiguration()) {
    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);

  writeBlock(
    gMotionModal.format(0),
    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))
  );
  
  onCommand(COMMAND_LOCK_MULTI_AXIS);

  currentWorkPlaneABC = abc;
}

var closestABC = false; // choose closest machine angles
var currentMachineABC;

function getWorkPlaneMachineABC(workPlane) {
  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))
    );
  }

  var tcp = false;
  if (tcp) {
    setRotation(W); // TCP mode
  } else {
    var O = machineConfiguration.getOrientation(abc);
    var R = machineConfiguration.getRemainingOrientation(abc, W);
    setRotation(R);
  }
  
  return abc;
}

function getLiveToolingMode(section) {
  if (section.getType() != TYPE_MILLING) {
    return -1;
  }
  var forward = section.workPlane.forward;
  if (isSameDirection(forward, new Vector(0, 0, 1))) {
   // writeln("(Milling from Z+ G17)")
    return 0;
  } else if (isSameDirection(forward, new Vector(0, 0, -1))) {
    return 1;
  } else if (Vector.dot(forward, new Vector(0, 0, 1)) < 1e-7) {
   // writeln("(Milling from X+ G19)")
    return 2;
  } else {
    error(localize("Orientation is not supported by CNC machine."));
    return -1;
  }
}

function getSpindle() {
  if (getNumberOfSections() == 0) {
    return SPINDLE_PRIMARY;
  }
  if (getCurrentSectionId() < 0) {
    return getSection(getNumberOfSections() - 1).spindle == 0;
  }
  if (currentSection.getType() == TYPE_TURNING) {
    return currentSection.spindle;
  } else {
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
      return SPINDLE_PRIMARY;
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
      if (!gotSecondarySpindle) {
        error(localize("Secondary spindle is not available."));
      }
      return SPINDLE_SECONDARY;
    } else {
      return SPINDLE_PRIMARY;
    }
  }
}

function getXZCMode(section) {
  // indexing C 
  if (gotCAxis) {
    if ((section.getType() == TYPE_MILLING)  &&
      getLiveToolingMode(section) == 0 &&  
      (section.hasParameter("operation-strategy") && (section.getParameter("operation-strategy") == "drill"))) {
    return true;
    } else {
        return false;
        }
  } else {
    return false;
  }   
}

var useXZCMode = false;
var usePolarMode = false;
var axialCenterDrilling = false;

function onSection() {
  writeln("");

  // use interpolation XY --> XC on the machine
  usePolarMode = (currentSection.getGlobalBoundingBox().lower.y < yAxisMinimum ||
    currentSection.getGlobalBoundingBox().upper.y > yAxisMaximum) && 
    (currentSection.getType() == TYPE_MILLING  &&
    getLiveToolingMode(currentSection) == 0)  &&  
    (hasParameter("operation:strategy") && getParameter("operation:strategy") != "drill") &&
    !currentSection.isMultiAxis();    

  // use XZC 
  useXZCMode = getXZCMode(currentSection);
    
  var tapping = (hasParameter("operation:cycleType") && (getParameter("operation:cycleType") == "tapping"));
  var forceToolAndRetract = optionalSection && !currentSection.isOptional();
  optionalSection = currentSection.isOptional();  

  var turning = (currentSection.getType() == TYPE_TURNING);
  
  var insertToolCall = forceToolAndRetract || isFirstSection() ||
    currentSection.getForceToolChange && currentSection.getForceToolChange() ||
    (tool.number != getPreviousSection().getTool().number) ||
      (tool.compensationOffset != getPreviousSection().getTool().compensationOffset) ||
      (tool.diameterOffset != getPreviousSection().getTool().diameterOffset);
  
  var retracted = false; // specifies that the tool has been retracted to the safe plane
  var newSpindle = isFirstSection() ||
    (getPreviousSection().spindle != currentSection.spindle);
  var newWorkOffset = isFirstSection() ||
    (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes
  var newWorkPlane = isFirstSection() ||
    !isSameDirection(getPreviousSection().getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis());
  axialCenterDrilling = hasParameter("operation-strategy") && getParameter("operation-strategy") == "drill" && 
    currentSection.getNumberOfCyclePoints() == 1 && 
    spatialFormat.format(getFramePosition(currentSection.getInitialPosition()).x) == 0 &&
    (currentSection.getType() == TYPE_MILLING)  &&
    getLiveToolingMode(currentSection) == 0 &&
    spatialFormat.format(currentSection.getFinalPosition().x) == 0;
  var stockTransfer = hasParameter ("operation-strategy") && getParameter("operation-strategy") == "turningStockTransfer";

  if (gotCAxis) {
    if (axialCenterDrilling) {
      useXZCMode = false;
      cOutput.disable();
    } else {
      cOutput.enable();
    }
  }

  if (false) {  // DEBUG
    writeln("YMIN" + yAxisMinimum);
    writeln("YMAX" + yAxisMaximum);
    writeln("BOUNDING MIN Y" + currentSection.getGlobalBoundingBox().lower.y);
    writeln("BOUNDING MAX Y" + currentSection.getGlobalBoundingBox().upper.y);       
    writeln("Polar Mode = " + usePolarMode);  
    writeln("Livetoolmode " + getLiveToolingMode(currentSection));  
    writeln("XZC Mode = " + useXZCMode);
    writeln("axialCenterDrilling =" + axialCenterDrilling);
    writeln("stockTransfer =" + stockTransfer);
    writeln("tapping =" + tapping);
  }    
  
  if (!isFirstSection()) {
    if (getPreviousSection().getType() == TYPE_MILLING && currentSection.getType() == TYPE_TURNING ||
      getPreviousSection().getType() == TYPE_TURNING && currentSection.getType() == TYPE_MILLING ||
      getPreviousSection().getType() == TYPE_MILLING && currentSection.getType() == TYPE_MILLING && insertToolCall ||
      axialCenterDrilling) {
        writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11));
        writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")), pOutput.format(12));    
        writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
        forceSpindleSpeed = true;
    }
  }
  
  if (insertToolCall || newSpindle || newWorkOffset || newWorkPlane && !currentSection.isPatterned()) { 
    // retract to safe plane
    retracted = true;
    // TAG: what about retract when milling along Z+
    if (!isFirstSection()) {
      if (gotYAxis) {
        writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + xFormat.format(properties.G53HomePosition_Y)); // retract
      }
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X)); // retract
      gMotionModal.reset();
      writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract with regard to spindle
      xOutput.reset();
    }
  }
   
  if (currentSection.getType() == TYPE_MILLING) { // handle multi-axis toolpath for milling
    if (!gotLiveTooling) {
      error(localize("Live tooling is not supported by the CNC machine."));
      return;
    }
/*
   if (currentSection.getType() == TYPE_MILLING) { // handle multi-axis toolpath for milling
      writeBlock(mFormat.format(05), "P11"); //Shut-off main spindle
   }
*/
    var config;
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1)) && !currentSection.isMultiAxis()) {
      config = machineConfigurationZ;
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
      error(localize("Milling from Z- is not supported by the CNC machine."));
      return;
    } else {
      switch (currentSection.spindle) {
      case SPINDLE_PRIMARY:
        config = machineConfigurationXC;
        break;
      case SPINDLE_SECONDARY:
        config = machineConfigurationXC;
        break;
      default:
        error(localize("Unsupported spindle."));
        return;
      }
    }
    if (!config) {
      error(localize("The requested orientation is not supported by the CNC machine."));
      return;
    }
    setMachineConfiguration(config);
    currentSection.optimizeMachineAnglesByMachine(config, 1); // map tip mode
  }
  
  writeln("");  
  
  if (toolNumberArray[tool.number] <= blockNumberArray[tool.number]) {
    writeln("N" + blockNumberArray[tool.number]);
    blockNumberArray[tool.number] = (blockNumberArray[tool.number] + 100);
  } else {
    writeln("N" + blockNumberArray[tool.number]);
  }  
  
  if (turning || axialCenterDrilling) {
    yOutput.disable();
    cOutput.disable();
  } else {
        if (usePolarMode || useXZCMode) {
      yOutput.enable();
      } 
    cOutput.enable();
  }  
  
  if (hasParameter("operation-comment")) {
    var comment = getParameter("operation-comment");
    if (comment) {
      writeComment(comment);
    }
  }
  
  if (properties.showNotes && hasParameter("notes")) {
    var notes = getParameter("notes");
    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) {
          writeComment(comment);
        }
      }
    }
  }

    
  if (stockTransfer) {
    return;  // skip onSection(), continue in onCycle()
  }
  
  if (insertToolCall) {
    forceWorkPlane();
    mModalFormat.reset();
    retracted = true;
    onCommand(COMMAND_COOLANT_OFF);
  
    if (!isFirstSection() && properties.optionalStop) {
      onCommand(COMMAND_OPTIONAL_STOP);
    }
    
/** handle multiple turrets here */
    if (gotMultiTurret) { 
      var activeTurret = tool.turret;
      if (activeTurret == 0) {
        warning(localize("Turret has not been specified. Using Turret 1 as default."));
        activeTurret = 1; // upper turret as default
      }
      switch (activeTurret) {
      case 1:
        // add specific handling for turret 1
        break;
      case 2:
        // add specific handling for turret 2, normally X-axis is reversed for the lower turret
        //xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:-1}); // inverted diameter mode
        //xOutput = createVariable({prefix:"X"}, xFormat);
        break;
      default:
        error(localize("Turret is not supported."));
      }
    }

    if (tool.number > 99) {
      warning(localize("Tool number exceeds maximum value."));
    }

    var compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset;
    if (compensationOffset > 99) {
      error(localize("Compensation offset is out of range."));
      return;
    }
    
    if (gotSecondarySpindle) {
        switch (currentSection.spindle) {
        case SPINDLE_PRIMARY: // main spindle
            writeBlock(gSpindleModal.format(15));
        break;
        case SPINDLE_SECONDARY: // sub spindle
            writeBlock(gSpindleModal.format(14));
        break;
        }
    }

    writeBlock("T" + + toolFormat.format(tool.number) + toolFormat.format(compensationOffset));
    if (tool.comment) {
      writeComment(tool.comment);
    }

    if (properties.preloadTool) {
      var nextTool = getNextTool(tool.number);
      if (nextTool) {
        var compensationOffset = nextTool.isTurningTool() ? nextTool.compensationOffset : nextTool.lengthOffset;
        if (compensationOffset > 99) {
          error(localize("Compensation offset is out of range."));
          return;
        }
        writeBlock("T" + toolFormat.format(nextTool.number * 100 + compensationOffset));
      } else {
        // preload first tool
        var section = getSection(0);
        var firstTool = section.getTool().number;
        if (tool.number != firstTool.number) {
          var compensationOffset = firstTool.isTurningTool() ? firstTool.compensationOffset : firstTool.lengthOffset;
          if (compensationOffset > 99) {
            error(localize("Compensation offset is out of range."));
            return;
          }
          writeBlock("T" + toolFormat.format(firstTool.number * 100 + compensationOffset));
        }
      }
    }
  }
  
    //command stop for manual tool change, useful for quick change live tools 
    if (insertToolCall && (tool.manualToolChange) == 1) {
        onCommand(COMMAND_STOP);
        writeBlock("(" + "MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number * 100 + compensationOffset) + ")");
      }

  if (newSpindle) {
    // select spindle if required
  }

  if (tool.maximumSpindleSpeed > 0 && currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
    var maximumSpindleSpeed = (tool.maximumSpindleSpeed > 0) ? Math.min(tool.maximumSpindleSpeed, properties.maximumSpindleSpeed) : properties.maximumSpindleSpeed;
    writeBlock(gFormat.format(50), sOutput.format(maximumSpindleSpeed)); 
  }
  
  // see page 138 in 96-8700an for stock transfer / G199/G198 
  if (insertToolCall ||
      newSpindle ||
      forceSpindleSpeed ||
      isFirstSection() ||
      (rpmFormat.areDifferent(tool.spindleRPM, sOutput.getCurrent())) ||
      (tool.clockwise != getPreviousSection().getTool().clockwise)) {
    if (turning) {
      if (tool.spindleRPM > 99999) {
        warning(localize("Spindle speed exceeds maximum value."));
      }
    } else {
      if (tool.spindleRPM > 6000) {
        warning(localize("Spindle speed exceeds maximum value."));
      }
    }
    gFeedModeModal.reset();
    if (currentSection.feedMode == FEED_PER_REVOLUTION) {
      writeBlock(gFeedModeModal.format(getCode("FEED_MODE_MM_REV"))); // mm/rev
    } else {
      writeBlock(gFeedModeModal.format(getCode("FEED_MODE_MM_MIN"))); // mm/min
    }
    switch (currentSection.spindle) {
    case SPINDLE_PRIMARY: // main spindle    
      if (turning || axialCenterDrilling) {  // turning main spindle
        if (properties.useTailStock) {
          writeBlock(mFormat.format(currentSection.tailstock ? getCode("TAILSTOCK_ON") : getCode("TAILSTOCK_OFF")));
        }        
        gSpindleModeModal.reset();
        if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
          writeBlock(gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_ON")), 
            sOutput.format(tool.surfaceSpeed * (1/1000)), 
            mFormat.format(tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")), pOutput.format(11)
          );
        } else {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")), 
            sOutput.format(tool.spindleRPM), 
            mFormat.format(tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")), pOutput.format(11)
          );
        }
        // wait for spindle here if required
      } else {  // milling main spindle
        writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")),
          (tapping ? sOutput.format(tool.spindleRPM) : sOutput.format(tool.spindleRPM)), 
          conditional(!tapping, mFormat.format(tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW"))), pOutput.format(12)
        );
      }
      break;
    case SPINDLE_SECONDARY: // sub spindle
      if (!gotSecondarySpindle) {
        error(localize("Secondary spindle is not available."));
        return;
      }
      if (turning || axialCenterDrilling) { //turning sub spindle
        // use could also swap spindles using G14/G15
        
        if (properties.useTailStock && currentSection.tailstock) {
          error(localize("Tail stock is not supported for secondary spindle."));
          return;
        }  
        gSpindleModeModal.reset();
        if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_ON")), 
            sOutput.format(tool.surfaceSpeed * (1/1000)),
            mFormat.format(tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW"))
          );
        } else {
          writeBlock(
            gSpindleModeModal.format(getCode("CONSTANT_SURFACE_SPEED_OFF")), 
            sOutput.format(tool.spindleRPM), 
            mFormat.format(tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW"))
          );
        }
        // wait for spindle here if required
      } else {  // milling sub spindle
      /*
        writeBlock(
          pOutput.format(tool.spindleRPM), mFormat.format(tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW"))
        );
       */
      }
      break;
    }
  }

  // wcs
  var workOffset = currentSection.workOffset;
  if (workOffset == 0) {
    warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET);
    workOffset = 1;
  }
  if (workOffset > 0) {
    if (workOffset > 6) {
      // alternatively use G154 P1-99
      var code = workOffset - 6;
      if (code >= 26) {
        error(localize("Work offset out of range."));
        return;
      }
      if (workOffset != currentWorkOffset) {
        writeBlock(gFormat.format(110 + code)); // G110->G129
        currentWorkOffset = workOffset;
      }
    } else {
      if (workOffset != currentWorkOffset) {
        writeBlock(gFormat.format(53 + workOffset)); // G54->G59
        currentWorkOffset = workOffset;
      }
    }
  }

/*
  if (gotYAxis) {
    writeBlock(gMotionModal.format(0), "Y" + yFormat.format(0));
    yOutput.reset();
  }
*/

  // set coolant after we have positioned at Z
  setCoolant(tool.coolant);
  
  if (properties.gotPartCatcher) {
    engagePartCatcher(true);
  }
  
  forceAny();
  gMotionModal.reset();

  if (gotCAxis && (getLiveToolingMode(currentSection) >= 0)) {
    if (!axialCenterDrilling) {
      writeBlock(mModalFormat.format(getCode("ENABLE_C_AXIS")));
    }
    gFeedModeModal.reset();
    writeBlock(tapping? gFeedModeModal.format(99) : gFeedModeModal.format(98));
  }
  
  if (currentSection.getType() == TYPE_TURNING) {
    // add support for tool indexing
    writeBlock(gPlaneModal.format(18));
    setRotation(currentSection.workPlane);
  } else if (!currentSection.isMultiAxis() && isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
    writeBlock(gPlaneModal.format(18)); // has to be G18 for DOOSAN?!
    if (gotCAxis) {
      cOutput.reset();
      //writeBlock(gMotionModal.format(0), gFormat.format(28), "H" + abcFormat.format(0)); // unwind c-axis
    }
    writeComment("Milling from Z+ G17");
    setRotation(currentSection.workPlane);
  } else if (!currentSection.isMultiAxis() && isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    writeBlock(gPlaneModal.format(18)); // has to be G18 for DOOSAN?!
    writeComment("Milling from Z- G17");
    setRotation(currentSection.workPlane);
  } else if (machineConfigurationXC || machineConfigurationXB || machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode
    //writeBlock(gPlaneModal.format(19));
    writeComment("Milling from X+ G19");
    // park sub spindle so there is room for milling from X+
    if (currentSection.isMultiAxis()) {
      forceWorkPlane();
      cancelTransformation();
    } else {
      var abc = new Vector(0, 0, 0);
      abc = getWorkPlaneMachineABC(currentSection.workPlane);
      setWorkPlane(abc);
    }
  } else { // pure 3D
    var remaining = currentSection.workPlane;
    if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) {
      error(localize("Tool orientation is not supported by the CNC machine."));
      return;
    }
    setRotation(remaining);
  }

  forceAny();
  gMotionModal.reset();

  var initialPosition = getFramePosition(currentSection.getInitialPosition());
/*
  if (!retracted) {
    // TAG: need to retract along X or Z
    if (getCurrentPosition().z < initialPosition.z) {
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
    }
  }
*/
  
  if (insertToolCall || retracted) {
    gPlaneModal.reset();
    gMotionModal.reset();
    if (useXZCMode) {
      writeBlock(gPlaneModal.format(18));
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
      writeBlock(
      gMotionModal.format(0), 
      xOutput.format(getModulus(initialPosition.x, initialPosition.y)),
      conditional(gotYAxis, yOutput.format(0)),
      cOutput.format(getC(initialPosition.x, initialPosition.y))
      );
    } else {  
      writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z));
      writeBlock(gMotionModal.format(0), conditional(!usePolarMode, xOutput.format(initialPosition.x)), conditional(gotYAxis, yOutput.format(initialPosition.y)));
    }
  }
  
  if (usePolarMode) {
    setPolarMode(true); // enable polar interpolation mode
    onCommand(COMMAND_UNLOCK_MULTI_AXIS);
  }
  
  if (properties.useParametricFeed &&
      hasParameter("operation-strategy") &&
      (getParameter("operation-strategy") != "drill") && currentSection.getType() != TYPE_TURNING) {
    if (!insertToolCall &&
        activeMovements &&
        (getCurrentSectionId() > 0) &&
        (getPreviousSection().getPatternId() == currentSection.getPatternId())) {
      // use the current feeds
    } else {
      initializeActiveFeeds();
    }
  } else {
    activeMovements = undefined;
  }
}

function setPolarMode(activate) {
  if (activate) {
    writeBlock(gPlaneModal.format(18));
    writeBlock(gMotionModal.format(0), cOutput.format(0)); // unwind to start at the right c-position with G112
    writeBlock(gPolarModal.format(getCode("POLAR_INTERPOLATION_ON")));  // command for polar interpolation
    yOutput = createVariable({prefix:"C"}, yFormat); // use Y coordinates in G112 as C
  } else {
    writeBlock(gPolarModal.format(getCode("POLAR_INTERPOLATION_OFF")));
    yOutput = createVariable({prefix:"Y"}, yFormat);
    writeBlock(gMotionModal.format(0), "C" + abcFormat.format(0)); // unwind C
    cOutput.reset();
  }
  forceXYZ();
}

function onDwell(seconds) {
  if (seconds > 99999.999) {
    warning(localize("Dwelling time is out of range."));
  }
  milliseconds = clamp(1, seconds * 1000, 99999999);
  writeBlock(/*gFeedModeModal.format(94),*/ gFormat.format(4), "P" + milliFormat.format(milliseconds));
}

var pendingRadiusCompensation = -1;

function onRadiusCompensation() {
  pendingRadiusCompensation = radiusCompensation;
}

var resetFeed = false;

function getHighfeedrate(radius) {
  if (currentSection.feedMode == FEED_PER_REVOLUTION) {
    var rpm = tool.spindleRPM; // rev/min
    if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) {
      var O = 2 * Math.PI * radius; // in/rev
      rpm = tool.surfaceSpeed/O; // in/min div in/rev => rev/min
    }
    return highFeedrate/rpm; // in/min div rev/min => in/rev
  }
  return highFeedrate;
}

function onRapid(_x, _y, _z) {
//if (xFormat.isSignificant(endRadius)) {
  if (useXZCMode) {
      var start = getCurrentPosition();
      var dxy = getModulus(_x - start.x, _y - start.y);
      if (true || (dxy < getTolerance())) {
        var x = xOutput.format(getModulus(_x, _y));
        var c = cOutput.format(getCClosest(_x, _y, cOutput.getCurrent()));
        var z = zOutput.format(_z);
        if (pendingRadiusCompensation >= 0) {
          error(localize("Radius compensation mode cannot be changed at rapid traversal."));
          return;
        }
        writeBlock(gMotionModal.format(0), x, c, z);
        forceFeed();
        return;
      }
      
      onLinear(_x, _y, _z, highFeedrate);
      return;
  }
  
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  if (x || y || z) {
    var useG1 = ((x ? 1 : 0) + (y ? 1 : 0) + (z ? 1 : 0)) > 1;
    if (pendingRadiusCompensation >= 0) {
      pendingRadiusCompensation = -1;
      if (useG1) {
        switch (radiusCompensation) {
        case RADIUS_COMPENSATION_LEFT:
          writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, getFeed(getHighfeedrate(_x)));
          break;
        case RADIUS_COMPENSATION_RIGHT:
          writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, getFeed(getHighfeedrate(_x)));
          break;
        default:
          writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, getFeed(getHighfeedrate(_x)));
        }
      } else {
        switch (radiusCompensation) {
        case RADIUS_COMPENSATION_LEFT:
          writeBlock(gMotionModal.format(0), gFormat.format(41), x, y, z);
          break;
        case RADIUS_COMPENSATION_RIGHT:
          writeBlock(gMotionModal.format(0), gFormat.format(42), x, y, z);
          break;
        default:
          writeBlock(gMotionModal.format(0), gFormat.format(40), x, y, z);
        }
      }
    }
    if (useG1 || usePolarMode) {  // G0 is forbidden in polar mode
      // axes are not synchronized
      writeBlock(gMotionModal.format(1), x, y, z, getFeed(getHighfeedrate(_x)));
    } else {
      writeBlock(gMotionModal.format(0), x, y, z);
      //forceFeed();
    }
    resetFeed = false;
  }
}

function onLinear(_x, _y, _z, feed) {
  if (useXZCMode) {
    if (pendingRadiusCompensation >= 0) {
      error(localize("Radius compensation is not supported."));
      return;
    }

    var start = getCurrentPosition();
    var startRadius = getModulus(start.x, start.y);
    var endRadius = getModulus(_x, _y);
    var radius = Math.min(startRadius, endRadius);
    if (false && !xFormat.areDifferent(startRadius, endRadius)) { // TAG: need to check DX/DY also
      var x = xOutput.format(endRadius);
      var z = zOutput.format(_z);
      if (xFormat.isSignificant(endRadius)) {
        var c = cOutput.format(getCClosest(_x, _y, cOutput.getCurrent()));
        writeBlock(gMotionModal.format(1), x, c, z, getFeed(feed));
      } else {
        writeBlock(gMotionModal.format(1), x, z, getFeed(feed)); // keep C
      }
      return;
    }
    if (radius < 0.1 && hasParameter("operation-strategy") && getParameter("operation-strategy") != "drill") { // TAG: how should we handle small radii
      error(localize("Cannot machine radius 0."));
      return;
    }

    var c = getCClosest(_x, _y, cOutput.getCurrent());
    var sweep = Math.abs(c - cOutput.getCurrent());
    if (sweep >= (Math.PI - 1e-6)) {
      error(localize("Cannot machine 180deg sweep."));
      return;
    }
  
    var numberOfSegments = getNumberOfSegments(radius, sweep, getTolerance());
    //writeComment("onLinear(): C-sweep:" + abcFormat.format(sweep) + " #segments:" + numberOfSegments);
    var factor = 1.0/numberOfSegments;
    for (var i = 1; i <= numberOfSegments; ++i) {
      var u = i * factor;
      var ux = u * _x + (1 - u) * start.x;
      var uy = u * _y + (1 - u) * start.y;
      var uz = u * _z + (1 - u) * start.z;
      var x = xOutput.format(getModulus(ux, uy));
      var c = cOutput.format(getCClosest(ux, uy, cOutput.getCurrent()));
      var z = zOutput.format(uz);
      writeBlock(gMotionModal.format(1), x, c, z, getFeed(feed));
    }
    return;
  }
  
  if (isSpeedFeedSynchronizationActive()) {
    resetFeed = true;
    var threadPitch = getParameter("operation:threadPitch");
    var threadsPerInch = ((unit == MM) ? 1.0 : 25.4)/threadPitch; // per mm for metric
    writeBlock(gMotionModal.format(32), xOutput.format(_x), yOutput.format(_y), zOutput.format(_z), pitchOutput.format(1/threadsPerInch));
    return;
  }
  if (resetFeed) {
    resetFeed = false;
    forceFeed();
  }
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  var f = getFeed(feed);
  if (x || y || z) {
    if (pendingRadiusCompensation >= 0) {
      pendingRadiusCompensation = -1;
      if (currentSection.getType() == TYPE_TURNING) {
        writeBlock(gPlaneModal.format(18));
      } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
        writeBlock(conditional(!usePolarMode, gPlaneModal.format(17)));
      } else if (Vector.dot(currentSection.workPlane.forward, new Vector(0, 0, 1)) < 1e-7) {
        //writeBlock(gPlaneModal.format(19));
      } else {
        error(localize("Tool orientation is not supported for radius compensation."));
        return;
      }
      switch (radiusCompensation) {
      case RADIUS_COMPENSATION_LEFT:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(41), x, y, z, f);
        break;
      case RADIUS_COMPENSATION_RIGHT:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(42), x, y, z, f);
        break;
      default:
        writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(40), x, y, z, f);
      }
    } else {
      writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 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(isSpeedFeedSynchronizationActive() ? 32 : 1), f);
    }
  }
}

function onRapid5D(_x, _y, _z, _a, _b, _c) {
  if (useXZCMode) {
    error(localize("Multi-axis motion is not supported for XZC mode."));
    return;
  }

  if (pendingRadiusCompensation >= 0) {
    error(localize("Radius compensation mode cannot be changed at rapid traversal."));
    return;
  }
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  var a = aOutput.format(_a);
  var b = bOutput.format(_b);
  var c = cOutput.format(_c);
  if (true) {
    // axes are not synchronized
    writeBlock(gMotionModal.format(1), x, y, z, a, b, c, getFeed(highFeedrate));
  } else {
    writeBlock(gMotionModal.format(0), x, y, z, a, b, c);
    forceFeed();
  }
}

function onLinear5D(_x, _y, _z, _a, _b, _c, feed) {
  if (useXZCMode) {
    error(localize("Multi-axis motion is not supported for XZC mode."));
    return;
  }

  if (pendingRadiusCompensation >= 0) {
    error(localize("Radius compensation cannot be activated/deactivated for 5-axis move."));
    return;
  }
  var x = xOutput.format(_x);
  var y = yOutput.format(_y);
  var z = zOutput.format(_z);
  var a = aOutput.format(_a);
  var b = bOutput.format(_b);
  var c = cOutput.format(_c);
  var f = 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
      forceFeed(); // force feed on next line
    } else {
      writeBlock(gMotionModal.format(1), f);
    }
  }
}

function onCircular(clockwise, cx, cy, cz, x, y, z, feed) {
  if (useXZCMode) {
    // TAG: var numberOfSegments = toDeg(getCircularSweep())/120;

    switch (getCircularPlane()) {
    case PLANE_ZX:
      if (!isSpiral()) {
        var c = getCClosest(x, y, cOutput.getCurrent());
        if (!cFormat.areDifferent(c, cOutput.getCurrent())) {
          validate(getCircularSweep() < Math.PI, localize("Circular sweep exceeds limit."));
          var start = getCurrentPosition();
          writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(getModulus(x, y)), cOutput.format(c), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
          return;
        }
      }
      break;
    case PLANE_XY:
      var d2 = center.x * center.x + center.y * center.y;
      if (d2 < 1e-18) { // center is on rotary axis
        writeBlock(gMotionModal.format(1), xOutput.format(getModulus(x, y)), cOutput.format(getCClosest(x, y, cOutput.getCurrent(), clockwise)), zOutput.format(z), getFeed(feed));
        return;
      }
      break;
    }
    
    linearize(getTolerance());
    return;
  }
  
  if (isSpeedFeedSynchronizationActive()) {
    error(localize("Speed-feed synchronization is not supported for circular moves."));
    return;
  }

  if (pendingRadiusCompensation >= 0) {
    error(localize("Radius compensation cannot be activated/deactivated for a circular move."));
    return;
  }

  var start = getCurrentPosition();

  if (isFullCircle()) {
    if (properties.useRadius || isHelical()) { // radius mode does not support full arcs
      linearize(tolerance);
      return;
    }
    switch (getCircularPlane()) {
    case PLANE_XY:
      writeBlock(conditional(!usePolarMode, gPlaneModal.format(17)), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed));
      break;
     case PLANE_ZX:
       if (usePolarMode) {
        linearize(tolerance);
        return
      }
      writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
      break;
    default:
      linearize(tolerance);
    }
  } else if (!properties.useRadius) {
    switch (getCircularPlane()) {
    case PLANE_XY:
      writeBlock(conditional(!usePolarMode, gPlaneModal.format(17)), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed));
      break;
    case PLANE_ZX:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(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(conditional(!usePolarMode, gPlaneModal.format(17)), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    case PLANE_ZX:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    case PLANE_YZ:
      if (usePolarMode) {
        linearize(tolerance);
        return;
      }
      writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed));
      break;
    default:
      linearize(tolerance);
    }
  }
}

function onCycle() {
  if (cycleType == "stock-transfer") {
    error(localize("Stock transfer is not supported."));
    return;
    /*
    writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")));
    setCoolant(COOLANT_OFF);
    onCommand(COMMAND_OPTIONAL_STOP);
    
    // wcs required here
    var workOffset = currentSection.workOffset;
    if (workOffset == 0) {
      warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET);
      workOffset = 1;
    }
    if (workOffset > 0) {
      if (workOffset > 6) {
        // alternatively use G154 P1-99
        var code = workOffset - 6;
        if (code >= 26) {
          error(localize("Work offset out of range."));
          return;
        }
        if (workOffset != currentWorkOffset) {
          writeBlock(gFormat.format(110 + code)); // G110->G129
          currentWorkOffset = workOffset;
        }
      } else {
        if (workOffset != currentWorkOffset) {
          writeBlock(gFormat.format(53 + workOffset)); // G54->G59
          currentWorkOffset = workOffset;
        }
      }
    }
    
    gMotionModal.reset();
    gFeedModeModal.reset();
    writeBlock(gFormat.format(103), "P1"); //Look Ahead set to 1 block
    writeBlock(mFormat.format(getCode("UNCLAMP_SECONDARY_CHUCK")));
    writeBlock(gFeedModeModal.format(98));
    writeBlock(gMotionModal.format(0), "B" + zFormat.format(properties.transBClearance));
    writeBlock(mFormat.format(12)); //Sub Spindle Air Blow on
    writeBlock(gMotionModal.format(1), "B" + zFormat.format(properties.transBPosition), "F" + feedFormat.format(properties.transFeedrate));  // move subspindle to main spindle with safety distance
    writeBlock(mFormat.format(getCode("CLAMP_SECONDARY_CHUCK")));
    onDwell(1);
    writeBlock(mFormat.format(getCode("UNCLAMP_PRIMARY_CHUCK")));
    onDwell(1);
    writeBlock(gMotionModal.format(1), "B" + zFormat.format(properties.transBClearance), "F" + feedFormat.format(properties.transFeedrate)); 
    writeBlock(mFormat.format(13)); //Sub Spindle Air Blow off
    writeBlock(gMotionModal.format(0), "B" + zFormat.format(0));
    writeBlock(mFormat.format(getCode("CLAMP_PRIMARY_CHUCK")));
    writeBlock(gFormat.format(103)); //Look Ahead set to Default
    gMotionModal.reset();
    gFeedModeModal.reset();
  */
  }
}

function getCommonCycle(x, y, z, r) {
  forceXYZ(); // force xyz on first drill hole of any cycle
  if (useXZCMode) {
    cOutput.reset();
    return [xOutput.format(getModulus(x, y)), cOutput.format(getCClosest(x, y, cOutput.getCurrent())),
      zOutput.format(z),
      "R" + spatialFormat.format(cyclePlane == 19 ? r*2 : r)];
  } else {
    return [xOutput.format(x), yOutput.format(y),
      zOutput.format(z),
      "R" + spatialFormat.format(cyclePlane == 19 ? r*2 : r)];
  }
}

function writeCycleClearance() {
  if (isFirstCyclePoint()) {
    switch (cyclePlane) {
    case 18:
      writeBlock(gMotionModal.format(0), zOutput.format(cycle.clearance));
      break;
    /*case 18:
      writeBlock(gMotionModal.format(0), yOutput.format(cycle.clearance));
      break;*/
    case 19:
      writeBlock(gMotionModal.format(0), xOutput.format(cycle.clearance));
      break;
    default:
      error(localize("Unsupported drilling orientation."));
      return;
    }
  }
}

var cyclePlane = undefined;

function onCyclePoint(x, y, z) {

  if (!properties.useCycles || currentSection.isMultiAxis()) {
    expandCyclePoint(x, y, z);
    return;
  }

  if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1)) ||
      isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    //writeBlock(gPlaneModal.format(17)); // XY plane
    cyclePlane = 18;
  } else if (Vector.dot(currentSection.workPlane.forward, new Vector(0, 0, 1)) < 1e-7) {
    //writeBlock(gPlaneModal.format(19)); // YZ plane
    cyclePlane = 19;
  } else {
    expandCyclePoint(x, y, z);
    return;
  }

  switch (cycleType) {
  case "thread-turning":
    var i = -cycle.incrementalX; // positive if taper goes down - delta radius
    var threadsPerInch = 1.0/cycle.pitch; // per mm for metric
    var f = 1/threadsPerInch;
    writeBlock(gMotionModal.format(92), xOutput.format(x - cycle.incrementalX), yOutput.format(y), zOutput.format(z), conditional(zFormat.isSignificant(i), g92IOutput.format(i)), pitchOutput.format(f));
    forceFeed();
    return;
  }

  if (isFirstCyclePoint()) {
    //repositionToCycleClearance(cycle, x, y, z);
    // return to initial Z which is clearance plane and set absolute mode

    var F = (gFeedModeModal.getCurrent() == 99 ? cycle.feedrate/tool.spindleRPM : cycle.feedrate);
    var P = (cycle.dwell == 0) ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds

    switch (cycleType) {
    case "drilling":
      writeBlock(
        gCycleModal.format((cyclePlane == 18) ? 83 : 87),
        getCommonCycle(x, y, z, cycle.retract - cycle.stock),
        feedOutput.format(F),
        conditional(!axialCenterDrilling, mFormat.format(89))
      );
      break;
/*      
    case "counter-boring":
      if (P > 0) {
        writeBlock(
          gCycleModal.format(82),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P),
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(81),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
*/
    case "chip-breaking":
      // cycle.accumulatedDepth is ignored
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 83 : 87),
          getCommonCycle(x, y, z, cycle.retract - cycle.stock),
          "Q" + qFormat.format(cycle.incrementalDepth),
          // conditional(cycle.incrementalDepthReduction > 0, "J" + spatialFormat.format(cycle.incrementalDepthReduction)),
          // conditional(cycle.minimumIncrementalDepth > 0, "K" + spatialFormat.format(cycle.minimumIncrementalDepth)),
          conditional(P > 0, "P" + milliFormat.format(P)),
          feedOutput.format(F),
          conditional(!axialCenterDrilling, mFormat.format(89))
        );
      break;
    case "deep-drilling":
      // either use Q or I,J,K
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 83 : 87),
          getCommonCycle(x, y, z, cycle.retract - cycle.stock),
          "Q" + qFormat.format(cycle.incrementalDepth),
          // conditional(cycle.incrementalDepthReduction > 0, "J" + spatialFormat.format(cycle.incrementalDepthReduction)),
          // conditional(cycle.minimumIncrementalDepth > 0, "K" + spatialFormat.format(cycle.minimumIncrementalDepth)),
          conditional(P > 0, "P" + milliFormat.format(P)),
          feedOutput.format(F),
          conditional(!axialCenterDrilling, mFormat.format(89))
        );
      break;
    case "tapping":
    case "right-tapping":
    case "left-tapping":
      writeBlock(mFormat.format(329), sOutput.format(tool.spindleRPM));
      if (!F) {
        F = tool.getTappingFeedrate();
      }
      writeBlock(
        gTappingModal.format(cyclePlane == 18 ? 84 : 88),
        getCommonCycle(x, y, z, cycle.retract - cycle.stock),
        "P" + milliFormat.format(P),
        pitchOutput.format(tool.threadPitch),
        conditional(!axialCenterDrilling, mFormat.format(89))
      );
      feedOutput.reset();
      break;
    case "tapping-with-chip-breaking":
    case "left-tapping-with-chip-breaking":
    case "right-tapping-with-chip-breaking":
      error(localize("Cycle not supported"));
      break;
/*
    case "fine-boring":
      writeBlock(
        gCycleModal.format(76),
        getCommonCycle(x, y, z, cycle.retract),
        "P" + milliFormat.format(P), // not optional
        "Q" + spatialFormat.format(cycle.shift),
        feedOutput.format(F),
        mFormat.format(89)
      );
      break;
    case "reaming":
      if (P > 0) {
        writeBlock(
          gCycleModal.format((cyclePlane == 18) ? 85 : 89),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P),
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(gcode),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
    case "stop-boring":
      if (P > 0) {
        expandCyclePoint(x, y, z);
      } else {
        writeBlock(
          gCycleModal.format(86),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
    case "boring":
      if (P > 0) {
        writeBlock(
          gCycleModal.format(89),
          getCommonCycle(x, y, z, cycle.retract),
          "P" + milliFormat.format(P), // not optional
          feedOutput.format(F),
          mFormat.format(89)
        );
      } else {
        writeBlock(
          gCycleModal.format(85),
          getCommonCycle(x, y, z, cycle.retract),
          feedOutput.format(F),
          mFormat.format(89)
        );
      }
      break;
*/      
    default:
      expandCyclePoint(x, y, z);
    }
  } else {
    if (cycleExpanded) {
      expandCyclePoint(x, y, z);
    } else if (useXZCMode) {
      var _x = xOutput.format(getModulus(x, y));
      var _c = cOutput.format(getC(x, y));
      if (!_x /*&& !_y*/ && !_c) {
        xOutput.reset(); // at least one axis is required
        _x = xOutput.format(getModulus(x, y));
      }
      writeBlock(_x, _c, conditional(cycle.incrementalDepth != cycle.depth, "Q" + qFormat.format(cycle.incrementalDepth)));
    } else {
      var _x = xOutput.format(x);
      var _y = yOutput.format(y);
      var _z = zOutput.format(z);
      if (!_x && !_y && !_z) {
        switch (cyclePlane) {
        case 17: 
        case 18: // ZX
          zOutput.reset(); // at least one axis is required
          _z = zOutput.format(z);
          xOutput.reset(); // at least one axis is required
          _x = xOutput.format(x);
          break;
        case 19: // YZ
          yOutput.reset(); // at least one axis is required
          _y = yOutput.format(y);
          break;
        }
      }
      writeBlock(_x, _y, _z, conditional(cycle.incrementalDepth != cycle.depth, "Q" + qFormat.format(cycle.incrementalDepth)));
    }
  }
}

function onCycleEnd() {
  if (!cycleExpanded) {
    switch (cycleType) {
    case "thread-turning":
      forceFeed();
      xOutput.reset();
      zOutput.reset();
      g92IOutput.reset();
      break;
    default:
      writeBlock(gCycleModal.format(80));
      gMotionModal.reset();
    }
  }
  cyclePlane = undefined;
}

function onPassThrough(text) {
  writeBlock(text);
}

function onParameter(name, value) {
}

var currentCoolantMode = COOLANT_OFF;

function setCoolant(coolant) {
  if (coolant == currentCoolantMode) {
    return; // coolant is already active
  }

  var m = undefined;
  if (coolant == COOLANT_OFF) {
    if (currentCoolantMode == COOLANT_THROUGH_TOOL) {
      m = 89;
    } else if (currentCoolantMode == COOLANT_AIR) {
      m = 84;
    } else {
      m = 9;
    }
    writeBlock(mFormat.format(m));
    currentCoolantMode = COOLANT_OFF;
    return;
  }

  if (currentCoolantMode != COOLANT_OFF) {
    setCoolant(COOLANT_OFF);
  }

  switch (coolant) {
  case COOLANT_FLOOD:
    m = 8;
    break;
  case COOLANT_THROUGH_TOOL:
    m = 88;
    break;
  case COOLANT_AIR:
    m = 83;
    break;
  default:
    warning(localize("Coolant not supported."));
    if (currentCoolantMode == COOLANT_OFF) {
      return;
    }
    coolant = COOLANT_OFF;
    m = 9;
  }

  writeBlock(mFormat.format(m));
  currentCoolantMode = coolant;
}

function onCommand(command) {
  switch (command) {
  case COMMAND_COOLANT_OFF:
    setCoolant(COOLANT_OFF);
    break;
  case COMMAND_COOLANT_ON:
    setCoolant(COOLANT_FLOOD);
    break;
  case COMMAND_LOCK_MULTI_AXIS:
    //writeBlock(mFormat.format((currentSection.getSpindle() == 0) ? 68 : 114));
    break;
  case COMMAND_UNLOCK_MULTI_AXIS:
    //writeBlock(mFormat.format((currentSection.getSpindle() == 0) ? 69 : 115));
    break;
  case COMMAND_START_CHIP_TRANSPORT:
    //writeBlock(mFormat.format(31));
    break;
  case COMMAND_STOP_CHIP_TRANSPORT:
    //writeBlock(mFormat.format(33));
    break;
  case COMMAND_OPEN_DOOR:
    if (gotDoorControl) {
      writeBlock(mFormat.format(85)); // optional
    }
    break;
  case COMMAND_CLOSE_DOOR:
    if (gotDoorControl) {
      writeBlock(mFormat.format(86)); // optional
    }
    break;
  case COMMAND_BREAK_CONTROL:
    break;
  case COMMAND_TOOL_MEASURE:
    break;
  case COMMAND_ACTIVATE_SPEED_FEED_SYNCHRONIZATION:
    break;
  case COMMAND_DEACTIVATE_SPEED_FEED_SYNCHRONIZATION:
    break;
  case COMMAND_STOP:
    writeBlock(mFormat.format(0));
    forceSpindleSpeed = true;
    break;
  case COMMAND_OPTIONAL_STOP:
    writeBlock(mFormat.format(1));
    forceSpindleSpeed = true;
    break;
  case COMMAND_END:
    writeBlock(mFormat.format(2));
    break;
  case COMMAND_ORIENTATE_SPINDLE:
    if (currentSection.getType() == TYPE_TURNING) {
      if (getSpindle() == 0) {
        writeBlock(mFormat.format(19)); // use P or R to set angle (optional)
      } else {
        writeBlock(mFormat.format(119));
      }
    } else {
      if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
        writeBlock(mFormat.format(19)); // use P or R to set angle (optional)
      } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
        writeBlock(mFormat.format(119));
      } else {
        error(localize("Spindle orientation is not supported for live tooling."));
        return;
      }
    }
    break;
  //case COMMAND_CLAMP: // add support for clamping
  //case COMMAND_UNCLAMP: // add support for clamping
  default:
    onUnsupportedCommand(command);
  }
}

function getCode(code) {
  switch(code) {
  case "PART_CATCHER_ON":
    return 36; 
    break;
  case "PART_CATCHER_OFF":
    return 37; 
    break;
  case "TAILSTOCK_ON": 
    return 21;
    break;
  case "TAILSTOCK_OFF": 
    return 22;
    break;
  case "ENABLE_C_AXIS": 
    return 35;
    break;
  case "DISABLE_C_AXIS": 
    return 34;
    break;
  case "POLAR_INTERPOLATION_ON": 
    return 112;
    break;
  case "POLAR_INTERPOLATION_OFF": 
    return 113;
    break;
  case "STOP_LIVE_TOOL": 
    return 5;
    break;
  case "STOP_MAIN_SPINDLE": 
    return 5;
    break;
  case "STOP_SUB_SPINDLE_CW": 
    return 5;
    break;
  case "START_LIVE_TOOL_CW": 
    return 3;
    break;
  case "START_LIVE_TOOL_CCW": 
    return 4;
    break;
  case "START_MAIN_SPINDLE_CW": 
    return 3;
    break;   
  case "START_MAIN_SPINDLE_CCW": 
    return 4;
    break;
  case "START_SUB_SPINDLE_CW": 
    return 143;
    break;
  case "START_SUB_SPINDLE_CCW": 
    return 144;
    break;       
  case "FEED_MODE_MM_REV": 
    return 99;
    break;  
  case "FEED_MODE_MM_MIN": 
    return 98;
    break;      
  case "CONSTANT_SURFACE_SPEED_ON": 
    return 96;
    break;
  case "CONSTANT_SURFACE_SPEED_OFF": 
    return 97;
    break; 
  case "AUTO_AIR_ON": 
    return 12;
    break;    
  case "AUTO_AIR_OFF": 
    return 13;
    break;
  case "CLAMP_PRIMARY_CHUCK":
    return 10;
    break;
  case "UNCLAMP_PRIMARY_CHUCK":
    return 11;
    break;
  case "CLAMP_SECONDARY_CHUCK": 
    return 110;
    break;
  case "UNCLAMP_SECONDARY_CHUCK": 
    return 111;
    break;
  case "SPINDLE_SYNCHRONIZATION_ON": 
    return 199;
    break;    
  case "SPINDLE_SYNCHRONIZATION_OFF": 
    return 198;
    break;   
  default:
    error(localize("Command " + code + " not defined."));
  }
}

function engagePartCatcher(engage) {

  if (properties.gotPartCatcher &&
      hasParameter("operation-strategy") &&
      (getParameter("operation-strategy") == "turningPart") &&
      currentSection.partCatcher == true) {
    if (engage) { 
      // catch part here
      writeBlock(mFormat.format(getCode("PART_CATCHER_ON")), formatComment(localize("PART CATCHER ON")));
    } else {
      onCommand(COMMAND_COOLANT_OFF);
      writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.G53HomePosition_X)); // retract
      writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      writeBlock(mFormat.format(getCode("PART_CATCHER_OFF")), formatComment(localize("PART CATCHER OFF")));
      forceXYZ();
    }
  }
}

function onSectionEnd() {

  if (properties.gotPartCatcher) {
    engagePartCatcher(false);
  }
  
  if (usePolarMode) {
    setPolarMode(false);  // disable polar interpolation mode
  }
/*
  if (!isLastSection()) {
    if (gotCAxis && (getLiveToolingMode(getNextSection()) < 0) && !currentSection.isPatterned() && (getLiveToolingMode(currentSection) >= 0)) {
      writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
    }
  } else {
    if (gotCAxis && (getLiveToolingMode(currentSection) >= 0)) {
      writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
    }
  }
*/
  if (((getCurrentSectionId() + 1) >= getNumberOfSections()) ||
      (tool.number != getNextSection().getTool().number)) {
    onCommand(COMMAND_BREAK_CONTROL);
  }

  if ((currentSection.getType() == TYPE_MILLING) &&
      (!hasNextSection() || (getNextSection().getType() != TYPE_MILLING))) {
    // exit milling mode
    if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) {
    } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) {
    } else {
      writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11)); 
    }
  }

  forceAny();
}

function onClose() {
  writeln("");

  optionalSection = false;

  onCommand(COMMAND_COOLANT_OFF);
  
  if (properties.gotChipConveyor) {
    onCommand(COMMAND_STOP_CHIP_TRANSPORT);
  }
  
  writeBlock(mFormat.format(getCode("STOP_LIVE_TOOL")), pOutput.format(11));
  writeBlock(mFormat.format(getCode("STOP_MAIN_SPINDLE")), pOutput.format(12));    
  writeBlock(mModalFormat.format(getCode("DISABLE_C_AXIS")));
  
  if (getNumberOfSections() > 0) { //Always retract X first. Retracting Z first causes safezone overtravel error to keep from crashing into subspindle. Z should already be retracted to and end of section. 
    var section = getSection(getNumberOfSections() - 1);
    if ((section.getType() != TYPE_TURNING) && isSameDirection(section.workPlane.forward, new Vector(0, 0, 1))) {            
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X), conditional(gotYAxis, "Y" + xFormat.format(properties.G53HomePosition_Y))); // retract
      xOutput.reset();
      gMotionModal.reset();
        writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      zOutput.reset();
    } else {
      if (gotYAxis) {
        writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + xFormat.format(properties.G53HomePosition_Y)); // retract
      }
      writeBlock(gFormat.format(28), "U" + xFormat.format(properties.G53HomePosition_X));
      xOutput.reset();
      gMotionModal.reset();
      writeBlock(gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.G53HomePositionSub_Z : properties.G53HomePosition_Z)); // retract
      zOutput.reset();
    }
  }
  
  gMotionModal.reset();
  if (false) {
    writeBlock(gMotionModal.format(0), "C" + abcFormat.format(0)); // unwind
  }

  if (gotYAxis) {
    writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.G53HomePosition_Y));
    yOutput.reset();
  }

  if (gotBarFeeder) {
    writeln("");
    writeComment(localize("Bar feed"));
    writeBlock(mFormat.format(5));
    // feed bar here
    writeOptionalBlock(gFormat.format(105));
    writeOptionalBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.G53HomePosition_X));
    writeOptionalBlock(mFormat.format(1));
    writeOptionalBlock(mFormat.format(99)); // restart
  }

  writeln("");
  writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off
  writeln("%");
}
 

буду благодарен за любую помощь и подсказки)

Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете опубликовать сообщение сейчас, а зарегистрироваться позже. Если у вас есть аккаунт, войдите в него для написания от своего имени.
Примечание: вашему сообщению потребуется утверждение модератора, прежде чем оно станет доступным.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу.




×
×
  • Создать...