fix(modeling): correct label line attachments not being recognized
* remove rounding where it does not matter * work around some precision errors in logic * adjust test cases (to higher precision) Closes #669
This commit is contained in:
parent
84dc3b50e7
commit
7d896855a9
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
var sqrt = Math.sqrt,
|
var sqrt = Math.sqrt,
|
||||||
min = Math.min,
|
min = Math.min,
|
||||||
max = Math.max;
|
max = Math.max,
|
||||||
|
abs = Math.abs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the square (power to two) of a number.
|
* Calculate the square (power to two) of a number.
|
||||||
|
@ -136,12 +137,6 @@ module.exports.getAttachment = getAttachment;
|
||||||
*/
|
*/
|
||||||
function getCircleSegmentIntersections(s1, s2, cc, cr) {
|
function getCircleSegmentIntersections(s1, s2, cc, cr) {
|
||||||
|
|
||||||
// silently round values
|
|
||||||
s1 = roundPoint(s1);
|
|
||||||
s2 = roundPoint(s2);
|
|
||||||
cc = roundPoint(cc);
|
|
||||||
cr = min(getDistance(s1, cc), getDistance(s2, cc));
|
|
||||||
|
|
||||||
var baX = s2.x - s1.x;
|
var baX = s2.x - s1.x;
|
||||||
var baY = s2.y - s1.y;
|
var baY = s2.y - s1.y;
|
||||||
var caX = cc.x - s1.x;
|
var caX = cc.x - s1.x;
|
||||||
|
@ -155,6 +150,12 @@ function getCircleSegmentIntersections(s1, s2, cc, cr) {
|
||||||
var q = c / a;
|
var q = c / a;
|
||||||
|
|
||||||
var disc = pBy2 * pBy2 - q;
|
var disc = pBy2 * pBy2 - q;
|
||||||
|
|
||||||
|
// round disc to 10 digits to work around
|
||||||
|
// negative, very close to zero results (-4e-15)
|
||||||
|
// being produced in some environments
|
||||||
|
disc = round(disc, 10);
|
||||||
|
|
||||||
if (disc < 0) {
|
if (disc < 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -165,8 +166,8 @@ function getCircleSegmentIntersections(s1, s2, cc, cr) {
|
||||||
var abScalingFactor2 = -pBy2 - tmpSqrt;
|
var abScalingFactor2 = -pBy2 - tmpSqrt;
|
||||||
|
|
||||||
var i1 = {
|
var i1 = {
|
||||||
x: round(s1.x - baX * abScalingFactor1),
|
x: s1.x - baX * abScalingFactor1,
|
||||||
y: round(s1.y - baY * abScalingFactor1)
|
y: s1.y - baY * abScalingFactor1
|
||||||
};
|
};
|
||||||
|
|
||||||
if (disc === 0) { // abScalingFactor1 == abScalingFactor2
|
if (disc === 0) { // abScalingFactor1 == abScalingFactor2
|
||||||
|
@ -174,10 +175,11 @@ function getCircleSegmentIntersections(s1, s2, cc, cr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var i2 = {
|
var i2 = {
|
||||||
x: round(s1.x - baX * abScalingFactor2),
|
x: s1.x - baX * abScalingFactor2,
|
||||||
y: round(s1.y - baY * abScalingFactor2)
|
y: s1.y - baY * abScalingFactor2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// return only points on line segment
|
||||||
return [ i1, i2 ].filter(function(p) {
|
return [ i1, i2 ].filter(function(p) {
|
||||||
return isPointInSegment(p, s1, s2);
|
return isPointInSegment(p, s1, s2);
|
||||||
});
|
});
|
||||||
|
@ -192,7 +194,14 @@ function isPointInSegment(p, segmentStart, segmentEnd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fenced(n, rangeStart, rangeEnd) {
|
function fenced(n, rangeStart, rangeEnd) {
|
||||||
return min(rangeStart, rangeEnd) <= n && n <= max(rangeStart, rangeEnd);
|
|
||||||
|
// use matching threshold to work around
|
||||||
|
// precisison errors in intersection computation
|
||||||
|
|
||||||
|
return (
|
||||||
|
n >= min(rangeStart, rangeEnd) - EQUAL_THRESHOLD &&
|
||||||
|
n <= max(rangeStart, rangeEnd) + EQUAL_THRESHOLD
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -211,23 +220,32 @@ function mid(p1, p2) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function round(n) {
|
/**
|
||||||
return Math.round(n * 1000) / 1000;
|
* Round number to precision
|
||||||
|
*
|
||||||
|
* @param {Number} number
|
||||||
|
* @param {Integer} [precision=1]
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
*/
|
||||||
|
function round(number, precision) {
|
||||||
|
|
||||||
|
if (typeof precision === 'undefined') {
|
||||||
|
return Math.round(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
var factor = Math.pow(10, precision);
|
||||||
|
var tempNumber = number * factor;
|
||||||
|
var roundedTempNumber = Math.round(tempNumber);
|
||||||
|
return roundedTempNumber / factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function roundPoint(p) {
|
var EQUAL_THRESHOLD = 0.1;
|
||||||
return {
|
|
||||||
x: round(p.x),
|
|
||||||
y: round(p.y)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var EQUAL_THRESHOLD = 0.2;
|
|
||||||
|
|
||||||
function pointsEqual(p1, p2) {
|
function pointsEqual(p1, p2) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Math.abs(p1.x - p2.x) <= EQUAL_THRESHOLD &&
|
abs(p1.x - p2.x) <= EQUAL_THRESHOLD &&
|
||||||
Math.abs(p1.y - p2.y) <= EQUAL_THRESHOLD
|
abs(p1.y - p2.y) <= EQUAL_THRESHOLD
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,14 +232,13 @@ describe('modeling/behavior/util - LineAttachmentUtil#getAttachment', function()
|
||||||
var attachment = getAttachment({ x: 35.197169, y: 5.399375 }, floatingPointLine);
|
var attachment = getAttachment({ x: 35.197169, y: 5.399375 }, floatingPointLine);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// expext values to be rounded to 3 decimal places
|
expect(attachment.type).to.equal('bendpoint');
|
||||||
expect(attachment).to.eql({
|
expect(attachment.segmentIndex).to.equal(1);
|
||||||
type: 'bendpoint',
|
expect(attachment.bendpointIndex).to.equal(1);
|
||||||
position: { x: 30.793, y: 10.463 },
|
|
||||||
bendpointIndex: 1,
|
|
||||||
segmentIndex: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// expect values to be roughly equal
|
||||||
|
expect(attachment.position.x).to.be.within(30.793 - EPSILON, 30.793 + EPSILON);
|
||||||
|
expect(attachment.position.y).to.be.within(10.463 - EPSILON, 10.463 + EPSILON);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue