Metamation Developer Notes

  • Developer Notes
  • Resource Map
  • Tools
    • Code Formatting
    • Configuring Git
    • Assignments
    • Testing with Windows Sandbox
    • Single Binary Applications
    • Self-Updating Applications
  • Flux Workflow
    • Flux Workflow
    • Flux Development Style Guide
    • Release notes for Flux
    • SonarCloud analysis for Flux
    • Build a Flux SDK Program
    • Shipping Flux
    • Flux.Test
      • BasicBendAuto Test
      • LaserAuto.cs Detailed Documentation
      • Laserexample:Test1
  • Technical Notes
    • File formats
      • .FX File Format
      • Au(Gold) streams
      • .GEO File Format
      • .LST File Format
      • .LST file - technology
      • .BNC File Format
      • .WAD Files: Flux Resource Packages
      • .Curl Files: ASCII config information
    • Folders App
      • Data\Bendtools
      • Data\Machines
    • FluxCode
      • Welcome & Repo Map
      • Architecture & System Context
      • Subsystem *Bend* (Press Brake)
      • Subsystem *BCell* (Bend Cell Automation)
      • API Maps
      • Data Model Catalog
      • Design Patterns -- A Reader's Guide
      • Tests and Golden Paths
      • Guided Code Tours
      • CAM Glossary with Code Mapping
      • Assignments
      • Flux Onboarding Handbook
    • Data flow
      • Part
        • Part.Dwg
        • Part.Load
        • Part.Load to Part.Dwg
      • BendTech.cs
      • Bend Technology
      • Laser Cutting Technology
    • LTS (Long term support mechanism)
    • Machine ID Scheme
  • FluxTester
    • Commands and Scripts
    • Command Cookbook
    • Script Commands
    • BendTooling.cs Test Inventory
    • LaserTooling.cs Test Steps
    • Fluxtester Recipe Book
    • Nesting.cs Overview
    • Nesting.cs Recipe Book
    • Job.cs Overview
    • Job.cs Recipe Book
  • Software license
  • 3d party software
    • Python
  • Documentation
    • Bento documentation
      • Structure of a Bento page
      • Attributes
    • Software
      • Software Requirement
      • Installation
      • Git workflow for documentation contributors
    • Quick start guide
    • Workflow
      • Roles and responsibilities
      • Analyze
      • Edit
      • Proofread
      • Pre-Publish
      • Publish
      • Release cycle
      • Information required for Documentation Team
      • Checklist for Documenters
    • Styleguide
    • Flavoring
    • Translation
      • Ordering translation for a new document
    • Citations
    • Annotation
FluxTester
/
Nesting.cs Recipe Book

Nesting.cs Recipe Book

Table of Contents

  1. Test Structure & Attributes

  2. Fixture Setup & Teardown

  3. File Operations

  4. Navigation & View Management

  5. Quick-Nest Operations

  6. Part Selection

  7. Part Manipulation

  8. Keyboard & Input Commands

  9. Mouse Operations

  10. Renesting Operations

  11. Validation & Assertions

  12. Script Execution

  13. Common Nesting Workflows

  14. Helper Methods Reference


Test Structure & Attributes

Basic Nesting Test Template

[TestFixture (1501, "Nesting Test", Module = "FluxCut", Subsystem = "Nesting")]
class Nesting {
    const string fxFile = "123.fx";
    const string testMachineID = "2230001";

    [FixtureInitialize]
    public void Init () {
        // Setup machines and resources
        Utils.InstallCutMachines (testMachineID);
    }

    [FixtureCleanUp]
    public void CleanUp () {
        // Clean temporary files
        foreach (var file in Directory.GetFiles (Utils.tempPath)) {
            if (file.Contains (".txt") || file.Contains (".png")) File.Delete (file);
        }
        Utils.UninstallMachine (testMachineID);
    }

    [Test (ID, "Test Description", Type = TestType.Functional)]
    public void Test_CaseID () {
        // Test implementation
    }
}

Machine IDs

const string testMachineID = "2230001";      // Primary test machine
Utils.InstallCutMachines (testMachineID);    // Install machines
Utils.UninstallMachine (testMachineID);      // Uninstall after tests

Fixture Setup & Teardown

Installation & Configuration

// Install cutting machine(s)
[FixtureInitialize]
public void Init () => Utils.InstallCutMachines ("2230001");

// Set default machine via script
Utils.RunScript ("Flux.CutMachine.Default = Flux.CutMachine.Get (2230001);");

// Set part thickness via script
Utils.RunScript ("Flux.PartEditor.Current.Part.Info.Thickness = 4;");

Resource Cleanup

