Variable from command line / user input
Moderator: andrew
Forum rules
Always indicate your operating system and QCAD version.
Attach drawing files and screenshots.
Post one question per topic.
Always indicate your operating system and QCAD version.
Attach drawing files and screenshots.
Post one question per topic.
Variable from command line / user input
QCAD version: 3.17.1
OS: Windows 10 at work and Devuan GNU/Linux at home
Hello, QCAD community, I am new here and would hugely appreciate some pointers on my first project.
I am working on a tool/script to automatically generate a 2D template for a brick arch (a trapezium consisting of smaller parallelograms cut from bricks with gaps between).
The image I have created as an icon for this tool should give a decent visualisation of what I mean (its half of what the output of this tool should look like):
The user needs to be able to specify archLength, archHeight (the total length and height of the drawing), skew (the angle of the ends of the arch), jointSize (the size of the gap between the bricks) and brickWidth (the width of the bricks being used) in order for the tool to calculate how many bricks will be used and draw the points for each parallelogram.
I have had trouble finding a comprehensive tutorial for this software so can somebody please show me how this user input can be achieved, or even better direct me to a guide/tutorial? Thanks in advance!
OS: Windows 10 at work and Devuan GNU/Linux at home
Hello, QCAD community, I am new here and would hugely appreciate some pointers on my first project.
I am working on a tool/script to automatically generate a 2D template for a brick arch (a trapezium consisting of smaller parallelograms cut from bricks with gaps between).
The image I have created as an icon for this tool should give a decent visualisation of what I mean (its half of what the output of this tool should look like):
The user needs to be able to specify archLength, archHeight (the total length and height of the drawing), skew (the angle of the ends of the arch), jointSize (the size of the gap between the bricks) and brickWidth (the width of the bricks being used) in order for the tool to calculate how many bricks will be used and draw the points for each parallelogram.
I have had trouble finding a comprehensive tutorial for this software so can somebody please show me how this user input can be achieved, or even better direct me to a guide/tutorial? Thanks in advance!
Re: Variable from command line / user input
Here is the code I have written so far. Its a bit of a mess and I expect a lot of things are probably in the wrong place. Trying to run it in QCAD produces no results and I don't know how to make QCAD print error messages.
Code: Select all
//! [include]
include("scripts/EAction.js");
//! [include]
//! [constructor]
/**
* \class brickArch
* \ingroup ecma_misc_draw
*/
function brickArch(guiAction) {
EAction.call(this, guiAction);
}
//! [constructor]
//! [inheritance]
brickArch.prototype = new EAction();
//! [inheritance]
//! [beginEvent]
brickArch.prototype.beginEvent = function() {
EAction.prototype.beginEvent.call(this);
qDebug("brickArch.prototype.beginEvent was called.");
var di = this.getDocumentInterface();
var document = this.getDocument();
var op = new RAddObjectsOperation();
// Collect dimensions from user: archLength, archHeight, jointSize, brickWidth
//var archLength = 1000, archHeight = 300, jointSize = 5, brickWidth = 100;
var trArchLength = qsTr("Arch length"), trArchHeight = qsTr("Arch height"), trJointSize = qsTr("Joint size"), trBrickWidth = qsTr("Brick width");
this.getDocumentInterface().setRelativeZero(new RVectorData(new RVector(round(-archLength / 2), 0)));
var brickCount = brickArch.prototype.countBricks(brickWidth, jointSize, archLength);
var bottomWidth = brickArch.prototype.findBottomWidth(archLength, brickCount, jointSize);
var topStart = brickArch.prototype.findTopStart(skew, archHeight);
var topWidth = brickArch.prototype.findTopWidth(topStart, archLength, brickCount, jointSize);
var brickLines = brickArch.prototype.createLines(brickArch.prototype.calculatePoints(numberOfBricks, bottomWidth, topStart, topWidth, jointSize));
// Draws the calculated lines onto the document
for (var i in brickLines) {
for (var x in brickLines[i]) {
op.addObject(new RLineEntity(document, new RLineData(brickLines[i][x])));
}
}
this.terminate();
};
//! [beginEvent]
//! [countBricks]
// Counts how many bricks are needed based on width of bricks, joint size and total arch length
brickArch.prototype.countBricks = function(brickWidth, jointSize, archLength) {
// Calculate number of bricks from width making sure it is odd
// Calculates size of 1 brick + 1 joint
var brickAndJoint = brickWidth + jointSize;
var brickCount = floor((archLength - jointSize) / brickAndJoint);
}
return brickCount;
};
//! [countBricks]
//! [findBottomWidth]
// Finds the width the bottom of each brick needs to be
brickArch.prototype.findBottomWidth = function(archLength, numberOfBricks, jointSize) {
justBricks = archLength - jointSize * (numberOfBricks - 1);
return round(justbricks / numberOfBricks);
};
//! [findBottomWidth]
//! [findTopStart]
// Finds the horizontal start point of the top left point of the arch
brickArch.prototype.findTopStart = function(skew, archHeight) {
// Finds the angle of the virtual triangle created between the vertical rule and the end of the arch
a = 180 - skew;
return round(-tan(a) * archHeight);
};
//! findTopStart
//! [findTopWidth]
// Finds the width the top of each brick needs to be
brickArch.prototype.findTopWidth = function(topStart, archLength, numberOfBricks, jointSize) {
fullTopLength = archLength - topStart * 2;
justBricks = fullTopLength - jointSize * (numberOfBricks - 1);
return round(justBricks / numberOfBricks);
};
//! [findTopWidth]
//! [calculatePoints]
// Returns a nested array of coordinates for each point in the arch
brickArch.prototype.calculatePoints = function(numberOfBricks, bottomWidth, topStart, topWidth, jointSize, archHeight) {
// Creates one array per brick to store the coordinates of their corners
var brickPoints = [];
for (var i = 0; i < numberOfBricks; i++) {
brickPoints[i] = [];
}
for (i = 0; i < numberOfBricks; i++) {
brickPoints[i][0] = new RVector(i * bottomWidth + i * jointSize, 0);
brickPoints[i][1] = new RVector(i * bottomWidth + i * jointSize + bottomWidth, 0);
brickPoints[i][2] = new RVector((i * topWidth + i * jointSize) + topStart, archHeight);
brickPoints[i][3] = new RVector((i * topWidth + i * jointSize + topWidth) + topStart, archHeight);
}
return brickPoints
};
//! [calculatePoints]
//! [createLines]
// Creates lines from coordinates array
brickArch.prototype.createLines = function(brickPoints) {
for (var x in bricks) {
brickLines[x] = [];
}
for (var i = 0; i < brickLines.length; i++) {
brickLines[i][0] = new RLine(brickPoints[i][0], brickPoints[i][1]);
brickLines[i][1] = new RLine(brickPoints[i][1], brickPoints[i][3]);
brickLines[i][2] = new RLine(brickPoints[i][3], brickPoints[i][2]);
brickLines[i][3] = new RLine(brickPoints[i][2], brickPoints[i][0]);
}
return brickLines;
};
//! [createLines]
//! [init]
brickArch.init = function(basePath) {
var action = new RGuiAction(qsTr("Brick Arch"), RMainWindowQt.getMainWindow());
action.setRequiresDocument(true);
action.setScriptFile(basePath + "brickArch.js");
action.setIcon(basePath + "/brickArch.svg");
action.setStatusTip(qsTr("Draw a brick arch"));
//action.setDefaultShortcut(new QKeySequence("p,3"));
action.setDefaultCommands(["point1"]);
action.setGroupSortOrder(73100);
action.setSortOrder(400);
action.setWidgetNames(["DrawExamplesMenu"]);
};
//! [init]
Re: Variable from command line / user input
You can run QCAD with the command line switch -enable-script-debugger to show an interactive debugger whenever a problem is found:cjm wrote:Trying to run it in QCAD produces no results and I don't know how to make QCAD print error messages.
Linux:
./qcad -enable-script-debugger
Windows:
qcad.exe -enable-script-debugger
This will yield:
Uncaught exception at /Users/andrew/data/RibbonSoft/projects/QCAD3/qcad/scripts/Misc/brickArc/brickArc.js:56: SyntaxError: Parse error
There's an error with a curly braket there.
Some general tips about programming:
- Start small (as a beginner, start really really small, think about the absolute minimum of code to start with):
Code: Select all
include("scripts/EAction.js");
function brickArch(guiAction) {
EAction.call(this, guiAction);
}
brickArch.prototype = new EAction();
brickArch.prototype.beginEvent = function() {
EAction.prototype.beginEvent.call(this);
qDebug("brickArch.prototype.beginEvent was called.");
this.terminate();
};
brickArch.init = function(basePath) {
var action = new RGuiAction(qsTr("Brick Arch"), RMainWindowQt.getMainWindow());
action.setRequiresDocument(true);
action.setScriptFile(basePath + "/brickArch.js");
action.setGroupSortOrder(73100);
action.setSortOrder(400);
action.setWidgetNames(["DrawExamplesMenu"]);
};
- After every change, test your changes.
BTW: Classes in QCAD usually start with a capital letter (i.e. BrickArch instead of brickArch). Make sure to also rename the file to BrickArch.js. Variables start with a small letter (e.g. var action;).
Re: Variable from command line / user input
Thank you for your advice, andrew! I have done as you suggested and completely rewritten my tool, testing it periodically for errors and making some substantial improvements from the original.
There are only 3 things missing now:
There are only 3 things missing now:
- Receiving the variables from the command line
Math formulas that work in the QCAD command line such asare not recognised in the context of a script (is there a Math script i need to import?)Code: Select all
floor() ceil() tan()
Creating line data to be written into the document (I've tried various configurations ofto no avail)Code: Select all
RLineEntity(RLineData(RLine()))
Re: Variable from command line / user input
If the user enters a value in the command line, your action receives a commandEvent:cjm wrote:Receiving the variables from the command line
Code: Select all
BrickArch.prototype.commandEvent = function(event) {
var cmd = event.getCommand();
if (cmd==="mycommand") {
// do something
event.accept();
}
};
In a script, you can use the standard ECMAScript / JavaScript functions available in the JavaScript Math Object:cjm wrote:Math formulas that work in the QCAD command line such asare not recognised in the context of a script (is there a Math script i need to import?)Code: Select all
floor() ceil() tan()
Math.floor(...);
Math.ceil(...);
Math.tan(...);
If you include the QCAD Simple API, you can do something like this:cjm wrote:Creating line data to be written into the document (I've tried various configurations ofto no avail)Code: Select all
RLineEntity(RLineData(RLine()))
Code: Select all
include("simple.js");
...
addLine(x1,y1, x2,y2);
addLine([x1,y1], [x2,y2]);
addLine(new RVector(x1,y1), new RVector(x2,y2));
Re: Variable from command line / user input
Sorry to bother you again with this, I had to take a break from this project for a while but I now have a few days free to dedicate to making this tool work and would appreciate some more help.
I remember finding a way to set the command prompt to a custom string created with qsTr but I cant find it now. That would be handy to prompt the user for the seperate
(The shorter ones are correct but the taller ones seem to be skewed to the left, the top row doesn't appear at all and there is a long error message in the debugger)
The Github repo is up to date, if you can help with either of these problems it would be much appreciated.
I need to collect regular number variables from these command events several times over, with a different variable entered each time. For example, the first time I would need to collect the archLength variable, then the archHeight variable, etc. I'm guessing something like:andrew wrote:If the user enters a value in the command line, your action receives a commandEvent:
Code: Select all
BrickArch.prototype.commandEvent = function(event) { var cmd = event.getCommand(); if (cmd==="mycommand") { // do something event.accept(); } };
Code: Select all
BrickArch.prototype.getVariables = function() {
for (i = 0; i < 5; i++) {
input = event.getCommand();
if (i == 0) {var archLength = input;};
if (i == 1) {var archHeight = input;};
if (i == 2) {var jointSize = input;};
if (i == 3) {var brickWidth = input;};
if (i == 4) {var skew = input;};
}
};
D'oh! This was how I had it originally, then I changed it before I knew about the script debugger, this seems to work as expected now, thank you!andrew wrote:In a script, you can use the standard ECMAScript / JavaScript functions available in the JavaScript Math Object:
Math.floor(...);
Math.ceil(...);
Math.tan(...);
This works as well to draw my lines but throws some errors when dealing with a large number of points and for some reason some points are in the wrong place despite using the same function to calculate them, as shown here:andrew wrote:If you include the QCAD Simple API, you can do something like this:All three calls have the same result.Code: Select all
include("simple.js"); ... addLine(x1,y1, x2,y2); addLine([x1,y1], [x2,y2]); addLine(new RVector(x1,y1), new RVector(x2,y2));
(The shorter ones are correct but the taller ones seem to be skewed to the left, the top row doesn't appear at all and there is a long error message in the debugger)
The Github repo is up to date, if you can help with either of these problems it would be much appreciated.
Re: Variable from command line / user input
You could use the a state to advance the state of collecting information. E.g. a variable this.dateEnteringState = 0 which advances whenever the user enters another value.cjm wrote:I need to collect regular number variables from these command events several times over, with a different variable entered each time.
You can also use the action's this.state if you really want to force the user to input all data in the correct order before proceeding.
Alternatively, you could use widgets in the options toolbar or a dialog.
cjm wrote:I remember finding a way to set the command prompt to a custom string created with qsTr but I cant find it now. That would be handy to prompt the user for the seperate
Code: Select all
this.setCommandPrompt("My Prompt:");
This looks like it would need some debugging (use qDebug() to output intermediate values).This works as well to draw my lines but throws some errors when dealing with a large number of points and for some reason some points are in the wrong place despite using the same function to calculate them, as shown here:
Re: Variable from command line / user input
Pitty that the pictures are revoked.
CVH
CVH