Generating an involute spiral - 99% of the way there...

Use this forum to ask questions about how to do things in QCAD.

Moderator: andrew

Forum rules

Always indicate your operating system and QCAD version.

Attach drawing files and screenshots.

Post one question per topic.

Post Reply
User avatar
DerekGove
Active Member
Posts: 41
Joined: Sat May 20, 2023 7:10 pm
Location: Cumbria

Generating an involute spiral - 99% of the way there...

Post by DerekGove » Fri May 26, 2023 1:00 pm

Afternoon,

I've modified a script CVH provided, with the intention of generating an involute spiral.

I have variables set for the centre of the evolute, the radius, the number of segments the evolute is divided into, etc... And the script generates the points along the generating line at the bottom of the evolute.

Code: Select all

var originX = 0;		// Centre of the evolute circle in x
var originY = 0;		// Centre of the evolute circle in y
var radius = 50;		// Radius of the evolute circle
var segments = 12;		// Number of segments the evolute circle is divided into 
var generators = 12;		// Number of generator lines created

var i, xPos, yPos;		// Iterator and X/Y positions
var nodes = [];			// Collector for polyline nodes
var GeneratorRotation		// The amount each generator line is rotated

// Populate array with nodes:
for (i=0;i<=generators;i++) {
    xPos = originX + (i * (2 * PI * radius) / segments);
    yPos = originY - radius;
    nodes.push(new RVector(xPos, yPos));
}

// Adding a dedicated layer:
addLayer("QCAD Involute", "Dark Blue", "CONTINUOUS", RLineweight.Weight025);
setCurrentLayer("QCAD Involute");

// Add a polyline with addPolyline or add a spline with addSpline:
addSpline(nodes);
The only bit I don't know how to do is to rotate each point around the center of the evolute. I see in the QCAD API there is a rotate function, which I'm guessing will be the preferred method, which is: rotate(entity, angle, cx,cy).

For my script, this will be

Code: Select all

rotate(entity, (360/segments), originX, originY)
But I have virtually zero experience with javascript, and I have no idea how how to turn the xPos and yPos of each point into an 'entity'. I don't even know what an entity is. I'm guessing it will involve setting a vector variable, something like: var pointRotated = ["xPos", "yPos"], but nothing I've tried works.

Clearly knowing about 'entities' is important! :D

Can anyone fill in this particular blank for me?

Thanks in advance!

Derek
QCAD Version 3.29.4 : Windows 10

User avatar
DerekGove
Active Member
Posts: 41
Joined: Sat May 20, 2023 7:10 pm
Location: Cumbria

Re: Generating an involute spiral - 99% of the way there...

Post by DerekGove » Fri May 26, 2023 4:39 pm

I can do a 'brute force' solution with trig, but I suspect the rotate function might be more elegant...

;)
QCAD Version 3.29.4 : Windows 10

CVH
Premier Member
Posts: 3468
Joined: Wed Sep 27, 2017 4:17 pm

Re: Generating an involute spiral - 99% of the way there...

Post by CVH » Fri May 26, 2023 6:55 pm

Derek,

First, xPos & yPos are merely values.
We create an new RVector with them ... Basically a coordinate X/Y and here Z will default to zero.
Maybe the name RVector is ambiguous here, a vector is a mathematical thing with a position, a length and an angle. :wink:
But the Math will hold for both.
All coordinates are relative to the origin and have an angle an a distance in relation with that.

Both functions of the simple API require an array of RVector's.
- addPolyline(...) as nodes. https://github.com/qcad/qcad/blob/maste ... te.js#L226
- addSpline(...) as fitpoints. https://github.com/qcad/qcad/blob/maste ... te.js#L321
If not given then parameter 'closed' will default to false.
And just the same for using 'relative' positions with polys.

Polylines, splines but also arcs, lines, ellipses, ... are shapes and can be added to a drawing.
Then we speak of entities, drawing entities.
A point entity has X/Y(Z) but that is a drawing entity on its own.

I think you need to revise the underlying math:
X(t)=r*(cos(t+a)+t*sin(t+a))
Y(t)=r*(sin(t+a)-t*cos(t+a))
Where a is the start location on the circle and that could be zero.

Remark that the curvature is very high near the circle.
You need an adaptive spread of factor t.

One could also rotate an RVector around a specified point:
https://qcad.org/doc/qcad/3.0/developer ... 17584941aa
Remind that this works with radians while the simple API uses degrees for convenience.