[FixtureCleanUp]
public void CleanUp () {
    // Delete temporary .txt files
    foreach (var file in Directory.GetFiles (Utils.tempPath)) {
        if (file.Contains (".txt")) File.Delete (file);
    }

    // Delete temporary .png files
    foreach (var file in Directory.GetFiles (Utils.tempPath)) {
        if (file.Contains (".png")) File.Delete (file);
    }

    // Combined cleanup
    foreach (var file in Directory.GetFiles (Utils.tempPath)) {
        if (file.Contains (".txt") || file.Contains (".png")) File.Delete (file);
    }

    // Uninstall machine
    Utils.UninstallMachine ("2230001");
}

File Operations

Opening Files

// Open part file
Utils.OpenFile (Utils.tData + "123.fx");
Utils.OpenFile (Utils.tData + fxFile);

// Open drawing file
Utils.OpenFile (Utils.tData + "thinComplex.dxf");

// Open with path construction
Utils.OpenFile (Utils.tData + filename);

File References

// Temporary paths
Utils.tempPath              // "c:/programdata/metamation/temp/"
Utils.tempPath + "test.png"
Utils.tempPath + "temp.txt"

// Test data paths
Utils.tData                 // Test data directory
Utils.tData + "123.fx"      // Primary test file
Utils.tData + "thinComplex.dxf"
Utils.tData + "Test_C122169/test_MovePartByDrag.txt"

Navigation & View Management

View Switching

// Switch to CutCAM view (laser tooling view)
Utils.Type ('l');

// Switch to Nesting view
Utils.Type ('n');

// Switch to settings
Utils.Type ('t');
Utils.Type ('a');  // Layout settings

// Access Layout view via script
Utils.RunScript ("Flux.PartEditor.Current.Skin = Layout");
Utils.RunScript ("Flux.PartEditor.Current.Skin = CutCAM");

Workflow Panel

// Open workflow panel
Utils.MainWin.FindFirstDescendant (e => e.ByName ("workflow")).Click ();

// Access workflow elements
var workflowElems = Utils.FindElement (() => Utils.MainWin.FindFirstChild ("WorkflowPanel")).FindAllChildren ();

// Find Quick-Nest button
var qnIcon = workflowElems.First (a => a.Name.StartsWith ("Quick-Nest"));
var pt = qnIcon.GetClickablePoint ();

// Check if Layout exists
workflowElems.FirstOrDefault (a => a.Name.StartsWith ("Layout")) != null

Settings Panel

// Open settings
var settings = Utils.MainWin.FindFirstChild ("SheafEditor");

// Access settings elements
layoutSettings.FindFirstDescendant (a => a.ByName ("Cut View")).Click ();
layoutSettings.FindFirstChild (a => a.ByClassName ("ScrollViewer"));

// Navigate sections
settings.FindFirstChild (a => a.ByControlType (ControlType.Pane));

Quick-Nest Operations

Creating Quick-Nest

// Basic quick nest (entire part)
DoNewQuickNest ();

// Single-part quick nest
DoNewQuickNest (true);

// Multi-part quick nest
DoNewQuickNest (false);

// Internal implementation
internal static void DoNewQuickNest (bool singlePart = false) {
    Utils.Type ('l');  // Switch to CutCAM view
    Utils.MainWin.FindFirstDescendant (e => e.ByName ("workflow")).Click ();

    var workflowElems = Utils.FindElement (() => Utils.MainWin.FindFirstChild ("WorkflowPanel"))
        .FindAllChildren ();
    var qnIcon = workflowElems.First (a => a.Name.StartsWith ("Quick-Nest"));
    var pt = qnIcon.GetClickablePoint ();

    // Delete existing layout
    if (workflowElems.FirstOrDefault (a => a.Name.StartsWith ("Layout")) != null) {
        Utils.MouseClick (pt, CONTROL);
        Utils.Type (LEFT); Utils.Type (ENTER);
    }

    // Create new quick nest
    Utils.MouseClick (pt, singlePart ? SHIFT : None);
    Thread.Sleep (500);
    Utils.Type (ESCAPE);
}

Quick-Nest with Modifiers

// Single-part nest (with Shift key)
Utils.MouseClick (qnBtn, SHIFT);

// Standard multi-part nest
Utils.MouseClick (qnBtn);

// Delete existing nest
Utils.MouseClick (pt, CONTROL);  // Ctrl+click
Utils.Type (LEFT);               // Navigate to Yes
Utils.Type (ENTER);              // Confirm

Part Selection

Selection Methods

// Select by point click
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));

// Select by double-click
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)), doubleClick: true);

// Select by double-click (alternative syntax)
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90, 0)), doubleClick: true);

// Select similar parts
SelectPartsBy ("Similar");

// Select same parts
SelectPartsBy ("Same Parts");

// Select parts in row
SelectPartsBy ("Similar Parts in Row");

