Toolpath by Layer

Hi,

Other than selecting a layer and using “Select Layer Entities”, is there a way to assign a tool path to a layer?

I’m using QCAD-CAM for laser cutting, so I want to make use of layers to separate each type of cut - ie cutting, engraving etc. Traditionally, you’d have 8-16 “pens” which are configs based on power and speed of cut, which gives you the full gamut of light scoring through to nuking your way through the material.

Having to manually select objects or select via the layer to re-add etc can be quite time consuming, and sometimes a missing entity goes by. It would also dramatically reduce the workflow and amount of clicking, as I’ve already designed something using multiple layers to isolate the different things going on, but then having to go back in and re-group them for CAM is twice the effort. Plus sometimes you can pull the wrong object into the wrong CAM, and as it’s colour coded by layer, makes it hard to pick it up!

Thanks
Jon

I’ll add that because it’s a laser, there’s virtually no tool width, so very difficult to see the CAM lines to check if something is in the right tool path set!

I’m not sure what exactly you mean.

What you can do in a post processor is to add additional information to the layer. You can look at the Beamo post processor for the FLUX beamo laser cutter which adds some information to layers (see layer dialog when Beamo post processor is active).

This layer information can then be used in the post processor.

Yeah, the Beamo one is what I’m after.

I’ve had a play with it, and a brief look through as well.

As most of that appears to be implemented in writeFile - how much of the block setup needs to be done in the init? I need to have some config switches that change relative or absolute commands used, and it obviously won’t work if they’re declared in the init block. Is it okay to set/override them in writeFile?

Example:
Absolute

this.arcCWMove = "AA[IA],[JA],[SWEEP]" + this.separator;

Relative

this.arcCWMove = "AA[I],[J],[SWEEP]" + this.separator;

etc - there’s more than often just a variable name that has to change as well. I’m assuming it’s okay practice to use writeFile to override based on the config settings? Obviously I have no idea how the CAM libraries work, so it’s guess work at what point those variable need to be set. I initially assumed they all had to be set in the init, but looking around others, I’ve seen the odd variable being overwritten in writeFile.

Also, stupid question, but any variables from the QT interface; are they available as variables within normal functions, or do I have to use registerVariable on them? I have a few config options, but unsure the correct way to declare and use them within the script code. I need access to them in writeFile, after setting them up in initConfigDialog. Based on the nearest existing code I can find, it’s just an objectName used. In that other sample script, it used registerVariable (but I don’t know why, as it’s not being merged into the block strings?), when surely I can just get it’s value to evaluate in an if statement using .getGlobalOption.

Looking at GCode2AxisPT.js

writeFile appears to be used to switch the value of a number of blocks, so I’ll follow suit I think.

Now, it’s also just confused me more regarding variables in the configDialog. Initially I thought you just do the UI mods, and the variable would be available via getGlobalOption. Also assumed there’s some kind of magic going on, as the options I’ve set, appear to save within the CAD file and persist on close/open.

But I see this block, which appears to define it as a CAD document variable (for persistence?).

GCode2AxisPT.prototype.postInit = function(dialog) {
    var ret = CamExporterV2.prototype.postInit.call(this, dialog);

    if (this.alwaysWriteG1===true) {
        this.cadDocument.setVariable(Cam.getCurrentVariablePrefix() + "AlwaysWriteG1", true);
    }
...
    return ret;
};

What/when is postInit called? Are UI element settings not stored in the CAD file? Is this a hang-over from an older version?

Also, the init declares and sets the default

this.alwaysWriteG1 = false;

which appears redundant and pointless, as writeFile uses this if evaluation

