I extended the test script a little further (FS#2620)
The reported results on the Command History:
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.

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();
}
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).

Visualization of the shapes involved for Case1 to 10:
The test script that can be run with: Misc .. Development .. Run Script (XC):
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");
CVH