1
0
Fork 0

Added utils.curveCrossesLine and utils.curveCrossesCurve

This commit is contained in:
Joost De Cock 2018-08-21 13:49:12 +02:00
parent aa80da37cc
commit f43be99877
3 changed files with 160 additions and 0 deletions

View file

@ -100,6 +100,16 @@ Point.prototype.sitsOn = function(that) {
else return false;
};
/** Checks whether this has roughly the same coordinates as that */
Point.prototype.sitsRoughlyOn = function(that) {
if (
Math.round(this.x) === Math.round(that.x) &&
Math.round(this.y) === Math.round(that.y)
)
return true;
else return false;
};
/** Shifts this point fraction of the distance towards that point */
Point.prototype.shiftFractionTowards = function(that, fraction) {
return this.shiftTowards(that, this.dist(that) * fraction);

View file

@ -1,4 +1,5 @@
import Point from "./point";
import Bezier from "bezier-js";
import { round } from "./round";
/** Returns internal hook name for a macro */
@ -69,3 +70,72 @@ export function units(value, to = "metric") {
if (to === "imperial") return round(value / 25.4) + '"';
else return round(value / 10) + "cm";
}
/** Find where a curve crosses a line */
export function curveCrossesLine(from, cp1, cp2, to, start, end) {
let intersections = [];
let bz = new Bezier(
{ x: from.x, y: from.y },
{ x: cp1.x, y: cp1.y },
{ x: cp2.x, y: cp2.y },
{ x: to.x, y: to.y }
);
let line = {
p1: { x: start.x, y: start.y },
p2: { x: end.x, y: end.y }
};
for (let t of bz.intersects(line)) {
let isect = bz.get(t);
intersections.push(new Point(isect.x, isect.y));
}
if (intersections.length === 0) return false;
else if (intersections.length === 1) return intersections[0];
else return intersections;
}
/** Find where a curve crosses another curve */
export function curveCrossesCurve(
fromA,
cp1A,
cp2A,
toA,
fromB,
cp1B,
cp2B,
toB
) {
let precision = 0.005; // See https://github.com/Pomax/bezierjs/issues/99
let intersections = [];
let curveA = new Bezier(
{ x: fromA.x, y: fromA.y },
{ x: cp1A.x, y: cp1A.y },
{ x: cp2A.x, y: cp2A.y },
{ x: toA.x, y: toA.y }
);
let curveB = new Bezier(
{ x: fromB.x, y: fromB.y },
{ x: cp1B.x, y: cp1B.y },
{ x: cp2B.x, y: cp2B.y },
{ x: toB.x, y: toB.y }
);
for (let tvalues of curveA.intersects(curveB, precision)) {
let intersection = curveA.get(tvalues.substr(0, tvalues.indexOf("/")));
intersections.push(new Point(intersection.x, intersection.y));
}
if (intersections.length === 0) return false;
else if (intersections.length === 1) return intersections.shift();
else {
let unique = [];
for (let i of intersections) {
let dupe = false;
for (let u of unique) {
if (i.sitsRoughlyOn(u)) dupe = true;
}
if (!dupe) unique.push(i);
}
return unique;
}
}

View file

@ -93,6 +93,86 @@ it("Should detect horizontal lines never pass a give Y-value", () => {
expect(freesewing.utils.beamCrossesY(a, b, 69)).to.equal(false);
});
it("Should find no intersections between a curve and a line", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let E = new freesewing.Point(-20, -20);
let D = new freesewing.Point(30, -85);
let hit = freesewing.utils.curveCrossesLine(A, Acp, Bcp, B, E, D);
expect(hit).to.equal(false);
});
it("Should find 1 intersection between a curve and a line", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let E = new freesewing.Point(20, 20);
let D = new freesewing.Point(30, -85);
let hit = freesewing.utils.curveCrossesLine(A, Acp, Bcp, B, E, D);
expect(hit.x).to.equal(20.85);
expect(hit.y).to.equal(11.11);
});
it("Should find 3 intersections between a curve and a line", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let E = new freesewing.Point(20, -5);
let D = new freesewing.Point(100, 85);
let hits = freesewing.utils.curveCrossesLine(A, Acp, Bcp, B, E, D);
expect(hits.length).to.equal(3);
});
it("Should find 9 intersections between two curves", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let C = new freesewing.Point(20, -5);
let Ccp = new freesewing.Point(60, 300);
let D = new freesewing.Point(100, 85);
let Dcp = new freesewing.Point(70, -220);
let hits = freesewing.utils.curveCrossesCurve(A, Acp, Bcp, B, C, Ccp, Dcp, D);
expect(hits.length).to.equal(9);
});
it("Should find 1 intersection between two curves", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let C = new freesewing.Point(20, -5);
let Ccp = new freesewing.Point(-60, 300);
let D = new freesewing.Point(-200, 85);
let Dcp = new freesewing.Point(-270, -220);
let hit = freesewing.utils.curveCrossesCurve(A, Acp, Bcp, B, C, Ccp, Dcp, D);
expect(hit.x).to.equal(15.58);
expect(hit.y).to.equal(10.56);
});
it("Should find no intersection between two curves", () => {
let A = new freesewing.Point(10, 10);
let Acp = new freesewing.Point(310, 40);
let B = new freesewing.Point(110, 70);
let Bcp = new freesewing.Point(-210, 40);
let C = new freesewing.Point(20, -5);
let Ccp = new freesewing.Point(-60, -300);
let D = new freesewing.Point(-200, 85);
let Dcp = new freesewing.Point(-270, -220);
let hit = freesewing.utils.curveCrossesCurve(A, Acp, Bcp, B, C, Ccp, Dcp, D);
expect(hit).to.equal(false);
});
it("Should correctly format units", () => {
expect(freesewing.utils.units(123.456)).to.equal("12.35cm");
expect(freesewing.utils.units(123.456, "imperial")).to.equal('4.86"');