Issues with QSharedPointers

Discussion forum for C++ and script developers who are using the QCAD development platform or who are looking to contribute to QCAD (translations, documentation, etc).

Moderator: andrew

Forum rules

Always indicate your operating system and QCAD version.

Attach drawing files, scripts and screenshots.

Post one question per topic.

Post Reply
CVH
Premier Member
Posts: 4879
Joined: Wed Sep 27, 2017 4:17 pm

Issues with QSharedPointers

Post by CVH » Tue Jan 07, 2025 8:35 am

Andrew,

I extended the test script a little further (FS#2620)
The reported results on the Command History:
QSP-issues.png
QSP-issues.png (27.98 KiB) Viewed 41195 times

Case1 and 7 are reported in the related bug report on Bugtracker.
There are NO intersections found for a Fit-Point Spline and a circle.
For Case1 a newly created RSpline with Fit-Points, for Case7 an offset to an ellipse = Fit-Point Spline (QSharedPointer)

Swapping the shapes works for Case1, see Case2 but gives a critical error for Case7, see Case8.
This is of no issue with Control-Point splines, see Case3 to 6.
Excluding QSharedPointers, spline 1a&b are RSpline's form a split and spline 2 is a newly created Control-Point spline, an RSpline.


:arrow:
The real solution for QSharedPointers as argument of shape.getIntersectionPoints(other) is to 'strip' the QSharedPointer with getPtr(obj).
Or Qt5 based with:

Code: Select all

if (isFunction(obj.data)) {
    obj = obj.data();
}
See Case10

And then it works both ways, as circle vs spline like in Case2 but in contradiction with Case1 also as spline vs circle.
The hint here is that this Fit-Point spline reports to have Control-Points besides Fit-Points:
... Ellipse offset(data) has Fit-Points: true (+CP)
It is no longer a Case1 or 2 but rather a Case3 to 6.


Case x1 to x3 are similar tests with QSharedPointers as argument of shape.getIntersectionPoints(other)
Expecting 2 intersections for each but they all fail critical.


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
In the light that every clone of an object will be a QSharedPointer in the near future (Commit 064fb09) ...
... I propose that RShape::getIntersectionPoints is able to handle these as argument.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


Not entirely by luck ArcTPR looks for the intersection of a parrallel curve and a circle ...
... Avoiding a critical error as with Case x1 to x3 and Case8 ...
... But that doesn't solve things for Case7 (or Case1) :!:
Hence 'No Solution' for a tangent arc AT (or circle CTP) to an ellipse (arc). :(
ArcTPR-NoSolution.png
ArcTPR-NoSolution.png (11.42 KiB) Viewed 41195 times

Visualization of the shapes involved for Case1 to 10:
testSplineScript_Shapes.png
testSplineScript_Shapes.png (13.15 KiB) Viewed 41195 times

The test script that can be run with: Misc .. Development .. Run Script (XC):
testQSPScript.js
(9.85 KiB) Downloaded 444 times

The code of this script in textual form:

Code: Select all

// Example points to fit:
var fitPoints = [new RVector(0, 9),
                new RVector(7, 0),
                new RVector(0, -9),
                new RVector(-7, 0)];

// Create an RSpline shape:
var spline1 = new RSpline();
spline1.setFitPoints(fitPoints);
spline1.setPeriodic(true);
// Create a RCircle shape:
var circle = new RCircle(RVector.nullVector, 8.0);

// Get intersections of RSpline and RCircle, expecting 4:
var ips1a = spline1.getIntersectionPoints(circle, false);
// Report the number of intersections on the Command History:
EAction.handleUserWarning("1: As fit-point spline 1 and circle: %1 intersections (of 4)".arg(ips1a.length));

// Get intersections of RCircle and RSpline, expecting 4:
var ips1b = circle.getIntersectionPoints(spline1, false);
// Report the number of intersections on the Command History:
EAction.handleUserInfo("2: As circle and fit-point spline 1: %1 intersections (of 4)".arg(ips1b.length));


// Cut up the spline in two parts -> 2 Control-Point RSpline shapes
var cutPoint = spline1.getTMin() + (spline1.getTDelta()/2.0);    // fitPoint (0, -9)
var splines = spline1.splitAtParams([cutPoint]);

// Get intersections of both spline segments and RCircle:
var ips2a = splines[0].getIntersectionPoints(circle, false);
ips2a = ips2a.concat(splines[1].getIntersectionPoints(circle, false));
// Report the number of intersections on the Command History:
EAction.handleUserInfo("3: As control-point splines 1a&b and circle: %1 intersections (of 4)".arg(ips2a.length));

// Get intersections of RCircle and both spline segments:
var ips2b = splines[0].getIntersectionPoints(circle, false);
ips2b = ips2b.concat(splines[1].getIntersectionPoints(circle, false));
// Report the number of intersections on the Command History:
EAction.handleUserInfo("4: As circle and control-point splines 1a&b: %1 intersections (of 4)".arg(ips2b.length));


// Example control points:
var controlPoints = [new RVector(0, 9),
                new RVector(7, 0),
                new RVector(0, -14),
                new RVector(-7, 0),
                new RVector(0, 9)];

// Create an RSpline shape:
var spline2 = new RSpline();
spline2.setControlPoints(controlPoints);
spline2.setPeriodic(true);

// Get intersections of RSpline and RCircle, expecting 4:
var ips3a = spline2.getIntersectionPoints(circle, false);
// Report the number of intersections on the Command History:
EAction.handleUserInfo("5: As control-point spline 2 and circle: %1 intersections (of 4)".arg(ips3a.length));

// Get intersections of RCircle and RSpline, expecting 4:
var ips3b = circle.getIntersectionPoints(spline2, false);
// Report the number of intersections on the Command History:
EAction.handleUserInfo("6: As circle and control-point spline 2: %1 intersections (of 4)".arg(ips3b.length));


// Create an REllipse shape:
var ellipse = new REllipse(new RVector(0, 0), new RVector(10, 0), 0.8, 0.0, 2*Math.PI, false);
// Get an offset inwards by 1 unit -> Fit-Point spline (QSharedPointer)
var eOffset = ellipse.getOffsetShapes(1.0, 1, RS.LeftHand, RVector.invalid)[0];

// Report some details of the offset shape:
var isQSP = isOfType(eOffset, RSplinePointer).toString();
EAction.handleUserInfo("... Ellipse offset is a QSharedPointer: %1".arg(isQSP));
var isSpl = isSplineShape(eOffset).toString();
EAction.handleUserInfo("... Ellipse offset is a spline: %1".arg(isSpl));
var hasFP = "undefined"
if (isSpl) {
    if (eOffset.hasFitPoints()) {
    hasFP = "true"
    }
    if (eOffset.countControlPoints() > 0) {
        hasFP += " (+CP)"
    }
    else {
        hasFP += " (noCP)"
    }
}
EAction.handleUserInfo("... Ellipse offset has Fit-Points: %1".arg(hasFP));

try {
    // Get intersections of ellipse offset and RCircle, expecting 4:
    var ips4a = eOffset.getIntersectionPoints(circle, false);
    // Report the number of intersections on the Command History:
    EAction.handleUserWarning("7: As ellipse offset (QSharedPointer) and circle: %1 intersections (of 4)".arg(ips4a.length));
}
catch(err) {
    msgShort = "No short error recorded, functional but intersections are missing";
    EAction.handleUserWarning("7: As ellipse offset (QSharedPointer) and circle: %1".arg(msgShort));
}

try {
    // Get intersections of RCircle and ellipse offset, expecting 4:
    var ips4b = circle.getIntersectionPoints(eOffset, false);
    // Report the number of intersections on the Command History:
    EAction.handleUserInfo("8: As circle and ellipse offset (QSharedPointer): %1 intersections (of 4)".arg(ips4b.length));
}
catch(err) {
    msgShort = "Wrong number/types of arguments for RShape.getIntersectionPoints()";
    EAction.handleUserWarning("8: As circle and ellipse offset (QSharedPointer): %1".arg(msgShort));
}

// Fix for QSharedPointers:
if (isFunction(eOffset.data)) {
    eOffsetData = eOffset.data();

    // Report some details of the offset shape:
    var isQSP = isOfType(eOffsetData, RSplinePointer).toString();
    EAction.handleUserInfo("... Ellipse offset(data) is a QSharedPointer: %1".arg(isQSP));
    var isSpl = isSplineShape(eOffsetData).toString();
    EAction.handleUserInfo("... Ellipse offset(data) is a spline: %1".arg(isSpl));
    var hasFP = "undefined"
    if (isSpl) {
        if (eOffsetData.hasFitPoints()) {
        hasFP = "true"
        }
        if (eOffsetData.countControlPoints() > 0) {
            hasFP += " (+CP)"
        }
        else {
            hasFP += " (noCP)"
        }
    }
    EAction.handleUserInfo("... Ellipse offset(data) has Fit-Points: %1".arg(hasFP));

    try {
        // Get intersections of ellipse offset and RCircle, expecting 4:
        var ips4c = eOffsetData.getIntersectionPoints(circle, false);
        // Report the number of intersections on the Command History:
        EAction.handleUserInfo("9: As ellipse offset(data) and circle: %1 intersections (of 4)".arg(ips4c.length));
    }
    catch(err) {
        msgShort = "No short error recorded, functional";
        EAction.handleUserWarning("9: As ellipse offset(data) and circle: %1".arg(msgShort));
    }

    try {
        // Get intersections of RCircle and ellipse offset, expecting 4:
        var ips4d = circle.getIntersectionPoints(eOffsetData, false);
        // Report the number of intersections on the Command History:
        EAction.handleUserInfo("10: As circle and ellipse offset(data): %1 intersections (of 4)".arg(ips4d.length));
    }
    catch(err) {
        msgShort = "No short error recorded, functional";
        EAction.handleUserWarning("10: As circle and ellipse offset(data): %1".arg(msgShort));
    }
}

// this.shape1 in ArcTPR.js can be line, arc, circle and ellipse
// parallels are getOffsetShapes by ShapeAlgorithms
// Lines -> RLine.getOffsetShapes -> RShape.getOffsetLines -> QSharedPointers
// Arcs -> RArc.getOffsetShapes -> RShape.getOffsetArcs -> QSharedPointers
// Circle -> RCircle.getOffsetShapes -> RShape.getOffsetArcs -> QSharedPointers
// Ellipse -> REllipse.getOffsetShapes -> QSharedPointers

EAction.handleUserInfo("");
EAction.handleUserInfo("Checking if a QSharedPointer as argument fails for other shapes ...");
// Create an RLine shape:
var line = new RLine(new RVector(-2, -10), new RVector(4, 10));
// Get the left parallel at 1 unit -> line((-2.9578, -9.7126), (3.0422, 10.2873)) (QSharedPointer)
var lOffset = line.getOffsetShapes(1.0, 1, RS.LeftHand, RVector.invalid)[0];
var isQSP = isOfType(lOffset, RLinePointer).toString();
EAction.handleUserInfo("... Line offset is a QSharedPointer: %1".arg(isQSP));

try {
    // Get intersections of RCircle and line offset, expecting 2:
    var ips5 = circle.getIntersectionPoints(lOffset, false);
    // Report the number of intersections on the Command History:
    EAction.handleUserInfo("x1: As circle and line offset (QSharedPointer): %1 intersections (of 2)".arg(ips5.length));
    }
catch(err) {
    msgShort = "RShape: Argument 0 is not of type RShape*";
    EAction.handleUserWarning("x1: As circle and line offset (QSharedPointer): %1".arg(msgShort));
}


// Create another RCircle shape:
var circle2 = new RCircle(new RVector(10, 0), 8.0);
// Get the left parallel at 1 unit -> circle with radius 7 (QSharedPointer)
var cOffset = circle2.getOffsetShapes(1.0, 1, RS.LeftHand, RVector.invalid)[0];
var isQSP = isOfType(cOffset, RCirclePointer).toString();
EAction.handleUserInfo("... Circle offset is a QSharedPointer: %1".arg(isQSP));

try {
    // Get intersections of RCircle and line offset, expecting 2:
    var ips6 = circle.getIntersectionPoints(cOffset, false);
    // Report the number of intersections on the Command History:
    EAction.handleUserInfo("x2: As circle and circle offset (QSharedPointer): %1 intersections (of 2)".arg(ips6.length));
    }
catch(err) {
    msgShort = "RShape: Argument 0 is not of type RShape*";
    EAction.handleUserWarning("x2: As circle and circle offset (QSharedPointer): %1".arg(msgShort));
}


// Create an RArc shape:
var arc = new RArc(new RVector(10, 0), 8.0, Math.PI/2, 3*Math.PI/2, false);
// Get the left parallel at 1 unit -> arc with radius 7 (QSharedPointer)
var aOffset = arc.getOffsetShapes(1.0, 1, RS.LeftHand, RVector.invalid)[0];
var isQSP = isOfType(aOffset, RArcPointer).toString();
EAction.handleUserInfo("... Arc offset is a QSharedPointer: %1".arg(isQSP));
try {
    // Get intersections of RCircle and line offset, expecting 2:
    var ips7 = circle.getIntersectionPoints(aOffset, false);
    // Report the number of intersections on the Command History:
    EAction.handleUserInfo("x3: As circle and arc offset (QSharedPointer): %1 intersections (of 2)".arg(ips7.length));
    }
catch(err) {
    msgShort = "RShape: Argument 0 is not of type RShape*";
    EAction.handleUserWarning("x3: As circle and arc offset (QSharedPointer): %1".arg(msgShort));
}

// Report end of script (If we get this far):
EAction.handleUserInfo("Script end");
Regards,
CVH

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

Re: Issues with QSharedPointers

Post by CVH » Tue Jan 07, 2025 2:37 pm

Update:
The method RShape::getIntersectionPoints() remains as it was.

Newer implementations tend to use shape.getIntersectionPoints(getPtr(other), ...) (Commit 02a8641)
Avoiding a QSharedPointers as argument if that possibility exist.

... Those users with custom built scripts know what to do again. :lol:

I have to wait for the new release to test if Case1 and 7 are solved meanwhile ... Rather unsure as it relates to Fit-Points splines.

Regards,
CVH

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

Re: Issues with QSharedPointers

Post by CVH » Wed Jan 08, 2025 11:31 am

Even correct handling of QSharedPointers didn't fix things.
Conclusions where not optimal because the nature of the shape alters on a second attempt.

A further update in a consecutive topic

Regards,
CVH

Post Reply

Return to “QCAD Programming, Script Programming and Contributing”