The path where the examples are stored has changed. They are now at
C:\ProgramData\Autodesk\ATU\ATU-Examples\.
Toolpath geometry is based upon the Advanced Toolpath Utility's geometry API described in Geometry Processing. Toolpaths may consist of opened and/or closed polylines, they can be modified using bsPathSets and they are generated based upon bsPolyline, bsPathSet or bsIsland objects.
Three new types are available exclusively for toolpath generation:

A bsHatch object is a container for bsHatchBlock objects and bsHatchBlock objects contain toolpath geometry. Both types provide api functions for toolpath operations. An object of type bsHatchInfo is used to calculate the build time of toolpaths.
The term "hatch" is based upon the fact, that toolpaths for solid areas sometimes look like a hatch pattern of a figure, which was drawn with a pencil. Have a look at the following picture, that shows a simple hatch pattern for a solid area on one layer of a 3D object:
![]() |
![]() |
Apart from the geometry data of toolpaths, there are some other very important aspects, that didn't appear or weren't important for most geometry modification tasks:
- Groups of polylines and connections between them and their geometry objects.
- Order of geometry object lists.
- Polyline attributes.
- Polyline directions.
While printing a layer, the additive printing machine will follow the toolpath from a start to an end point. As soon as the layer contains more than one area, the machine has to stop operation, jump to a new position and start operating again. This operation is called a skip. The exposure preview widget is able to show all skips, if desired. The following picture shows skips as dotted lines and a look at the open path below shows, that a skip is needed to reach the beginning of the segment and again to get away from it.
![]() |
![]() |
Depending on the layer's geometry complexity, an intelligent order for the toolpath from the first to the last geometry object seems to be a good idea, but at the moment it is not possible to see the direction of the toolpath at all. The machine may start at the left or at the right side of the path above and the rectangle below may be processed before or after the open path.
That is why the exposure preview offers to show toolpath directions. Use the Arrows option to enable toolpath directions.

Now imagine, that a machine has to change parameters while following a toolpath. At certain positions the laser power or the speed values have to be in or decreased.
For that reason, the toolpath structure allows to add attributes to toolpath segments. A segment has to be chosen and a rightclick shows a popup menu, that offers an attribute information dialog.
![]() |
![]() |
Taking this introduction as a start, a look at the example projects might be interesting as a next step.
Using the Toolpath Buildstyle Examples
All toolpath creation example buildstyles benefit from an optional function, that can be used within buildstyles.
exports.preprocessLayerStack = function(modelDataSrc, modelDataTarget, progress) { }
This function gets called as soon as the buildstyle processor is done with input geometry processing. The modelDataSrc object contains the processed geometry and the modelDataTarget object is empty. All processing steps following preprocessLayerStack will use the modelDataTarget object for geometry processing. Within preprocessLayerStack, the buildstyle code is used to generate the target model data by copying data from the source to the target model or by constructing new layer geometry data.
The example buildstyles don't use any meshes from the input geometry at all. The preprocessLayerStack function is used to construct geometry exclusively within the buildstyle. Of course, this isn't a real-world example, but it is a good start to get familiar with ATU's geometry concept.
All buildstyles will refuse to work without having any input geometry, so it is necessary to load a geometry file even if it isn't used later on.
For a start, use the Advanced Toolpath Utility to open the first toolpath creation example buildstyle at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\01_Toolpath-Creation\.
Now, open the Input Geometry Files widget and add the tree_sample_part.stl file as a part to the project. The layer thickness should be 100 micrometers. It can be found ZIP-compressed at C:\ProgramData\Autodesk\ATU\ATU-Examples\Geometry files\.

Hit Compile and check, if you can see geometry and toolpath objects at the exposure preview widget.