// Select parts in column
SelectPartsBy ("Similar Parts in Column");

Selection Helper

internal static AutomationElement SelectPartsBy (string option) {
    var g = Utils.WaitForGlob ();
    g.FindFirstChild (a => a.ByName (option)).Click ();
    return g;
}

Glob Operations (Selection Dialog)

// Wait for selection dialog
var g = Utils.WaitForGlob ();

// Interact with glob options
g.FindFirstChild (a => a.ByName ("All Blocks")).Click ();
g.FindFirstChild (a => a.ByName ("Similar")).Click ();
g.FindFirstDescendant (a => a.ByName ("Explode")).Click ();
g.FindFirstChild (a => a.ByName ("Group")).Click ();
g.FindFirstDescendant (a => a.ByName ("Ungroup")).Click ();

// Return to access glob again
var g = Utils.WaitForGlob ();

Part Manipulation

Part Movement

// Convert measurement points to pixels
var p = Utils.MeasurePtsToPixel ([new (50, 90), new (150, 90)]);

// Move part by dragging
Utils.MouseClick (p[0]);                    // Select part
Utils.DragAndDrop (Mouse.Position, p[1]);  // Drag from current to target
Utils.Type (ESC);                           // Finalize

// Move part by double-click + mouse move
Utils.MouseClick (p[0], true);              // Double-click to enable move
Utils.MouseMove (p[1]);                     // Move to target position
Utils.Type (ESC);                           // Finalize

Creating Duplicates

// Duplicate with Ctrl+drag
var p = Utils.MeasurePtsToPixel ([new (50, 90), new (150, 90)]);
Utils.MouseClick (p[0]);                    // Enable edit mode
using (var ob = Keyboard.Pressing ((VirtualKeyShort)CONTROL))
    Utils.DragAndDrop (Mouse.Position, p[1]);  // Ctrl+drag
Utils.Type (ESC);

Creating Part Arrays

// Array along COLUMN direction
var p = Utils.MeasurePtsToPixel ([
    new (50, 90),       // Click point
    new (87, 167),      // Start point
    new (190, 1500)     // End point
]);
Utils.MouseClick (p[0]);        // Click at corner
Utils.MoveGlob ();              // Move any glob if needed
Utils.DragAndDrop (p[1], p[2]); // Drag to create array

// Array along ROW direction
Utils.Type (ESC);
Utils.Type ('a', CONTROL);      // Ctrl+A to select all
Utils.MoveGlob ();
var p2 = Utils.MeasurePtsToPixel ([
    new (90, 1360),
    new (3000, 1500)
]);
Utils.DragAndDrop (p2[0], p2[1]);
Utils.Type (ESC);

Part Rotation

// Rotate with Ctrl+mouse wheel
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90, 0)), doubleClick: true);
using (Keyboard.Pressing ((VirtualKeyShort)CONTROL))
    Mouse.Scroll (25);  // Rotate by 25 units

Grouping Parts

// Group parts
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));
SelectPartsBy ("Similar").FindFirstDescendant (a => a.ByName ("Group")).Click ();
Utils.Type (ESC);

// Ungroup parts
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));
Utils.WaitForGlob ().FindFirstDescendant (a => a.ByName ("Ungroup")).Click ();

Creating Overlaps

// Move part to create overlap
var p = Utils.MeasurePtsToPixel ([new (50, 90), new (150, 90)]);
Utils.MouseClick (p[0]);
using var ob = Keyboard.Pressing ((VirtualKeyShort)CONTROL);
Utils.DragAndDrop (p[0], p[1]);

Keyboard & Input Commands

Navigation Keys

// View switching
Utils.Type ('l');      // CutCAM view
Utils.Type ('n');      // Nesting view
Utils.Type ('t');      // Settings
Utils.Type ('a');      // Layout/Cut settings
Utils.Type ('w');      // Window/Workspace
Utils.Type ('s');      // Select/Settings
Utils.Type ('k');      // Laser CAM settings

// Finalization
Utils.Type (ESC);      // Escape/Cancel
Utils.Type (ESCAPE);   // Alternative Escape
Utils.Type (ENTER);    // Confirm
Utils.Type (LEFT);     // Navigate left

Modifier Keys

using static FluxTester.Utils.KeyShort;

// Key constants
CONTROL              // Ctrl key
SHIFT                // Shift key
ESC                  // Escape key
ENTER               // Enter key
TAB                 // Tab key
LEFT                // Left arrow
RIGHT               // Right arrow

Multi-Key Input

// Sequential key presses
Utils.Type ('t'); Utils.Type ('a');  // Settings > Layout

// Type character with modifier
Utils.Type ('a', CONTROL);  // Ctrl+A (select all)