(this.getGlobalOption("AlwaysWriteG1", false)===true) {

and doesn’t reference the declared variable. Does getGlobalOption do anything auto-magic like loading a named variable etc, or does it just return the value of the variable (I assume the second option is a default/null value) as a basic lookup function?

Thanks

Yes, you can set up variables that don’t change for one single export in your writeFile implementation before exporting.

Any variable in your JavaScript that you want to use in your output has to be registered using registerVariable:

For example:

this.registerVariable("dateTime", "DATETIME", true, "", 0);

This registers variable this.dateTime of your JavaScript to be available in the post processor output as “[DATETIME]”

Correct. Those configuration options are saved to the document as persistent document variables with the objectName of the widget being the key and its status or text etc. being the value.

E.g. you can add a line edit with objectName “MyConfigurationOption” and retrieve its value in your post processor with:

this.getGlobalOption("MyConfigurationOption", "My Default Value");

Where “MyDefault Value” should match the initial state / contents of the widget in the config dialog. This is redundant but needed since defaults need to exist even if the config dialog is never shown.

Whether you want / need to expose the configuration option as a variable to the post processor with registerVariable is up to you.

Example for a widget with objectName “MyIntValue” for an integer value with default value 7:

this.myIntValue = this.getGlobalOption("MyIntValue", 7);
this.registerVariable("myIntValue", "MYINTVALUE", true, "", 0);

Note that GCode2AxisPT is user contributed. For configuration options, Dxf.js is a good example.

Thank you Andrew,

Making more sense now.

I’ll have a look at DXF.js as well then.

If I’m showing a Qt menu during the writeFile process, how do I access the text stream? I’m assuming instead of returning to the inherited writeFile I call it instead, and then can show the menu. I’d like a preview text block in the menu, so need to access the text stream somehow.

Thanks

You can call the original writeFile and when it returns do something with the file that was written (e.g. read it and display it):

MyPost.prototype.writeFile = function(fileName) {
    CamExporterV2.prototype.writeFile.call(this, fileName);

    // check if file exists, read file and display
    // ...
};

Ahh, okay… wasn’t sure if easier to get text stream, but literally just read from the file and display…

Because of the way laser power is defined, following the example of Beamo, it’s easier to set the power for objects on the layer. But Beamo works a bit differently as they use an SVG renderer (and appear to do most of it themselves in their own way?)

3 issues…

  1. How can I change the selection of lines/arcs to be supplied to the CAM tool path, from those highlighted/selected to the contents of a layer? The cleanest solution would be to either assign a layer to a CAM tool path or in layer attributes assign a CAM tool path - with the result that the instead of manually selecting paths, that all paths on a layer are selected and used for that CAM tool path. I’m guessing I need to somehow override the function that supplies a list of paths to the CAM tool path, and give it a list derived from a layer instead?

  2. I don’t know how CamExporter works so unsure how during iteration through the CAM generation that I can access each line/arc’s layer and in turn set that attribute back into the currently processed CAM line (I just need to prefix “SPx” for the tool). I assume just assign a new variable (add it into the string template in the init… but what would I override to add the code to get the layer options to set the variable? Is there a single path function which calls descendants (like arc, line etc), or do I have to do this for every path type?

  3. I need to get a list of tools used and the feed/speed into the header - I can only think of iterating through layers/CAM tools and reading them that way. Is there anything in CamExporter I can use instead to get a list of tools used (and therefore add them to the header in writeFile), or does it not know what tools are used (ie it just calls the tool change block for each CAM toolpath)?

Thanks

Working blind with the Cam scripts, I’m assuming at some point I can replace the list of EntityID’s being given to whatever Cam function gets called first with them.

Without Entities selected, (but always an active layer), then the buttons dim for Add Profile Toolpath.

Can I just find the active layer, or does an object from that layer need to be selected in order to get a LayerID?

Obviously need to filter and ensure “CAM” and descendent layers are excluded, but otherwise validation appears to be within the generation functions, so I just need a way of call the Add Profile Toolpath (if you re-generate a tool path without any entities/deleted them, it shows a warning in the output).

My alternative thought, is to add a “layer” drop down in the CAM Profile Toolpath dialog and then use that to select the entities, but again the buttons dim… Beauty of this approach, is that a layer is always selected, so we have something to pass forward, but the generation validation stops any later errors by catching empty list of entites.

Just really blind here, so have no idea where to start!

Which parts of QCAD/CAM do you actually need?

Are you planning to create tools with diameters and toolpaths with the various toolpath settings such as offset, lead in / lead out, etc?

If you don’t need any of that, you might be better off just overwriting writeFile, iterate through all entities in your drawing and write them to HP/GL.

In any case, I would strongly recommend to start simple and add features one by one.


Can I just find the active layer, or does an object from that layer need to be selected in order to get a LayerID?

What is your context?

You could for example override writeLinearMove and write different text blocks, depending on the layer or even simply stream to the output without using text blocks:

MyPost.prototype.writeLinearMove = function() {
    var layerName = this.currentEntity.getLayerName();

    // write any kind of HP/GL code depending on layer name
    // use this.xPosition / this.yPosition / this.zPosition for the target position:
    this.write("...");
};

Similarly, you could override writeArcCWMove, writeArcCCWMove, writeLinearMoveZ (pen up / down or laser on / off).

There are many ways to approach this. The only thing that is fixed is writeFile(fileName) that really needs to be implemented somehow otherwise, nothing is exported.

I hope that helps.

Thanks Andrew,

I don’t want to replace that much functionality - this is mostly workflow optimisations. I want to be able have a tool path for all objects on a layer, rather than having to manually select them.

The best process I think is to be able to select a Layer when inside the CAM tool path window. Problem is that the buttons are hidden when there’s no selection (I know that there’s validation in the processing functions, so overriding this should be fine).

  1. I don’t know how to reference the CAM widget to change the behaviour of the Toolpath and Drill routines

  2. I have already got modifications for the CAM tool path window, so I can add drop down etc accordingly.

  3. I don’t know how to get a list of all Layers excluding CAM (not sure if there’s a programatic way of testing for name other than just testing for matching labels? likewise, how do I test for child layers of a named layer too?)

  4. I don’t know how to get a list of EntityID for a given Layer.

  5. I don’t know the function to overload to replace selected EntityID with my list of EntityIDs. I presume it’s a function called by the export/regenerate paths buttons.

Thanks

Just one of the search matches with ‘dialog’.
This doesn’t change the behavior of but its how to suppress or add widgets:

In the same linked topic:
We once discovered that for B all settings names must start with “Cam”.
That way they are stored in toolpaths.

Classes of interest:

Indeed, you need to verify/filter naming.

You are probably interested in entity id’s of a filtered layer per id and on the Model_Space block.

Having the Entity id you can query it from the document;

or

The more I read about your endeavor I think that in a way you are interested in adding a variant of the ‘Add Profile Toolpath’ resource that selects entities on a layer and calls for the CamExporter to handle a toolpath without a selection as required by KP.

Regards,
CVH

Thanks CVH,

I’ll go through and read up.

I’ve figured out a few bits, but not working yet… I’ll post shortly.

Yes, absolutely. Whilst I can of course use “Select Layer Entities” for a Layer, if I make any changes to the layer, it’s many clicks and potentially many mistakes to update the tool path. Being able to just regenerate, and it freshly pulls every entity from a layer is great.

I could potentially have 5-10 different layers with different speeds/power, and if I’ve already isolated each entity to a colour coded layer, to then have to reselect all entities, and run the risk of mixing entities across layers seems added risk.

It means production can get very smart, and I can have dissimilar materials in nested layers cut on the same bed, with the machine using different tool presets for diff layers.

It would be so much easier to assign a layer to a tool path. It also means that instead of having laser presets in code (like Beamo) and configuring by Layer, that I can just have those as tools stored in a template file. As I use diff materials, I want to tweak the presets anyway, and doing it in code doesn’t feel right!

So my preferred method now is to enable the “Add Profile Toolpath” button/menu options at all times. Add a “Layers” drop down on the CAM Profile Toolpath dialog, and use that as the source of entities vs it being the currently selected entities.

It goes further than that …
Regenerating toolpaths, does that require to regenerate the existent toolpaths or does that restart the process with filtering layer entities?

Further you really need to differentiate the two processes:
A) Creating toolpaths from drawing entities … Resulting in CamEntities in toolpath blocks.
B) Creating an output from CamEntities what is in your case some specific HPGL dialect.
While Cam Export (KX) does A and then B automatically with ‘Always regenerate all toolpaths before export’.
Incorporating A as a sub-process of B is as putting the cart before the horse and probably not really feasible without major tricks.

