Automatically add dimension labels to drawing with a script

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
cjm
Junior Member
Posts: 11
Joined: Sun Jun 25, 2017 5:54 pm

Automatically add dimension labels to drawing with a script

Post by cjm » Sun Mar 29, 2020 1:57 am

Is there a way to create dimension labels with a script? For example, in the command line, the following input will create a dimension label:

Code: Select all

dimaligned
0,0
100,0
100
Is there an easy way to do this within a script, short of including and pulling apart the Dimension scripts?

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

Re: Automatically add dimension labels to drawing with a script

Post by CVH » Sun Mar 29, 2020 6:39 am

One method is to duplicate the functionality of the dim scripts.
Analog to this story:
https://qcad.org/rsforum/viewtopic.php?&t=6801

The major part of the dim scripts is data collection.
That data you have at hand.
The last value might be an issue, the side is relative to the actual pointer position.
With DimAligned.js as example:
The data is collected in 'this.data' as a new RDimAlignedData.
The last case of DimAligned.prototype.pickCoordinate creates the operation and finally cast it.

The other method would be to preset all the data and parse it to the dim script.
Analog to this story:
https://qcad.org/rsforum/viewtopic.php?&t=6649

Regards,
CVH

cjm
Junior Member
Posts: 11
Joined: Sun Jun 25, 2017 5:54 pm

Re: Automatically add dimension labels to drawing with a script

Post by cjm » Mon Mar 30, 2020 4:07 am

I decided to take the second route you suggested, with mixed success. I have fully working functions for horizontal and aligned dims, however I'm still having trouble creating functions for vertical and angular dims. I will post what success I have had so far.

My horizontal dim function, which works correctly; it receives the co-ordinates as lists and convert them to RVectors internally (I had to tweak the getOperation function because it tries to read the toolbar value for Scale, which causes an error if it isn't present):

Code: Select all

function drawHorizontalDim(extensionPoint1, extensionPoint2, definitionPoint)
{
        include("scripts/Draw/Dimension/DimRotated/DimRotated.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimRotated();

        // Amend getOperation for absence of scale value in toolbar
        a.getOperation = function(preview) {
        if (!this.data.isValid()) {
            return undefined;
        }

        var doc = this.getDocument();
        var scale = 1;
        var scaled_data = this.data;

        scaled_data.setLinearFactor(1/scale);

        var entity = new RDimRotatedEntity(doc, scaled_data);
        if (!isEntity(entity)) {
            return undefined;
        }

        return new RAddObjectOperation(entity, this.getToolTitle());
        };

        a.setDocumentInterface(di);

        a.data.setExtensionPoint1(new RVector(extensionPoint1));
        a.data.setExtensionPoint2(new RVector(extensionPoint2));
        a.data.setDefinitionPoint(new RVector(definitionPoint));
        // Locks the rotation of the measurement at 0
        a.data.setRotation(0.0);

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}
My aligned dim function, which works correctly in much the same way:

Code: Select all

function drawAlignedDim(extensionPoint1, extensionPoint2, definitionPoint)
{
        include("scripts/Draw/Dimension/DimAligned/DimAligned.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimAligned();

        // Amend getOperation for absence of scale value in toolbar
        a.getOperation = function(preview) {
        if (!this.data.isValid()) {
            return undefined;
        }

        var doc = this.getDocument();
        var scale = 1;
        var scaled_data = this.data;

        scaled_data.setLinearFactor(1/scale);

        var entity = new RDimAlignedEntity(doc, scaled_data);
        if (!isEntity(entity)) {
            return undefined;
        }

        return new RAddObjectOperation(entity, this.getToolTitle());
        };

        a.setDocumentInterface(di);

        a.data.setExtensionPoint1(new RVector(extensionPoint1));
        a.data.setExtensionPoint2(new RVector(extensionPoint2));
        a.data.setDefinitionPoint(new RVector(definitionPoint));

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}
My vertical dim function; this almost works but the definitionPoint isn't used correctly. Unlike the horizontal dim function, which aligns the label to the absolute y value of definitionPoint, regardless of the x value, the vertical one seems to be stuck either exactly between extensionPoint 1 and 2, or aligned with extensionPoint1, and nothing else (I have tried multiple x and y values and these are the only results I can achieve):

Code: Select all

function drawVerticalDim(extensionPoint1, extensionPoint2, definitionPoint)
{
        include("scripts/Draw/Dimension/DimRotated/DimRotated.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimRotated();

        // Amend getOperation for absence of scale value in toolbar
        a.getOperation = function(preview) {
        if (!this.data.isValid()) {
            return undefined;
        }

        var doc = this.getDocument();
        var scale = 1;
        var scaled_data = this.data;

        scaled_data.setLinearFactor(1/scale);

        var entity = new RDimRotatedEntity(doc, scaled_data);
        if (!isEntity(entity)) {
            return undefined;
        }

        return new RAddObjectOperation(entity, this.getToolTitle());
        };

        a.setDocumentInterface(di);

        a.data.setExtensionPoint1(new RVector(extensionPoint1));
        a.data.setExtensionPoint2(new RVector(extensionPoint2));
        a.data.setDefinitionPoint(new RVector(definitionPoint));
        a.data.setRotation(Math.PI / 2);

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}
And finally, my angular dim function; this doesn't work at all yet.

Code: Select all

function drawAngularDim(firstEntity, secondEntity, dimArcPosition)
{
        include("scripts/Draw/Dimension/DimAngular/DimAngular.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimAngular();

        a.setDocumentInterface(di);

        a.firstEntity = firstEntity;
        a.secondEntity = secondEntity;
        a.dimArcPosition = dimArcPosition;

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}

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

Re: Automatically add dimension labels to drawing with a script

Post by CVH » Mon Mar 30, 2020 7:21 am

You will have to dig somewhat further:
cjm wrote:
Mon Mar 30, 2020 4:07 am
And finally, my angular dim function
At first glance, way too little parsed.
Where are those 1ste and 2nd entity defined?

In the switch from DimAngular.prototype.pickEntity one can see that Qcad looks
for the ClosestSimpleShape near the position.
So Qcad is still picking entities....

The data that is really needed is collected in:
this.data3P for a new RDimAngular3PEntity
or in this.data2L for a new RDimAngular2LEntity.
cjm wrote:
Mon Mar 30, 2020 4:07 am
My vertical dim function; this almost works
It is correct that DimHorizontal & DimVertical are both DimRotated.
The diff is set in DimHorizontal.js and DimVertical.js:
this.data.setRotation = 0 or pi/2.

Regards,
CVH

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

Re: Automatically add dimension labels to drawing with a script

Post by CVH » Mon Mar 30, 2020 7:48 am

BTW,
I would be very interested in your scripts.
In a way you are making a simple API for dimensions.

I have a crude script in the pipeline that reproducible documents entities to csv.
I am doing a lot of math on entities props so it is handy to have the numbers in full.

My goal is to code the round trip too.
From reproducible data back to entities.
And why not for dimensions too.

Regards,
CVH

cjm
Junior Member
Posts: 11
Joined: Sun Jun 25, 2017 5:54 pm

Re: Automatically add dimension labels to drawing with a script

Post by cjm » Mon Mar 30, 2020 5:07 pm

CVH wrote:
Mon Mar 30, 2020 7:21 am
It is correct that DimHorizontal & DimVertical are both DimRotated.
The diff is set in DimHorizontal.js and DimVertical.js:
this.data.setRotation = 0 or pi/2.
I set this.data.setRotation in my functions and thought that would be enough but evidently not. I have just rewritten them to use the DimHorizontal.js and DimVertical.js, rather than both of them using DimRotated.js and they both work now, so I must have missed something before.

Code: Select all

function drawHorizontalDim(extensionPoint1, extensionPoint2, definitionPoint)
{
        include("scripts/Draw/Dimension/DimHorizontal/DimHorizontal.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimHorizontal();

        // Amend getOperation for absence of scale value in toolbar
        a.getOperation = function(preview) {
        if (!this.data.isValid()) {
            return undefined;
        }

        var doc = this.getDocument();
        var scale = 1;
        var scaled_data = this.data;

        scaled_data.setLinearFactor(1/scale);

        var entity = new RDimRotatedEntity(doc, scaled_data);
        if (!isEntity(entity)) {
            return undefined;
        }

        return new RAddObjectOperation(entity, this.getToolTitle());
        };

        a.setDocumentInterface(di);

        a.data.setExtensionPoint1(new RVector(extensionPoint1));
        a.data.setExtensionPoint2(new RVector(extensionPoint2));
        a.data.setDefinitionPoint(new RVector(definitionPoint));
        //a.data.setRotation(0.0);

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}

Code: Select all

function drawVerticalDim(extensionPoint1, extensionPoint2, definitionPoint)
{
        include("scripts/Draw/Dimension/DimVertical/DimVertical.js");
        var di = getDocumentInterface();
        var doc = this.getDocument();
        // create and initialize tool:
        var a = new DimVertical();

        // Amend getOperation for absence of scale value in toolbar
        a.getOperation = function(preview) {
        if (!this.data.isValid()) {
            return undefined;
        }

        var doc = this.getDocument();
        var scale = 1;
        var scaled_data = this.data;

        scaled_data.setLinearFactor(1/scale);

        var entity = new RDimRotatedEntity(doc, scaled_data);
        if (!isEntity(entity)) {
            return undefined;
        }

        return new RAddObjectOperation(entity, this.getToolTitle());
        };

        a.setDocumentInterface(di);

        a.data.setExtensionPoint1(new RVector(extensionPoint1));
        a.data.setExtensionPoint2(new RVector(extensionPoint2));
        a.data.setDefinitionPoint(new RVector(definitionPoint));

        // run operation on current document:
        var op = a.getOperation(false);
        di.applyOperation(op);
}
//! [drawVerticalDim]
CVH wrote:
Mon Mar 30, 2020 7:21 am
Where are those 1ste and 2nd entity defined?

In the switch from DimAngular.prototype.pickEntity one can see that Qcad looks
for the ClosestSimpleShape near the position.
So Qcad is still picking entities....

The data that is really needed is collected in:
this.data3P for a new RDimAngular3PEntity
or in this.data2L for a new RDimAngular2LEntity.
I have been creating RLines, RLineData and RLineEntitys and passing them to the function as arguments, hoping that I could do the choosing for it, but so far it hasn't worked.

Thanks for your help by the way, I hope these functions are of some use to you. If you want to see how I am using them, here's my github repo.

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

Re: Automatically add dimension labels to drawing with a script

Post by CVH » Mon Mar 30, 2020 5:51 pm

Glad we are getting somewhere...
cjm wrote:
Mon Mar 30, 2020 5:07 pm
I have been creating RLines, RLineData and RLineEntitys
That is the essence of my reply.

The approach as with interfacing with a user that points in a drawing:
  • a.firstEntity = firstEntity;
    a.secondEntity = secondEntity;
    a.dimArcPosition = dimArcPosition;
Requires that those entities exist in the drawing.
It is not enough that you define the RLine, REntity or RShape.
You still have to cast them and re-query them if needed.

Besides it can handle inner an outer angle,
DimAngular.js has two outcomes:
a new RDimAngular3PEntity
or a new RDimAngular2LEntity.
I think that you have to concentrate on that.
One route through DimAngular.prototype.getOperation at a time.
And then execute the op.

Regards,
CVH

Post Reply

Return to “QCAD 'How Do I' Questions”