It is common under QCAD to start variable names in lower case.
Just to not conflict with other things ... :wink:

Regards,
CVH

CVH
Premier Member
Posts: 3468
Joined: Wed Sep 27, 2017 4:17 pm

Re: Generating an involute spiral - 99% of the way there...

Post by CVH » Fri May 26, 2023 10:25 pm

DerekGove wrote:
Fri May 26, 2023 1:00 pm
I see in the QCAD API there is a rotate function, which I'm guessing will be the preferred method, which is: rotate(entity, angle, cx,cy).
Again Simple API.
It rotates (angle) a whole entity around a certain center point (cx, cy).

https://github.com/qcad/qcad/blob/maste ... ify.js#L94
Problematic because parameter e can be:
- A shape and then the shape is rotated. (L105)
- An entity ready to include in the drawing and that is rotated. (L102)
- An existent drawing entity by id (L109) and then it is retrieved, rotated and replaced in the drawing.

Here, when addPolyline() or addSpline() are not a part of a transaction ...
... One could retrieve the Id after creation:

Code: Select all

.
...
// Add a polyline with addPolyline or add a spline with addSpline:
var newEntity = addSpline(nodes);
var newEntityId = newEntity.getId();
But I don't think that it was the idea to rotate the resulting straight polyline or spline itself. :wink:

Regards,
CVH

CVH
Premier Member
Posts: 3468
Joined: Wed Sep 27, 2017 4:17 pm

Re: Generating an involute spiral - 99% of the way there...

Post by CVH » Sun May 28, 2023 4:44 am

And after a little tweaking: :wink:

Code: Select all

// Approximation of an involute of a circle with a polyline or a spline
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - by CVH
var originX = 0;         // Center of the evolute circle in X
var originY = 0;         // Center of the evolute circle in Y
var radius = 50;         // Radius of the evolute circle
var startPoint = 90;     // Start position on the evolute circle (degrees)
var points = 15;         // Number of points generated
var angleStep = 10;      // Stepping angle on the evolute circle (degrees)
var direction = -1;      // Direction of the involute (1=CCW, -1=CW)

var i, t, xPos, yPos;       // Iterator, angle and X/Y positions
var nodes = [];             // Collector for polyline nodes
var drawStrings = true;     // Draw the unwound string at each point (true or false)
var tangentPoints = [];     // Collector for tangent points

// Populate an array with nodes and one with positions on the circle:
for (i=0;i<=points;i++) {
    t = angleStep * i * direction;
    xPos = radius *(cos(t + startPoint) + deg2rad(t) * sin(t + startPoint)) + originX;
    yPos = radius *(sin(t + startPoint) - deg2rad(t) * cos(t + startPoint)) + originY;
    nodes.push(new RVector(xPos, yPos));
    tangentPoints.push(new RVector.createPolar(radius, deg2rad(t + startPoint)));
}

// Add a dedicated layer:
addLayer("QCAD Involute", "Dark Blue", "CONTINUOUS", RLineweight.Weight025);
setCurrentLayer("QCAD Involute");

// Add the evolute circle:
addCircle(originX, originY, radius);

// Add a polyline with addPolyline or add a spline with addSpline:
addPolyline(nodes);

// Add strings if required:
if (drawStrings) {
    // Process all collected point sets except the first set:
    for (i=1;i<=points;i++) {
        // Add a line for each point set:
        addLine(tangentPoints[i], nodes[i]);
    }
}
Type 'GE' for Misc .. Development .. Script Shell and agree with the dialog.
SELECT ALL of the code panel above and copy that.
Paste the code in the bottom line of the Script Shell.

Regards,
CVH

User avatar
DerekGove
Active Member
Posts: 41
Joined: Sat May 20, 2023 7:10 pm
Location: Cumbria

Re: Generating an involute spiral - 99% of the way there...

Post by DerekGove » Sun May 28, 2023 11:07 am

Curse you CVH, I wanted to post my version before you did, to prove I wasn't just copying your homework! :D

Here's my version:

Code: Select all

var evolutex = 0;		// Centre of the Evolute in x direction
var evolutey= 0;		// Centre of the Evolute in y direction
var radius = 50;		// Radius of the evolute circle
var stepAngle =15;		// Angle between each tangent point on evolute
var generators = 24;		// Number of generator lines created
var startAngle = 270;		// Angle involute begins at. 
var flip = -1			// Direction. Use 1 or -1.
var i, xPos, yPos;		// Iterator and x/y positions
var genAngle;			// Generation angle
var nodes = [];			// Collector for polyline nodes