// Access key shortcuts with KeyShort
using (Keyboard.Pressing ((VirtualKeyShort)CONTROL))
    Mouse.Scroll (25);  // Ctrl+mouse wheel

using (Keyboard.Pressing ((VirtualKeyShort)SHIFT))
    Utils.DragAndDrop (start, end);  // Shift+drag

Mouse Operations

Basic Mouse Actions

// Single click
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));

// Double click
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)), doubleClick: true);

// Click with modifier
Utils.MouseClick (pt, CONTROL);    // Ctrl+click
Utils.MouseClick (pt, SHIFT);      // Shift+click

// Get current mouse position
var currentPos = Mouse.Position;

Measurement & Conversion

// Single point conversion
var pixelPt = Utils.MeasurePtToPixel (new (X, Y, Z));
var pixelPt = Utils.MeasurePtToPixel (new (153.946, 91.549, 0));

// Multiple points conversion
var pixels = Utils.MeasurePtsToPixel ([
    new (50, 90),
    new (87, 167),
    new (190, 1500)
]);

// Access individual points
pixels[0]  // First point
pixels[1]  // Second point
pixels[2]  // Third point

Drag & Drop

// Simple drag and drop
Utils.DragAndDrop (startPoint, endPoint);

// Drag from current position
Utils.DragAndDrop (Mouse.Position, p[1]);

// Drag with modifier key (Ctrl+drag)
using (Keyboard.Pressing ((VirtualKeyShort)CONTROL))
    Utils.DragAndDrop (start, end);

// Drag with Shift (twinline nesting)
using (var ob = Keyboard.Pressing ((VirtualKeyShort)SHIFT))
    Utils.DragAndDrop (start, end);

Mouse Movement

// Move mouse to position
Utils.MouseMove (Utils.MeasurePtToPixel (new (150, 90)));

// Move glob if in the way
Utils.MoveGlob ();

Mouse Wheel

// Scroll/rotate with modifier
using (Keyboard.Pressing ((VirtualKeyShort)CONTROL))
    Mouse.Scroll (25);  // Rotate parts by 25 units

Renesting Operations

Renest Method

// Renest with specific option
Renest (RenestOption.RearrangeToCreateRemSheet);
Renest (RenestOption.RearrangeToFullSheet);
Renest (RenestOption.SpreadPartsAlongX);
Renest (RenestOption.SpreadPartsAlongY);
Renest (RenestOption.SpreadPartsAlongXY);

// Renest by enum cast (0-4)
for (int i = 0; i < 5; i++) {
    Renest ((RenestOption)i);
}

// Internal implementation
internal static void Renest (RenestOption option) {
    Utils.RunScript ("Flux.PartEditor.Current.Skin = Layout");
    Utils.FindElement (() => Utils.MainWin.FindFirstChild ("CmdBar")
        .FindFirstChild (a => a.ByName ("nesting"))).Click ();

    char key = (option) switch {
        RenestOption.RearrangeToCreateRemSheet => 'a',
        RenestOption.RearrangeToFullSheet => 'b',
        RenestOption.SpreadPartsAlongX => 'c',
        RenestOption.SpreadPartsAlongY => 'd',
        RenestOption.SpreadPartsAlongXY => 'e',
        RenestOption.Cancel or _ => 'f',
    };
    Utils.FindElement (() => Utils.MainWin.FindFirstChild ()
        .FindFirstChild (a => a.ByControlType (ControlType.MenuItem)));
    Utils.Type (key);
}

RenestOption Enum

internal enum RenestOption {
    RearrangeToCreateRemSheet = 0,  // 'a'
    RearrangeToFullSheet = 1,       // 'b'
    SpreadPartsAlongX = 2,          // 'c'
    SpreadPartsAlongY = 3,          // 'd'
    SpreadPartsAlongXY = 4,         // 'e'
    Cancel = 5                      // 'f'
}

Recompute Operations

Recompute Method

// Default recompute (retool all elements)
Recompute ();

// Specific recompute option
Recompute (RecomputeOption.RetoolAllElements);
Recompute (RecomputeOption.ToolOnlyUntooledElements);
Recompute (RecomputeOption.Sequence);
Recompute (RecomputeOption.Routing);

// Internal implementation
internal static void Recompute (RecomputeOption option = RecomputeOption.RetoolAllElements) {
    Utils.Type (ESC);

    bool skinIsLayout = Utils.RunScriptWithOutput ("var result = Flux.PartEditor.Current.Skin.ToString()")
        = "Layout";

    Utils.FindElement (() => Utils.MainWin.FindFirstChild ("CmdBar")
        .FindFirstChild (a => a.ByName ("recompute"))).Click ();

    char key = (option) switch {
        RecomputeOption.RetoolAllElements => skinIsLayout ? 'd' : 'a',
        RecomputeOption.ToolOnlyUntooledElements => skinIsLayout ? 'a' : 'b',
        RecomputeOption.Sequence => skinIsLayout ? 'b' : 'c',
        RecomputeOption.Routing => skinIsLayout ? 'c' : 'd',
        _ => skinIsLayout ? 'd' : 'e'
    };

    Utils.FindElement (() => Utils.MainWin.FindFirstChild ()
        .FindFirstChild (a => a.ByControlType (ControlType.MenuItem)));
    Utils.Type (key);
}