Simple Toolpath Creation
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\01_Toolpath-Creation\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\geometry\05_Hatch-Geometry\.
The toolpath code is added to a new file called toolpath.js. This file is called at the main scripts makeExposureLayer function:
exports.makeExposureLayer = function(modelData, hatchResult, nLayerNr) { var toolpath = TOOLPATH.createToolpath(modelData, hatchResult, nLayerNr); hatchResult.moveDataFrom(toolpath); };
This function processes layer toolpaths in parallel.
The toolpath creation is split up into three functions. The createToolpath function is the one, which is called from the main script and it calls createIslandToolpath to generate toolpaths for closed polylines and createPolylineToolpath to generate toolpaths for open polylines.
exports.createToolpath = function(modelData, hatchResult, layerNo) { var toolpath = new HATCH.bsHatch(); /* * Process closed geometry. */ var islandIterator = modelData.getFirstIsland(layerNo) do { // Processes the current island if( islandIterator.isValid() ) { createIslandToolpath( islandIterator.getIsland(), islandIterator.getModelSubtype(), toolpath); } }while( islandIterator.next() ); /* * Process non closed geometry. */ var polylineIterator = modelData.getFirstLayerPolyline( layerNo, POLY_IT.nLayerOpenPolylines); do { if( polylineIterator.isValid() ) { createPolylineToolpath( polylineIterator.clone(), polylineIterator.getModelSubtype(), toolpath); } }while( polylineIterator.next() ); // Return toolpath return toolpath; }; function createPolylineToolpath(polyline, geometryType, toolpath) { polyline.polylineToHatch(toolpath); } function createIslandToolpath( island, geometryType, toolpath) { /* Creates an island, that is 25 micrometers smaller, than the original island. The laser operation will affect more material, so that the object will have the right size in the end.*/ var beamCompensatedIsland = new ISLAND.bsIsland(); island.createOffset(beamCompensatedIsland, -0.025); beamCompensatedIsland.borderToHatch(toolpath); /* Creates another one, that is again 25 micrometers smaller than the first one. This will make the hull more solid */ var beamCompensatedIsland2 = new ISLAND.bsIsland(); beamCompensatedIsland. createOffset(beamCompensatedIsland2, -0.025); beamCompensatedIsland2.borderToHatch(toolpath); /* Creates in "inner" island, that will be used to create the internal object structure */ var innerIsland = new ISLAND.bsIsland(); beamCompensatedIsland2. createOffset(innerIsland, -0.025); innerIsland.borderToHatch(toolpath); /* Creates the hatch pattern for the inner island */ var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); innerIsland.hatch(tempHatch, 1.0, 90.0, HATCH.nHatchFlagAlternating); //toolpath.moveDataFrom(tempHatch); return toolpath; }
Functional Description (Step by Step)
Starting with the createToolpath function:
A bsHatch object is created and it will be passed to the toolpath calculation functions later on, to be filled with toolpath geometry data.
var toolpath = new HATCH.bsHatch();
The function iterates over all closed and later all opened polylines.
exports.createToolpath = function(modelData, hatchResult, layerNo) { var islandIterator = modelData.getFirstIsland(layerNo) do { }while( islandIterator.next() ); . . .
. . . var polylineIterator = modelData.getFirstLayerPolyline( layerNo, POLY_IT.nLayerOpenPolylines); do { }while( polylineIterator.next() ); };
For each loop, the iterator is checked and the processing function is called with three parameters:
- The island or polyline object.
- The model subtype (identifying the geometry as part or support geometry data).
- The hatch container object.
if( islandIterator.isValid() ) { createIslandToolpath( islandIterator.getIsland(), islandIterator.getModelSubtype(), toolpath); }
A toolpath for opened polylines is created by simply adding the polyline as hatch geometry to the final hatch object.
function createPolylineToolpath(polyline, geometryType, toolpath) { polyline.polylineToHatch(toolpath); }
A toolpath for closed polylines is created. This is a bit more complicated.
function createIslandToolpath( island, geometryType, toolpath) { /* Creates an island, that is 25 micrometers smaller, than the original island. The laser operation will affect more material, so that the object will have the right size in the end.*/ var beamCompensatedIsland = new ISLAND.bsIsland(); island.createOffset(beamCompensatedIsland, -0.025); beamCompensatedIsland.borderToHatch(toolpath); /* Creates another one, that is again 25 micrometers smaller than the first one. This will make the hull more solid */ var beamCompensatedIsland2 = new ISLAND.bsIsland(); beamCompensatedIsland. createOffset(beamCompensatedIsland2, -0.025); beamCompensatedIsland2.borderToHatch(toolpath); /* Creates in "inner" island, that will be used to create the internal object structure */ var innerIsland = new ISLAND.bsIsland(); beamCompensatedIsland2. createOffset(innerIsland, -0.025); innerIsland.borderToHatch(toolpath); /* Creates the hatch pattern for the inner island */ var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); innerIsland.hatch(tempHatch, 1.0, 90.0, HATCH.nHatchFlagAlternating); //toolpath.moveDataFrom(tempHatch); return toolpath; }
The first important part is the laser beam compensation. Instead of using the island border as a toolpath, which would make the part bigger as expected, a new, smaller island is created as an offset of the original island. This smaller island is added to the hatch container as toolpath.
var beamCompensatedIsland = new ISLAND.bsIsland(); island.createOffset(beamCompensatedIsland, -0.025); beamCompensatedIsland.borderToHatch(toolpath);

The inner part of the object is filled using a hatch pattern:

Building the object with such a hatch pattern only, would result in a bad object hull, because the stripe pattern may become apparent at the object's hull. Two other offsets, next to the beam compensation offset are used to create a good quality hull.

/* Creates another one, that is again 25 micrometers smaller than the first one. This will make the hull more solid */ var beamCompensatedIsland2 = new ISLAND.bsIsland(); beamCompensatedIsland. createOffset(beamCompensatedIsland2, -0.025); beamCompensatedIsland2.borderToHatch(toolpath); /* Creates in "inner" island, that will be used to create the internal object structure */ var innerIsland = new ISLAND.bsIsland(); beamCompensatedIsland2. createOffset(innerIsland, -0.025); innerIsland.borderToHatch(toolpath);
After all, the inner hatch pattern is generated.
/* Creates the hatch pattern for the inner island */ var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch);
A new, temporary hatch container has to be created, because the hatch function deletes existing hatch geometry from the result hatch container.
The hatch pattern is created with a density of 1.0 and an angle of 60 degrees.
Later, the generated hatch data is moved to the result hatch container.
Toolpath Attributes
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\02_Toolpath-Attributes\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\geometry\05_Hatch-Geometry\.
The toolpath code is added to a new file called toolpath.js. This file is called at the main scripts makeExposureLayer function:
exports.makeExposureLayer = function(modelData, hatchResult, nLayerNr) { var toolpath = TOOLPATH.createToolpath(modelData, hatchResult, nLayerNr); hatchResult.moveDataFrom(toolpath); };
In addition, two attributes are declared at the main.js file. Toolpath attributes have to be declared at declareBuildAttributes, otherwise they aren't accessible.
exports.declareBuildAttributes = function(buildAttrib) { buildAttrib.declareAttributeInt('power'); buildAttrib.declareAttributeReal('speed'); };
Functional Description
Toolpath attributes are added for opened and closed polylines. The following code box shows the original version of the createPolylineToolpath function.
The createPolylineToolpath before adding attributes:
function createPolylineToolpath(polyline, geometryType, toolpath) { polyline.polylineToHatch(tempHatch); }
The createPolylineToolpath after adding attributes:
Instead of writing the hatch geometry directly to the overall toolpath hatch object, a temporary hatch object is used now. This temporary object is moved to the overall hatch object at the end.
This was changed, because now the temporary hatch object does not contain any toolpath geometry from previous toolpath calculations.
An iterator is used to step through all generated bsHatchBlock objects (In this case there is one bsHatchBlock object available).
For every hatch block, power attributes are set for the first three points and the fourth segment of the toolpath geometry.
function createPolylineToolpath(polyline, geometryType, toolpath) { var tempHatch = new HATCH.bsHatch(); polyline.polylineToHatch(tempHatch); var hatchBlockIt = tempHatch.getHatchBlockIterator(); do { if( hatchBlockIt.isValid() ) { var block = hatchBlockIt.get(); block.setPointAttributeInt(0,'power', 50, false); block.setPointAttributeInt(1,'power', 30, false); block.setPointAttributeInt(2,'power', 60, false); block.setPointAttributeInt(3,'power', 100, true); } }while(hatchBlockIt.next()); toolpath.moveDataFrom(tempHatch); }
For closed polylines, toolpath attributes are added to every hatch block.
The temporary hatch object contains geometry from the hatch pattern generation only. An iterator steps through all bsHatchBlocks and adds a speed parameter to all pattern geometry segments.
. . . /* Creates the hatch pattern for the inner island */ var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); var hatchBlockIt = tempHatch.getHatchBlockIterator(); do { if( hatchBlockIt.isValid() ) { var block = hatchBlockIt.get(); block.setAttributeReal('speed', 50.45); } }while(hatchBlockIt.next()); toolpath.moveDataFrom(tempHatch); return toolpath; }
Examine Buildstyle Calculation Results
The following picture shows the open polyline structure of the buildstyle project.

