Skip to content

Commit facb2f8

Browse files
committed
mv arc/sector/annular path fn to angles.js
... their polygon-equivalent to helpers.js Then, add wrappers on Polar.prototype, to handle is `gridshape: 'linear'` cases.
1 parent 95119c4 commit facb2f8

File tree

4 files changed

+221
-122
lines changed

4 files changed

+221
-122
lines changed

src/lib/angles.js

+116-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,118 @@ function isPtInsideSector(r, a, rRng, sector) {
115115
return r >= r0 && r <= r1;
116116
}
117117

118+
// common to pathArc, pathSector and pathAnnulus
119+
function _path(r0, r1, a0, a1, cx, cy, isClosed) {
120+
cx = cx || 0;
121+
cy = cy || 0;
122+
123+
var isCircle = isFullCircle([a0, a1].map(rad2deg));
124+
var aStart, aMid, aEnd;
125+
var rStart, rEnd;
126+
127+
if(isCircle) {
128+
aStart = 0;
129+
aMid = PI;
130+
aEnd = 2 * PI;
131+
} else {
132+
if(a0 < a1) {
133+
aStart = a0;
134+
aEnd = a1;
135+
} else {
136+
aStart = a1;
137+
aEnd = a0;
138+
}
139+
}
140+
141+
if(r0 < r1) {
142+
rStart = r0;
143+
rEnd = r1;
144+
} else {
145+
rStart = r1;
146+
rEnd = r0;
147+
}
148+
149+
// N.B. svg coordinates here, where y increases downward
150+
function pt(r, a) {
151+
return [r * Math.cos(a) + cx, cy - r * Math.sin(a)];
152+
}
153+
154+
var largeArc = Math.abs(aEnd - aStart) <= PI ? 0 : 1;
155+
function arc(r, a, cw) {
156+
return 'A' + [r, r] + ' ' + [0, largeArc, cw] + ' ' + pt(r, a);
157+
}
158+
159+
var p;
160+
161+
if(isCircle) {
162+
if(rStart === null) {
163+
p = 'M' + pt(rEnd, aStart) +
164+
arc(rEnd, aMid, 0) +
165+
arc(rEnd, aEnd, 0) + 'Z';
166+
} else {
167+
p = 'M' + pt(rStart, aStart) +
168+
arc(rStart, aMid, 0) +
169+
arc(rStart, aEnd, 0) + 'Z' +
170+
'M' + pt(rEnd, aStart) +
171+
arc(rEnd, aMid, 1) +
172+
arc(rEnd, aEnd, 1) + 'Z';
173+
}
174+
} else {
175+
if(rStart === null) {
176+
p = 'M' + pt(rEnd, aStart) + arc(rEnd, aEnd, 0);
177+
if(isClosed) p += 'L0,0Z';
178+
} else {
179+
p = 'M' + pt(rStart, aStart) +
180+
'L' + pt(rEnd, aStart) +
181+
arc(rEnd, aEnd, 0) +
182+
'L' + pt(rStart, aEnd) +
183+
arc(rStart, aStart, 1) + 'Z';
184+
}
185+
}
186+
187+
return p;
188+
}
189+
190+
/* path an arc
191+
*
192+
* @param {number} r : radius
193+
* @param {number} a0 : first angular coordinate
194+
* @param {number} a1 : second angular coordinate
195+
* @param {number (optional)} cx : x coordinate of center
196+
* @param {number (optional)} cy : y coordinate of center
197+
* @return {string} svg path
198+
*/
199+
function pathArc(r, a0, a1, cx, cy) {
200+
return _path(null, r, a0, a1, cx, cy, 0);
201+
}
202+
203+
/* path a sector
204+
*
205+
* @param {number} r : radius
206+
* @param {number} a0 : first angular coordinate
207+
* @param {number} a1 : second angular coordinate
208+
* @param {number (optional)} cx : x coordinate of center
209+
* @param {number (optional)} cy : y coordinate of center
210+
* @return {string} svg path
211+
*/
212+
function pathSector(r, a0, a1, cx, cy) {
213+
return _path(null, r, a0, a1, cx, cy, 1);
214+
}
215+
216+
/* path an annulus
217+
*
218+
* @param {number} r0 : first radial coordinate
219+
* @param {number} r1 : second radial coordinate
220+
* @param {number} a0 : first angular coordinate
221+
* @param {number} a1 : second angular coordinate
222+
* @param {number (optional)} cx : x coordinate of center
223+
* @param {number (optional)} cy : y coordinate of center
224+
* @return {string} svg path
225+
*/
226+
function pathAnnulus(r0, r1, a0, a1, cx, cy) {
227+
return _path(r0, r1, a0, a1, cx, cy, 1);
228+
}
229+
118230
module.exports = {
119231
deg2rad: deg2rad,
120232
rad2deg: rad2deg,
@@ -124,5 +236,8 @@ module.exports = {
124236
angleDist: angleDist,
125237
isFullCircle: isFullCircle,
126238
isAngleInsideSector: isAngleInsideSector,
127-
isPtInsideSector: isPtInsideSector
239+
isPtInsideSector: isPtInsideSector,
240+
pathArc: pathArc,
241+
pathSector: pathSector,
242+
pathAnnulus: pathAnnulus
128243
};

src/lib/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ lib.angleDist = anglesModule.angleDist;
9393
lib.isFullCircle = anglesModule.isFullCircle;
9494
lib.isAngleInsideSector = anglesModule.isAngleInsideSector;
9595
lib.isPtInsideSector = anglesModule.isPtInsideSector;
96+
lib.pathArc = anglesModule.pathArc;
97+
lib.pathSector = anglesModule.pathSector;
98+
lib.pathAnnulus = anglesModule.pathAnnulus;
9699

97100
var geom2dModule = require('./geometry2d');
98101
lib.segmentsIntersect = geom2dModule.segmentsIntersect;

src/plots/polar/helpers.js

+62-7
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,71 @@ function clampTiny(v) {
203203
return Math.abs(v) > 1e-10 ? v : 0;
204204
}
205205

206-
module.exports = {
207-
isPtInsidePolygon: isPtInsidePolygon,
206+
function transformForSVG(pts0, cx, cy) {
207+
cx = cx || 0;
208+
cy = cy || 0;
208209

209-
makePolygon: makePolygon,
210-
makeRegularPolygon: makeRegularPolygon,
211-
makeClippedPolygon: makeClippedPolygon,
210+
var len = pts0.length;
211+
var pts1 = new Array(len);
212212

213+
for(var i = 0; i < len; i++) {
214+
var pt = pts0[i];
215+
pts1[i] = [cx + pt[0], cy - pt[1]];
216+
}
217+
return pts1;
218+
}
219+
220+
/* path polygon
221+
*
222+
* @param {number} r : polygon 'radius'
223+
* @param {2-item array} sector : polar sector in which polygon is clipped
224+
* @param {array} vangles : angles of polygon vertices in *radians*
225+
* @param {number (optional)} cx : x coordinate of center
226+
* @param {number (optional)} cy : y coordinate of center
227+
* @return {string} svg path
228+
*
229+
*/
230+
function pathPolygon(r, sector, vangles, cx, cy) {
231+
var poly = makePolygon(r, sector, vangles);
232+
return 'M' + transformForSVG(poly, cx, cy).join('L');
233+
}
234+
235+
/* path a polygon 'annulus'
236+
* i.e. a polygon with a concentric hole
237+
*
238+
* N.B. this routine uses the evenodd SVG rule
239+
*
240+
* @param {number} r0 : first radial coordinate
241+
* @param {number} r1 : second radial coordinate
242+
* @param {2-item array} sector : polar sector in which polygon is clipped
243+
* @param {array} vangles : angles of polygon vertices in *radians*
244+
* @param {number (optional)} cx : x coordinate of center
245+
* @param {number (optional)} cy : y coordinate of center
246+
* @return {string} svg path
247+
*
248+
*/
249+
function pathPolygonAnnulus(r0, r1, sector, vangles, cx, cy) {
250+
var rStart, rEnd;
251+
252+
if(r0 < r1) {
253+
rStart = r0;
254+
rEnd = r1;
255+
} else {
256+
rStart = r1;
257+
rEnd = r0;
258+
}
259+
260+
var inner = transformForSVG(makePolygon(rStart, sector, vangles), cx, cy);
261+
var outer = transformForSVG(makePolygon(rEnd, sector, vangles), cx, cy);
262+
return 'M' + outer.reverse().join('L') + 'M' + inner.join('L');
263+
}
264+
265+
module.exports = {
266+
isPtInsidePolygon: isPtInsidePolygon,
213267
findPolygonOffset: findPolygonOffset,
214268
findIntersectionXY: findIntersectionXY,
215269
findXYatLength: findXYatLength,
216-
217-
clampTiny: clampTiny
270+
clampTiny: clampTiny,
271+
pathPolygon: pathPolygon,
272+
pathPolygonAnnulus: pathPolygonAnnulus
218273
};

0 commit comments

Comments
 (0)