RecomputeOption Enum

internal enum RecomputeOption {
    RetoolAllElements = 0,              // CutCAM: 'a', Layout: 'd'
    ToolOnlyUntooledElements = 1,       // CutCAM: 'b', Layout: 'a'
    Sequence = 2,                       // CutCAM: 'c', Layout: 'b'
    Routing = 3,                        // CutCAM: 'd', Layout: 'c'
    Cancel = 4                          // CutCAM: 'e', Layout: 'd'
}

Validation & Assertions

Layout Data Validation

// Check part placement in layout
CheckPartsInLayout (folder: "C122169", filename: "test_MovePartByDrag");
CheckPartsInLayout ("C122170", "test_MovePartBySelect");
CheckPartsInLayout ("C122172", "test_CreatePartsArray");

// Internal implementation
internal static void CheckPartsInLayout (string folder, string filename) {
    List<string> commands = [
        "StringBuilder layData = new ();",
        "Flux.Layout.Current.Dump (layData)",
        "var result = layData.ToString ();"
    ];
    string output = Utils.RunScriptWithOutput (commands);
    Assert.AreTextEqual ($"{Utils.tData}Test_{folder}/{filename}.txt", output);
}

Selected Parts Validation

// Check selected part outlines
CheckSelectedParts ("C123187", "test_Similar Parts in Row");
CheckSelectedParts ("C123186", "test_grouped");
CheckSelectedParts ("C123186", "test_ungrouped");

// Internal implementation
internal static void CheckSelectedParts (string folder, string filename) {
    List<string> commands = [
        "StringBuilder selectedParts = new ();",
        "foreach (var part in Flux.Layout.Current.Children) { " +
        "  if (part.IsSelected) { " +
        "     foreach (var v in part.PartOutlines) selectedParts.Append (v.ToString () + '\\n');" +
        "  }" +
        "}",
        "var result = selectedParts.ToString ();"
    ];
    Assert.AreTextEqual ($"{Utils.tData}Test_{folder}/{filename}.txt", Utils.RunScriptWithOutput (commands));
}

Visual Validation (Screenshots)

// Render and compare screen
CheckLuxScreen ("C123184", "test_OverlappingParts");
CheckLuxScreen ("C200391", "supportPins");

// Internal implementation
internal static void CheckLuxScreen (string folder, string filename = "test") {
    string path = Utils.tempPath + "test.png";
    Utils.RenderSceneToFile (path);
    Assert.AreBitmapsEqual ($"{Utils.tData}Test_{folder}/{filename}.png", path, 95);
}

Script-Based Assertions

// Script with output validation
List<string> commands = [
    "int count = 0;",
    "foreach (var v in Flux.Part.Current.CutTech.AllSteps) { if (v.IsSelected) count++; }",
    "var result = count.ToString();"
];
Assert.AreEqual (Utils.RunScriptWithOutput (commands), "55");

// Twinline validation
List<string> commands = [
    "StringBuilder sb = new ();",
    "bool twinline = true;",
    "foreach (var v in Flux.Layout.Current.Children) { if (v.Tech != Flux.CLGroup) twinline = false; }",
    "var result = (twinline = true).ToString();"
];
Assert.AreEqual (Utils.RunScriptWithOutput (commands), "True");

Query-Based Assertions

// Check overlapping parts
bool hasOverlap = DoAnyPartOverlaps ();
Assert.False (hasOverlap);

// Check parts within sheet margin
bool withinMargin = AreAllPartsNestedWithinSheet (includeTooling: true);
Assert.True (withinMargin);

Script Execution

Simple Script Execution

// Run script without output
Utils.RunScript ("Flux.PartEditor.Current.Part.Info.Thickness = 4;");

// Set default machine
Utils.RunScript ("Flux.CutMachine.Default = Flux.CutMachine.Get (2230001);");

// Switch view
Utils.RunScript ("Flux.PartEditor.Current.Skin = Layout");
Utils.RunScript ("Flux.PartEditor.Current.Skin = CutCAM");

Script with Output

// Single line script
var result = Utils.RunScriptWithOutput ("var result = Flux.Part.Current.Name;");

// Get current skin
bool skinIsLayout = Utils.RunScriptWithOutput ("var result = Flux.PartEditor.Current.Skin.ToString()")
    = "Layout";

