Skip to content

Commit 7d405a0

Browse files
committed
fix edge-ray intersection edge cases
1 parent c12ff4a commit 7d405a0

File tree

4 files changed

+107
-33
lines changed

4 files changed

+107
-33
lines changed

Diff for: src/plots/polar/polar.js

+42-31
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,6 @@ proto.updateMainDrag = function(fullLayout, polarLayout) {
758758
function findEnclosingVertexAngles(a) {
759759
var cycleIndex = makeCycleIndexFn(vangles.length);
760760
var i0 = findIndexOfMin(vangles, function(v) {
761-
if(!isAngleInSector(v, sector)) return Infinity;
762761
var adelta = angleDelta(v, a);
763762
return adelta > 0 ? adelta : Infinity;
764763
});
@@ -823,8 +822,8 @@ proto.updateMainDrag = function(fullLayout, polarLayout) {
823822
// match origin for asymmetric polygons
824823
if(vangles) {
825824
var offset = findPolygonOffset(radius, sector, vangles);
826-
x0 += offset.left;
827-
y0 += offset.top;
825+
x0 += cxx + offset[0];
826+
y0 += cyy + offset[1];
828827
}
829828

830829
switch(dragModeNow) {
@@ -1323,7 +1322,7 @@ function findIndexOfMin(arr, fn) {
13231322
return ind;
13241323
}
13251324

1326-
// find intersection of 'v0' <-> 'v1' edge with a 'radial' line
1325+
// find intersection of 'v0' <-> 'v1' edge with a ray at angle 'a'
13271326
// (i.e. a line that starts from the origin at angle 'a')
13281327
// given an (xp,yp) pair on the 'v0' <-> 'v1' line
13291328
// (N.B. 'v0' and 'v1' are angles in radians)
@@ -1334,28 +1333,40 @@ function findIntersectionXY(v0, v1, a, xpyp) {
13341333
var yp = xpyp[1];
13351334
var dsin = clampTiny(Math.sin(v1) - Math.sin(v0));
13361335
var dcos = clampTiny(Math.cos(v1) - Math.cos(v0));
1337-
1338-
if(dsin && dcos) {
1339-
// given
1340-
// g(x) := v0 -> v1 line = m * x + b
1341-
// h(x) := mr * x
1342-
// solve g(xstar) = h(xstar)
1343-
var m = dsin / dcos;
1344-
var b = yp - m * xp;
1345-
var mr = Math.sin(a) / Math.cos(a);
1346-
xstar = b / (mr - m);
1347-
ystar = mr * xstar;
1348-
} else {
1349-
var r;
1350-
if(dcos) {
1336+
var tanA = Math.tan(a);
1337+
var cotanA = clampTiny(1 / tanA);
1338+
var m = dsin / dcos;
1339+
var b = yp - m * xp;
1340+
1341+
if(cotanA) {
1342+
if(dsin && dcos) {
1343+
// given
1344+
// g(x) := v0 -> v1 line = m*x + b
1345+
// h(x) := ray at angle 'a' = m*x = tanA*x
1346+
// solve g(xstar) = h(xstar)
1347+
xstar = b / (tanA - m);
1348+
ystar = tanA * xstar;
1349+
} else if(dcos) {
13511350
// horizontal v0 -> v1
1352-
r = yp / Math.sin(v0);
1351+
xstar = yp * cotanA;
1352+
ystar = yp;
13531353
} else {
1354-
// vertical v0 -> va
1355-
r = xp / Math.cos(v0);
1354+
// vertical v0 -> v1
1355+
xstar = xp;
1356+
ystar = xp * tanA;
1357+
}
1358+
} else {
1359+
// vertical ray
1360+
if(dsin && dcos) {
1361+
xstar = 0;
1362+
ystar = b;
1363+
} else if(dcos) {
1364+
xstar = 0;
1365+
ystar = yp;
1366+
} else {
1367+
// does this case exists?
1368+
xstar = ystar = NaN;
13561369
}
1357-
xstar = r * Math.cos(a);
1358-
ystar = r * Math.sin(a);
13591370
}
13601371

13611372
return [xstar, ystar];
@@ -1365,7 +1376,7 @@ function findIntersectionXY(v0, v1, a, xpyp) {
13651376
// rearranged into 0 = a*x^2 + b * x + c
13661377
//
13671378
// where f(x) = m*x + t + yp
1368-
// and x01 = (-b +/- del) / (2*a)
1379+
// and (x0, x1) = (-b +/- del) / (2*a)
13691380
function findXYatLength(l, m, xp, yp) {
13701381
var t = -m * xp;
13711382
var a = m * m + 1;
@@ -1454,15 +1465,14 @@ function makePolygon(r, sector, vangles) {
14541465
function findPolygonOffset(r, sector, vangles) {
14551466
var minX = Infinity;
14561467
var minY = Infinity;
1468+
var vertices = makePolygon(r, sector, vangles);
14571469

1458-
for(var i = 0; i < vangles.length; i++) {
1459-
var va = vangles[i];
1460-
if(isAngleInSector(va, sector)) {
1461-
minX = Math.min(minX, r * Math.cos(va));
1462-
minY = Math.min(minY, -r * Math.sin(va));
1463-
}
1470+
for(var i = 0; i < vertices.length; i++) {
1471+
var v = vertices[i];
1472+
minX = Math.min(minX, v[0]);
1473+
minY = Math.min(minY, -v[1]);
14641474
}
1465-
return {top: minY + r, left: minX + r};
1475+
return [minX, minY];
14661476
}
14671477

14681478
function invertY(pts0) {
@@ -1564,6 +1574,7 @@ function strRotate(angle) {
15641574
return 'rotate(' + angle + ')';
15651575
}
15661576

1577+
// to more easily catch 'almost zero' numbers in if-else blocks
15671578
function clampTiny(v) {
15681579
return Math.abs(v) > 1e-10 ? v : 0;
15691580
}

Diff for: test/image/baselines/polar_polygon-grids.png

9.18 KB
Loading

Diff for: test/image/mocks/polar_polygon-grids.json

+37
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@
3838
"theta": ["b"],
3939
"name": "out-of-polygon (should not see it)",
4040
"subplot": "polar4"
41+
},
42+
{
43+
"type": "scatterpolar",
44+
"r": [5, 4, 2, 4, 5, 5],
45+
"theta": ["b", "c", "d", "e", "a", "b"],
46+
"fill": "toself",
47+
"subplot": "polar5"
48+
},
49+
{
50+
"type": "scatterpolar",
51+
"r": [5, 4, 2, 4, 5, 5],
52+
"theta": ["b", "c", "d", "e", "a", "b"],
53+
"fill": "toself",
54+
"subplot": "polar6"
4155
}
4256
],
4357
"layout": {
@@ -96,6 +110,29 @@
96110
"range": [0, 400]
97111
}
98112
},
113+
"polar5": {
114+
"gridshape": "linear",
115+
"domain": {
116+
"x": [0.4, 0.6],
117+
"y": [0.4, 0.6]
118+
},
119+
"angularaxis": {
120+
"direction": "clockwise",
121+
"tickfont": {"color": "red"}
122+
},
123+
"sector": [-90, 90]
124+
},
125+
"polar6": {
126+
"gridshape": "linear",
127+
"domain": {
128+
"x": [0.8, 1],
129+
"y": [0.45, 0.65]
130+
},
131+
"angularaxis": {
132+
"tickfont": {"color": "blue" }
133+
},
134+
"sector": [0, 180]
135+
},
99136
"width": 550,
100137
"height": 550,
101138
"margin": {"l": 40, "r": 40, "b": 60, "t": 20, "pad": 0},

Diff for: test/jasmine/tests/polar_test.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -1292,8 +1292,7 @@ describe('Test polar *gridshape linear* interactions', function() {
12921292
[-142.658, -46.353], [-88.167, 121.352],
12931293
[88.167, 121.352], [142.658, -46.352],
12941294
[0, -150], [-142.658, -46.352],
1295-
[-142.658, -46.352],
1296-
[-88.167, 121.352],
1295+
[-142.658, -46.352], [-88.167, 121.352],
12971296
[88.167, 121.352], [142.658, -46.352],
12981297
[0, -150], [-142.658, -46.352],
12991298
[-49.261, -16.005], [-30.445, 41.904],
@@ -1308,6 +1307,33 @@ describe('Test polar *gridshape linear* interactions', function() {
13081307
]
13091308
});
13101309
})
1310+
.then(function() {
1311+
return Plotly.relayout(gd, 'polar.sector', [-90, 90]);
1312+
})
1313+
.then(function() { return _dragStart([200, 200], [200, 230]); })
1314+
.then(function() {
1315+
_assertAndDragEnd('half-sector, drag outward', {
1316+
zoombox: [
1317+
[0, 121.352], [88.167, 121.352],
1318+
[142.658, -46.352], [0, -150],
1319+
[0, -150], [0, 0],
1320+
[0, 121.352], [0, 121.352],
1321+
[88.167, 121.352], [142.658, -46.352],
1322+
[0, -150], [0, -150],
1323+
[0, 0], [0, 121.352],
1324+
[0, 71.329], [51.823, 71.329],
1325+
[83.852, -27.245], [0, -88.16778784387097],
1326+
[0, -88.167], [0, 0],
1327+
[0, 71.329]
1328+
],
1329+
corners: [
1330+
[73.602, 10.771], [65.877, 34.548],
1331+
[62.073, 33.312], [69.798, 9.535],
1332+
[121.177, 26.229], [113.452, 50.006],
1333+
[109.648, 48.770], [117.373, 24.993]
1334+
]
1335+
});
1336+
})
13111337
.catch(failTest)
13121338
.then(done);
13131339
});

0 commit comments

Comments
 (0)