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:
Nico Rehwaldt 2017-04-27 23:31:00 +02:00 committed by Philipp Fromme
parent 84dc3b50e7
commit 7d896855a9
2 changed files with 48 additions and 31 deletions

View File

@ -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
); );
} }

View File

@ -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);
}); });
}); });