// Multi-line script
var result = Utils.RunScriptWithOutput (new List<string> {
    "int count = 0;",
    "foreach (var v in Flux.Part.Current.CutTech.AllSteps) { if (v.IsSelected) count++; }",
    "var result = count.ToString();"
});

Complex Multi-Line Scripts

// Layout data dump
List<string> commands = [
    "StringBuilder layData = new ();",
    "Flux.Layout.Current.Dump (layData)",
    "var result = layData.ToString ();"
];
string output = Utils.RunScriptWithOutput (commands);

// Selected parts collection
List<string> commands = [
    "StringBuilder selectedParts = new ();",
    "foreach (var part in Flux.Layout.Current.Children) { " +
    "  if (part.IsSelected) { " +
    "     foreach (var v in part.PartOutlines) selectedParts.Append (v.ToString () + '\\n');" +
    "  }" +
    "}",
    "var result = selectedParts.ToString ();"
];

// Twinline check
List<string> commands = [
    "StringBuilder sb = new ();",
    "bool twinline = true;",
    "foreach (var v in Flux.Layout.Current.Children) { if (v.Tech != Flux.CLGroup) twinline = false; }",
    "var result = (twinline = true).ToString();"
];

// Sheet margin check
List<string> commands = [
    "var lay = Flux.Layout.Current;",
    "var sm = lay.SheetMargin;",
    "var size = lay.SheetSize;",
    "var bound = new Flux.Bound2 (sm.Left - 0.1, sm.Bottom - 0.1, size.X - sm.Right + 0.1, size.Y - sm.Top + 0.1);",
    "var result = lay.Children.All (a => bound.Contains (a.GetBoundSansTooling ())).ToString();"
];

Common Nesting Workflows

Basic Part Movement Workflow

[Test (428, "Moving the part by dragging")]
public void Test_C122169 () {
    // 1. Open file and create quick nest
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest (true);

    // 2. Get target coordinates
    var p = Utils.MeasurePtsToPixel ([new (50, 90), new (150, 90)]);

    // 3. Move part
    Utils.MouseClick (p[0]);
    Utils.DragAndDrop (Mouse.Position, p[1]);
    Utils.Type (ESC);

    // 4. Validate
    CheckPartsInLayout (folder: "C122169", filename: "test_MovePartByDrag");
}

Part Selection Workflow

[Test (437, "Parts Selection")]
public void Test_C123187 () {
    string[] options = ["Same Parts", "Similar Parts in Row", "Similar Parts in Column"];

    for (int i = 0; i < 3; i++) {
        string option = options[i];

        // 1. Setup
        Utils.OpenFile (Utils.tData + fxFile);
        DoNewQuickNest (false);

        // 2. Select part
        Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));

        // 3. Apply selection mode
        SelectPartsBy (option);

        // 4. Validate
        CheckSelectedParts ("C123187", $"test_{option}");
    }
}

Grouping Workflow

[Test (1513, "Group parts together")]
public void Test_C123186 () {
    // Setup
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest ();

    // GROUPING PHASE
    // 1. Select initial part
    Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));

    // 2. Select similar and group
    SelectPartsBy ("Similar").FindFirstDescendant (a => a.ByName ("Group")).Click ();
    Utils.Type (ESC);

    // 3. Verify group selection
    Utils.MouseClick (Utils.MeasurePtToPixel (new (150, 90)));
    CheckSelectedParts ("C123186", "test_grouped");

    // UNGROUPING PHASE
    // 4. Select part and ungroup
    Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));
    Utils.WaitForGlob ().FindFirstDescendant (a => a.ByName ("Ungroup")).Click ();

    // 5. Verify ungrouped
    Utils.MouseClick (Utils.MeasurePtToPixel (new (150, 90)));
    CheckSelectedParts ("C123186", "test_ungrouped");
}

Quick-Nest with Settings Workflow

[Test (1514, "Nest start corner option")]
public void Test_C123192 () {
    int index = 0;
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest (true);

    foreach (var type in new string[] { "Bottom left", "Bottom right", "Top left", "Top right" }) {
        // 1. Open workflow
        Utils.MainWin.FindFirstDescendant (e => e.ByName ("workflow")).Click ();

        // 2. Access settings
        var qnBtn = Utils.FindElement (() => Utils.MainWin.FindFirstChild ("WorkflowPanel"))
            .FindAllChildren ().First (a => a.Name.StartsWith ("Quick-Nest"))
            .GetClickablePoint ();
        Utils.MouseClick (qnBtn);

        // 3. Select corner option
        var qnSettings = Utils.MainWin.FindFirstChild ("SheafEditor");
        var combo = qnSettings.FindFirstChild (a => a.ByControlType (ControlType.Pane))
            .FindAllChildren (a => a.ByControlType (ControlType.ComboBox))[1]
            .AsComboBox ();
        combo.Expand ();
        combo.Items[index++].Click ();

        // 4. Create new nest
        Utils.MouseClick (qnBtn);
        DoNewQuickNest (true);

        // 5. Validate
        CheckPartsInLayout (folder: "C123192", filename: $"test_{type}");
    }
}