// Populate array with nodes:
for (i=0;i<=generators;i++) {
   
genAngle = stepAngle*i*flip;
xPos = (radius * (cos(genAngle+startAngle) + (genAngle*PI/180) * sin(genAngle+startAngle)))+evolutex
yPos = (radius * (sin(genAngle+startAngle) - (genAngle*PI/180) * cos(genAngle+startAngle)))+evolutey
    nodes.push(new RVector(xPos, yPos));
}

// Adding a dedicated layer:
addLayer("QCAD Involute", "Dark Blue", "CONTINUOUS", RLineweight.Weight025);
setCurrentLayer("QCAD Involute");

// Add a polyline with addPolyline or add a spline with addSpline:
addPolyline(nodes);
I must admit, it took me an embarrassing length of time to get this working. Not because of coding, working with degrees/radians or anything, but simply because when I glanced at the involute equation, I misread the yPos calculation to have a '+' in it rather than a '-'. I only worked out what it should be after drawing one out with set squares and compasses, plotting the points, and trying to reverse engineer the equation to see where it was going wrong. I like to work things out for myself, even though I do need a nudge in the right direction sometimes, and I often get there after doing it the long way.;)

Some observations...

I converted degreed to radians the long way. I tried using rad(x) radian(x), and other variations, but none of them worked. '*PI/180' is 7 characters though, just like 'deg2rad', so I'm not sure if there's any coding benefit there.... ;)
It is common under QCAD to start variable names in lower case.
- Yeah, I was trying to follow the convention in your scripts. One error slipped through in my earlier attempt. I didn't know why they were all started with lower case, but it was clearly like that for a reason.

Thanks for the explanation about entities.

My first attempt was trying to reproduce the geometrical construction I'm familiar with using maths. I have managed to get it working to rotate the generated points in the x direction using trig. I only have to get the y direction sorted now. It's obviously not the best way to do it, but it was a good exercise nonetheless.

Thanks for all your help,

Derek
QCAD Version 3.29.4 : Windows 10

CVH
Premier Member
Posts: 3468
Joined: Wed Sep 27, 2017 4:17 pm

Re: Generating an involute spiral - 99% of the way there...

Post by CVH » Mon May 29, 2023 4:24 am

DerekGove wrote:
Sun May 28, 2023 11:07 am
I converted degreed to radians the long way.
... so I'm not sure if there's any coding benefit there....
Doesn't really matter. In fact, it is the shortest way ... :lol:

deg2rad(angle) is a function of input.js:
https://github.com/qcad/qcad/blob/maste ... put.js#L31

input.js is a collection of mathematical functions that can be used in all input fields of the QCAD GUI.
Trigonometric functions are again in degrees for convenience.
The sin(angle) and cos(angle) functions we both use are handled there too.
Most things are translated to the standard ECMAScript Math class what uses radians.

deg2rad(angle) is an odd one:
- input.js > 2pi360 variant
- library.js > pi180 variant (https://github.com/qcad/qcad/blob/maste ... y.js#L1575)
- RMath.cpp > 2pi360 variant (https://github.com/qcad/qcad/blob/19f68 ... h.cpp#L613)
Math wise, smaller numbers have smaller uncertainties but those of library.js are caught by input.js.
(I believe that input.js is initiated later and overwrites the existent function ... :? )

In standard scripting I tend to use the RMath.rad2deg(angle) and RMath.deg2rad(angle) because that is more common under QCAD.
And then we also use the standard Math.sin(angle) and Math.cos(angle). :wink:

For the record:
- What comes after '//' are comments and is not processed as code.
- Instruction lines end in a semicolon (Mostly not critical here).
- We usually indent the code between curly brackets 1 level for readability.
That could be a TAB but under QCAD it is common to use 4 spaces.

Eventually we could write it without all the comments, spaces, TAB's and linefeed's and put everything on one single line.
Then the use of the semicolon is more critical. :wink:
DerekGove wrote:
Sun May 28, 2023 11:07 am
I like to work things out for myself, even though I do need a nudge in the right direction sometimes
You can always reach me for a nudge by Private Message (PM, see top right or click on the username).

Regards,
CVH

Post Reply

Return to “QCAD 'How Do I' Questions”