Using the right mouse button action shows the popup menu. The "attribute info" menu entry opens a property dialog box. Moving the mouse across the line segments, while the attribute information dialog is still open, shows the attributes for different points and segments.
![]() |
![]() |
A closer look at the attribute information dialog box shows the difference between point and edge (segment) attributes.
The next picture shows the rectangular geometry from the buildstyle:

The attribute information dialog for the inner toolpath shows the speed attribute at the exposure (#23), instead of showing it at the segment. The example above has added attributes to the segment itself. Here it was added to the whole hatch block.

Sensitive Areas
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\03_Sensitive-Areas\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\geometry\05_Hatch-Geometry\.
The toolpath code is added to a new file called toolpath.js. This file is called at the main scripts makeExposureLayer function:
Functional Description
The Advanced Toolpath Utility build processor recognizes sensitive areas like upskin, downskin, overhang areas as well as pointed edges. Buildstyle developers can use this information to create more robust toolpaths, producing parts in better quality. The examples below add geometry from sensitive areas in one step to the toolpath (hatch object). Keep in mind, that it is also possible to retrieve geometry from sensitive areas as bsPathSet objects, so that paths can be directly modified.
The createToolpath function starts different operations, that create sensible areas of different types. Only closed polylines are considered here.
exports.createToolpath = function(modelData, hatchResult, layerNo) { var toolpath = new HATCH.bsHatch(); /* * Process closed geometry. */ var islandIterator = modelData.getFirstIsland(layerNo) do { // Processes the current island if( islandIterator.isValid() ) { getOverhangAreas(islandIterator.getIsland(), toolpath); getMultipleLayerOverhangAreas(islandIterator.getIsland(), toolpath); getOverlapOverhang(islandIterator.getIsland(), toolpath); // getSkinAreas(islandIterator.getIsland(), // toolpath); getNarrowAppendix(islandIterator.getIsland(), toolpath); getNarrowBridge(islandIterator.getIsland(), toolpath); } }while( islandIterator.next() ); /* Return toolpath */ return toolpath; };
The following example adds bridge sections (areas, that are too thin for creating the desired hatching) to the hatch object.

/* Bridging of two seperate areas */ function getNarrowBridge(island, toolpath) { var offsetedIsland = new ISLAND.bsIsland(); island.createOffset(offsetedIsland, -0.3); var tempHatch = new HATCH.bsHatch(); island.createNarrowBridgePolylines(tempHatch,-0.3); toolpath.moveDataFrom(tempHatch); // offsetedIsland.borderToHatch(toolpath); }
The following example adds sections with pointed edges (edge regions, that are too thin for the hatch pattern) to the hatch object.

/* Pointing edges */ function getNarrowAppendix(island, toolpath) { var offsetedIsland = new ISLAND.bsIsland(); island.createOffset(offsetedIsland, -0.3); var tempHatch = new HATCH.bsHatch(); island.createNarrowAppendixPolylines(tempHatch,-0.3, 1.0); toolpath.moveDataFrom(tempHatch); //offsetedIsland.borderToHatch(toolpath); }
The following example adds upskin areas to the hatch object.
![]() |
![]() |
/* Upskin areas */ function getSkinAreas(island, toolpath) { var skin = new ISLAND.bsIsland(); var noSkin = new ISLAND.bsIsland(); island.splitSkin(skin,noSkin, true); var tempHatch = new HATCH.bsHatch(); skin.hatch(tempHatch, 0.3, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); //noSkin.borderToHatch(toolpath); }
The following example adds overhang sections to the hatch object.
![]() |
![]() |
/* Overhang (simple) */ function getOverhangAreas(island, toolpath) { var normal = new ISLAND.bsIsland(); var overhang = new ISLAND.bsIsland(); island.splitOverhang(normal,overhang); //normal.borderToHatch(toolpath); var tempHatch = new HATCH.bsHatch(); overhang.hatch(tempHatch, 0.3, 180, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); }
The following example calculates overhangs across multiple layers with a defined downskin angle (this example uses 3 layers and an angle of 20 degrees).
![]() |
![]() |
/* Overhang (multiple layers and downskin angle are considered) */ function getMultipleLayerOverhangAreas(island, toolpath) { var volume = new ISLAND.bsIsland(); var overhang = new ISLAND.bsIsland(); var overhangNoOverlap = new ISLAND.bsIsland(); island.splitMultiLayerOverhang(20, 0.0, 3, volume, overhang, overhangNoOverlap); var tempHatch = new HATCH.bsHatch(); overhang.hatch(tempHatch, 0.3, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); }
The following example finds a bridge section from overhang to the regular area.
![]() |
![]() |
/* Overhang (Multiple layers, upskin angle and border area are considered ) */ function getOverlapOverhang(island, toolpath) { var volume = new ISLAND.bsIsland(); var overhang = new ISLAND.bsIsland(); var overhangNoOverlap = new ISLAND.bsIsland(); island.splitMultiLayerOverhang(30, 1.0, 3, volume, overhang, overhangNoOverlap); overhang.subtract(overhangNoOverlap); var tempHatch = new HATCH.bsHatch(); overhang.hatch(tempHatch, 0.3, 120, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); }
Detailed Toolpath Creation
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\04_Advanced-Hatching\.
This toolpath example buildstyle is based upon the "Simple Toolpath Creation" example, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\01_Toolpath-Creation\.
The hatch pattern at the createIslandToolpath function was replaced by three possible function calls, demonstrating different hatch options:
The createIslandToolpath function from the "Simple Toolpath Creation" example:
function createIslandToolpath( island, geometryType, toolpath) { . . . /* Creates the hatch pattern for the inner island */ var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); return toolpath; }
The three function calls for alternate hatch patterns. By commenting out two of the three operations a single operation can be examined. The following example only uses the flexDensityAndAlternateHatching demonstration.
function createIslandToolpath( island, geometryType, toolpath, layerNo) { . . . flexDensityAndAlternateHatching(innerIsland, toolpath); //fixedHatchPatternOrigin(innerIsland, toolpath); //createStripeRegions(innerIsland, toolpath); return toolpath; }
Functional Description
The flexDensityAndAlternateHatching example demonstrates two hatch pattern parameters: A flexible hatch density and alternating directions.
The two options are just passed to the hatch function. The angle for the hatch pattern is set to 0 and the desired hatch density is 1.0 mm.
function flexDensityAndAlternateHatching(innerIsland, toolpath) { var angle = 0; var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, angle, HATCH.nHatchFlagFlexDensity | HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); }
The fixedHatchPatternOrigin example demonstrates a fixed origin for hatch patterns.
The start point can be positioned anywhere on the layer. The pattern generator will use that point as a reference. The angle for the hatch pattern is set to 90 degrees and the desired hatch density is 2.0 mm.
function fixedHatchPatternOrigin(innerIsland, toolpath) { var angle = 90; var tempHatch = new HATCH.bsHatch(); var startPoint = new VEC2.Vec2(-1.0, -5.0); /* Creates the hatch pattern for the inner island */ innerIsland.hatchExt(tempHatch, startPoint, 2.0, angle, HATCH.nHatchFlagFixedOrigin); toolpath.moveDataFrom(tempHatch); }
The createStripeRegions example demonstrates stripe generation. A more advanced demonstration of stripes can be found at the programming examples section. The chessboard demonstration buildstyle uses the stripes to generate a chess board pattern.
It uses the createStripes function to split up islands into a region of several stripes. The result is an bsIsland object containing several islands (the stripes).
function createStripeRegions(innerIsland, toolpath) { var angle = 0; /* create stripes */ var resultStripes = new ISLAND.bsIsland(); innerIsland.createStripes(resultStripes, 2.0, 1.0, -0.25, 100.0, 15); . . . }
The takeOutDiscreteArea function can be used to extract each stripe (curIsland) one by one from the stripe results island object.
. . . var curIsland = new ISLAND.bsIsland(); while( resultStripes.takeOutDiscreteArea(curIsland) ) { . . . } . . .
Each stripe will have a border and is filled with geometry from a hatch pattern. The hatch pattern's angle is alternated between 0 and 90 degrees.
. . . if( angle == 90 ){ angle = 0; } else{ angle = 90; } curIsland.borderToHatch(toolpath); var tempHatch = new HATCH.bsHatch(); curIsland.hatch(tempHatch, 1.0, angle, HATCH.nHatchFlagFixedOrigin | HATCH.nHatchFlagAlternating); toolpath.moveDataFrom(tempHatch); curIsland.makeEmpty(); . . .
Examine Buildstyle Calculation Results
For the flexDensityAndAlternateHatching example the following hatch function has to be used in createIslandToolpath.
flexDensityAndAlternateHatching(innerIsland, toolpath); //fixedHatchPatternOrigin(innerIsland, toolpath); //createStripeRegions(innerIsland, toolpath);
The exposure preview widget can be used to get a similar view of the part below. The "hatch" and the "arrows" option have to be turned on.

The direction of the inner hatch pattern is alternating. It starts downwards, goes upwards and then downwards again. Change the flexDensityAndAlternateHatching function by removing the "alternating" option and the direction will change to upwards only.
function flexDensityAndAlternateHatching(innerIsland, toolpath) { var angle = 0; var tempHatch = new HATCH.bsHatch(); innerIsland.hatch(tempHatch, 1.0, angle, HATCH.nHatchFlagFlexDensity); toolpath.moveDataFrom(tempHatch); }

Removing the "density" option will rearrange the internal hatch pattern just a bit.
Now use the exposure preview to show the rectangle.

The z-pos box (at the lower right of the exposure preview panel) can be used to switch between layers. Using it to view the layers above creates the impression, that the hatch patterns lines are moving. The rectangle is getting bigger layer by layer and the hatch pattern is oriented by the rectangle itself. That is why the pattern's lines are aligned on different positions for each layer.
This will lead us to the next example. Change the code at createIslandToolpath matching this:
//flexDensityAndAlternateHatching(innerIsland, toolpath); fixedHatchPatternOrigin(innerIsland, toolpath); //createStripeRegions(innerIsland, toolpath);
The fixedHatchPatternOrigin function orients the hatch pattern to a point anywhere in the layer. Looking at the rectangle again, while stepping through each layer, shows that the pattern is now fixed.
For the last example change the code at createIslandToolpath to this.
//flexDensityAndAlternateHatching(innerIsland, toolpath); //fixedHatchPatternOrigin(innerIsland, toolpath); createStripeRegions(innerIsland, toolpath);
A striped pattern should appear with alternating hatch angles.

Hatch Geometry Modification
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\05_Hatch-Geometry-Modification\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\geometry\05_Hatch-Geometry\.
The toolpath code is added to a new file called toolpath.js. This file is called at the main scripts makeExposureLayer function:
For closed polylines this buildstyle changes the segment length of a generated hatch block and it creates offsets for paths at pointed edge areas. The two operations are done in separate functions (modifyNarrowAppendixPaths and modifyHatchPattern) both called at createToolpath.
exports.createToolpath = function(modelData, hatchResult, layerNo) { var toolpath = new HATCH.bsHatch(); /* * Process closed geometry. */ var islandIterator = modelData.getFirstIsland(layerNo) do { /* Processes the current island */ if( islandIterator.isValid() ) { modifyNarrowAppendixPaths(islandIterator.getIsland(), toolpath); modifyHatchPattern(islandIterator.getIsland(), toolpath); } }while( islandIterator.next() ); /* Return toolpath */ return toolpath; };
Functional Description (Step by Step)
At the modifyNarrowAppendixPaths function pointing edge areas are detected first.
function modifyNarrowAppendixPaths(island, toolpath) { /* Find edge areas */ var tempHatch = new HATCH.bsHatch(); island.createNarrowAppendixPolylines(tempHatch,-0.3, 1.0); . . .
Found geometry data is then written to a bsPathSet object.
. . . /* Create bsPathSet and add hatch geometry */ var hatchPaths = new PATH_SET.bsPathSet(); hatchPaths.addHatches(tempHatch); process.print('Number of paths: [' + hatchPaths.getPathCount() + ' ]'); . . .
An offset is calculated for each path.
. . . /* Process a simple modification (create an offset) */ hatchPaths.createOffset(0.025); . . .
The previously generated hatch geometry is cleared and the offset paths are added to the hatch object. After all, the hatch data is added to the overall hatch object.
. . . /* Delete existing */ tempHatch.clear(); tempHatch.addPaths(hatchPaths); /* Apply hatches */ toolpath.moveDataFrom(tempHatch); }
At the modifyHatchPattern function, a hatch pattern is generated for each island. Since original islands are read only, the island has to be cloned, before creating the pattern. Otherwise no hatch geometry would be created.
function modifyHatchPattern(island, toolpath) { /* Create hatch pattern */ var tempHatch = new HATCH.bsHatch(); island.clone().hatch(tempHatch, 0.5, 30, HATCH.nHatchFlagFixedZeroOrigin); . . .
The pattern geometry is then written to a bsPathSet object.
. . . /* Create bsPathSet and add hatch geometry */ var hatchPaths = new PATH_SET.bsPathSet(); hatchPaths.addHatches(tempHatch); . . .
Every third hatch path is removed and every second path will be shortened. The changeLineLength function only contains code to shorten a line.
. . . /* remove and resize hatch geometry */ for( var index=0; index < hatchPaths.getPathCount(); index ++) { if( (index % 3) == 0){ hatchPaths.deletePath(index); } if( (index % 2) == 0){ var pathPointsArr = hatchPaths.getPathPoints(index); if(pathPointsArr.length == 2) { var newPathSet = changeLineLength(-5.0, pathPointsArr); hatchPaths.deletePath(index); hatchPaths.addPaths(newPathSet); } } } . . .
The generated hatch data is cleared, the new data is added to the temporary object and later on to the final hatch object.
. . . /* Delete generated and add new hatch data */ tempHatch.clear(); tempHatch.addPaths(hatchPaths); /* Apply hatches */ toolpath.moveDataFrom(tempHatch); }
Examine Buildstyle Calculation Results
![]() |
![]() |
Hatch Block Reordering
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\06_Hatch-Block-Sorting\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\geometry\05_Hatch-Geometry\. The toolpath code is added to a new file called toolpath.js. This file is called at the main scripts makeExposureLayer function.
This buildstyle demonstrates how to split up hatch blocks and reorder them according to predefined and custom rules.
exports.createToolpath = function(modelData, hatchResult, layerNo) { /* Process closed geometry. */ var toolpath = new HATCH.bsHatch(); var message = ''; var currentIslandIdx=0; var islandIterator = modelData.getFirstIsland(layerNo) do { /* Processes the current island */ if( islandIterator.isValid() ) { message += 'Processing island no ' + currentIslandIdx + '\n'; var island = islandIterator.getIsland().clone(); /* Create hatch geometry */ var tempHatch = new HATCH.bsHatch(); island.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); /* Use internal hatch block */ var hotspot = new VEC2.Vec2(0.0,0.0); // Only relevant, if // HATCH.nSortFlagUseHotSpot // is used. tempHatch.pathReordering(hotspot, HATCH.nSortFlagShortestPath) /* Iterate all hatch blocks */ var hBlockIt = tempHatch.getHatchBlockIterator(); var hBlockIdx = 0; do { if(hBlockIt.isValid()) { var hatchBlock = hBlockIt.get(); /* Increase power every 5th hatch element */ var minMoveVal = 0; var pointCount = hatchBlock.getPointCount(); for(var idx=0; idx < pointCount; idx += 2) { if( (idx % 10) == 0){ minMoveVal += 10; } hatchBlock.setPointAttributeInt(idx, 'power', minMoveVal, true); } hBlockIdx++; } }while(hBlockIt.next()); message += 'No of hatch blocks before segmenting ' + hBlockIdx + '\n'; /* Split up hatch blocks by differnet power values */ tempHatch.createIntAttribSegmenting('power', false); hBlockIt = tempHatch.getHatchBlockIterator(); hBlockIdx = 0; do { if(hBlockIt.isValid()) { hBlockIdx++; } }while(hBlockIt.next()); message += 'No of hatch blocks after segmenting ' + hBlockIdx + '\n'; toolpath.moveDataFrom(tempHatch); currentIslandIdx++; } }while( islandIterator.next() ); /* Sort hatch blocks */ var hBlockIt = toolpath.getHatchBlockIterator(); var hBlockIdx = 0; var hatchBlockArray = new Array(); do{ if(hBlockIt.isValid()){ hBlockIdx++; hatchBlockArray.push(hBlockIt.get()); } }while(hBlockIt.next()); message += '\nNo of hatch blocks after all ' + hatchBlockArray.length + '\n'; message += '\nUnsorted hatch block list\n'; for(var aIdx=0; aIdx<hatchBlockArray.length; aIdx++){ message += 'Hatch block power val ' + hatchBlockArray[aIdx].getPointAttributeInt(0,'power') + '\n'; } /* Sort hatch blocks according to their power values */ hatchBlockArray.sort(function(hatchA, hatchB) { var powerA = hatchA.getPointAttributeInt(0,'power'); var powerB = hatchB.getPointAttributeInt(0,'power'); return (powerA - powerB); }); /* Clear existing toolpath geometry */ toolpath.makeEmpty(); message += '\nSorted hatch block list\n'; for(var aIdx=0; aIdx<hatchBlockArray.length; aIdx++){ message += 'Hatch block power val ' + hatchBlockArray[aIdx].getPointAttributeInt(0,'power') + '\n'; /* Add sorted hatch block */ toolpath.addHatchBlock(hatchBlockArray[aIdx]); } /* Print log messages */ process.print(message); /* Return toolpath */ return toolpath; };
Functional Description (Step by Step)
The first part of the toolpath operation creates a result hatch object and iterates over all islands.
exports.createToolpath = function(modelData, hatchResult, layerNo) { /* Process closed geometry. */ var toolpath = new HATCH.bsHatch(); var message = ''; var currentIslandIdx=0; var islandIterator = modelData.getFirstIsland(layerNo) do { /* Processes the current island */ if( islandIterator.isValid() ) { message += 'Processing island no ' + currentIslandIdx + '\n'; var island = islandIterator.getIsland().clone(); . . .
Toolpath geometry is generated using a hatch pattern.
. . . /* Create hatch geometry */ var tempHatch = new HATCH.bsHatch(); island.hatch(tempHatch, 1.0, 60, HATCH.nHatchFlagAlternating); . . .
As a simple demonstration, the hatch blocks are sorted using an internal sort method (shortest path). The result is thrown away later on.
. . . /* Use internal hatch block */ var hotspot = new VEC2.Vec2(0.0,0.0); // Only relevant, if // HATCH.nSortFlagUseHotSpot // is used. tempHatch.pathReordering(hotspot, HATCH.nSortFlagShortestPath);
A hatch block iterator is used to add an increasing power value attribute to the segments of the generated toolpath geometry.
. . . /* Iterate all hatch blocks */ var hBlockIt = tempHatch.getHatchBlockIterator(); var hBlockIdx = 0; do { if(hBlockIt.isValid()) { var hatchBlock = hBlockIt.get(); /* Increase power every 5th hatch element */ var minMoveVal = 0; var pointCount = hatchBlock.getPointCount(); for(var idx=0; idx < pointCount; idx += 2) { if( (idx % 10) == 0){ minMoveVal += 10; } hatchBlock.setPointAttributeInt(idx, 'power', minMoveVal, true); } hBlockIdx++; } }while(hBlockIt.next()); . . .
The hatch blocks are split up according to their power values.
. . . /* Split up hatch blocks by differnet power values */ tempHatch.createIntAttribSegmenting('power', false); . . .
The new amount of available hatch blocks is determined.
hBlockIt = tempHatch.getHatchBlockIterator(); hBlockIdx = 0; do { if(hBlockIt.isValid()) { hBlockIdx++; } }while(hBlockIt.next());
All hatch blocks from all islands are moved to an array (hatchBlockArray).
. . . /* Sort hatch blocks */ var hBlockIt = toolpath.getHatchBlockIterator(); var hBlockIdx = 0; var hatchBlockArray = new Array(); do{ if(hBlockIt.isValid()){ hBlockIdx++; hatchBlockArray.push(hBlockIt.get()); } }while(hBlockIt.next()); . . .
The array is sorted.
. . . /* Sort hatch blocks according to their power values */ hatchBlockArray.sort(function(hatchA, hatchB) { var powerA = hatchA.getPointAttributeInt(0,'power'); var powerB = hatchB.getPointAttributeInt(0,'power'); return (powerA - powerB); }); . . .
Examine Buildstyle Calculation Results
This buildstyle creates output to the buildstyle log widget.
The first thing to examine is the amount of hatch blocks before and after splitting them according to their power values.
Processing island no 0 No of hatch blocks before segmenting 1 No of hatch blocks after segmenting 6 Processing island no 1 No of hatch blocks before segmenting 1 No of hatch blocks after segmenting 6 Processing island no 2 No of hatch blocks before segmenting 1 No of hatch blocks after segmenting 4 Processing island no 3 No of hatch blocks before segmenting 1 No of hatch blocks after segmenting 3 Processing island no 4 No of hatch blocks before segmenting 0 No of hatch blocks after segmenting 0 Processing island no 5 No of hatch blocks before segmenting 1 No of hatch blocks after segmenting 11
Then, the hatch block order is displayed by showing the power values before and after sorting.
Unsorted hatch block list Hatch block power val 10 Hatch block power val 20 Hatch block power val 30 Hatch block power val 40 Hatch block power val 50 Hatch block power val 60 Hatch block power val 10 Hatch block power val 20 Hatch block power val 30 Hatch block power val 40 Hatch block power val 50 Hatch block power val 60 Hatch block power val 10 Hatch block power val 20 Hatch block power val 30 Hatch block power val 40 Hatch block power val 10 Hatch block power val 20 Hatch block power val 30 Hatch block power val 10 Hatch block power val 20 Hatch block power val 30 Hatch block power val 40 Hatch block power val 50 Hatch block power val 60 Hatch block power val 70 Hatch block power val 80 Hatch block power val 90 Hatch block power val 100 Hatch block power val 110 Sorted hatch block list Hatch block power val 10 Hatch block power val 10 Hatch block power val 10 Hatch block power val 10 Hatch block power val 10 Hatch block power val 20 Hatch block power val 20 Hatch block power val 20 Hatch block power val 20 Hatch block power val 20 Hatch block power val 30 Hatch block power val 30 Hatch block power val 30 Hatch block power val 30 Hatch block power val 30 Hatch block power val 40 Hatch block power val 40 Hatch block power val 40 Hatch block power val 40 Hatch block power val 50 Hatch block power val 50 Hatch block power val 50 Hatch block power val 60 Hatch block power val 60 Hatch block power val 60 Hatch block power val 70 Hatch block power val 80 Hatch block power val 90 Hatch block power val 100 Hatch block power val 110
Hull/Core Generation
The buildstyle can be found at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\07_Hull-Core\.
The toolpath example buildstyles are based upon the hatch geometry buildstyle from the geometry processing chapter, at C:\ProgramData\Autodesk\ATU\ATU-Examples\tutorial-projects\toolpathing\05_Hatch-Geometry-Modification\.
Separating hull and core areas of solid parts is one idea of getting parts printed faster. The idea is to save time by skipping the print operation for several layers at the core area. Only for the core region the laser power is increased, so that more material is affected at the build process and the material for the skipped layers is melted afterwards. Of course, the build quality is worse but it doesn't matter for areas inside of parts.

The hull and core generator works in the 3D space and it is a buildstyle feature and has to be activated. This is done at the main.js script.
exports.declareModelFeatures = function(modelFeatures) { modelFeatures.enableFeature(MODEL_FEATURES.nFeatureHullAndCore, true); };
Hull and core generation is added at the main.js script at makeExposureLayer.
exports.makeExposureLayer = function(modelData, hatchResult, nLayerNr) { var islandIterator = modelData.getFirstIsland(nLayerNr); do { /* Processes the current island */ if( islandIterator.isValid() ) { var hullIsland = new ISLAND.bsIsland(); var hullIsland2 = new ISLAND.bsIsland(); var coreIsland = new ISLAND.bsIsland(); var outerHullIndex = 0; var innerHullIndex = 1; var outerHullSkip = 1; var innerHullSkip = 2; var coreSkip = 3; var surfaceOffset = 0.0; var hullCoreGen = new HULLGEN.bsHullAndCoreGenerator(); hullCoreGen.setTolerance(0.25); hullCoreGen.addHull(outerHullSkip, 0.26); hullCoreGen.addHull(innerHullSkip, 0.5); hullCoreGen.setCoreSkip(coreSkip); hullCoreGen.setSurfaceOffset(surfaceOffset); var island = islandIterator.getIsland().clone(); hullCoreGen.createHull(outerHullIndex, island, hullIsland); hullCoreGen.createHull(innerHullIndex, island, hullIsland2); hullCoreGen.createCore(island, coreIsland); if( hullCoreGen.needHullExposure(outerHullIndex)){ hullIsland.borderToHatch(hatchResult); } if( hullCoreGen.needHullExposure(innerHullIndex)){ hullIsland2.borderToHatch(hatchResult); } var offsetCoreIsland = new ISLAND.bsIsland(); coreIsland.createOffset(offsetCoreIsland, -0.1); if( hullCoreGen.needCoreExposure()){ offsetCoreIsland.borderToHatch(hatchResult); } } }while( islandIterator.next() ); };
Functional Description (Step by Step)
The first block initializes the hull and core generator.
exports.makeExposureLayer = function(modelData, hatchResult, nLayerNr) { var islandIterator = modelData.getFirstIsland(nLayerNr); var hullIsland = new ISLAND.bsIsland(); var hullIsland2 = new ISLAND.bsIsland(); var coreIsland = new ISLAND.bsIsland(); var outerHullIndex = 0; var innerHullIndex = 1; var outerHullSkip = 1; var innerHullSkip = 2; var coreSkip = 3; var surfaceOffset = 0.0; var hullCoreGen = new HULLGEN.bsHullAndCoreGenerator(); hullCoreGen.setTolerance(0.25); hullCoreGen.addHull(outerHullSkip, 0.26); hullCoreGen.addHull(innerHullSkip, 0.5); hullCoreGen.setCoreSkip(coreSkip); hullCoreGen.setSurfaceOffset(surfaceOffset); . . .
For each island two hull and the core islands are generated.
. . . do { /* Processes the current island */ if( islandIterator.isValid() ) { var island = islandIterator.getIsland().clone(); hullCoreGen.createHull(outerHullIndex, island, hullIsland); hullCoreGen.createHull(innerHullIndex, island, hullIsland2); hullCoreGen.createCore(island, coreIsland);
Depending on a specified layer skip value the hulls island borders are added as hatch geometry.
. . . if( hullCoreGen.needHullExposure(outerHullIndex)){ hullIsland.borderToHatch(hatchResult); } if( hullCoreGen.needHullExposure(innerHullIndex)){ hullIsland2.borderToHatch(hatchResult); } . . .
The border island is offset and added as hatch geometry.
. . . var offsetCoreIsland = new ISLAND.bsIsland(); coreIsland.createOffset(offsetCoreIsland, -0.1); if( hullCoreGen.needCoreExposure()){ offsetCoreIsland.borderToHatch(hatchResult); } . . .
Examine Buildstyle Calculation Results
This buildstyle invites to play with different parameters.
Here are two examples:
Example 1 | Example 2 |
---|---|
var outerHullIndex = 0; var innerHullIndex = 1; var outerHullSkip = 1; var innerHullSkip = 2; var coreSkip = 3; var surfaceOffset = 0.0; |
var outerHullIndex = 0; var innerHullIndex = 1; var outerHullSkip = 1; var innerHullSkip = 2; var coreSkip = 3; var surfaceOffset = -0.2; |
The second hull starts at layer 3 (300 micrometers). The core starts at layer 8 (800 micrometers). The second hull is generated every second layer. The core is generated every third layer. |
The second hull starts at layer 4 (400 micrometers). The core starts at layer 10 (1000 micrometers). The second hull is generated every second layer. The core is generated every third layer. A negative hull offset of 0.2 is added |
At 800 micrometers the first and the second hull are generated. The third, closed polyline in the middle is the inner loop (the hole) of the second hull. The core is skipped. It is rendered every third layer. |
At 1000 micrometers the first and the second hull are generated. The first hull is now an offset region inside the part's border island The third, closed polyline in the middle is the inner loop (the hole) of the second hull. The core is skipped. It is rendered every third layer. |
800 micrometers ![]() |
1000 micrometers ![]() |
At 1200 micrometers the first and the second hull as well as the core are generated. The third, closed polyline in the middle is the inner loop (the hole) of the second hull. The fourth, closed polyline is the offset core border. |
At 1200 micrometers the first and the second hull as well as the core are generated. The third, closed polyline in the middle is the inner loop (the hole) of the second hull. The fourth, closed polyline is the offset core border. |
1200 micrometers ![]() |
1200 micrometers ![]() |