Renesting Workflow

[Test (1517, "Nesting options")]
public void Test_C145736 () {
    string[] nestConds = ["CreateRemSheet", "UseFullSheet", "SpreadAlongX", "SpreadAlongY", "SpreadAlongXandY"];

    // Setup
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest (singlePart: true);

    // Create some parts
    var p = Utils.MeasurePtsToPixel ([new (50, 90), new (87, 167), new (1500, 1500)]);
    Utils.MouseClick (p[0]);
    Utils.MoveGlob ();
    Utils.DragAndDrop (p[1], p[2]);
    Thread.Sleep (1000);
    Utils.Type (ESC);

    // Test each renest option
    for (int i = 0; i < 5; i++) {
        Renest ((RenestOption)i);
        CheckPartsInLayout ("C145736", $"test_{nestConds[i]}");
        Thread.Sleep (2000);
    }
}

Twinline Nesting Workflow

[Test (1518, "Manual Twinline Nesting")]
public void Test_C150617 () {
    // Setup
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest (singlePart: true);

    // Select and position
    Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));
    Utils.MoveGlob ();

    // Create twinline with Shift+drag
    using (var ob = Keyboard.Pressing ((VirtualKeyShort)SHIFT))
        Utils.DragAndDrop (
            Utils.MeasurePtToPixel (new (87, 167)),
            Utils.MeasurePtToPixel (new (3000, 1500))
        );

    Thread.Sleep (500);
    Utils.Type (ESC);

    // Validate twinline
    List<string> commands = [
        "StringBuilder sb = new ();",
        "bool twinline = true;",
        "foreach (var v in Flux.Layout.Current.Children) { if (v.Tech != Flux.CLGroup) twinline = false; }",
        "var result = (twinline = true).ToString();"
    ];
    Assert.AreEqual (Utils.RunScriptWithOutput (commands), "True");
}

Array Creation Workflow

[Test (1511, "Creating array of parts in layout")]
public void Test_C122172 () {
    Utils.OpenFile (Utils.tData + fxFile);
    DoNewQuickNest (true);

    var p = Utils.MeasurePtsToPixel ([
        new (50, 90),        // Click point
        new (87, 167),       // Column start
        new (190, 1500),     // Column end
        new (90, 1360),      // Row start
        new (3000, 1500)     // Row end
    ]);

    // Column array
    Utils.MouseClick (p[0]);
    Utils.MoveGlob ();
    Utils.DragAndDrop (p[1], p[2]);
    Utils.Type (ESC);

    // Row array
    Utils.Type ('a', CONTROL);      // Select all
    Utils.MoveGlob ();
    Utils.DragAndDrop (p[3], p[4]);
    Utils.Type (ESC);

    // Validate
    CheckPartsInLayout ("C122172", "test_CreatePartsArray");
}

Helper Methods Reference

UI Navigation Helpers

// Find main window
Utils.MainWin

// Get clickable point
element.GetClickablePoint ()

// Find element with retry
Utils.FindElement (() => Utils.MainWin.FindFirstChild ("CmdBar"))

// Retry settings
var r = Utils.RetrySettings ();

// Get desktop
var desktop = new UIA3Automation ().GetDesktop ()

Layout & Part Queries

// Check for overlaps
DoAnyPartOverlaps ()
// Returns: bool.Parse (Utils.RunScriptWithOutput (...))

// Check margin fit
AreAllPartsNestedWithinSheet (includeTooling: false)
// Returns: bool based on Flux script

// Count selected
int selectedCount = ...  // Via script iteration

// Get part count
Flux.Layout.Current.Children.Count  // Via script

Timing & Sync

Thread.Sleep (500);     // 500ms delay
Thread.Sleep (1000);    // 1 second
Thread.Sleep (2000);    // 2 seconds
Utils.WaitForGlob ();   // Wait for dialog
Utils.FindElement (...) // Wait with retry

File Operations

// Cleanup
foreach (var file in Directory.GetFiles (Utils.tempPath)) {
    if (file.Contains (".txt") || file.Contains (".png"))
        File.Delete (file);
}

// Write files (via script)
Utils.RenderSceneToFile (path);

Best Practices

✅ DO: - Use DoNewQuickNest() for consistent nest creation - Always call Utils.Type (ESC) to finalize operations - Use measurement point conversion for consistent coordinates - Validate with both layout data AND visual comparison - Clean up temporary files in [FixtureCleanUp] - Use meaningful variable names for part coordinates - Add comments for non-obvious UI operations - Use helper methods for repeated patterns

