Issues with Fit-Point splines (before 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 Fit-Point splines (before QSharedPointers)

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

Andrew,

I implemented the gathered knowledge from the former topic to ArcTPR.js to no avail. :(

Intersections between a newly created Fit-Point spline shape and a circle remains empty. (Case1)
And just the same with swapping the shapes. (Case2) :shock:

But then I stumbled on the fact that Case2 was valid --ONLY AFTER-- trying to query intersections for Case1.
There are thus Intersections found for a second attempt with the same shapes. :!: NONE for a first attempt.

A newer test script proved that:
testFPSScript_results.png
testFPSScript_results.png (33.28 KiB) Viewed 76758 times


Something changes for the spline shape after a first attempt to get intersections points.
What exactly can be determined from Case C.1 and Case C.2.
After a first attempt there are Control Points reported besides the Fit Points:
... Trial 2: Shape 3 has Fit-Points: true (+CP)

Suspecting this is related with an internal update of the shape.
An update() is already performed when adding Fit-Points. (Reference)

updateInternal() is a Protected Member Functions and can't be called in direct.
This can however be initiated by other functions:
  • RSpline.copySpline() or .getControlPointsWrapped(); .getActualKnotVector()
    .getDirection1() or getDirection2()
    .getExploded(segments); .getPointAt(t)
    .getTMin() or getTMax()
    .getDiscontinuities(); .getBezierSegments(queryBox)
For the Case D I opted to simply get the minimal t without really needing it.
An updateInternal() is done and the spline additionally has Control-Points while it was created with Fit-Points.
Finding intersections between a spline with Control-Points and a circle is functional.
:arrow: Issue fixed ... Or rather ... Circumvented.


The test script that can be run with: Misc .. Development .. Run Script (XC):
testFPSScript.js
(5.15 KiB) Downloaded 1420 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 circle1 = new RCircle(RVector.nullVector, 8.0);

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

// SECOND ATTEMPT
EAction.handleUserInfo("Re-query");
// Get intersections of RSpline and RCircle, expecting 4:
var ips1b = spline1.getIntersectionPoints(circle1, false);
// Report the number of intersections on the Command History:
EAction.handleUserInfo("1.2: Again as fit-point spline 1 and circle: %1 intersections (of 4)".arg(ips1b.length));

// START OVER NEW
EAction.handleUserInfo("");
// Create an RSpline shape:
var spline2 = new RSpline();
spline2.setFitPoints(fitPoints);
spline2.setPeriodic(true);
// Create a RCircle shape:
var circle2 = new RCircle(RVector.nullVector, 8.0);

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

// SECOND ATTEMPT
EAction.handleUserInfo("Re-query");
// Get intersections of RCircle and RSpline, expecting 4:
var ips2b = circle2.getIntersectionPoints(spline2, false);
// Report the number of intersections on the Command History:
EAction.handleUserInfo("2.2: Again as circle and fit-point spline 2: %1 intersections (of 4)".arg(ips2b.length));


// Case 1.2 and 2.2 are functional ... What has changed for the second attempt?

// START OVER NEW
EAction.handleUserInfo("");
// Create an RSpline shape:
var spline3 = new RSpline();
spline3.setFitPoints(fitPoints);
spline3.setPeriodic(true);
// Create a RCircle shape:
var circle3 = new RCircle(RVector.nullVector, 8.0);

// Report some details of the RSpline shape:
var isSpl = isSplineShape(spline3).toString();
EAction.handleUserInfo("... Trial 1: Shape 3 is a spline shape: %1".arg(isSpl));
var hasFP = "undefined"
if (isSpl) {
    if (spline3.hasFitPoints()) {
    hasFP = "true"
    }
    if (spline3.countControlPoints() > 0) {
        hasFP += " (+CP)"
    }
    else {
        hasFP += " (noCP)"
    }
}
EAction.handleUserInfo("... Trial 1: Shape 3 has Fit-Points: %1".arg(hasFP));

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

// SECOND ATTEMPT
EAction.handleUserInfo("Re-query");
// Report some details of the RSpline shape:
var isSpl = isSplineShape(spline3).toString();
EAction.handleUserInfo("... Trial 2: Shape 3 is a spline shape: %1".arg(isSpl));
var hasFP = "undefined"
if (isSpl) {
    if (spline3.hasFitPoints()) {
    hasFP = "true"
    }
    if (spline3.countControlPoints() > 0) {
        hasFP += " (+CP)"
    }
    else {
        hasFP += " (noCP)"
    }
}
EAction.handleUserInfo("... Trial 2: Shape 3 has Fit-Points: %1".arg(hasFP));

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


// Case 3.2 is functional because after the first query it reports to have Control-Points as well
// Can we force that?
// updateInternal() is a Protected Member Functions
// It can however be initiated by other functions:
//    RSpline.copySpline(RSpline)
//    RSpline.getControlPointsWrapped()
//    RSpline.getActualKnotVector()
//    RSpline.getDirection1() or getDirection2()
//    RSpline.getExploded(segments)
//    RSpline.getPointAt(t)
//    RSpline.getTMin() or getTMax()
//    RSpline.getDiscontinuities()
//    RSpline::getBezierSegments(queryBox)

// START OVER NEW
EAction.handleUserInfo("");
// Create an RSpline shape:
var spline4 = new RSpline();
spline4.setFitPoints(fitPoints);
spline4.setPeriodic(true);
// Create a RCircle shape:
var circle4 = new RCircle(RVector.nullVector, 8.0);

// Force an updateInternal():
var dummy = spline4.getTMin();

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

EAction.handleUserMessage("=> Issue found and fixed")

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

Post Reply

Return to “QCAD Programming, Script Programming and Contributing”