While manually selecting entities may be prone to error.
Auto selecting everything can be a mess too depending on what is in the drawing besides geometry to cut.

Blind trust in that it will always be the intended selections, and only those, may lead to dangerous situations.
Then you would blame QCAD/CAM when an accident happens.

Your automated methods must be rigorously tested, the coding itself must be so robust that it will never ever fail.

Regards,
CVH

From playing in the Script Shell, it would appear that regenerate is the operation called anyway, and if no entities are supplied it gets a stored list of entities. I don’t see much overhead difference there. The EntityId’s on the Layer are already in memory, so I can’t see it slowing things down.


True to a certain extent, but I am having to use “select all entities on layer”, so it’s all going to be added, irrespective of whether I do it automatically or by hand. The preview and paths are good for confirming nothing odd will happen. Or if I just use a lasso to select blocks of entities, I’m going to have issues either way if there’s stacked lines etc doing it manually.

At some point, a list of selected EntityId’s is passed to the “Add Toolpath” function. That’s where I’m suggesting the entry point is. Allow us to specify a layer and use all Entities on it instead of a manual selection of Entities.

Now, the debate is whether:

a) additions to the layer are added automatically on regenerate

b) additions/removals to the layer are manually updates (for example using a similar operation to “Update Toolpath from Selection”, such as “Update Toolpath from Layer”, or it gets renamed to “Update Toolpath” and just figures out what to update using.)