❌ DON’T: - Hardcode pixel coordinates (use measurement points) - Skip Utils.MoveGlob() when dragging near dialogs - Forget Thread.Sleep() for async operations - Mix view switches without proper navigation - Create multiple quick-nests without cleanup - Skip assertions in validation - Use generic names (p, g, r, etc. without context) - Forget to close settings/dialogs with ESC


Common Pitfalls & Solutions

Glob Interference

// Problem: Glob blocks drag operation
// Solution: Move glob before dragging
Utils.MoveGlob ();
Utils.DragAndDrop (start, end);

View State Confusion

// Problem: Don't know which view is active
// Solution: Check via script
bool skinIsLayout = Utils.RunScriptWithOutput ("var result = Flux.PartEditor.Current.Skin.ToString()") = "Layout";

Timing Issues

// Problem: Operation not complete
// Solution: Add appropriate delays
Utils.MouseClick (pt);
Thread.Sleep (500);
Utils.Type (ESC);

Selection Not Persisting

// Problem: Selection lost after operation
// Solution: Re-select before validation
Utils.MouseClick (Utils.MeasurePtToPixel (new (50, 90)));
SelectPartsBy ("Similar");
CheckSelectedParts (...);

Quick Reference Cheat Sheet

Operation Command

Create quick nest

DoNewQuickNest (bool singlePart = false)

Select parts

SelectPartsBy (string option)

Move part

Utils.DragAndDrop (start, end)

Rotate part

Keyboard.Pressing (CONTROL) + Mouse.Scroll (25)

Create duplicate

Keyboard.Pressing (CONTROL) + Utils.DragAndDrop (…​)

Create twinline

Keyboard.Pressing (SHIFT) + Utils.DragAndDrop (…​)

Group parts

SelectPartsBy ("Similar").FindFirstDescendant (a => a.ByName ("Group")).Click ()

Renest

Renest (RenestOption.option)

Recompute

Recompute (RecomputeOption.option)

Validate layout

CheckPartsInLayout (folder, filename)

Validate selection

CheckSelectedParts (folder, filename)

Visual validation

CheckLuxScreen (folder, filename)

Switch view

Utils.Type ('l') for CutCAM, Utils.Type ('n') for Nesting

This recipe book covers all major patterns and commands used in the Nesting.cs framework for creating automated layout and nesting tests in the Flux application.

Contents

  • Table of Contents
  • Test Structure & Attributes
  • Basic Nesting Test Template
  • Machine IDs
  • Fixture Setup & Teardown
  • Installation & Configuration
  • Resource Cleanup
  • File Operations
  • Opening Files
  • File References
  • Navigation & View Management
  • View Switching
  • Workflow Panel
  • Settings Panel
  • Quick-Nest Operations
  • Creating Quick-Nest
  • Quick-Nest with Modifiers
  • Part Selection
  • Selection Methods
  • Selection Helper
  • Glob Operations (Selection Dialog)
  • Part Manipulation
  • Part Movement
  • Creating Duplicates
  • Creating Part Arrays
  • Part Rotation
  • Grouping Parts
  • Creating Overlaps
  • Keyboard & Input Commands
  • Navigation Keys
  • Modifier Keys
  • Multi-Key Input
  • Mouse Operations
  • Basic Mouse Actions
  • Measurement & Conversion
  • Drag & Drop
  • Mouse Movement
  • Mouse Wheel
  • Renesting Operations
  • Renest Method
  • RenestOption Enum
  • Recompute Operations
  • Recompute Method
  • RecomputeOption Enum
  • Validation & Assertions
  • Layout Data Validation
  • Selected Parts Validation
  • Visual Validation (Screenshots)
  • Script-Based Assertions
  • Query-Based Assertions
  • Script Execution
  • Simple Script Execution
  • Script with Output
  • Complex Multi-Line Scripts
  • Common Nesting Workflows
  • Basic Part Movement Workflow
  • Part Selection Workflow
  • Grouping Workflow
  • Quick-Nest with Settings Workflow
  • Renesting Workflow
  • Twinline Nesting Workflow
  • Array Creation Workflow
  • Helper Methods Reference
  • UI Navigation Helpers
  • Layout & Part Queries
  • Timing & Sync
  • File Operations
  • Best Practices
  • Common Pitfalls & Solutions
  • Glob Interference
  • View State Confusion
  • Timing Issues
  • Selection Not Persisting
  • Quick Reference Cheat Sheet
Nesting.cs Overview Job.cs Overview

      Copyright © 2025 TRUMPF Metamation. All rights reserved.

    Compiled by Bento