Page 1 of 1

Tutorial: Writing a plugin that draws a dovetail

Posted: Thu May 23, 2013 11:53 pm
by matthiaswm
OK, so this is how I write plugins. I write C++ code for thirtysome years, learned a few other languages and do some Reverse Engineering. That may or may not explain my approach here. I had no clue about Java Script until a few weeks ago. It's easy and powerful. You can learn it!

When extending functionality, I like to base my code on a working script and then change it the way I need, verifying my steps. So first we need to find an existing script that does 90% of what we want. Drawing a rectangle from point to point is good. After searching a bit, I found a directory: .../scripts/Draw/Line/LineRectangle/ . So lets duplicate the entire directory just where it is and name the new one "LineDove".

Go into the directory and rename the following files:

Code: Select all

  LineRectangle.svg, LineRectangleInit.js, LineRectangle.js
to 
  LineDove.svg, LineDoveInit.js, LineDove.js
LineDove.svg is the vector graphic for the icon in the toolbar. Leave it alone for now, or edit it, if you have time to spare.

LineDoveInit.js registers the script with the user interface. Open the file in a text editor (not MSWord! Just a plain and simple text editor) and replace all occurrences of LineRectangle with LineDove. Replace the word "&Rectangle" with "Dovetail", and change the setDefaulCommands. The code looks now like this:
function init(basePath) {
    var action = new RGuiAction(qsTranslate("LineDove", "&Rectangle"),
        RMainWindowQt.getMainWindow());
    action.setRequiresDocument(true);
    action.setScriptFile(basePath + "/LineDove.js");
    action.setIcon(basePath + "/LineDove.svg");
    action.setDefaultShortcut(new QKeySequence("r,v"));
    action.setStatusTip(qsTranslate("LineDove", "Draw a dovetail joint"));
    action.setDefaultCommands(["dovetail"]);
    action.setSortOrder(500);
    EAction.addGuiActionTo(action, Line, true, true, true, true);
}
LineDove.js contains the actual script. But let's first fix the names so that the original script may run. In the entire file, replace LineRectangle with LineDove. Now find the first line that contains new RVector. This line of code draws the first side of the rectangle. Replace the code snippet this.corner1.y with this.corner1.y/2 (divide the y coordinate of your first click by two).

Let's check if we did everything right!

Launch QCad and select Draw/Line. You should find *two* icons for drawing a rectangle. Try the first one and draw a rectangle. If you did everything right, you will now see a very quirky shape drawn. No dovetail yet, but at least we "wrote" our first plugin. To be continued... .

If anything went wrong and QCad is not launching anymore, or crashing or anything else, simply remove the directory we created earlier (".../scripts/Draw/Line/LineDove/"). Everything should be back to normal. Now try over ;-)

Re: Writing a plugin that draws a dovetail

Posted: Fri May 24, 2013 9:19 am
by Clive
Hi Matthias
This is exactly what I was talking about, your 'step by step' method is perfect. Explaining about the little things - no matter how basic they are is exactly what beginners to scripting in QCAD need.
Explaining what the different scripts do and what to change, then checking etc. etc.is brilliant and is very welcome. I will definitely try some of this out :wink:
matthiaswm wrote: No dovetail yet, but at least we "wrote" our first plugin. To be continued... .
Thank you so much for your time on this, looking forward to the next installment on this tutorial :D .

I'm hoping this will encourage others to add some 'scripting' tutorials for QCAD.

Re: Writing a plugin that draws a dovetail

Posted: Sat May 25, 2013 6:10 pm
by matthiaswm
Allright, now let's finish that birds rear. We need math!

The dimensions of a dovetail joint are not fixed, so I decided to make them symmetrical, allowing multiple fingers. If the tail is 12mm at the end, and 8mm at the base, I need 6mm to the left and right of the base which gives us a base with of 20mm. Let's then make the tail 8mm long to look proportional. Of course, the CAD program know nothing about Millimetrs or inches, so we need to use fractions to make everything based on the unit 1.

So here is the formula for drawing our dove tail, starting at the left, moving to the right, pointing to the top:
  • draw 6mm to the right (the base of the slot)
  • draw 2mm to the left and 8mm up (the first diagonal, shaping the tail)
  • draw 12mm to the right (the end of the tail)
  • draw 2mm to the left and 8mm down (the second diagonal)
  • draw 6mm to the right
OK, so if we add up the numbers and we put that in code, it reads:

Code: Select all

LineDove.prototype.getOperation = function(preview) {
    var corners = new Array(
        new RVector( 0, 0),
        new RVector( 6, 0),
        new RVector( 4, 8),
        new RVector(16, 8),
        new RVector(14, 0),
        new RVector(20, 0)
    );
    var op = new RAddObjectsOperation();
    for (var i=0; i<5; ++i) {
        var lineData = new RLineData(corners[i],corners[i+1]);
        var line = new RLineEntity(this.getDocument(), lineData);
        op.addObject(line);
    }
    return op;
};
Here is a trick for testing. If you are on Linux or OS X, start QCad from the command line with additional options. You will get diagnostic output, and you can modify and test the script without quitting and relaunching QCad. In OS X, the command line is:

Code: Select all

/Applications/QCAD.app/Contents/MacOS/QCAD -always-load-scripts
  or if you are adventurous:
/Applications/QCAD.app/Contents/MacOS/QCAD -always-load-scripts -enable-script-debugger
The code above is nice, but it only puts one very specific Dovetail at 0, 0. That should be more universal! To generate the Dovetail where we clicked the first time, we add the line line.move(this.corner1);.