I can’t see any point to b).

I don’t see a scenario where you would change entities, and then want to regenerate a tool path, using the previously cached entities anyway? Surely when you make a change and regenerate, it should regenerate the new entities, and not require an update. And that is the current behaviour of regenerate. So, surely if you add more elements to a layer or remove elements, you want that immediately reflected as well? You don’t want to click regenerate and see just the original entities that you’ve changed are updated!?

You draw a square, and create a tool path. I then want to add an inset to one side of the square.

The desired outcome, is that you change the entities, click regenerate and now see CAM for the newly tweaked design.

The outcome by not automatically updating a layer, is that you now see CAM for 3 sides of the square. I have just tried this out, and have not deleted the 4th side. I split the entity using “Remove Segment”, so it has now removed and replaced the entity with two new entities, and neither are in the CAM Toolpath. It 100% makes sense that if a Layer is used as a source of entities, then that list is updated on every regenerate.

As an aside, if I’m doing CAM, I would never put something not to be cut on the same layer as something to be actively cut. I would put it into its own layer, and I group based upon what process is being run. Not only do you get the benefit of visually identifying the differences (colourising lines) but it even makes it easier to select what might an outside compensation, inside compensation and then different tools/depths/passes.

If you make a mistake, and an object is on the wrong layer, you’ll see very quickly when it regenerates the paths. However, with the manual selection process, which could be taking entities from anywhere on any layer, you can have weird things happen and have no idea why. I spent ages debugging some CAM today, to find that some entities has been selected in the wrong Toolpath. I isolated layers, flipped back and forth, but couldn’t figure out why. I deleted the Toolpaths, to find one had somehow picked up some other entities. If the Toolpaths used layers as sources, then I wouldn’t have had the wrong entities in the wrong Toolpaths whatsoever.

I agree with Mechatronic on selection by layer, and, I will add a caveat. Though it is not a best practice for plasma or laser cutting, selection by layer after nesting would speed things up quite a bit. The downside being your nest may take a considerable time longer to cut and there is a greater chance of part shifting due to thermal expansion. I suppose you could change the layer names a bit for unique parts, but won’t work for nesting the same part with multiple quantities. Many times you may want to cut only 1 or a few parts out of a nest. Would not be possible in the case you have Toolpaths per layer and have nested a multiple of the same part unless you have the ability to skip pierce points.

In any case, I would vote for ToolPath by Layer.