Wait a minute! Ho did I find out about this magic function named move()? Ah, it's all in the manual. So line is of type RLineEntity. But if we go to the documentation of RLineEntity https://www.ribbonsoft.com/doc/qcad/3.0 ... mbers.html, there is no function named move(). However, RLineEntity is derived from REntity, meaning it can do anything that REntity can do plus more. Click on List of all members, and there it is: move https://www.ribbonsoft.com/doc/qcad/3.0 ... 1b52e8a745.

If we can move our list of vectors, we surely can rotate and scale it as well. So let's find out how long the dowetail should be, and at what angle we need to draw it:

Code: Select all

    var len = this.corner1.getDistanceTo(this.corner2);
    var ang = this.corner1.getAngleTo(this.corner2);
and we apply that to the vector list (remember that we need to scale by 1/20 because our initial calculations assumed a 20mm wide joint):

Code: Select all

LineDove.prototype.getOperation = function(preview) {
    var len = this.corner1.getDistanceTo(this.corner2);
    var ang = this.corner1.getAngleTo(this.corner2);
    var corners = new Array(
        new RVector( 0, 0),
        new RVector( 6, 0),
        new RVector( 4, 8),
        new RVector(16, 8),
        new RVector(14, 0),
        new RVector(20, 0)
    );
    var op = new RAddObjectsOperation();
    for (var i=0; i<5; ++i) {
        var lineData = new RLineData(corners[i],corners[i+1]);
        var line = new RLineEntity(this.getDocument(), lineData);
        line.scale(len/20);
        line.move(this.corner1);
        line.rotate(ang, this.corner1);
        op.addObject(line);
    }
    return op;
};
Tadaaa.... . ;-)

Re: Writing a plugin that draws a dovetail

Posted: Sun May 26, 2013 9:59 am
by Clive
Nice, thank you so much :D

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Fri Jul 12, 2013 8:36 pm
by Husky
Has somebody finished this Dove Tail Plug in? Would it be possible for a "non programmer" like me to download a working script for QCAD? :oops:

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Fri Jul 12, 2013 9:34 pm
by matthiaswm
Oh, sure. Here's the archive that you will need to unpack:

adding: scripts/Draw/Line/LineDove/
adding: scripts/Draw/Line/LineDove/LineDove.js
adding: scripts/Draw/Line/LineDove/LineDove.svg
adding: scripts/Draw/Line/LineDove/LineDoveInit.js

[Edit from andrew: please note that this script might be outdated. The latest version is available in all newer QCAD installations under Misc > Draw]

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Sat Jul 13, 2013 1:48 am
by Husky
Very nice! Thank you! :D :D :D

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Sun Jul 14, 2013 10:28 am
by caigner
Indeed a very useful script. Thanks alot!

Because I use a router bit with 14° angle to cut the dovetail I modified the numbers slightly to achieve this angle:

Code: Select all

    var corners = new Array(
        new RVector( 0, 0),
        new RVector( 6, 0),
        new RVector( 4.0053759772545544670076804975611, 8),
        new RVector(15.994624022745445532992319502439, 8),
        new RVector(14, 0),
        new RVector(20, 0)
    );

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Sun Jul 14, 2013 12:16 pm
by matthiaswm
Sure, great! It's nice to see the script being used in real life, even though it was originally just a tutorial for writing scripts ;-)

One elegant way would be a parameter in the tool bar that takes the angle an diameter of the router bit and applies that to the drawing. Are you readers interested in that? When time permits, I can add that to the tutorial.

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Sun Jul 14, 2013 1:11 pm
by Clive
matthiaswm wrote:One elegant way would be a parameter in the tool bar that takes the angle an diameter of the router bit and applies that to the drawing. Are you readers interested in that? When time permits, I can add that to the tutorial.
Yes please, that would be great :wink: but of course in your own time.

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Sun Jul 14, 2013 6:28 pm
by Husky
clive wrote:
matthiaswm wrote:One elegant way would be a parameter in the tool bar that takes the angle an diameter of the router bit and applies that to the drawing. Are you readers interested in that? When time permits, I can add that to the tutorial.
Yes please, that would be great :wink: but of course in your own time.
Yes please, for me (us) too. :D
That's what I'm really looking for to be able to work with different settings for all kinds of dove tails .... without leaving the QCAD Program surface :wink:

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Thu Aug 15, 2013 8:22 am
by Husky
matthiaswm wrote:Oh, sure. Here's the archive that you will need to unpack:

adding: scripts/Draw/Line/LineDove/
adding: scripts/Draw/Line/LineDove/LineDove.js
adding: scripts/Draw/Line/LineDove/LineDove.svg
adding: scripts/Draw/Line/LineDove/LineDoveInit.js
Do you mind if I put your script (.zip) also in our new "QCAD 3 ' script Add-On & Plug-in challenge" Forum?
Just to make sure everybody will find it ..... :wink: :wink: :wink:

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Wed Mar 04, 2015 8:26 am
by caigner
matthiaswm wrote:One elegant way would be a parameter in the tool bar that takes the angle an diameter of the router bit and applies that to the drawing. Are you readers interested in that? When time permits, I can add that to the tutorial.
Hi Matthias!

A parameter for the angle in the toolbar would be a really great addition to this wonderful script. Could you? Would you? Please! :-)
I am using hand tools to cut dovetails and old woodworkers suggest different angles for different wood hardness.

Regards,
Christian

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Tue Feb 14, 2017 1:27 pm
by caigner
I have given it a try to produce a script that will take number of dovetails, height of dovetails, dovetail/pin ratio and gradient.

Try as I might, I couldn't make it work, but I have posted my attempt here:

viewtopic.php?f=107&t=4737

Re: Tutorial: Writing a plugin that draws a dovetail

Posted: Thu Feb 16, 2017 1:03 pm
by caigner
I finally did it!

For the new Dovetail Script please go to:

viewtopic.php?f=107&t=4737#p17410